feat(core): RDP client on IronRDP

clients::rdp connects over any caller-dialled TCP stream (direct, proxy
or SSH tunnel), upgrades to TLS and logs on with NLA (CredSSP/NTLM),
optionally falling back to TLS-only logon for servers without NLA such
as xrdp (credentials are passed so they log straight in). The server
certificate is pinned through a caller check on its SHA256 fingerprint
before any credentials are sent. The desktop decodes into the VNC
client's RGBA framebuffer; input (IronRDP's scancode/Unicode/mouse
operations), Display Control resizes and the deactivation-reactivation
sequence run on the session thread.

IronRDP's releases need three vendored patches (vendor/README.md):
picky and sspi with their RustCrypto release-candidate pins relaxed so
they share russh's stable versions (their own suites, 402 tests, pass
against them), and ironrdp-session with two unreleased upstream bitmap
fixes (#1486 stride, #1524 RDP6 orientation) without which xrdp desktops
render sheared.

Verified live against xrdp (scottyhardy/docker-remote-desktop): logon,
full desktop rendering, keyboard and mouse input.
This commit is contained in:
Andy Dixon
2026-10-12 10:50:24 +01:00
parent 6a4d7381d9
commit 50c0104d57
227 changed files with 66687 additions and 20 deletions
+111
View File
@@ -0,0 +1,111 @@
//! The builders are required to compose and execute some of the `Sspi` methods.
mod accept_sec_context;
mod acq_cred_handle;
mod change_password;
mod init_sec_context;
use std::fmt;
pub use self::accept_sec_context::{
AcceptSecurityContext, AcceptSecurityContextResult, EmptyAcceptSecurityContext, FilledAcceptSecurityContext,
};
pub use self::acq_cred_handle::{
AcquireCredentialsHandle, AcquireCredentialsHandleResult, EmptyAcquireCredentialsHandle,
FilledAcquireCredentialsHandle, WithCredentialUse, WithoutCredentialUse,
};
pub use self::change_password::{ChangePassword, ChangePasswordBuilder};
pub use self::init_sec_context::{
EmptyInitializeSecurityContext, FilledInitializeSecurityContext, InitializeSecurityContext,
InitializeSecurityContextResult,
};
/// Allows to represent a value of a builder that is mandatory to be specified (during implementation
/// of the builder).
pub trait ToAssign: fmt::Debug {}
/// Allows to represent a mandatory value of a builder that is already specified (during implementation
/// of the builder).
pub trait Assigned: ToAssign {}
/// Allows to represent a mandatory value that is yet to be specified (during implementation
/// of the builder).
pub trait NotAssigned: ToAssign {}
/// Simulates the presence of a value
///
/// Simulates the presence of the `credentials_handle` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithCredentialsHandle;
impl ToAssign for WithCredentialsHandle {}
impl Assigned for WithCredentialsHandle {}
/// Simulates the absence of a value
///
/// Simulates the absence of the `credentials_handle` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithoutCredentialsHandle;
impl ToAssign for WithoutCredentialsHandle {}
impl NotAssigned for WithoutCredentialsHandle {}
/// Simulates the presence of a value
///
/// Simulates the presence of the `context_requirements` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithContextRequirements;
impl ToAssign for WithContextRequirements {}
impl Assigned for WithContextRequirements {}
/// Simulates the absence of a value
///
/// Simulates the absence of the `context_requirements` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithoutContextRequirements;
impl ToAssign for WithoutContextRequirements {}
impl NotAssigned for WithoutContextRequirements {}
/// Simulates the presence of a value
///
/// Simulates the presence of the `target_data_representation` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithTargetDataRepresentation;
impl ToAssign for WithTargetDataRepresentation {}
impl Assigned for WithTargetDataRepresentation {}
/// Simulates the absence of a value
///
/// Simulates the absence of the `target_data_representation` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithoutTargetDataRepresentation;
impl ToAssign for WithoutTargetDataRepresentation {}
impl NotAssigned for WithoutTargetDataRepresentation {}
/// Simulates the presence of a value
///
/// Simulates the presence of the `output` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithOutput;
impl ToAssign for WithOutput {}
impl Assigned for WithOutput {}
/// Simulates the absence of a value
///
/// Simulates the absence of the `output` value of the
/// `AcceptSecurityContext` and
/// `InitializeSecurityContext` builders.
#[derive(Debug)]
pub struct WithoutOutput;
impl ToAssign for WithoutOutput {}
impl NotAssigned for WithoutOutput {}