From ad3c2eaa7034e4e67a76bc04e3944a1311120ec8 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Sun, 24 Sep 2023 12:33:20 -0700 Subject: [PATCH 1/4] Adds decoding for ServerDeviceAnnounceResponse --- crates/ironrdp-rdpdr/src/lib.rs | 4 ++ crates/ironrdp-rdpdr/src/pdu/efs.rs | 88 +++++++++++++++++++++++++++-- crates/ironrdp-rdpdr/src/pdu/mod.rs | 18 +++++- 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/crates/ironrdp-rdpdr/src/lib.rs b/crates/ironrdp-rdpdr/src/lib.rs index eaff126f9..8720e07cc 100644 --- a/crates/ironrdp-rdpdr/src/lib.rs +++ b/crates/ironrdp-rdpdr/src/lib.rs @@ -112,6 +112,10 @@ impl StaticVirtualChannelProcessor for Rdpdr { RdpdrPdu::VersionAndIdPdu(pdu) if pdu.kind == VersionAndIdPduKind::ServerClientIdConfirm => { self.handle_client_id_confirm() } + RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => { + warn!("received unimplemented packet: {:?}", pdu); // todo + Ok(Vec::new()) + } RdpdrPdu::Unimplemented => { warn!("received unimplemented packet: {:?}", pdu); Ok(Vec::new()) diff --git a/crates/ironrdp-rdpdr/src/pdu/efs.rs b/crates/ironrdp-rdpdr/src/pdu/efs.rs index 189130f51..4aca7ebff 100644 --- a/crates/ironrdp-rdpdr/src/pdu/efs.rs +++ b/crates/ironrdp-rdpdr/src/pdu/efs.rs @@ -71,7 +71,7 @@ impl VersionAndIdPdu { Ok(()) } - pub fn decode(header: SharedHeader, src: &mut ReadCursor) -> PduResult { + pub fn decode(header: SharedHeader, payload: &mut ReadCursor) -> PduResult { let kind = match header.packet_id { PacketId::CoreServerAnnounce => VersionAndIdPduKind::ServerAnnounceRequest, PacketId::CoreClientidConfirm => VersionAndIdPduKind::ServerClientIdConfirm, @@ -84,10 +84,10 @@ impl VersionAndIdPdu { } }; - ensure_size!(ctx: kind.name(), in: src, size: Self::FIXED_PART_SIZE); - let version_major = src.read_u16(); - let version_minor = src.read_u16(); - let client_id = src.read_u32(); + ensure_size!(ctx: kind.name(), in: payload, size: Self::FIXED_PART_SIZE); + let version_major = payload.read_u16(); + let version_minor = payload.read_u16(); + let client_id = payload.read_u32(); Ok(Self { version_major, @@ -874,3 +874,81 @@ impl TryFrom for DeviceType { } } } + +/// [2.2.2.1 Server Device Announce Response (DR_CORE_DEVICE_ANNOUNCE_RSP)] +/// +/// [2.2.2.1 Server Device Announce Response (DR_CORE_DEVICE_ANNOUNCE_RSP)]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/a4c0b619-6e87-4721-bdc4-5d2db7f485f3 +#[derive(Debug)] +pub struct ServerDeviceAnnounceResponse { + pub device_id: u32, + pub result_code: NtStatus, +} + +impl ServerDeviceAnnounceResponse { + const NAME: &str = "DR_CORE_DEVICE_ANNOUNCE_RSP"; + const FIXED_PART_SIZE: usize = size_of::() * 2; // DeviceId, ResultCode + + pub fn name(&self) -> &'static str { + Self::NAME + } + + pub fn encode(&self, dst: &mut WriteCursor) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + dst.write_u32(self.device_id); + dst.write_u32(self.result_code as u32); + Ok(()) + } + + pub fn decode(payload: &mut ReadCursor<'_>) -> PduResult { + ensure_size!(ctx: Self::NAME, in: payload, size: Self::FIXED_PART_SIZE); + let device_id = payload.read_u32(); + let result_code = NtStatus::try_from(payload.read_u32())?; + + Ok(Self { device_id, result_code }) + } + + pub fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +/// [2.3.1 NTSTATUS Values] +/// +/// Windows defines an absolutely massive list of potential NTSTATUS values. +/// This enum includes some basic ones for communicating with the RDP server. +/// +/// [2.3.1 NTSTATUS Values]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 +#[derive(Debug, PartialEq, Copy, Clone)] +#[repr(u32)] +pub enum NtStatus { + Success = 0x00000000, + Unsuccessful = 0xC0000001, + NotImplemented = 0xC0000002, + NoMoreFiles = 0x80000006, + ObjectNameCollision = 0xC0000035, + AccessDenied = 0xC0000022, + NotADirectory = 0xC0000103, + NoSuchFile = 0xC000000F, + NotSupported = 0xC00000BB, + DirectoryNotEmpty = 0xC0000101, +} + +impl std::convert::TryFrom for NtStatus { + type Error = PduError; + + fn try_from(value: u32) -> Result { + match value { + 0x00000000 => Ok(NtStatus::Success), + 0xC0000001 => Ok(NtStatus::Unsuccessful), + 0xC0000002 => Ok(NtStatus::NotImplemented), + 0x80000006 => Ok(NtStatus::NoMoreFiles), + 0xC0000035 => Ok(NtStatus::ObjectNameCollision), + 0xC0000022 => Ok(NtStatus::AccessDenied), + 0xC0000103 => Ok(NtStatus::NotADirectory), + 0xC000000F => Ok(NtStatus::NoSuchFile), + 0xC00000BB => Ok(NtStatus::NotSupported), + 0xC0000101 => Ok(NtStatus::DirectoryNotEmpty), + _ => Err(invalid_message_err!("try_from", "NtStatus", "unsupported value")), + } + } +} diff --git a/crates/ironrdp-rdpdr/src/pdu/mod.rs b/crates/ironrdp-rdpdr/src/pdu/mod.rs index 93bf86416..832d9c5a3 100644 --- a/crates/ironrdp-rdpdr/src/pdu/mod.rs +++ b/crates/ironrdp-rdpdr/src/pdu/mod.rs @@ -5,8 +5,8 @@ use ironrdp_pdu::cursor::{ReadCursor, WriteCursor}; use ironrdp_pdu::{ensure_size, invalid_message_err, PduDecode, PduEncode, PduError, PduResult}; use self::efs::{ - ClientDeviceListAnnounce, ClientNameRequest, CoreCapability, CoreCapabilityKind, VersionAndIdPdu, - VersionAndIdPduKind, + ClientDeviceListAnnounce, ClientNameRequest, CoreCapability, CoreCapabilityKind, ServerDeviceAnnounceResponse, + VersionAndIdPdu, VersionAndIdPduKind, }; pub mod efs; @@ -17,6 +17,7 @@ pub enum RdpdrPdu { ClientNameRequest(ClientNameRequest), CoreCapability(CoreCapability), ClientDeviceListAnnounce(ClientDeviceListAnnounce), + ServerDeviceAnnounceResponse(ServerDeviceAnnounceResponse), /// TODO: temporary value for development, this should be removed Unimplemented, } @@ -57,6 +58,10 @@ impl RdpdrPdu { component: Component::RdpdrCtypCore, packet_id: PacketId::CoreDevicelistAnnounce, }, + RdpdrPdu::ServerDeviceAnnounceResponse(_) => SharedHeader { + component: Component::RdpdrCtypCore, + packet_id: PacketId::CoreDeviceReply, + }, RdpdrPdu::Unimplemented => SharedHeader { component: Component::Unimplemented, packet_id: PacketId::Unimplemented, @@ -72,6 +77,9 @@ impl PduDecode<'_> for RdpdrPdu { PacketId::CoreServerAnnounce => Ok(RdpdrPdu::VersionAndIdPdu(VersionAndIdPdu::decode(header, src)?)), PacketId::CoreServerCapability => Ok(RdpdrPdu::CoreCapability(CoreCapability::decode(header, src)?)), PacketId::CoreClientidConfirm => Ok(RdpdrPdu::VersionAndIdPdu(VersionAndIdPdu::decode(header, src)?)), + PacketId::CoreDeviceReply => Ok(RdpdrPdu::ServerDeviceAnnounceResponse( + ServerDeviceAnnounceResponse::decode(src)?, + )), _ => Ok(RdpdrPdu::Unimplemented), } } @@ -86,6 +94,7 @@ impl PduEncode for RdpdrPdu { RdpdrPdu::ClientNameRequest(pdu) => pdu.encode(dst), RdpdrPdu::CoreCapability(pdu) => pdu.encode(dst), RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.encode(dst), + RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.encode(dst), RdpdrPdu::Unimplemented => Ok(()), } } @@ -96,6 +105,7 @@ impl PduEncode for RdpdrPdu { RdpdrPdu::ClientNameRequest(pdu) => pdu.name(), RdpdrPdu::CoreCapability(pdu) => pdu.name(), RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.name(), + RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.name(), RdpdrPdu::Unimplemented => "Unimplemented", } } @@ -107,6 +117,7 @@ impl PduEncode for RdpdrPdu { RdpdrPdu::ClientNameRequest(pdu) => pdu.size(), RdpdrPdu::CoreCapability(pdu) => pdu.size(), RdpdrPdu::ClientDeviceListAnnounce(pdu) => pdu.size(), + RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => pdu.size(), RdpdrPdu::Unimplemented => 0, } } @@ -127,6 +138,9 @@ impl fmt::Debug for RdpdrPdu { Self::ClientDeviceListAnnounce(it) => { write!(f, "RdpdrPdu({:?})", it) } + Self::ServerDeviceAnnounceResponse(it) => { + write!(f, "RdpdrPdu({:?})", it) + } Self::Unimplemented => { write!(f, "RdpdrPdu::Unimplemented") } From a1eb5aebdadbd165a590730fc2a8ebf2f6fdf7a8 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Sun, 1 Oct 2023 21:04:30 -0700 Subject: [PATCH 2/4] payload --> src --- crates/ironrdp-rdpdr/src/pdu/efs.rs | 74 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/crates/ironrdp-rdpdr/src/pdu/efs.rs b/crates/ironrdp-rdpdr/src/pdu/efs.rs index 4aca7ebff..a35597747 100644 --- a/crates/ironrdp-rdpdr/src/pdu/efs.rs +++ b/crates/ironrdp-rdpdr/src/pdu/efs.rs @@ -71,7 +71,7 @@ impl VersionAndIdPdu { Ok(()) } - pub fn decode(header: SharedHeader, payload: &mut ReadCursor) -> PduResult { + pub fn decode(header: SharedHeader, src: &mut ReadCursor) -> PduResult { let kind = match header.packet_id { PacketId::CoreServerAnnounce => VersionAndIdPduKind::ServerAnnounceRequest, PacketId::CoreClientidConfirm => VersionAndIdPduKind::ServerClientIdConfirm, @@ -84,10 +84,10 @@ impl VersionAndIdPdu { } }; - ensure_size!(ctx: kind.name(), in: payload, size: Self::FIXED_PART_SIZE); - let version_major = payload.read_u16(); - let version_minor = payload.read_u16(); - let client_id = payload.read_u32(); + ensure_size!(ctx: kind.name(), in: src, size: Self::FIXED_PART_SIZE); + let version_major = src.read_u16(); + let version_minor = src.read_u16(); + let client_id = src.read_u32(); Ok(Self { version_major, @@ -208,7 +208,7 @@ impl CoreCapability { Ok(()) } - pub fn decode(header: SharedHeader, payload: &mut ReadCursor<'_>) -> PduResult { + pub fn decode(header: SharedHeader, src: &mut ReadCursor<'_>) -> PduResult { let kind = match header.packet_id { PacketId::CoreServerCapability => CoreCapabilityKind::ServerCoreCapabilityRequest, PacketId::CoreClientCapability => CoreCapabilityKind::ClientCoreCapabilityResponse, @@ -221,13 +221,13 @@ impl CoreCapability { } }; - ensure_size!(ctx: kind.name(), in: payload, size: Self::FIXED_PART_SIZE); + ensure_size!(ctx: kind.name(), in: src, size: Self::FIXED_PART_SIZE); - let num_capabilities = payload.read_u16(); - let padding = payload.read_u16(); + let num_capabilities = src.read_u16(); + let padding = src.read_u16(); let mut capabilities = Vec::new(); for _ in 0..num_capabilities { - capabilities.push(CapabilityMessage::decode(payload)?); + capabilities.push(CapabilityMessage::decode(src)?); } Ok(Self { @@ -372,9 +372,9 @@ impl CapabilityMessage { self.capability_data.encode(dst) } - fn decode(payload: &mut ReadCursor<'_>) -> PduResult { - let header = CapabilityHeader::decode(payload)?; - let capability_data = CapabilityData::decode(payload, &header)?; + fn decode(src: &mut ReadCursor<'_>) -> PduResult { + let header = CapabilityHeader::decode(src)?; + let capability_data = CapabilityData::decode(src, &header)?; Ok(Self { header, @@ -423,11 +423,11 @@ impl CapabilityHeader { } } - fn decode(payload: &mut ReadCursor<'_>) -> PduResult { - ensure_size!(in: payload, size: Self::SIZE); - let cap_type: CapabilityType = payload.read_u16().try_into()?; - let length = payload.read_u16(); - let version = payload.read_u32(); + fn decode(src: &mut ReadCursor<'_>) -> PduResult { + ensure_size!(in: src, size: Self::SIZE); + let cap_type: CapabilityType = src.read_u16().try_into()?; + let length = src.read_u16(); + let version = src.read_u32(); Ok(Self { cap_type, @@ -499,10 +499,10 @@ impl CapabilityData { } } - fn decode(payload: &mut ReadCursor<'_>, header: &CapabilityHeader) -> PduResult { + fn decode(src: &mut ReadCursor<'_>, header: &CapabilityHeader) -> PduResult { match header.cap_type { CapabilityType::General => Ok(CapabilityData::General(GeneralCapabilitySet::decode( - payload, + src, header.version, )?)), CapabilityType::Printer => Ok(CapabilityData::Printer), @@ -575,22 +575,22 @@ impl GeneralCapabilitySet { Ok(()) } - fn decode(payload: &mut ReadCursor<'_>, version: u32) -> PduResult { - ensure_size!(in: payload, size: Self::SIZE); - let os_type = payload.read_u32(); - let os_version = payload.read_u32(); - let protocol_major_version = payload.read_u16(); - let protocol_minor_version = payload.read_u16(); - let io_code_1 = IoCode1::from_bits(payload.read_u32()) - .ok_or_else(|| invalid_message_err!("io_code_1", "invalid io_code_1"))?; - let io_code_2 = payload.read_u32(); - let extended_pdu = ExtendedPdu::from_bits(payload.read_u32()) + fn decode(src: &mut ReadCursor<'_>, version: u32) -> PduResult { + ensure_size!(in: src, size: Self::SIZE); + let os_type = src.read_u32(); + let os_version = src.read_u32(); + let protocol_major_version = src.read_u16(); + let protocol_minor_version = src.read_u16(); + let io_code_1 = + IoCode1::from_bits(src.read_u32()).ok_or_else(|| invalid_message_err!("io_code_1", "invalid io_code_1"))?; + let io_code_2 = src.read_u32(); + let extended_pdu = ExtendedPdu::from_bits(src.read_u32()) .ok_or_else(|| invalid_message_err!("extended_pdu", "invalid extended_pdu"))?; - let extra_flags_1 = ExtraFlags1::from_bits(payload.read_u32()) + let extra_flags_1 = ExtraFlags1::from_bits(src.read_u32()) .ok_or_else(|| invalid_message_err!("extra_flags_1", "invalid extra_flags_1"))?; - let extra_flags_2 = payload.read_u32(); + let extra_flags_2 = src.read_u32(); let special_type_device_cap = if version == GENERAL_CAPABILITY_VERSION_02 { - payload.read_u32() + src.read_u32() } else { 0 }; @@ -899,10 +899,10 @@ impl ServerDeviceAnnounceResponse { Ok(()) } - pub fn decode(payload: &mut ReadCursor<'_>) -> PduResult { - ensure_size!(ctx: Self::NAME, in: payload, size: Self::FIXED_PART_SIZE); - let device_id = payload.read_u32(); - let result_code = NtStatus::try_from(payload.read_u32())?; + pub fn decode(src: &mut ReadCursor<'_>) -> PduResult { + ensure_size!(ctx: Self::NAME, in: src, size: Self::FIXED_PART_SIZE); + let device_id = src.read_u32(); + let result_code = NtStatus::try_from(src.read_u32())?; Ok(Self { device_id, result_code }) } From 5a32895b9d0d1caa515afc5da06537b5738f9cc0 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Sun, 1 Oct 2023 21:08:04 -0700 Subject: [PATCH 3/4] use tracing log format --- crates/ironrdp-rdpdr/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/ironrdp-rdpdr/src/lib.rs b/crates/ironrdp-rdpdr/src/lib.rs index 8720e07cc..f775d18d2 100644 --- a/crates/ironrdp-rdpdr/src/lib.rs +++ b/crates/ironrdp-rdpdr/src/lib.rs @@ -5,12 +5,14 @@ #![allow(clippy::cast_possible_wrap)] // FIXME: remove #![allow(clippy::cast_sign_loss)] // FIXME: remove +#[macro_use] +extern crate tracing; + pub mod pdu; use ironrdp_pdu::gcc::ChannelName; use ironrdp_pdu::{decode, other_err, PduResult}; use ironrdp_svc::{impl_as_any, CompressionCondition, StaticVirtualChannelProcessor, SvcMessage}; -use tracing::{trace, warn}; use crate::pdu::efs::{ Capabilities, ClientDeviceListAnnounce, ClientNameRequest, ClientNameRequestUnicodeFlag, CoreCapability, @@ -113,11 +115,11 @@ impl StaticVirtualChannelProcessor for Rdpdr { self.handle_client_id_confirm() } RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => { - warn!("received unimplemented packet: {:?}", pdu); // todo + warn!(?pdu, "received unimplemented packet"); // todo Ok(Vec::new()) } RdpdrPdu::Unimplemented => { - warn!("received unimplemented packet: {:?}", pdu); + warn!(?pdu, "received unimplemented packet"); Ok(Vec::new()) } _ => Err(other_err!("rdpdr", "internal error")), From 2b9e6431db96087fab8f156e6856d017257f83a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Mon, 2 Oct 2023 11:01:54 -0400 Subject: [PATCH 4/4] Fix lints --- crates/ironrdp-rdpdr/src/pdu/efs.rs | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/ironrdp-rdpdr/src/pdu/efs.rs b/crates/ironrdp-rdpdr/src/pdu/efs.rs index a35597747..0067c88fc 100644 --- a/crates/ironrdp-rdpdr/src/pdu/efs.rs +++ b/crates/ironrdp-rdpdr/src/pdu/efs.rs @@ -921,33 +921,33 @@ impl ServerDeviceAnnounceResponse { #[derive(Debug, PartialEq, Copy, Clone)] #[repr(u32)] pub enum NtStatus { - Success = 0x00000000, - Unsuccessful = 0xC0000001, - NotImplemented = 0xC0000002, - NoMoreFiles = 0x80000006, - ObjectNameCollision = 0xC0000035, - AccessDenied = 0xC0000022, - NotADirectory = 0xC0000103, - NoSuchFile = 0xC000000F, - NotSupported = 0xC00000BB, - DirectoryNotEmpty = 0xC0000101, -} - -impl std::convert::TryFrom for NtStatus { + Success = 0x0000_0000, + Unsuccessful = 0xC000_0001, + NotImplemented = 0xC000_0002, + NoMoreFiles = 0x8000_0006, + ObjectNameCollision = 0xC000_0035, + AccessDenied = 0xC000_0022, + NotADirectory = 0xC000_0103, + NoSuchFile = 0xC000_000F, + NotSupported = 0xC000_00BB, + DirectoryNotEmpty = 0xC000_0101, +} + +impl TryFrom for NtStatus { type Error = PduError; fn try_from(value: u32) -> Result { match value { - 0x00000000 => Ok(NtStatus::Success), - 0xC0000001 => Ok(NtStatus::Unsuccessful), - 0xC0000002 => Ok(NtStatus::NotImplemented), - 0x80000006 => Ok(NtStatus::NoMoreFiles), - 0xC0000035 => Ok(NtStatus::ObjectNameCollision), - 0xC0000022 => Ok(NtStatus::AccessDenied), - 0xC0000103 => Ok(NtStatus::NotADirectory), - 0xC000000F => Ok(NtStatus::NoSuchFile), - 0xC00000BB => Ok(NtStatus::NotSupported), - 0xC0000101 => Ok(NtStatus::DirectoryNotEmpty), + 0x0000_0000 => Ok(NtStatus::Success), + 0xC000_0001 => Ok(NtStatus::Unsuccessful), + 0xC000_0002 => Ok(NtStatus::NotImplemented), + 0x8000_0006 => Ok(NtStatus::NoMoreFiles), + 0xC000_0035 => Ok(NtStatus::ObjectNameCollision), + 0xC000_0022 => Ok(NtStatus::AccessDenied), + 0xC000_0103 => Ok(NtStatus::NotADirectory), + 0xC000_000F => Ok(NtStatus::NoSuchFile), + 0xC000_00BB => Ok(NtStatus::NotSupported), + 0xC000_0101 => Ok(NtStatus::DirectoryNotEmpty), _ => Err(invalid_message_err!("try_from", "NtStatus", "unsupported value")), } }