ironrdp_pdu/rdp/
session_info.rs

1use 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}