ironrdp_async/
connector.rs

1use 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        }; // drop generator
150
151        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}