Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 62 additions & 141 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,10 @@ opt-level = 3
# FIXME: We need to catch up with Diplomat upstream again, but this is a significant amount of work.
# In the meantime, we use this forked version which fixes an undefined behavior in the code expanded by the bridge macro.
diplomat = { git = "https://github.com/CBenoit/diplomat", rev = "6dc806e80162b6b39509a04a2835744236cd2396" }

sspi = { path = "../sspi-rs" }
picky = { path = "../picky-rs/picky" }
picky-asn1 = { path = "../picky-rs/picky-asn1" }
picky-asn1-der = { path = "../picky-rs/picky-asn1-der" }
picky-asn1-x509 = { path = "../picky-rs/picky-asn1-x509" }
picky-krb = { path = "../picky-rs/picky-krb" }
2 changes: 1 addition & 1 deletion crates/ironrdp-acceptor/src/credssp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'a> CredsspSequence<'a> {
self.state = next_state;
if let Some(ts_request) = ts_request {
debug!(?ts_request, "Send");
let length = usize::from(ts_request.buffer_len());
let length = usize::from(ts_request.buffer_len().map_err(|e| custom_err!("TsRequest", e))?);
let unfilled_buffer = output.unfilled_to(length);

ts_request
Expand Down
5 changes: 3 additions & 2 deletions crates/ironrdp-client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::Arc;

use anyhow::Context as _;
use ironrdp_cfg::PropertySetExt as _;
use ironrdp_connector::credssp::KdcResolution;
use ironrdp_propertyset::PropertySet;
use ironrdp_rail::pdu::ExecutePdu;
use url::Url;
Expand Down Expand Up @@ -1340,7 +1341,7 @@ impl ConfigBuilder {
/// has no KDC proxy URL); `hostname` is derived from the client name and not stored separately.
#[must_use]
pub fn with_kerberos_config(mut self, cfg: ironrdp_connector::credssp::KerberosConfig) -> Self {
if let Some(url) = &cfg.kdc_proxy_url {
if let KdcResolution::KdcUrl(Some(url)) = &cfg.kdc_resolution {
self.properties.set_kdc_proxy_url(url.to_string());
} else {
self.properties.clear_kdc_proxy_url();
Expand Down Expand Up @@ -2381,7 +2382,7 @@ fn kerberos_config_from_properties(
Url::parse(&kdc_proxy_url)
.ok()
.map(|url| ironrdp_connector::credssp::KerberosConfig {
kdc_proxy_url: Some(url),
kdc_resolution: KdcResolution::KdcUrl(Some(url)),
hostname: client_name.to_owned(),
})
}
Expand Down
4 changes: 2 additions & 2 deletions crates/ironrdp-connector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ ironrdp-svc = { path = "../ironrdp-svc", version = "0.8" } # public
ironrdp-core = { path = "../ironrdp-core", version = "0.2" } # public
ironrdp-error = { path = "../ironrdp-error", version = "0.2" } # public
ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.9", features = ["std"] } # public
sspi = { version = "0.21", features = ["scard"] }
sspi = { version = "0.22", features = ["scard"] }
url = "2.5" # public
rand = { version = "0.9", features = ["std"] } # TODO: dependency injection?
tracing = { version = "0.1", features = ["log"] }
picky-asn1-der = "0.5"
picky-asn1-x509 = "0.15"
picky = "=7.0.0-rc.25" # FIXME: We are pinning with = because the candidate version number counts as the minor number by Cargo, and will be automatically bumped in the Cargo.lock.
picky = "=7.0.0-rc.26" # FIXME: We are pinning with = because the candidate version number counts as the minor number by Cargo, and will be automatically bumped in the Cargo.lock.

[lints]
workspace = true
35 changes: 30 additions & 5 deletions crates/ironrdp-connector/src/credssp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,54 @@ use crate::{
ConnectorError, ConnectorErrorKind, ConnectorResult, Credentials, ServerName, Written, custom_err, general_err,
};

/// Strategy for resolving the KDC to use for Kerberos authentication.
#[derive(Debug, Clone)]
pub enum KdcResolution {
/// Use IAKerb extension to proxy KDC communication through the server to the LocalKDC.
IAKerb,
/// External KDC URL.
KdcUrl(Option<url::Url>),
}

impl From<KdcResolution> for sspi::KdcResolution {
fn from(val: KdcResolution) -> Self {
match val {
KdcResolution::IAKerb => sspi::KdcResolution::IAKerb,
KdcResolution::KdcUrl(url) => sspi::KdcResolution::KdcUrl(url),
}
}
}

#[derive(Debug, Clone)]
pub struct KerberosConfig {
pub kdc_proxy_url: Option<url::Url>,
pub kdc_resolution: KdcResolution,
pub hostname: String,
}

impl KerberosConfig {
pub fn new(kdc_proxy_url: Option<String>, hostname: String) -> ConnectorResult<Self> {
pub fn new_with_kdc_url(kdc_proxy_url: Option<String>, hostname: String) -> ConnectorResult<Self> {
let kdc_proxy_url = kdc_proxy_url
.map(|url| url::Url::parse(&url))
.transpose()
.map_err(|e| custom_err!("invalid KDC URL", e))?;
Ok(Self {
kdc_proxy_url,
kdc_resolution: KdcResolution::KdcUrl(kdc_proxy_url),
hostname,
})
}

pub fn new_with_iakerb(hostname: String) -> Self {
Self {
kdc_resolution: KdcResolution::IAKerb,
hostname,
}
}
}

impl From<KerberosConfig> for sspi::KerberosConfig {
fn from(val: KerberosConfig) -> Self {
sspi::KerberosConfig {
kdc_url: val.kdc_proxy_url,
kdc_resolution: val.kdc_resolution.into(),
client_computer_name: val.hostname,
}
}
Expand Down Expand Up @@ -262,7 +287,7 @@ fn extract_user_principal_name(cert: &Certificate) -> Option<String> {
}

fn write_credssp_request(ts_request: credssp::TsRequest, output: &mut WriteBuf) -> ConnectorResult<usize> {
let length = usize::from(ts_request.buffer_len());
let length = usize::from(ts_request.buffer_len().map_err(|e| custom_err!("TsRequest", e))?);

let unfilled_buffer = output.unfilled_to(length);

Expand Down
4 changes: 2 additions & 2 deletions crates/ironrdp-mstsgu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ ironrdp-core = { path = "../ironrdp-core", version = "0.2", features = ["std"] }
ironrdp-error = { path = "../ironrdp-error", version = "0.2" }
ironrdp-tls = { path = "../ironrdp-tls", version = "0.2.2" } # public
log = "0.4"
sspi = { version = "0.21", features = ["network_client"] }
sspi = { version = "0.22", features = ["network_client"] }
tokio-tungstenite = { version = "0.29" }
tokio-util = { version = "0.7" }
tokio = { version = "1.52", features = ["macros", "rt", "io-util"] }
tokio-socks = "0.5.3"
uuid = { version = "1", features = ["v4"] } # public, exposed by RpcSyntaxIdentifier
picky = { version = "=7.0.0-rc.25", optional = true }
picky = { version = "=7.0.0-rc.26", optional = true }
picky-asn1-der = { version = "0.5", optional = true }
picky-asn1-x509 = { version = "0.15", optional = true }

Expand Down
9 changes: 5 additions & 4 deletions crates/ironrdp-testsuite-extra/tests/client/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;

use std::sync::Arc;

use ironrdp::connector::sspi::KdcResolution;
#[cfg(windows)]
use ironrdp_cfg::GatewayCredentialsSource;
use ironrdp_cfg::PropertySetExt as _;
Expand Down Expand Up @@ -435,10 +436,10 @@ fn kdc_proxy_name_is_normalized_to_https_url() {
);

let kerberos = config.kerberos_config().expect("kerberos config should be present");
let kdc_proxy_url = kerberos
.kdc_proxy_url
.as_ref()
.expect("kdc proxy url should be present");
let kdc_proxy_url = match &kerberos.kdc_resolution {
KdcResolution::KdcUrl(Some(url)) => url,
_ => panic!("kdc proxy url should be present"),
};
assert_eq!(kdc_proxy_url.as_str(), "https://kdc.example.com/KdcProxy");
}

Expand Down
21 changes: 10 additions & 11 deletions crates/ironrdp-web/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ use core::time::Duration;
use std::borrow::Cow;
use std::rc::Rc;

use crate::canvas::Canvas;
use crate::clipboard;
use crate::clipboard::{ClipboardData, FileMetadata, WasmClipboard, WasmClipboardBackend, WasmClipboardBackendMessage};
use crate::error::IronError;
use crate::image::extract_partial_image;
use crate::input::InputTransaction;
use crate::network_client::WasmNetworkClient;
use crate::printer::{JsPrinterStreamCallbacks, WasmPrinter, WasmPrinterBackend, wasm_printer_pair};
use anyhow::Context as _;
use base64::Engine as _;
use futures_channel::mpsc;
Expand All @@ -18,7 +26,7 @@ use ironrdp::cliprdr::CliprdrClient;
use ironrdp::cliprdr::backend::ClipboardMessage;
use ironrdp::cliprdr::pdu::{FileContentsFlags, FileContentsRequest, FileContentsResponse, FileDescriptor};
use ironrdp::connector::connection_activation::ConnectionActivationState;
use ironrdp::connector::credssp::KerberosConfig;
use ironrdp::connector::credssp::{KdcResolution, KerberosConfig};
use ironrdp::connector::{self, ClientConnector, Credentials};
use ironrdp::displaycontrol::client::DisplayControlClient;
use ironrdp::dvc::DrdynvcClient;
Expand All @@ -40,15 +48,6 @@ use wasm_bindgen::{JsCast as _, JsValue};
use wasm_bindgen_futures::spawn_local;
use web_sys::HtmlCanvasElement;

use crate::canvas::Canvas;
use crate::clipboard;
use crate::clipboard::{ClipboardData, FileMetadata, WasmClipboard, WasmClipboardBackend, WasmClipboardBackendMessage};
use crate::error::IronError;
use crate::image::extract_partial_image;
use crate::input::InputTransaction;
use crate::network_client::WasmNetworkClient;
use crate::printer::{JsPrinterStreamCallbacks, WasmPrinter, WasmPrinterBackend, wasm_printer_pair};

const DEFAULT_WIDTH: u16 = 1280;
const DEFAULT_HEIGHT: u16 = 720;

Expand Down Expand Up @@ -1670,7 +1669,7 @@ async fn connect(
let kerberos_config = url::Url::parse(kdc_proxy_url.unwrap_or_default().as_str())
.ok()
.map(|url| KerberosConfig {
kdc_proxy_url: Some(url),
kdc_resolution: KdcResolution::KdcUrl(Some(url)),
// HACK: It's supposed to be the computer name of the client, but since it's not easy to retrieve this information in the browser,
// we set the destination hostname instead because it happens to work.
hostname: destination.clone(),
Expand Down
2 changes: 1 addition & 1 deletion crates/ironrdp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async-trait = "0.1"
image = { version = "0.25", default-features = false, features = ["png"] }
pico-args = "0.5"
x509-cert = { version = "0.3", default-features = false, features = ["std"] }
sspi = { version = "0.21", features = ["network_client"] }
sspi = { version = "0.22", features = ["network_client"] }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tokio = { version = "1", features = ["macros", "rt", "sync", "time"] }
Expand Down
2 changes: 1 addition & 1 deletion ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ironrdp-dvc-pipe-proxy.path = "../crates/ironrdp-dvc-pipe-proxy"
ironrdp-core = { path = "../crates/ironrdp-core", features = ["alloc"] }
ironrdp-vmconnect = { path = "../crates/ironrdp-vmconnect" }
ironrdp-rdcleanpath.path = "../crates/ironrdp-rdcleanpath"
sspi = { version = "0.21", features = ["network_client"] }
sspi = { version = "0.22", features = ["network_client"] }
thiserror = "2"
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
Expand Down
Loading