Skip to content

Commit 08e16f8

Browse files
Add vmconnect support to RDP clients
1 parent d3e0cb1 commit 08e16f8

File tree

46 files changed

+2215
-514
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2215
-514
lines changed

Cargo.lock

Lines changed: 29 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,4 @@ opt-level = 3
210210
# FIXME: We need to catch up with Diplomat upstream again, but this is a significant amount of work.
211211
# In the meantime, we use this forked version which fixes an undefined behavior in the code expanded by the bridge macro.
212212
diplomat = { git = "https://github.com/CBenoit/diplomat", rev = "6dc806e80162b6b39509a04a2835744236cd2396" }
213+
sspi = { git = "https://github.com/Devolutions/sspi-rs.git", rev = "370951c1b017bfef4276185b374345e8b6b1e532" }

crates/iron-remote-desktop/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ macro_rules! make_bridge {
437437

438438
#[doc(hidden)]
439439
pub mod internal {
440+
use tracing::Level;
440441
#[doc(hidden)]
441442
pub use wasm_bindgen;
442443
#[doc(hidden)]
@@ -458,7 +459,8 @@ pub mod internal {
458459
}
459460
}
460461

461-
fn set_logger_once(level: tracing::Level) {
462+
fn set_logger_once(_level: tracing::Level) {
463+
use tracing::Level;
462464
use tracing_subscriber::filter::LevelFilter;
463465
use tracing_subscriber::fmt::time::UtcTime;
464466
use tracing_subscriber::prelude::*;
@@ -472,7 +474,7 @@ pub mod internal {
472474
.with_timer(UtcTime::rfc_3339()) // std::time is not available in browsers
473475
.with_writer(MakeConsoleWriter);
474476

475-
let level_filter = LevelFilter::from_level(level);
477+
let level_filter = LevelFilter::from_level(Level::TRACE);
476478

477479
tracing_subscriber::registry().with(fmt_layer).with(level_filter).init();
478480
})

crates/ironrdp-async/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ test = false
1717

1818
[dependencies]
1919
ironrdp-connector = { path = "../ironrdp-connector", version = "0.7" } # public
20+
ironrdp-vmconnect = { path = "../ironrdp-vmconnect", version = "0.1" } # public
2021
ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] } # public
2122
ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public
2223
tracing = { version = "0.1", features = ["log"] }

crates/ironrdp-async/src/connector.rs

Lines changed: 87 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use ironrdp_connector::credssp::{CredsspProcessGenerator, CredsspSequence, KerberosConfig};
1+
use ironrdp_connector::credssp::{CredsspProcessGenerator, KerberosConfig};
22
use ironrdp_connector::sspi::credssp::ClientState;
33
use ironrdp_connector::sspi::generator::GeneratorState;
44
use ironrdp_connector::{
5-
custom_err, general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorError, ConnectorResult,
6-
ServerName, State as _,
5+
custom_err, general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorCore, ConnectorError,
6+
ConnectorResult, SecurityConnector, ServerName,
77
};
88
use ironrdp_core::WriteBuf;
99
use tracing::{debug, info, instrument, trace};
@@ -15,7 +15,10 @@ use crate::{single_sequence_step, AsyncNetworkClient};
1515
pub struct ShouldUpgrade;
1616

1717
#[instrument(skip_all)]
18-
pub async fn connect_begin<S>(framed: &mut Framed<S>, connector: &mut ClientConnector) -> ConnectorResult<ShouldUpgrade>
18+
pub async fn connect_begin<S>(
19+
framed: &mut Framed<S>,
20+
connector: &mut dyn ConnectorCore,
21+
) -> ConnectorResult<ShouldUpgrade>
1922
where
2023
S: Sync + FramedRead + FramedWrite,
2124
{
@@ -33,7 +36,7 @@ where
3336
/// # Panics
3437
///
3538
/// Panics if connector state is not [ClientConnectorState::EnhancedSecurityUpgrade].
36-
pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade {
39+
pub fn skip_connect_begin(connector: &mut dyn SecurityConnector) -> ShouldUpgrade {
3740
assert!(connector.should_perform_security_upgrade());
3841
ShouldUpgrade
3942
}
@@ -42,22 +45,26 @@ pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade {
4245
pub struct Upgraded;
4346

4447
#[instrument(skip_all)]
45-
pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Upgraded {
48+
pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut dyn SecurityConnector) -> Upgraded {
4649
trace!("Marked as upgraded");
4750
connector.mark_security_upgrade_as_done();
4851
Upgraded
4952
}
5053

51-
#[instrument(skip_all)]
52-
pub async fn connect_finalize<S>(
54+
#[non_exhaustive]
55+
pub struct CredSSPFinished {
56+
pub(crate) write_buf: WriteBuf,
57+
}
58+
59+
pub async fn perform_credssp<S>(
5360
_: Upgraded,
61+
connector: &mut dyn ConnectorCore,
5462
framed: &mut Framed<S>,
55-
mut connector: ClientConnector,
5663
server_name: ServerName,
5764
server_public_key: Vec<u8>,
5865
network_client: Option<&mut dyn AsyncNetworkClient>,
5966
kerberos_config: Option<KerberosConfig>,
60-
) -> ConnectorResult<ConnectionResult>
67+
) -> ConnectorResult<CredSSPFinished>
6168
where
6269
S: FramedRead + FramedWrite,
6370
{
@@ -66,7 +73,7 @@ where
6673
if connector.should_perform_credssp() {
6774
perform_credssp_step(
6875
framed,
69-
&mut connector,
76+
connector,
7077
&mut buf,
7178
server_name,
7279
server_public_key,
@@ -76,6 +83,19 @@ where
7683
.await?;
7784
}
7885

86+
Ok(CredSSPFinished { write_buf: buf })
87+
}
88+
89+
#[instrument(skip_all)]
90+
pub async fn connect_finalize<S>(
91+
CredSSPFinished { write_buf: mut buf }: CredSSPFinished,
92+
framed: &mut Framed<S>,
93+
mut connector: ClientConnector,
94+
) -> ConnectorResult<ConnectionResult>
95+
where
96+
S: FramedRead + FramedWrite,
97+
{
98+
buf.clear();
7999
let result = loop {
80100
single_sequence_step(framed, &mut connector, &mut buf).await?;
81101

@@ -112,7 +132,7 @@ async fn resolve_generator(
112132
#[instrument(level = "trace", skip_all)]
113133
async fn perform_credssp_step<S>(
114134
framed: &mut Framed<S>,
115-
connector: &mut ClientConnector,
135+
connector: &mut dyn ConnectorCore,
116136
buf: &mut WriteBuf,
117137
server_name: ServerName,
118138
server_public_key: Vec<u8>,
@@ -124,70 +144,70 @@ where
124144
{
125145
assert!(connector.should_perform_credssp());
126146

127-
let selected_protocol = match connector.state {
128-
ClientConnectorState::Credssp { selected_protocol, .. } => selected_protocol,
129-
_ => return Err(general_err!("invalid connector state for CredSSP sequence")),
130-
};
131-
132-
let (mut sequence, mut ts_request) = CredsspSequence::init(
133-
connector.config.credentials.clone(),
134-
connector.config.domain.as_deref(),
135-
selected_protocol,
136-
server_name,
137-
server_public_key,
138-
kerberos_config,
139-
)?;
140-
141-
loop {
142-
let client_state = {
143-
let mut generator = sequence.process_ts_request(ts_request);
147+
let selected_protocol = connector
148+
.selected_protocol()
149+
.ok_or_else(|| general_err!("CredSSP protocol not selected, cannot perform CredSSP step"))?;
144150

145-
if let Some(network_client_ref) = network_client.as_deref_mut() {
146-
trace!("resolving network");
147-
resolve_generator(&mut generator, network_client_ref).await?
148-
} else {
149-
generator
150-
.resolve_to_result()
151-
.map_err(|e| custom_err!("resolve without network client", e))?
151+
{
152+
let (mut sequence, mut ts_request) = connector.init_credssp(
153+
connector.config().credentials.clone(),
154+
connector.config().domain.as_deref(),
155+
selected_protocol,
156+
server_name,
157+
server_public_key,
158+
kerberos_config,
159+
)?;
160+
161+
loop {
162+
let client_state = {
163+
let mut generator = sequence.process_ts_request(ts_request);
164+
165+
if let Some(network_client_ref) = network_client.as_deref_mut() {
166+
trace!("resolving network");
167+
resolve_generator(&mut generator, network_client_ref).await?
168+
} else {
169+
generator
170+
.resolve_to_result()
171+
.map_err(|e| custom_err!("resolve without network client", e))?
172+
}
173+
}; // drop generator
174+
175+
buf.clear();
176+
let written = sequence.handle_process_result(client_state, buf)?;
177+
178+
if let Some(response_len) = written.size() {
179+
let response = &buf[..response_len];
180+
trace!(response_len, "Send response");
181+
framed
182+
.write_all(response)
183+
.await
184+
.map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
152185
}
153-
}; // drop generator
154186

155-
buf.clear();
156-
let written = sequence.handle_process_result(client_state, buf)?;
187+
let Some(next_pdu_hint) = sequence.next_pdu_hint() else {
188+
break;
189+
};
157190

158-
if let Some(response_len) = written.size() {
159-
let response = &buf[..response_len];
160-
trace!(response_len, "Send response");
161-
framed
162-
.write_all(response)
163-
.await
164-
.map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
165-
}
166-
167-
let Some(next_pdu_hint) = sequence.next_pdu_hint() else {
168-
break;
169-
};
170-
171-
debug!(
172-
connector.state = connector.state.name(),
173-
hint = ?next_pdu_hint,
174-
"Wait for PDU"
175-
);
191+
debug!(
192+
connector.state = connector.state().name(),
193+
hint = ?next_pdu_hint,
194+
"Wait for PDU"
195+
);
176196

177-
let pdu = framed
178-
.read_by_hint(next_pdu_hint)
179-
.await
180-
.map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
197+
let pdu = framed
198+
.read_by_hint(next_pdu_hint)
199+
.await
200+
.map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
181201

182-
trace!(length = pdu.len(), "PDU received");
202+
trace!(length = pdu.len(), "PDU received");
183203

184-
if let Some(next_request) = sequence.decode_server_message(&pdu)? {
185-
ts_request = next_request;
186-
} else {
187-
break;
204+
if let Some(next_request) = sequence.decode_server_message(&pdu)? {
205+
ts_request = next_request;
206+
} else {
207+
break;
208+
}
188209
}
189210
}
190-
191211
connector.mark_credssp_as_done();
192212

193213
Ok(())

crates/ironrdp-async/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub use bytes;
66
mod connector;
77
mod framed;
88
mod session;
9+
mod vmconnector;
910

1011
use core::future::Future;
1112
use core::pin::Pin;
@@ -15,7 +16,7 @@ use ironrdp_connector::ConnectorResult;
1516

1617
pub use self::connector::*;
1718
pub use self::framed::*;
18-
// pub use self::session::*;
19+
pub use self::vmconnector::*;
1920

2021
pub trait AsyncNetworkClient {
2122
fn send<'a>(

0 commit comments

Comments
 (0)