diff --git a/Cargo.lock b/Cargo.lock index 094ee523941..43915dd616d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cexpr" @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "delog" @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "der" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid 0.9.1", "pem-rfc7468 0.6.0", @@ -656,9 +656,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ "hermit-abi 0.2.6", "io-lifetimes", @@ -687,9 +687,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" @@ -739,9 +739,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "linux-raw-sys" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "lock_api" @@ -912,9 +912,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d4bda43fd1b844cbc6e6e54b5444e2b1bc7838bce59ad205902cccbb26d6761" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ "asn1-rs", ] @@ -978,7 +978,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" dependencies = [ - "der 0.6.0", + "der 0.6.1", "pkcs8 0.9.0", "spki 0.6.0", "zeroize", @@ -1001,7 +1001,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der 0.6.0", + "der 0.6.1", "spki 0.6.0", ] @@ -1022,18 +1022,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1144,7 +1144,7 @@ dependencies = [ [[package]] name = "rdp-rs" version = "0.1.0" -source = "git+https://github.com/gravitational/rdp-rs?rev=8f9f2ab4835f3e52cc9d1771114cc745f3c02759#8f9f2ab4835f3e52cc9d1771114cc745f3c02759" +source = "git+https://github.com/gravitational/rdp-rs?rev=75eb6a30b83e7152ee6213964b5ac6e783304840#75eb6a30b83e7152ee6213964b5ac6e783304840" dependencies = [ "boring", "bufstream", @@ -1283,9 +1283,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" +checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ "bitflags", "errno", @@ -1309,9 +1309,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "scopeguard" @@ -1331,24 +1331,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" [[package]] name = "serde" -version = "1.0.148" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.148" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -1357,9 +1357,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -1420,7 +1420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der 0.6.0", + "der 0.6.1", ] [[package]] @@ -1449,9 +1449,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.104" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1501,18 +1501,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -1548,24 +1548,24 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-xid" diff --git a/docs/pages/includes/desktop-access/desktop-config.yaml b/docs/pages/includes/desktop-access/desktop-config.yaml index c0c6c4306db..c8479bc6c22 100644 --- a/docs/pages/includes/desktop-access/desktop-config.yaml +++ b/docs/pages/includes/desktop-access/desktop-config.yaml @@ -7,6 +7,10 @@ windows_desktop_service: # connect to windows_desktop_service, users connect to the proxy's web UI # instead. public_addr: "desktop-access.example.com:3028" + # (optional) Determines whether desktop sessions will show a user-selected wallpaper + # vs a system-default, single-color wallpaper. For improved visual performance, + # set this to false (its default value). + show_desktop_wallpaper: false ldap: # Address of the LDAP server for secure LDAP connections. # Usually, this address will use port 636, like: ldap.example.com:636. diff --git a/lib/config/configuration.go b/lib/config/configuration.go index ed85437eaad..ba4386e4343 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -1574,6 +1574,7 @@ func applyWindowsDesktopConfig(fc *FileConfig, cfg *service.Config) error { if err != nil { return trace.Wrap(err) } + cfg.WindowsDesktop.ShowDesktopWallpaper = fc.WindowsDesktop.ShowDesktopWallpaper cfg.WindowsDesktop.Hosts, err = utils.AddrsFromStrings(fc.WindowsDesktop.Hosts, defaults.RDPListenPort) if err != nil { return trace.Wrap(err) diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index 55bfa6aca90..c3edb3a7e6e 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -1928,6 +1928,9 @@ type WindowsDesktopService struct { Labels map[string]string `yaml:"labels,omitempty"` // PublicAddr is a list of advertised public addresses of this service. PublicAddr apiutils.Strings `yaml:"public_addr,omitempty"` + // ShowDesktopWallpaper determines whether desktop sessions will show a + // user-selected wallpaper vs a system-default, single-color wallpaper. + ShowDesktopWallpaper bool `yaml:"show_desktop_wallpaper,omitempty"` // LDAP is the LDAP connection parameters. LDAP LDAPConfig `yaml:"ldap"` // Discovery configures desktop discovery via LDAP. diff --git a/lib/service/cfg.go b/lib/service/cfg.go index 3c720eda194..278881e9361 100644 --- a/lib/service/cfg.go +++ b/lib/service/cfg.go @@ -1283,6 +1283,9 @@ type WindowsDesktopConfig struct { ListenAddr utils.NetAddr // PublicAddrs is a list of advertised public addresses of the service. PublicAddrs []utils.NetAddr + // ShowDesktopWallpaper determines whether desktop sessions will show a + // user-selected wallpaper vs a system-default, single-color wallpaper. + ShowDesktopWallpaper bool // LDAP is the LDAP connection parameters. LDAP LDAPConfig diff --git a/lib/service/desktop.go b/lib/service/desktop.go index 34efa03f194..9ecf7a4af5b 100644 --- a/lib/service/desktop.go +++ b/lib/service/desktop.go @@ -221,6 +221,7 @@ func (process *TeleportProcess) initWindowsDesktopServiceRegistered(log *logrus. StaticHosts: cfg.WindowsDesktop.Hosts, OnHeartbeat: process.onHeartbeat(teleport.ComponentWindowsDesktop), }, + ShowDesktopWallpaper: cfg.WindowsDesktop.ShowDesktopWallpaper, LDAPConfig: windows.LDAPConfig(cfg.WindowsDesktop.LDAP), DiscoveryBaseDN: cfg.WindowsDesktop.Discovery.BaseDN, DiscoveryLDAPFilters: cfg.WindowsDesktop.Discovery.Filters, diff --git a/lib/srv/desktop/rdp/rdpclient/Cargo.toml b/lib/srv/desktop/rdp/rdpclient/Cargo.toml index 758ee4d24a9..770a97d96ed 100644 --- a/lib/srv/desktop/rdp/rdpclient/Cargo.toml +++ b/lib/srv/desktop/rdp/rdpclient/Cargo.toml @@ -20,7 +20,7 @@ num-traits = "0.2.15" rand = { version = "0.8.5", features = ["getrandom"] } rand_chacha = "0.3.1" rsa = "0.7.2" -rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "8f9f2ab4835f3e52cc9d1771114cc745f3c02759" } +rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "75eb6a30b83e7152ee6213964b5ac6e783304840" } uuid = { version = "1.2.2", features = ["v4"] } utf16string = "0.2.0" diff --git a/lib/srv/desktop/rdp/rdpclient/client.go b/lib/srv/desktop/rdp/rdpclient/client.go index 2927af7816f..da890266897 100644 --- a/lib/srv/desktop/rdp/rdpclient/client.go +++ b/lib/srv/desktop/rdp/rdpclient/client.go @@ -241,19 +241,21 @@ func (c *Client) connect(ctx context.Context) error { res := C.connect_rdp( C.uintptr_t(c.handle), - addr, - username, - // cert length and bytes. - C.uint32_t(len(userCertDER)), - (*C.uint8_t)(unsafe.Pointer(&userCertDER[0])), - // key length and bytes. - C.uint32_t(len(userKeyDER)), - (*C.uint8_t)(unsafe.Pointer(&userKeyDER[0])), - // screen size. - C.uint16_t(c.clientWidth), - C.uint16_t(c.clientHeight), - C.bool(c.cfg.AllowClipboard), - C.bool(c.cfg.AllowDirectorySharing), + C.CGOConnectParams{ + go_addr: addr, + go_username: username, + // cert length and bytes. + cert_der_len: C.uint32_t(len(userCertDER)), + cert_der: (*C.uint8_t)(unsafe.Pointer(&userCertDER[0])), + // key length and bytes. + key_der_len: C.uint32_t(len(userKeyDER)), + key_der: (*C.uint8_t)(unsafe.Pointer(&userKeyDER[0])), + screen_width: C.uint16_t(c.clientWidth), + screen_height: C.uint16_t(c.clientHeight), + allow_clipboard: C.bool(c.cfg.AllowClipboard), + allow_directory_sharing: C.bool(c.cfg.AllowDirectorySharing), + show_desktop_wallpaper: C.bool(c.cfg.ShowDesktopWallpaper), + }, ) if res.err != C.ErrCodeSuccess { return trace.ConnectionProblem(nil, "RDP connection failed") diff --git a/lib/srv/desktop/rdp/rdpclient/client_common.go b/lib/srv/desktop/rdp/rdpclient/client_common.go index acefa2b0aec..5763598aa81 100644 --- a/lib/srv/desktop/rdp/rdpclient/client_common.go +++ b/lib/srv/desktop/rdp/rdpclient/client_common.go @@ -54,6 +54,10 @@ type Config struct { // directory sharing. AllowDirectorySharing bool + // ShowDesktopWallpaper determines whether desktop sessions will show a + // user-selected wallpaper vs a system-default, single-color wallpaper. + ShowDesktopWallpaper bool + // Log is the logger for status messages. Log logrus.FieldLogger } diff --git a/lib/srv/desktop/rdp/rdpclient/src/lib.rs b/lib/srv/desktop/rdp/rdpclient/src/lib.rs index ce8e9b4be23..489fd462205 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/lib.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/lib.rs @@ -176,36 +176,25 @@ impl From> for ClientOrError { /// The caller mmust ensure that go_addr, go_username, cert_der, key_der point to valid buffers in respect /// to their corresponding parameters. #[no_mangle] -pub unsafe extern "C" fn connect_rdp( - go_ref: usize, - go_addr: *const c_char, - go_username: *const c_char, - cert_der_len: u32, - cert_der: *mut u8, - key_der_len: u32, - key_der: *mut u8, - screen_width: u16, - screen_height: u16, - allow_clipboard: bool, - allow_directory_sharing: bool, -) -> ClientOrError { +pub unsafe extern "C" fn connect_rdp(go_ref: usize, params: CGOConnectParams) -> ClientOrError { // Convert from C to Rust types. - let addr = from_c_string(go_addr); - let username = from_c_string(go_username); - let cert_der = from_go_array(cert_der, cert_der_len); - let key_der = from_go_array(key_der, key_der_len); + let addr = from_c_string(params.go_addr); + let username = from_c_string(params.go_username); + let cert_der = from_go_array(params.cert_der, params.cert_der_len); + let key_der = from_go_array(params.key_der, params.key_der_len); connect_rdp_inner( go_ref, - &addr, ConnectParams { + addr, username, cert_der, key_der, - screen_width, - screen_height, - allow_clipboard, - allow_directory_sharing, + screen_width: params.screen_width, + screen_height: params.screen_height, + allow_clipboard: params.allow_clipboard, + allow_directory_sharing: params.allow_directory_sharing, + show_desktop_wallpaper: params.show_desktop_wallpaper, }, ) .into() @@ -234,7 +223,23 @@ const RDP_CONNECT_TIMEOUT: time::Duration = time::Duration::from_secs(5); const RDP_HANDSHAKE_TIMEOUT: time::Duration = time::Duration::from_secs(10); const RDPSND_CHANNEL_NAME: &str = "rdpsnd"; +#[repr(C)] +pub struct CGOConnectParams { + go_addr: *const c_char, + go_username: *const c_char, + cert_der_len: u32, + cert_der: *mut u8, + key_der_len: u32, + key_der: *mut u8, + screen_width: u16, + screen_height: u16, + allow_clipboard: bool, + allow_directory_sharing: bool, + show_desktop_wallpaper: bool, +} + struct ConnectParams { + addr: String, username: String, cert_der: Vec, key_der: Vec, @@ -242,15 +247,13 @@ struct ConnectParams { screen_height: u16, allow_clipboard: bool, allow_directory_sharing: bool, + show_desktop_wallpaper: bool, } -fn connect_rdp_inner( - go_ref: usize, - addr: &str, - params: ConnectParams, -) -> Result { +fn connect_rdp_inner(go_ref: usize, params: ConnectParams) -> Result { // Connect and authenticate. - let addr = addr + let addr = params + .addr .to_socket_addrs()? .next() .ok_or(ConnectError::InvalidAddr())?; @@ -291,6 +294,11 @@ fn connect_rdp_inner( // Generate a random 8-digit PIN for our smartcard. let mut rng = rand_chacha::ChaCha20Rng::from_entropy(); let pin = format!("{:08}", rng.gen_range(0i32..=99999999i32)); + let mut performance_flags = sec::ExtendedInfoFlag::PerfDisableFullWindowDrag as u32 + | sec::ExtendedInfoFlag::PerfDisableMenuAnimations as u32; + if !params.show_desktop_wallpaper { + performance_flags |= sec::ExtendedInfoFlag::PerfDisableWallpaper as u32; + } sec::connect( &mut mcs, &domain.to_string(), @@ -300,11 +308,7 @@ fn connect_rdp_inner( // InfoPasswordIsScPin means that the user will not be prompted for the smartcard PIN code, // which is known only to Teleport and unique for each RDP session. Some(sec::InfoFlag::InfoPasswordIsScPin as u32 | sec::InfoFlag::InfoMouseHasWheel as u32), - Some( - sec::ExtendedInfoFlag::PerfDisableCursorBlink as u32 - | sec::ExtendedInfoFlag::PerfDisableFullWindowDrag as u32 - | sec::ExtendedInfoFlag::PerfDisableMenuAnimations as u32, - ), + Some(performance_flags), )?; // Client for the "global" channel - video output and user input. let global = global::Client::new( diff --git a/lib/srv/desktop/windows_server.go b/lib/srv/desktop/windows_server.go index 2256f31265d..f2a9c045f0e 100644 --- a/lib/srv/desktop/windows_server.go +++ b/lib/srv/desktop/windows_server.go @@ -161,6 +161,9 @@ type WindowsServiceConfig struct { Heartbeat HeartbeatConfig // HostLabelsFn gets labels that should be applied to a Windows host. HostLabelsFn func(host string) map[string]string + // ShowDesktopWallpaper determines whether desktop sessions will show a + // user-selected wallpaper vs a system-default, single-color wallpaper. + ShowDesktopWallpaper bool // LDAPConfig contains parameters for connecting to an LDAP server. windows.LDAPConfig // DiscoveryBaseDN is the base DN for searching for Windows Desktops. @@ -809,6 +812,7 @@ func (s *WindowsService) connectRDP(ctx context.Context, log logrus.FieldLogger, AuthorizeFn: authorize, AllowClipboard: authCtx.Checker.DesktopClipboard(), AllowDirectorySharing: authCtx.Checker.DesktopDirectorySharing(), + ShowDesktopWallpaper: s.cfg.ShowDesktopWallpaper, }) if err != nil { s.onSessionStart(ctx, sw, &identity, sessionStartTime, windowsUser, string(sessionID), desktop, err)