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 {
36 assert!(connector.should_perform_security_upgrade());
37 ShouldUpgrade
38}
39
40#[non_exhaustive]
41pub struct Upgraded;
42
43#[instrument(skip_all)]
44pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Upgraded {
45 trace!("Marked as upgraded");
46 connector.mark_security_upgrade_as_done();
47 Upgraded
48}
49
50#[instrument(skip_all)]
51pub fn connect_finalize<S>(
52 _: Upgraded,
53 framed: &mut Framed<S>,
54 mut connector: ClientConnector,
55 server_name: ServerName,
56 server_public_key: Vec<u8>,
57 network_client: &mut impl NetworkClient,
58 kerberos_config: Option<KerberosConfig>,
59) -> ConnectorResult<ConnectionResult>
60where
61 S: Read + Write,
62{
63 let mut buf = WriteBuf::new();
64
65 debug!("CredSSP procedure");
66
67 if connector.should_perform_credssp() {
68 perform_credssp_step(
69 framed,
70 &mut connector,
71 &mut buf,
72 server_name,
73 server_public_key,
74 network_client,
75 kerberos_config,
76 )?;
77 }
78
79 debug!("Remaining of connection sequence");
80
81 let result = loop {
82 single_sequence_step(framed, &mut connector, &mut buf)?;
83
84 if let ClientConnectorState::Connected { result } = connector.state {
85 break result;
86 }
87 };
88
89 info!("Connected with success");
90
91 Ok(result)
92}
93
94fn resolve_generator(
95 generator: &mut CredsspProcessGenerator<'_>,
96 network_client: &mut impl NetworkClient,
97) -> ConnectorResult<ClientState> {
98 let mut state = generator.start();
99
100 loop {
101 match state {
102 GeneratorState::Suspended(request) => {
103 let response = network_client.send(&request).unwrap();
104 state = generator.resume(Ok(response));
105 }
106 GeneratorState::Completed(client_state) => {
107 break client_state
108 .map_err(|e| ConnectorError::new("CredSSP", ironrdp_connector::ConnectorErrorKind::Credssp(e)))
109 }
110 }
111 }
112}
113
114#[instrument(level = "trace", skip_all)]
115fn perform_credssp_step<S>(
116 framed: &mut Framed<S>,
117 connector: &mut ClientConnector,
118 buf: &mut WriteBuf,
119 server_name: ServerName,
120 server_public_key: Vec<u8>,
121 network_client: &mut impl NetworkClient,
122 kerberos_config: Option<KerberosConfig>,
123) -> ConnectorResult<()>
124where
125 S: Read + Write,
126{
127 assert!(connector.should_perform_credssp());
128
129 let selected_protocol = match connector.state {
130 ClientConnectorState::Credssp { selected_protocol, .. } => selected_protocol,
131 _ => return Err(general_err!("invalid connector state for CredSSP sequence")),
132 };
133
134 let (mut sequence, mut ts_request) = CredsspSequence::init(
135 connector.config.credentials.clone(),
136 connector.config.domain.as_deref(),
137 selected_protocol,
138 server_name,
139 server_public_key,
140 kerberos_config,
141 )?;
142
143 loop {
144 let client_state = {
145 let mut generator = sequence.process_ts_request(ts_request);
146 resolve_generator(&mut generator, network_client)?
147 }; buf.clear();
150 let written = sequence.handle_process_result(client_state, buf)?;
151
152 if let Some(response_len) = written.size() {
153 let response = &buf[..response_len];
154 trace!(response_len, "Send response");
155 framed
156 .write_all(response)
157 .map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
158 }
159
160 let Some(next_pdu_hint) = sequence.next_pdu_hint() else {
161 break;
162 };
163
164 debug!(
165 connector.state = connector.state.name(),
166 hint = ?next_pdu_hint,
167 "Wait for PDU"
168 );
169
170 let pdu = framed
171 .read_by_hint(next_pdu_hint)
172 .map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
173
174 trace!(length = pdu.len(), "PDU received");
175
176 if let Some(next_request) = sequence.decode_server_message(&pdu)? {
177 ts_request = next_request;
178 } else {
179 break;
180 }
181 }
182
183 connector.mark_credssp_as_done();
184
185 Ok(())
186}
187
188pub fn single_sequence_step<S>(
189 framed: &mut Framed<S>,
190 connector: &mut ClientConnector,
191 buf: &mut WriteBuf,
192) -> ConnectorResult<()>
193where
194 S: Read + Write,
195{
196 buf.clear();
197
198 let written = if let Some(next_pdu_hint) = connector.next_pdu_hint() {
199 debug!(
200 connector.state = connector.state.name(),
201 hint = ?next_pdu_hint,
202 "Wait for PDU"
203 );
204
205 let pdu = framed
206 .read_by_hint(next_pdu_hint)
207 .map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
208
209 trace!(length = pdu.len(), "PDU received");
210
211 connector.step(&pdu, buf)?
212 } else {
213 connector.step_no_input(buf)?
214 };
215
216 if let Some(response_len) = written.size() {
217 let response = &buf[..response_len];
218 trace!(response_len, "Send response");
219 framed
220 .write_all(response)
221 .map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
222 }
223
224 Ok(())
225}