ironrdp_pdu/rdp/
session_info.rs1use std::io;
2
3use ironrdp_core::{
4 ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode, DecodeResult, Encode,
5 EncodeResult, ReadCursor, WriteCursor,
6};
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9use thiserror::Error;
10
11use crate::PduError;
12
13#[cfg(test)]
14mod tests;
15
16mod logon_extended;
17mod logon_info;
18
19pub use self::logon_extended::{
20 LogonErrorNotificationData, LogonErrorNotificationDataErrorCode, LogonErrorNotificationType, LogonErrorsInfo,
21 LogonExFlags, LogonInfoExtended, ServerAutoReconnect,
22};
23pub use self::logon_info::{LogonInfo, LogonInfoVersion1, LogonInfoVersion2};
24
25const INFO_TYPE_FIELD_SIZE: usize = 4;
26const PLAIN_NOTIFY_PADDING_SIZE: usize = 576;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct SaveSessionInfoPdu {
30 pub info_type: InfoType,
31 pub info_data: InfoData,
32}
33
34impl SaveSessionInfoPdu {
35 const NAME: &'static str = "SaveSessionInfoPdu";
36
37 const FIXED_PART_SIZE: usize = INFO_TYPE_FIELD_SIZE;
38}
39
40impl Encode for SaveSessionInfoPdu {
41 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
42 ensure_fixed_part_size!(in: dst);
43
44 dst.write_u32(self.info_type.to_u32().unwrap());
45 match self.info_data {
46 InfoData::LogonInfoV1(ref info_v1) => {
47 info_v1.encode(dst)?;
48 }
49 InfoData::LogonInfoV2(ref info_v2) => {
50 info_v2.encode(dst)?;
51 }
52 InfoData::PlainNotify => {
53 ensure_size!(in: dst, size: PLAIN_NOTIFY_PADDING_SIZE);
54 write_padding!(dst, PLAIN_NOTIFY_PADDING_SIZE);
55 }
56 InfoData::LogonExtended(ref extended) => {
57 extended.encode(dst)?;
58 }
59 }
60
61 Ok(())
62 }
63
64 fn name(&self) -> &'static str {
65 Self::NAME
66 }
67
68 fn size(&self) -> usize {
69 let info_data_size = match self.info_data {
70 InfoData::LogonInfoV1(ref info_v1) => info_v1.size(),
71 InfoData::LogonInfoV2(ref info_v2) => info_v2.size(),
72 InfoData::PlainNotify => PLAIN_NOTIFY_PADDING_SIZE,
73 InfoData::LogonExtended(ref extended) => extended.size(),
74 };
75
76 Self::FIXED_PART_SIZE + info_data_size
77 }
78}
79
80impl<'de> Decode<'de> for SaveSessionInfoPdu {
81 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
82 ensure_fixed_part_size!(in: src);
83
84 let info_type = InfoType::from_u32(src.read_u32())
85 .ok_or_else(|| invalid_field_err!("infoType", "invalid save session info type"))?;
86
87 let info_data = match info_type {
88 InfoType::Logon => InfoData::LogonInfoV1(LogonInfoVersion1::decode(src)?),
89 InfoType::LogonLong => InfoData::LogonInfoV2(LogonInfoVersion2::decode(src)?),
90 InfoType::PlainNotify => {
91 ensure_size!(in: src, size: PLAIN_NOTIFY_PADDING_SIZE);
92 read_padding!(src, PLAIN_NOTIFY_PADDING_SIZE);
93
94 InfoData::PlainNotify
95 }
96 InfoType::LogonExtended => InfoData::LogonExtended(LogonInfoExtended::decode(src)?),
97 };
98
99 Ok(Self { info_type, info_data })
100 }
101}
102
103#[repr(u32)]
104#[derive(Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
105pub enum InfoType {
106 Logon = 0x0000_0000,
107 LogonLong = 0x0000_0001,
108 PlainNotify = 0x0000_0002,
109 LogonExtended = 0x0000_0003,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub enum InfoData {
114 LogonInfoV1(LogonInfoVersion1),
115 LogonInfoV2(LogonInfoVersion2),
116 PlainNotify,
117 LogonExtended(LogonInfoExtended),
118}
119
120#[derive(Debug, Error)]
121pub enum SessionError {
122 #[error("IO error")]
123 IOError(#[from] io::Error),
124 #[error("invalid save session info type value")]
125 InvalidSaveSessionInfoType,
126 #[error("invalid domain name size value")]
127 InvalidDomainNameSize,
128 #[error("invalid user name size value")]
129 InvalidUserNameSize,
130 #[error("invalid logon version value")]
131 InvalidLogonVersion2,
132 #[error("invalid logon info version2 size value")]
133 InvalidLogonVersion2Size,
134 #[error("invalid server auto-reconnect packet size value")]
135 InvalidAutoReconnectPacketSize,
136 #[error("invalid server auto-reconnect version")]
137 InvalidAutoReconnectVersion,
138 #[error("invalid logon error type value")]
139 InvalidLogonErrorType,
140 #[error("invalid logon error data value")]
141 InvalidLogonErrorData,
142 #[error("PDU error: {0}")]
143 Pdu(PduError),
144}
145
146impl From<PduError> for SessionError {
147 fn from(e: PduError) -> Self {
148 Self::Pdu(e)
149 }
150}