ironrdp_pdu/gcc/core_data/
server.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
use bitflags::bitflags;
use ironrdp_core::{
    ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
    WriteCursor,
};
use tap::Pipe as _;

use super::RdpVersion;
use crate::nego::SecurityProtocol;

const CLIENT_REQUESTED_PROTOCOL_SIZE: usize = 4;
const EARLY_CAPABILITY_FLAGS_SIZE: usize = 4;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServerCoreData {
    pub version: RdpVersion,
    pub optional_data: ServerCoreOptionalData,
}

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

    const FIXED_PART_SIZE: usize = 4 /* rdpVersion */;
}

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

        dst.write_u32(self.version.0);
        self.optional_data.encode(dst)
    }

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

    fn size(&self) -> usize {
        Self::FIXED_PART_SIZE + self.optional_data.size()
    }
}

impl<'de> Decode<'de> for ServerCoreData {
    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
        ensure_fixed_part_size!(in: src);

        let version = src.read_u32().pipe(RdpVersion);
        let optional_data = ServerCoreOptionalData::decode(src)?;

        Ok(Self { version, optional_data })
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ServerCoreOptionalData {
    pub client_requested_protocols: Option<SecurityProtocol>,
    pub early_capability_flags: Option<ServerEarlyCapabilityFlags>,
}

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

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

        if let Some(value) = self.client_requested_protocols {
            dst.write_u32(value.bits());
        };

        if let Some(value) = self.early_capability_flags {
            dst.write_u32(value.bits());
        }

        Ok(())
    }

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

    fn size(&self) -> usize {
        let mut size = 0;

        if self.client_requested_protocols.is_some() {
            size += CLIENT_REQUESTED_PROTOCOL_SIZE;
        }
        if self.early_capability_flags.is_some() {
            size += EARLY_CAPABILITY_FLAGS_SIZE;
        }

        size
    }
}

macro_rules! try_or_return {
    ($expr:expr, $ret:expr) => {
        match $expr {
            Ok(v) => v,
            Err(_) => return Ok($ret),
        }
    };
}

impl<'de> Decode<'de> for ServerCoreOptionalData {
    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
        let mut optional_data = Self::default();

        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"))?,
        );

        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(optional_data)
    }
}

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct ServerEarlyCapabilityFlags: u32 {
        const EDGE_ACTIONS_SUPPORTED_V1 = 0x0000_0001;
        const DYNAMIC_DST_SUPPORTED = 0x0000_0002;
        const EDGE_ACTIONS_SUPPORTED_V2 = 0x0000_0004;
        const SKIP_CHANNELJOIN_SUPPORTED = 0x0000_0008;
        // The source may set any bits
        const _ = !0;
    }
}