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}