diff --git a/Cargo.lock b/Cargo.lock index 7148f803bba23..2201695e591d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,16 +566,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "gethostname" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "getrandom" version = "0.1.16" @@ -1233,12 +1223,11 @@ dependencies = [ [[package]] name = "rdp-rs" version = "0.1.0" -source = "git+https://github.com/gravitational/rdp-rs?rev=edfb5330a11d11eaf36d65e4300555368b4c6b02#edfb5330a11d11eaf36d65e4300555368b4c6b02" +source = "git+https://github.com/gravitational/rdp-rs?rev=2b0d99cc60c7b6474a1e2224a0bd6b2beca56b63#2b0d99cc60c7b6474a1e2224a0bd6b2beca56b63" dependencies = [ "boring", "bufstream", "byteorder", - "gethostname", "hmac", "indexmap", "md-5", @@ -1251,6 +1240,7 @@ dependencies = [ "ring", "rsa 0.6.1", "rustls", + "uuid", "x509-parser", "yasna", ] @@ -1706,9 +1696,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom 0.2.8", ] diff --git a/lib/srv/desktop/rdp/rdpclient/Cargo.toml b/lib/srv/desktop/rdp/rdpclient/Cargo.toml index 64d155318516d..e5c6fe042c832 100644 --- a/lib/srv/desktop/rdp/rdpclient/Cargo.toml +++ b/lib/srv/desktop/rdp/rdpclient/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "rdp-client" version = "0.1.0" -authors = ["Andrew Lytvynov ", "Zac Bergquist "] +authors = [ + "Andrew Lytvynov ", + "Zac Bergquist ", +] edition = "2018" [lib] @@ -20,7 +23,7 @@ num-traits = "0.2.16" rand = { version = "0.8.5", features = ["getrandom"] } rand_chacha = "0.3.1" rsa = "0.9.2" -rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "edfb5330a11d11eaf36d65e4300555368b4c6b02" } +rdp-rs = { git = "https://github.com/gravitational/rdp-rs", rev = "2b0d99cc60c7b6474a1e2224a0bd6b2beca56b63" } uuid = { version = "1.4.1", features = ["v4"] } utf16string = "0.2.0" png = "0.17.10" diff --git a/lib/srv/desktop/rdp/rdpclient/client.go b/lib/srv/desktop/rdp/rdpclient/client.go index 8e4fc0b551af6..7c0bb25556c23 100644 --- a/lib/srv/desktop/rdp/rdpclient/client.go +++ b/lib/srv/desktop/rdp/rdpclient/client.go @@ -237,12 +237,14 @@ func (c *Client) connect(ctx context.Context) error { return trace.Wrap(err) } - // Addr and username strings only need to be valid for the duration of + // These strings only need to be valid for the duration of // C.connect_rdp. They are copied on the Rust side and can be freed here. addr := C.CString(c.cfg.Addr) defer C.free(unsafe.Pointer(addr)) username := C.CString(c.username) defer C.free(unsafe.Pointer(username)) + hostID := C.CString(c.cfg.HostID) + defer C.free(unsafe.Pointer(hostID)) cert_der, err := utils.UnsafeSliceData(userCertDER) if err != nil { @@ -261,8 +263,9 @@ func (c *Client) connect(ctx context.Context) error { res := C.connect_rdp( C.uintptr_t(c.handle), C.CGOConnectParams{ - go_addr: addr, - go_username: username, + go_addr: addr, + go_username: username, + go_client_id: hostID, // cert length and bytes. cert_der_len: C.uint32_t(len(userCertDER)), cert_der: (*C.uint8_t)(cert_der), diff --git a/lib/srv/desktop/rdp/rdpclient/client_common.go b/lib/srv/desktop/rdp/rdpclient/client_common.go index 5763598aa81d4..582d5e798faa4 100644 --- a/lib/srv/desktop/rdp/rdpclient/client_common.go +++ b/lib/srv/desktop/rdp/rdpclient/client_common.go @@ -32,10 +32,14 @@ import ( type Config struct { // Addr is the network address of the RDP server, in the form host:port. Addr string - // UserCertGenerator generates user certificates for RDP authentication. + + // GenerateUserCert generates user certificates for RDP authentication. GenerateUserCert GenerateUserCertFn CertTTL time.Duration + // HostID uniquely identifies the Teleport agent running the RDP client. + HostID string + // AuthorizeFn is called to authorize a user connecting to a Windows desktop. AuthorizeFn func(login string) error diff --git a/lib/srv/desktop/rdp/rdpclient/src/cliprdr.rs b/lib/srv/desktop/rdp/rdpclient/src/cliprdr.rs index 7bbb592d74834..2e5990adcc43c 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/cliprdr.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/cliprdr.rs @@ -749,6 +749,7 @@ enum ClipboardFormat { /// Sent as a reply to the format list PDU - used to indicate whether /// the format list PDU was processed succesfully. #[derive(Debug)] +#[allow(dead_code)] struct FormatListResponsePDU { // empty, the only information needed is the flags in the header } diff --git a/lib/srv/desktop/rdp/rdpclient/src/lib.rs b/lib/srv/desktop/rdp/rdpclient/src/lib.rs index d3e30365266db..4f4b4b110509d 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/lib.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/lib.rs @@ -56,10 +56,12 @@ use rdp::core::event::*; use rdp::core::gcc::KeyboardLayout; use rdp::core::global; use rdp::core::global::ServerError; +use rdp::core::license::MemoryLicenseStore; use rdp::core::mcs; use rdp::core::sec; use rdp::core::tpkt; use rdp::core::x224; +use rdp::core::LicenseStore; use rdp::model::error::{Error as RdpError, RdpError as RdpProtocolError, RdpErrorKind, RdpResult}; use rdp::model::link::{Link, Stream}; use rdpdr::path::UnixPath; @@ -74,6 +76,7 @@ use std::net; use std::net::{TcpStream, ToSocketAddrs}; use std::os::raw::c_char; use std::os::unix::io::AsRawFd; +use std::sync::OnceLock; use std::sync::{Arc, Mutex}; use std::{mem, ptr, slice, time}; @@ -182,6 +185,7 @@ pub unsafe extern "C" fn connect_rdp(go_ref: usize, params: CGOConnectParams) -> // Convert from C to Rust types. let addr = from_c_string(params.go_addr); let username = from_c_string(params.go_username); + let client_id = from_c_string(params.go_client_id); 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); @@ -190,6 +194,7 @@ pub unsafe extern "C" fn connect_rdp(go_ref: usize, params: CGOConnectParams) -> ConnectParams { addr, username, + client_id, cert_der, key_der, screen_width: params.screen_width, @@ -230,6 +235,7 @@ const RDPSND_CHANNEL_NAME: &str = "rdpsnd"; pub struct CGOConnectParams { go_addr: *const c_char, go_username: *const c_char, + go_client_id: *const c_char, cert_der_len: u32, cert_der: *mut u8, key_der_len: u32, @@ -244,6 +250,7 @@ pub struct CGOConnectParams { struct ConnectParams { addr: String, username: String, + client_id: String, cert_der: Vec, key_der: Vec, screen_width: u16, @@ -253,6 +260,8 @@ struct ConnectParams { show_desktop_wallpaper: bool, } +static LICENSE_STORE: OnceLock> = OnceLock::new(); + fn connect_rdp_inner(go_ref: usize, params: ConnectParams) -> Result { // Connect and authenticate. let addr = params @@ -288,7 +297,7 @@ fn connect_rdp_inner(go_ref: usize, params: ConnectParams) -> Result Result Result { + inner: Mutex, +} + +impl SyncLicenseStore { + pub fn new(license_store: L) -> Self { + Self { + inner: Mutex::new(license_store), + } + } +} + +impl LicenseStore for &SyncLicenseStore { + fn write_license( + &mut self, + major: u16, + minor: u16, + company: &str, + issuer: &str, + product_id: &str, + license: &[u8], + ) { + info!("Saving {major}.{minor} license from {issuer}"); + self.inner + .lock() + .unwrap() + .write_license(major, minor, company, issuer, product_id, license); + } + + fn read_license( + &self, + major: u16, + minor: u16, + company: &str, + issuer: &str, + product_id: &str, + ) -> Option> { + let license = self + .inner + .lock() + .unwrap() + .read_license(major, minor, company, issuer, product_id); + if license.is_some() { + info!("Found existing {major}.{minor} license from {issuer}"); + } else { + info!("No existing {major}.{minor} license from {issuer}"); + } + + license + } +} + // These functions are defined on the Go side. Look for functions with '//export funcname' // comments. extern "C" { diff --git a/lib/srv/desktop/windows_server.go b/lib/srv/desktop/windows_server.go index 07d2cc7ebfd8b..803df2a81a644 100644 --- a/lib/srv/desktop/windows_server.go +++ b/lib/srv/desktop/windows_server.go @@ -877,6 +877,7 @@ func (s *WindowsService) connectRDP(ctx context.Context, log logrus.FieldLogger, }, CertTTL: windows.CertTTL, Addr: addr.String(), + HostID: s.cfg.Heartbeat.HostUUID, Conn: tdpConn, AuthorizeFn: authorize, AllowClipboard: authCtx.Checker.DesktopClipboard(),