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