rdp/core/
global.rs

1use core::mcs;
2use core::tpkt;
3use std::io::{Read, Write, Cursor};
4use model::error::{RdpResult, Error, RdpErrorKind, RdpError};
5use model::data::{Component, MessageOption, U32, DynOption, U16, DataType, Message, Array, Trame, Check, to_vec};
6use core::event::{RdpEvent, BitmapEvent};
7use num_enum::TryFromPrimitive;
8use std::convert::TryFrom;
9use core::capability::{Capability, capability_set};
10use core::capability;
11use core::gcc::KeyboardLayout;
12
13
14/// Raw PDU type use by the protocol
15#[repr(u16)]
16#[derive(Copy, Clone, Eq, PartialEq, Debug, TryFromPrimitive)]
17enum PDUType {
18    PdutypeDemandactivepdu = 0x11,
19    PdutypeConfirmactivepdu = 0x13,
20    PdutypeDeactivateallpdu = 0x16,
21    PdutypeDatapdu = 0x17,
22    PdutypeServerRedirPkt = 0x1A
23}
24
25/// PDU type available
26/// Most of them are used for initial handshake
27/// Then once connected only Data are send and received
28struct PDU {
29    pub pdu_type: PDUType,
30    pub message: Component
31}
32
33impl PDU {
34    /// Build a PDU structure from reading stream
35    pub fn from_stream(stream: &mut dyn Read) -> RdpResult<Self> {
36        let mut header = share_control_header(None, None, None);
37        header.read(stream)?;
38        PDU::from_control(&header)
39    }
40
41    /// Build a PDU data directly from a control message
42    pub fn from_control(control: &Component) -> RdpResult<Self> {
43        let pdu_type = cast!(DataType::U16, control["pduType"])?;
44        let mut pdu = match PDUType::try_from(pdu_type)? {
45            PDUType::PdutypeDemandactivepdu => ts_demand_active_pdu(),
46            PDUType::PdutypeDatapdu => share_data_header(None, None, None),
47            PDUType::PdutypeConfirmactivepdu => ts_confirm_active_pdu(None, None, None),
48            PDUType::PdutypeDeactivateallpdu => ts_deactivate_all_pdu(),
49            _ => return Err(Error::RdpError(RdpError::new(RdpErrorKind::NotImplemented, "GLOBAL: PDU not implemented")))
50        };
51        pdu.message.read(&mut Cursor::new(cast!(DataType::Slice, control["pduMessage"])?))?;
52        Ok(pdu)
53    }
54}
55
56/// Demand Active PDU
57/// First PDU send from server to client
58/// This payload include all capabilities
59/// of the target server
60///
61/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/bd612af5-cb54-43a2-9646-438bc3ecf5db
62fn ts_demand_active_pdu() -> PDU {
63    PDU {
64        pdu_type: PDUType::PdutypeDemandactivepdu,
65        message: component![
66            "shareId" => U32::LE(0),
67            "lengthSourceDescriptor" => DynOption::new(U16::LE(0), |length| MessageOption::Size("sourceDescriptor".to_string(), length.inner() as usize)),
68            "lengthCombinedCapabilities" => DynOption::new(U16::LE(0), |length| MessageOption::Size("capabilitySets".to_string(), length.inner() as usize - 4)),
69            "sourceDescriptor" => Vec::<u8>::new(),
70            "numberCapabilities" => U16::LE(0),
71            "pad2Octets" => U16::LE(0),
72            "capabilitySets" => Array::new(|| capability_set(None)),
73            "sessionId" => U32::LE(0)
74        ]
75    }
76}
77
78/// First PDU send from client to server
79/// This PDU declare capabilities for the client
80///
81/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4e9722c3-ad83-43f5-af5a-529f73d88b48
82fn ts_confirm_active_pdu(share_id: Option<u32>, source: Option<Vec<u8>>, capabilities_set: Option<Array<Component>>) -> PDU {
83    let default_capabilities_set = capabilities_set.unwrap_or(Array::new(|| capability_set(None)));
84    let default_source = source.unwrap_or(vec![]);
85    PDU {
86        pdu_type: PDUType::PdutypeConfirmactivepdu,
87        message: component![
88            "shareId" => U32::LE(share_id.unwrap_or(0)),
89            "originatorId" => Check::new(U16::LE(0x03EA)),
90            "lengthSourceDescriptor" => DynOption::new(U16::LE(default_source.len() as u16), |length| MessageOption::Size("sourceDescriptor".to_string(), length.inner() as usize)),
91            "lengthCombinedCapabilities" => DynOption::new(U16::LE(default_capabilities_set.length() as u16 + 4), |length| MessageOption::Size("capabilitySets".to_string(), length.inner() as usize - 4)),
92            "sourceDescriptor" => default_source,
93            "numberCapabilities" => U16::LE(default_capabilities_set.inner().len() as u16),
94            "pad2Octets" => U16::LE(0),
95            "capabilitySets" => default_capabilities_set
96        ]
97    }
98}
99
100/// Use to inform user that a session already exist
101///
102/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/fc191c40-e688-4d5a-a550-6609cd5b8b59
103fn ts_deactivate_all_pdu() -> PDU {
104    PDU {
105        pdu_type: PDUType::PdutypeDeactivateallpdu,
106        message: component![
107            "shareId" => U32::LE(0),
108            "lengthSourceDescriptor" => DynOption::new(U16::LE(0), |length| MessageOption::Size("sourceDescriptor".to_string(), length.inner() as usize)),
109            "sourceDescriptor" => Vec::<u8>::new()
110        ]
111    }
112}
113
114/// All Data PDU share the same layout
115fn share_data_header(share_id: Option<u32>, pdu_type_2: Option<PDUType2>, message: Option<Vec<u8>>) -> PDU {
116    let default_message = message.unwrap_or(vec![]);
117    PDU {
118        pdu_type: PDUType::PdutypeDatapdu,
119        message: component![
120            "shareId" => U32::LE(share_id.unwrap_or(0)),
121            "pad1" => 0 as u8,
122            "streamId" => 1 as u8,
123            "uncompressedLength" => DynOption::new(U16::LE(default_message.length() as u16 + 18), | size | MessageOption::Size("payload".to_string(), size.inner() as usize - 18)),
124            "pduType2" => pdu_type_2.unwrap_or(PDUType2::Pdutype2ArcStatusPdu) as u8,
125            "compressedType" => 0 as u8,
126            "compressedLength" => U16::LE(0),
127            "payload" => default_message
128        ]
129    }
130}
131
132
133/// This is the main PDU payload format
134/// It use the share control header to dispatch between all PDU
135fn share_control_header(pdu_type: Option<PDUType>, pdu_source: Option<u16>, message: Option<Vec<u8>>) -> Component {
136    let default_message = message.unwrap_or(vec![]);
137    component![
138        "totalLength" => DynOption::new(U16::LE(default_message.length() as u16 + 6), |total| MessageOption::Size("pduMessage".to_string(), total.inner() as usize - 6)),
139        "pduType" => U16::LE(pdu_type.unwrap_or(PDUType::PdutypeDemandactivepdu) as u16),
140        "PDUSource" => Some(U16::LE(pdu_source.unwrap_or(0))),
141        "pduMessage" => default_message
142    ]
143}
144
145#[derive(Debug, TryFromPrimitive, Copy, Clone, Eq, PartialEq)]
146#[repr(u8)]
147enum PDUType2 {
148    Pdutype2Update = 0x02,
149    Pdutype2Control = 0x14,
150    Pdutype2Pointer = 0x1B,
151    Pdutype2Input = 0x1C,
152    Pdutype2Synchronize = 0x1F,
153    Pdutype2RefreshRect = 0x21,
154    Pdutype2PlaySound = 0x22,
155    Pdutype2SuppressOutput = 0x23,
156    Pdutype2ShutdownRequest = 0x24,
157    Pdutype2ShutdownDenied = 0x25,
158    Pdutype2SaveSessionInfo = 0x26,
159    Pdutype2Fontlist = 0x27,
160    Pdutype2Fontmap = 0x28,
161    Pdutype2SetKeyboardIndicators = 0x29,
162    Pdutype2BitmapcachePersistentList = 0x2B,
163    Pdutype2BitmapcacheErrorPdu = 0x2C,
164    Pdutype2SetKeyboardImeStatus = 0x2D,
165    Pdutype2OffscrcacheErrorPdu = 0x2E,
166    Pdutype2SetErrorInfoPdu = 0x2F,
167    Pdutype2DrawninegridErrorPdu = 0x30,
168    Pdutype2DrawgdiplusErrorPdu = 0x31,
169    Pdutype2ArcStatusPdu = 0x32,
170    Pdutype2StatusInfoPdu = 0x36,
171    Pdutype2MonitorLayoutPdu = 0x37,
172    Unknown
173}
174
175/// Data PDU container
176struct DataPDU {
177    pdu_type: PDUType2,
178    message: Component
179}
180
181impl DataPDU {
182    /// Build a DATA PDU from a PDU container
183    /// User must check that the PDU is a DATA PDU
184    /// If not this function will panic
185    pub fn from_pdu(data_pdu: &PDU) -> RdpResult<DataPDU> {
186        let pdu_type = PDUType2::try_from(cast!(DataType::U8, data_pdu.message["pduType2"])?)?;
187        let mut result = match pdu_type {
188            PDUType2::Pdutype2Synchronize => ts_synchronize_pdu(None),
189            PDUType2::Pdutype2Control => ts_control_pdu(None),
190            PDUType2::Pdutype2Fontlist => ts_font_list_pdu(),
191            PDUType2::Pdutype2Fontmap => ts_font_map_pdu(),
192            PDUType2::Pdutype2SetErrorInfoPdu => ts_set_error_info_pdu(),
193            _ => return Err(Error::RdpError(RdpError::new(RdpErrorKind::NotImplemented, &format!("GLOBAL: Data PDU parsing not implemented {:?}", pdu_type))))
194        };
195        result.message.read(&mut Cursor::new(cast!(DataType::Slice, data_pdu.message["payload"])?))?;
196        Ok(result)
197    }
198}
199
200/// Synchronize payload send by both side (client, server)
201///
202/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/3fb4c95e-ad2d-43d1-a46f-5bd49418da49
203fn ts_synchronize_pdu(target_user: Option<u16>) -> DataPDU {
204    DataPDU {
205        pdu_type: PDUType2::Pdutype2Synchronize,
206        message: component![
207            "messageType" => Check::new(U16::LE(1)),
208            "targetUser" => Some(U16::LE(target_user.unwrap_or(0)))
209        ]
210    }
211}
212
213/// Font list PDU
214///
215/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/e373575a-01e2-43a7-a6d8-e1952b83e787
216fn ts_font_list_pdu() -> DataPDU {
217    DataPDU {
218        pdu_type: PDUType2::Pdutype2Fontlist,
219        message: component![
220            "numberFonts" => U16::LE(0),
221            "totalNumFonts" => U16::LE(0),
222            "listFlags" => U16::LE(0x0003),
223            "entrySize" => U16::LE(0x0032)
224        ]
225    }
226}
227
228/// Error info PDU
229///
230/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a21a1bd9-2303-49c1-90ec-3932435c248c
231fn ts_set_error_info_pdu() -> DataPDU {
232    DataPDU {
233        pdu_type: PDUType2::Pdutype2SetErrorInfoPdu,
234        message: component![
235            "errorInfo" => U32::LE(0)
236        ]
237    }
238}
239
240#[repr(u16)]
241#[allow(dead_code)]
242enum Action {
243    CtrlactionRequestControl = 0x0001,
244    CtrlactionGrantedControl = 0x0002,
245    CtrlactionDetach = 0x0003,
246    CtrlactionCooperate = 0x0004
247}
248
249/// Control payload send during pdu handshake
250///
251/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/0448f397-aa11-455d-81b1-f1265085239d
252fn ts_control_pdu(action: Option<Action>) -> DataPDU {
253    DataPDU {
254        pdu_type: PDUType2::Pdutype2Control,
255        message: component![
256            "action" => U16::LE(action.unwrap_or(Action::CtrlactionCooperate) as u16),
257            "grantId" => U16::LE(0),
258            "controlId" => U32::LE(0)
259        ]
260    }
261}
262
263/// Font details send from server to client
264///
265/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/b4e557f3-7540-46fc-815d-0c12299cf1ee
266fn ts_font_map_pdu() -> DataPDU {
267    DataPDU {
268        pdu_type: PDUType2::Pdutype2Fontmap,
269        message: component![
270            "numberEntries" => U16::LE(0),
271            "totalNumEntries" => U16::LE(0),
272            "mapFlags" => U16::LE(0x0003),
273            "entrySize" => U16::LE(0x0004)
274        ]
275    }
276}
277
278/// Send input event as slow path
279fn ts_input_pdu_data(events: Option<Array<Component>>) -> DataPDU {
280    let default_events = events.unwrap_or(Array::new(|| ts_input_event(None, None)));
281    DataPDU {
282        pdu_type: PDUType2::Pdutype2Input,
283        message: component![
284            "numEvents" => U16::LE(default_events.inner().len() as u16),
285            "pad2Octets" => U16::LE(0),
286            "slowPathInputEvents" => default_events
287        ]
288    }
289}
290
291/// All slow path input events
292fn ts_input_event(message_type: Option<InputEventType>, data: Option<Vec<u8>>) -> Component {
293    component![
294        "eventTime" => U32::LE(0),
295        "messageType" => U16::LE(message_type.unwrap_or(InputEventType::InputEventMouse) as u16),
296        "slowPathInputData" => data.unwrap_or(vec![])
297    ]
298}
299
300/// All input event type
301///
302/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a9a26b3d-84a2-495f-83fc-9edd6601f33b
303#[repr(u16)]
304pub enum InputEventType {
305    InputEventSync = 0x0000,
306    InputEventUnused = 0x0002,
307    InputEventScancode = 0x0004,
308    InputEventUnicode = 0x0005,
309    InputEventMouse = 0x8001,
310    InputEventMousex = 0x8002
311}
312
313/// All Terminal Service Slow Path Input Event
314pub struct TSInputEvent {
315    event_type: InputEventType,
316    message: Component
317}
318
319/// All supported flags for pointer event
320///
321/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/2c1ced34-340a-46cd-be6e-fc8cab7c3b17
322#[repr(u16)]
323pub enum PointerFlag {
324    PtrflagsHwheel = 0x0400,
325    PtrflagsWheel = 0x0200,
326    PtrflagsWheelNegative = 0x0100,
327    WheelRotationMask = 0x01FF,
328    PtrflagsMove = 0x0800,
329    PtrflagsDown = 0x8000,
330    PtrflagsButton1 = 0x1000,
331    PtrflagsButton2 = 0x2000,
332    PtrflagsButton3 = 0x4000
333}
334
335/// A pointer event
336///
337/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/2c1ced34-340a-46cd-be6e-fc8cab7c3b17
338pub fn ts_pointer_event(flags: Option<u16>, x: Option<u16>, y: Option<u16>) -> TSInputEvent {
339    TSInputEvent {
340        event_type: InputEventType::InputEventMouse,
341        message : component![
342            "pointerFlags" => U16::LE(flags.unwrap_or(0)),
343            "xPos" => U16::LE(x.unwrap_or(0)),
344            "yPos" => U16::LE(y.unwrap_or(0))
345        ]
346    }
347}
348
349#[repr(u16)]
350pub enum KeyboardFlag {
351    KbdflagsExtended = 0x0100,
352    KbdflagsDown = 0x4000,
353    KbdflagsRelease = 0x8000
354}
355
356/// Raw input keyboard event
357/// Use to send scancode directly
358pub fn ts_keyboard_event(flags: Option<u16>, key_code: Option<u16>) -> TSInputEvent {
359    TSInputEvent {
360        event_type: InputEventType::InputEventScancode,
361        message: component![
362            "keyboardFlags" => U16::LE(flags.unwrap_or(0)),
363            "keyCode" => U16::LE(key_code.unwrap_or(0)),
364            "pad2Octets" => U16::LE(0)
365        ]
366    }
367}
368
369/// Fast Path update (Not a PDU)
370///
371/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a1c4caa8-00ed-45bb-a06e-5177473766d3
372fn ts_fp_update() -> Component {
373    component![
374        "updateHeader" => DynOption::new(0 as u8, |header| {
375            if (header >> 4) & 0x2 as u8 == 0 as u8 {
376                MessageOption::SkipField("compressionFlags".to_string())
377            }
378            else {
379                MessageOption::None
380            }
381        }),
382        "compressionFlags" => 0 as u8,
383        "size" => DynOption::new(U16::LE(0), | size | MessageOption::Size("updateData".to_string(), size.inner() as usize)),
384        "updateData" => Vec::<u8>::new()
385    ]
386}
387
388
389#[repr(u8)]
390#[derive(Debug, TryFromPrimitive, Copy, Clone, Eq, PartialEq)]
391enum FastPathUpdateType {
392    FastpathUpdatetypeOrders = 0x0,
393    FastpathUpdatetypeBitmap = 0x1,
394    FastpathUpdatetypePalette = 0x2,
395    FastpathUpdatetypeSynchronize = 0x3,
396    FastpathUpdatetypeSurfcmds = 0x4,
397    FastpathUpdatetypePtrNull = 0x5,
398    FastpathUpdatetypePtrDefault = 0x6,
399    FastpathUpdatetypePtrPosition = 0x8,
400    FastpathUpdatetypeColor = 0x9,
401    FastpathUpdatetypeCached = 0xA,
402    FastpathUpdatetypePointer = 0xB,
403    Unknown
404}
405
406struct FastPathUpdate{
407    fp_type: FastPathUpdateType,
408    message: Component
409}
410
411impl FastPathUpdate {
412    /// Parse Fast Path update order
413    fn from_fp(fast_path: &Component) -> RdpResult<FastPathUpdate> {
414        let fp_update_type = FastPathUpdateType::try_from(cast!(DataType::U8, fast_path["updateHeader"])? & 0xf)?;
415        let mut result = match fp_update_type {
416            FastPathUpdateType::FastpathUpdatetypeBitmap => ts_fp_update_bitmap(),
417            FastPathUpdateType::FastpathUpdatetypeColor => ts_colorpointerattribute(),
418            FastPathUpdateType::FastpathUpdatetypeSynchronize => ts_fp_update_synchronize(),
419            FastPathUpdateType::FastpathUpdatetypePtrNull => ts_fp_systempointerhiddenattribute(),
420            _ => return Err(Error::RdpError(RdpError::new(RdpErrorKind::NotImplemented, &format!("GLOBAL: Fast Path parsing not implemented {:?}", fp_update_type))))
421        };
422        result.message.read(&mut Cursor::new(cast!(DataType::Slice, fast_path["updateData"])?))?;
423        Ok(result)
424    }
425}
426
427fn ts_cd_header() -> Component {
428    component![
429        "cbCompFirstRowSize" => Check::new(U16::LE(0)),
430        "cbCompMainBodySize" => U16::LE(0),
431        "cbScanWidth" => U16::LE(0),
432        "cbUncompressedSize" => U16::LE(0)
433    ]
434}
435
436#[repr(u16)]
437enum BitmapFlag {
438    BitmapCompression = 0x0001,
439    NoBitmapCompressionHdr = 0x0400,
440}
441
442fn ts_bitmap_data() -> Component {
443    component![
444        "destLeft" => U16::LE(0),
445        "destTop" => U16::LE(0),
446        "destRight" => U16::LE(0),
447        "destBottom" => U16::LE(0),
448        "width" => U16::LE(0),
449        "height" => U16::LE(0),
450        "bitsPerPixel" => U16::LE(0),
451        "flags" => DynOption::new(U16::LE(0), |flags| {
452            if flags.inner() & BitmapFlag::BitmapCompression as u16 == 0 || flags.inner() & BitmapFlag::NoBitmapCompressionHdr as u16 != 0 {
453                MessageOption::SkipField("bitmapComprHdr".to_string())
454            }
455            else {
456                MessageOption::None
457            }
458        }),
459        "bitmapLength" => DynOption::new(U16::LE(0), | length | MessageOption::Size("bitmapDataStream".to_string(), length.inner() as usize)),
460        "bitmapComprHdr" => DynOption::new(ts_cd_header(), |header| MessageOption::Size("bitmapDataStream".to_string(), cast!(DataType::U16, header["cbCompMainBodySize"]).unwrap() as usize)),
461        "bitmapDataStream" => Vec::<u8>::new()
462    ]
463}
464
465/// Fast Path bitmap update
466fn ts_fp_update_bitmap() -> FastPathUpdate {
467    FastPathUpdate {
468        fp_type: FastPathUpdateType::FastpathUpdatetypeBitmap,
469        message: component![
470            "header" => Check::new(U16::LE(FastPathUpdateType::FastpathUpdatetypeBitmap as u16)),
471            "numberRectangles" => U16::LE(0),
472            "rectangles" => Array::new(|| ts_bitmap_data())
473        ]
474    }
475}
476
477/// A new pointer for mouse
478///
479/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/71fad4fc-6ad4-4c7f-8103-a442bebaf7d2
480fn ts_colorpointerattribute() -> FastPathUpdate {
481    FastPathUpdate {
482        fp_type: FastPathUpdateType::FastpathUpdatetypeColor,
483        message: component![
484            "cacheIndex " => U16::LE(0),
485            "hotSpot " => U32::LE(0),
486            "width" => U16::LE(0),
487            "height" => U16::LE(0),
488            "lengthAndMask" => DynOption::new(U16::LE(0), |length| MessageOption::Size("andMaskData".to_string(), length.inner() as usize)),
489            "lengthXorMask" => DynOption::new(U16::LE(0), |length| MessageOption::Size("xorMaskData".to_string(), length.inner() as usize)),
490            "xorMaskData" => Vec::<u8>::new(),
491            "andMaskData" => Vec::<u8>::new(),
492            "pad" => Some(0 as u8)
493         ]
494    }
495}
496
497/// Empty fields
498///
499/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/406dc477-c516-41cb-a8a0-ab4cc7119621
500fn ts_fp_update_synchronize() -> FastPathUpdate {
501    FastPathUpdate {
502        fp_type: FastPathUpdateType::FastpathUpdatetypeSynchronize,
503        message: component![]
504    }
505}
506
507/// Empty fields
508///
509/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/406dc477-c516-41cb-a8a0-ab4cc7119621
510fn ts_fp_systempointerhiddenattribute() -> FastPathUpdate {
511    FastPathUpdate {
512        fp_type: FastPathUpdateType::FastpathUpdatetypePtrNull,
513        message: component![]
514    }
515}
516
517enum ClientState {
518    /// Wait for demand active pdu from server
519    DemandActivePDU,
520    /// Wait for synchronize pdu from server
521    SynchronizePDU,
522    /// wait for control cooperate from server
523    ControlCooperate,
524    /// Wait for control granted from server
525    ControlGranted,
526    /// Wait for font map pdu from server
527    FontMap,
528    /// wait for date
529    /// either data pdu or fast path data
530    Data
531}
532
533pub struct Client {
534    /// Current state of the connection sequence
535    state: ClientState,
536    /// user id negotiated by the MCS layer
537    user_id: u16,
538    /// Global channel id
539    /// This is a static id but come from MCS layer
540    channel_id: u16,
541    /// Screen width
542    width: u16,
543    /// Screen height
544    height: u16,
545    /// Keyboard layout
546    layout: KeyboardLayout,
547    /// Share id negotiated by global
548    /// channel during connection sequence
549    share_id: Option<u32>,
550    /// Keep tracing of server capabilities
551    server_capabilities: Vec<Capability>,
552    /// Name send to the server
553    name: String
554}
555
556impl Client {
557    /// Ctor for a new global channel client
558    /// user_id and channel_id must come from mcs channel once connected
559    /// Width and height are screen size
560    ///
561    /// # Example
562    /// ```rust, ignore
563    /// use rdp::core::global;
564    /// use rdp::core::gcc::KeyboardLayout;
565    /// let mut global_channel = global::Client::new(
566    ///     mcs.get_user_id(),
567    ///     mcs.get_global_channel_id(),
568    ///     800,
569    ///     600,
570    ///     KeyboardLayout::US,
571    ///     "mstsc-rs"
572    /// );
573    /// ```
574    pub fn new(user_id: u16, channel_id: u16, width: u16, height: u16, layout: KeyboardLayout, name: &str) -> Client {
575        Client {
576            state: ClientState::DemandActivePDU,
577            server_capabilities: Vec::new(),
578            share_id: None,
579            user_id,
580            channel_id,
581            width,
582            height,
583            layout,
584            name: String::from(name)
585        }
586    }
587
588    /// Read demand Active payload
589    /// This message is sent from server to client
590    /// and inform about server capabilities
591    ///
592    /// This function return true if it read the expected PDU
593    fn read_demand_active_pdu(&mut self, stream: &mut dyn Read) -> RdpResult<bool> {
594        let pdu = PDU::from_stream(stream)?;
595        if pdu.pdu_type == PDUType::PdutypeDemandactivepdu {
596            for capability_set in cast!(DataType::Trame, pdu.message["capabilitySets"])?.iter() {
597                match Capability::from_capability_set(cast!(DataType::Component, capability_set)?) {
598                    Ok(capability) => self.server_capabilities.push(capability),
599                    Err(e) => println!("GLOBAL: {:?}", e)
600                }
601            }
602            self.share_id = Some(cast!(DataType::U32, pdu.message["shareId"])?);
603            return Ok(true)
604        }
605        return Ok(false)
606    }
607
608    /// Read server synchronize pdu
609    /// This sent from server to client
610    ///
611    /// This function return true if it read the expected PDU
612    fn read_synchronize_pdu(&mut self, stream: &mut dyn Read) -> RdpResult<bool> {
613        let pdu = PDU::from_stream(stream)?;
614        if pdu.pdu_type != PDUType::PdutypeDatapdu {
615            return Ok(false)
616        }
617        if DataPDU::from_pdu(&pdu)?.pdu_type != PDUType2::Pdutype2Synchronize {
618            return Ok(false)
619        }
620        Ok(true)
621    }
622
623    /// Read the server control PDU with the expected action
624    ///
625    /// This function return true if it read the expected PDU with the expected action
626    fn read_control_pdu(&mut self, stream: &mut dyn Read, action: Action) -> RdpResult<bool> {
627        let pdu = PDU::from_stream(stream)?;
628        if pdu.pdu_type != PDUType::PdutypeDatapdu {
629            return Ok(false)
630        }
631
632        let data_pdu = DataPDU::from_pdu(&pdu)?;
633        if data_pdu.pdu_type != PDUType2::Pdutype2Control {
634            return Ok(false)
635        }
636
637        if cast!(DataType::U16,  data_pdu.message["action"])? != action as u16 {
638            return Err(Error::RdpError(RdpError::new(RdpErrorKind::UnexpectedType, "GLOBAL: bad message type")))
639        }
640
641        Ok(true)
642    }
643
644    /// Read the server font data PDU
645    ///
646    /// This function return true if it read the expected PDU
647    fn read_font_map_pdu(&mut self, stream: &mut dyn Read) ->  RdpResult<bool> {
648        let pdu = PDU::from_stream(stream)?;
649        if pdu.pdu_type != PDUType::PdutypeDatapdu {
650            return Ok(false)
651        }
652        if DataPDU::from_pdu(&pdu)?.pdu_type != PDUType2::Pdutype2Fontmap {
653            return Ok(false)
654        }
655        Ok(true)
656    }
657
658    /// Expect data PDU
659    /// This is the old school PDU for bitmap
660    /// transfer. Now all version use Fast Path transfer PDU
661    fn read_data_pdu(&mut self, stream: &mut dyn Read) -> RdpResult<()> {
662        //let pdu = PDU::from_stream(stream)?;
663        let mut message = Array::new(|| share_control_header(None, None, None));
664        message.read(stream)?;
665
666        for pdu in message.inner() {
667            let pdu = PDU::from_control(cast!(DataType::Component, pdu)?)?;
668
669            // Ask for a new handshake
670            if pdu.pdu_type == PDUType::PdutypeDeactivateallpdu {
671                println!("GLOBAL: deactive/reactive sequence initiated");
672                self.state = ClientState::DemandActivePDU;
673                continue;
674            }
675            if pdu.pdu_type != PDUType::PdutypeDatapdu {
676                println!("GLOBAL: Ignore PDU {:?}", pdu.pdu_type);
677                continue;
678            }
679
680            match DataPDU::from_pdu(&pdu) {
681                Ok(data_pdu) => {
682                    match data_pdu.pdu_type {
683                        PDUType2::Pdutype2SetErrorInfoPdu => println!("GLOBAL: Receive error PDU from server {:?}", cast!(DataType::U32, data_pdu.message["errorInfo"])?),
684                        _ => println!("GLOBAL: Data PDU not handle {:?}", data_pdu.pdu_type)
685                    }
686                },
687                Err(e) => println!("GLOBAL: Parsing data PDU error {:?}", e)
688            };
689        }
690        Ok(())
691    }
692
693    /// Read fast path input data
694    /// Reading is processed using a callback patterm
695    /// This is where bitmap are received
696    fn read_fast_path<T>(&mut self, stream: &mut dyn Read, mut callback: T) -> RdpResult<()>
697    where T: FnMut(RdpEvent) {
698        // it could be have one or more fast path payload
699        let mut fp_messages = Array::new(|| ts_fp_update());
700        fp_messages.read(stream)?;
701
702        for fp_message in fp_messages.inner().iter() {
703            match FastPathUpdate::from_fp(cast!(DataType::Component, fp_message)?) {
704                Ok(order) => {
705                    match order.fp_type {
706                        FastPathUpdateType::FastpathUpdatetypeBitmap => {
707                            for rectangle in cast!(DataType::Trame, order.message["rectangles"])? {
708                                let bitmap = cast!(DataType::Component, rectangle)?;
709                                callback(RdpEvent::Bitmap(
710                                    BitmapEvent {
711                                        dest_left: cast!(DataType::U16, bitmap["destLeft"])?,
712                                        dest_top: cast!(DataType::U16, bitmap["destTop"])?,
713                                        dest_right: cast!(DataType::U16, bitmap["destRight"])?,
714                                        dest_bottom: cast!(DataType::U16, bitmap["destBottom"])?,
715                                        width: cast!(DataType::U16, bitmap["width"])?,
716                                        height: cast!(DataType::U16, bitmap["height"])?,
717                                        bpp: cast!(DataType::U16, bitmap["bitsPerPixel"])?,
718                                        is_compress: cast!(DataType::U16, bitmap["flags"])? & BitmapFlag::BitmapCompression as u16 != 0,
719                                        data: cast!(DataType::Slice, bitmap["bitmapDataStream"])?.to_vec()
720                                    }
721                                ));
722                            }
723                        },
724                        // do nothing
725                        FastPathUpdateType::FastpathUpdatetypeColor | FastPathUpdateType::FastpathUpdatetypePtrNull | FastPathUpdateType::FastpathUpdatetypeSynchronize => (),
726                        _ => println!("GLOBAL: Fast Path order not handled {:?}", order.fp_type)
727                    }
728                },
729                Err(e) => println!("GLOBAL: Unknown Fast Path order {:?}", e)
730            };
731        }
732
733        Ok(())
734    }
735
736    /// Write confirm active pdu
737    /// This PDU include all client capabilities
738    fn write_confirm_active_pdu<S: Read + Write>(&mut self, mcs: &mut mcs::Client<S>) -> RdpResult<()> {
739        let pdu = ts_confirm_active_pdu(self.share_id, Some(self.name.as_bytes().to_vec()), Some(Array::from_trame(
740            trame![
741                capability_set(Some(capability::ts_general_capability_set(Some(capability::GeneralExtraFlag::LongCredentialsSupported as u16 | capability::GeneralExtraFlag::NoBitmapCompressionHdr as u16 | capability::GeneralExtraFlag::EncSaltedChecksum as u16 | capability::GeneralExtraFlag::FastpathOutputSupported as u16)))),
742                capability_set(Some(capability::ts_bitmap_capability_set(Some(0x0018), Some(self.width), Some(self.height)))),
743                capability_set(Some(capability::ts_order_capability_set(Some(capability::OrderFlag::NEGOTIATEORDERSUPPORT as u16 | capability::OrderFlag::ZEROBOUNDSDELTASSUPPORT as u16)))),
744                capability_set(Some(capability::ts_bitmap_cache_capability_set())),
745                capability_set(Some(capability::ts_pointer_capability_set())),
746                capability_set(Some(capability::ts_sound_capability_set())),
747                capability_set(Some(capability::ts_input_capability_set(Some(capability::InputFlags::InputFlagScancodes as u16 | capability::InputFlags::InputFlagMousex as u16 | capability::InputFlags::InputFlagUnicode as u16), Some(self.layout)))),
748                capability_set(Some(capability::ts_brush_capability_set())),
749                capability_set(Some(capability::ts_glyph_capability_set())),
750                capability_set(Some(capability::ts_offscreen_capability_set())),
751                capability_set(Some(capability::ts_virtualchannel_capability_set())),
752                capability_set(Some(capability::ts_multifragment_update_capability_ts()))
753            ]
754        )));
755        self.write_pdu(pdu, mcs)
756    }
757
758    /// This is the finalize connection sequence
759    /// sent from client to server
760    fn write_client_finalize<S: Read + Write>(&self, mcs: &mut mcs::Client<S>) -> RdpResult<()> {
761        self.write_data_pdu(ts_synchronize_pdu(Some(self.channel_id)), mcs)?;
762        self.write_data_pdu(ts_control_pdu(Some(Action::CtrlactionCooperate)), mcs)?;
763        self.write_data_pdu(ts_control_pdu(Some(Action::CtrlactionRequestControl)), mcs)?;
764        self.write_data_pdu(ts_font_list_pdu(), mcs)
765    }
766
767    /// Send a classic PDU to the global channel
768    fn write_pdu<S: Read + Write>(&self, message: PDU, mcs: &mut mcs::Client<S>) -> RdpResult<()> {
769        mcs.write(&"global".to_string(), share_control_header(Some(message.pdu_type), Some(self.user_id), Some(to_vec(&message.message))))
770    }
771
772    /// Send Data pdu
773    fn write_data_pdu<S: Read + Write>(&self, message: DataPDU, mcs: &mut mcs::Client<S>) -> RdpResult<()> {
774        self.write_pdu(share_data_header(self.share_id, Some(message.pdu_type), Some(to_vec(&message.message))), mcs)
775    }
776
777    /// Public interface to sent input event
778    ///
779    /// # Example
780    /// ```rust, ignore
781    /// let mut mcs = mcs::Client::new(...);
782    /// let mut global = global::Global::new(...);
783    /// global.write_input_event(
784    ///     ts_pointer_event(
785    ///         Some(flags),
786    ///         Some(x),
787    ///         Some(y)
788    ///     ),
789    ///     &mut mcs
790    /// )
791    ///
792    /// global.write_input_event(
793    ///     ts_keyboard_event(
794    ///         Some(flags),
795    ///         Some(code)
796    ///     ),
797    ///     &mut self.mcs
798    /// )
799    /// ```
800    pub fn write_input_event<S: Read + Write>(&self, event: TSInputEvent, mcs: &mut mcs::Client<S>) -> RdpResult<()> {
801        self.write_data_pdu(ts_input_pdu_data(Some(Array::from_trame(trame![ts_input_event(Some(event.event_type), Some(to_vec(&event.message)))]))), mcs)
802    }
803
804    /// Read payload on global channel
805    /// This is the main read function for global channel
806    ///
807    /// # Example
808    /// ```rust, ignore
809    /// let mut mcs = mcs::Client::new(...);
810    /// let mut global = global::Global::new(...);
811    /// let (channel_name, message) = mcs.read().unwrap();
812    /// match channel_name.as_str() {
813    ///     "global" => global.read(message, &mut mcs, |event| {
814    ///         // do something with event
815    ///     }),
816    ///     ...
817    /// }
818    /// ```
819    pub fn read<S: Read + Write, T>(&mut self, payload: tpkt::Payload, mcs: &mut mcs::Client<S>, callback: T) -> RdpResult<()>
820    where T: FnMut(RdpEvent){
821        match self.state {
822            ClientState::DemandActivePDU => {
823                if self.read_demand_active_pdu(&mut try_let!(tpkt::Payload::Raw, payload)?)? {
824                    self.write_confirm_active_pdu(mcs)?;
825                    self.write_client_finalize(mcs)?;
826                    // now wait for server synchronize
827                    self.state = ClientState::SynchronizePDU;
828                }
829                Ok(())
830            }
831            ClientState::SynchronizePDU => {
832                if self.read_synchronize_pdu(&mut try_let!(tpkt::Payload::Raw, payload)?)? {
833                    // next state is control cooperate
834                    self.state = ClientState::ControlCooperate;
835                }
836                Ok(())
837            },
838            ClientState::ControlCooperate => {
839                if self.read_control_pdu(&mut try_let!(tpkt::Payload::Raw, payload)?, Action::CtrlactionCooperate)? {
840                    // next state is control granted
841                    self.state = ClientState::ControlGranted;
842                }
843                Ok(())
844            },
845            ClientState::ControlGranted => {
846                if self.read_control_pdu(&mut try_let!(tpkt::Payload::Raw, payload)?, Action::CtrlactionGrantedControl)? {
847                    // next state is font map pdu
848                    self.state = ClientState::FontMap;
849                }
850                Ok(())
851            },
852            ClientState::FontMap => {
853                if self.read_font_map_pdu(&mut try_let!(tpkt::Payload::Raw, payload)?)? {
854                    // finish handshake now wait for sdata
855                    self.state = ClientState::Data;
856                }
857                Ok(())
858            },
859            ClientState::Data => {
860                // Now we can receive update data
861                match payload {
862                    tpkt::Payload::Raw(mut stream) => self.read_data_pdu(&mut stream),
863                    tpkt::Payload::FastPath(_sec_flag, mut stream) => self.read_fast_path(&mut stream, callback)
864                }
865            }
866        }
867    }
868}
869
870#[cfg(test)]
871mod test {
872    use super::*;
873
874    /// Test format message of demand active pdu
875    #[test]
876    fn test_demand_active_pdu() {
877        let mut stream = Cursor::new(vec![234, 3, 1, 0, 4, 0, 179, 1, 82, 68, 80, 0, 17, 0, 0, 0, 9, 0, 8, 0, 234, 3, 0, 0, 1, 0, 24, 0, 1, 0, 3, 0, 0, 2, 0, 0, 0, 0, 29, 4, 0, 0, 0, 0, 0, 0, 1, 1, 20, 0, 12, 0, 2, 0, 0, 0, 64, 6, 0, 0, 10, 0, 8, 0, 6, 0, 0, 0, 8, 0, 10, 0, 1, 0, 25, 0, 25, 0, 27, 0, 6, 0, 3, 0, 14, 0, 8, 0, 1, 0, 0, 0, 2, 0, 28, 0, 32, 0, 1, 0, 1, 0, 1, 0, 32, 3, 88, 2, 0, 0, 1, 0, 1, 0, 0, 30, 1, 0, 0, 0, 29, 0, 96, 0, 4, 185, 27, 141, 202, 15, 0, 79, 21, 88, 159, 174, 45, 26, 135, 226, 214, 0, 3, 0, 1, 1, 3, 18, 47, 119, 118, 114, 189, 99, 68, 175, 179, 183, 60, 156, 111, 120, 134, 0, 4, 0, 0, 0, 0, 0, 166, 81, 67, 156, 53, 53, 174, 66, 145, 12, 205, 252, 229, 118, 11, 88, 0, 4, 0, 0, 0, 0, 0, 212, 204, 68, 39, 138, 157, 116, 78, 128, 60, 14, 203, 238, 161, 156, 84, 0, 4, 0, 0, 0, 0, 0, 3, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 66, 15, 0, 1, 0, 20, 0, 0, 0, 1, 0, 0, 0, 170, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 161, 6, 6, 0, 64, 66, 15, 0, 64, 66, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 18, 0, 8, 0, 1, 0, 0, 0, 13, 0, 88, 0, 117, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 8, 0, 255, 0, 0, 0, 24, 0, 11, 0, 2, 0, 0, 0, 3, 12, 0, 26, 0, 8, 0, 43, 72, 9, 0, 28, 0, 12, 0, 82, 0, 0, 0, 0, 0, 0, 0, 30, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
878        let mut pdu = ts_demand_active_pdu();
879        pdu.message.read(&mut stream).unwrap();
880        assert_eq!(cast!(DataType::U16, pdu.message["numberCapabilities"]).unwrap(), 17)
881    }
882
883    /// Test confirm active PDU format
884    #[test]
885    fn test_confirm_active_pdu() {
886        let mut stream = Cursor::new(vec![]);
887        ts_confirm_active_pdu(Some(4), Some(b"rdp-rs".to_vec()), Some(Array::from_trame(trame![capability_set(Some(capability::ts_brush_capability_set()))]))).message.write(&mut stream).unwrap();
888        assert_eq!(stream.into_inner(), [4, 0, 0, 0, 234, 3, 6, 0, 12, 0, 114, 100, 112, 45, 114, 115, 1, 0, 0, 0, 15, 0, 8, 0, 0, 0, 0, 0]);
889    }
890
891    #[test]
892    fn test_share_control_header() {
893        let mut stream = Cursor::new(vec![]);
894        share_control_header(Some(PDUType::PdutypeConfirmactivepdu), Some(12), Some(to_vec(&ts_confirm_active_pdu(Some(4), Some(b"rdp-rs".to_vec()), Some(Array::from_trame(trame![capability_set(Some(capability::ts_brush_capability_set()))]))).message))).write(&mut stream).unwrap();
895
896        assert_eq!(stream.into_inner(), vec![34, 0, 19, 0, 12, 0, 4, 0, 0, 0, 234, 3, 6, 0, 12, 0, 114, 100, 112, 45, 114, 115, 1, 0, 0, 0, 15, 0, 8, 0, 0, 0, 0, 0])
897    }
898
899    #[test]
900    fn test_read_synchronize_pdu() {
901        let mut stream = Cursor::new(vec![22, 0, 23, 0, 234, 3, 234, 3, 1, 0, 0, 2, 22, 0, 31, 0, 0, 0, 1, 0, 0, 0]);
902        let mut global = Client::new(0,0, 800, 600, KeyboardLayout::US, "foo");
903        assert!(global.read_synchronize_pdu(&mut stream).unwrap())
904    }
905
906    #[test]
907    fn test_read_control_cooperate_pdu() {
908        let mut stream = Cursor::new(vec![26, 0, 23, 0, 234, 3, 234, 3, 1, 0, 0, 2, 26, 0, 20, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
909        let mut global = Client::new(0,0, 800, 600, KeyboardLayout::US, "foo");
910        assert!(global.read_control_pdu(&mut stream, Action::CtrlactionCooperate).unwrap())
911    }
912
913    #[test]
914    fn test_read_control_granted_pdu() {
915        let mut stream = Cursor::new(vec![26, 0, 23, 0, 234, 3, 234, 3, 1, 0, 0, 2, 26, 0, 20, 0, 0, 0, 2, 0, 236, 3, 234, 3, 0, 0]);
916        let mut global = Client::new(0,0, 800, 600, KeyboardLayout::US, "foo");
917        assert!(global.read_control_pdu(&mut stream, Action::CtrlactionGrantedControl).unwrap())
918    }
919
920    #[test]
921    fn test_read_font_map_pdu() {
922        let mut stream = Cursor::new(vec![26, 0, 23, 0, 234, 3, 234, 3, 1, 0, 0, 2, 26, 0, 40, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0]);
923        let mut global = Client::new(0,0, 800, 600, KeyboardLayout::US, "foo");
924        assert!(global.read_font_map_pdu(&mut stream).unwrap())
925    }
926}