From 2a8da087fdfe51b6c90eab608ba83d54debeda2e Mon Sep 17 00:00:00 2001 From: Greg Lamberson Date: Wed, 13 May 2026 13:46:15 -0500 Subject: [PATCH] feat(error): record byte offset on decode and encode error variants Reshapes the position-aware error approach per #1266 review feedback. Moves position metadata out of the foundational `ironrdp-error` crate and onto the decode and encode `*ErrorKind` enum variants where it actually applies. Previously this PR added an optional `ErrorPosition { offset, field }` slot to `Error`'s `ErrorMeta`, paying a metadata slot on every error in the workspace to serve only the decode and encode surfaces. The new shape places a non-optional `offset: usize` on each variant that can know one: - `DecodeErrorKind::{NotEnoughBytes, InvalidField, UnexpectedMessageType, UnsupportedVersion, UnsupportedValue}` gain `offset: usize` - `EncodeErrorKind::*` mirrors the same shape for encode-side errors - `*::Other` is unchanged; producers of `Other` typically lack stream-cursor access and the variant exists precisely for those cases The `in_field` dotted-path use case is dropped from this PR per the same review: `Error::set_context` already covers it. No parallel structured field-tracking channel is introduced. Trait and macro changes: - `NotEnoughBytesErr`, `InvalidFieldErr`, `UnexpectedMessageTypeErr`, `UnsupportedVersionErr`, `UnsupportedValueErr` all take an additional `offset: usize` parameter - The five corresponding `*_err!` macros gain `at:` and `in:` prefixes for explicit offset and cursor-extracted offset respectively - `OtherErr` and `other_err!` are unchanged - `cast_length!` and `cast_int!` macros pass `0` to the new offset slot (the macros do not have stream-cursor access) Call-site migration: - All 84 affected files updated to pass an explicit offset - Most existing call sites pass `0` (the documented "offset unknown" sentinel) since the cursor is not always in lexical scope at the call site - Cursor-aware sites can opt in via the new `in: cursor` macro syntax - A workspace sweep upgrading `at: 0` to `in: cursor` where applicable is a follow-up Display output includes the offset when known: `invalid \`field\` at offset 47: reason` Refs #1257, #1120. Supersedes the cross-cutting `ErrorPosition` approach that was on this branch before today's review. --- crates/ironrdp-ainput/src/lib.rs | 8 +- crates/ironrdp-cfg/src/lib.rs | 3 +- crates/ironrdp-cliprdr-format/src/bitmap.rs | 12 +- .../ironrdp-cliprdr/src/pdu/capabilities.rs | 6 +- .../src/pdu/client_temporary_directory.rs | 2 +- .../ironrdp-cliprdr/src/pdu/file_contents.rs | 37 ++--- .../src/pdu/format_data/file_list.rs | 12 +- crates/ironrdp-cliprdr/src/pdu/format_list.rs | 2 +- crates/ironrdp-cliprdr/src/pdu/mod.rs | 2 +- crates/ironrdp-core/src/decode.rs | 99 +++++++++---- crates/ironrdp-core/src/encode.rs | 97 ++++++++---- crates/ironrdp-core/src/error.rs | 139 ++++++------------ crates/ironrdp-core/src/macros.rs | 83 +++++++++-- crates/ironrdp-displaycontrol/src/pdu/mod.rs | 52 +++---- crates/ironrdp-dvc/src/client.rs | 2 +- crates/ironrdp-dvc/src/complete_data.rs | 2 +- crates/ironrdp-dvc/src/lib.rs | 3 +- crates/ironrdp-dvc/src/pdu.rs | 12 +- crates/ironrdp-dvc/src/server.rs | 2 +- crates/ironrdp-egfx/src/pdu/avc.rs | 4 +- crates/ironrdp-egfx/src/pdu/cmd.rs | 18 +-- crates/ironrdp-egfx/src/pdu/common.rs | 2 +- crates/ironrdp-graphics/src/clearcodec/mod.rs | 30 ++-- .../src/rdp6/bitmap_stream/encoder.rs | 2 + crates/ironrdp-mstsgu/src/proto.rs | 4 +- .../src/basic_output/bitmap/mod.rs | 22 +-- .../src/basic_output/bitmap/rdp6.rs | 8 +- .../src/basic_output/fast_path/mod.rs | 16 +- .../src/basic_output/pointer/mod.rs | 14 +- .../ironrdp-pdu/src/basic_output/slow_path.rs | 14 +- .../src/basic_output/surface_commands/mod.rs | 4 +- crates/ironrdp-pdu/src/ber.rs | 20 +-- .../src/codecs/clearcodec/bands.rs | 11 +- .../ironrdp-pdu/src/codecs/clearcodec/mod.rs | 2 +- .../ironrdp-pdu/src/codecs/clearcodec/rlex.rs | 4 +- .../src/codecs/clearcodec/subcodec.rs | 4 +- .../src/codecs/rfx/data_messages.rs | 36 ++--- .../src/codecs/rfx/header_messages.rs | 12 +- crates/ironrdp-pdu/src/codecs/rfx/mod.rs | 10 +- .../ironrdp-pdu/src/codecs/rfx/progressive.rs | 30 ++-- crates/ironrdp-pdu/src/gcc/cluster_data.rs | 4 +- .../ironrdp-pdu/src/gcc/conference_create.rs | 94 ++++-------- .../ironrdp-pdu/src/gcc/core_data/client.rs | 76 ++++------ .../ironrdp-pdu/src/gcc/core_data/server.rs | 4 +- crates/ironrdp-pdu/src/gcc/mod.rs | 16 +- crates/ironrdp-pdu/src/gcc/monitor_data.rs | 4 +- .../src/gcc/monitor_extended_data.rs | 6 +- .../src/gcc/multi_transport_channel_data.rs | 2 +- crates/ironrdp-pdu/src/gcc/network_data.rs | 4 +- crates/ironrdp-pdu/src/gcc/security_data.rs | 16 +- crates/ironrdp-pdu/src/input/fast_path.rs | 12 +- crates/ironrdp-pdu/src/input/mod.rs | 2 +- crates/ironrdp-pdu/src/lib.rs | 2 +- crates/ironrdp-pdu/src/mcs.rs | 21 ++- crates/ironrdp-pdu/src/nego.rs | 9 +- crates/ironrdp-pdu/src/pcb.rs | 5 +- crates/ironrdp-pdu/src/rdp/autodetect.rs | 16 +- .../src/rdp/capability_sets/bitmap.rs | 6 +- .../rdp/capability_sets/bitmap_codecs/mod.rs | 28 ++-- .../src/rdp/capability_sets/brush/mod.rs | 2 +- .../src/rdp/capability_sets/general/mod.rs | 8 +- .../rdp/capability_sets/glyph_cache/mod.rs | 2 +- .../src/rdp/capability_sets/mod.rs | 8 +- crates/ironrdp-pdu/src/rdp/client_info.rs | 10 +- .../src/rdp/finalization_messages.rs | 8 +- crates/ironrdp-pdu/src/rdp/headers.rs | 16 +- crates/ironrdp-pdu/src/rdp/mod.rs | 2 +- crates/ironrdp-pdu/src/rdp/multitransport.rs | 6 +- .../ironrdp-pdu/src/rdp/server_error_info.rs | 4 +- .../rdp/server_license/client_license_info.rs | 10 +- .../client_new_license_request/mod.rs | 10 +- .../client_platform_challenge_response/mod.rs | 16 +- .../licensing_error_message/mod.rs | 8 +- .../ironrdp-pdu/src/rdp/server_license/mod.rs | 18 +-- .../server_license_request/cert.rs | 20 +-- .../server_license_request/mod.rs | 22 +-- .../server_platform_challenge/mod.rs | 2 +- .../server_upgrade_license/mod.rs | 8 +- .../src/rdp/session_info/logon_extended.rs | 6 +- .../src/rdp/session_info/logon_info.rs | 12 +- .../ironrdp-pdu/src/rdp/session_info/mod.rs | 2 +- crates/ironrdp-pdu/src/rdp/suppress_output.rs | 2 +- crates/ironrdp-pdu/src/tpdu.rs | 4 +- crates/ironrdp-pdu/src/tpkt.rs | 2 +- crates/ironrdp-pdu/src/utils.rs | 4 +- crates/ironrdp-pdu/src/x224.rs | 1 + crates/ironrdp-rdpdr/src/pdu/efs.rs | 82 ++++------- crates/ironrdp-rdpdr/src/pdu/esc/mod.rs | 34 ++--- crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs | 2 +- crates/ironrdp-rdpdr/src/pdu/esc/rpce.rs | 8 +- crates/ironrdp-rdpdr/src/pdu/mod.rs | 10 +- crates/ironrdp-rdpeusb/src/pdu/caps.rs | 6 +- .../ironrdp-rdpeusb/src/pdu/completion/mod.rs | 10 +- .../src/pdu/completion/ts_urb_result.rs | 17 ++- crates/ironrdp-rdpeusb/src/pdu/header.rs | 4 +- .../src/pdu/iface_manipulation.rs | 2 +- crates/ironrdp-rdpeusb/src/pdu/mod.rs | 26 ++-- crates/ironrdp-rdpeusb/src/pdu/notify.rs | 6 +- crates/ironrdp-rdpeusb/src/pdu/sink.rs | 22 +-- crates/ironrdp-rdpeusb/src/pdu/usb_dev/mod.rs | 20 +-- .../src/pdu/usb_dev/ts_urb/mod.rs | 66 +++++---- .../src/pdu/usb_dev/ts_urb/utils.rs | 18 ++- crates/ironrdp-rdpsnd/src/pdu/mod.rs | 20 +-- crates/ironrdp-server/src/encoder/bitmap.rs | 6 +- crates/ironrdp-server/src/lib.rs | 3 +- crates/ironrdp-session/src/fast_path.rs | 2 +- crates/ironrdp-str/src/fixed.rs | 6 +- crates/ironrdp-str/src/multi_sz.rs | 14 +- crates/ironrdp-str/src/prefixed.rs | 20 +-- crates/ironrdp-str/src/unframed.rs | 4 +- crates/ironrdp-testsuite-core/tests/pcb.rs | 39 ++--- .../ironrdp-testsuite-core/tests/pdu/mcs.rs | 1 + .../ironrdp-testsuite-core/tests/pdu/x224.rs | 3 + .../tests/session/connection_activation.rs | 1 - .../tests/str_types/multi_sz.rs | 2 + .../tests/str_types/prefixed.rs | 4 + .../tests/str_types/unframed.rs | 1 + crates/ironrdp-web/src/printer.rs | 6 +- 118 files changed, 923 insertions(+), 924 deletions(-) diff --git a/crates/ironrdp-ainput/src/lib.rs b/crates/ironrdp-ainput/src/lib.rs index 6c4ef9c0b..ec294e36d 100644 --- a/crates/ironrdp-ainput/src/lib.rs +++ b/crates/ironrdp-ainput/src/lib.rs @@ -159,8 +159,8 @@ impl<'de> Decode<'de> for ServerPdu { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let pdu_type = - ServerPduType::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type"))?; + let pdu_type = ServerPduType::from_u16(src.read_u16()) + .ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type", at: 0))?; let server_pdu = match pdu_type { ServerPduType::Version => ServerPdu::Version(VersionPdu::decode(src)?), @@ -256,8 +256,8 @@ impl<'de> Decode<'de> for ClientPdu { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let pdu_type = - ClientPduType::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type"))?; + let pdu_type = ClientPduType::from_u16(src.read_u16()) + .ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type", at: 0))?; let client_pdu = match pdu_type { ClientPduType::Mouse => ClientPdu::Mouse(MousePdu::decode(src)?), diff --git a/crates/ironrdp-cfg/src/lib.rs b/crates/ironrdp-cfg/src/lib.rs index b96b571d9..a041e7a7e 100644 --- a/crates/ironrdp-cfg/src/lib.rs +++ b/crates/ironrdp-cfg/src/lib.rs @@ -1,7 +1,6 @@ mod target_addr; -pub use target_addr::{ParseTargetAddrError, TargetAddr, TargetHost}; - use ironrdp_propertyset::PropertySet; +pub use target_addr::{ParseTargetAddrError, TargetAddr, TargetHost}; /// Error returned when the `server port` property value is outside the valid port range (1–65535). #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/ironrdp-cliprdr-format/src/bitmap.rs b/crates/ironrdp-cliprdr-format/src/bitmap.rs index 8d3d50080..28a88d0fd 100644 --- a/crates/ironrdp-cliprdr-format/src/bitmap.rs +++ b/crates/ironrdp-cliprdr-format/src/bitmap.rs @@ -243,19 +243,19 @@ impl BitmapInfoHeader { let width = src.read_i32(); check_invariant(width != i32::MIN && width.abs() <= 10_000) - .ok_or_else(|| invalid_field_err!("biWidth", "width is too big"))?; + .ok_or_else(|| invalid_field_err!("biWidth", "width is too big", at: 0))?; let height = src.read_i32(); check_invariant(height != i32::MIN && height.abs() <= 10_000) - .ok_or_else(|| invalid_field_err!("biHeight", "height is too big"))?; + .ok_or_else(|| invalid_field_err!("biHeight", "height is too big", at: 0))?; let planes = src.read_u16(); if planes != 1 { - return Err(invalid_field_err!("biPlanes", "invalid planes count")); + return Err(invalid_field_err!("biPlanes", "invalid planes count", at: 0)); } let bit_count = src.read_u16(); - check_invariant(bit_count <= 32).ok_or_else(|| invalid_field_err!("biBitCount", "invalid bit count"))?; + check_invariant(bit_count <= 32).ok_or_else(|| invalid_field_err!("biBitCount", "invalid bit count", at: 0))?; let compression = BitmapCompression(src.read_u32()); let size_image = src.read_u32(); @@ -320,7 +320,7 @@ impl<'a> Decode<'a> for BitmapInfoHeader { let size: usize = cast_int!("biSize", size)?; if size != Self::FIXED_PART_SIZE { - return Err(invalid_field_err!("biSize", "invalid V1 bitmap info header size")); + return Err(invalid_field_err!("biSize", "invalid V1 bitmap info header size", at: 0)); } Ok(header) @@ -406,7 +406,7 @@ impl<'a> Decode<'a> for BitmapV5Header { let size: usize = cast_int!("biSize", size)?; if size != Self::FIXED_PART_SIZE { - return Err(invalid_field_err!("biSize", "invalid V5 bitmap info header size")); + return Err(invalid_field_err!("biSize", "invalid V5 bitmap info header size", at: 0)); } let red_mask = src.read_u32(); diff --git a/crates/ironrdp-cliprdr/src/pdu/capabilities.rs b/crates/ironrdp-cliprdr/src/pdu/capabilities.rs index bab0f52f7..32449dcb5 100644 --- a/crates/ironrdp-cliprdr/src/pdu/capabilities.rs +++ b/crates/ironrdp-cliprdr/src/pdu/capabilities.rs @@ -170,10 +170,8 @@ impl<'de> Decode<'de> for CapabilitySet { let general = GeneralCapabilitySet::decode(src)?; Ok(Self::General(general)) } - _ => Err(invalid_field_err!( - "capabilitySetType", - "invalid clipboard capability set type" - )), + _ => Err(invalid_field_err!( "capabilitySetType", + "invalid clipboard capability set type", at: 0)), } } } diff --git a/crates/ironrdp-cliprdr/src/pdu/client_temporary_directory.rs b/crates/ironrdp-cliprdr/src/pdu/client_temporary_directory.rs index b3168d685..42fcd503e 100644 --- a/crates/ironrdp-cliprdr/src/pdu/client_temporary_directory.rs +++ b/crates/ironrdp-cliprdr/src/pdu/client_temporary_directory.rs @@ -52,7 +52,7 @@ impl ClientTemporaryDirectory<'_> { let mut cursor = ReadCursor::new(&self.path_buffer); read_string_from_cursor(&mut cursor, CharacterSet::Unicode, true) - .map_err(|_| invalid_field_err!("wszTempDir", "failed to decode temp dir path")) + .map_err(|_| invalid_field_err!("wszTempDir", "failed to decode temp dir path", at: 0)) } } diff --git a/crates/ironrdp-cliprdr/src/pdu/file_contents.rs b/crates/ironrdp-cliprdr/src/pdu/file_contents.rs index ebad901ec..247f04c9f 100644 --- a/crates/ironrdp-cliprdr/src/pdu/file_contents.rs +++ b/crates/ironrdp-cliprdr/src/pdu/file_contents.rs @@ -129,18 +129,15 @@ impl<'a> FileContentsResponse<'a> { /// Should not panic - the try_into conversion is guaranteed to succeed after length validation. pub fn data_as_size(&self) -> DecodeResult { if self.data.len() != 8 { - return Err(invalid_field_err!( - "requestedFileContentsData", - "SIZE response must be exactly 8 bytes per MS-RDPECLIP 2.2.5.4" - )); + return Err(invalid_field_err!( "requestedFileContentsData", + "SIZE response must be exactly 8 bytes per MS-RDPECLIP 2.2.5.4", at: 0)); } // Per length check above, this conversion is infallible. - let chunk: [u8; 8] = self - .data - .as_ref() - .try_into() - .map_err(|_| invalid_field_err!("requestedFileContentsData", "SIZE response data is not 8 bytes"))?; + let chunk: [u8; 8] = + self.data.as_ref().try_into().map_err( + |_| invalid_field_err!("requestedFileContentsData", "SIZE response data is not 8 bytes", at: 0), + )?; Ok(u64::from_le_bytes(chunk)) } } @@ -182,7 +179,7 @@ impl<'de> Decode<'de> for FileContentsResponse<'de> { ensure_size!(in: src, size: header.data_length()); if header.data_length() < Self::FIXED_PART_SIZE { - return Err(invalid_field_err!("requestedFileContentsData", "invalid data size")); + return Err(invalid_field_err!("requestedFileContentsData", "invalid data size", at: 0)); }; let data_size = header.data_length() - Self::FIXED_PART_SIZE; @@ -287,28 +284,22 @@ impl<'de> Decode<'de> for FileContentsRequest { // [MS-RDPECLIP] 2.2.5.3 - Validate lindex is non-negative if index < 0 { - return Err(invalid_field_err!( - "lindex", - "file index must be non-negative per MS-RDPECLIP 2.2.5.3" - )); + return Err(invalid_field_err!( "lindex", + "file index must be non-negative per MS-RDPECLIP 2.2.5.3", at: 0)); } // [MS-RDPECLIP] 2.2.5.3 - Validate flags are spec-compliant - flags.validate().map_err(|e| invalid_field_err!("dwFlags", e))?; + flags.validate().map_err(|e| invalid_field_err!("dwFlags", e, at: 0))?; // [MS-RDPECLIP] 2.2.5.3 - Validate SIZE request constraints if flags.contains(FileContentsFlags::SIZE) { if requested_size != 8 { - return Err(invalid_field_err!( - "cbRequested", - "SIZE request must have cbRequested=8 per MS-RDPECLIP 2.2.5.3" - )); + return Err(invalid_field_err!( "cbRequested", + "SIZE request must have cbRequested=8 per MS-RDPECLIP 2.2.5.3", at: 0)); } if position != 0 { - return Err(invalid_field_err!( - "position", - "SIZE request must have position=0 per MS-RDPECLIP 2.2.5.3" - )); + return Err(invalid_field_err!( "position", + "SIZE request must have position=0 per MS-RDPECLIP 2.2.5.3", at: 0)); } } diff --git a/crates/ironrdp-cliprdr/src/pdu/format_data/file_list.rs b/crates/ironrdp-cliprdr/src/pdu/format_data/file_list.rs index 132ce6e2e..de393bdec 100644 --- a/crates/ironrdp-cliprdr/src/pdu/format_data/file_list.rs +++ b/crates/ironrdp-cliprdr/src/pdu/format_data/file_list.rs @@ -191,10 +191,8 @@ impl Encode for FileDescriptor { // UTF-16 encoding: each code unit is 2 bytes, plus 2 bytes for null terminator. let encoded_len = wire_name.encode_utf16().count() * 2 + 2; if NAME_LENGTH < encoded_len { - return Err(ironrdp_core::invalid_field_err!( - "cFileName", - "encoded wire name exceeds NAME_LENGTH (520 bytes)" - )); + return Err(ironrdp_core::invalid_field_err!( "cFileName", + "encoded wire name exceeds NAME_LENGTH (520 bytes)", at: 0)); } let written = encode_string(dst.remaining_mut(), &wire_name, CharacterSet::Unicode, true)?; @@ -304,10 +302,8 @@ impl<'de> Decode<'de> for PackedFileList { let file_count: usize = cast_length!(Self::NAME, "cItems", src.read_u32())?; if MAX_FILE_COUNT < file_count { - return Err(ironrdp_core::invalid_field_err!( - "cItems", - "file count exceeds maximum of 100000" - )); + return Err(ironrdp_core::invalid_field_err!( "cItems", + "file count exceeds maximum of 100000", at: 0)); } // Cap pre-allocation against remaining bytes to prevent OOM from diff --git a/crates/ironrdp-cliprdr/src/pdu/format_list.rs b/crates/ironrdp-cliprdr/src/pdu/format_list.rs index 02fd46293..3520d0f11 100644 --- a/crates/ironrdp-cliprdr/src/pdu/format_list.rs +++ b/crates/ironrdp-cliprdr/src/pdu/format_list.rs @@ -457,7 +457,7 @@ impl<'de> Decode<'de> for FormatListResponse { match header.message_flags { ClipboardPduFlags::RESPONSE_OK => Ok(FormatListResponse::Ok), ClipboardPduFlags::RESPONSE_FAIL => Ok(FormatListResponse::Fail), - _ => Err(invalid_field_err!("msgFlags", "invalid format list message flags")), + _ => Err(invalid_field_err!("msgFlags", "invalid format list message flags", at: 0)), } } } diff --git a/crates/ironrdp-cliprdr/src/pdu/mod.rs b/crates/ironrdp-cliprdr/src/pdu/mod.rs index a45bd942e..95581a9ea 100644 --- a/crates/ironrdp-cliprdr/src/pdu/mod.rs +++ b/crates/ironrdp-cliprdr/src/pdu/mod.rs @@ -243,7 +243,7 @@ impl<'de> Decode<'de> for ClipboardPdu<'de> { MSG_TYPE_FILE_CONTENTS_RESPONSE => ClipboardPdu::FileContentsResponse(FileContentsResponse::decode(src)?), MSG_TYPE_LOCK_CLIPDATA => ClipboardPdu::LockData(LockDataId::decode(src)?), MSG_TYPE_UNLOCK_CLIPDATA => ClipboardPdu::UnlockData(LockDataId::decode(src)?), - _ => return Err(invalid_field_err!("msgType", "unknown clipboard PDU type")), + _ => return Err(invalid_field_err!("msgType", "unknown clipboard PDU type", at: 0)), }; Ok(pdu) diff --git a/crates/ironrdp-core/src/decode.rs b/crates/ironrdp-core/src/decode.rs index 910c95ff0..17d23f8ac 100644 --- a/crates/ironrdp-core/src/decode.rs +++ b/crates/ironrdp-core/src/decode.rs @@ -14,7 +14,16 @@ pub type DecodeResult = Result; /// An error type specifically for encoding operations, wrapping an [`DecodeErrorKind`]. pub type DecodeError = ironrdp_error::Error; -/// Enum representing different kinds of decode errors. +/// Structured decode errors carry the fields needed to describe the failure, +/// including a byte `offset` when the error can be associated with +/// a position in the input stream. +/// +/// The `offset` is the cursor position at, or nearest to, where the error was +/// detected. Producers without a stream cursor (a `try_from` on a primitive, +/// a constructor, a validator) pass `0`. +/// +/// [`DecodeErrorKind::Other`] is reserved for errors that do not fit one of the +/// structured variants and therefore does not carry an offset. #[non_exhaustive] #[derive(Clone, Debug)] pub enum DecodeErrorKind { @@ -24,6 +33,11 @@ pub enum DecodeErrorKind { received: usize, /// Number of bytes expected. expected: usize, + /// Byte offset in the input stream where the shortage was detected. + /// + /// `0` indicates that the producer had no stream cursor in scope + /// (a `try_from` on a primitive, a constructor, a validator). + offset: usize, }, /// Error when a field is invalid. InvalidField { @@ -31,16 +45,28 @@ pub enum DecodeErrorKind { field: &'static str, /// Reason for invalidity. reason: &'static str, + /// Byte offset in the input stream where the invalid field was decoded. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Error when an unexpected message type is encountered. UnexpectedMessageType { /// The unexpected message type received. got: u8, + /// Byte offset in the input stream where the unexpected type was read. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Error when an unsupported version is encountered. UnsupportedVersion { /// The unsupported version received. got: u8, + /// Byte offset in the input stream where the unsupported version was read. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Error when an unsupported value is encountered (with allocation feature). #[cfg(feature = "alloc")] @@ -49,14 +75,26 @@ pub enum DecodeErrorKind { name: &'static str, /// The unsupported value. value: String, + /// Byte offset in the input stream where the unsupported value was read. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Error when an unsupported value is encountered (without allocation feature). #[cfg(not(feature = "alloc"))] UnsupportedValue { /// Name of the unsupported value. name: &'static str, + /// Byte offset in the input stream where the unsupported value was read. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Generic error for other cases. + /// + /// Does not carry an offset: producers of this variant typically do not + /// have stream-cursor access, and the variant exists precisely for those + /// cases. Other { /// Description of the error. description: &'static str, @@ -69,26 +107,30 @@ impl core::error::Error for DecodeErrorKind {} impl fmt::Display for DecodeErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::NotEnoughBytes { received, expected } => write!( + Self::NotEnoughBytes { + received, + expected, + offset, + } => write!( f, - "not enough bytes provided to decode: received {received} bytes, expected {expected} bytes" + "not enough bytes provided to decode at offset {offset}: received {received} bytes, expected {expected} bytes" ), - Self::InvalidField { field, reason } => { - write!(f, "invalid `{field}`: {reason}") + Self::InvalidField { field, reason, offset } => { + write!(f, "invalid `{field}` at offset {offset}: {reason}") } - Self::UnexpectedMessageType { got } => { - write!(f, "invalid message type ({got})") + Self::UnexpectedMessageType { got, offset } => { + write!(f, "invalid message type ({got}) at offset {offset}") } - Self::UnsupportedVersion { got } => { - write!(f, "unsupported version ({got})") + Self::UnsupportedVersion { got, offset } => { + write!(f, "unsupported version ({got}) at offset {offset}") } #[cfg(feature = "alloc")] - Self::UnsupportedValue { name, value } => { - write!(f, "unsupported {name} ({value})") + Self::UnsupportedValue { name, value, offset } => { + write!(f, "unsupported {name} ({value}) at offset {offset}") } #[cfg(not(feature = "alloc"))] - Self::UnsupportedValue { name } => { - write!(f, "unsupported {name}") + Self::UnsupportedValue { name, offset } => { + write!(f, "unsupported {name} at offset {offset}") } Self::Other { description } => { write!(f, "other ({description})") @@ -98,37 +140,44 @@ impl fmt::Display for DecodeErrorKind { } impl NotEnoughBytesErr for DecodeError { - fn not_enough_bytes(context: &'static str, received: usize, expected: usize) -> Self { - Self::new(context, DecodeErrorKind::NotEnoughBytes { received, expected }) + fn not_enough_bytes(context: &'static str, received: usize, expected: usize, offset: usize) -> Self { + Self::new( + context, + DecodeErrorKind::NotEnoughBytes { + received, + expected, + offset, + }, + ) } } impl InvalidFieldErr for DecodeError { - fn invalid_field(context: &'static str, field: &'static str, reason: &'static str) -> Self { - Self::new(context, DecodeErrorKind::InvalidField { field, reason }) + fn invalid_field(context: &'static str, field: &'static str, reason: &'static str, offset: usize) -> Self { + Self::new(context, DecodeErrorKind::InvalidField { field, reason, offset }) } } impl UnexpectedMessageTypeErr for DecodeError { - fn unexpected_message_type(context: &'static str, got: u8) -> Self { - Self::new(context, DecodeErrorKind::UnexpectedMessageType { got }) + fn unexpected_message_type(context: &'static str, got: u8, offset: usize) -> Self { + Self::new(context, DecodeErrorKind::UnexpectedMessageType { got, offset }) } } impl UnsupportedVersionErr for DecodeError { - fn unsupported_version(context: &'static str, got: u8) -> Self { - Self::new(context, DecodeErrorKind::UnsupportedVersion { got }) + fn unsupported_version(context: &'static str, got: u8, offset: usize) -> Self { + Self::new(context, DecodeErrorKind::UnsupportedVersion { got, offset }) } } impl UnsupportedValueErr for DecodeError { #[cfg(feature = "alloc")] - fn unsupported_value(context: &'static str, name: &'static str, value: String) -> Self { - Self::new(context, DecodeErrorKind::UnsupportedValue { name, value }) + fn unsupported_value(context: &'static str, name: &'static str, value: String, offset: usize) -> Self { + Self::new(context, DecodeErrorKind::UnsupportedValue { name, value, offset }) } #[cfg(not(feature = "alloc"))] - fn unsupported_value(context: &'static str, name: &'static str) -> Self { - Self::new(context, DecodeErrorKind::UnsupportedValue { name }) + fn unsupported_value(context: &'static str, name: &'static str, offset: usize) -> Self { + Self::new(context, DecodeErrorKind::UnsupportedValue { name, offset }) } } diff --git a/crates/ironrdp-core/src/encode.rs b/crates/ironrdp-core/src/encode.rs index 75e4e256e..dd0de74b4 100644 --- a/crates/ironrdp-core/src/encode.rs +++ b/crates/ironrdp-core/src/encode.rs @@ -18,7 +18,15 @@ pub type EncodeResult = Result; /// An error type specifically for encoding operations, wrapping an [`EncodeErrorKind`]. pub type EncodeError = ironrdp_error::Error; -/// Represents the different kinds of errors that can occur during encoding operations. +/// Structured encode errors carry the fields needed to describe the failure, +/// including a byte `offset` when the error can be associated with +/// a position in the output stream. +/// +/// The `offset` is the cursor position at, or nearest to, where the error was +/// detected. Producers without a stream cursor pass `0`. +/// +/// [`EncodeErrorKind::Other`] is reserved for errors that do not fit one of the +/// structured variants and therefore does not carry an offset. #[non_exhaustive] #[derive(Clone, Debug)] pub enum EncodeErrorKind { @@ -28,6 +36,11 @@ pub enum EncodeErrorKind { received: usize, /// The number of bytes expected or required. expected: usize, + /// Byte offset in the output stream where the shortage was detected. + /// + /// `0` indicates that the producer had no stream cursor in scope + /// (a `try_from` on a primitive, a constructor, a validator). + offset: usize, }, /// Indicates that a field in the data being encoded is invalid. InvalidField { @@ -35,16 +48,28 @@ pub enum EncodeErrorKind { field: &'static str, /// The reason why the field is considered invalid. reason: &'static str, + /// Byte offset in the output stream where the invalid field was being written. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Indicates that an unexpected message type was encountered during encoding. UnexpectedMessageType { /// The unexpected message type that was received. got: u8, + /// Byte offset in the output stream where the unexpected type was written. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Indicates that an unsupported version was encountered during encoding. UnsupportedVersion { /// The unsupported version that was received. got: u8, + /// Byte offset in the output stream where the unsupported version was written. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Indicates that an unsupported value was encountered during encoding. #[cfg(feature = "alloc")] @@ -53,14 +78,25 @@ pub enum EncodeErrorKind { name: &'static str, /// The unsupported value that was received. value: String, + /// Byte offset in the output stream where the unsupported value was written. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Indicates that an unsupported value was encountered during encoding (no-alloc version). #[cfg(not(feature = "alloc"))] UnsupportedValue { /// The name of the field or parameter with the unsupported value. name: &'static str, + /// Byte offset in the output stream where the unsupported value was written. + /// + /// `0` indicates that the producer had no stream cursor in scope. + offset: usize, }, /// Represents any other error that doesn't fit into the above categories. + /// + /// Does not carry an offset: producers of this variant typically do not + /// have stream-cursor access. Other { /// A description of the error. description: &'static str, @@ -73,26 +109,30 @@ impl core::error::Error for EncodeErrorKind {} impl fmt::Display for EncodeErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::NotEnoughBytes { received, expected } => write!( + Self::NotEnoughBytes { + received, + expected, + offset, + } => write!( f, - "not enough bytes provided to decode: received {received} bytes, expected {expected} bytes" + "not enough bytes provided to encode at offset {offset}: received {received} bytes, expected {expected} bytes" ), - Self::InvalidField { field, reason } => { - write!(f, "invalid `{field}`: {reason}") + Self::InvalidField { field, reason, offset } => { + write!(f, "invalid `{field}` at offset {offset}: {reason}") } - Self::UnexpectedMessageType { got } => { - write!(f, "invalid message type ({got})") + Self::UnexpectedMessageType { got, offset } => { + write!(f, "invalid message type ({got}) at offset {offset}") } - Self::UnsupportedVersion { got } => { - write!(f, "unsupported version ({got})") + Self::UnsupportedVersion { got, offset } => { + write!(f, "unsupported version ({got}) at offset {offset}") } #[cfg(feature = "alloc")] - Self::UnsupportedValue { name, value } => { - write!(f, "unsupported {name} ({value})") + Self::UnsupportedValue { name, value, offset } => { + write!(f, "unsupported {name} ({value}) at offset {offset}") } #[cfg(not(feature = "alloc"))] - Self::UnsupportedValue { name } => { - write!(f, "unsupported {name}") + Self::UnsupportedValue { name, offset } => { + write!(f, "unsupported {name} at offset {offset}") } Self::Other { description } => { write!(f, "other ({description})") @@ -102,37 +142,44 @@ impl fmt::Display for EncodeErrorKind { } impl NotEnoughBytesErr for EncodeError { - fn not_enough_bytes(context: &'static str, received: usize, expected: usize) -> Self { - Self::new(context, EncodeErrorKind::NotEnoughBytes { received, expected }) + fn not_enough_bytes(context: &'static str, received: usize, expected: usize, offset: usize) -> Self { + Self::new( + context, + EncodeErrorKind::NotEnoughBytes { + received, + expected, + offset, + }, + ) } } impl InvalidFieldErr for EncodeError { - fn invalid_field(context: &'static str, field: &'static str, reason: &'static str) -> Self { - Self::new(context, EncodeErrorKind::InvalidField { field, reason }) + fn invalid_field(context: &'static str, field: &'static str, reason: &'static str, offset: usize) -> Self { + Self::new(context, EncodeErrorKind::InvalidField { field, reason, offset }) } } impl UnexpectedMessageTypeErr for EncodeError { - fn unexpected_message_type(context: &'static str, got: u8) -> Self { - Self::new(context, EncodeErrorKind::UnexpectedMessageType { got }) + fn unexpected_message_type(context: &'static str, got: u8, offset: usize) -> Self { + Self::new(context, EncodeErrorKind::UnexpectedMessageType { got, offset }) } } impl UnsupportedVersionErr for EncodeError { - fn unsupported_version(context: &'static str, got: u8) -> Self { - Self::new(context, EncodeErrorKind::UnsupportedVersion { got }) + fn unsupported_version(context: &'static str, got: u8, offset: usize) -> Self { + Self::new(context, EncodeErrorKind::UnsupportedVersion { got, offset }) } } impl UnsupportedValueErr for EncodeError { #[cfg(feature = "alloc")] - fn unsupported_value(context: &'static str, name: &'static str, value: String) -> Self { - Self::new(context, EncodeErrorKind::UnsupportedValue { name, value }) + fn unsupported_value(context: &'static str, name: &'static str, value: String, offset: usize) -> Self { + Self::new(context, EncodeErrorKind::UnsupportedValue { name, value, offset }) } #[cfg(not(feature = "alloc"))] - fn unsupported_value(context: &'static str, name: &'static str) -> Self { - Self::new(context, EncodeErrorKind::UnsupportedValue { name }) + fn unsupported_value(context: &'static str, name: &'static str, offset: usize) -> Self { + Self::new(context, EncodeErrorKind::UnsupportedValue { name, offset }) } } diff --git a/crates/ironrdp-core/src/error.rs b/crates/ironrdp-core/src/error.rs index 954ad77c4..1d1b04eb4 100644 --- a/crates/ironrdp-core/src/error.rs +++ b/crates/ironrdp-core/src/error.rs @@ -33,28 +33,25 @@ pub trait NotEnoughBytesErr { /// * `context` - The context in which the error occurred. /// * `received` - The number of bytes received. /// * `expected` - The number of bytes expected. + /// * `offset` - Byte offset in the input stream where the shortage was detected. + /// Callers without stream-cursor access pass `0`. /// /// # Returns /// /// A new error instance. - fn not_enough_bytes(context: &'static str, received: usize, expected: usize) -> Self; + fn not_enough_bytes(context: &'static str, received: usize, expected: usize, offset: usize) -> Self; } /// Helper function to create a "not enough bytes" error. /// /// This function is a convenience wrapper around the `NotEnoughBytesErr` trait. -/// -/// # Arguments -/// -/// * `context` - The context in which the error occurred. -/// * `received` - The number of bytes received. -/// * `expected` - The number of bytes expected. -/// -/// # Returns -/// -/// A new error instance of type `T` that implements `NotEnoughBytesErr`. -pub fn not_enough_bytes_err(context: &'static str, received: usize, expected: usize) -> T { - T::not_enough_bytes(context, received, expected) +pub fn not_enough_bytes_err( + context: &'static str, + received: usize, + expected: usize, + offset: usize, +) -> T { + T::not_enough_bytes(context, received, expected, offset) } /// Trait for creating "invalid field" errors. @@ -66,39 +63,34 @@ pub trait InvalidFieldErr { /// * `context` - The context in which the error occurred. /// * `field` - The name of the invalid field. /// * `reason` - The reason why the field is invalid. + /// * `offset` - Byte offset in the input stream where the field was decoded. + /// Callers without stream-cursor access pass `0`. /// /// # Returns /// /// A new error instance. - fn invalid_field(context: &'static str, field: &'static str, reason: &'static str) -> Self; + fn invalid_field(context: &'static str, field: &'static str, reason: &'static str, offset: usize) -> Self; } /// Helper function to create an "invalid field" error with a source. -/// -/// This function is a convenience wrapper around the `InvalidFieldErr` and `WithSource` traits. -/// -/// # Arguments -/// -/// * `context` - The context in which the error occurred. -/// * `field` - The name of the invalid field. -/// * `reason` - The reason why the field is invalid. -/// * `source` - The source error to add. -/// -/// # Returns -/// -/// A new error instance of type `T` that implements both `InvalidFieldErr` and `WithSource`. pub fn invalid_field_err_with_source( context: &'static str, field: &'static str, reason: &'static str, + offset: usize, source: E, ) -> T { - T::invalid_field(context, field, reason).with_source(source) + T::invalid_field(context, field, reason, offset).with_source(source) } /// Helper function to create an "invalid field" error. -pub fn invalid_field_err(context: &'static str, field: &'static str, reason: &'static str) -> T { - T::invalid_field(context, field, reason) +pub fn invalid_field_err( + context: &'static str, + field: &'static str, + reason: &'static str, + offset: usize, +) -> T { + T::invalid_field(context, field, reason, offset) } /// Trait for creating "unexpected message type" errors. @@ -109,27 +101,14 @@ pub trait UnexpectedMessageTypeErr { /// /// * `context` - The context in which the error occurred. /// * `got` - The unexpected message type received. - /// - /// # Returns - /// - /// A new error instance. - fn unexpected_message_type(context: &'static str, got: u8) -> Self; + /// * `offset` - Byte offset in the input stream where the type was read. + /// Callers without stream-cursor access pass `0`. + fn unexpected_message_type(context: &'static str, got: u8, offset: usize) -> Self; } /// Helper function to create an "unexpected message type" error. -/// -/// This function is a convenience wrapper around the `UnexpectedMessageTypeErr` trait. -/// -/// # Arguments -/// -/// * `context` - The context in which the error occurred. -/// * `got` - The unexpected message type received. -/// -/// # Returns -/// -/// A new error instance of type `T` that implements `UnexpectedMessageTypeErr`. -pub fn unexpected_message_type_err(context: &'static str, got: u8) -> T { - T::unexpected_message_type(context, got) +pub fn unexpected_message_type_err(context: &'static str, got: u8, offset: usize) -> T { + T::unexpected_message_type(context, got, offset) } /// Trait for creating "unsupported version" errors. @@ -140,27 +119,14 @@ pub trait UnsupportedVersionErr { /// /// * `context` - The context in which the error occurred. /// * `got` - The unsupported version received. - /// - /// # Returns - /// - /// A new error instance. - fn unsupported_version(context: &'static str, got: u8) -> Self; + /// * `offset` - Byte offset in the input stream where the version was read. + /// Callers without stream-cursor access pass `0`. + fn unsupported_version(context: &'static str, got: u8, offset: usize) -> Self; } /// Helper function to create an "unsupported version" error. -/// -/// This function is a convenience wrapper around the `UnsupportedVersionErr` trait. -/// -/// # Arguments -/// -/// * `context` - The context in which the error occurred. -/// * `got` - The unsupported version received. -/// -/// # Returns -/// -/// A new error instance of type `T` that implements `UnsupportedVersionErr`. -pub fn unsupported_version_err(context: &'static str, got: u8) -> T { - T::unsupported_version(context, got) +pub fn unsupported_version_err(context: &'static str, got: u8, offset: usize) -> T { + T::unsupported_version(context, got, offset) } /// Trait for creating "unsupported value" errors. @@ -172,12 +138,10 @@ pub trait UnsupportedValueErr { /// * `context` - The context in which the error occurred. /// * `name` - The name of the unsupported value. /// * `value` - The unsupported value. - /// - /// # Returns - /// - /// A new error instance. + /// * `offset` - Byte offset in the input stream where the value was read. + /// Callers without stream-cursor access pass `0`. #[cfg(feature = "alloc")] - fn unsupported_value(context: &'static str, name: &'static str, value: String) -> Self; + fn unsupported_value(context: &'static str, name: &'static str, value: String, offset: usize) -> Self; /// Creates a new "unsupported value" error when the "alloc" feature is disabled. /// @@ -185,36 +149,27 @@ pub trait UnsupportedValueErr { /// /// * `context` - The context in which the error occurred. /// * `name` - The name of the unsupported value. - /// - /// # Returns - /// - /// A new error instance. + /// * `offset` - Byte offset in the input stream where the value was read. + /// Callers without stream-cursor access pass `0`. #[cfg(not(feature = "alloc"))] - fn unsupported_value(context: &'static str, name: &'static str) -> Self; + fn unsupported_value(context: &'static str, name: &'static str, offset: usize) -> Self; } /// Helper function to create an "unsupported value" error when the "alloc" feature is enabled. -/// -/// This function is a convenience wrapper around the `UnsupportedValueErr` trait. -/// -/// # Arguments -/// -/// * `context` - The context in which the error occurred. -/// * `name` - The name of the unsupported value. -/// * `value` - The unsupported value. -/// -/// # Returns -/// -/// A new error instance of type `T` that implements `UnsupportedValueErr`.] #[cfg(feature = "alloc")] -pub fn unsupported_value_err(context: &'static str, name: &'static str, value: String) -> T { - T::unsupported_value(context, name, value) +pub fn unsupported_value_err( + context: &'static str, + name: &'static str, + value: String, + offset: usize, +) -> T { + T::unsupported_value(context, name, value, offset) } /// Helper function to create an "unsupported value" error. #[cfg(not(feature = "alloc"))] -pub fn unsupported_value_err(context: &'static str, name: &'static str) -> T { - T::unsupported_value(context, name) +pub fn unsupported_value_err(context: &'static str, name: &'static str, offset: usize) -> T { + T::unsupported_value(context, name, offset) } /// Trait for creating generic "other" errors. diff --git a/crates/ironrdp-core/src/macros.rs b/crates/ironrdp-core/src/macros.rs index c6d610402..81e4a47a1 100644 --- a/crates/ironrdp-core/src/macros.rs +++ b/crates/ironrdp-core/src/macros.rs @@ -60,8 +60,20 @@ macro_rules! function { /// If the context is not provided, it will use the current function name. #[macro_export] macro_rules! not_enough_bytes_err { - ( $context:expr, $received:expr , $expected:expr $(,)? ) => {{ $crate::not_enough_bytes_err($context, $received, $expected) }}; - ( $received:expr , $expected:expr $(,)? ) => {{ $crate::not_enough_bytes_err!($crate::function!(), $received, $expected) }}; + // offset extracted from cursor.pos() + ( $context:expr, $received:expr, $expected:expr, in: $cursor:expr $(,)? ) => {{ + $crate::not_enough_bytes_err($context, $received, $expected, $cursor.pos()) + }}; + ( $received:expr, $expected:expr, in: $cursor:expr $(,)? ) => {{ + $crate::not_enough_bytes_err!($crate::function!(), $received, $expected, in: $cursor) + }}; + // explicit offset (use 0 when the producer has no stream-cursor access) + ( $context:expr, $received:expr, $expected:expr, at: $offset:expr $(,)? ) => {{ + $crate::not_enough_bytes_err($context, $received, $expected, $offset) + }}; + ( $received:expr, $expected:expr, at: $offset:expr $(,)? ) => {{ + $crate::not_enough_bytes_err!($crate::function!(), $received, $expected, at: $offset) + }}; } /// Creates an "invalid field" error with context information. @@ -88,8 +100,18 @@ macro_rules! not_enough_bytes_err { /// If the context is not provided, it will use the current function name. #[macro_export] macro_rules! invalid_field_err { - ( $context:expr, $field:expr , $reason:expr $(,)? ) => {{ $crate::invalid_field_err($context, $field, $reason) }}; - ( $field:expr , $reason:expr $(,)? ) => {{ $crate::invalid_field_err!($crate::function!(), $field, $reason) }}; + ( $context:expr, $field:expr, $reason:expr, in: $cursor:expr $(,)? ) => {{ + $crate::invalid_field_err($context, $field, $reason, $cursor.pos()) + }}; + ( $field:expr, $reason:expr, in: $cursor:expr $(,)? ) => {{ + $crate::invalid_field_err!($crate::function!(), $field, $reason, in: $cursor) + }}; + ( $context:expr, $field:expr, $reason:expr, at: $offset:expr $(,)? ) => {{ + $crate::invalid_field_err($context, $field, $reason, $offset) + }}; + ( $field:expr, $reason:expr, at: $offset:expr $(,)? ) => {{ + $crate::invalid_field_err!($crate::function!(), $field, $reason, at: $offset) + }}; } /// Creates an "unexpected message type" error with context information. @@ -115,8 +137,18 @@ macro_rules! invalid_field_err { /// If the context is not provided, it will use the current function name. #[macro_export] macro_rules! unexpected_message_type_err { - ( $context:expr, $got:expr $(,)? ) => {{ $crate::unexpected_message_type_err($context, $got) }}; - ( $got:expr $(,)? ) => {{ $crate::unexpected_message_type_err!($crate::function!(), $got) }}; + ( $context:expr, $got:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unexpected_message_type_err($context, $got, $cursor.pos()) + }}; + ( $got:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unexpected_message_type_err!($crate::function!(), $got, in: $cursor) + }}; + ( $context:expr, $got:expr, at: $offset:expr $(,)? ) => {{ + $crate::unexpected_message_type_err($context, $got, $offset) + }}; + ( $got:expr, at: $offset:expr $(,)? ) => {{ + $crate::unexpected_message_type_err!($crate::function!(), $got, at: $offset) + }}; } /// Creates an "unsupported version" error with context information. @@ -142,8 +174,18 @@ macro_rules! unexpected_message_type_err { /// If the context is not provided, it will use the current function name. #[macro_export] macro_rules! unsupported_version_err { - ( $context:expr, $got:expr $(,)? ) => {{ $crate::unsupported_version_err($context, $got) }}; - ( $got:expr $(,)? ) => {{ $crate::unsupported_version_err!($crate::function!(), $got) }}; + ( $context:expr, $got:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unsupported_version_err($context, $got, $cursor.pos()) + }}; + ( $got:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unsupported_version_err!($crate::function!(), $got, in: $cursor) + }}; + ( $context:expr, $got:expr, at: $offset:expr $(,)? ) => {{ + $crate::unsupported_version_err($context, $got, $offset) + }}; + ( $got:expr, at: $offset:expr $(,)? ) => {{ + $crate::unsupported_version_err!($crate::function!(), $got, at: $offset) + }}; } /// Creates an "unsupported value" error with context information. @@ -170,8 +212,18 @@ macro_rules! unsupported_version_err { /// If the context is not provided, it will use the current function name. #[macro_export] macro_rules! unsupported_value_err { - ( $context:expr, $name:expr, $value:expr $(,)? ) => {{ $crate::unsupported_value_err($context, $name, $value) }}; - ( $name:expr, $value:expr $(,)? ) => {{ $crate::unsupported_value_err!($crate::function!(), $name, $value) }}; + ( $context:expr, $name:expr, $value:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unsupported_value_err($context, $name, $value, $cursor.pos()) + }}; + ( $name:expr, $value:expr, in: $cursor:expr $(,)? ) => {{ + $crate::unsupported_value_err!($crate::function!(), $name, $value, in: $cursor) + }}; + ( $context:expr, $name:expr, $value:expr, at: $offset:expr $(,)? ) => {{ + $crate::unsupported_value_err($context, $name, $value, $offset) + }}; + ( $name:expr, $value:expr, at: $offset:expr $(,)? ) => {{ + $crate::unsupported_value_err!($crate::function!(), $name, $value, at: $offset) + }}; } /// Creates a generic "other" error with optional context and source information. @@ -256,7 +308,12 @@ macro_rules! ensure_size { let received = $buf.len(); let expected = $expected; if !(received >= expected) { - return Err($crate::not_enough_bytes_err($ctx, received, expected)); + // ensure_size!'s $buf binding is either a ReadCursor, a WriteCursor, + // or a plain `&[u8]` / `&mut [u8]`. The first two expose `.pos()`, + // the latter do not. We pass offset 0 from this macro; callers that + // want a real offset use `not_enough_bytes_err!(..., in: cursor)` + // directly. + return Err($crate::not_enough_bytes_err($ctx, received, expected, 0)); } }}; (in: $buf:ident, size: $expected:expr) => {{ @@ -328,7 +385,7 @@ macro_rules! ensure_fixed_part_size { macro_rules! cast_length { ($ctx:expr, $field:expr, $len:expr) => {{ $len.try_into() - .map_err(|e| $crate::invalid_field_err_with_source($ctx, $field, "too many elements", e)) + .map_err(|e| $crate::invalid_field_err_with_source($ctx, $field, "too many elements", 0, e)) }}; ($field:expr, $len:expr) => {{ $crate::cast_length!($crate::function!(), $field, $len) }}; } @@ -362,7 +419,7 @@ macro_rules! cast_length { macro_rules! cast_int { ($ctx:expr, $field:expr, $len:expr) => {{ $len.try_into().map_err(|e| { - $crate::invalid_field_err_with_source($ctx, $field, "out of range integral type conversion", e) + $crate::invalid_field_err_with_source($ctx, $field, "out of range integral type conversion", 0, e) }) }}; ($field:expr, $len:expr) => {{ $crate::cast_int!($crate::function!(), $field, $len) }}; diff --git a/crates/ironrdp-displaycontrol/src/pdu/mod.rs b/crates/ironrdp-displaycontrol/src/pdu/mod.rs index 41efbc5a6..64d23ae1c 100644 --- a/crates/ironrdp-displaycontrol/src/pdu/mod.rs +++ b/crates/ironrdp-displaycontrol/src/pdu/mod.rs @@ -89,7 +89,7 @@ impl<'de> Decode<'de> for DisplayControlPdu { let _payload_length = pdu_length .checked_sub(Self::FIXED_PART_SIZE.try_into().expect("always in range")) - .ok_or_else(|| invalid_field_err!("Length", "Display control PDU length is too small"))?; + .ok_or_else(|| invalid_field_err!("Length", "Display control PDU length is too small", at: 0))?; match kind { DISPLAYCONTROL_PDU_TYPE_CAPS => { @@ -100,7 +100,7 @@ impl<'de> Decode<'de> for DisplayControlPdu { let layout = DisplayControlMonitorLayout::decode(src)?; Ok(DisplayControlPdu::MonitorLayout(layout)) } - _ => Err(invalid_field_err!("Type", "Unknown display control PDU type")), + _ => Err(invalid_field_err!("Type", "Unknown display control PDU type", at: 0)), } } } @@ -220,16 +220,14 @@ impl DisplayControlMonitorLayout { pub fn new(monitors: &[MonitorLayoutEntry]) -> EncodeResult { if monitors.len() > MAX_SUPPORTED_MONITORS.into() { - return Err(invalid_field_err!("NumMonitors", "Too many monitors",)); + return Err(invalid_field_err!("NumMonitors", "Too many monitors", at: 0)); } let primary_monitors_count = monitors.iter().filter(|monitor| monitor.is_primary()).count(); if primary_monitors_count != 1 { - return Err(invalid_field_err!( - "PrimaryMonitor", - "There must be exactly one primary monitor" - )); + return Err(invalid_field_err!( "PrimaryMonitor", + "There must be exactly one primary monitor", at: 0)); } Ok(Self { @@ -293,7 +291,7 @@ impl Encode for DisplayControlMonitorLayout { .monitors .len() .try_into() - .map_err(|_| invalid_field_err!("NumMonitors", "Number of monitors is too big"))?; + .map_err(|_| invalid_field_err!("NumMonitors", "Number of monitors is too big", at: 0))?; dst.write_u32(monitors_count); @@ -325,16 +323,14 @@ impl<'de> Decode<'de> for DisplayControlMonitorLayout { let monitor_layout_size = src.read_u32(); if monitor_layout_size != MonitorLayoutEntry::FIXED_PART_SIZE.try_into().expect("always in range") { - return Err(invalid_field_err!( - "MonitorLayoutSize", - "Monitor layout size is invalid" - )); + return Err(invalid_field_err!( "MonitorLayoutSize", + "Monitor layout size is invalid", at: 0)); } let num_monitors = cast_length!("number of monitors", src.read_u32())?; if num_monitors > MAX_SUPPORTED_MONITORS.into() { - return Err(invalid_field_err!("NumMonitors", "Too many monitors")); + return Err(invalid_field_err!("NumMonitors", "Too many monitors", at: 0)); } let mut monitors = Vec::with_capacity(num_monitors); @@ -367,13 +363,13 @@ pub struct MonitorLayoutEntry { macro_rules! validate_dimensions { ($width:expr, $height:expr) => {{ if !(200..=8192).contains(&$width) { - return Err(invalid_field_err!("Width", "Monitor width is out of range")); + return Err(invalid_field_err!("Width", "Monitor width is out of range", at: 0)); } if $width % 2 != 0 { - return Err(invalid_field_err!("Width", "Monitor width cannot be odd")); + return Err(invalid_field_err!("Width", "Monitor width cannot be odd", at: 0)); } if !(200..=8192).contains(&$height) { - return Err(invalid_field_err!("Height", "Monitor height is out of range")); + return Err(invalid_field_err!("Height", "Monitor height is out of range", at: 0)); } Ok(()) }}; @@ -701,10 +697,8 @@ impl DeviceScaleFactor { fn validate_position(left: i32, top: i32, is_primary: bool) -> EncodeResult<()> { if is_primary && (left != 0 || top != 0) { - return Err(invalid_field_err!( - "Position", - "Primary monitor position must be (0, 0)" - )); + return Err(invalid_field_err!( "Position", + "Primary monitor position must be (0, 0)", at: 0)); } Ok(()) @@ -712,10 +706,8 @@ fn validate_position(left: i32, top: i32, is_primary: bool) -> EncodeResult<()> fn validate_desktop_scale_factor(desktop_scale_factor: u32) -> EncodeResult<()> { if !(100..=500).contains(&desktop_scale_factor) { - return Err(invalid_field_err!( - "DesktopScaleFactor", - "Desktop scale factor is out of range" - )); + return Err(invalid_field_err!( "DesktopScaleFactor", + "Desktop scale factor is out of range", at: 0)); } Ok(()) @@ -723,10 +715,10 @@ fn validate_desktop_scale_factor(desktop_scale_factor: u32) -> EncodeResult<()> fn validate_physical_dimensions(physical_width: u32, physical_height: u32) -> EncodeResult<()> { if !(10..=10000).contains(&physical_width) { - return Err(invalid_field_err!("PhysicalWidth", "Physical width is out of range")); + return Err(invalid_field_err!("PhysicalWidth", "Physical width is out of range", at: 0)); } if !(10..=10000).contains(&physical_height) { - return Err(invalid_field_err!("PhysicalHeight", "Physical height is out of range")); + return Err(invalid_field_err!("PhysicalHeight", "Physical height is out of range", at: 0)); } Ok(()) @@ -738,16 +730,14 @@ fn calculate_monitor_area( max_monitor_area_factor_b: u32, ) -> DecodeResult { if max_num_monitors > MAX_SUPPORTED_MONITORS.into() { - return Err(invalid_field_err!("NumMonitors", "Too many monitors")); + return Err(invalid_field_err!("NumMonitors", "Too many monitors", at: 0)); } if max_monitor_area_factor_a > MAX_MONITOR_AREA_FACTOR.into() || max_monitor_area_factor_b > MAX_MONITOR_AREA_FACTOR.into() { - return Err(invalid_field_err!( - "MaxMonitorAreaFactor", - "Invalid monitor area factor" - )); + return Err(invalid_field_err!( "MaxMonitorAreaFactor", + "Invalid monitor area factor", at: 0)); } // As per invariants: This multiplication would never overflow. diff --git a/crates/ironrdp-dvc/src/client.rs b/crates/ironrdp-dvc/src/client.rs index c38330720..54a5d292a 100644 --- a/crates/ironrdp-dvc/src/client.rs +++ b/crates/ironrdp-dvc/src/client.rs @@ -4,7 +4,6 @@ use alloc::vec::Vec; use core::any::TypeId; use core::fmt; -use crate::alloc::borrow::ToOwned as _; use ironrdp_core::{Decode as _, DecodeResult, ReadCursor, impl_as_any}; use ironrdp_pdu::{self as pdu, decode_err, encode_err, pdu_other_err}; use ironrdp_svc::{ChannelFlags, CompressionCondition, SvcClientProcessor, SvcMessage, SvcProcessor}; @@ -12,6 +11,7 @@ use pdu::PduResult; use pdu::gcc::ChannelName; use tracing::debug; +use crate::alloc::borrow::ToOwned as _; use crate::pdu::{ CapabilitiesResponsePdu, CapsVersion, ClosePdu, CreateResponsePdu, CreationStatus, DrdynvcClientPdu, DrdynvcServerPdu, diff --git a/crates/ironrdp-dvc/src/complete_data.rs b/crates/ironrdp-dvc/src/complete_data.rs index 9c0cc8d37..cd5a6509c 100644 --- a/crates/ironrdp-dvc/src/complete_data.rs +++ b/crates/ironrdp-dvc/src/complete_data.rs @@ -75,7 +75,7 @@ impl CompleteData { } } } - _ => Err(invalid_field_err!("DVC message", "data", "overflow occurred")), + _ => Err(invalid_field_err!("DVC message", "data", "overflow occurred", at: 0)), } } } diff --git a/crates/ironrdp-dvc/src/lib.rs b/crates/ironrdp-dvc/src/lib.rs index 6126653b0..d09b82c81 100644 --- a/crates/ironrdp-dvc/src/lib.rs +++ b/crates/ironrdp-dvc/src/lib.rs @@ -4,11 +4,10 @@ extern crate alloc; -use core::any::TypeId; - use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; +use core::any::TypeId; use pdu::DrdynvcDataPdu; diff --git a/crates/ironrdp-dvc/src/pdu.rs b/crates/ironrdp-dvc/src/pdu.rs index 3a277be60..4c2e2e833 100644 --- a/crates/ironrdp-dvc/src/pdu.rs +++ b/crates/ironrdp-dvc/src/pdu.rs @@ -103,7 +103,7 @@ impl Decode<'_> for DrdynvcClientPdu { Cmd::Data => Ok(Self::Data(DrdynvcDataPdu::Data(DataPdu::decode(header, src)?))), Cmd::Close => Ok(Self::Close(ClosePdu::decode(header, src)?)), Cmd::Capability => Ok(Self::Capabilities(CapabilitiesResponsePdu::decode(header, src)?)), - _ => Err(unsupported_value_err!("Cmd", header.cmd.into())), + _ => Err(unsupported_value_err!("Cmd", header.cmd.into(), at: 0)), } } } @@ -157,7 +157,7 @@ impl Decode<'_> for DrdynvcServerPdu { Cmd::Data => Ok(Self::Data(DrdynvcDataPdu::Data(DataPdu::decode(header, src)?))), Cmd::Close => Ok(Self::Close(ClosePdu::decode(header, src)?)), Cmd::Capability => Ok(Self::Capabilities(CapabilitiesRequestPdu::decode(header, src)?)), - _ => Err(unsupported_value_err!("Cmd", header.cmd.into())), + _ => Err(unsupported_value_err!("Cmd", header.cmd.into(), at: 0)), } } } @@ -259,7 +259,7 @@ impl TryFrom for Cmd { 0x07 => Ok(Self::DataCompressed), 0x08 => Ok(Self::SoftSyncRequest), 0x09 => Ok(Self::SoftSyncResponse), - _ => Err(invalid_field_err!("Cmd", "invalid cmd")), + _ => Err(invalid_field_err!("Cmd", "invalid cmd", at: 0)), } } } @@ -397,7 +397,7 @@ impl FieldType { FieldType::U8 => dst.write_u8(cast_length!("FieldType::encode", value)?), FieldType::U16 => dst.write_u16(cast_length!("FieldType::encode", value)?), FieldType::U32 => dst.write_u32(value), - _ => return Err(invalid_field_err!("FieldType", "invalid field type")), + _ => return Err(invalid_field_err!("FieldType", "invalid field type", at: 0)), }; Ok(()) } @@ -408,7 +408,7 @@ impl FieldType { FieldType::U8 => Ok(u32::from(src.read_u8())), FieldType::U16 => Ok(u32::from(src.read_u16())), FieldType::U32 => Ok(src.read_u32()), - _ => Err(invalid_field_err!("FieldType", "invalid field type")), + _ => Err(invalid_field_err!("FieldType", "invalid field type", at: 0)), } } @@ -729,7 +729,7 @@ impl TryFrom for CapsVersion { 0x0001 => Ok(Self::V1), 0x0002 => Ok(Self::V2), 0x0003 => Ok(Self::V3), - _ => Err(invalid_field_err!("CapsVersion", "invalid version")), + _ => Err(invalid_field_err!("CapsVersion", "invalid version", at: 0)), } } } diff --git a/crates/ironrdp-dvc/src/server.rs b/crates/ironrdp-dvc/src/server.rs index 21e905e68..284e43c6c 100644 --- a/crates/ironrdp-dvc/src/server.rs +++ b/crates/ironrdp-dvc/src/server.rs @@ -183,7 +183,7 @@ impl DrdynvcServer { fn channel_by_id(&mut self, id: u32) -> DecodeResult<&mut DynamicChannel> { self.dynamic_channels .get_mut(id) - .ok_or_else(|| invalid_field_err!("DRDYNVC", "", "invalid channel id")) + .ok_or_else(|| invalid_field_err!("DRDYNVC", "", "invalid channel id", at: 0)) } /// Creates a new DVC, returns CreateRequest PDU to send to client. diff --git a/crates/ironrdp-egfx/src/pdu/avc.rs b/crates/ironrdp-egfx/src/pdu/avc.rs index d5039bfa4..fe962c894 100644 --- a/crates/ironrdp-egfx/src/pdu/avc.rs +++ b/crates/ironrdp-egfx/src/pdu/avc.rs @@ -234,13 +234,13 @@ impl<'de> Decode<'de> for Avc444BitmapStream<'de> { let encoding_raw: u8 = stream_info.get_bits(30..32).try_into().unwrap(); // Only 0x00 (LUMA_AND_CHROMA), 0x01 (LUMA), 0x02 (CHROMA) are defined. if encoding_raw > 2 { - return Err(invalid_field_err!("encoding", "reserved encoding value")); + return Err(invalid_field_err!("encoding", "reserved encoding value", at: 0)); } let encoding = Encoding::from_bits_retain(encoding_raw); if stream_len == 0 { if encoding == Encoding::LUMA_AND_CHROMA { - return Err(invalid_field_err!("encoding", "invalid encoding")); + return Err(invalid_field_err!("encoding", "invalid encoding", at: 0)); } let stream1 = Avc420BitmapStream::decode(src)?; diff --git a/crates/ironrdp-egfx/src/pdu/cmd.rs b/crates/ironrdp-egfx/src/pdu/cmd.rs index c61c09e66..d95bacc90 100644 --- a/crates/ironrdp-egfx/src/pdu/cmd.rs +++ b/crates/ironrdp-egfx/src/pdu/cmd.rs @@ -206,7 +206,7 @@ impl<'de> Decode<'de> for GfxPdu { #[expect(clippy::unwrap_used, reason = "FIXED_PART_SIZE is a small constant")] let _payload_length = pdu_length .checked_sub(Self::FIXED_PART_SIZE.try_into().unwrap()) - .ok_or_else(|| invalid_field_err!("Length", "GFX PDU length is too small"))?; + .ok_or_else(|| invalid_field_err!("Length", "GFX PDU length is too small", at: 0))?; match cmdid { RDPGFX_CMDID_WIRETOSURFACE_1 => { @@ -301,7 +301,7 @@ impl<'de> Decode<'de> for GfxPdu { let pdu = MapSurfaceToScaledWindowPdu::decode(src)?; Ok(GfxPdu::MapSurfaceToScaledWindow(pdu)) } - _ => Err(invalid_field_err!("Type", "Unknown GFX PDU type")), + _ => Err(invalid_field_err!("Type", "Unknown GFX PDU type", at: 0)), } } } @@ -1209,20 +1209,18 @@ impl<'a> Decode<'a> for ResetGraphicsPdu { let width = src.read_u32(); if width > MAX_RESET_GRAPHICS_WIDTH_HEIGHT { - return Err(invalid_field_err!("width", "invalid reset graphics width")); + return Err(invalid_field_err!("width", "invalid reset graphics width", at: 0)); } let height = src.read_u32(); if height > MAX_RESET_GRAPHICS_WIDTH_HEIGHT { - return Err(invalid_field_err!("height", "invalid reset graphics height")); + return Err(invalid_field_err!("height", "invalid reset graphics height", at: 0)); } let monitor_count = src.read_u32(); if monitor_count > MONITOR_COUNT_MAX { - return Err(invalid_field_err!( - "monitor_count", - "invalid reset graphics monitor count" - )); + return Err(invalid_field_err!( "monitor_count", + "invalid reset graphics monitor count", at: 0)); } #[expect(clippy::as_conversions, reason = "monitor_count validated above")] @@ -2207,7 +2205,7 @@ impl TryFrom for Codec1Type { 0xc => Ok(Codec1Type::Alpha), 0xe => Ok(Codec1Type::Avc444), 0xf => Ok(Codec1Type::Avc444v2), - _ => Err(invalid_field_err!("Codec1Type", "invalid codec type")), + _ => Err(invalid_field_err!("Codec1Type", "invalid codec type", at: 0)), } } } @@ -2232,7 +2230,7 @@ impl TryFrom for Codec2Type { fn try_from(value: u16) -> Result { match value { 0x9 => Ok(Codec2Type::RemoteFxProgressive), - _ => Err(invalid_field_err!("Codec2Type", "invalid codec type")), + _ => Err(invalid_field_err!("Codec2Type", "invalid codec type", at: 0)), } } } diff --git a/crates/ironrdp-egfx/src/pdu/common.rs b/crates/ironrdp-egfx/src/pdu/common.rs index ef4c47555..c8493099a 100644 --- a/crates/ironrdp-egfx/src/pdu/common.rs +++ b/crates/ironrdp-egfx/src/pdu/common.rs @@ -119,7 +119,7 @@ impl TryFrom for PixelFormat { match value { 0x20 => Ok(PixelFormat::XRgb), 0x21 => Ok(PixelFormat::ARgb), - _ => Err(invalid_field_err!("PixelFormat", "invalid pixel format")), + _ => Err(invalid_field_err!("PixelFormat", "invalid pixel format", at: 0)), } } } diff --git a/crates/ironrdp-graphics/src/clearcodec/mod.rs b/crates/ironrdp-graphics/src/clearcodec/mod.rs index ab6e653c5..b85c7ee92 100644 --- a/crates/ironrdp-graphics/src/clearcodec/mod.rs +++ b/crates/ironrdp-graphics/src/clearcodec/mod.rs @@ -56,7 +56,7 @@ impl ClearCodecDecoder { // Validate glyph index range per spec: 0..3999 inclusive if let Some(idx) = stream.glyph_index { if idx >= GLYPH_CACHE_WRAP { - return Err(invalid_field_err!("glyphIndex", "glyph index out of range 0-3999")); + return Err(invalid_field_err!("glyphIndex", "glyph index out of range 0-3999", in: src)); } } @@ -64,19 +64,19 @@ impl ClearCodecDecoder { let h = usize::from(height); let pixel_count = w .checked_mul(h) - .ok_or_else(|| invalid_field_err!("dimensions", "width * height overflow"))?; + .ok_or_else(|| invalid_field_err!("dimensions", "width * height overflow", in: src))?; // Handle glyph hit: return cached pixel data if stream.is_glyph_hit() { let glyph_index = stream .glyph_index - .ok_or_else(|| invalid_field_err!("flags", "GLYPH_HIT without GLYPH_INDEX"))?; + .ok_or_else(|| invalid_field_err!("flags", "GLYPH_HIT without GLYPH_INDEX", in: src))?; let entry = self .glyph_cache .get(glyph_index) - .ok_or_else(|| invalid_field_err!("glyphIndex", "glyph cache miss on hit"))?; + .ok_or_else(|| invalid_field_err!("glyphIndex", "glyph cache miss on hit", in: src))?; if entry.width != width || entry.height != height { - return Err(invalid_field_err!("glyphIndex", "cached glyph dimensions mismatch")); + return Err(invalid_field_err!("glyphIndex", "cached glyph dimensions mismatch", in: src)); } return Ok(entry.pixels.clone()); } @@ -96,7 +96,7 @@ impl ClearCodecDecoder { return Err(invalid_field_err!( "dimensions", "width or height exceeds 8192-pixel decoder limit" - )); + , in: src)); } // Decode composite payload @@ -212,14 +212,14 @@ impl ClearCodecDecoder { let cached = self .vbar_cache .get_vbar(*index) - .ok_or_else(|| invalid_field_err!("vbarIndex", "V-bar cache miss on hit"))?; + .ok_or_else(|| invalid_field_err!("vbarIndex", "V-bar cache miss on hit", at: 0))?; Ok(cached.clone()) } VBar::ShortCacheHit { index, y_on } => { let cached_short = self .vbar_cache .get_short_vbar(*index) - .ok_or_else(|| invalid_field_err!("shortVbarIndex", "short V-bar cache miss on hit"))?; + .ok_or_else(|| invalid_field_err!("shortVbarIndex", "short V-bar cache miss on hit", at: 0))?; // Create a modified short vbar with the y_on from this reference let modified = ShortVBar { y_on: *y_on, @@ -261,7 +261,7 @@ impl ClearCodecDecoder { let x_end = usize::from(sub.x_start) + usize::from(sub.width); let y_end = usize::from(sub.y_start) + usize::from(sub.height); if x_end > sw || y_end > sh { - return Err(invalid_field_err!("subcodec", "region exceeds surface bounds")); + return Err(invalid_field_err!("subcodec", "region exceeds surface bounds", at: 0)); } match sub.codec_id { @@ -271,9 +271,9 @@ impl ClearCodecDecoder { let expected = w .checked_mul(h) .and_then(|v| v.checked_mul(3)) - .ok_or_else(|| invalid_field_err!("bitmapData", "raw subcodec dimensions overflow"))?; + .ok_or_else(|| invalid_field_err!("bitmapData", "raw subcodec dimensions overflow", at: 0))?; if sub.bitmap_data.len() < expected { - return Err(invalid_field_err!("bitmapData", "raw subcodec data too short")); + return Err(invalid_field_err!("bitmapData", "raw subcodec data too short", at: 0)); } for row in 0..h { for col in 0..w { @@ -297,16 +297,16 @@ impl ClearCodecDecoder { for seg in &rlex.segments { if usize::from(seg.start_index) >= palette_len { - return Err(invalid_field_err!("rlex", "start_index exceeds palette size")); + return Err(invalid_field_err!("rlex", "start_index exceeds palette size", at: 0)); } if usize::from(seg.stop_index) >= palette_len { - return Err(invalid_field_err!("rlex", "stop_index exceeds palette size")); + return Err(invalid_field_err!("rlex", "stop_index exceeds palette size", at: 0)); } let color = &rlex.palette[usize::from(seg.start_index)]; for _ in 0..seg.run_length { if px >= region_pixels { - return Err(invalid_field_err!("rlex", "run exceeds region pixel count")); + return Err(invalid_field_err!("rlex", "run exceeds region pixel count", at: 0)); } let x = usize::from(sub.x_start) + px % w; let y = usize::from(sub.y_start) + px / w; @@ -320,7 +320,7 @@ impl ClearCodecDecoder { for palette_idx in seg.start_index..=seg.stop_index { if px >= region_pixels { - return Err(invalid_field_err!("rlex", "suite exceeds region pixel count")); + return Err(invalid_field_err!("rlex", "suite exceeds region pixel count", at: 0)); } let color = &rlex.palette[usize::from(palette_idx)]; let x = usize::from(sub.x_start) + px % w; diff --git a/crates/ironrdp-graphics/src/rdp6/bitmap_stream/encoder.rs b/crates/ironrdp-graphics/src/rdp6/bitmap_stream/encoder.rs index 3887d14d5..660d93441 100644 --- a/crates/ironrdp-graphics/src/rdp6/bitmap_stream/encoder.rs +++ b/crates/ironrdp-graphics/src/rdp6/bitmap_stream/encoder.rs @@ -188,6 +188,7 @@ impl BitmapStreamEncoder { "BitmapStreamData", remaining, needed, + 0, ))); } @@ -263,6 +264,7 @@ impl BitmapStreamEncoder { "BitmapStreamData", remaining, needed, + 0, ))); } diff --git a/crates/ironrdp-mstsgu/src/proto.rs b/crates/ironrdp-mstsgu/src/proto.rs index 983ae291a..561b9df28 100644 --- a/crates/ironrdp-mstsgu/src/proto.rs +++ b/crates/ironrdp-mstsgu/src/proto.rs @@ -109,7 +109,7 @@ impl<'a> Decode<'a> for PktHdr { ensure_fixed_part_size!(in: src); let ty = src.read_u16(); - let mty = PktTy::try_from(ty).map_err(|_| unsupported_value_err("PktHdr::ty", "ty", format!("0x{ty:x}")))?; + let mty = PktTy::try_from(ty).map_err(|_| unsupported_value_err("PktHdr::ty", "ty", format!("0x{ty:x}"), 0))?; Ok(PktHdr { ty: mty, @@ -182,7 +182,7 @@ impl Decode<'_> for HandshakeRespPkt { _extended_auth: { let raw = src.read_u16(); HttpExtendedAuth::from_bits(raw) - .ok_or_else(|| unsupported_value_err("HandshakeResp", "extended_auth", format!("0x{raw:x}")))? + .ok_or_else(|| unsupported_value_err("HandshakeResp", "extended_auth", format!("0x{raw:x}"), 0))? }, }) } diff --git a/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs b/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs index d3ec08acb..ee2cb1e55 100644 --- a/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs @@ -70,7 +70,7 @@ impl<'de> Decode<'de> for BitmapUpdateData<'de> { let update_type = BitmapFlags::from_bits_retain(src.read_u16()); if !update_type.contains(BitmapFlags::BITMAP_UPDATE_TYPE) { - return Err(invalid_field_err!("updateType", "invalid update type")); + return Err(invalid_field_err!("updateType", "invalid update type", at: 0)); } let rectangle_count = usize::from(src.read_u16()); @@ -157,10 +157,8 @@ impl<'de> Decode<'de> for BitmapData<'de> { { // Check if encoded_bitmap_data_length is at least CompressedDataHeader::ENCODED_SIZE if encoded_bitmap_data_length < CompressedDataHeader::ENCODED_SIZE { - return Err(invalid_field_err!( - "cbCompEncodedBitmapDataLength", - "length is less than CompressedDataHeader::ENCODED_SIZE" - )); + return Err(invalid_field_err!( "cbCompEncodedBitmapDataLength", + "length is less than CompressedDataHeader::ENCODED_SIZE", at: 0)); } let buffer_length = encoded_bitmap_data_length - CompressedDataHeader::ENCODED_SIZE; @@ -219,17 +217,15 @@ impl<'de> Decode<'de> for CompressedDataHeader { let size = src.read_u16(); if size != FIRST_ROW_SIZE_VALUE { - return Err(invalid_field_err!("cbCompFirstRowSize", "invalid first row size")); + return Err(invalid_field_err!("cbCompFirstRowSize", "invalid first row size", at: 0)); } let main_body_size = src.read_u16(); let scan_width = src.read_u16(); if !scan_width.is_multiple_of(4) { - return Err(invalid_field_err!( - "cbScanWidth", - "The width of the bitmap must be divisible by 4" - )); + return Err(invalid_field_err!( "cbScanWidth", + "The width of the bitmap must be divisible by 4", at: 0)); } let uncompressed_size = src.read_u16(); @@ -246,10 +242,8 @@ impl Encode for CompressedDataHeader { ensure_fixed_part_size!(in: dst); if !self.scan_width.is_multiple_of(4) { - return Err(invalid_field_err!( - "cbScanWidth", - "The width of the bitmap must be divisible by 4" - )); + return Err(invalid_field_err!( "cbScanWidth", + "The width of the bitmap must be divisible by 4", at: 0)); } dst.write_u16(FIRST_ROW_SIZE_VALUE); dst.write_u16(self.main_body_size); diff --git a/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs b/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs index 9a41324b1..851a9276d 100644 --- a/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs +++ b/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs @@ -127,10 +127,8 @@ impl<'a> Decode<'a> for BitmapStream<'a> { let color_planes_size = if !header.enable_rle_compression { // Cut padding field if RLE flags is set to 0 if src.is_empty() { - return Err(invalid_field_err!( - "padding", - "missing padding byte from zero-sized non-RLE bitmap data", - )); + return Err(invalid_field_err!( "padding", + "missing padding byte from zero-sized non-RLE bitmap data", at: 0)); } src.len() - NON_RLE_PADDING_SIZE } else { @@ -297,6 +295,7 @@ mod tests { kind: NotEnoughBytes { received: 0, expected: 1, + offset: 0, }, source: None, } @@ -312,6 +311,7 @@ mod tests { kind: InvalidField { field: "padding", reason: "missing padding byte from zero-sized non-RLE bitmap data", + offset: 0, }, source: None, } diff --git a/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs b/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs index 34189405f..70a414894 100644 --- a/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs @@ -94,14 +94,12 @@ impl<'de> Decode<'de> for FastPathHeader { let flags = EncryptionFlags::from_bits_retain(header.get_bits(6..8)); let (length, sizeof_length) = per::read_length(src).map_err(|e| { - DecodeError::invalid_field("", "length", "Invalid encoded fast path PDU length").with_source(e) + DecodeError::invalid_field("", "length", "Invalid encoded fast path PDU length", 0).with_source(e) })?; let length = usize::from(length); if length < sizeof_length + Self::FIXED_PART_SIZE { - return Err(invalid_field_err!( - "length", - "received fastpath PDU length is smaller than header size" - )); + return Err(invalid_field_err!( "length", + "received fastpath PDU length is smaller than header size", at: 0)); } let data_length = length - sizeof_length - Self::FIXED_PART_SIZE; // Detect case, when received packet has non-optimal packet length packing. @@ -176,11 +174,11 @@ impl<'de> Decode<'de> for FastPathUpdatePdu<'de> { let update_code = header.get_bits(0..4); let update_code = UpdateCode::from_u8(update_code) - .ok_or_else(|| invalid_field_err!("updateHeader", "Invalid update code"))?; + .ok_or_else(|| invalid_field_err!("updateHeader", "Invalid update code", at: 0))?; let fragmentation = header.get_bits(4..6); let fragmentation = Fragmentation::from_u8(fragmentation) - .ok_or_else(|| invalid_field_err!("updateHeader", "Invalid fragmentation"))?; + .ok_or_else(|| invalid_field_err!("updateHeader", "Invalid fragmentation", at: 0))?; let compression = Compression::from_bits_retain(header.get_bits(6..8)); @@ -193,7 +191,7 @@ impl<'de> Decode<'de> for FastPathUpdatePdu<'de> { CompressionFlags::from_bits_retain(compression_flags_with_type & !SHARE_DATA_HEADER_COMPRESSION_MASK); let compression_type = CompressionType::from_u8(compression_flags_with_type & SHARE_DATA_HEADER_COMPRESSION_MASK) - .ok_or_else(|| invalid_field_err!("compressionFlags", "invalid compression type"))?; + .ok_or_else(|| invalid_field_err!("compressionFlags", "invalid compression type", at: 0))?; (Some(compression_flags), Some(compression_type)) } else { @@ -264,7 +262,7 @@ impl<'a> FastPathUpdate<'a> { UpdateCode::CachedPointer => Ok(Self::Pointer(PointerUpdateData::Cached(decode_cursor(src)?))), UpdateCode::NewPointer => Ok(Self::Pointer(PointerUpdateData::New(decode_cursor(src)?))), UpdateCode::LargePointer => Ok(Self::Pointer(PointerUpdateData::Large(decode_cursor(src)?))), - _ => Err(invalid_field_err!("updateCode", "unsupported fast-path update code")), + _ => Err(invalid_field_err!("updateCode", "unsupported fast-path update code", at: 0)), } } diff --git a/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs b/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs index eeb0eb96e..23a78e832 100644 --- a/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs @@ -77,22 +77,20 @@ macro_rules! check_masks_alignment { let check_mask = |mask: &[u8], field: &'static str| { if $pointer_height == 0 { - return Err(invalid_field_err!(field, "pointer height cannot be zero")); + return Err(invalid_field_err!(field, "pointer height cannot be zero", at: 0)); } if $large_ptr && (mask.len() > U32_MAX) { - return Err(invalid_field_err!(field, "pointer mask is too big for u32 size")); + return Err(invalid_field_err!(field, "pointer mask is too big for u32 size", at: 0)); } if !$large_ptr && (mask.len() > usize::from(u16::MAX)) { - return Err(invalid_field_err!(field, "pointer mask is too big for u16 size")); + return Err(invalid_field_err!(field, "pointer mask is too big for u16 size", at: 0)); } if (mask.len() % pointer_height) != 0 { - return Err(invalid_field_err!(field, "pointer mask have incomplete scanlines")); + return Err(invalid_field_err!(field, "pointer mask have incomplete scanlines", at: 0)); } if (mask.len() / pointer_height) % 2 != 0 { - return Err(invalid_field_err!( - field, - "pointer mask scanlines should be aligned to 16 bits" - )); + return Err(invalid_field_err!( field, + "pointer mask scanlines should be aligned to 16 bits", at: 0)); } Ok(()) }; diff --git a/crates/ironrdp-pdu/src/basic_output/slow_path.rs b/crates/ironrdp-pdu/src/basic_output/slow_path.rs index 1caf9238f..0ba66f872 100644 --- a/crates/ironrdp-pdu/src/basic_output/slow_path.rs +++ b/crates/ironrdp-pdu/src/basic_output/slow_path.rs @@ -39,10 +39,8 @@ pub fn read_graphics_update_type(src: &mut ReadCursor<'_>) -> DecodeResult Ok(GraphicsUpdateType::Bitmap), 0x0002 => Ok(GraphicsUpdateType::Palette), 0x0003 => Ok(GraphicsUpdateType::Synchronize), - _ => Err(invalid_field_err!( - "updateType", - "unknown slow-path graphics update type" - )), + _ => Err(invalid_field_err!( "updateType", + "unknown slow-path graphics update type", at: 0)), } } @@ -105,7 +103,7 @@ pub fn decode_slow_path_pointer<'a>(src: &mut ReadCursor<'a>) -> DecodeResult Ok(PointerUpdateData::SetHidden), 0x0000_7F00 => Ok(PointerUpdateData::SetDefault), - _ => Err(invalid_field_err!("systemPointerType", "unknown system pointer type")), + _ => Err(invalid_field_err!("systemPointerType", "unknown system pointer type", at: 0)), } } 0x0003 => { @@ -128,9 +126,7 @@ pub fn decode_slow_path_pointer<'a>(src: &mut ReadCursor<'a>) -> DecodeResult Err(invalid_field_err!( - "messageType", - "unknown slow-path pointer message type" - )), + _ => Err(invalid_field_err!( "messageType", + "unknown slow-path pointer message type", at: 0)), } } diff --git a/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs b/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs index 2c5946370..2624632a8 100644 --- a/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs @@ -61,7 +61,7 @@ impl<'de> Decode<'de> for SurfaceCommand<'de> { let cmd_type = src.read_u16(); let cmd_type = SurfaceCommandType::from_u16(cmd_type) - .ok_or_else(|| invalid_field_err!("cmdType", "invalid surface command"))?; + .ok_or_else(|| invalid_field_err!("cmdType", "invalid surface command", at: 0))?; match cmd_type { SurfaceCommandType::SetSurfaceBits => Ok(Self::SetSurfaceBits(SurfaceBitsPdu::decode(src)?)), @@ -151,7 +151,7 @@ impl<'de> Decode<'de> for FrameMarkerPdu { let frame_action = src.read_u16(); let frame_action = FrameAction::from_u16(frame_action) - .ok_or_else(|| invalid_field_err!("frameAction", "invalid frame action"))?; + .ok_or_else(|| invalid_field_err!("frameAction", "invalid frame action", at: 0))?; let frame_id = if src.is_empty() { // Sometimes Windows 10 RDP server sends not complete FrameMarker PDU (without frame ID), diff --git a/crates/ironrdp-pdu/src/ber.rs b/crates/ironrdp-pdu/src/ber.rs index 1154b03e9..ac58d45ac 100644 --- a/crates/ironrdp-pdu/src/ber.rs +++ b/crates/ironrdp-pdu/src/ber.rs @@ -105,7 +105,7 @@ pub(crate) fn read_sequence_tag(stream: &mut ReadCursor<'_>) -> DecodeResult, tagnum: u8) -> D if tagnum > 0x1E { if identifier != Class::Application.as_u8() | Pc::Construct.as_u8() | TAG_MASK { - return Err(invalid_field_err!("identifier", "invalid application tag identifier")); + return Err(invalid_field_err!("identifier", "invalid application tag identifier", at: 0)); } ensure_size!(in: stream, size: 1); if stream.read_u8() != tagnum { - return Err(invalid_field_err!("tagnum", "invalid application tag identifier")); + return Err(invalid_field_err!("tagnum", "invalid application tag identifier", at: 0)); } } else if identifier != Class::Application.as_u8() | Pc::Construct.as_u8() | (TAG_MASK & tagnum) { - return Err(invalid_field_err!("identifier", "invalid application tag identifier")); + return Err(invalid_field_err!("identifier", "invalid application tag identifier", at: 0)); } read_length(stream) @@ -161,13 +161,13 @@ pub(crate) fn read_enumerated(stream: &mut ReadCursor<'_>, count: u8) -> DecodeR let length = read_length(stream)?; if length != 1 { - return Err(invalid_field_err!("len", "invalid enumerated len")); + return Err(invalid_field_err!("len", "invalid enumerated len", at: 0)); } ensure_size!(in: stream, size: 1); let enumerated = stream.read_u8(); if enumerated == u8::MAX || enumerated + 1 > count { - return Err(invalid_field_err!("enumerated", "invalid enumerated value")); + return Err(invalid_field_err!("enumerated", "invalid enumerated value", at: 0)); } Ok(enumerated) @@ -229,7 +229,7 @@ pub(crate) fn read_integer(stream: &mut ReadCursor<'_>) -> DecodeResult { ensure_size!(in: stream, size: 8); Ok(stream.read_u64_be()) } else { - Err(invalid_field_err!("len", "invalid integer len")) + Err(invalid_field_err!("len", "invalid integer len", at: 0)) } } @@ -250,7 +250,7 @@ pub(crate) fn read_bool(stream: &mut ReadCursor<'_>) -> DecodeResult { let length = read_length(stream)?; if length != 1 { - return Err(invalid_field_err!("len", "invalid integer len")); + return Err(invalid_field_err!("len", "invalid integer len", at: 0)); } ensure_size!(in: stream, size: 1); @@ -298,7 +298,7 @@ fn read_universal_tag(stream: &mut ReadCursor<'_>, tag: Tag, pc: Pc) -> DecodeRe let identifier = stream.read_u8(); if identifier != Class::Universal.as_u8() | pc.as_u8() | (TAG_MASK & tag.as_u8()) { - Err(invalid_field_err!("identifier", "invalid universal tag identifier")) + Err(invalid_field_err!("identifier", "invalid universal tag identifier", at: 0)) } else { Ok(()) } @@ -338,7 +338,7 @@ fn read_length(stream: &mut ReadCursor<'_>) -> DecodeResult { ensure_size!(in: stream, size: 2); Ok(stream.read_u16_be()) } else { - Err(invalid_field_err!("len", "invalid length of the length")) + Err(invalid_field_err!("len", "invalid length of the length", at: 0)) } } else { Ok(u16::from(byte)) diff --git a/crates/ironrdp-pdu/src/codecs/clearcodec/bands.rs b/crates/ironrdp-pdu/src/codecs/clearcodec/bands.rs index 863ba1224..33e1db1fe 100644 --- a/crates/ironrdp-pdu/src/codecs/clearcodec/bands.rs +++ b/crates/ironrdp-pdu/src/codecs/clearcodec/bands.rs @@ -94,14 +94,14 @@ fn decode_single_band<'a>(src: &mut ReadCursor<'a>) -> DecodeResult> { let height = y_end .checked_sub(y_start) .and_then(|h| h.checked_add(1)) - .ok_or_else(|| invalid_field_err!("yEnd", "yEnd < yStart"))?; + .ok_or_else(|| invalid_field_err!("yEnd", "yEnd < yStart", in: src))?; if height > MAX_BAND_HEIGHT { - return Err(invalid_field_err!("bandHeight", "band height exceeds 52")); + return Err(invalid_field_err!("bandHeight", "band height exceeds 52", in: src)); } if x_end < x_start { - return Err(invalid_field_err!("xEnd", "xEnd < xStart")); + return Err(invalid_field_err!("xEnd", "xEnd < xStart", in: src)); } // `x_end - x_start` is at most u16::MAX (when x_end = u16::MAX and @@ -153,13 +153,14 @@ fn decode_vbar<'a>(src: &mut ReadCursor<'a>, band_height: u16) -> DecodeResult band_height { return Err(invalid_field_err!( "shortVBarCacheMiss", - "shortVBarYOff exceeds band height" + "shortVBarYOff exceeds band height", + in: src )); } diff --git a/crates/ironrdp-pdu/src/codecs/clearcodec/mod.rs b/crates/ironrdp-pdu/src/codecs/clearcodec/mod.rs index a94e61a9b..dd84fd977 100644 --- a/crates/ironrdp-pdu/src/codecs/clearcodec/mod.rs +++ b/crates/ironrdp-pdu/src/codecs/clearcodec/mod.rs @@ -123,7 +123,7 @@ impl<'a> CompositePayload<'a> { let total = residual_byte_count .checked_add(bands_byte_count) .and_then(|s| s.checked_add(subcodec_byte_count)) - .ok_or_else(|| invalid_field_err!("byteCount", "layer byte counts overflow"))?; + .ok_or_else(|| invalid_field_err!("byteCount", "layer byte counts overflow", in: src))?; ensure_size!(ctx: Self::NAME, in: src, size: total); diff --git a/crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs b/crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs index c2a5d7701..5d45e0a69 100644 --- a/crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs +++ b/crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs @@ -47,11 +47,11 @@ pub fn decode_rlex(data: &[u8]) -> DecodeResult { let palette_count = src.read_u8(); if palette_count == 0 { - return Err(invalid_field_err!("paletteCount", "palette count is 0")); + return Err(invalid_field_err!("paletteCount", "palette count is 0", in: src)); } if palette_count > MAX_PALETTE_COUNT { - return Err(invalid_field_err!("paletteCount", "palette count exceeds 127")); + return Err(invalid_field_err!("paletteCount", "palette count exceeds 127", in: src)); } let palette_byte_count = usize::from(palette_count) * 3; diff --git a/crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs b/crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs index fcad5eeff..a9bd41635 100644 --- a/crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs +++ b/crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs @@ -24,7 +24,7 @@ impl SubcodecId { 0x00 => Ok(Self::Raw), 0x01 => Ok(Self::NsCodec), 0x02 => Ok(Self::Rlex), - _ => Err(invalid_field_err!("subCodecId", "unknown subcodec ID")), + _ => Err(invalid_field_err!("subCodecId", "unknown subcodec ID", at: 0)), } } } @@ -73,7 +73,7 @@ fn decode_single_subcodec<'a>(src: &mut ReadCursor<'a>) -> DecodeResult Decode<'de> for ContextPdu { let id = src.read_u8(); if id != CONTEXT_ID { - return Err(invalid_field_err!("ctxId", "Invalid context ID")); + return Err(invalid_field_err!("ctxId", "Invalid context ID", at: 0)); } let tile_size = src.read_u16(); if tile_size != TILE_SIZE { - return Err(invalid_field_err!("tileSize", "Invalid tile size")); + return Err(invalid_field_err!("tileSize", "Invalid tile size", at: 0)); } let properties = src.read_u16(); let flags = OperatingMode::from_bits_retain(properties.get_bits(0..3)); let color_conversion_transform = properties.get_bits(3..5); if color_conversion_transform != COLOR_CONVERSION_ICT { - return Err(invalid_field_err!("cct", "Invalid color conversion transform")); + return Err(invalid_field_err!("cct", "Invalid color conversion transform", at: 0)); } let dwt = properties.get_bits(5..9); if dwt != CLW_XFORM_DWT_53_A { - return Err(invalid_field_err!("dwt", "Invalid DWT")); + return Err(invalid_field_err!("dwt", "Invalid DWT", at: 0)); } let entropy_algorithm_bits = properties.get_bits(9..13); let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits) - .ok_or_else(|| invalid_field_err!("entropy_algorithm", "Invalid entropy algorithm"))?; + .ok_or_else(|| invalid_field_err!("entropy_algorithm", "Invalid entropy algorithm", at: 0))?; let quantization_type = properties.get_bits(13..15); if quantization_type != SCALAR_QUANTIZATION { - return Err(invalid_field_err!("qt", "Invalid quantization type")); + return Err(invalid_field_err!("qt", "Invalid quantization type", at: 0)); } let _reserved = properties.get_bit(15); @@ -248,7 +248,7 @@ impl<'de> Decode<'de> for RegionPdu { let region_flags = src.read_u8(); let lrf = region_flags.get_bit(0); if lrf != LRF { - return Err(invalid_field_err!("lrf", "Invalid lrf")); + return Err(invalid_field_err!("lrf", "Invalid lrf", at: 0)); } let number_of_rectangles = usize::from(src.read_u16()); @@ -263,12 +263,12 @@ impl<'de> Decode<'de> for RegionPdu { let region_type = src.read_u16(); if region_type != CBT_REGION { - return Err(invalid_field_err!("regionType", "Invalid region type")); + return Err(invalid_field_err!("regionType", "Invalid region type", at: 0)); } let number_of_tilesets = src.read_u16(); if number_of_tilesets != NUMBER_OF_TILESETS { - return Err(invalid_field_err!("numTilesets", "Invalid number of tilesets")); + return Err(invalid_field_err!("numTilesets", "Invalid number of tilesets", at: 0)); } Ok(Self { rectangles }) @@ -343,18 +343,18 @@ impl<'de> Decode<'de> for TileSetPdu<'de> { let subtype = src.read_u16(); if subtype != CBT_TILESET { - return Err(invalid_field_err!("subtype", "Invalid message type")); + return Err(invalid_field_err!("subtype", "Invalid message type", at: 0)); } let id_of_context = src.read_u16(); if id_of_context != IDX { - return Err(invalid_field_err!("id_of_context", "Invalid RFX context")); + return Err(invalid_field_err!("id_of_context", "Invalid RFX context", at: 0)); } let properties = src.read_u16(); let is_last = properties.get_bit(0); if is_last != IS_LAST_TILESET_FLAG { - return Err(invalid_field_err!("last", "Invalid last flag")); + return Err(invalid_field_err!("last", "Invalid last flag", at: 0)); } // The encoder MUST set `flags` value to the value of flags @@ -364,28 +364,28 @@ impl<'de> Decode<'de> for TileSetPdu<'de> { let color_conversion_transform = properties.get_bits(4..6); if color_conversion_transform != COLOR_CONVERSION_ICT { - return Err(invalid_field_err!("cct", "Invalid color conversion")); + return Err(invalid_field_err!("cct", "Invalid color conversion", at: 0)); } let dwt = properties.get_bits(6..10); if dwt != CLW_XFORM_DWT_53_A { - return Err(invalid_field_err!("xft", "Invalid DWT")); + return Err(invalid_field_err!("xft", "Invalid DWT", at: 0)); } let entropy_algorithm_bits = properties.get_bits(10..14); let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits) - .ok_or_else(|| invalid_field_err!("entropy", "Invalid entropy algorithm"))?; + .ok_or_else(|| invalid_field_err!("entropy", "Invalid entropy algorithm", at: 0))?; let quantization_type = properties.get_bits(14..16); if quantization_type != SCALAR_QUANTIZATION { - return Err(invalid_field_err!("scalar", "Invalid quantization type")); + return Err(invalid_field_err!("scalar", "Invalid quantization type", at: 0)); } let number_of_quants = usize::from(src.read_u8()); let tile_size = u16::from(src.read_u8()); if tile_size != TILE_SIZE { - return Err(invalid_field_err!("tile_size", "Invalid tile size")); + return Err(invalid_field_err!("tile_size", "Invalid tile size", at: 0)); } let number_of_tiles = usize::from(src.read_u16()); @@ -403,7 +403,7 @@ impl<'de> Decode<'de> for TileSetPdu<'de> { .into_iter() .map(|b| match b { Block::Tile(tile) => Ok(tile), - _ => Err(invalid_field_err!("tile", "Invalid block type, expected Tile")), + _ => Err(invalid_field_err!("tile", "Invalid block type, expected Tile", at: 0)), }) .collect::, _>>()?; diff --git a/crates/ironrdp-pdu/src/codecs/rfx/header_messages.rs b/crates/ironrdp-pdu/src/codecs/rfx/header_messages.rs index f27cbbeb5..b172d08f8 100644 --- a/crates/ironrdp-pdu/src/codecs/rfx/header_messages.rs +++ b/crates/ironrdp-pdu/src/codecs/rfx/header_messages.rs @@ -48,11 +48,11 @@ impl<'de> Decode<'de> for SyncPdu { let magic = src.read_u32(); if magic != SYNC_MAGIC { - return Err(invalid_field_err!("magic", "Invalid sync magic")); + return Err(invalid_field_err!("magic", "Invalid sync magic", at: 0)); } let version = src.read_u16(); if version != SYNC_VERSION { - return Err(invalid_field_err!("version", "Invalid sync version")); + return Err(invalid_field_err!("version", "Invalid sync version", at: 0)); } Ok(Self) @@ -97,7 +97,7 @@ impl<'de> Decode<'de> for CodecVersionsPdu { let codec_number = src.read_u8(); if codec_number != CODECS_NUMBER { - return Err(invalid_field_err!("codec_number", "Invalid codec number")); + return Err(invalid_field_err!("codec_number", "Invalid codec number", at: 0)); } let _codec_version = CodecVersion::decode(src)?; @@ -195,7 +195,7 @@ impl<'de> Decode<'de> for RfxChannel { let channel_id = src.read_u8(); if channel_id != CHANNEL_ID { - return Err(invalid_field_err!("channelId", "Invalid channel ID")); + return Err(invalid_field_err!("channelId", "Invalid channel ID", at: 0)); } let width = src.read_i16(); @@ -242,11 +242,11 @@ impl<'de> Decode<'de> for CodecVersion { let codec_id = src.read_u8(); if codec_id != CODEC_ID { - return Err(invalid_field_err!("codec_id", "Invalid codec ID")); + return Err(invalid_field_err!("codec_id", "Invalid codec ID", at: 0)); } let codec_version = src.read_u16(); if codec_version != CODEC_VERSION { - return Err(invalid_field_err!("codec_version", "Invalid codec version")); + return Err(invalid_field_err!("codec_version", "Invalid codec version", at: 0)); } Ok(Self) diff --git a/crates/ironrdp-pdu/src/codecs/rfx/mod.rs b/crates/ironrdp-pdu/src/codecs/rfx/mod.rs index fec0a4b74..4150dc999 100644 --- a/crates/ironrdp-pdu/src/codecs/rfx/mod.rs +++ b/crates/ironrdp-pdu/src/codecs/rfx/mod.rs @@ -123,14 +123,14 @@ impl<'de> Decode<'de> for Block<'de> { CHANNEL_ID_FOR_OTHER_VALUES }; if channel.channel_id != expected_id { - return Err(invalid_field_err!("channelId", "Invalid channel ID")); + return Err(invalid_field_err!("channelId", "Invalid channel ID", at: 0)); } len += channel.size(); } let data_len = header .data_length .checked_sub(len) - .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length"))?; + .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length", at: 0))?; ensure_size!(in: src, size: data_len); let src = &mut ReadCursor::new(src.read_slice(data_len)); match header.ty { @@ -211,11 +211,11 @@ impl<'de> Decode<'de> for BlockHeader { ensure_fixed_part_size!(in: src); let ty = src.read_u16(); - let ty = BlockType::from_u16(ty).ok_or_else(|| invalid_field_err!("blockType", "Invalid block type"))?; + let ty = BlockType::from_u16(ty).ok_or_else(|| invalid_field_err!("blockType", "Invalid block type", at: 0))?; let data_length: usize = cast_length!("block length", src.read_u32())?; data_length .checked_sub(Self::FIXED_PART_SIZE) - .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length"))?; + .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length", at: 0))?; Ok(Self { ty, data_length }) } @@ -261,7 +261,7 @@ impl Decode<'_> for CodecChannelHeader { let codec_id = src.read_u8(); if codec_id != CODEC_ID { - return Err(invalid_field_err!("codecId", "Invalid codec ID")); + return Err(invalid_field_err!("codecId", "Invalid codec ID", at: 0)); } let channel_id = src.read_u8(); diff --git a/crates/ironrdp-pdu/src/codecs/rfx/progressive.rs b/crates/ironrdp-pdu/src/codecs/rfx/progressive.rs index 271fa9450..77c501d4f 100644 --- a/crates/ironrdp-pdu/src/codecs/rfx/progressive.rs +++ b/crates/ironrdp-pdu/src/codecs/rfx/progressive.rs @@ -99,7 +99,7 @@ impl Decode<'_> for ProgressiveBlockHeader { ensure_fixed_part_size!(in: src); let raw = src.read_u16(); let block_type = ProgressiveBlockType::from_u16(raw) - .ok_or_else(|| invalid_field_err!("blockType", "unknown progressive block type"))?; + .ok_or_else(|| invalid_field_err!("blockType", "unknown progressive block type", at: 0))?; let block_len = src.read_u32(); Ok(Self { block_type, block_len }) } @@ -303,11 +303,11 @@ impl Decode<'_> for ProgressiveSyncPdu { ensure_fixed_part_size!(in: src); let magic = src.read_u32(); if magic != SYNC_MAGIC { - return Err(invalid_field_err!("magic", "invalid progressive sync magic")); + return Err(invalid_field_err!("magic", "invalid progressive sync magic", at: 0)); } let version = src.read_u16(); if version != SYNC_VERSION { - return Err(invalid_field_err!("version", "unsupported progressive version")); + return Err(invalid_field_err!("version", "unsupported progressive version", at: 0)); } Ok(Self) } @@ -431,7 +431,7 @@ impl Decode<'_> for ProgressiveContextPdu { let context_id = src.read_u8(); let tile_size = src.read_u16(); if tile_size != TILE_SIZE { - return Err(invalid_field_err!("tileSize", "only 64x64 tiles supported")); + return Err(invalid_field_err!("tileSize", "only 64x64 tiles supported", at: 0)); } let flags = src.read_u8(); Ok(Self { @@ -875,7 +875,7 @@ impl<'de> Decode<'de> for ProgressiveRegion<'de> { let tile_size = src.read_u8(); if tile_size != 0x40 { - return Err(invalid_field_err!("tileSize", "only 64x64 tiles supported")); + return Err(invalid_field_err!("tileSize", "only 64x64 tiles supported", at: 0)); } let num_rects = usize::from(src.read_u16()); @@ -884,13 +884,11 @@ impl<'de> Decode<'de> for ProgressiveRegion<'de> { let flags = src.read_u8(); if num_rects == 0 { - return Err(invalid_field_err!( - "numRects", - "region must contain at least one rectangle" - )); + return Err(invalid_field_err!( "numRects", + "region must contain at least one rectangle", at: 0)); } if num_quant > 7 { - return Err(invalid_field_err!("numQuant", "quant count exceeds maximum of 7")); + return Err(invalid_field_err!("numQuant", "quant count exceeds maximum of 7", at: 0)); } let num_tiles = usize::from(src.read_u16()); let _tile_data_size = src.read_u32(); @@ -921,7 +919,7 @@ impl<'de> Decode<'de> for ProgressiveRegion<'de> { let body_len = header .block_len .checked_sub(BLOCK_HEADER_SIZE_U32) - .ok_or_else(|| invalid_field_err!("blockLen", "tile block length too small"))?; + .ok_or_else(|| invalid_field_err!("blockLen", "tile block length too small", at: 0))?; let body_len: usize = cast_length!("tileBodyLen", body_len)?; ensure_size!(ctx: Self::NAME, in: src, size: body_len); let tile_src = &mut ReadCursor::new(src.read_slice(body_len)); @@ -931,7 +929,7 @@ impl<'de> Decode<'de> for ProgressiveRegion<'de> { ProgressiveBlockType::TileFirst => ProgressiveTile::First(TileFirst::decode(tile_src)?), ProgressiveBlockType::TileUpgrade => ProgressiveTile::Upgrade(TileUpgrade::decode(tile_src)?), _ => { - return Err(invalid_field_err!("blockType", "expected tile block inside region")); + return Err(invalid_field_err!("blockType", "expected tile block inside region", at: 0)); } }; tiles.push(tile); @@ -945,7 +943,7 @@ impl<'de> Decode<'de> for ProgressiveRegion<'de> { ProgressiveTile::Upgrade(t) => [t.quant_idx_y, t.quant_idx_cb, t.quant_idx_cr], }; if indices.iter().any(|&i| usize::from(i) >= quant_count) { - return Err(invalid_field_err!("quantIdx", "tile quant index out of range")); + return Err(invalid_field_err!("quantIdx", "tile quant index out of range", at: 0)); } } @@ -989,7 +987,7 @@ pub fn decode_progressive_stream<'a>(data: &'a [u8]) -> DecodeResult(data: &'a [u8]) -> DecodeResult(data: &'a [u8]) -> DecodeResult ProgressiveBlock::Region(ProgressiveRegion::decode(body_src)?), // Tile blocks should only appear inside regions; skip at top level ProgressiveBlockType::TileSimple | ProgressiveBlockType::TileFirst | ProgressiveBlockType::TileUpgrade => { - return Err(invalid_field_err!("blockType", "tile block outside of region")); + return Err(invalid_field_err!("blockType", "tile block outside of region", at: 0)); } }; blocks.push(block); diff --git a/crates/ironrdp-pdu/src/gcc/cluster_data.rs b/crates/ironrdp-pdu/src/gcc/cluster_data.rs index 88b87dd48..d08faac51 100644 --- a/crates/ironrdp-pdu/src/gcc/cluster_data.rs +++ b/crates/ironrdp-pdu/src/gcc/cluster_data.rs @@ -53,9 +53,9 @@ impl<'de> Decode<'de> for ClientClusterData { let redirected_session_id = src.read_u32(); let flags = RedirectionFlags::from_bits(flags_with_version & !REDIRECTION_VERSION_MASK) - .ok_or_else(|| invalid_field_err!("flags", "invalid redirection flags"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid redirection flags", at: 0))?; let redirection_version = RedirectionVersion::from_u32((flags_with_version & REDIRECTION_VERSION_MASK) >> 2) - .ok_or_else(|| invalid_field_err!("redirVersion", "invalid redirection version"))?; + .ok_or_else(|| invalid_field_err!("redirVersion", "invalid redirection version", at: 0))?; Ok(Self { flags, diff --git a/crates/ironrdp-pdu/src/gcc/conference_create.rs b/crates/ironrdp-pdu/src/gcc/conference_create.rs index e7afbbade..a7edc1456 100644 --- a/crates/ironrdp-pdu/src/gcc/conference_create.rs +++ b/crates/ironrdp-pdu/src/gcc/conference_create.rs @@ -48,10 +48,8 @@ impl ConferenceCreateRequest { // Ensure the invariant on gcc_blocks.size() is respected. check_invariant(gcc_blocks.size() <= usize::from(u16::MAX) - CONFERENCE_REQUEST_CONNECT_PDU_SIZE).ok_or_else( || { - invalid_field_err!( - "gcc_blocks", - "gcc_blocks.size() + CONFERENCE_REQUEST_CONNECT_PDU_SIZE > u16::MAX" - ) + invalid_field_err!( "gcc_blocks", + "gcc_blocks.size() + CONFERENCE_REQUEST_CONNECT_PDU_SIZE > u16::MAX", at: 0) }, )?; @@ -139,14 +137,12 @@ impl<'de> Decode<'de> for ConferenceCreateRequest { // ConnectData::Key: select object (0) of type OBJECT_IDENTIFIER ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != OBJECT_IDENTIFIER_KEY { - return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key")); + return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key", at: 0)); } // ConnectData::Key: value (OBJECT_IDENTIFIER) if per::read_object_id(src).map_err(|e| other_err!("value", source: e))? != CONFERENCE_REQUEST_OBJECT_ID { - return Err(invalid_field_err!( - "ConnectData::Key", - "Got unexpected ConnectData key value" - )); + return Err(invalid_field_err!( "ConnectData::Key", + "Got unexpected ConnectData key value", at: 0)); } // ConnectData::connectPDU: length @@ -154,18 +150,14 @@ impl<'de> Decode<'de> for ConferenceCreateRequest { // ConnectGCCPDU (CHOICE): Select conferenceCreateRequest (0) of type ConferenceCreateRequest ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != CONNECT_GCC_PDU_CONFERENCE_REQUEST_CHOICE { - return Err(invalid_field_err!( - "ConnectData::connectPdu", - "Got invalid ConnectGCCPDU choice (expected ConferenceCreateRequest)" - )); + return Err(invalid_field_err!( "ConnectData::connectPdu", + "Got invalid ConnectGCCPDU choice (expected ConferenceCreateRequest)", at: 0)); } // ConferenceCreateRequest::Selection: select optional userData from ConferenceCreateRequest ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_selection(src) != CONFERENCE_REQUEST_USER_DATA_SELECTION { - return Err(invalid_field_err!( - "ConferenceCreateRequest::Selection", - "Got invalid ConferenceCreateRequest selection (expected UserData)", - )); + return Err(invalid_field_err!( "ConferenceCreateRequest::Selection", + "Got invalid ConferenceCreateRequest selection (expected UserData)", at: 0)); } // ConferenceCreateRequest::ConferenceName per::read_numeric_string(src, 1).map_err(|e| other_err!("confName", source: e))?; @@ -176,28 +168,22 @@ impl<'de> Decode<'de> for ConferenceCreateRequest { // one set of UserData ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_number_of_sets(src) != USER_DATA_NUMBER_OF_SETS { - return Err(invalid_field_err!( - "ConferenceCreateRequest", - "Got invalid ConferenceCreateRequest number of sets (expected 1)", - )); + return Err(invalid_field_err!( "ConferenceCreateRequest", + "Got invalid ConferenceCreateRequest number of sets (expected 1)", at: 0)); } // select h221NonStandard ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != USER_DATA_H221_NON_STANDARD_CHOICE { - return Err(invalid_field_err!( - "ConferenceCreateRequest", - "Expected UserData H221NonStandard choice", - )); + return Err(invalid_field_err!( "ConferenceCreateRequest", + "Expected UserData H221NonStandard choice", at: 0)); } // h221NonStandard: client-to-server H.221 key, "Duca" if per::read_octet_string(src, H221_NON_STANDARD_MIN_LENGTH) .map_err(|e| other_err!("client-to-server", source: e))? != CONFERENCE_REQUEST_CLIENT_TO_SERVER_H221_NON_STANDARD { - return Err(invalid_field_err!( - "ConferenceCreateRequest", - "Got invalid H221NonStandard client-to-server key", - )); + return Err(invalid_field_err!( "ConferenceCreateRequest", + "Got invalid H221NonStandard client-to-server key", at: 0)); } // H221NonStandardIdentifier (octet string) let (_gcc_blocks_buffer_length, _) = per::read_length(src).map_err(|e| other_err!("len", source: e))?; @@ -232,10 +218,8 @@ impl ConferenceCreateResponse { // Ensure the invariant on gcc_blocks.size() is respected. check_invariant(gcc_blocks.size() <= usize::from(u16::MAX) - CONFERENCE_RESPONSE_CONNECT_PDU_SIZE).ok_or_else( || { - invalid_field_err!( - "gcc_blocks", - "gcc_blocks.size() + CONFERENCE_REQUEST_CONNECT_PDU_SIZE > u16::MAX" - ) + invalid_field_err!( "gcc_blocks", + "gcc_blocks.size() + CONFERENCE_REQUEST_CONNECT_PDU_SIZE > u16::MAX", at: 0) }, )?; @@ -320,67 +304,53 @@ impl<'de> Decode<'de> for ConferenceCreateResponse { // ConnectData::Key: select type OBJECT_IDENTIFIER ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != OBJECT_IDENTIFIER_KEY { - return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key")); + return Err(invalid_field_err!("ConnectData::Key", "Got unexpected ConnectData key", at: 0)); } // ConnectData::Key: value if per::read_object_id(src).map_err(|e| other_err!("value", source: e))? != CONFERENCE_REQUEST_OBJECT_ID { - return Err(invalid_field_err!( - "ConnectData::Key", - "Got unexpected ConnectData key value" - )); + return Err(invalid_field_err!( "ConnectData::Key", + "Got unexpected ConnectData key value", at: 0)); }; // ConnectData::connectPDU: length (MUST be ignored by the client according to [MS-RDPBCGR]) let _length = per::read_length(src).map_err(|e| other_err!("len", source: e))?; // ConnectGCCPDU (CHOICE): Select conferenceCreateResponse (1) of type ConferenceCreateResponse ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != CONNECT_GCC_PDU_CONFERENCE_RESPONSE_CHOICE { - return Err(invalid_field_err!( - "ConnectData::connectPdu", - "Got invalid ConnectGCCPDU choice (expected ConferenceCreateResponse)" - )); + return Err(invalid_field_err!( "ConnectData::connectPdu", + "Got invalid ConnectGCCPDU choice (expected ConferenceCreateResponse)", at: 0)); } // ConferenceCreateResponse::nodeID (UserID) let user_id = per::read_u16(src, CONFERENCE_REQUEST_U16_MIN).map_err(|e| other_err!("userId", source: e))?; // ConferenceCreateResponse::tag (INTEGER) if per::read_u32(src).map_err(|e| other_err!("tag", source: e))? != CONFERENCE_RESPONSE_TAG { - return Err(invalid_field_err!( - "ConferenceCreateResponse::tag", - "Got unexpected ConferenceCreateResponse tag", - )); + return Err(invalid_field_err!( "ConferenceCreateResponse::tag", + "Got unexpected ConferenceCreateResponse tag", at: 0)); } // ConferenceCreateResponse::result (ENUMERATED) if per::read_enum(src, mcs::RESULT_ENUM_LENGTH).map_err(|e| other_err!("result", source: e))? != CONFERENCE_RESPONSE_RESULT { - return Err(invalid_field_err!( - "ConferenceCreateResponse::result", - "Got invalid ConferenceCreateResponse result", - )); + return Err(invalid_field_err!( "ConferenceCreateResponse::result", + "Got invalid ConferenceCreateResponse result", at: 0)); } ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_number_of_sets(src) != USER_DATA_NUMBER_OF_SETS { - return Err(invalid_field_err!( - "ConferenceCreateResponse", - "Got invalid ConferenceCreateResponse number of sets (expected 1)", - )); + return Err(invalid_field_err!( "ConferenceCreateResponse", + "Got invalid ConferenceCreateResponse number of sets (expected 1)", at: 0)); } // select h221NonStandard ensure_size!(in: src, size: per::CHOICE_SIZE); if per::read_choice(src) != USER_DATA_H221_NON_STANDARD_CHOICE { - return Err(invalid_field_err!( - "ConferenceCreateResponse", - "Expected UserData H221NonStandard choice", - )); + return Err(invalid_field_err!( "ConferenceCreateResponse", + "Expected UserData H221NonStandard choice", at: 0)); } // h221NonStandard, server-to-client H.221 key, "McDn" if per::read_octet_string(src, H221_NON_STANDARD_MIN_LENGTH) .map_err(|e| other_err!("server-to-client", source: e))? != CONFERENCE_REQUEST_SERVER_TO_CLIENT_H221_NON_STANDARD { - return Err(invalid_field_err!( - "ConferenceCreateResponse", - "Got invalid H221NonStandard server-to-client key", - )); + return Err(invalid_field_err!( "ConferenceCreateResponse", + "Got invalid H221NonStandard server-to-client key", at: 0)); } let (_gcc_blocks_buffer_length, _) = per::read_length(src).map_err(|e| other_err!("len", source: e))?; let gcc_blocks = ServerGccBlocks::decode(src)?; diff --git a/crates/ironrdp-pdu/src/gcc/core_data/client.rs b/crates/ironrdp-pdu/src/gcc/core_data/client.rs index e787bde9c..5cc7a5786 100644 --- a/crates/ironrdp-pdu/src/gcc/core_data/client.rs +++ b/crates/ironrdp-pdu/src/gcc/core_data/client.rs @@ -143,11 +143,11 @@ impl<'de> Decode<'de> for ClientCoreData { let color_depth = src .read_u16() .pipe(ColorDepth::from_u16) - .ok_or_else(|| invalid_field_err!("colorDepth", "invalid color depth"))?; + .ok_or_else(|| invalid_field_err!("colorDepth", "invalid color depth", at: 0))?; let sec_access_sequence = src .read_u16() .pipe(SecureAccessSequence::from_u16) - .ok_or_else(|| invalid_field_err!("secAccessSequence", "invalid secure access sequence"))?; + .ok_or_else(|| invalid_field_err!("secAccessSequence", "invalid secure access sequence", at: 0))?; let keyboard_layout = src.read_u32(); let client_build = src.read_u32(); @@ -159,7 +159,7 @@ impl<'de> Decode<'de> for ClientCoreData { let keyboard_type = src .read_u32() .pipe(KeyboardType::from_u32) - .ok_or_else(|| invalid_field_err!("keyboardType", "invalid keyboard type"))?; + .ok_or_else(|| invalid_field_err!("keyboardType", "invalid keyboard type", at: 0))?; let keyboard_subtype = src.read_u32(); let keyboard_functional_keys_count = src.read_u32(); @@ -230,51 +230,45 @@ impl Encode for ClientCoreOptionalData { if let Some(value) = self.client_product_id { if self.post_beta2_color_depth.is_none() { - return Err(invalid_field_err!( - "postBeta2ColorDepth", - "postBeta2ColorDepth must be present" - )); + return Err(invalid_field_err!( "postBeta2ColorDepth", + "postBeta2ColorDepth must be present", at: 0)); } dst.write_u16(value); } if let Some(value) = self.serial_number { if self.client_product_id.is_none() { - return Err(invalid_field_err!("clientProductId", "clientProductId must be present")); + return Err(invalid_field_err!("clientProductId", "clientProductId must be present", at: 0)); } dst.write_u32(value); } if let Some(value) = self.high_color_depth { if self.serial_number.is_none() { - return Err(invalid_field_err!("serialNumber", "serialNumber must be present")); + return Err(invalid_field_err!("serialNumber", "serialNumber must be present", at: 0)); } dst.write_u16(value.as_u16()); } if let Some(value) = self.supported_color_depths { if self.high_color_depth.is_none() { - return Err(invalid_field_err!("highColorDepth", "highColorDepth must be present")); + return Err(invalid_field_err!("highColorDepth", "highColorDepth must be present", at: 0)); } dst.write_u16(value.bits()); } if let Some(value) = self.early_capability_flags { if self.supported_color_depths.is_none() { - return Err(invalid_field_err!( - "supportedColorDepths", - "supportedColorDepths must be present" - )); + return Err(invalid_field_err!( "supportedColorDepths", + "supportedColorDepths must be present", at: 0)); } dst.write_u16(value.bits()); } if let Some(ref value) = self.dig_product_id { if self.early_capability_flags.is_none() { - return Err(invalid_field_err!( - "earlyCapabilityFlags", - "earlyCapabilityFlags must be present" - )); + return Err(invalid_field_err!( "earlyCapabilityFlags", + "earlyCapabilityFlags must be present", at: 0)); } let mut dig_product_id_buffer = utils::to_utf16_bytes(value); dig_product_id_buffer.resize(DIG_PRODUCT_ID_SIZE - 2, 0); @@ -285,7 +279,7 @@ impl Encode for ClientCoreOptionalData { if let Some(value) = self.connection_type { if self.dig_product_id.is_none() { - return Err(invalid_field_err!("digProductId", "digProductId must be present")); + return Err(invalid_field_err!("digProductId", "digProductId must be present", at: 0)); } dst.write_u8(value.as_u8()); write_padding!(dst, 1); @@ -293,57 +287,47 @@ impl Encode for ClientCoreOptionalData { if let Some(value) = self.server_selected_protocol { if self.connection_type.is_none() { - return Err(invalid_field_err!("connectionType", "connectionType must be present")); + return Err(invalid_field_err!("connectionType", "connectionType must be present", at: 0)); } dst.write_u32(value.bits()) } if let Some(value) = self.desktop_physical_width { if self.server_selected_protocol.is_none() { - return Err(invalid_field_err!( - "serverSelectedProtocol", - "serverSelectedProtocol must be present" - )); + return Err(invalid_field_err!( "serverSelectedProtocol", + "serverSelectedProtocol must be present", at: 0)); } dst.write_u32(value); } if let Some(value) = self.desktop_physical_height { if self.desktop_physical_width.is_none() { - return Err(invalid_field_err!( - "desktopPhysicalWidth", - "desktopPhysicalWidth must be present" - )); + return Err(invalid_field_err!( "desktopPhysicalWidth", + "desktopPhysicalWidth must be present", at: 0)); } dst.write_u32(value); } if let Some(value) = self.desktop_orientation { if self.desktop_physical_height.is_none() { - return Err(invalid_field_err!( - "desktopPhysicalHeight", - "desktopPhysicalHeight must be present" - )); + return Err(invalid_field_err!( "desktopPhysicalHeight", + "desktopPhysicalHeight must be present", at: 0)); } dst.write_u16(value); } if let Some(value) = self.desktop_scale_factor { if self.desktop_orientation.is_none() { - return Err(invalid_field_err!( - "desktopOrientation", - "desktopOrientation must be present" - )); + return Err(invalid_field_err!( "desktopOrientation", + "desktopOrientation must be present", at: 0)); } dst.write_u32(value); } if let Some(value) = self.device_scale_factor { if self.desktop_scale_factor.is_none() { - return Err(invalid_field_err!( - "desktopScaleFactor", - "desktopScaleFactor must be present" - )); + return Err(invalid_field_err!( "desktopScaleFactor", + "desktopScaleFactor must be present", at: 0)); } dst.write_u32(value); } @@ -420,7 +404,7 @@ impl<'de> Decode<'de> for ClientCoreOptionalData { optional_data.post_beta2_color_depth = Some( ColorDepth::from_u16(try_or_return!(src.try_read_u16(), optional_data)) - .ok_or_else(|| invalid_field_err!("postBeta2ColorDepth", "invalid color depth"))?, + .ok_or_else(|| invalid_field_err!("postBeta2ColorDepth", "invalid color depth", at: 0))?, ); optional_data.client_product_id = Some(try_or_return!(src.try_read_u16(), optional_data)); @@ -428,17 +412,17 @@ impl<'de> Decode<'de> for ClientCoreOptionalData { optional_data.high_color_depth = Some( HighColorDepth::from_u16(try_or_return!(src.try_read_u16(), optional_data)) - .ok_or_else(|| invalid_field_err!("highColorDepth", "invalid color depth"))?, + .ok_or_else(|| invalid_field_err!("highColorDepth", "invalid color depth", at: 0))?, ); optional_data.supported_color_depths = Some( SupportedColorDepths::from_bits(try_or_return!(src.try_read_u16(), optional_data)) - .ok_or_else(|| invalid_field_err!("supportedColorDepths", "invalid supported color depths"))?, + .ok_or_else(|| invalid_field_err!("supportedColorDepths", "invalid supported color depths", at: 0))?, ); optional_data.early_capability_flags = Some( ClientEarlyCapabilityFlags::from_bits(try_or_return!(src.try_read_u16(), optional_data)) - .ok_or_else(|| invalid_field_err!("earlyCapabilityFlags", "invalid early capability flags"))?, + .ok_or_else(|| invalid_field_err!("earlyCapabilityFlags", "invalid early capability flags", at: 0))?, ); if src.len() < DIG_PRODUCT_ID_SIZE { @@ -450,14 +434,14 @@ impl<'de> Decode<'de> for ClientCoreOptionalData { optional_data.connection_type = Some( ConnectionType::from_u8(try_or_return!(src.try_read_u8(), optional_data)) - .ok_or_else(|| invalid_field_err!("connectionType", "invalid connection type"))?, + .ok_or_else(|| invalid_field_err!("connectionType", "invalid connection type", at: 0))?, ); try_or_return!(src.try_read_u8(), optional_data); optional_data.server_selected_protocol = Some( SecurityProtocol::from_bits(try_or_return!(src.try_read_u32(), optional_data)) - .ok_or_else(|| invalid_field_err!("serverSelectedProtocol", "invalid security protocol"))?, + .ok_or_else(|| invalid_field_err!("serverSelectedProtocol", "invalid security protocol", at: 0))?, ); optional_data.desktop_physical_width = Some(try_or_return!(src.try_read_u32(), optional_data)); diff --git a/crates/ironrdp-pdu/src/gcc/core_data/server.rs b/crates/ironrdp-pdu/src/gcc/core_data/server.rs index 575afc9b3..4c9190458 100644 --- a/crates/ironrdp-pdu/src/gcc/core_data/server.rs +++ b/crates/ironrdp-pdu/src/gcc/core_data/server.rs @@ -111,12 +111,12 @@ impl<'de> Decode<'de> for ServerCoreOptionalData { optional_data.client_requested_protocols = Some( SecurityProtocol::from_bits(try_or_return!(src.try_read_u32(), optional_data)) - .ok_or_else(|| invalid_field_err!("clientReqProtocols", "invalid server security protocol"))?, + .ok_or_else(|| invalid_field_err!("clientReqProtocols", "invalid server security protocol", at: 0))?, ); optional_data.early_capability_flags = Some( ServerEarlyCapabilityFlags::from_bits(try_or_return!(src.try_read_u32(), optional_data)) - .ok_or_else(|| invalid_field_err!("earlyCapFlags", "invalid early capability flags"))?, + .ok_or_else(|| invalid_field_err!("earlyCapFlags", "invalid early capability flags", at: 0))?, ); Ok(optional_data) diff --git a/crates/ironrdp-pdu/src/gcc/mod.rs b/crates/ironrdp-pdu/src/gcc/mod.rs index 2156a613b..d5ae229f7 100644 --- a/crates/ironrdp-pdu/src/gcc/mod.rs +++ b/crates/ironrdp-pdu/src/gcc/mod.rs @@ -164,8 +164,9 @@ impl<'de> Decode<'de> for ClientGccBlocks { } Ok(Self { - core: core.ok_or_else(|| invalid_field_err!("core", "required GCC core is absent"))?, - security: security.ok_or_else(|| invalid_field_err!("security", "required GCC security is absent"))?, + core: core.ok_or_else(|| invalid_field_err!("core", "required GCC core is absent", at: 0))?, + security: security + .ok_or_else(|| invalid_field_err!("security", "required GCC security is absent", at: 0))?, network, cluster, monitor, @@ -256,9 +257,10 @@ impl<'de> Decode<'de> for ServerGccBlocks { } Ok(Self { - core: core.ok_or_else(|| invalid_field_err!("core", "required GCC core is absent"))?, - network: network.ok_or_else(|| invalid_field_err!("network", "required GCC network is absent"))?, - security: security.ok_or_else(|| invalid_field_err!("security", "required GCC security is absent"))?, + core: core.ok_or_else(|| invalid_field_err!("core", "required GCC core is absent", at: 0))?, + network: network.ok_or_else(|| invalid_field_err!("network", "required GCC network is absent", at: 0))?, + security: security + .ok_or_else(|| invalid_field_err!("security", "required GCC security is absent", at: 0))?, message_channel, multi_transport_channel, }) @@ -338,11 +340,11 @@ impl UserDataHeader { ensure_fixed_part_size!(in: src); let block_type = - T::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("blockType", "invalid GCC type"))?; + T::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("blockType", "invalid GCC type", at: 0))?; let block_length: usize = cast_length!("blockLen", src.read_u16())?; if block_length <= USER_DATA_HEADER_SIZE { - return Err(invalid_field_err!("blockLen", "invalid UserDataHeader length")); + return Err(invalid_field_err!("blockLen", "invalid UserDataHeader length", at: 0)); } let len = block_length - USER_DATA_HEADER_SIZE; diff --git a/crates/ironrdp-pdu/src/gcc/monitor_data.rs b/crates/ironrdp-pdu/src/gcc/monitor_data.rs index 01972e8ef..b46240137 100644 --- a/crates/ironrdp-pdu/src/gcc/monitor_data.rs +++ b/crates/ironrdp-pdu/src/gcc/monitor_data.rs @@ -53,7 +53,7 @@ impl<'de> Decode<'de> for ClientMonitorData { let monitor_count = cast_length!("number of monitors", src.read_u32())?; if monitor_count > MONITOR_COUNT_MAX { - return Err(invalid_field_err!("nMonitors", "too many monitors")); + return Err(invalid_field_err!("nMonitors", "too many monitors", at: 0)); } let mut monitors = Vec::with_capacity(monitor_count); @@ -112,7 +112,7 @@ impl<'de> Decode<'de> for Monitor { let right = src.read_i32(); let bottom = src.read_i32(); let flags = MonitorFlags::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("flags", "invalid monitor flags"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid monitor flags", at: 0))?; Ok(Self { left, diff --git a/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs b/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs index d90b6aa47..d158b9042 100644 --- a/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs +++ b/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs @@ -57,13 +57,13 @@ impl<'de> Decode<'de> for ClientMonitorExtendedData { let monitor_attribute_size = src.read_u32(); if monitor_attribute_size != MONITOR_ATTRIBUTE_SIZE { - return Err(invalid_field_err!("monitorAttributeSize", "invalid size")); + return Err(invalid_field_err!("monitorAttributeSize", "invalid size", at: 0)); } let monitor_count = cast_length!("monitorCount", src.read_u32())?; if monitor_count > MONITOR_COUNT_MAX { - return Err(invalid_field_err!("monitorCount", "invalid monitor count")); + return Err(invalid_field_err!("monitorCount", "invalid monitor count", at: 0)); } let mut extended_monitors_info = Vec::with_capacity(monitor_count); @@ -120,7 +120,7 @@ impl<'de> Decode<'de> for ExtendedMonitorInfo { let physical_width = src.read_u32(); let physical_height = src.read_u32(); let orientation = MonitorOrientation::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("orientation", "invalid monitor orientation"))?; + .ok_or_else(|| invalid_field_err!("orientation", "invalid monitor orientation", at: 0))?; let desktop_scale_factor = src.read_u32(); let device_scale_factor = src.read_u32(); diff --git a/crates/ironrdp-pdu/src/gcc/multi_transport_channel_data.rs b/crates/ironrdp-pdu/src/gcc/multi_transport_channel_data.rs index 8265069e0..dbe524e7e 100644 --- a/crates/ironrdp-pdu/src/gcc/multi_transport_channel_data.rs +++ b/crates/ironrdp-pdu/src/gcc/multi_transport_channel_data.rs @@ -38,7 +38,7 @@ impl<'de> Decode<'de> for MultiTransportChannelData { ensure_fixed_part_size!(in: src); let flags = MultiTransportFlags::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("flags", "invalid multitransport flags"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid multitransport flags", at: 0))?; Ok(Self { flags }) } diff --git a/crates/ironrdp-pdu/src/gcc/network_data.rs b/crates/ironrdp-pdu/src/gcc/network_data.rs index 76c883e3c..c703906f4 100644 --- a/crates/ironrdp-pdu/src/gcc/network_data.rs +++ b/crates/ironrdp-pdu/src/gcc/network_data.rs @@ -153,7 +153,7 @@ impl<'de> Decode<'de> for ClientNetworkData { let channel_count = cast_length!("channelCount", src.read_u32())?; if channel_count > CHANNELS_MAX { - return Err(invalid_field_err!("channelCount", "invalid channel count")); + return Err(invalid_field_err!("channelCount", "invalid channel count", at: 0)); } let mut channels = Vec::with_capacity(channel_count); @@ -283,7 +283,7 @@ impl<'de> Decode<'de> for ChannelDef { let name = ChannelName::new(name); let options = ChannelOptions::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("options", "invalid channel options"))?; + .ok_or_else(|| invalid_field_err!("options", "invalid channel options", at: 0))?; Ok(Self { name, options }) } diff --git a/crates/ironrdp-pdu/src/gcc/security_data.rs b/crates/ironrdp-pdu/src/gcc/security_data.rs index 5433f4143..ee9178c83 100644 --- a/crates/ironrdp-pdu/src/gcc/security_data.rs +++ b/crates/ironrdp-pdu/src/gcc/security_data.rs @@ -60,7 +60,7 @@ impl<'de> Decode<'de> for ClientSecurityData { ensure_fixed_part_size!(in: src); let encryption_methods = EncryptionMethod::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("encryptionMethods", "invalid encryption methods"))?; + .ok_or_else(|| invalid_field_err!("encryptionMethods", "invalid encryption methods", at: 0))?; let ext_encryption_methods = src.read_u32(); Ok(Self { @@ -103,10 +103,8 @@ impl Encode for ServerSecurityData { if self.encryption_method.is_empty() && self.encryption_level == EncryptionLevel::None { if self.server_random.is_some() || !self.server_cert.is_empty() { - Err(invalid_field_err!( - "serverRandom", - "An encryption method and encryption level is none, but the server random or certificate is not empty" - )) + Err(invalid_field_err!( "serverRandom", + "An encryption method and encryption level is none, but the server random or certificate is not empty", at: 0)) } else { Ok(()) } @@ -150,9 +148,9 @@ impl<'de> Decode<'de> for ServerSecurityData { ensure_fixed_part_size!(in: src); let encryption_method = EncryptionMethod::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("encryptionMethod", "invalid encryption method"))?; + .ok_or_else(|| invalid_field_err!("encryptionMethod", "invalid encryption method", at: 0))?; let encryption_level = EncryptionLevel::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("encryptionLevel", "invalid encryption level"))?; + .ok_or_else(|| invalid_field_err!("encryptionLevel", "invalid encryption level", at: 0))?; let (server_random, server_cert) = if encryption_method.is_empty() && encryption_level == EncryptionLevel::None { @@ -162,13 +160,13 @@ impl<'de> Decode<'de> for ServerSecurityData { let server_random_len: usize = cast_length!("serverRandomLen", src.read_u32())?; if server_random_len != SERVER_RANDOM_LEN { - return Err(invalid_field_err!("serverRandomLen", "Invalid server random length")); + return Err(invalid_field_err!("serverRandomLen", "Invalid server random length", at: 0)); } let server_cert_len = cast_length!("serverCertLen", src.read_u32())?; if server_cert_len > MAX_SERVER_CERT_LEN { - return Err(invalid_field_err!("serverCetLen", "Invalid server certificate length")); + return Err(invalid_field_err!("serverCetLen", "Invalid server certificate length", at: 0)); } ensure_size!(in: src, size: SERVER_RANDOM_LEN); diff --git a/crates/ironrdp-pdu/src/input/fast_path.rs b/crates/ironrdp-pdu/src/input/fast_path.rs index 28c6767b0..713261586 100644 --- a/crates/ironrdp-pdu/src/input/fast_path.rs +++ b/crates/ironrdp-pdu/src/input/fast_path.rs @@ -66,7 +66,7 @@ impl<'de> Decode<'de> for FastPathInputHeader { let (length, sizeof_length) = per::read_length(src).map_err(|e| other_err!("perLen", source: e))?; if !flags.is_empty() { - return Err(invalid_field_err!("flags", "encryption not supported")); + return Err(invalid_field_err!("flags", "encryption not supported", at: 0)); } let num_events_length = if num_events == 0 { @@ -193,13 +193,13 @@ impl<'de> Decode<'de> for FastPathInputEvent { let flags = header.get_bits(0..5); let code = header.get_bits(5..8); let code: FastpathInputEventType = FastpathInputEventType::from_u8(code) - .ok_or_else(|| invalid_field_err!("code", "input event code unsupported"))?; + .ok_or_else(|| invalid_field_err!("code", "input event code unsupported", at: 0))?; let event = match code { FastpathInputEventType::ScanCode => { ensure_size!(in: src, size: 1); let code = src.read_u8(); let flags = KeyboardFlags::from_bits(flags) - .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?; + .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported", at: 0))?; FastPathInputEvent::KeyboardEvent(flags, code) } FastpathInputEventType::Mouse => { @@ -216,14 +216,14 @@ impl<'de> Decode<'de> for FastPathInputEvent { } FastpathInputEventType::Sync => { let flags = SynchronizeFlags::from_bits(flags) - .ok_or_else(|| invalid_field_err!("flags", "input synchronize flags unsupported"))?; + .ok_or_else(|| invalid_field_err!("flags", "input synchronize flags unsupported", at: 0))?; FastPathInputEvent::SyncEvent(flags) } FastpathInputEventType::Unicode => { ensure_size!(in: src, size: 2); let code = src.read_u16(); let flags = KeyboardFlags::from_bits(flags) - .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?; + .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported", at: 0))?; FastPathInputEvent::UnicodeKeyboardEvent(flags, code) } FastpathInputEventType::QoeTimestamp => { @@ -284,7 +284,7 @@ impl FastPathInput { pub fn new(input_events: Vec) -> DecodeResult { // Ensure the invariant on `input_events.len()` is respected. if !(1..=255usize).contains(&input_events.len()) { - return Err(invalid_field_err!("nEvents", "invalid number of input events")); + return Err(invalid_field_err!("nEvents", "invalid number of input events", at: 0)); } Ok(Self(input_events)) diff --git a/crates/ironrdp-pdu/src/input/mod.rs b/crates/ironrdp-pdu/src/input/mod.rs index 1e73147d5..4c12025d6 100644 --- a/crates/ironrdp-pdu/src/input/mod.rs +++ b/crates/ironrdp-pdu/src/input/mod.rs @@ -131,7 +131,7 @@ impl<'de> Decode<'de> for InputEvent { let _event_time = src.read_u32(); // ignored by a server let event_type = src.read_u16(); let event_type = InputEventType::from_u16(event_type) - .ok_or_else(|| invalid_field_err!("eventType", "invalid input event type"))?; + .ok_or_else(|| invalid_field_err!("eventType", "invalid input event type", at: 0))?; match event_type { InputEventType::Sync => Ok(Self::Sync(SyncPdu::decode(src)?)), diff --git a/crates/ironrdp-pdu/src/lib.rs b/crates/ironrdp-pdu/src/lib.rs index 8db507d67..15f53c11f 100644 --- a/crates/ironrdp-pdu/src/lib.rs +++ b/crates/ironrdp-pdu/src/lib.rs @@ -128,7 +128,7 @@ pub fn find_size(bytes: &[u8]) -> DecodeResult> { let fp_output_header = bytes[0]; let action = Action::from_fp_output_header(fp_output_header) - .map_err(|unknown_action| unexpected_message_type_err("fpOutputHeader", unknown_action))?; + .map_err(|unknown_action| unexpected_message_type_err("fpOutputHeader", unknown_action, 0))?; match action { Action::X224 => { diff --git a/crates/ironrdp-pdu/src/mcs.rs b/crates/ironrdp-pdu/src/mcs.rs index 28dd85053..d085e43ec 100644 --- a/crates/ironrdp-pdu/src/mcs.rs +++ b/crates/ironrdp-pdu/src/mcs.rs @@ -142,7 +142,7 @@ const SEND_DATA_PDU_DATA_PRIORITY_AND_SEGMENTATION: u8 = 0x70; /// |e| ::invalid_field(Self::MCS_NAME, field_name, "PER").with_source(e) /// ``` macro_rules! per_field_err { - ($field_name:expr) => {{ |error| ironrdp_core::invalid_field_err_with_source(Self::MCS_NAME, $field_name, "PER", error) }}; + ($field_name:expr) => {{ |error| ironrdp_core::invalid_field_err_with_source(Self::MCS_NAME, $field_name, "PER", 0, error) }}; } #[doc(hidden)] @@ -202,7 +202,7 @@ enum DomainMcsPdu { impl DomainMcsPdu { fn check_expected(self, name: &'static str, expected: DomainMcsPdu) -> DecodeResult<()> { if self != expected { - Err(unexpected_message_type_err!(name, self.as_u8())) + Err(unexpected_message_type_err!(name, self.as_u8(), at: 0)) } else { Ok(()) } @@ -243,14 +243,14 @@ fn read_mcspdu_header(src: &mut ReadCursor<'_>, ctx: &'static str) -> DecodeResu let choice = src.try_read_u8().map_err(|e| other_err!(ctx, source: e))?; DomainMcsPdu::from_choice(choice) - .ok_or_else(|| invalid_field_err(ctx, "domain-mcspdu", "unexpected application tag for CHOICE")) + .ok_or_else(|| invalid_field_err(ctx, "domain-mcspdu", "unexpected application tag for CHOICE", 0)) } fn peek_mcspdu_header(src: &mut ReadCursor<'_>, ctx: &'static str) -> DecodeResult { let choice = src.try_peek_u8().map_err(|e| other_err!(ctx, source: e))?; DomainMcsPdu::from_choice(choice) - .ok_or_else(|| invalid_field_err(ctx, "domain-mcspdu", "unexpected application tag for CHOICE")) + .ok_or_else(|| invalid_field_err(ctx, "domain-mcspdu", "unexpected application tag for CHOICE", 0)) } fn write_mcspdu_header(dst: &mut WriteCursor<'_>, domain_mcspdu: DomainMcsPdu, options: u8) { @@ -617,6 +617,7 @@ impl<'de> McsPdu<'de> for SendDataRequest<'de> { Self::MCS_NAME, "userDataLength", "inconsistent with user data size advertised in TPDU", + 0, )); } @@ -695,6 +696,7 @@ impl<'de> McsPdu<'de> for SendDataIndication<'de> { Self::MCS_NAME, "userDataLength", "inconsistent with user data size advertised in TPDU", + 0, )); } @@ -829,12 +831,19 @@ impl<'de> McsPdu<'de> for DisconnectProviderUltimatum { let reason = ((b1 & 0x03) << 1) | (b2 >> 7); DomainMcsPdu::from_u8(domain_mcspdu_choice) - .ok_or_else(|| invalid_field_err(Self::MCS_NAME, "domain-mcspdu", "unexpected application tag for CHOICE"))? + .ok_or_else(|| { + invalid_field_err( + Self::MCS_NAME, + "domain-mcspdu", + "unexpected application tag for CHOICE", + 0, + ) + })? .check_expected(Self::MCS_NAME, DomainMcsPdu::DisconnectProviderUltimatum)?; Ok(Self { reason: DisconnectReason::from_u8(reason) - .ok_or_else(|| invalid_field_err(Self::MCS_NAME, "reason", "unknown variant"))?, + .ok_or_else(|| invalid_field_err(Self::MCS_NAME, "reason", "unknown variant", 0))?, }) } diff --git a/crates/ironrdp-pdu/src/nego.rs b/crates/ironrdp-pdu/src/nego.rs index f7d27e83b..c9602dc9f 100644 --- a/crates/ironrdp-pdu/src/nego.rs +++ b/crates/ironrdp-pdu/src/nego.rs @@ -297,6 +297,7 @@ impl<'de> X224Pdu<'de> for ConnectionRequest { Self::NAME, "flags", "CORRECTION_INFO_PRESENT flag is set, but not supported by IronRDP", + 0, )); } @@ -317,6 +318,7 @@ impl<'de> X224Pdu<'de> for ConnectionRequest { Self::NAME, "TPDU header variable part", "advertised size too small", + 0, )); }; @@ -324,7 +326,7 @@ impl<'de> X224Pdu<'de> for ConnectionRequest { let msg_type = NegoMsgType::from(src.read_u8()); if msg_type != NegoMsgType::REQUEST { - return Err(unexpected_message_type_err!(Self::NAME, u8::from(msg_type))); + return Err(unexpected_message_type_err!(Self::NAME, u8::from(msg_type), at: 0)); } let flags = RequestFlags::from_bits_retain(src.read_u8()); @@ -335,6 +337,7 @@ impl<'de> X224Pdu<'de> for ConnectionRequest { Self::NAME, "flags", "CORRECTION_INFO_PRESENT flag is set, but not supported by IronRDP", + 0, )); } @@ -432,7 +435,7 @@ impl<'de> X224Pdu<'de> for ConnectionConfirm { Ok(Self::Failure { code }) } - unexpected => Err(unexpected_message_type_err!(Self::X224_NAME, u8::from(unexpected))), + unexpected => Err(unexpected_message_type_err!(Self::X224_NAME, u8::from(unexpected), at: 0)), } } else { Ok(Self::Response { @@ -477,7 +480,7 @@ fn read_nego_data(src: &mut ReadCursor<'_>, ctx: &'static str, prefix: &str) -> src.advance(2); let data = core::str::from_utf8(&src.inner()[identifier_start..identifier_end]) - .map_err(|_| invalid_field_err(ctx, "identifier", "not valid UTF-8"))? + .map_err(|_| invalid_field_err(ctx, "identifier", "not valid UTF-8", 0))? .to_owned(); Ok(Some(data)) diff --git a/crates/ironrdp-pdu/src/pcb.rs b/crates/ironrdp-pdu/src/pcb.rs index 404d4e6ee..896dd90dc 100644 --- a/crates/ironrdp-pdu/src/pcb.rs +++ b/crates/ironrdp-pdu/src/pcb.rs @@ -58,6 +58,7 @@ impl<'de> Decode<'de> for PreconnectionBlob { Self::NAME, "cbSize", "advertised size too small for Preconnection PDU V1", + 0, )); } @@ -83,13 +84,14 @@ impl<'de> Decode<'de> for PreconnectionBlob { Self::NAME, "cchPCB", "PCB string bigger than advertised size", + 0, )); } let wsz_pcb_utf16 = src.read_slice(cb_pcb); let payload = crate::utf16::read_utf16_string(wsz_pcb_utf16, Some(cch_pcb)) - .map_err(|e| invalid_field_err_with_source(Self::NAME, "wszPCB", "bad UTF-16 string", e))?; + .map_err(|e| invalid_field_err_with_source(Self::NAME, "wszPCB", "bad UTF-16 string", 0, e))?; let leftover_size = remaining_size - 2 - cb_pcb; src.advance(leftover_size); // Consume (unused) leftover data @@ -116,6 +118,7 @@ impl Encode for PreconnectionBlob { Self::NAME, "version", "there is no string payload in Preconnection PDU V1", + 0, )); } diff --git a/crates/ironrdp-pdu/src/rdp/autodetect.rs b/crates/ironrdp-pdu/src/rdp/autodetect.rs index fc49c54c6..79d1eeb46 100644 --- a/crates/ironrdp-pdu/src/rdp/autodetect.rs +++ b/crates/ironrdp-pdu/src/rdp/autodetect.rs @@ -388,10 +388,8 @@ impl<'de> Decode<'de> for AutoDetectRequest { let header_type_id = src.read_u8(); if header_type_id != TYPE_ID_AUTODETECT_REQUEST { - return Err(invalid_field_err!( - "headerTypeId", - "expected TYPE_ID_AUTODETECT_REQUEST (0x00)" - )); + return Err(invalid_field_err!( "headerTypeId", + "expected TYPE_ID_AUTODETECT_REQUEST (0x00)", at: 0)); } let sequence_number = src.read_u16(); @@ -481,7 +479,7 @@ impl<'de> Decode<'de> for AutoDetectRequest { }) } - _ => Err(invalid_field_err!("requestType", "unknown autodetect request type")), + _ => Err(invalid_field_err!("requestType", "unknown autodetect request type", at: 0)), } } } @@ -636,10 +634,8 @@ impl<'de> Decode<'de> for AutoDetectResponse { let header_type_id = src.read_u8(); if header_type_id != TYPE_ID_AUTODETECT_RESPONSE { - return Err(invalid_field_err!( - "headerTypeId", - "expected TYPE_ID_AUTODETECT_RESPONSE (0x01)" - )); + return Err(invalid_field_err!( "headerTypeId", + "expected TYPE_ID_AUTODETECT_RESPONSE (0x01)", at: 0)); } let sequence_number = src.read_u16(); @@ -671,7 +667,7 @@ impl<'de> Decode<'de> for AutoDetectResponse { }) } - _ => Err(invalid_field_err!("responseType", "unknown autodetect response type")), + _ => Err(invalid_field_err!("responseType", "unknown autodetect response type", at: 0)), } } } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap.rs index a9c0a3a19..9c4791d37 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap.rs @@ -84,10 +84,8 @@ impl<'de> Decode<'de> for Bitmap { let is_bitmap_compress_flag_set = src.read_u16() != 0; if !is_bitmap_compress_flag_set { - return Err(invalid_field_err!( - "isBitmapCompressFlagSet", - "invalid compression flag" - )); + return Err(invalid_field_err!( "isBitmapCompressFlagSet", + "invalid compression flag", at: 0)); } let _high_color_flags = src.read_u8(); diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs index 59687dd4f..410cf8747 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs @@ -271,7 +271,7 @@ impl<'de> Decode<'de> for Codec { GUID_REMOTEFX | GUID_IMAGE_REMOTEFX => { let byte = property_buffer .first() - .ok_or_else(|| invalid_field_err!("remotefx property", "must not be empty"))?; + .ok_or_else(|| invalid_field_err!("remotefx property", "must not be empty", at: 0))?; let property = if *byte == 0 { RemoteFxContainer::ServerContainer(codec_properties_len) } else { @@ -288,14 +288,14 @@ impl<'de> Decode<'de> for Codec { #[cfg(feature = "qoi")] GUID_QOI => { if !property_buffer.is_empty() { - return Err(invalid_field_err!("qoi property", "must be empty")); + return Err(invalid_field_err!("qoi property", "must be empty", at: 0)); } CodecProperty::Qoi } #[cfg(feature = "qoiz")] GUID_QOIZ => { if !property_buffer.is_empty() { - return Err(invalid_field_err!("qoi property", "must be empty")); + return Err(invalid_field_err!("qoi property", "must be empty", at: 0)); } CodecProperty::QoiZ } @@ -478,17 +478,17 @@ impl<'de> Decode<'de> for RfxCaps { let block_type = src.read_u16(); if block_type != RFX_CAPS_BLOCK_TYPE { - return Err(invalid_field_err!("blockType", "invalid rfx caps block type")); + return Err(invalid_field_err!("blockType", "invalid rfx caps block type", at: 0)); } let block_len = src.read_u32(); if block_len != RFX_CAPS_BLOCK_LENGTH { - return Err(invalid_field_err!("blockLen", "invalid rfx caps block length")); + return Err(invalid_field_err!("blockLen", "invalid rfx caps block length", at: 0)); } let num_capsets = src.read_u16(); if num_capsets != RFX_CAPS_NUM_CAPSETS { - return Err(invalid_field_err!("numCapsets", "invalid rfx caps num capsets")); + return Err(invalid_field_err!("numCapsets", "invalid rfx caps num capsets", at: 0)); } let capsets_data = RfxCapset::decode(src)?; @@ -543,19 +543,19 @@ impl<'de> Decode<'de> for RfxCapset { let block_type = src.read_u16(); if block_type != RFX_CAPSET_BLOCK_TYPE { - return Err(invalid_field_err!("blockType", "invalid rfx capset block type")); + return Err(invalid_field_err!("blockType", "invalid rfx capset block type", at: 0)); } let _block_len = src.read_u32(); let codec_id = src.read_u8(); if codec_id != 1 { - return Err(invalid_field_err!("codecId", "invalid rfx codec ID")); + return Err(invalid_field_err!("codecId", "invalid rfx codec ID", at: 0)); } let capset_type = src.read_u16(); if capset_type != RFX_CAPSET_TYPE { - return Err(invalid_field_err!("capsetType", "invalid rfx capset type")); + return Err(invalid_field_err!("capsetType", "invalid rfx capset type", at: 0)); } let num_icaps = src.read_u16(); @@ -612,28 +612,28 @@ impl<'de> Decode<'de> for RfxICap { let version = src.read_u16(); if version != RFX_ICAP_VERSION { - return Err(invalid_field_err!("version", "invalid rfx icap version")); + return Err(invalid_field_err!("version", "invalid rfx icap version", at: 0)); } let tile_size = src.read_u16(); if tile_size != RFX_ICAP_TILE_SIZE { - return Err(invalid_field_err!("tileSize", "invalid rfx icap tile size")); + return Err(invalid_field_err!("tileSize", "invalid rfx icap tile size", at: 0)); } let flags = RfxICapFlags::from_bits_retain(src.read_u8()); let color_conversion = src.read_u8(); if color_conversion != RFX_ICAP_COLOR_CONVERSION { - return Err(invalid_field_err!("colorConv", "invalid rfx color conversion bits")); + return Err(invalid_field_err!("colorConv", "invalid rfx color conversion bits", at: 0)); } let transform_bits = src.read_u8(); if transform_bits != RFX_ICAP_TRANSFORM_BITS { - return Err(invalid_field_err!("transformBits", "invalid rfx transform bits")); + return Err(invalid_field_err!("transformBits", "invalid rfx transform bits", at: 0)); } let entropy_bits = EntropyBits::from_u8(src.read_u8()) - .ok_or_else(|| invalid_field_err!("entropyBits", "invalid rfx entropy bits"))?; + .ok_or_else(|| invalid_field_err!("entropyBits", "invalid rfx entropy bits", at: 0))?; Ok(RfxICap { flags, entropy_bits }) } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs index 8c2ea6919..c8d0db6e4 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs @@ -63,7 +63,7 @@ impl<'de> Decode<'de> for Brush { ensure_fixed_part_size!(in: src); let support_level = SupportLevel::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("supportLevel", "invalid brush support level"))?; + .ok_or_else(|| invalid_field_err!("supportLevel", "invalid brush support level", at: 0))?; Ok(Brush { support_level }) } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs index eb9d548f5..2327a20f4 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs @@ -168,24 +168,24 @@ impl<'de> Decode<'de> for General { let compression_types = src.read_u16(); if compression_types != 0 { - return Err(invalid_field_err!("compressionTypes", "invalid compression types")); + return Err(invalid_field_err!("compressionTypes", "invalid compression types", at: 0)); } let extra_flags = GeneralExtraFlags::from_bits_retain(src.read_u16()); let update_cap_flags = src.read_u16(); if update_cap_flags != 0 { - return Err(invalid_field_err!("updateCapFlags", "invalid update cap flags")); + return Err(invalid_field_err!("updateCapFlags", "invalid update cap flags", at: 0)); } let remote_unshare_flag = src.read_u16(); if remote_unshare_flag != 0 { - return Err(invalid_field_err!("remoteUnshareFlags", "invalid remote unshare flag")); + return Err(invalid_field_err!("remoteUnshareFlags", "invalid remote unshare flag", at: 0)); } let compression_level = src.read_u16(); if compression_level != 0 { - return Err(invalid_field_err!("compressionLevel", "invalid compression level")); + return Err(invalid_field_err!("compressionLevel", "invalid compression level", at: 0)); } let refresh_rect_support = src.read_u8() != 0; diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs index c09dcf0c9..02c576a33 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs @@ -127,7 +127,7 @@ impl<'de> Decode<'de> for GlyphCache { let frag_cache = CacheDefinition::decode(src)?; let glyph_support_level = GlyphSupportLevel::from_u16(src.read_u16()) - .ok_or_else(|| invalid_field_err!("glyphSupport", "invalid glyph support level"))?; + .ok_or_else(|| invalid_field_err!("glyphSupport", "invalid glyph support level", at: 0))?; let _padding = src.read_u16(); Ok(GlyphCache { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs index 555888525..98908ccaf 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs @@ -505,16 +505,14 @@ impl<'de> Decode<'de> for CapabilitySet { let capability_set_type_raw = src.read_u16(); let capability_set_type = CapabilitySetType::from_u16(capability_set_type_raw).ok_or_else(|| { - unsupported_value_err!( - "capabilitySetType", - format!("invalid capability set type: {}", capability_set_type_raw) - ) + unsupported_value_err!( "capabilitySetType", + format!("invalid capability set type: {}", capability_set_type_raw), at: 0) })?; let length = usize::from(src.read_u16()); if length < CAPABILITY_SET_TYPE_FIELD_SIZE + CAPABILITY_SET_LENGTH_FIELD_SIZE { - return Err(invalid_field_err!("len", "invalid capability set length")); + return Err(invalid_field_err!("len", "invalid capability set length", at: 0)); } let buffer_length = length - CAPABILITY_SET_TYPE_FIELD_SIZE - CAPABILITY_SET_LENGTH_FIELD_SIZE; diff --git a/crates/ironrdp-pdu/src/rdp/client_info.rs b/crates/ironrdp-pdu/src/rdp/client_info.rs index da125aa3b..2fd7d01e5 100644 --- a/crates/ironrdp-pdu/src/rdp/client_info.rs +++ b/crates/ironrdp-pdu/src/rdp/client_info.rs @@ -143,9 +143,9 @@ impl<'de> Decode<'de> for ClientInfo { let flags_with_compression_type = src.read_u32(); let flags = ClientInfoFlags::from_bits(flags_with_compression_type & !COMPRESSION_TYPE_MASK) - .ok_or_else(|| invalid_field_err!("flags", "invalid ClientInfoFlags"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid ClientInfoFlags", at: 0))?; let compression_type = CompressionType::from_u32((flags_with_compression_type & COMPRESSION_TYPE_MASK) >> 9) - .ok_or_else(|| invalid_field_err!("flags", "invalid CompressionType"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid CompressionType", at: 0))?; let character_set = if flags.contains(ClientInfoFlags::UNICODE) { CharacterSet::Unicode @@ -375,7 +375,7 @@ impl<'de> Decode<'de> for ExtendedClientOptionalInfo { } optional_data.performance_flags = Some( PerformanceFlags::from_bits(src.read_u32()) - .ok_or_else(|| invalid_field_err!("performanceFlags", "invalid performance flags"))?, + .ok_or_else(|| invalid_field_err!("performanceFlags", "invalid performance flags", at: 0))?, ); if src.len() < 2 { @@ -385,11 +385,11 @@ impl<'de> Decode<'de> for ExtendedClientOptionalInfo { if reconnect_cookie_size != u16::try_from(RECONNECT_COOKIE_LEN).expect("RECONNECT_COOKIE_LEN fit into u16") && reconnect_cookie_size != 0 { - return Err(invalid_field_err!("cbAutoReconnectCookie", "invalid cookie size")); + return Err(invalid_field_err!("cbAutoReconnectCookie", "invalid cookie size", at: 0)); } if reconnect_cookie_size != 0 { if src.len() < RECONNECT_COOKIE_LEN { - return Err(invalid_field_err!("cbAutoReconnectCookie", "missing cookie data")); + return Err(invalid_field_err!("cbAutoReconnectCookie", "missing cookie data", at: 0)); } optional_data.reconnect_cookie = Some(src.read_array()); } diff --git a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs index fee1ae58e..be1abc265 100644 --- a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs @@ -51,7 +51,7 @@ impl<'de> Decode<'de> for SynchronizePdu { let message_type = src.read_u16(); if message_type != SYNCHRONIZE_MESSAGE_TYPE { - return Err(invalid_field_err!("messageType", "invalid message type")); + return Err(invalid_field_err!("messageType", "invalid message type", at: 0)); } let target_user_id = src.read_u16(); @@ -99,7 +99,7 @@ impl<'de> Decode<'de> for ControlPdu { ensure_fixed_part_size!(in: src); let action = ControlAction::from_u16(src.read_u16()) - .ok_or_else(|| invalid_field_err!("action", "invalid control action"))?; + .ok_or_else(|| invalid_field_err!("action", "invalid control action", at: 0))?; let grant_id = src.read_u16(); let control_id = src.read_u32(); @@ -169,7 +169,7 @@ impl<'de> Decode<'de> for FontPdu { let number = src.read_u16(); let total_number = src.read_u16(); let flags = SequenceFlags::from_bits(src.read_u16()) - .ok_or_else(|| invalid_field_err!("flags", "invalid sequence flags"))?; + .ok_or_else(|| invalid_field_err!("flags", "invalid sequence flags", at: 0))?; let entry_size = src.read_u16(); Ok(Self { @@ -221,7 +221,7 @@ impl<'de> Decode<'de> for MonitorLayoutPdu { let monitor_count = src.read_u32(); if monitor_count > MAX_MONITOR_COUNT { - return Err(invalid_field_err!("nMonitors", "invalid monitor count")); + return Err(invalid_field_err!("nMonitors", "invalid monitor count", at: 0)); } let mut monitors = Vec::with_capacity( diff --git a/crates/ironrdp-pdu/src/rdp/headers.rs b/crates/ironrdp-pdu/src/rdp/headers.rs index 2e4557d05..be68ba081 100644 --- a/crates/ironrdp-pdu/src/rdp/headers.rs +++ b/crates/ironrdp-pdu/src/rdp/headers.rs @@ -67,7 +67,7 @@ impl<'de> Decode<'de> for BasicSecurityHeader { ensure_fixed_part_size!(in: src); let flags = BasicSecurityHeaderFlags::from_bits(src.read_u16()) - .ok_or_else(|| invalid_field_err!("securityHeader", "invalid basic security header"))?; + .ok_or_else(|| invalid_field_err!("securityHeader", "invalid basic security header", at: 0))?; let _flags_hi = src.read_u16(); // unused Ok(Self { flags }) @@ -124,10 +124,10 @@ impl<'de> Decode<'de> for ShareControlHeader { let share_id = src.read_u32(); let pdu_type = ShareControlPduType::from_u16(pdu_type_with_version & SHARE_CONTROL_HEADER_MASK) - .ok_or_else(|| invalid_field_err!("pdu_type", "invalid pdu type"))?; + .ok_or_else(|| invalid_field_err!("pdu_type", "invalid pdu type", at: 0))?; let pdu_version = pdu_type_with_version & !SHARE_CONTROL_HEADER_MASK; if pdu_version != PROTOCOL_VERSION { - return Err(invalid_field_err!("pdu_version", "invalid PDU version")); + return Err(invalid_field_err!("pdu_version", "invalid PDU version", at: 0)); } let share_pdu = ShareControlPdu::from_type(src, pdu_type)?; @@ -145,7 +145,7 @@ impl<'de> Decode<'de> for ShareControlHeader { if header_length != total_length { if total_length < header_length { - return Err(not_enough_bytes_err!(total_length, header_length)); + return Err(not_enough_bytes_err!(total_length, header_length, at: 0)); } let padding = total_length - header_length; @@ -200,7 +200,7 @@ impl ShareControlPdu { ShareControlPduType::DeactivateAllPdu => { Ok(ShareControlPdu::ServerDeactivateAll(ServerDeactivateAll::decode(src)?)) } - _ => Err(invalid_field_err!("share_type", "unexpected share control PDU type")), + _ => Err(invalid_field_err!("share_type", "unexpected share control PDU type", at: 0)), } } } @@ -284,17 +284,17 @@ impl<'de> Decode<'de> for ShareDataHeader { read_padding!(src, 1); let stream_priority = StreamPriority::from_u8(src.read_u8()) - .ok_or_else(|| invalid_field_err!("streamPriority", "Invalid stream priority"))?; + .ok_or_else(|| invalid_field_err!("streamPriority", "Invalid stream priority", at: 0))?; let _uncompressed_length = src.read_u16(); let pdu_type = ShareDataPduType::from_u8(src.read_u8()) - .ok_or_else(|| invalid_field_err!("pduType", "Invalid pdu type"))?; + .ok_or_else(|| invalid_field_err!("pduType", "Invalid pdu type", at: 0))?; let compression_flags_with_type = src.read_u8(); let compression_flags = CompressionFlags::from_bits_retain(compression_flags_with_type & !SHARE_DATA_HEADER_COMPRESSION_MASK); let compression_type = client_info::CompressionType::from_u8(compression_flags_with_type & SHARE_DATA_HEADER_COMPRESSION_MASK) - .ok_or_else(|| invalid_field_err!("compressionType", "Invalid compression type"))?; + .ok_or_else(|| invalid_field_err!("compressionType", "Invalid compression type", at: 0))?; let _compressed_length = src.read_u16(); let share_data_pdu = ShareDataPdu::from_type(src, pdu_type)?; diff --git a/crates/ironrdp-pdu/src/rdp/mod.rs b/crates/ironrdp-pdu/src/rdp/mod.rs index 96ff89aed..b2415fbdf 100644 --- a/crates/ironrdp-pdu/src/rdp/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/mod.rs @@ -56,7 +56,7 @@ impl<'de> Decode<'de> for ClientInfoPdu { let security_header = BasicSecurityHeader::decode(src)?; if !security_header.flags.contains(BasicSecurityHeaderFlags::INFO_PKT) { - return Err(invalid_field_err!("securityHeader", "got invalid security header")); + return Err(invalid_field_err!("securityHeader", "got invalid security header", at: 0)); } let client_info = ClientInfo::decode(src)?; diff --git a/crates/ironrdp-pdu/src/rdp/multitransport.rs b/crates/ironrdp-pdu/src/rdp/multitransport.rs index 66fa0df62..1290d826a 100644 --- a/crates/ironrdp-pdu/src/rdp/multitransport.rs +++ b/crates/ironrdp-pdu/src/rdp/multitransport.rs @@ -116,14 +116,14 @@ impl<'de> Decode<'de> for MultitransportRequestPdu { let security_header = BasicSecurityHeader::decode(src)?; if !security_header.flags.contains(BasicSecurityHeaderFlags::TRANSPORT_REQ) { - return Err(invalid_field_err!("securityHeader", "expected TRANSPORT_REQ flag")); + return Err(invalid_field_err!("securityHeader", "expected TRANSPORT_REQ flag", at: 0)); } let request_id = src.read_u32(); let protocol_raw = src.read_u16(); let requested_protocol = RequestedProtocol::from_u16(protocol_raw) - .ok_or_else(|| invalid_field_err!("requestedProtocol", "unknown protocol value"))?; + .ok_or_else(|| invalid_field_err!("requestedProtocol", "unknown protocol value", at: 0))?; read_padding!(src, 2); @@ -230,7 +230,7 @@ impl<'de> Decode<'de> for MultitransportResponsePdu { let security_header = BasicSecurityHeader::decode(src)?; if !security_header.flags.contains(BasicSecurityHeaderFlags::TRANSPORT_RSP) { - return Err(invalid_field_err!("securityHeader", "expected TRANSPORT_RSP flag")); + return Err(invalid_field_err!("securityHeader", "expected TRANSPORT_RSP flag", at: 0)); } let request_id = src.read_u32(); diff --git a/crates/ironrdp-pdu/src/rdp/server_error_info.rs b/crates/ironrdp-pdu/src/rdp/server_error_info.rs index 5aeb1f597..9e90fa365 100644 --- a/crates/ironrdp-pdu/src/rdp/server_error_info.rs +++ b/crates/ironrdp-pdu/src/rdp/server_error_info.rs @@ -37,8 +37,8 @@ impl<'de> Decode<'de> for ServerSetErrorInfoPdu { ensure_fixed_part_size!(in: src); let error_info = src.read_u32(); - let error_info = - ErrorInfo::from_u32(error_info).ok_or_else(|| invalid_field_err!("errorInfo", "unexpected info code"))?; + let error_info = ErrorInfo::from_u32(error_info) + .ok_or_else(|| invalid_field_err!("errorInfo", "unexpected info code", at: 0))?; Ok(Self(error_info)) } diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs index 6434a0f3f..0c209ff33 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs @@ -144,12 +144,12 @@ impl ClientLicenseInfo { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::LicenseInfo { - return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type")); + return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type", at: 0)); } let key_exchange_algorithm = src.read_u32(); if key_exchange_algorithm != KEY_EXCHANGE_ALGORITHM_RSA { - return Err(invalid_field_err!("keyExchangeAlgo", "invalid key exchange algorithm")); + return Err(invalid_field_err!("keyExchangeAlgo", "invalid key exchange algorithm", at: 0)); } // We can ignore platform ID @@ -160,21 +160,21 @@ impl ClientLicenseInfo { let premaster_secret_blob_header = BlobHeader::decode(src)?; if premaster_secret_blob_header.blob_type != BlobType::RANDOM { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: premaster_secret_blob_header.length); let encrypted_premaster_secret = src.read_slice(premaster_secret_blob_header.length).into(); let license_info_blob_header = BlobHeader::decode(src)?; if license_info_blob_header.blob_type != BlobType::DATA { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: license_info_blob_header.length); let license_info = src.read_slice(license_info_blob_header.length).into(); let encrypted_hwid_blob_header = BlobHeader::decode(src)?; if encrypted_hwid_blob_header.blob_type != BlobType::DATA { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: encrypted_hwid_blob_header.length); let encrypted_hwid = src.read_slice(encrypted_hwid_blob_header.length).into(); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs index f1fbaf17d..66cbdc71c 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs @@ -161,13 +161,13 @@ impl ClientNewLicenseRequest { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::NewLicenseRequest { - return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type")); + return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type", at: 0)); } ensure_size!(in: src, size: LICENSE_REQUEST_STATIC_FIELDS_SIZE + RANDOM_NUMBER_SIZE); let key_exchange_algorithm = src.read_u32(); if key_exchange_algorithm != KEY_EXCHANGE_ALGORITHM_RSA { - return Err(invalid_field_err!("keyExchangeAlgo", "invalid key exchange algorithm")); + return Err(invalid_field_err!("keyExchangeAlgo", "invalid key exchange algorithm", at: 0)); } let _platform_id = src.read_u32(); @@ -175,14 +175,14 @@ impl ClientNewLicenseRequest { let premaster_secret_blob_header = BlobHeader::decode(src)?; if premaster_secret_blob_header.blob_type != BlobType::RANDOM { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: premaster_secret_blob_header.length); let encrypted_premaster_secret = src.read_slice(premaster_secret_blob_header.length).into(); let username_blob_header = BlobHeader::decode(src)?; if username_blob_header.blob_type != BlobType::CLIENT_USER_NAME { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: username_blob_header.length); let client_username = @@ -190,7 +190,7 @@ impl ClientNewLicenseRequest { let machine_name_blob = BlobHeader::decode(src)?; if machine_name_blob.blob_type != BlobType::CLIENT_MACHINE_NAME_BLOB { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: machine_name_blob.length); let client_machine_name = diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs index abd1a8773..fa2ddc310 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs @@ -122,22 +122,20 @@ impl ClientPlatformChallengeResponse { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::PlatformChallengeResponse { - return Err(invalid_field_err!( - "preambleMessageType", - "unexpected preamble message type" - )); + return Err(invalid_field_err!( "preambleMessageType", + "unexpected preamble message type", at: 0)); } let encrypted_challenge_blob = BlobHeader::decode(src)?; if encrypted_challenge_blob.blob_type != BlobType::ENCRYPTED_DATA { - return Err(invalid_field_err!("blobType", "unexpected blob type")); + return Err(invalid_field_err!("blobType", "unexpected blob type", at: 0)); } ensure_size!(in: src, size: encrypted_challenge_blob.length); let encrypted_challenge_response_data = src.read_slice(encrypted_challenge_blob.length).into(); let encrypted_hwid_blob = BlobHeader::decode(src)?; if encrypted_hwid_blob.blob_type != BlobType::ENCRYPTED_DATA { - return Err(invalid_field_err!("blobType", "unexpected blob type")); + return Err(invalid_field_err!("blobType", "unexpected blob type", at: 0)); } ensure_size!(in: src, size: encrypted_hwid_blob.length); let encrypted_hwid = src.read_slice(encrypted_hwid_blob.length).into(); @@ -245,14 +243,14 @@ impl<'de> Decode<'de> for PlatformChallengeResponseData { let version = src.read_u16(); if version != RESPONSE_DATA_VERSION { - return Err(invalid_field_err!("version", "invalid challenge response version")); + return Err(invalid_field_err!("version", "invalid challenge response version", at: 0)); } let client_type = ClientType::from_u16(src.read_u16()) - .ok_or_else(|| invalid_field_err!("clientType", "invalid client type"))?; + .ok_or_else(|| invalid_field_err!("clientType", "invalid client type", at: 0))?; let license_detail_level = LicenseDetailLevel::from_u16(src.read_u16()) - .ok_or_else(|| invalid_field_err!("licenseDetailLevel", "invalid license detail level"))?; + .ok_or_else(|| invalid_field_err!("licenseDetailLevel", "invalid license detail level", at: 0))?; let challenge_len: usize = cast_length!("len", src.read_u16())?; ensure_size!(in: src, size: challenge_len); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs index ffacf42fe..be9951046 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs @@ -71,18 +71,18 @@ impl LicensingErrorMessage { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::ErrorAlert { - return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type")); + return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type", at: 0)); } ensure_fixed_part_size!(in: src); let error_code = LicenseErrorCode::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("errorCode", "invalid error code"))?; + .ok_or_else(|| invalid_field_err!("errorCode", "invalid error code", at: 0))?; let state_transition = LicensingStateTransition::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("stateTransition", "invalid state transition"))?; + .ok_or_else(|| invalid_field_err!("stateTransition", "invalid state transition", at: 0))?; let error_info_blob = BlobHeader::decode(src)?; if error_info_blob.length != 0 && error_info_blob.blob_type != BlobType::ERROR { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } let error_info = vec![0u8; error_info_blob.length]; diff --git a/crates/ironrdp-pdu/src/rdp/server_license/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/mod.rs index 9d2fbec6a..a29b7854e 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/mod.rs @@ -105,23 +105,21 @@ impl<'de> Decode<'de> for LicenseHeader { let security_header = BasicSecurityHeader::decode(src)?; if !security_header.flags.contains(BasicSecurityHeaderFlags::LICENSE_PKT) { - return Err(invalid_field_err!( - "securityHeaderFlags", - "invalid security header flags" - )); + return Err(invalid_field_err!( "securityHeaderFlags", + "invalid security header flags", at: 0)); } let preamble_message_type = PreambleType::from_u8(src.read_u8()) - .ok_or_else(|| invalid_field_err!("preambleType", "invalid license type"))?; + .ok_or_else(|| invalid_field_err!("preambleType", "invalid license type", at: 0))?; let flags_with_version = src.read_u8(); let preamble_message_size = src.read_u16(); let preamble_flags = PreambleFlags::from_bits(flags_with_version & !PROTOCOL_VERSION_MASK) - .ok_or_else(|| invalid_field_err!("preambleFlags", "Got invalid flags field"))?; + .ok_or_else(|| invalid_field_err!("preambleFlags", "Got invalid flags field", at: 0))?; let preamble_version = PreambleVersion::from_u8(flags_with_version & PROTOCOL_VERSION_MASK) - .ok_or_else(|| invalid_field_err!("preambleVersion", "Got invalid version in the flags filed"))?; + .ok_or_else(|| invalid_field_err!("preambleVersion", "Got invalid version in the flags filed", at: 0))?; Ok(Self { security_header, @@ -482,10 +480,8 @@ impl<'de> Decode<'de> for LicensePdu { PreambleType::NewLicense | PreambleType::UpgradeLicense => { Ok(ServerUpgradeLicense::decode(license_header, src)?.into()) } - PreambleType::LicenseInfo => Err(unsupported_value_err!( - "LicensePdu::LicenseInfo", - "LicenseInfo is not supported".to_owned() - )), + PreambleType::LicenseInfo => Err(unsupported_value_err!( "LicensePdu::LicenseInfo", + "LicenseInfo is not supported".to_owned(), at: 0)), PreambleType::NewLicenseRequest => Ok(ClientNewLicenseRequest::decode(license_header, src)?.into()), PreambleType::PlatformChallengeResponse => { Ok(ClientPlatformChallengeResponse::decode(license_header, src)?.into()) diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/cert.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/cert.rs index 8f2a37275..f77ba1855 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/cert.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/cert.rs @@ -75,14 +75,14 @@ impl<'de> Decode<'de> for X509CertificateChain { ensure_size!(in: src, size: 4); let certificate_count = cast_length!("certArrayLen", src.read_u32())?; if !(MIN_CERTIFICATE_AMOUNT..MAX_CERTIFICATE_AMOUNT).contains(&certificate_count) { - return Err(invalid_field_err!("certArrayLen", "invalid x509 certificate amount")); + return Err(invalid_field_err!("certArrayLen", "invalid x509 certificate amount", at: 0)); } let certificate_array: Vec<_> = core::iter::repeat_with(|| { ensure_size!(in: src, size: 4); let certificate_len = cast_length!("certLen", src.read_u32())?; if certificate_len > MAX_CERTIFICATE_LEN { - return Err(invalid_field_err!("certLen", "invalid x509 certificate length")); + return Err(invalid_field_err!("certLen", "invalid x509 certificate length", at: 0)); } ensure_size!(in: src, size: certificate_len); @@ -148,23 +148,23 @@ impl<'de> Decode<'de> for ProprietaryCertificate { let signature_algorithm_id = src.read_u32(); if signature_algorithm_id != SIGNATURE_ALGORITHM_RSA { - return Err(invalid_field_err!("sigAlgId", "invalid signature algorithm ID")); + return Err(invalid_field_err!("sigAlgId", "invalid signature algorithm ID", at: 0)); } let key_algorithm_id = src.read_u32(); if key_algorithm_id != KEY_EXCHANGE_ALGORITHM_RSA { - return Err(invalid_field_err!("keyAlgId", "invalid key algorithm ID")); + return Err(invalid_field_err!("keyAlgId", "invalid key algorithm ID", at: 0)); } let key_blob_header = BlobHeader::decode(src)?; if key_blob_header.blob_type != BlobType::RSA_KEY { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } let public_key = RsaPublicKey::decode(src)?; let sig_blob_header = BlobHeader::decode(src)?; if sig_blob_header.blob_type != BlobType::RSA_SIGNATURE { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: sig_blob_header.length); let signature = src.read_slice(sig_blob_header.length).into(); @@ -219,23 +219,23 @@ impl<'de> Decode<'de> for RsaPublicKey { let magic = src.read_u32(); if magic != RSA_SENTINEL { - return Err(invalid_field_err!("magic", "invalid RSA public key magic")); + return Err(invalid_field_err!("magic", "invalid RSA public key magic", at: 0)); } let keylen = cast_length!("keyLen", src.read_u32())?; let bitlen: usize = cast_length!("bitlen", src.read_u32())?; if keylen != (bitlen / 8) + 8 { - return Err(invalid_field_err!("bitlen", "invalid RSA public key length")); + return Err(invalid_field_err!("bitlen", "invalid RSA public key length", at: 0)); } if bitlen < 8 { - return Err(invalid_field_err!("bitlen", "invalid RSA public key length")); + return Err(invalid_field_err!("bitlen", "invalid RSA public key length", at: 0)); } let datalen: usize = cast_length!("dataLen", src.read_u32())?; if datalen != (bitlen / 8) - 1 { - return Err(invalid_field_err!("dataLen", "invalid RSA public key data length")); + return Err(invalid_field_err!("dataLen", "invalid RSA public key data length", at: 0)); } let public_exponent = src.read_u32(); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs index 86e5e7328..728d819ab 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs @@ -72,7 +72,7 @@ impl ServerLicenseRequest { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::LicenseRequest { - return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type")); + return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type", at: 0)); } ensure_size!(in: src, size: RANDOM_NUMBER_SIZE); @@ -82,18 +82,18 @@ impl ServerLicenseRequest { let key_exchange_algorithm_blob = BlobHeader::decode(src)?; if key_exchange_algorithm_blob.blob_type != BlobType::KEY_EXCHANGE_ALGORITHM { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } ensure_size!(in: src, size: 4); let key_exchange_algorithm = src.read_u32(); if key_exchange_algorithm != RSA_EXCHANGE_ALGORITHM { - return Err(invalid_field_err!("keyAlgo", "invalid key exchange algorithm")); + return Err(invalid_field_err!("keyAlgo", "invalid key exchange algorithm", at: 0)); } let cert_blob = BlobHeader::decode(src)?; if cert_blob.blob_type != BlobType::CERTIFICATE { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } // The terminal server can choose not to send the certificate by setting the wblobLen field in the Licensing Binary BLOB structure to 0 @@ -106,7 +106,7 @@ impl ServerLicenseRequest { ensure_size!(in: src, size: 4); let scope_count = src.read_u32(); if scope_count > MAX_SCOPE_COUNT { - return Err(invalid_field_err!("scopeCount", "invalid scope count")); + return Err(invalid_field_err!("scopeCount", "invalid scope count", at: 0)); } let mut scope_list = Vec::with_capacity( @@ -183,10 +183,10 @@ impl<'de> Decode<'de> for Scope { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { let blob_header = BlobHeader::decode(src)?; if blob_header.blob_type != BlobType::SCOPE { - return Err(invalid_field_err!("blobType", "invalid blob type")); + return Err(invalid_field_err!("blobType", "invalid blob type", at: 0)); } if blob_header.length < UTF8_NULL_TERMINATOR_SIZE { - return Err(invalid_field_err!("blobLen", "blob too small")); + return Err(invalid_field_err!("blobLen", "blob too small", at: 0)); } ensure_size!(in: src, size: blob_header.length); let mut blob_data = src.read_slice(blob_header.length).to_vec(); @@ -195,7 +195,7 @@ impl<'de> Decode<'de> for Scope { if let Ok(data) = core::str::from_utf8(&blob_data) { Ok(Self(String::from(data))) } else { - Err(invalid_field_err!("scope", "scope is not utf8")) + Err(invalid_field_err!("scope", "scope is not utf8", at: 0)) } } } @@ -306,7 +306,7 @@ impl<'de> Decode<'de> for ServerCertificate { let certificate = match cert_version & CERT_CHAIN_VERSION_MASK { 1 => CertificateType::Proprietary(ProprietaryCertificate::decode(src)?), 2 => CertificateType::X509(X509CertificateChain::decode(src)?), - _ => return Err(invalid_field_err!("certVersion", "invalid certificate version")), + _ => return Err(invalid_field_err!("certVersion", "invalid certificate version", at: 0)), }; Ok(Self { @@ -375,7 +375,7 @@ impl<'de> Decode<'de> for ProductInfo { let company_name_len = cast_length!("companyLen", src.read_u32())?; if !(2..=MAX_COMPANY_NAME_LEN).contains(&company_name_len) { - return Err(invalid_field_err!("companyLen", "invalid company name length")); + return Err(invalid_field_err!("companyLen", "invalid company name length", at: 0)); } ensure_size!(in: src, size: company_name_len); @@ -386,7 +386,7 @@ impl<'de> Decode<'de> for ProductInfo { ensure_size!(in: src, size: 4); let product_id_len = cast_length!("productIdLen", src.read_u32())?; if !(2..=MAX_PRODUCT_ID_LEN).contains(&product_id_len) { - return Err(invalid_field_err!("productIdLen", "invalid produce ID length")); + return Err(invalid_field_err!("productIdLen", "invalid produce ID length", at: 0)); } ensure_size!(in: src, size: product_id_len); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs index 007395906..9d9f89689 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs @@ -39,7 +39,7 @@ impl ServerPlatformChallenge { pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult { if license_header.preamble_message_type != PreambleType::PlatformChallenge { - return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type")); + return Err(invalid_field_err!("preambleMessageType", "unexpected preamble type", at: 0)); } ensure_size!(in: src, size: 4); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs index bc1b4f351..f563bed34 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs @@ -45,15 +45,13 @@ impl ServerUpgradeLicense { if license_header.preamble_message_type != PreambleType::UpgradeLicense && license_header.preamble_message_type != PreambleType::NewLicense { - return Err(invalid_field_err!( - "preambleType", - "got unexpected message preamble type" - )); + return Err(invalid_field_err!( "preambleType", + "got unexpected message preamble type", at: 0)); } let encrypted_license_info_blob = BlobHeader::decode(src)?; if encrypted_license_info_blob.blob_type != BlobType::ENCRYPTED_DATA { - return Err(invalid_field_err!("blobType", "unexpected blob type")); + return Err(invalid_field_err!("blobType", "unexpected blob type", at: 0)); } ensure_size!(in: src, size: encrypted_license_info_blob.length + MAC_SIZE); diff --git a/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs b/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs index b9a266de8..daec7be70 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs @@ -140,12 +140,12 @@ impl<'de> Decode<'de> for ServerAutoReconnect { let packet_length = src.read_u32(); if packet_length != u32::try_from(AUTO_RECONNECT_PACKET_SIZE).expect("AUTO_RECONNECT_PACKET_SIZE fits into u32") { - return Err(invalid_field_err!("packetLen", "invalid auto-reconnect packet size")); + return Err(invalid_field_err!("packetLen", "invalid auto-reconnect packet size", at: 0)); } let version = src.read_u32(); if version != AUTO_RECONNECT_VERSION_1 { - return Err(invalid_field_err!("version", "invalid auto-reconnect version")); + return Err(invalid_field_err!("version", "invalid auto-reconnect version", at: 0)); } let logon_id = src.read_u32(); @@ -197,7 +197,7 @@ impl<'de> Decode<'de> for LogonErrorsInfo { let _data_length = src.read_u32(); let error_type = LogonErrorNotificationType::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("errorType", "invalid logon error type"))?; + .ok_or_else(|| invalid_field_err!("errorType", "invalid logon error type", at: 0))?; let error_notification_data = src.read_u32(); let error_data = LogonErrorNotificationDataErrorCode::from_u32(error_notification_data) diff --git a/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs b/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs index b93109d54..109d1e353 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs @@ -71,7 +71,7 @@ impl<'de> Decode<'de> for LogonInfoVersion1 { let domain_name_size: usize = cast_length!("domainNameSize", src.read_u32())?; if domain_name_size > DOMAIN_NAME_SIZE_V1 { - return Err(invalid_field_err!("domainNameSize", "invalid domain name size")); + return Err(invalid_field_err!("domainNameSize", "invalid domain name size", at: 0)); } let domain_name = @@ -79,7 +79,7 @@ impl<'de> Decode<'de> for LogonInfoVersion1 { let user_name_size: usize = cast_length!("userNameSize", src.read_u32())?; if user_name_size > USER_NAME_SIZE_V1 { - return Err(invalid_field_err!("userNameSize", "invalid user name size")); + return Err(invalid_field_err!("userNameSize", "invalid user name size", at: 0)); } let user_name = utils::decode_string(src.read_slice(USER_NAME_SIZE_V1), utils::CharacterSet::Unicode, false)?; @@ -153,23 +153,23 @@ impl<'de> Decode<'de> for LogonInfoVersion2 { let version = src.read_u16(); if version != SAVE_SESSION_PDU_VERSION_ONE { - return Err(invalid_field_err!("version", "invalid logon version 2")); + return Err(invalid_field_err!("version", "invalid logon version 2", at: 0)); } let size: usize = cast_length!("LogonInfoSize", src.read_u32())?; if size != LOGON_INFO_V2_SIZE { - return Err(invalid_field_err!("domainNameSize", "invalid logon info size")); + return Err(invalid_field_err!("domainNameSize", "invalid logon info size", at: 0)); } let session_id = src.read_u32(); let domain_name_size: usize = cast_length!("domainNameSize", src.read_u32())?; if domain_name_size > DOMAIN_NAME_SIZE_V2 { - return Err(invalid_field_err!("domainNameSize", "invalid domain name size")); + return Err(invalid_field_err!("domainNameSize", "invalid domain name size", at: 0)); } let user_name_size: usize = cast_length!("userNameSize", src.read_u32())?; if user_name_size > USER_NAME_SIZE_V2 { - return Err(invalid_field_err!("userNameSize", "invalid user name size")); + return Err(invalid_field_err!("userNameSize", "invalid user name size", at: 0)); } read_padding!(src, LOGON_INFO_V2_PADDING_SIZE); diff --git a/crates/ironrdp-pdu/src/rdp/session_info/mod.rs b/crates/ironrdp-pdu/src/rdp/session_info/mod.rs index 9dcc2573a..bdf8fa56e 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/mod.rs @@ -78,7 +78,7 @@ impl<'de> Decode<'de> for SaveSessionInfoPdu { ensure_fixed_part_size!(in: src); let info_type = InfoType::from_u32(src.read_u32()) - .ok_or_else(|| invalid_field_err!("infoType", "invalid save session info type"))?; + .ok_or_else(|| invalid_field_err!("infoType", "invalid save session info type", at: 0))?; let info_data = match info_type { InfoType::Logon => InfoData::LogonInfoV1(LogonInfoVersion1::decode(src)?), diff --git a/crates/ironrdp-pdu/src/rdp/suppress_output.rs b/crates/ironrdp-pdu/src/rdp/suppress_output.rs index 468876794..b5d5728fa 100644 --- a/crates/ironrdp-pdu/src/rdp/suppress_output.rs +++ b/crates/ironrdp-pdu/src/rdp/suppress_output.rs @@ -86,7 +86,7 @@ impl<'de> Decode<'de> for SuppressOutputPdu { ensure_fixed_part_size!(in: src); let allow_display_updates = AllowDisplayUpdatesType::from_u8(src.read_u8()) - .ok_or_else(|| invalid_field_err!("allowDisplayUpdates", "invalid display update type"))?; + .ok_or_else(|| invalid_field_err!("allowDisplayUpdates", "invalid display update type", at: 0))?; read_padding!(src, 3); let desktop_rect = if allow_display_updates == AllowDisplayUpdatesType::AllowDisplayUpdates { Some(InclusiveRectangle::decode(src)?) diff --git a/crates/ironrdp-pdu/src/tpdu.rs b/crates/ironrdp-pdu/src/tpdu.rs index d140ce708..bf3296c7b 100644 --- a/crates/ironrdp-pdu/src/tpdu.rs +++ b/crates/ironrdp-pdu/src/tpdu.rs @@ -29,7 +29,7 @@ impl TpduCode { if self == expected { Ok(()) } else { - Err(unexpected_message_type_err!(TpduHeader::NAME, self.0)) + Err(unexpected_message_type_err!(TpduHeader::NAME, self.0, at: 0)) } } } @@ -127,6 +127,7 @@ impl TpduHeader { Self::NAME, "li", "tpdu length greater than tpkt length", + 0, )); } @@ -136,6 +137,7 @@ impl TpduHeader { Self::NAME, "li", "unsupported X.224 extension (suggested by LI field set to 255)", + 0, )); } diff --git a/crates/ironrdp-pdu/src/tpkt.rs b/crates/ironrdp-pdu/src/tpkt.rs index 2665dc776..bd07c4dbe 100644 --- a/crates/ironrdp-pdu/src/tpkt.rs +++ b/crates/ironrdp-pdu/src/tpkt.rs @@ -56,7 +56,7 @@ impl TpktHeader { let version = src.read_u8(); if version != Self::VERSION { - return Err(unsupported_version_err!("TPKT version", version)); + return Err(unsupported_version_err!("TPKT version", version, at: 0)); } read_padding!(src, 1); diff --git a/crates/ironrdp-pdu/src/utils.rs b/crates/ironrdp-pdu/src/utils.rs index 397f2e085..232ddb64c 100644 --- a/crates/ironrdp-pdu/src/utils.rs +++ b/crates/ironrdp-pdu/src/utils.rs @@ -117,13 +117,13 @@ pub fn read_string_from_cursor( .expect("BUG: str_buffer is always even for UTF16"); String::from_utf16(&u16_buffer) - .map_err(|_| invalid_field_err!("UTF16 decode", "buffer", "Failed to decode UTF16 string"))? + .map_err(|_| invalid_field_err!("UTF16 decode", "buffer", "Failed to decode UTF16 string", at: 0))? } CharacterSet::Ansi => { ensure_size!(ctx: "Decode string (UTF-8)", in: cursor, size: size); let slice = cursor.read_slice(size); String::from_utf8(slice.to_vec()) - .map_err(|_| invalid_field_err!("UTF8 decode", "buffer", "Failed to decode UTF8 string"))? + .map_err(|_| invalid_field_err!("UTF8 decode", "buffer", "Failed to decode UTF8 string", at: 0))? } }; diff --git a/crates/ironrdp-pdu/src/x224.rs b/crates/ironrdp-pdu/src/x224.rs index 6372ca6d4..7a31997d4 100644 --- a/crates/ironrdp-pdu/src/x224.rs +++ b/crates/ironrdp-pdu/src/x224.rs @@ -86,6 +86,7 @@ where "TpduHeader", "li", "fixed part bigger than total header size", + 0, )); } diff --git a/crates/ironrdp-rdpdr/src/pdu/efs.rs b/crates/ironrdp-rdpdr/src/pdu/efs.rs index 5d6094f51..a205d0723 100644 --- a/crates/ironrdp-rdpdr/src/pdu/efs.rs +++ b/crates/ironrdp-rdpdr/src/pdu/efs.rs @@ -60,11 +60,9 @@ impl VersionAndIdPdu { pub fn new_client_announce_reply(req: VersionAndIdPdu) -> DecodeResult { if req.kind != VersionAndIdPduKind::ServerAnnounceRequest { - return Err(invalid_field_err!( - "VersionAndIdPdu::new_client_announce_reply", + return Err(invalid_field_err!( "VersionAndIdPdu::new_client_announce_reply", "VersionAndIdPduKind", - "invalid value" - )); + "invalid value", at: 0)); } Ok(Self { @@ -88,11 +86,9 @@ impl VersionAndIdPdu { PacketId::CoreServerAnnounce => VersionAndIdPduKind::ServerAnnounceRequest, PacketId::CoreClientidConfirm => VersionAndIdPduKind::ServerClientIdConfirm, _ => { - return Err(invalid_field_err!( - "VersionAndIdPdu::decode", + return Err(invalid_field_err!( "VersionAndIdPdu::decode", "PacketId", - "invalid value" - )); + "invalid value", at: 0)); } }; @@ -244,11 +240,9 @@ impl CoreCapability { PacketId::CoreServerCapability => CoreCapabilityKind::ServerCoreCapabilityRequest, PacketId::CoreClientCapability => CoreCapabilityKind::ClientCoreCapabilityResponse, _ => { - return Err(invalid_field_err!( - "CoreCapability::decode", + return Err(invalid_field_err!( "CoreCapability::decode", "PacketId", - "invalid value" - )); + "invalid value", at: 0)); } }; @@ -607,7 +601,7 @@ impl TryFrom for CapabilityType { 0x0003 => Ok(CapabilityType::Port), 0x0004 => Ok(CapabilityType::Drive), 0x0005 => Ok(CapabilityType::Smartcard), - _ => Err(invalid_field_err!("try_from", "CapabilityType", "invalid value")), + _ => Err(invalid_field_err!("try_from", "CapabilityType", "invalid value", at: 0)), } } } @@ -971,11 +965,9 @@ impl Devices { if let Some(device_type) = self.0.iter().find(|d| d.device_id == device_id).map(|d| d.device_type) { Ok(device_type) } else { - Err(invalid_field_err!( - "Devices::for_device_type", + Err(invalid_field_err!( "Devices::for_device_type", "device_id", - "no device with that ID" - )) + "no device with that ID", at: 0)) } } @@ -1259,7 +1251,7 @@ impl TryFrom for DeviceType { 0x0000_0004 => Ok(DeviceType::Print), 0x0000_0008 => Ok(DeviceType::Filesystem), 0x0000_0020 => Ok(DeviceType::Smartcard), - _ => Err(invalid_field_err!("try_from", "DeviceType", "invalid value")), + _ => Err(invalid_field_err!("try_from", "DeviceType", "invalid value", at: 0)), } } } @@ -1459,7 +1451,7 @@ impl TryFrom for MajorFunction { 0x0000_0006 => Ok(MajorFunction::SetInformation), 0x0000_000c => Ok(MajorFunction::DirectoryControl), 0x0000_0011 => Ok(MajorFunction::LockControl), - _ => Err(invalid_field_err!("try_from", "MajorFunction", "unsupported value")), + _ => Err(invalid_field_err!("try_from", "MajorFunction", "unsupported value", at: 0)), } } } @@ -1537,7 +1529,7 @@ where let input_buffer_length = src.read_u32(); let io_control_code = T::try_from(src.read_u32()).map_err(|e| { error!("Failed to parse IoCtlCode"); - invalid_field_err_with_source("DeviceControlRequest", "IoCtlCode", "invalid IoCtlCode", e) + invalid_field_err_with_source("DeviceControlRequest", "IoCtlCode", "invalid IoCtlCode", 0, e) })?; // Padding (20 bytes): An array of 20 bytes. Reserved. This field can be set to any value and MUST be ignored. @@ -1713,11 +1705,9 @@ impl ServerDriveIoRequest { MajorFunction::QueryVolumeInformation => { Ok(ServerDriveQueryVolumeInformationRequest::decode(dev_io_req, src)?.into()) } - MajorFunction::SetVolumeInformation => Err(unsupported_value_err!( - "ServerDriveIoRequest::decode", + MajorFunction::SetVolumeInformation => Err(unsupported_value_err!( "ServerDriveIoRequest::decode", "MajorFunction", - "SetVolumeInformation".to_owned() - )), // FreeRDP doesn't implement this + "SetVolumeInformation".to_owned(), at: 0)), // FreeRDP doesn't implement this MajorFunction::QueryInformation => Ok(ServerDriveQueryInformationRequest::decode(dev_io_req, src)?.into()), MajorFunction::SetInformation => Ok(ServerDriveSetInformationRequest::decode(dev_io_req, src)?.into()), MajorFunction::DirectoryControl => match dev_io_req.minor_function { @@ -1728,11 +1718,9 @@ impl ServerDriveIoRequest { Ok(ServerDriveNotifyChangeDirectoryRequest::decode(dev_io_req, src)?.into()) } // If MajorFunction is set to IRP_MJ_DIRECTORY_CONTROL and MinorFunction is set to any other value, we've encountered a server bug. - _ => Err(invalid_field_err!( - "ServerDriveIoRequest::decode", + _ => Err(invalid_field_err!( "ServerDriveIoRequest::decode", "MinorFunction", - "invalid value" - )), + "invalid value", at: 0)), }, MajorFunction::LockControl => Ok(ServerDriveLockControlRequest::decode(dev_io_req, src)?.into()), } @@ -1831,11 +1819,9 @@ impl PrinterIoRequest { MajorFunction::Create => Ok(Self::Create(DeviceCreateRequest::decode(dev_io_req, src)?)), MajorFunction::Write => Ok(Self::Write(DeviceWriteRequest::decode(dev_io_req, src)?)), MajorFunction::Close => Ok(Self::Close(DeviceCloseRequest::decode(dev_io_req))), - _ => Err(invalid_field_err!( - "PrinterIoRequest::decode", + _ => Err(invalid_field_err!( "PrinterIoRequest::decode", "MajorFunction", - "unsupported value" - )), + "unsupported value", at: 0)), } } @@ -2301,11 +2287,9 @@ impl FileInformationClass { Self::FullDirectory(f) => f.encode(dst), Self::Names(f) => f.encode(dst), Self::Directory(f) => f.encode(dst), - _ => Err(unsupported_value_err!( - "FileInformationClass::encode", + _ => Err(unsupported_value_err!( "FileInformationClass::encode", "FileInformationClass", - self.to_string() - )), + self.to_string(), at: 0)), } } @@ -2326,11 +2310,9 @@ impl FileInformationClass { FileInformationClassLevel::FILE_ALLOCATION_INFORMATION => { Ok(FileAllocationInformation::decode(src)?.into()) } - _ => Err(unsupported_value_err!( - "FileInformationClass::decode", + _ => Err(unsupported_value_err!( "FileInformationClass::decode", "FileInformationClassLevel", - file_info_class_level.to_string() - )), + file_info_class_level.to_string(), at: 0)), } } @@ -2940,11 +2922,9 @@ impl ServerDriveQueryDirectoryRequest { | FileInformationClassLevel::FILE_BOTH_DIRECTORY_INFORMATION | FileInformationClassLevel::FILE_NAMES_INFORMATION => {} _ => { - return Err(invalid_field_err!( - "ServerDriveQueryDirectoryRequest::decode", + return Err(invalid_field_err!( "ServerDriveQueryDirectoryRequest::decode", "file_info_class_lvl", - "received invalid level" - )); + "received invalid level", at: 0)); } } @@ -3064,11 +3044,9 @@ impl ServerDriveQueryVolumeInformationRequest { | FileSystemInformationClassLevel::FILE_FS_FULL_SIZE_INFORMATION | FileSystemInformationClassLevel::FILE_FS_DEVICE_INFORMATION => {} _ => { - return Err(invalid_field_err!( - "ServerDriveQueryVolumeInformationRequest::decode", - "fs_info_class_lvl", - "received invalid level" - )); + return Err(invalid_field_err!( "ServerDriveQueryVolumeInformationRequest::decode", + "fs_info_class_lvl", + "received invalid level", at: 0)); } } @@ -3615,11 +3593,9 @@ impl ServerDriveSetInformationRequest { | FileInformationClassLevel::FILE_RENAME_INFORMATION | FileInformationClassLevel::FILE_ALLOCATION_INFORMATION => {} _ => { - return Err(invalid_field_err!( - "ServerDriveSetInformationRequest::decode", + return Err(invalid_field_err!( "ServerDriveSetInformationRequest::decode", "file_information_class_level", - "received invalid level" - )); + "received invalid level", at: 0)); } }; diff --git a/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs b/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs index bfe19fa51..f7f53ea64 100644 --- a/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs +++ b/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs @@ -160,10 +160,8 @@ impl ndr::Decode for ScardContext { let length = src.read_u32(); if length != Self::VALUE_LENGTH { error!(?length, "Unsupported value length in ScardContext"); - return Err(invalid_field_err!( - "decode_ptr", - "unsupported value length in ScardContext" - )); + return Err(invalid_field_err!( "decode_ptr", + "unsupported value length in ScardContext", at: 0)); } let _ptr = ndr::decode_ptr(src, index)?; @@ -176,10 +174,8 @@ impl ndr::Decode for ScardContext { let length = src.read_u32(); if length != Self::VALUE_LENGTH { error!(?length, "Unsupported value length in ScardContext"); - return Err(invalid_field_err!( - "decode_value", - "unsupported value length in ScardContext" - )); + return Err(invalid_field_err!( "decode_value", + "unsupported value length in ScardContext", at: 0)); } self.value = src.read_u32(); Ok(()) @@ -371,7 +367,7 @@ impl TryFrom for ScardIoCtlCode { 0x0009_0108 => Ok(ScardIoCtlCode::GetDeviceTypeId), _ => { error!("Unsupported ScardIoCtlCode: 0x{:08x}", value); - Err(invalid_field_err!("try_from", "ScardIoCtlCode", "unsupported value")) + Err(invalid_field_err!("try_from", "ScardIoCtlCode", "unsupported value", at: 0)) } } } @@ -634,7 +630,7 @@ impl TryFrom for Scope { 0x0000_0002 => Ok(Scope::System), _ => { error!("Unsupported Scope: 0x{:08x}", value); - Err(invalid_field_err!("try_from", "Scope", "unsupported value")) + Err(invalid_field_err!("try_from", "Scope", "unsupported value", at: 0)) } } } @@ -728,10 +724,8 @@ impl rpce::HeaderlessDecode for ListReadersCall { ensure_size!(in: src, size: size_of::()); let groups_length = src.read_u32(); if groups_length != groups_ptr_length { - return Err(invalid_field_err!( - "decode", - "mismatched reader groups length in NDR pointer and value" - )); + return Err(invalid_field_err!( "decode", + "mismatched reader groups length in NDR pointer and value", at: 0)); } let groups = read_multistring_from_cursor(src, charset)?; @@ -1063,10 +1057,8 @@ impl ndr::Decode for ScardHandle { let length = src.read_u32(); if length != Self::VALUE_LENGTH { error!(?length, "Unsupported value length in ScardHandle"); - return Err(invalid_field_err!( - "decode_ptr", - "unsupported value length in ScardHandle" - )); + return Err(invalid_field_err!( "decode_ptr", + "unsupported value length in ScardHandle", at: 0)); } let _ptr = ndr::decode_ptr(src, index)?; Ok(Self { context, value: 0 }) @@ -1079,10 +1071,8 @@ impl ndr::Decode for ScardHandle { let length = src.read_u32(); if length != Self::VALUE_LENGTH { error!(?length, "Unsupported value length in ScardHandle"); - return Err(invalid_field_err!( - "decode_value", - "unsupported value length in ScardHandle" - )); + return Err(invalid_field_err!( "decode_value", + "unsupported value length in ScardHandle", at: 0)); } ensure_size!(in: src, size: size_of::()); self.value = src.read_u32(); diff --git a/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs b/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs index 14bda22ea..f1df021a9 100644 --- a/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs +++ b/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs @@ -62,7 +62,7 @@ pub fn decode_ptr(src: &mut ReadCursor<'_>, index: &mut u32) -> DecodeResult for Endianness { match value { 0x00 => Ok(Endianness::BigEndian), 0x10 => Ok(Endianness::LittleEndian), - _ => Err(invalid_field_err!("try_from", "RpceEndianness", "unsupported value")), + _ => Err(invalid_field_err!("try_from", "RpceEndianness", "unsupported value", at: 0)), } } } diff --git a/crates/ironrdp-rdpdr/src/pdu/mod.rs b/crates/ironrdp-rdpdr/src/pdu/mod.rs index 9ab261b93..30c57e867 100644 --- a/crates/ironrdp-rdpdr/src/pdu/mod.rs +++ b/crates/ironrdp-rdpdr/src/pdu/mod.rs @@ -117,11 +117,9 @@ impl RdpdrPdu { )), PacketId::CoreDeviceIoRequest => Ok(RdpdrPdu::DeviceIoRequest(DeviceIoRequest::decode(src)?)), PacketId::CoreUserLoggedon => Ok(RdpdrPdu::UserLoggedon), - packet_id => Err(unsupported_value_err!( - "RdpdrPdu::decode_body", + packet_id => Err(unsupported_value_err!( "RdpdrPdu::decode_body", "PacketId", - format!("{packet_id} ({:#06X})", u16::from(packet_id)) - )), + format!("{packet_id} ({:#06X})", u16::from(packet_id)), at: 0)), } } } @@ -372,7 +370,7 @@ impl TryFrom for Component { match value { 0x4472 => Ok(Component::RdpdrCtypCore), 0x5052 => Ok(Component::RdpdrCtypPrn), - _ => Err(invalid_field_err!("try_from", "Component", "invalid value")), + _ => Err(invalid_field_err!("try_from", "Component", "invalid value", at: 0)), } } } @@ -436,7 +434,7 @@ impl TryFrom for PacketId { 0x5043 => Ok(PacketId::PrnCacheData), 0x554C => Ok(PacketId::CoreUserLoggedon), 0x5543 => Ok(PacketId::PrnUsingXps), - _ => Err(invalid_field_err!("try_from", "PacketId", "invalid value")), + _ => Err(invalid_field_err!("try_from", "PacketId", "invalid value", at: 0)), } } } diff --git a/crates/ironrdp-rdpeusb/src/pdu/caps.rs b/crates/ironrdp-rdpeusb/src/pdu/caps.rs index b61f5d2c6..b2aae7f57 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/caps.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/caps.rs @@ -55,7 +55,8 @@ impl RimExchangeCapabilityRequest { if src.read_u32() != 1 { return Err(invalid_field_err!( "RIM_EXCHANGE_CAPABILITY_REQUEST::CapabilityValue", - "is not 0x1 (RIM_CAPABILITY_VERSION_01)" + "is not 0x1 (RIM_CAPABILITY_VERSION_01)", + in: src, )); } Ok(Self { @@ -117,7 +118,8 @@ impl RimExchangeCapabilityResponse { if src.read_u32() != 1 { return Err(invalid_field_err!( "RIM_EXCHANGE_CAPABILITY_RESPONSE::CapabilityValue", - "is not 0x1 (RIM_CAPABILITY_VERSION_01)" + "is not 0x1 (RIM_CAPABILITY_VERSION_01)", + in: src, )); }; let result = src.read_u32(); diff --git a/crates/ironrdp-rdpeusb/src/pdu/completion/mod.rs b/crates/ironrdp-rdpeusb/src/pdu/completion/mod.rs index c9139b1b9..5aaca2897 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/completion/mod.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/completion/mod.rs @@ -94,7 +94,7 @@ impl IoControlCompletion { return Err(invalid_field_err!( "Information != OutputBufferSize", "HResult is: 0x0 (IOCTL success), but Information != OutputBufferSize" - )); + , in: src)); } ensure_size!(in: src, size: n); src.read_slice(n).to_vec() @@ -113,7 +113,7 @@ impl IoControlCompletion { "OutputBufferSize", "HResult is not one of: 0x0 (success), 0x8007007A (insufficient buffer error), \ so expected OutputBufferSize: 0x0" - )); + , in: src)); } Vec::new() } @@ -194,7 +194,7 @@ impl UrbCompletion { pub(crate) fn decode(src: &mut ReadCursor<'_>, msg_id: MessageId, udev_iface: InterfaceId) -> DecodeResult { ensure_size!(in: src, size: 4 /* RequestId */ + 4 /* CbTsUrbResult */); let req_id = RequestIdTransferInOut::try_from(src.read_u32()) - .map_err(|reason| invalid_field_err!("URB_COMPLETION::RequestId", reason))?; + .map_err(|reason| invalid_field_err!("URB_COMPLETION::RequestId", reason, in: src))?; let cb_ts_urb_result: usize = src.read_u32().try_into().map_err(|e| other_err!(source: e))?; ensure_size!(in: src, size: cb_ts_urb_result); @@ -240,7 +240,7 @@ impl Encode for UrbCompletion { return Err(invalid_field_err!( "URB_COMPLETION::TsUrbResult", "has non-empty payload but payload is not TS_URB_ISOCH_TRANSFER_RESULT" - )); + , in: dst)); } self.ts_urb_result.encode(dst)?; @@ -296,7 +296,7 @@ impl UrbCompletionNoData { pub(crate) fn decode(src: &mut ReadCursor<'_>, msg_id: MessageId, udev_iface: InterfaceId) -> DecodeResult { ensure_size!(in: src, size: 4 /* RequestId */ + 4 /* CbTsUrbResult */); let req_id = RequestIdTransferInOut::try_from(src.read_u32()) - .map_err(|reason| invalid_field_err!("URB_COMPLETION_NO_DATA::RequestId", reason))?; + .map_err(|reason| invalid_field_err!("URB_COMPLETION_NO_DATA::RequestId", reason, in: src))?; let cb_ts_urb_result = usize::try_from(src.read_u32()).map_err(|e| other_err!(source: e))?; ensure_size!(in: src, size: cb_ts_urb_result); diff --git a/crates/ironrdp-rdpeusb/src/pdu/completion/ts_urb_result.rs b/crates/ironrdp-rdpeusb/src/pdu/completion/ts_urb_result.rs index 0263f8f15..d85561c63 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/completion/ts_urb_result.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/completion/ts_urb_result.rs @@ -41,7 +41,7 @@ impl Decode<'_> for TsUrbResult { let header = TsUrbResultHeader::decode(src)?; const ACTUAL_HEADER_SIZE: usize = size_of::(/* Size */) + TsUrbResultHeader::FIXED_PART_SIZE; if urb_size < ACTUAL_HEADER_SIZE { - return Err(invalid_field_err!("TS_URB_RESULT_HEADER::Size", "is smaller than 8")); + return Err(invalid_field_err!("TS_URB_RESULT_HEADER::Size", "is smaller than 8", in: src)); } let payload_size = urb_size - ACTUAL_HEADER_SIZE; ensure_size!(in: src, size: payload_size); @@ -221,7 +221,8 @@ impl Encode for TsUrbSelectConfigResult { dst.write_u32(self.interface.len().try_into().map_err(|_| { invalid_field_err!( "TS_URB_SELECT_CONFIGURATION_RESULT::Interface", - "too many interfaces / alternate settings; count exceeded field NumInterfaces (4 bytes)" + "too many interfaces / alternate settings; count exceeded field NumInterfaces (4 bytes)", + in: dst, ) })?); self.interface @@ -357,13 +358,15 @@ impl Encode for TsUrbIsochTransferResult { dst.write_u32(self.iso_packet.len().try_into().map_err(|_| { invalid_field_err!( "TS_URB_ISOCH_TRANSFER_RESULT::IsoPacket", - "too many packets: count exceeded field NumberOfPackets (4 bytes)" + "too many packets: count exceeded field NumberOfPackets (4 bytes)", + in: dst, ) })?); dst.write_u32(Self::count_error(&self.iso_packet).try_into().map_err(|_| { invalid_field_err!( "TS_URB_ISOCH_TRANSFER_RESULT::IsoPacket", - "too many failed transfers: count exceeded field ErrorCount (4 bytes)" + "too many failed transfers: count exceeded field ErrorCount (4 bytes)", + in: dst, ) })?); self.iso_packet.iter().try_for_each(|iso| iso.encode(dst)) @@ -425,7 +428,8 @@ impl Decode<'_> for TsUsbdInterfaceInfoResult { let length @ 16.. = src.read_u16() else { return Err(invalid_field_err!( "TS_USBD_INTERFACE_INFORMATION_RESULT::Length", - "is less than min reqd value of 16" + "is less than min reqd value of 16", + in: src, )); }; let remaining_length = usize::from(length) - 2 /* Length */; @@ -527,7 +531,8 @@ impl Decode<'_> for TsUsbdPipeInfoResult { 0x0 (UsbdPipeTypeControl),\ 0x1 (UsbdPipeTypeIsochronous),\ 0x2 (UsbdPipeTypeBulk),\ - 0x3 (UsbdPipeTypeInterrupt)" + 0x3 (UsbdPipeTypeInterrupt)", + in: src, )); } }; diff --git a/crates/ironrdp-rdpeusb/src/pdu/header.rs b/crates/ironrdp-rdpeusb/src/pdu/header.rs index 38174fbb9..05e22e3b3 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/header.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/header.rs @@ -47,7 +47,7 @@ impl TryFrom for Mask { 0x0 => Ok(Self::None), 0x1 => Ok(Self::Proxy), 0x2 => Ok(Self::Stub), - _ => Err(invalid_field_err!("try_from", "Mask", "invalid mask")), + _ => Err(invalid_field_err!("try_from", "Mask", "invalid mask", at: 0)), } } } @@ -122,7 +122,7 @@ impl TryFrom for InterfaceId { "try_from", "InterfaceId", "InterfaceId greater than 30 bits" - )) + , at: 0)) } } } diff --git a/crates/ironrdp-rdpeusb/src/pdu/iface_manipulation.rs b/crates/ironrdp-rdpeusb/src/pdu/iface_manipulation.rs index 4624c1241..7aa82a19c 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/iface_manipulation.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/iface_manipulation.rs @@ -50,7 +50,7 @@ impl Decode<'_> for InterfaceRelease { return Err(invalid_field_err!( "SHARED_MSG_HEADER::FunctionId", "must be 0x1 (RIMCALL_RELEASE)" - )); + , in: src)); } Ok(Self { iface_id, msg_id }) diff --git a/crates/ironrdp-rdpeusb/src/pdu/mod.rs b/crates/ironrdp-rdpeusb/src/pdu/mod.rs index 1833486b8..5d6b0295b 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/mod.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/mod.rs @@ -49,7 +49,7 @@ impl UrbdrcServerControlPdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid RIM_EXCHANGE_CAPABILITY_REQUEST header" - )), + , in: src)), } } @@ -61,7 +61,7 @@ impl UrbdrcServerControlPdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid CHANNEL_CREATED header" - )), + , in: src)), } } } @@ -89,7 +89,7 @@ impl UrbdrcServerDevicePdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid CHANNEL_CREATED header" - )), + , in: src)), } } } @@ -102,7 +102,7 @@ impl Decode<'_> for UrbdrcServerControlPdu { match unpack(header.iface_id)? { (InterfaceId::CAPABILITIES, Mask::None) => Self::decode_caps(src, f_id, header), (InterfaceId::NOTIFY_CLIENT, Mask::Proxy) => Self::decode_notification(src, f_id, header), - _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header")), + _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header", in: src)), } } } @@ -142,9 +142,9 @@ impl Decode<'_> for UrbdrcServerDevicePdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER::FunctionId", "unsupported function id for USB device interface" - )), + , in: src)), }, - _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header")), + _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header", in: src)), } } } @@ -239,7 +239,7 @@ impl UrbdrcClientControlPdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid function id in DEVICE_SINK" - )), + , in: src)), } } fn decode_notification(src: &mut ReadCursor<'_>, header: SharedMsgHeader) -> DecodeResult { @@ -252,7 +252,7 @@ impl UrbdrcClientControlPdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid function id in CHANNEL_CREATED" - )), + , in: src)), } } } @@ -267,7 +267,7 @@ impl Decode<'_> for UrbdrcClientControlPdu { } (InterfaceId::DEVICE_SINK, Mask::Proxy) => Self::decode_sink(src, header), (InterfaceId::NOTIFY_SERVER, Mask::Proxy) => Self::decode_notification(src, header), - _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header")), + _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header", in: src)), } } } @@ -283,7 +283,7 @@ impl UrbdrcClientDevicePdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid function id in DEVICE_SINK" - )), + , in: src)), } } fn decode_notification(src: &mut ReadCursor<'_>, header: SharedMsgHeader) -> DecodeResult { @@ -296,7 +296,7 @@ impl UrbdrcClientDevicePdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER", "invalid function id in CHANNEL_CREATED" - )), + , in: src)), } } } @@ -330,10 +330,10 @@ impl Decode<'_> for UrbdrcClientDevicePdu { _ => Err(invalid_field_err!( "SHARED_MSG_HEADER::InterfaceId", "unknown interface id" - )), + , in: src)), } } - _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header")), + _ => Err(invalid_field_err!("SHARED_MSG_HEADER", "invalid header", in: src)), } } } diff --git a/crates/ironrdp-rdpeusb/src/pdu/notify.rs b/crates/ironrdp-rdpeusb/src/pdu/notify.rs index a01fae3de..40ad87884 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/notify.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/notify.rs @@ -70,15 +70,15 @@ impl ChannelCreated { let major = src.read_u32(); if major != Self::MAJOR_VER { - return Err(unsupported_value_err!("MajorVersion", format!("{major}"))); + return Err(unsupported_value_err!("MajorVersion", format!("{major}"), in: src)); } let minor = src.read_u32(); if minor != Self::MINOR_VER { - return Err(unsupported_value_err!("MinorVersion", format!("{minor}"))); + return Err(unsupported_value_err!("MinorVersion", format!("{minor}"), in: src)); } let capabilities = src.read_u32(); if capabilities != Self::CAPS { - return Err(unsupported_value_err!("Capabilities", format!("{capabilities}"))); + return Err(unsupported_value_err!("Capabilities", format!("{capabilities}"), in: src)); } Ok(Self { diff --git a/crates/ironrdp-rdpeusb/src/pdu/sink.rs b/crates/ironrdp-rdpeusb/src/pdu/sink.rs index e28148dea..a1c067f19 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/sink.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/sink.rs @@ -93,13 +93,13 @@ impl AddDevice { ensure_size!(in: src, size: 4 /* NumUsbDevice */); let num_usb_device = src.read_u32(); if num_usb_device != 0x1 { - return Err(unsupported_value_err!("NumUsbDevice", format!("{num_usb_device}"))); + return Err(unsupported_value_err!("NumUsbDevice", format!("{num_usb_device}"), in: src)); } ensure_size!(in: src, size: InterfaceId::FIXED_PART_SIZE); let usb_device = match src.read_u32() { 0x0..=0x3 => { - return Err(invalid_field_err!("UsbDevice", "conflict with default interfaces")); + return Err(invalid_field_err!("UsbDevice", "conflict with default interfaces", in: src)); } value => InterfaceId::try_from(value)?, }; @@ -225,7 +225,7 @@ impl UsbDeviceCaps { impl Encode for UsbDeviceCaps { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { Self::check_device_speed(self.usb_bus_iface_ver, self.device_speed) - .map_err(|reason| invalid_field_err!("USB_DEVICE_CAPABILITIES::DeviceIsHighSpeed", reason))?; + .map_err(|reason| invalid_field_err!("USB_DEVICE_CAPABILITIES::DeviceIsHighSpeed", reason, in: dst))?; ensure_fixed_part_size!(in: dst); @@ -263,36 +263,36 @@ impl Decode<'_> for UsbDeviceCaps { let cb_size = src.read_u32(); if cb_size != Self::CB_SIZE { - return Err(unsupported_value_err!("CbSize", format!("{cb_size}"))); + return Err(unsupported_value_err!("CbSize", format!("{cb_size}"), in: src)); } let usb_bus_iface_ver = match src.read_u32() { 0x0 => UsbBusIfaceVer::V0, 0x1 => UsbBusIfaceVer::V1, 0x2 => UsbBusIfaceVer::V2, - value => return Err(unsupported_value_err!("UsbBusInterfaceVersion", format!("{value}"))), + value => return Err(unsupported_value_err!("UsbBusInterfaceVersion", format!("{value}"), in: src)), }; let usbdi_ver = match src.read_u32() { 0x500 => UsbdiVer::V0x500, 0x600 => UsbdiVer::V0x600, - value => return Err(unsupported_value_err!("USBDI_Version", format!("{value}"))), + value => return Err(unsupported_value_err!("USBDI_Version", format!("{value}"), in: src)), }; let supported_usb_ver = match src.read_u32() { 0x100 => SupportedUsbVer::Usb10, 0x110 => SupportedUsbVer::Usb11, 0x200 => SupportedUsbVer::Usb20, - value => return Err(unsupported_value_err!("SupportedUsbVersion", format!("{value}"))), + value => return Err(unsupported_value_err!("SupportedUsbVersion", format!("{value}"), in: src)), }; let hcd_caps = src.read_u32(); if hcd_caps != Self::HCD_CAPS { - return Err(unsupported_value_err!("HcdCapabilities", format!("{hcd_caps}"))); + return Err(unsupported_value_err!("HcdCapabilities", format!("{hcd_caps}"), in: src)); } let device_speed = match src.read_u32() { 0x0 => DeviceSpeed::FullSpeed, 0x1 => DeviceSpeed::HighSpeed, - value => return Err(unsupported_value_err!("DeviceIsHighSpeed", format!("{value}"))), + value => return Err(unsupported_value_err!("DeviceIsHighSpeed", format!("{value}"), in: src)), }; Self::check_device_speed(usb_bus_iface_ver, device_speed) - .map_err(|reason| invalid_field_err!("USB_DEVICE_CAPABILITIES::DeviceIsHighSpeed", reason))?; + .map_err(|reason| invalid_field_err!("USB_DEVICE_CAPABILITIES::DeviceIsHighSpeed", reason, in: src))?; let no_ack_isoch_write_jitter_buf_size = match src.read_u32() { 0 => NoAckIsochWriteJitterBufSizeInMs::TS_URB_ISOCH_TRANSFER_NOT_SUPPORTED, value @ 10..=512 => NoAckIsochWriteJitterBufSizeInMs(value), @@ -300,7 +300,7 @@ impl Decode<'_> for UsbDeviceCaps { return Err(unsupported_value_err!( "NoAckIsochWriteJitterBufferSizeInMs", format!("{value}") - )); + , in: src)); } }; diff --git a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/mod.rs b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/mod.rs index 7fa1ec056..32cf06d9a 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/mod.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/mod.rs @@ -114,7 +114,7 @@ impl RegisterRequestCallback { return Err(invalid_field_err!( "RequestCompletion", "conflict with default interfaces" - )); + , in: src)); } value => Some(InterfaceId::try_from(value)?), } @@ -219,7 +219,7 @@ impl IoControl { 0x220_020 => IoctlInternalUsb::GetHubName, 0x220_420 => IoctlInternalUsb::GetBusInfo, 0x220_424 => IoctlInternalUsb::GetControllerName, - value => return Err(unsupported_value_err!("IoControlCode", format!("{value}"))), + value => return Err(unsupported_value_err!("IoControlCode", format!("{value}"), in: src)), }; let input_buffer_size = src.read_u32().try_into().map_err(|e| other_err!(source: e))?; ensure_size!(in: src, @@ -240,14 +240,14 @@ impl IoControl { io_control .check_output_buffer_size() .map(|()| io_control) - .map_err(|reason| invalid_field_err!("IO_CONTROL::OutputBufferSize", reason)) + .map_err(|reason| invalid_field_err!("IO_CONTROL::OutputBufferSize", reason, in: src)) } } impl Encode for IoControl { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { self.check_output_buffer_size() - .map_err(|reason| invalid_field_err!("IO_CONTROL::OutputBufferSize", reason))?; + .map_err(|reason| invalid_field_err!("IO_CONTROL::OutputBufferSize", reason, in: dst))?; ensure_size!(in: dst, size: self.size()); self.header().encode(dst)?; @@ -436,7 +436,7 @@ impl InternalIoControl { return Err(unsupported_value_err!( "INTERNAL_IO_CONTROL::IoControlCode", format!("{code:#X}") - )); + , in: src)); } } { @@ -445,7 +445,7 @@ impl InternalIoControl { return Err(unsupported_value_err!( "INTERNAL_IO_CONTROL::InputBufferSize", format!("{size:#X}") - )); + , in: src)); } } let output_buffer_size = src.read_u32(/* OutputBufferSize */); @@ -453,7 +453,7 @@ impl InternalIoControl { return Err(unsupported_value_err!( "INTERNAL_IO_CONTROL::OutputBufferSize", format!("{output_buffer_size:#X}") - )); + , in: src)); } let req_id = src.read_u32(); @@ -713,7 +713,7 @@ impl TransferInRequest { transfer_in_req .check_output_buffer_size() - .map_err(|reason| invalid_field_err!("TRANSFER_IN_REQUEST::OutputBufferSize", reason))?; + .map_err(|reason| invalid_field_err!("TRANSFER_IN_REQUEST::OutputBufferSize", reason, in: src))?; Ok(transfer_in_req) } @@ -722,7 +722,7 @@ impl TransferInRequest { impl Encode for TransferInRequest { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { self.check_output_buffer_size() - .map_err(|reason| invalid_field_err!("TRANSFER_IN_REQUEST::OutputBufferSize", reason))?; + .map_err(|reason| invalid_field_err!("TRANSFER_IN_REQUEST::OutputBufferSize", reason, in: dst))?; ensure_size!(in: dst, size: self.size()); self.header().encode(dst)?; @@ -854,7 +854,7 @@ impl RetractDevice { let reason = src.read_u32(); #[expect(clippy::as_conversions)] if reason != UsbRetractReason::BlockedByPolicy as u32 { - return Err(unsupported_value_err!("RETRACT_DEVICE::Reason", format!("{reason}"))); + return Err(unsupported_value_err!("RETRACT_DEVICE::Reason", format!("{reason}"), in: src)); } Ok(Self { diff --git a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/mod.rs b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/mod.rs index b050d3d4b..e659bdbea 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/mod.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/mod.rs @@ -27,12 +27,12 @@ macro_rules! ensure_transfer_flag { return Err(invalid_field_err!( concat!("TRANSFER_IN_REQUEST::TsUrb: ", $ts_urb_name, "::TransferFlags"), "does not contain USBD_TRANSFER_DIRECTION_IN" - )); + , at: 0)); } else if !transfer_in && flag_in { return Err(invalid_field_err!( concat!("TRANSFER_OUT_REQUEST::TsUrb: ", $ts_urb_name, "::TransferFlags"), "contains USBD_TRANSFER_DIRECTION_IN" - )); + , at: 0)); } }; } @@ -66,7 +66,7 @@ impl Decode<'_> for TsUrbIn { return Err(invalid_field_err!( "TRANSFER_IN_REQUEST::TsUrb::TS_URB_HEADER::NoAck", "is non-zero: NoAck MUST be set to zero for TRANSFER_IN_REQUEST" - )); + , in: src)); } let payload_size = usize::from(header.ts_urb_size) - header.size(); @@ -165,7 +165,7 @@ impl Decode<'_> for TsUrbIn { UrbFunction::URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR => { Self::OsFeatDescReq(TsUrbOsFeatDescRequest::decode(&mut src, header)?) } - func => return Err(unsupported_value_err!("URB Function", format!("{}", u16::from(func)))), + func => return Err(unsupported_value_err!("URB Function", format!("{}", u16::from(func)), in: src)), }; Ok(ts_urb) @@ -311,7 +311,7 @@ impl Decode<'_> for TsUrbOut { ); Self::VendorClassReq(urb) } - func => return Err(unsupported_value_err!("URB Function", format!("{}", u16::from(func)))), + func => return Err(unsupported_value_err!("URB Function", format!("{}", u16::from(func)), in: src)), }; Ok(ts_urb) @@ -427,13 +427,13 @@ impl Encode for TsUrbSelectConfig { return Err(invalid_field_err!( "TS_URB_SELECT_CONFIGURATION::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_SELECT_CONFIGURATION" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_SELECT_CONFIGURATION::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_size!(in: dst, size: self.size()); self.header.encode_with_size(dst, self.size())?; @@ -518,13 +518,13 @@ impl Encode for TsUrbSelectInterface { return Err(invalid_field_err!( "TS_URB_SELECT_INTERFACE::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_SELECT_INTERFACE" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_SELECT_INTERFACE::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_size!(in: dst, size: self.size()); @@ -589,14 +589,15 @@ impl Encode for TsUrbPipeRequest { URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL, \ URB_FUNCTION_SYNC_RESET_PIPE, \ URB_FUNCTION_SYNC_CLEAR_STALL, \ - URB_FUNCTION_CLOSE_STATIC_STREAMS" + URB_FUNCTION_CLOSE_STATIC_STREAMS", + in: dst )); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_PIPE_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); @@ -643,13 +644,13 @@ impl Encode for TsUrbGetCurrFrameNum { return Err(invalid_field_err!( "TS_URB_GET_CURRENT_FRAME_NUMBER::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_GET_CURRENT_FRAME_NUMBER" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_GET_CURRENT_FRAME_NUMBER::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } self.header.encode_with_size(dst, self.size()) } @@ -708,7 +709,7 @@ impl Encode for TsUrbControlTransfer { return Err(invalid_field_err!( "TS_URB_CONTROL_TRANSFER::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_CONTROL_TRANSFER" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); self.header.encode_with_size(dst, self.size())?; @@ -771,7 +772,7 @@ impl Encode for TsUrbBulkOrInterruptTransfer { return Err(invalid_field_err!( "TS_URB_BULK_OR_INTERRUPT_TRANSFER::TS_URB_HEADER::URB_Function", "is not one of: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER, URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); @@ -845,7 +846,7 @@ impl Encode for TsUrbIsochTransfer { return Err(invalid_field_err!( "TS_URB_ISOCH_TRANSFER::TS_URB_HEADER::URB_Function", "is not one of: URB_FUNCTION_ISOCH_TRANSFER, URB_FUNCTION_ISOCH_TRANSFER_USING_CHAINED_MDL" - )); + , in: dst)); } ensure_size!(in: dst, size: self.size()); @@ -857,7 +858,7 @@ impl Encode for TsUrbIsochTransfer { invalid_field_err!( "TS_URB_ISOCH_TRANSFER::IsoPacket", "too many packets: count exceeded field NumberOfPackets (4 bytes)" - ) + , in: dst) })?); dst.write_u32(self.error_count); self.iso_packet.iter().try_for_each(|packet| packet.encode(dst)) @@ -942,7 +943,8 @@ impl Encode for TsUrbControlDescRequest { URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, \ URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE, \ URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT, \ - URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE" + URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE", + in: dst )); } ensure_fixed_part_size!(in: dst); @@ -1023,13 +1025,13 @@ impl Encode for TsUrbControlFeatRequest { URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE, \ URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT, \ URB_FUNCTION_CLEAR_FEATURE_TO_OTHER" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_CONTROL_FEATURE_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); @@ -1093,14 +1095,15 @@ impl Encode for TsUrbControlGetStatusRequest { URB_FUNCTION_GET_STATUS_FROM_DEVICE, \ URB_FUNCTION_GET_STATUS_FROM_INTERFACE, \ URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, \ - URB_FUNCTION_GET_STATUS_FROM_OTHER" + URB_FUNCTION_GET_STATUS_FROM_OTHER", + in: dst )); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_CONTROL_GET_STATUS_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); @@ -1192,7 +1195,8 @@ impl Encode for TsUrbControlVendorClassRequest { URB_FUNCTION_CLASS_DEVICE, \ URB_FUNCTION_CLASS_INTERFACE, \ URB_FUNCTION_CLASS_ENDPOINT, \ - URB_FUNCTION_CLASS_OTHER" + URB_FUNCTION_CLASS_OTHER", + in: dst )); } ensure_fixed_part_size!(in: dst); @@ -1244,13 +1248,13 @@ impl Encode for TsUrbControlGetConfigRequest { return Err(invalid_field_err!( "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_GET_CONFIGURATION" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); self.header.encode_with_size(dst, self.size()) @@ -1299,13 +1303,13 @@ impl Encode for TsUrbControlGetInterfaceRequest { return Err(invalid_field_err!( "TS_URB_CONTROL_GET_INTERFACE_REQUEST::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_GET_INTERFACE" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_CONTROL_GET_INTERFACE_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); self.header.encode_with_size(dst, self.size())?; @@ -1359,7 +1363,7 @@ impl TsUrbOsFeatDescRequest { return Err(invalid_field_err!( "TRANSFER_IN_REQUEST::TsUrb: TS_URB_OS_FEATURE_DESCRIPTOR_REQUEST::MS_PageIndex", "must be: 0x0" - )); + , in: src)); } let ms_feat_desc_index = src.read_u16(); read_padding!(src, 3); @@ -1379,13 +1383,13 @@ impl Encode for TsUrbOsFeatDescRequest { return Err(invalid_field_err!( "TS_URB_OS_FEATURE_DESCRIPTOR_REQUEST::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR" - )); + , in: dst)); } if self.header.no_ack { return Err(invalid_field_err!( "TS_URB_OS_FEATURE_DESCRIPTOR_REQUEST::TS_URB_HEADER::URB_Function::NoAck", "is non-zero" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); self.header.encode_with_size(dst, self.size())?; @@ -1457,7 +1461,7 @@ impl Encode for TsUrbControlTransferEx { return Err(invalid_field_err!( "TS_URB_CONTROL_TRANSFER_EX::TS_URB_HEADER::URB_Function", "is not URB_FUNCTION_CONTROL_TRANSFER_EX" - )); + , in: dst)); } ensure_fixed_part_size!(in: dst); self.header.encode_with_size(dst, self.size())?; diff --git a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/utils.rs b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/utils.rs index 54431578f..2c5d9d806 100644 --- a/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/utils.rs +++ b/crates/ironrdp-rdpeusb/src/pdu/usb_dev/ts_urb/utils.rs @@ -342,7 +342,7 @@ impl TsUrbHeader { pub(super) fn encode_with_size(&self, dst: &mut WriteCursor<'_>, ts_urb_size: usize) -> EncodeResult<()> { let ts_urb_size = ts_urb_size .try_into() - .map_err(|_| invalid_field_err!("TS_URB_HEADER::Size", "too large: exceeded 2-byte size field"))?; + .map_err(|_| invalid_field_err!("TS_URB_HEADER::Size", "too large: exceeded 2-byte size field", in: dst))?; Self { ts_urb_size, @@ -382,7 +382,7 @@ impl Decode<'_> for TsUrbHeader { ensure_fixed_part_size!(in: src); let size = src.read_u16(); if usize::from(size) < Self::FIXED_PART_SIZE { - return Err(invalid_field_err!("TS_URB_HEADER::Size", "is smaller than 8")); + return Err(invalid_field_err!("TS_URB_HEADER::Size", "is smaller than 8", in: src)); } let func = UrbFunction::from(src.read_u16()); @@ -398,7 +398,7 @@ impl Decode<'_> for TsUrbHeader { return Err(invalid_field_err!( "TS_URB_HEADER::NoAck", "this bit can only be set when URB Function is an isochronous transfer" - )); + , in: src)); } Ok(Self { @@ -552,7 +552,8 @@ impl Decode<'_> for TsUsbdInterfaceInfo { let length @ 12.. = src.read_u16() else { return Err(invalid_field_err!( "TS_USBD_INTERFACE_INFORMATION::Length", - "is less than min reqd value of 12" + "is less than min reqd value of 12", + in: src, )); }; @@ -569,7 +570,8 @@ impl Decode<'_> for TsUsbdInterfaceInfo { if number_of_pipes != number_of_pipes_expected.into() { return Err(invalid_field_err!( "TS_USBD_INTERFACE_INFORMATION::NumberOfPipesExpected", - "is not equal to TS_USBD_INTERFACE_INFORMATION::NumberOfPipes" + "is not equal to TS_USBD_INTERFACE_INFORMATION::NumberOfPipes", + in: src, )); } @@ -578,7 +580,8 @@ impl Decode<'_> for TsUsbdInterfaceInfo { let Some(length_suggested_size) = length_suggested_size else { return Err(invalid_field_err!( "TS_USBD_INTERFACE_INFORMATION::Length", - "is too small" + "is too small", + in: src, )); }; @@ -587,7 +590,8 @@ impl Decode<'_> for TsUsbdInterfaceInfo { { return Err(invalid_field_err!( "TS_USBD_INTERFACE_INFORMATION::NumberOfPipes", - "does not reflect number of pipes suggested by TS_USBD_INTERFACE_INFORMATION::Length" + "does not reflect number of pipes suggested by TS_USBD_INTERFACE_INFORMATION::Length", + in: src, )); } } diff --git a/crates/ironrdp-rdpsnd/src/pdu/mod.rs b/crates/ironrdp-rdpsnd/src/pdu/mod.rs index e26fa5969..3271fa321 100644 --- a/crates/ironrdp-rdpsnd/src/pdu/mod.rs +++ b/crates/ironrdp-rdpsnd/src/pdu/mod.rs @@ -45,7 +45,7 @@ impl TryFrom for Version { 0x05 => Ok(Self::V5), 0x06 => Ok(Self::V6), 0x08 => Ok(Self::V8), - _ => Err(invalid_field_err!("Version", "unknown audio output version")), + _ => Err(invalid_field_err!("Version", "unknown audio output version", at: 0)), } } } @@ -486,7 +486,7 @@ impl TryFrom for QualityMode { 0x00 => Ok(Self::Dynamic), 0x01 => Ok(Self::Medium), 0x02 => Ok(Self::High), - _ => Err(invalid_field_err!("QualityMode", "unknown audio quality mode")), + _ => Err(invalid_field_err!("QualityMode", "unknown audio quality mode", at: 0)), } } } @@ -636,7 +636,7 @@ impl<'de> Decode<'de> for TrainingPdu { let len = usize::from(src.read_u16()); let data = if len != 0 { if len < Self::FIXED_PART_SIZE + ServerAudioOutputPdu::FIXED_PART_SIZE { - return Err(invalid_field_err!("TrainingPdu::wPackSize", "too small")); + return Err(invalid_field_err!("TrainingPdu::wPackSize", "too small", at: 0)); } let len = len - Self::FIXED_PART_SIZE - ServerAudioOutputPdu::FIXED_PART_SIZE; ensure_size!(in: src, size: len); @@ -849,7 +849,7 @@ impl WavePdu<'_> { let body_size = usize::from(body_size); let data_len = body_size .checked_sub(info.size()) - .ok_or_else(|| invalid_field_err!("Length", "WaveInfo body_size is too small"))?; + .ok_or_else(|| invalid_field_err!("Length", "WaveInfo body_size is too small", at: 0))?; let wave = SndWavePdu::decode(src, data_len)?; let mut data = Vec::with_capacity(wave.size()); @@ -1264,10 +1264,8 @@ impl<'de> Decode<'de> for ServerAudioOutputPdu<'_> { let pdu = PitchPdu::decode(src)?; Ok(Self::Pitch(pdu)) } - _ => Err(invalid_field_err!( - "ServerAudioOutputPdu::msgType", - "Unknown audio output PDU type" - )), + _ => Err(invalid_field_err!( "ServerAudioOutputPdu::msgType", + "Unknown audio output PDU type", at: 0)), } } } @@ -1355,10 +1353,8 @@ impl<'de> Decode<'de> for ClientAudioOutputPdu { let pdu = WaveConfirmPdu::decode(src)?; Ok(Self::WaveConfirm(pdu)) } - _ => Err(invalid_field_err!( - "ClientAudioOutputPdu::msgType", - "Unknown audio output PDU type" - )), + _ => Err(invalid_field_err!( "ClientAudioOutputPdu::msgType", + "Unknown audio output PDU type", at: 0)), } } } diff --git a/crates/ironrdp-server/src/encoder/bitmap.rs b/crates/ironrdp-server/src/encoder/bitmap.rs index 9ad364c87..4cb91d4d8 100644 --- a/crates/ironrdp-server/src/encoder/bitmap.rs +++ b/crates/ironrdp-server/src/encoder/bitmap.rs @@ -29,10 +29,8 @@ impl BitmapEncoder { // It’s not clear how to achieve that yet, but generally, server uses multiple of 4-widths, // and client has surface capabilities, so this path is unlikely. if !bitmap.width.get().is_multiple_of(4) { - return Err(BitmapEncodeError::Encode(invalid_field_err!( - "bitmap", - "Width must be a multiple of 4" - ))); + return Err(BitmapEncodeError::Encode(invalid_field_err!( "bitmap", + "Width must be a multiple of 4", at: 0))); } let bytes_per_pixel = u16::from(bitmap.format.bytes_per_pixel()); diff --git a/crates/ironrdp-server/src/lib.rs b/crates/ironrdp-server/src/lib.rs index 4ae6b7167..f3cc7dabc 100644 --- a/crates/ironrdp-server/src/lib.rs +++ b/crates/ironrdp-server/src/lib.rs @@ -2,7 +2,8 @@ #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] #![allow(clippy::arithmetic_side_effects)] // TODO: should we enable this lint back? -pub use {tokio, tokio_rustls}; +pub use tokio; +pub use tokio_rustls; mod macros; diff --git a/crates/ironrdp-session/src/fast_path.rs b/crates/ironrdp-session/src/fast_path.rs index 2a05d1a23..f1edc622b 100644 --- a/crates/ironrdp-session/src/fast_path.rs +++ b/crates/ironrdp-session/src/fast_path.rs @@ -167,7 +167,7 @@ impl Processor { // FIXME: This seems to be a way of special-handling the error case in FastPathUpdate::decode_cursor_with_code // to ignore the unsupported update PDUs, but this is a fragile logic and the rationale behind it is not // obvious. - if let DecodeErrorKind::InvalidField { field, reason } = e.kind() { + if let DecodeErrorKind::InvalidField { field, reason, .. } = e.kind() { warn!(field, reason, "Received invalid Fast-Path update"); processor_updates.push(UpdateKind::None); } else { diff --git a/crates/ironrdp-str/src/fixed.rs b/crates/ironrdp-str/src/fixed.rs index 28545eb9c..9b09a19c5 100644 --- a/crates/ironrdp-str/src/fixed.rs +++ b/crates/ironrdp-str/src/fixed.rs @@ -330,10 +330,8 @@ impl DecodeOwned for FixedString { // After stripping trailing nulls from WCHAR_COUNT units, the result must be // strictly shorter — if no null was present the field is malformed. if units.len() >= WCHAR_COUNT { - return Err(ironrdp_core::invalid_field_err!( - "content", - "fixed-size string field is missing its null terminator" - )); + return Err(ironrdp_core::invalid_field_err!( "content", + "fixed-size string field is missing its null terminator", at: 0)); } Ok(Self(StringRepr::from_wire_units(units))) diff --git a/crates/ironrdp-str/src/multi_sz.rs b/crates/ironrdp-str/src/multi_sz.rs index bae155728..307d68e32 100644 --- a/crates/ironrdp-str/src/multi_sz.rs +++ b/crates/ironrdp-str/src/multi_sz.rs @@ -480,7 +480,7 @@ impl Encode for MultiSzString { let total_cch: u32 = cast_length!( "cch", self.checked_total_cch() - .ok_or_else(|| invalid_field_err!("cch", "MULTI_SZ total length overflow"))? + .ok_or_else(|| invalid_field_err!("cch", "MULTI_SZ total length overflow", at: 0))? )?; ensure_size!(in: dst, size: self.size()); @@ -540,12 +540,12 @@ impl DecodeOwned for MultiSzString { // The minimum valid total_cch is 1 (just the final sentinel null). if total_cch == 0 { - return Err(invalid_field_err!("cch", "zero cch for MULTI_SZ is invalid")); + return Err(invalid_field_err!("cch", "zero cch for MULTI_SZ is invalid", at: 0)); } let byte_count = total_cch .checked_mul(2) - .ok_or_else(|| invalid_field_err!("cch", "MULTI_SZ byte length overflow"))?; + .ok_or_else(|| invalid_field_err!("cch", "MULTI_SZ byte length overflow", at: 0))?; ensure_size!(in: src, size: byte_count); // One allocation: read all bytes and reinterpret as u16 code units. @@ -556,7 +556,7 @@ impl DecodeOwned for MultiSzString { if let Some(&unit) = all_units.last() && unit != 0 { - return Err(invalid_field_err!("content", "MULTI_SZ must end with a null sentinel")); + return Err(invalid_field_err!("content", "MULTI_SZ must end with a null sentinel", at: 0)); } // Strip the sentinel null; per-string null terminators are retained in storage. @@ -567,10 +567,8 @@ impl DecodeOwned for MultiSzString { // Without this check, a last segment without its own null would be silently dropped // by the null-scanning iterators. if !all_units.is_empty() && all_units.last() != Some(&0) { - return Err(invalid_field_err!( - "content", - "MULTI_SZ last segment is missing its null terminator" - )); + return Err(invalid_field_err!( "content", + "MULTI_SZ last segment is missing its null terminator", at: 0)); } Ok(Self(MultiSzStringRepr::Wire(all_units))) diff --git a/crates/ironrdp-str/src/prefixed.rs b/crates/ironrdp-str/src/prefixed.rs index d9faaa29a..e7c0b0d6f 100644 --- a/crates/ironrdp-str/src/prefixed.rs +++ b/crates/ironrdp-str/src/prefixed.rs @@ -360,14 +360,14 @@ impl Encode for PrefixedString { let counted_cch = if N::NULL_COUNTED_IN_PREFIX { content_cch .checked_add(1) - .ok_or_else(|| invalid_field_err!("length prefix", "content length overflow"))? + .ok_or_else(|| invalid_field_err!("length prefix", "content length overflow", at: 0))? } else { content_cch }; let prefix_value = if P::IS_BYTE_COUNT { counted_cch .checked_mul(2) - .ok_or_else(|| invalid_field_err!("length prefix", "byte length overflow"))? + .ok_or_else(|| invalid_field_err!("length prefix", "byte length overflow", at: 0))? } else { counted_cch }; @@ -406,10 +406,8 @@ impl DecodeOwned for PrefixedString DecodeOwned for PrefixedString DecodeOwned for PrefixedString DecodeOwned for PrefixedString, wchar_count: usize) -> DecodeResult { let byte_count = wchar_count .checked_mul(2) - .ok_or_else(|| invalid_field_err!("wchar_count", "character count overflow"))?; + .ok_or_else(|| invalid_field_err!("wchar_count", "character count overflow", at: 0))?; ensure_size!(in: src, size: byte_count); let slice = src.read_slice(byte_count); @@ -157,7 +157,7 @@ impl UnframedString { /// Otherwise equivalent to `decode(src, byte_len / 2)`. pub fn decode_from_byte_len(src: &mut ReadCursor<'_>, byte_len: usize) -> DecodeResult { if byte_len % 2 != 0 { - return Err(invalid_field_err!("byte_len", "odd byte count for utf-16 string field")); + return Err(invalid_field_err!("byte_len", "odd byte count for utf-16 string field", at: 0)); } Self::decode(src, byte_len / 2) } diff --git a/crates/ironrdp-testsuite-core/tests/pcb.rs b/crates/ironrdp-testsuite-core/tests/pcb.rs index c31dd812f..ed1c64013 100644 --- a/crates/ironrdp-testsuite-core/tests/pcb.rs +++ b/crates/ironrdp-testsuite-core/tests/pcb.rs @@ -100,15 +100,16 @@ fn null_size() { .unwrap(); expect![[r#" - Error { - context: "PreconnectionBlob", - kind: InvalidField { - field: "cbSize", - reason: "advertised size too small for Preconnection PDU V1", - }, - source: None, - } - "#]] + Error { + context: "PreconnectionBlob", + kind: InvalidField { + field: "cbSize", + reason: "advertised size too small for Preconnection PDU V1", + offset: 0, + }, + source: None, + } + "#]] .assert_debug_eq(&e); } @@ -131,6 +132,7 @@ fn truncated() { kind: NotEnoughBytes { received: 0, expected: 239, + offset: 0, }, source: None, } @@ -155,14 +157,15 @@ fn pcb_v2_string_too_big() { .unwrap(); expect![[r#" - Error { - context: "PreconnectionBlob", - kind: InvalidField { - field: "cchPCB", - reason: "PCB string bigger than advertised size", - }, - source: None, - } - "#]] + Error { + context: "PreconnectionBlob", + kind: InvalidField { + field: "cchPCB", + reason: "PCB string bigger than advertised size", + offset: 0, + }, + source: None, + } + "#]] .assert_debug_eq(&e); } diff --git a/crates/ironrdp-testsuite-core/tests/pdu/mcs.rs b/crates/ironrdp-testsuite-core/tests/pdu/mcs.rs index c3ae4914b..133d2e56e 100644 --- a/crates/ironrdp-testsuite-core/tests/pdu/mcs.rs +++ b/crates/ironrdp-testsuite-core/tests/pdu/mcs.rs @@ -21,6 +21,7 @@ fn invalid_domain_mcspdu() { kind: InvalidField { field: "domain-mcspdu", reason: "unexpected application tag for CHOICE", + offset: 0, }, source: None, } diff --git a/crates/ironrdp-testsuite-core/tests/pdu/x224.rs b/crates/ironrdp-testsuite-core/tests/pdu/x224.rs index dfb85dcf2..9085690e7 100644 --- a/crates/ironrdp-testsuite-core/tests/pdu/x224.rs +++ b/crates/ironrdp-testsuite-core/tests/pdu/x224.rs @@ -244,6 +244,7 @@ fn nego_request_unexpected_rdp_msg_type() { context: "Client X.224 Connection Request", kind: UnexpectedMessageType { got: 3, + offset: 0, }, source: None, } @@ -278,6 +279,7 @@ fn nego_confirm_unexpected_rdp_msg_type() { context: "Server X.224 Connection Confirm", kind: UnexpectedMessageType { got: 175, + offset: 0, }, source: None, } @@ -341,6 +343,7 @@ fn cookie_without_cr_lf_error_decode() { kind: NotEnoughBytes { received: 1, expected: 2, + offset: 0, }, source: None, } diff --git a/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs b/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs index 79887d371..bf12dc51f 100644 --- a/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs +++ b/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs @@ -8,7 +8,6 @@ use ironrdp_pdu::mcs::{McsMessage, SendDataIndication}; use ironrdp_pdu::rdp::capability_sets::MajorPlatformType; use ironrdp_pdu::rdp::headers::{ServerDeactivateAll, ShareControlHeader, ShareControlPdu}; use ironrdp_pdu::x224::X224; - use ironrdp_testsuite_core::capsets::SERVER_DEMAND_ACTIVE; const USER_CHANNEL_ID: u16 = 1002; diff --git a/crates/ironrdp-testsuite-core/tests/str_types/multi_sz.rs b/crates/ironrdp-testsuite-core/tests/str_types/multi_sz.rs index e71c2378e..21d2c6bf7 100644 --- a/crates/ironrdp-testsuite-core/tests/str_types/multi_sz.rs +++ b/crates/ironrdp-testsuite-core/tests/str_types/multi_sz.rs @@ -70,6 +70,7 @@ fn rejects_missing_segment_null_terminator() { kind: InvalidField { field: "content", reason: "MULTI_SZ last segment is missing its null terminator", + offset: 0, }, source: None, } @@ -87,6 +88,7 @@ fn rejects_zero_cch() { kind: InvalidField { field: "cch", reason: "zero cch for MULTI_SZ is invalid", + offset: 0, }, source: None, } diff --git a/crates/ironrdp-testsuite-core/tests/str_types/prefixed.rs b/crates/ironrdp-testsuite-core/tests/str_types/prefixed.rs index 72c8fcd90..d222ca043 100644 --- a/crates/ironrdp-testsuite-core/tests/str_types/prefixed.rs +++ b/crates/ironrdp-testsuite-core/tests/str_types/prefixed.rs @@ -126,6 +126,7 @@ fn rejects_null_counted_zero_cch() { kind: InvalidField { field: "length prefix", reason: "NullCounted prefix of 0 is invalid; minimum is 1 (empty string with null)", + offset: 0, }, source: None, } @@ -150,6 +151,7 @@ fn rejects_nonzero_null_terminator_null_counted() { kind: InvalidField { field: "null terminator", reason: "expected 0x0000 null terminator", + offset: 0, }, source: None, } @@ -172,6 +174,7 @@ fn rejects_nonzero_null_terminator_null_uncounted() { kind: InvalidField { field: "null terminator", reason: "expected 0x0000 null terminator", + offset: 0, }, source: None, } @@ -192,6 +195,7 @@ fn rejects_odd_byte_count() { kind: InvalidField { field: "length prefix", reason: "odd byte count for utf-16 string field", + offset: 0, }, source: None, } diff --git a/crates/ironrdp-testsuite-core/tests/str_types/unframed.rs b/crates/ironrdp-testsuite-core/tests/str_types/unframed.rs index 274f4c4fb..574ac2589 100644 --- a/crates/ironrdp-testsuite-core/tests/str_types/unframed.rs +++ b/crates/ironrdp-testsuite-core/tests/str_types/unframed.rs @@ -30,6 +30,7 @@ fn rejects_odd_byte_len() { kind: InvalidField { field: "byte_len", reason: "odd byte count for utf-16 string field", + offset: 0, }, source: None, } diff --git a/crates/ironrdp-web/src/printer.rs b/crates/ironrdp-web/src/printer.rs index 918dd5cb1..3dbda3d13 100644 --- a/crates/ironrdp-web/src/printer.rs +++ b/crates/ironrdp-web/src/printer.rs @@ -20,12 +20,11 @@ //! [`SvcMessage`] layer prepends the correct RDPDR `SharedHeader` //! (`RDPDR_CTYP_CORE` + `PAKID_CORE_DEVICE_IOCOMPLETION`) automatically. +use core::sync::atomic::{AtomicUsize, Ordering}; use std::collections::HashMap; use std::fmt; use std::sync::Arc; -use core::sync::atomic::{AtomicUsize, Ordering}; - use futures_channel::mpsc; use ironrdp::rdpdr::backend::RdpdrBackend; use ironrdp::rdpdr::pdu::RdpdrPdu; @@ -443,12 +442,13 @@ pub(crate) fn wasm_printer_pair( #[cfg(test)] mod tests { - use super::*; use ironrdp::rdpdr::pdu::efs::{ CreateDisposition, CreateOptions, DesiredAccess, DeviceCloseRequest, DeviceCreateRequest, DeviceIoRequest, DeviceWriteRequest, FileAttributes, MajorFunction, MinorFunction, SharedAccess, }; + use super::*; + const DEVICE_ID: u32 = 42; fn printer_backend() -> (WasmPrinterBackend, mpsc::UnboundedReceiver) {