ironrdp_pdu/rdp/
session_info.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::io;

use ironrdp_core::{
    ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
    WriteCursor,
};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive as _, ToPrimitive as _};
use thiserror::Error;

use crate::PduError;

#[cfg(test)]
mod tests;

mod logon_extended;
mod logon_info;

pub use self::logon_extended::{
    LogonErrorNotificationData, LogonErrorNotificationDataErrorCode, LogonErrorNotificationType, LogonErrorsInfo,
    LogonExFlags, LogonInfoExtended, ServerAutoReconnect,
};
pub use self::logon_info::{LogonInfo, LogonInfoVersion1, LogonInfoVersion2};

const INFO_TYPE_FIELD_SIZE: usize = 4;
const PLAIN_NOTIFY_PADDING_SIZE: usize = 576;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SaveSessionInfoPdu {
    pub info_type: InfoType,
    pub info_data: InfoData,
}

impl SaveSessionInfoPdu {
    const NAME: &'static str = "SaveSessionInfoPdu";

    const FIXED_PART_SIZE: usize = INFO_TYPE_FIELD_SIZE;
}

impl Encode for SaveSessionInfoPdu {
    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
        ensure_fixed_part_size!(in: dst);

        dst.write_u32(self.info_type.to_u32().unwrap());
        match self.info_data {
            InfoData::LogonInfoV1(ref info_v1) => {
                info_v1.encode(dst)?;
            }
            InfoData::LogonInfoV2(ref info_v2) => {
                info_v2.encode(dst)?;
            }
            InfoData::PlainNotify => {
                ensure_size!(in: dst, size: PLAIN_NOTIFY_PADDING_SIZE);
                write_padding!(dst, PLAIN_NOTIFY_PADDING_SIZE);
            }
            InfoData::LogonExtended(ref extended) => {
                extended.encode(dst)?;
            }
        }

        Ok(())
    }

    fn name(&self) -> &'static str {
        Self::NAME
    }

    fn size(&self) -> usize {
        let info_data_size = match self.info_data {
            InfoData::LogonInfoV1(ref info_v1) => info_v1.size(),
            InfoData::LogonInfoV2(ref info_v2) => info_v2.size(),
            InfoData::PlainNotify => PLAIN_NOTIFY_PADDING_SIZE,
            InfoData::LogonExtended(ref extended) => extended.size(),
        };

        Self::FIXED_PART_SIZE + info_data_size
    }
}

impl<'de> Decode<'de> for SaveSessionInfoPdu {
    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
        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"))?;

        let info_data = match info_type {
            InfoType::Logon => InfoData::LogonInfoV1(LogonInfoVersion1::decode(src)?),
            InfoType::LogonLong => InfoData::LogonInfoV2(LogonInfoVersion2::decode(src)?),
            InfoType::PlainNotify => {
                ensure_size!(in: src, size: PLAIN_NOTIFY_PADDING_SIZE);
                read_padding!(src, PLAIN_NOTIFY_PADDING_SIZE);

                InfoData::PlainNotify
            }
            InfoType::LogonExtended => InfoData::LogonExtended(LogonInfoExtended::decode(src)?),
        };

        Ok(Self { info_type, info_data })
    }
}

#[repr(u32)]
#[derive(Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum InfoType {
    Logon = 0x0000_0000,
    LogonLong = 0x0000_0001,
    PlainNotify = 0x0000_0002,
    LogonExtended = 0x0000_0003,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InfoData {
    LogonInfoV1(LogonInfoVersion1),
    LogonInfoV2(LogonInfoVersion2),
    PlainNotify,
    LogonExtended(LogonInfoExtended),
}

#[derive(Debug, Error)]
pub enum SessionError {
    #[error("IO error")]
    IOError(#[from] io::Error),
    #[error("invalid save session info type value")]
    InvalidSaveSessionInfoType,
    #[error("invalid domain name size value")]
    InvalidDomainNameSize,
    #[error("invalid user name size value")]
    InvalidUserNameSize,
    #[error("invalid logon version value")]
    InvalidLogonVersion2,
    #[error("invalid logon info version2 size value")]
    InvalidLogonVersion2Size,
    #[error("invalid server auto-reconnect packet size value")]
    InvalidAutoReconnectPacketSize,
    #[error("invalid server auto-reconnect version")]
    InvalidAutoReconnectVersion,
    #[error("invalid logon error type value")]
    InvalidLogonErrorType,
    #[error("invalid logon error data value")]
    InvalidLogonErrorData,
    #[error("PDU error: {0}")]
    Pdu(PduError),
}

impl From<PduError> for SessionError {
    fn from(e: PduError) -> Self {
        Self::Pdu(e)
    }
}