sources/Google.Solutions.Terminal/Controls/RdpClient.ConnectionProperties.cs (391 lines of code) (raw):

// // Copyright 2024 Google LLC // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // using Google.Solutions.Platform.Interop; using System; using System.ComponentModel; using System.Diagnostics; using System.Windows.Forms; namespace Google.Solutions.Terminal.Controls { public partial class RdpClient { private const string RdpCategory = "Remote Desktop"; /// <summary> /// Server to connect to. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public string? Server { get => this.client.Server; set { ExpectState(ConnectionState.NotConnected); this.client.Server = value; } } /// <summary> /// Server port to connect to. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public ushort ServerPort { get => (ushort)this.client.AdvancedSettings7.RDPPort; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RDPPort = value; } } /// <summary> /// NetBIOS domain to use for authentication. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public string? Domain { get => this.client.Domain; set { ExpectState(ConnectionState.NotConnected); this.client.Domain = value; } } /// <summary> /// UPN or username to use for authentication. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public string? Username { get => this.client.UserName; set { ExpectState(ConnectionState.NotConnected); this.client.UserName = value; } } /// <summary> /// Password to use for authentication. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public string? Password { get => "*"; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.ClearTextPassword = value; } } /// <summary> /// Connection Timeout, including time allowed to enter user credentials. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public TimeSpan ConnectionTimeout { get => TimeSpan.FromSeconds(this.clientAdvancedSettings.singleConnectionTimeout); set { ExpectState(ConnectionState.NotConnected); // // Apply timeouts. Note that the control might take // about twice the configured timeout before sending a // OnDisconnected event. // this.clientAdvancedSettings.singleConnectionTimeout = (int)value.TotalSeconds; this.clientAdvancedSettings.overallConnectionTimeout = (int)value.TotalSeconds; } } /// <summary> /// Connect to the server for administrative purposes, equivalent /// to running "mstsc /admin". Only relevant for RDS. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableAdminMode { get => this.clientAdvancedSettings.ConnectToAdministerServer; set => this.clientAdvancedSettings.ConnectToAdministerServer = value; } //--------------------------------------------------------------------- // Security properties. //--------------------------------------------------------------------- /// <summary> /// Enable Network Level Authentication (CredSSP). /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableNetworkLevelAuthentication { get => this.clientAdvancedSettings.EnableCredSspSupport; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.EnableCredSspSupport = value; if (!value) { // // To disable NLA, we must enable server authentication. // this.clientAdvancedSettings.AuthenticationLevel = 2; } } } /// <summary> /// Server authentication level. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public uint ServerAuthenticationLevel { get => this.clientAdvancedSettings.AuthenticationLevel; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.AuthenticationLevel = value; } } /// <summary> /// Show a credential prompt if invalid credentials were passed. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableCredentialPrompt { get => this.clientNonScriptable.AllowPromptingForCredentials; set { ExpectState(ConnectionState.NotConnected); this.clientNonScriptable.AllowPromptingForCredentials = value; } } /// <summary> /// Enable 'restricted admin' mode. /// /// Note the following: /// /// 1. Restricted admin mode must be enabled on the server first: /// /// New-ItemProperty -Path"HKLM:\System\CurrentControlSet\Control\Lsa" ` /// -Name "DisableRestrictedAdmin" /// -Value 0 ` /// -PropertyType DWORD -Force /// /// See 'Microsoft Security Advisory 2871997' for details: /// https://learn.microsoft.com/en-us/security-updates/securityadvisories/2016/2871997 /// /// Optionally, it can be enforced via GPO: /// /// Computer Configuration\Policies\Administrative Templates\System\Credentials Delegation /// > 'Restrict delegation of credentials to remote servers' = enabled /// /// 2. Restricted admin mode only works for users that have local admin /// rights on the target machine. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableRestrictedAdminMode { get { try { return (bool)this.clientExtendedSettings.get_Property("RestrictedLogon"); } catch (Exception) { return false; } } set { ExpectState(ConnectionState.NotConnected); this.clientExtendedSettings.set_Property("RestrictedLogon", value); } } /// <summary> /// Enable remote credential guard (RCG). /// /// Note the following: /// /// 1. Restricted admin mode must be enabled on the server first /// (same as for restricted admin mode). /// /// 2. RCG requires Kerberos. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableRemoteCredentialGuard { get { try { return (bool)this.clientExtendedSettings.get_Property("DisableCredentialsDelegation") && (bool)this.clientExtendedSettings.get_Property("RedirectedAuthentication"); } catch (Exception) { return false; } } set { ExpectState(ConnectionState.NotConnected); this.clientExtendedSettings.set_Property("DisableCredentialsDelegation", value); this.clientExtendedSettings.set_Property("RedirectedAuthentication", value); } } //--------------------------------------------------------------------- // Connection Bar properties. //--------------------------------------------------------------------- /// <summary> /// Display the (blue) connection bar at the top. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableConnectionBar { get => this.clientAdvancedSettings.DisplayConnectionBar; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.DisplayConnectionBar = value; } } /// <summary> /// Display a minimize button in the (blue) connection bar at the top. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableConnectionBarMinimizeButton { get => this.clientAdvancedSettings.ConnectionBarShowMinimizeButton; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.ConnectionBarShowMinimizeButton = value; } } /// <summary> /// Pin the (blue) connection bar at the top. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableConnectionBarPin { get => this.clientAdvancedSettings.PinConnectionBar; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.PinConnectionBar = value; } } /// <summary> /// Text to show in connection bar at the top. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public string ConnectionBarText { get => this.clientNonScriptable.ConnectionBarText; set { ExpectState(ConnectionState.NotConnected); this.clientNonScriptable.ConnectionBarText = value; } } //--------------------------------------------------------------------- // Device properties. //--------------------------------------------------------------------- /// <summary> /// Redirect the clipboard. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableClipboardRedirection { get => this.clientAdvancedSettings.RedirectClipboard; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectClipboard = value; } } /// <summary> /// Redirect local printers. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnablePrinterRedirection { get => this.clientAdvancedSettings.RedirectPrinters; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectPrinters = value; } } /// <summary> /// Redirect local smart cards. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableSmartCardRedirection { get => this.clientAdvancedSettings.RedirectSmartCards; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectSmartCards = value; } } /// <summary> /// Redirect local drives. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableDriveRedirection { get => this.clientAdvancedSettings.RedirectDrives; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectDrives = value; } } /// <summary> /// Redirect local devices. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableDeviceRedirection { get => this.clientAdvancedSettings.RedirectDevices; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectDevices = value; } } /// <summary> /// Redirect local ports. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnablePortRedirection { get => this.clientAdvancedSettings.RedirectPorts; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.RedirectPorts = value; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableWebAuthnRedirection { get; set; } //--------------------------------------------------------------------- // Hotkey properties. //--------------------------------------------------------------------- [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public Keys FocusHotKey { // // NB. The Ctrl+Alt modifiers are implied by the HotKeyFocusRelease properties. // get => (Keys)this.clientAdvancedSettings.HotKeyFocusReleaseLeft | Keys.Control | Keys.Alt; set { Debug.Assert(value.HasFlag(Keys.Control)); Debug.Assert(value.HasFlag(Keys.Alt)); var keyWithoutModifiers = (int)(value & ~(Keys.Control | Keys.Alt)); this.clientAdvancedSettings.HotKeyFocusReleaseLeft = keyWithoutModifiers; this.clientAdvancedSettings.HotKeyFocusReleaseRight = keyWithoutModifiers; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public Keys FullScreenHotKey { // // NB. The Ctrl+Alt modifiers are implied by the HotKeyFullScreen properties. // get => (Keys)this.clientAdvancedSettings.HotKeyFullScreen | Keys.Control | Keys.Alt; set { Debug.Assert(value.HasFlag(Keys.Control)); Debug.Assert(value.HasFlag(Keys.Alt)); var keyWithoutModifiers = (int)(value & ~(Keys.Control | Keys.Alt)); this.clientAdvancedSettings.HotKeyFullScreen = keyWithoutModifiers; this.clientAdvancedSettings.HotKeyFullScreen = keyWithoutModifiers; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public int KeyboardHookMode { get => this.clientSecuredSettings.KeyboardHookMode; set { ExpectState(ConnectionState.NotConnected); this.clientSecuredSettings.KeyboardHookMode = value; } } //--------------------------------------------------------------------- // Sound and color properties. //--------------------------------------------------------------------- /// <summary> /// Control where to play audio: /// /// 0 - play locally /// 1 - play on server /// 3 - do not play /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public int AudioRedirectionMode { get => this.clientSecuredSettings.AudioRedirectionMode; set { ExpectState(ConnectionState.NotConnected); this.clientSecuredSettings.AudioRedirectionMode = value; } } /// <summary> /// Indicates whether the default audio input device is redirected from the /// client to the remote session. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableAudioCaptureRedirection { get => this.clientAdvancedSettings.AudioCaptureRedirectionMode; set { ExpectState(ConnectionState.NotConnected); this.clientAdvancedSettings.AudioCaptureRedirectionMode = value; } } /// <summary> /// Color depth, in bits. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public int ColorDepth { get => this.client.ColorDepth; set { ExpectState(ConnectionState.NotConnected); this.client.ColorDepth = value; } } /// <summary> /// Scale DPI setting of remote session to match local DPI settings. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableDpiScaling { get; set; } /// <summary> /// Auto-resize remote desktop to fit client size. /// </summary> [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Category(RdpCategory)] public bool EnableAutoResize { get; set; } = true; } }