ironrdp_async/
connector.rs1use ironrdp_connector::credssp::{CredsspProcessGenerator, CredsspSequence, KerberosConfig};
2use ironrdp_connector::sspi::credssp::ClientState;
3use ironrdp_connector::sspi::generator::GeneratorState;
4use ironrdp_connector::{
5 custom_err, general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorError, ConnectorResult,
6 ServerName, State as _,
7};
8use ironrdp_core::WriteBuf;
9
10use crate::framed::{Framed, FramedRead, FramedWrite};
11use crate::{single_sequence_step, AsyncNetworkClient};
12
13#[non_exhaustive]
14pub struct ShouldUpgrade;
15
16#[instrument(skip_all)]
17pub async fn connect_begin<S>(framed: &mut Framed<S>, connector: &mut ClientConnector) -> ConnectorResult<ShouldUpgrade>
18where
19 S: Sync + FramedRead + FramedWrite,
20{
21 let mut buf = WriteBuf::new();
22
23 info!("Begin connection procedure");
24
25 while !connector.should_perform_security_upgrade() {
26 single_sequence_step(framed, connector, &mut buf).await?;
27 }
28
29 Ok(ShouldUpgrade)
30}
31
32pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade {
33 assert!(connector.should_perform_security_upgrade());
34 ShouldUpgrade
35}
36
37#[non_exhaustive]
38pub struct Upgraded;
39
40#[instrument(skip_all)]
41pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Upgraded {
42 trace!("Marked as upgraded");
43 connector.mark_security_upgrade_as_done();
44 Upgraded
45}
46
47#[instrument(skip_all)]
48pub async fn connect_finalize<S>(
49 _: Upgraded,
50 framed: &mut Framed<S>,
51 mut connector: ClientConnector,
52 server_name: ServerName,
53 server_public_key: Vec<u8>,
54 network_client: Option<&mut dyn AsyncNetworkClient>,
55 kerberos_config: Option<KerberosConfig>,
56) -> ConnectorResult<ConnectionResult>
57where
58 S: FramedRead + FramedWrite,
59{
60 let mut buf = WriteBuf::new();
61
62 if connector.should_perform_credssp() {
63 perform_credssp_step(
64 framed,
65 &mut connector,
66 &mut buf,
67 server_name,
68 server_public_key,
69 network_client,
70 kerberos_config,
71 )
72 .await?;
73 }
74
75 let result = loop {
76 single_sequence_step(framed, &mut connector, &mut buf).await?;
77
78 if let ClientConnectorState::Connected { result } = connector.state {
79 break result;
80 }
81 };
82
83 info!("Connected with success");
84
85 Ok(result)
86}
87
88async fn resolve_generator(
89 generator: &mut CredsspProcessGenerator<'_>,
90 network_client: &mut dyn AsyncNetworkClient,
91) -> ConnectorResult<ClientState> {
92 let mut state = generator.start();
93
94 loop {
95 match state {
96 GeneratorState::Suspended(request) => {
97 let response = network_client.send(&request).await?;
98 state = generator.resume(Ok(response));
99 }
100 GeneratorState::Completed(client_state) => {
101 break client_state
102 .map_err(|e| ConnectorError::new("CredSSP", ironrdp_connector::ConnectorErrorKind::Credssp(e)))
103 }
104 }
105 }
106}
107
108#[instrument(level = "trace", skip_all)]
109async fn perform_credssp_step<S>(
110 framed: &mut Framed<S>,
111 connector: &mut ClientConnector,
112 buf: &mut WriteBuf,
113 server_name: ServerName,
114 server_public_key: Vec<u8>,
115 mut network_client: Option<&mut dyn AsyncNetworkClient>,
116 kerberos_config: Option<KerberosConfig>,
117) -> ConnectorResult<()>
118where
119 S: FramedRead + FramedWrite,
120{
121 assert!(connector.should_perform_credssp());
122
123 let selected_protocol = match connector.state {
124 ClientConnectorState::Credssp { selected_protocol, .. } => selected_protocol,
125 _ => return Err(general_err!("invalid connector state for CredSSP sequence")),
126 };
127
128 let (mut sequence, mut ts_request) = CredsspSequence::init(
129 connector.config.credentials.clone(),
130 connector.config.domain.as_deref(),
131 selected_protocol,
132 server_name,
133 server_public_key,
134 kerberos_config,
135 )?;
136
137 loop {
138 let client_state = {
139 let mut generator = sequence.process_ts_request(ts_request);
140
141 if let Some(network_client_ref) = network_client.as_deref_mut() {
142 trace!("resolving network");
143 resolve_generator(&mut generator, network_client_ref).await?
144 } else {
145 generator
146 .resolve_to_result()
147 .map_err(|e| custom_err!("resolve without network client", e))?
148 }
149 }; buf.clear();
152 let written = sequence.handle_process_result(client_state, buf)?;
153
154 if let Some(response_len) = written.size() {
155 let response = &buf[..response_len];
156 trace!(response_len, "Send response");
157 framed
158 .write_all(response)
159 .await
160 .map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
161 }
162
163 let Some(next_pdu_hint) = sequence.next_pdu_hint() else {
164 break;
165 };
166
167 debug!(
168 connector.state = connector.state.name(),
169 hint = ?next_pdu_hint,
170 "Wait for PDU"
171 );
172
173 let pdu = framed
174 .read_by_hint(next_pdu_hint)
175 .await
176 .map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
177
178 trace!(length = pdu.len(), "PDU received");
179
180 if let Some(next_request) = sequence.decode_server_message(&pdu)? {
181 ts_request = next_request;
182 } else {
183 break;
184 }
185 }
186
187 connector.mark_credssp_as_done();
188
189 Ok(())
190}