ironrdp_blocking/
connector.rs1use std::io::{Read, Write};
2
3use ironrdp_connector::credssp::{CredsspProcessGenerator, CredsspSequence, KerberosConfig};
4use ironrdp_connector::sspi::credssp::ClientState;
5use ironrdp_connector::sspi::generator::GeneratorState;
6use ironrdp_connector::sspi::network_client::NetworkClient;
7use ironrdp_connector::{
8 general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorError, ConnectorResult,
9 Sequence as _, ServerName, State as _,
10};
11use ironrdp_core::WriteBuf;
12use tracing::{debug, info, instrument, trace};
13
14use crate::framed::Framed;
15
16#[non_exhaustive]
17pub struct ShouldUpgrade;
18
19#[instrument(skip_all)]
20pub fn connect_begin<S>(framed: &mut Framed<S>, connector: &mut ClientConnector) -> ConnectorResult<ShouldUpgrade>
21where
22 S: Sync + Read + Write,
23{
24 let mut buf = WriteBuf::new();
25
26 info!("Begin connection procedure");
27
28 while !connector.should_perform_security_upgrade() {
29 single_sequence_step(framed, connector, &mut buf)?;
30 }
31
32 Ok(ShouldUpgrade)
33}
34
35pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade {
39 assert!(connector.should_perform_security_upgrade());
40 ShouldUpgrade
41}
42
43#[non_exhaustive]
44pub struct Upgraded;
45
46#[instrument(skip_all)]
47pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Upgraded {
48 trace!("Marked as upgraded");
49 connector.mark_security_upgrade_as_done();
50 Upgraded
51}
52
53#[instrument(skip_all)]
54pub fn connect_finalize<S>(
55 _: Upgraded,
56 mut connector: ClientConnector,
57 framed: &mut Framed<S>,
58 network_client: &mut impl NetworkClient,
59 server_name: ServerName,
60 server_public_key: Vec<u8>,
61 kerberos_config: Option<KerberosConfig>,
62) -> ConnectorResult<ConnectionResult>
63where
64 S: Read + Write,
65{
66 let mut buf = WriteBuf::new();
67
68 debug!("CredSSP procedure");
69
70 if connector.should_perform_credssp() {
71 perform_credssp_step(
72 &mut connector,
73 framed,
74 network_client,
75 &mut buf,
76 server_name,
77 server_public_key,
78 kerberos_config,
79 )?;
80 }
81
82 debug!("Remaining of connection sequence");
83
84 let result = loop {
85 single_sequence_step(framed, &mut connector, &mut buf)?;
86
87 if let ClientConnectorState::Connected { result } = connector.state {
88 break result;
89 }
90 };
91
92 info!("Connected with success");
93
94 Ok(result)
95}
96
97fn resolve_generator(
98 generator: &mut CredsspProcessGenerator<'_>,
99 network_client: &mut impl NetworkClient,
100) -> ConnectorResult<ClientState> {
101 let mut state = generator.start();
102
103 loop {
104 match state {
105 GeneratorState::Suspended(request) => {
106 let response = network_client.send(&request).map_err(|e| {
107 ConnectorError::new("network client send", ironrdp_connector::ConnectorErrorKind::Credssp(e))
108 })?;
109 state = generator.resume(Ok(response));
110 }
111 GeneratorState::Completed(client_state) => {
112 break client_state
113 .map_err(|e| ConnectorError::new("CredSSP", ironrdp_connector::ConnectorErrorKind::Credssp(e)))
114 }
115 }
116 }
117}
118
119#[instrument(level = "trace", skip_all)]
120fn perform_credssp_step<S>(
121 connector: &mut ClientConnector,
122 framed: &mut Framed<S>,
123 network_client: &mut impl NetworkClient,
124 buf: &mut WriteBuf,
125 server_name: ServerName,
126 server_public_key: Vec<u8>,
127 kerberos_config: Option<KerberosConfig>,
128) -> ConnectorResult<()>
129where
130 S: Read + Write,
131{
132 assert!(connector.should_perform_credssp());
133
134 let selected_protocol = match connector.state {
135 ClientConnectorState::Credssp { selected_protocol, .. } => selected_protocol,
136 _ => return Err(general_err!("invalid connector state for CredSSP sequence")),
137 };
138
139 let (mut sequence, mut ts_request) = CredsspSequence::init(
140 connector.config.credentials.clone(),
141 connector.config.domain.as_deref(),
142 selected_protocol,
143 server_name,
144 server_public_key,
145 kerberos_config,
146 )?;
147
148 loop {
149 let client_state = {
150 let mut generator = sequence.process_ts_request(ts_request);
151 resolve_generator(&mut generator, network_client)?
152 }; buf.clear();
155 let written = sequence.handle_process_result(client_state, buf)?;
156
157 if let Some(response_len) = written.size() {
158 let response = &buf[..response_len];
159 trace!(response_len, "Send response");
160 framed
161 .write_all(response)
162 .map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
163 }
164
165 let Some(next_pdu_hint) = sequence.next_pdu_hint() else {
166 break;
167 };
168
169 debug!(
170 connector.state = connector.state.name(),
171 hint = ?next_pdu_hint,
172 "Wait for PDU"
173 );
174
175 let pdu = framed
176 .read_by_hint(next_pdu_hint)
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}
192
193pub fn single_sequence_step<S>(
194 framed: &mut Framed<S>,
195 connector: &mut ClientConnector,
196 buf: &mut WriteBuf,
197) -> ConnectorResult<()>
198where
199 S: Read + Write,
200{
201 buf.clear();
202
203 let written = if let Some(next_pdu_hint) = connector.next_pdu_hint() {
204 debug!(
205 connector.state = connector.state.name(),
206 hint = ?next_pdu_hint,
207 "Wait for PDU"
208 );
209
210 let pdu = framed
211 .read_by_hint(next_pdu_hint)
212 .map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
213
214 trace!(length = pdu.len(), "PDU received");
215
216 connector.step(&pdu, buf)?
217 } else {
218 connector.step_no_input(buf)?
219 };
220
221 if let Some(response_len) = written.size() {
222 let response = &buf[..response_len];
223 trace!(response_len, "Send response");
224 framed
225 .write_all(response)
226 .map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
227 }
228
229 Ok(())
230}