ironrdp_rdpdr/pdu/
mod.rs

1use core::fmt::{self, Display};
2
3use ironrdp_core::{
4    ensure_size, invalid_field_err, unsupported_value_err, Decode, DecodeError, DecodeResult, Encode, EncodeResult,
5    ReadCursor, WriteCursor,
6};
7use ironrdp_svc::SvcEncode;
8
9use self::efs::{
10    ClientDeviceListAnnounce, ClientDeviceListRemove, ClientDriveQueryDirectoryResponse,
11    ClientDriveQueryInformationResponse, ClientDriveQueryVolumeInformationResponse, ClientDriveSetInformationResponse,
12    ClientNameRequest, CoreCapability, CoreCapabilityKind, DeviceCloseResponse, DeviceControlResponse,
13    DeviceCreateResponse, DeviceIoRequest, DeviceReadResponse, DeviceWriteResponse, ServerDeviceAnnounceResponse,
14    VersionAndIdPdu, VersionAndIdPduKind,
15};
16
17pub mod efs;
18pub mod esc;
19
20/// All available RDPDR PDUs.
21pub enum RdpdrPdu {
22    VersionAndIdPdu(VersionAndIdPdu),
23    ClientNameRequest(ClientNameRequest),
24    CoreCapability(CoreCapability),
25    ClientDeviceListAnnounce(ClientDeviceListAnnounce),
26    ClientDeviceListRemove(ClientDeviceListRemove),
27    ServerDeviceAnnounceResponse(ServerDeviceAnnounceResponse),
28    DeviceIoRequest(DeviceIoRequest),
29    DeviceControlResponse(DeviceControlResponse),
30    DeviceCreateResponse(DeviceCreateResponse),
31    ClientDriveQueryInformationResponse(ClientDriveQueryInformationResponse),
32    DeviceCloseResponse(DeviceCloseResponse),
33    ClientDriveQueryDirectoryResponse(ClientDriveQueryDirectoryResponse),
34    ClientDriveQueryVolumeInformationResponse(ClientDriveQueryVolumeInformationResponse),
35    DeviceReadResponse(DeviceReadResponse),
36    DeviceWriteResponse(DeviceWriteResponse),
37    ClientDriveSetInformationResponse(ClientDriveSetInformationResponse),
38    UserLoggedon,
39    EmptyResponse,
40}
41
42impl RdpdrPdu {
43    /// Returns the [`SharedHeader`] of the PDU.
44    fn header(&self) -> SharedHeader {
45        match self {
46            RdpdrPdu::VersionAndIdPdu(pdu) => match pdu.kind {
47                VersionAndIdPduKind::ClientAnnounceReply => SharedHeader {
48                    component: Component::RdpdrCtypCore,
49                    packet_id: PacketId::CoreClientidConfirm,
50                },
51                VersionAndIdPduKind::ServerAnnounceRequest => SharedHeader {
52                    component: Component::RdpdrCtypCore,
53                    packet_id: PacketId::CoreServerAnnounce,
54                },
55                VersionAndIdPduKind::ServerClientIdConfirm => SharedHeader {
56                    component: Component::RdpdrCtypCore,
57                    packet_id: PacketId::CoreClientidConfirm,
58                },
59            },
60            RdpdrPdu::ClientNameRequest(_) => SharedHeader {
61                component: Component::RdpdrCtypCore,
62                packet_id: PacketId::CoreClientName,
63            },
64            RdpdrPdu::CoreCapability(pdu) => match pdu.kind {
65                CoreCapabilityKind::ServerCoreCapabilityRequest => SharedHeader {
66                    component: Component::RdpdrCtypCore,
67                    packet_id: PacketId::CoreServerCapability,
68                },
69                CoreCapabilityKind::ClientCoreCapabilityResponse => SharedHeader {
70                    component: Component::RdpdrCtypCore,
71                    packet_id: PacketId::CoreClientCapability,
72                },
73            },
74            RdpdrPdu::ClientDeviceListAnnounce(_) => SharedHeader {
75                component: Component::RdpdrCtypCore,
76                packet_id: PacketId::CoreDevicelistAnnounce,
77            },
78            RdpdrPdu::ClientDeviceListRemove(_) => SharedHeader {
79                component: Component::RdpdrCtypCore,
80                packet_id: PacketId::CoreDevicelistRemove,
81            },
82            RdpdrPdu::ServerDeviceAnnounceResponse(_) => SharedHeader {
83                component: Component::RdpdrCtypCore,
84                packet_id: PacketId::CoreDeviceReply,
85            },
86            RdpdrPdu::DeviceIoRequest(_) => SharedHeader {
87                component: Component::RdpdrCtypCore,
88                packet_id: PacketId::CoreDeviceIoRequest,
89            },
90            RdpdrPdu::DeviceControlResponse(_)
91            | RdpdrPdu::DeviceCreateResponse(_)
92            | RdpdrPdu::ClientDriveQueryInformationResponse(_)
93            | RdpdrPdu::DeviceCloseResponse(_)
94            | RdpdrPdu::ClientDriveQueryDirectoryResponse(_)
95            | RdpdrPdu::ClientDriveQueryVolumeInformationResponse(_)
96            | RdpdrPdu::DeviceReadResponse(_)
97            | RdpdrPdu::DeviceWriteResponse(_)
98            | RdpdrPdu::ClientDriveSetInformationResponse(_)
99            | RdpdrPdu::EmptyResponse => SharedHeader {
100                component: Component::RdpdrCtypCore,
101                packet_id: PacketId::CoreDeviceIoCompletion,
102            },
103            RdpdrPdu::UserLoggedon => SharedHeader {
104                component: Component::RdpdrCtypCore,
105                packet_id: PacketId::CoreUserLoggedon,
106            },
107        }
108    }
109}
110
111impl Decode<'_> for RdpdrPdu {
112    fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
113        let header = SharedHeader::decode(src)?;
114        match header.packet_id {
115            PacketId::CoreServerAnnounce => Ok(RdpdrPdu::VersionAndIdPdu(VersionAndIdPdu::decode(header, src)?)),
116            PacketId::CoreServerCapability => Ok(RdpdrPdu::CoreCapability(CoreCapability::decode(header, src)?)),
117            PacketId::CoreClientidConfirm => Ok(RdpdrPdu::VersionAndIdPdu(VersionAndIdPdu::decode(header, src)?)),
118            PacketId::CoreDeviceReply => Ok(RdpdrPdu::ServerDeviceAnnounceResponse(
119                ServerDeviceAnnounceResponse::decode(src)?,
120            )),
121            PacketId::CoreDeviceIoRequest => Ok(RdpdrPdu::DeviceIoRequest(DeviceIoRequest::decode(src)?)),
122            PacketId::CoreUserLoggedon => Ok(RdpdrPdu::UserLoggedon),
123            _ => Err(unsupported_value_err!(
124                "RdpdrPdu",
125                "PacketId",
126                header.packet_id.to_string()
127            )),
128        }
129    }
130}
131
132impl Encode for RdpdrPdu {
133    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
134        self.header().encode(dst)?;
135
136        match self {
137            RdpdrPdu::VersionAndIdPdu(pdu) => pdu.encode(dst),
138            RdpdrPdu::ClientNameRequest(pdu) => pdu.encode(dst),
139            RdpdrPdu::CoreCapability(pdu) => pdu.encode(dst),
140            RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.encode(dst),
141            RdpdrPdu::ClientDeviceListRemove(pdu) => pdu.encode(dst),
142            RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.encode(dst),
143            RdpdrPdu::DeviceIoRequest(pdu) => pdu.encode(dst),
144            RdpdrPdu::DeviceControlResponse(pdu) => pdu.encode(dst),
145            RdpdrPdu::DeviceCreateResponse(pdu) => pdu.encode(dst),
146            RdpdrPdu::ClientDriveQueryInformationResponse(pdu) => pdu.encode(dst),
147            RdpdrPdu::DeviceCloseResponse(pdu) => pdu.encode(dst),
148            RdpdrPdu::ClientDriveQueryDirectoryResponse(pdu) => pdu.encode(dst),
149            RdpdrPdu::ClientDriveQueryVolumeInformationResponse(pdu) => pdu.encode(dst),
150            RdpdrPdu::DeviceReadResponse(pdu) => pdu.encode(dst),
151            RdpdrPdu::DeviceWriteResponse(pdu) => pdu.encode(dst),
152            RdpdrPdu::ClientDriveSetInformationResponse(pdu) => pdu.encode(dst),
153            RdpdrPdu::UserLoggedon => Ok(()),
154            RdpdrPdu::EmptyResponse => {
155                // https://github.com/FreeRDP/FreeRDP/blob/dfa231c0a55b005af775b833f92f6bcd30363d77/channels/drive/client/drive_main.c#L601
156                dst.write_u32(0);
157                Ok(())
158            }
159        }
160    }
161
162    fn name(&self) -> &'static str {
163        match self {
164            RdpdrPdu::VersionAndIdPdu(pdu) => pdu.name(),
165            RdpdrPdu::ClientNameRequest(pdu) => pdu.name(),
166            RdpdrPdu::CoreCapability(pdu) => pdu.name(),
167            RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.name(),
168            RdpdrPdu::ClientDeviceListRemove(pdu) => pdu.name(),
169            RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.name(),
170            RdpdrPdu::DeviceIoRequest(pdu) => pdu.name(),
171            RdpdrPdu::DeviceControlResponse(pdu) => pdu.name(),
172            RdpdrPdu::DeviceCreateResponse(pdu) => pdu.name(),
173            RdpdrPdu::ClientDriveQueryInformationResponse(pdu) => pdu.name(),
174            RdpdrPdu::DeviceCloseResponse(pdu) => pdu.name(),
175            RdpdrPdu::ClientDriveQueryDirectoryResponse(pdu) => pdu.name(),
176            RdpdrPdu::ClientDriveQueryVolumeInformationResponse(pdu) => pdu.name(),
177            RdpdrPdu::DeviceReadResponse(pdu) => pdu.name(),
178            RdpdrPdu::DeviceWriteResponse(pdu) => pdu.name(),
179            RdpdrPdu::ClientDriveSetInformationResponse(pdu) => pdu.name(),
180            RdpdrPdu::UserLoggedon => "UserLoggedon",
181            RdpdrPdu::EmptyResponse => "EmptyResponse",
182        }
183    }
184
185    fn size(&self) -> usize {
186        SharedHeader::SIZE
187            + match self {
188                RdpdrPdu::VersionAndIdPdu(pdu) => pdu.size(),
189                RdpdrPdu::ClientNameRequest(pdu) => pdu.size(),
190                RdpdrPdu::CoreCapability(pdu) => pdu.size(),
191                RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.size(),
192                RdpdrPdu::ClientDeviceListRemove(pdu) => pdu.size(),
193                RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.size(),
194                RdpdrPdu::DeviceIoRequest(pdu) => pdu.size(),
195                RdpdrPdu::DeviceControlResponse(pdu) => pdu.size(),
196                RdpdrPdu::DeviceCreateResponse(pdu) => pdu.size(),
197                RdpdrPdu::ClientDriveQueryInformationResponse(pdu) => pdu.size(),
198                RdpdrPdu::DeviceCloseResponse(pdu) => pdu.size(),
199                RdpdrPdu::ClientDriveQueryDirectoryResponse(pdu) => pdu.size(),
200                RdpdrPdu::ClientDriveQueryVolumeInformationResponse(pdu) => pdu.size(),
201                RdpdrPdu::DeviceReadResponse(pdu) => pdu.size(),
202                RdpdrPdu::DeviceWriteResponse(pdu) => pdu.size(),
203                RdpdrPdu::ClientDriveSetInformationResponse(pdu) => pdu.size(),
204                RdpdrPdu::UserLoggedon => 0,
205                RdpdrPdu::EmptyResponse => size_of::<u32>(),
206            }
207    }
208}
209
210impl SvcEncode for RdpdrPdu {}
211
212impl fmt::Debug for RdpdrPdu {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        match self {
215            Self::VersionAndIdPdu(it) => {
216                write!(f, "RdpdrPdu({it:?})")
217            }
218            Self::ClientNameRequest(it) => {
219                write!(f, "RdpdrPdu({it:?})")
220            }
221            Self::CoreCapability(it) => {
222                write!(f, "RdpdrPdu({it:?})")
223            }
224            Self::ClientDeviceListAnnounce(it) => {
225                write!(f, "RdpdrPdu({it:?})")
226            }
227            Self::ClientDeviceListRemove(it) => {
228                write!(f, "RdpdrPdu({it:?})")
229            }
230            Self::ServerDeviceAnnounceResponse(it) => {
231                write!(f, "RdpdrPdu({it:?})")
232            }
233            Self::DeviceIoRequest(it) => {
234                write!(f, "RdpdrPdu({it:?})")
235            }
236            Self::DeviceControlResponse(it) => {
237                write!(f, "RdpdrPdu({it:?})")
238            }
239            Self::DeviceCreateResponse(it) => {
240                write!(f, "RdpdrPdu({it:?})")
241            }
242            Self::ClientDriveQueryInformationResponse(it) => {
243                write!(f, "RdpdrPdu({it:?})")
244            }
245            Self::DeviceCloseResponse(it) => {
246                write!(f, "RdpdrPdu({it:?})")
247            }
248            Self::ClientDriveQueryDirectoryResponse(it) => {
249                write!(f, "RdpdrPdu({it:?})")
250            }
251            Self::ClientDriveQueryVolumeInformationResponse(it) => {
252                write!(f, "RdpdrPdu({it:?})")
253            }
254            Self::DeviceReadResponse(it) => {
255                write!(f, "RdpdrPdu({it:?})")
256            }
257            Self::DeviceWriteResponse(it) => {
258                write!(f, "RdpdrPdu({it:?})")
259            }
260            Self::ClientDriveSetInformationResponse(it) => {
261                write!(f, "RdpdrPdu({it:?})")
262            }
263            Self::UserLoggedon => {
264                write!(f, "RdpdrPdu(UserLoggedon)")
265            }
266            Self::EmptyResponse => {
267                write!(f, "RdpdrPdu(EmptyResponse)")
268            }
269        }
270    }
271}
272
273impl From<DeviceControlResponse> for RdpdrPdu {
274    fn from(value: DeviceControlResponse) -> Self {
275        Self::DeviceControlResponse(value)
276    }
277}
278
279impl From<DeviceCreateResponse> for RdpdrPdu {
280    fn from(value: DeviceCreateResponse) -> Self {
281        Self::DeviceCreateResponse(value)
282    }
283}
284
285impl From<ClientDriveQueryInformationResponse> for RdpdrPdu {
286    fn from(value: ClientDriveQueryInformationResponse) -> Self {
287        Self::ClientDriveQueryInformationResponse(value)
288    }
289}
290
291impl From<DeviceCloseResponse> for RdpdrPdu {
292    fn from(value: DeviceCloseResponse) -> Self {
293        Self::DeviceCloseResponse(value)
294    }
295}
296
297impl From<ClientDriveQueryDirectoryResponse> for RdpdrPdu {
298    fn from(value: ClientDriveQueryDirectoryResponse) -> Self {
299        Self::ClientDriveQueryDirectoryResponse(value)
300    }
301}
302
303impl From<ClientDriveQueryVolumeInformationResponse> for RdpdrPdu {
304    fn from(value: ClientDriveQueryVolumeInformationResponse) -> Self {
305        Self::ClientDriveQueryVolumeInformationResponse(value)
306    }
307}
308
309impl From<DeviceReadResponse> for RdpdrPdu {
310    fn from(value: DeviceReadResponse) -> Self {
311        Self::DeviceReadResponse(value)
312    }
313}
314
315impl From<DeviceWriteResponse> for RdpdrPdu {
316    fn from(value: DeviceWriteResponse) -> Self {
317        Self::DeviceWriteResponse(value)
318    }
319}
320
321impl From<ClientDriveSetInformationResponse> for RdpdrPdu {
322    fn from(value: ClientDriveSetInformationResponse) -> Self {
323        Self::ClientDriveSetInformationResponse(value)
324    }
325}
326
327/// [2.2.1.1] Shared Header (RDPDR_HEADER), a header that is shared by all RDPDR PDUs.
328///
329/// [2.2.1.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/29d4108f-8163-4a67-8271-e48c4b9c2a7c
330#[derive(Debug)]
331pub struct SharedHeader {
332    pub component: Component,
333    pub packet_id: PacketId,
334}
335
336impl SharedHeader {
337    const SIZE: usize = size_of::<u16>() * 2;
338
339    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
340        ensure_size!(in: dst, size: Self::SIZE);
341        dst.write_u16(self.component.into());
342        dst.write_u16(self.packet_id.into());
343        Ok(())
344    }
345
346    pub fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
347        ensure_size!(in: src, size: Self::SIZE);
348        Ok(Self {
349            component: src.read_u16().try_into()?,
350            packet_id: src.read_u16().try_into()?,
351        })
352    }
353}
354
355#[derive(Debug, Clone, Copy)]
356#[repr(u16)]
357pub enum Component {
358    /// RDPDR_CTYP_CORE
359    RdpdrCtypCore = 0x4472,
360    /// RDPDR_CTYP_PRN
361    RdpdrCtypPrn = 0x5052,
362}
363
364impl TryFrom<u16> for Component {
365    type Error = DecodeError;
366
367    fn try_from(value: u16) -> Result<Self, Self::Error> {
368        match value {
369            0x4472 => Ok(Component::RdpdrCtypCore),
370            0x5052 => Ok(Component::RdpdrCtypPrn),
371            _ => Err(invalid_field_err!("try_from", "Component", "invalid value")),
372        }
373    }
374}
375
376impl From<Component> for u16 {
377    fn from(component: Component) -> Self {
378        component as u16
379    }
380}
381
382#[derive(Debug, Clone, Copy)]
383#[repr(u16)]
384pub enum PacketId {
385    /// PAKID_CORE_SERVER_ANNOUNCE
386    CoreServerAnnounce = 0x496E,
387    /// PAKID_CORE_CLIENTID_CONFIRM
388    CoreClientidConfirm = 0x4343,
389    /// PAKID_CORE_CLIENT_NAME
390    CoreClientName = 0x434E,
391    /// PAKID_CORE_DEVICELIST_ANNOUNCE
392    CoreDevicelistAnnounce = 0x4441,
393    /// PAKID_CORE_DEVICE_REPLY
394    CoreDeviceReply = 0x6472,
395    /// PAKID_CORE_DEVICE_IOREQUEST
396    CoreDeviceIoRequest = 0x4952,
397    /// PAKID_CORE_DEVICE_IOCOMPLETION
398    CoreDeviceIoCompletion = 0x4943,
399    /// PAKID_CORE_SERVER_CAPABILITY
400    CoreServerCapability = 0x5350,
401    /// PAKID_CORE_CLIENT_CAPABILITY
402    CoreClientCapability = 0x4350,
403    /// PAKID_CORE_DEVICELIST_REMOVE
404    CoreDevicelistRemove = 0x444D,
405    /// PAKID_PRN_CACHE_DATA
406    PrnCacheData = 0x5043,
407    /// PAKID_CORE_USER_LOGGEDON
408    CoreUserLoggedon = 0x554C,
409    /// PAKID_PRN_USING_XPS
410    PrnUsingXps = 0x5543,
411}
412
413impl TryFrom<u16> for PacketId {
414    type Error = DecodeError;
415
416    fn try_from(value: u16) -> Result<Self, Self::Error> {
417        match value {
418            0x496E => Ok(PacketId::CoreServerAnnounce),
419            0x4343 => Ok(PacketId::CoreClientidConfirm),
420            0x434E => Ok(PacketId::CoreClientName),
421            0x4441 => Ok(PacketId::CoreDevicelistAnnounce),
422            0x6472 => Ok(PacketId::CoreDeviceReply),
423            0x4952 => Ok(PacketId::CoreDeviceIoRequest),
424            0x4943 => Ok(PacketId::CoreDeviceIoCompletion),
425            0x5350 => Ok(PacketId::CoreServerCapability),
426            0x4350 => Ok(PacketId::CoreClientCapability),
427            0x444D => Ok(PacketId::CoreDevicelistRemove),
428            0x5043 => Ok(PacketId::PrnCacheData),
429            0x554C => Ok(PacketId::CoreUserLoggedon),
430            0x5543 => Ok(PacketId::PrnUsingXps),
431            _ => Err(invalid_field_err!("try_from", "PacketId", "invalid value")),
432        }
433    }
434}
435
436impl Display for PacketId {
437    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438        match self {
439            PacketId::CoreServerAnnounce => write!(f, "PAKID_CORE_SERVER_ANNOUNCE"),
440            PacketId::CoreClientidConfirm => write!(f, "PAKID_CORE_CLIENTID_CONFIRM"),
441            PacketId::CoreClientName => write!(f, "PAKID_CORE_CLIENT_NAME"),
442            PacketId::CoreDevicelistAnnounce => write!(f, "PAKID_CORE_DEVICELIST_ANNOUNCE"),
443            PacketId::CoreDeviceReply => write!(f, "PAKID_CORE_DEVICE_REPLY"),
444            PacketId::CoreDeviceIoRequest => write!(f, "PAKID_CORE_DEVICE_IOREQUEST"),
445            PacketId::CoreDeviceIoCompletion => write!(f, "PAKID_CORE_DEVICE_IOCOMPLETION"),
446            PacketId::CoreServerCapability => write!(f, "PAKID_CORE_SERVER_CAPABILITY"),
447            PacketId::CoreClientCapability => write!(f, "PAKID_CORE_CLIENT_CAPABILITY"),
448            PacketId::CoreDevicelistRemove => write!(f, "PAKID_CORE_DEVICELIST_REMOVE"),
449            PacketId::PrnCacheData => write!(f, "PAKID_PRN_CACHE_DATA"),
450            PacketId::CoreUserLoggedon => write!(f, "PAKID_CORE_USER_LOGGEDON"),
451            PacketId::PrnUsingXps => write!(f, "PAKID_PRN_USING_XPS"),
452        }
453    }
454}
455
456impl From<PacketId> for u16 {
457    fn from(packet_id: PacketId) -> Self {
458        packet_id as u16
459    }
460}