ironrdp_acceptor/
finalization.rs

1use ironrdp_connector::{ConnectorError, ConnectorErrorExt as _, ConnectorResult, Sequence, State, Written};
2use ironrdp_core::WriteBuf;
3use ironrdp_pdu::rdp;
4use ironrdp_pdu::x224::X224;
5use tracing::debug;
6
7use crate::util::{self, wrap_share_data};
8
9#[derive(Debug)]
10pub struct FinalizationSequence {
11    state: FinalizationState,
12    user_channel_id: u16,
13    io_channel_id: u16,
14
15    input_events: Vec<Vec<u8>>,
16}
17
18#[derive(Default, Debug)]
19pub enum FinalizationState {
20    #[default]
21    Consumed,
22
23    WaitSynchronize,
24    WaitControlCooperate,
25    WaitRequestControl,
26    WaitFontList,
27
28    SendSynchronizeConfirm,
29    SendControlCooperateConfirm,
30    SendGrantedControlConfirm,
31    SendFontMap,
32
33    Finished,
34}
35
36impl State for FinalizationState {
37    fn name(&self) -> &'static str {
38        match self {
39            Self::Consumed => "Consumed",
40            Self::WaitSynchronize => "WaitSynchronize",
41            Self::WaitControlCooperate => "WaitControlCooperate",
42            Self::WaitRequestControl => "WaitRequestControl",
43            Self::WaitFontList => "WaitFontList",
44            Self::SendSynchronizeConfirm => "SendSynchronizeConfirm",
45            Self::SendControlCooperateConfirm => "SendControlCooperateConfirm",
46            Self::SendGrantedControlConfirm => "SendGrantedControlConfirm",
47            Self::SendFontMap => "SendFontMap",
48            Self::Finished => "Finished",
49        }
50    }
51
52    fn is_terminal(&self) -> bool {
53        matches!(self, Self::Finished { .. })
54    }
55
56    fn as_any(&self) -> &dyn core::any::Any {
57        self
58    }
59}
60
61impl Sequence for FinalizationSequence {
62    fn next_pdu_hint(&self) -> Option<&dyn ironrdp_pdu::PduHint> {
63        match &self.state {
64            FinalizationState::Consumed => None,
65            FinalizationState::WaitSynchronize => Some(&ironrdp_pdu::X224Hint),
66            FinalizationState::WaitControlCooperate => Some(&ironrdp_pdu::X224Hint),
67            FinalizationState::WaitRequestControl => Some(&ironrdp_pdu::X224Hint),
68            FinalizationState::WaitFontList => Some(&ironrdp_pdu::RdpHint),
69            FinalizationState::SendSynchronizeConfirm => None,
70            FinalizationState::SendControlCooperateConfirm => None,
71            FinalizationState::SendGrantedControlConfirm => None,
72            FinalizationState::SendFontMap => None,
73            FinalizationState::Finished => None,
74        }
75    }
76
77    fn state(&self) -> &dyn State {
78        &self.state
79    }
80
81    fn step(&mut self, input: &[u8], output: &mut WriteBuf) -> ConnectorResult<Written> {
82        let (written, next_state) = match core::mem::take(&mut self.state) {
83            FinalizationState::WaitSynchronize => {
84                let synchronize = decode_share_control(input);
85
86                debug!(message = ?synchronize, "Received");
87
88                (Written::Nothing, FinalizationState::WaitControlCooperate)
89            }
90
91            FinalizationState::WaitControlCooperate => {
92                let cooperate = decode_share_control(input);
93
94                debug!(message = ?cooperate, "Received");
95
96                (Written::Nothing, FinalizationState::WaitRequestControl)
97            }
98
99            FinalizationState::WaitRequestControl => {
100                let control = decode_share_control(input)?;
101
102                debug!(message = ?control, "Received");
103
104                (Written::Nothing, FinalizationState::WaitFontList)
105            }
106
107            FinalizationState::WaitFontList => match decode_font_list(input) {
108                Ok(font_list) => {
109                    debug!(message = ?font_list, "Received");
110
111                    (Written::Nothing, FinalizationState::SendSynchronizeConfirm)
112                }
113
114                Err(()) => {
115                    self.input_events.push(input.to_vec());
116
117                    (Written::Nothing, FinalizationState::WaitFontList)
118                }
119            },
120
121            FinalizationState::SendSynchronizeConfirm => {
122                let synchronize_confirm = create_synchronize_confirm();
123
124                debug!(message = ?synchronize_confirm, "Send");
125
126                let share_data = wrap_share_data(synchronize_confirm, self.io_channel_id);
127                let written =
128                    util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &share_data, output)?;
129
130                (
131                    Written::from_size(written)?,
132                    FinalizationState::SendControlCooperateConfirm,
133                )
134            }
135
136            FinalizationState::SendControlCooperateConfirm => {
137                let cooperate_confirm = create_cooperate_confirm();
138
139                debug!(message = ?cooperate_confirm, "Send");
140
141                let share_data = wrap_share_data(cooperate_confirm, self.io_channel_id);
142                let written =
143                    util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &share_data, output)?;
144
145                (
146                    Written::from_size(written)?,
147                    FinalizationState::SendGrantedControlConfirm,
148                )
149            }
150
151            FinalizationState::SendGrantedControlConfirm => {
152                let control_confirm = create_control_confirm(self.user_channel_id);
153
154                debug!(message = ?control_confirm, "Send");
155
156                let share_data = wrap_share_data(control_confirm, self.io_channel_id);
157                let written =
158                    util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &share_data, output)?;
159
160                (Written::from_size(written)?, FinalizationState::SendFontMap)
161            }
162
163            FinalizationState::SendFontMap => {
164                let font_map = create_font_map();
165
166                debug!(message = ?font_map, "Send");
167
168                let share_data = wrap_share_data(font_map, self.io_channel_id);
169                let written =
170                    util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &share_data, output)?;
171
172                (Written::from_size(written)?, FinalizationState::Finished)
173            }
174
175            _ => unreachable!(),
176        };
177
178        self.state = next_state;
179        Ok(written)
180    }
181}
182
183impl FinalizationSequence {
184    pub fn new(user_channel_id: u16, io_channel_id: u16) -> Self {
185        Self {
186            state: FinalizationState::WaitSynchronize,
187            user_channel_id,
188            io_channel_id,
189            input_events: Vec::new(),
190        }
191    }
192
193    pub fn into_input_events(self) -> Vec<Vec<u8>> {
194        self.input_events
195    }
196
197    pub fn is_done(&self) -> bool {
198        self.state.is_terminal()
199    }
200}
201
202fn create_synchronize_confirm() -> rdp::headers::ShareDataPdu {
203    rdp::headers::ShareDataPdu::Synchronize(rdp::finalization_messages::SynchronizePdu { target_user_id: 0 })
204}
205
206fn create_cooperate_confirm() -> rdp::headers::ShareDataPdu {
207    rdp::headers::ShareDataPdu::Control(rdp::finalization_messages::ControlPdu {
208        action: rdp::finalization_messages::ControlAction::Cooperate,
209        grant_id: 0,
210        control_id: 0,
211    })
212}
213
214fn create_control_confirm(user_id: u16) -> rdp::headers::ShareDataPdu {
215    rdp::headers::ShareDataPdu::Control(rdp::finalization_messages::ControlPdu {
216        action: rdp::finalization_messages::ControlAction::GrantedControl,
217        grant_id: user_id,
218        control_id: u32::from(rdp::capability_sets::SERVER_CHANNEL_ID),
219    })
220}
221
222fn create_font_map() -> rdp::headers::ShareDataPdu {
223    rdp::headers::ShareDataPdu::FontMap(rdp::finalization_messages::FontPdu::default())
224}
225
226fn decode_share_control(input: &[u8]) -> ConnectorResult<rdp::headers::ShareControlHeader> {
227    let data_request = ironrdp_core::decode::<X224<ironrdp_pdu::mcs::SendDataRequest<'_>>>(input)
228        .map_err(ConnectorError::decode)
229        .map(|p| p.0)?;
230    let share_control = ironrdp_core::decode::<rdp::headers::ShareControlHeader>(data_request.user_data.as_ref())
231        .map_err(ConnectorError::decode)?;
232    Ok(share_control)
233}
234
235fn decode_font_list(input: &[u8]) -> Result<rdp::finalization_messages::FontPdu, ()> {
236    use ironrdp_pdu::rdp::headers::{ShareControlPdu, ShareDataPdu};
237
238    let share_control = decode_share_control(input).map_err(|_| ())?;
239
240    let ShareControlPdu::Data(data_pdu) = share_control.share_control_pdu else {
241        return Err(());
242    };
243
244    let ShareDataPdu::FontList(font_pdu) = data_pdu.share_data_pdu else {
245        return Err(());
246    };
247
248    Ok(font_pdu)
249}