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;
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        }; // drop generator
151
152        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}