1use core::mcs;
2use core::license;
3use core::tpkt;
4use model::error::{RdpResult, Error, RdpError, RdpErrorKind};
5use model::data::{Message, Component, U16, U32, DynOption, MessageOption, Trame, DataType};
6use std::io::{Write, Read};
7use model::unicode::Unicode;
8
9#[repr(u16)]
12#[allow(dead_code)]
13enum SecurityFlag {
14 SecExchangePkt = 0x0001,
15 SecTransportReq = 0x0002,
16 RdpSecTransportRsp = 0x0004,
17 SecEncrypt = 0x0008,
18 SecResetSeqno = 0x0010,
19 SecIgnoreSeqno = 0x0020,
20 SecInfoPkt = 0x0040,
21 SecLicensePkt = 0x0080,
22 SecLicenseEncryptCs = 0x0200,
23 SecRedirectionPkt = 0x0400,
24 SecSecureChecksum = 0x0800,
25 SecAutodetectReq = 0x1000,
26 SecAutodetectRsp = 0x2000,
27 SecHeartbeat = 0x4000,
28 SecFlagshiValid = 0x8000
29}
30
31#[allow(dead_code)]
34enum InfoFlag {
35 InfoMouse = 0x00000001,
36 InfoDisablectrlaltdel = 0x00000002,
37 InfoAutologon = 0x00000008,
38 InfoUnicode = 0x00000010,
39 InfoMaximizeshell = 0x00000020,
40 InfoLogonnotify = 0x00000040,
41 InfoCompression = 0x00000080,
42 InfoEnablewindowskey = 0x00000100,
43 InfoRemoteconsoleaudio = 0x00002000,
44 InfoForceEncryptedCsPdu = 0x00004000,
45 InfoRail = 0x00008000,
46 InfoLogonerrors = 0x00010000,
47 InfoMouseHasWheel = 0x00020000,
48 InfoPasswordIsScPin = 0x00040000,
49 InfoNoaudioplayback = 0x00080000,
50 InfoUsingSavedCreds = 0x00100000,
51 InfoAudiocapture = 0x00200000,
52 InfoVideoDisable = 0x00400000,
53 InfoCompressionTypeMask = 0x00001E00
54}
55
56#[allow(dead_code)]
57enum AfInet {
58 AfInet = 0x00002,
59 AfInet6 = 0x0017
60}
61
62fn rdp_extended_infos() -> Component {
65 component![
66 "clientAddressFamily" => U16::LE(AfInet::AfInet as u16),
67 "cbClientAddress" => DynOption::new(U16::LE(0), |x| MessageOption::Size("clientAddress".to_string(), x.inner() as usize + 2)),
68 "clientAddress" => b"\x00\x00".to_vec(),
69 "cbClientDir" => U16::LE(0),
70 "clientDir" => b"\x00\x00".to_vec(),
71 "clientTimeZone" => vec![0; 172],
72 "clientSessionId" => U32::LE(0),
73 "performanceFlags" => U32::LE(0)
74 ]
75}
76
77fn rdp_infos(is_extended_info: bool, domain: &String, username: &String, password: &String, auto_logon: bool) -> Component {
81 let mut domain_format = domain.to_unicode();
82 domain_format.push(0);
83 domain_format.push(0);
84
85 let mut username_format = username.to_unicode();
86 username_format.push(0);
87 username_format.push(0);
88
89 let mut password_format = password.to_unicode();
90 password_format.push(0);
91 password_format.push(0);
92
93 component![
94 "codePage" => U32::LE(0),
95 "flag" => U32::LE(
96 InfoFlag::InfoMouse as u32 |
97 InfoFlag::InfoUnicode as u32 |
98 InfoFlag::InfoLogonnotify as u32 |
99 InfoFlag::InfoLogonerrors as u32 |
100 InfoFlag::InfoDisablectrlaltdel as u32 |
101 InfoFlag::InfoEnablewindowskey as u32 |
102 if auto_logon { InfoFlag::InfoAutologon as u32 } else { 0 }
103 ),
104 "cbDomain" => U16::LE((domain_format.len() - 2) as u16),
105 "cbUserName" => U16::LE((username_format.len() - 2) as u16),
106 "cbPassword" => U16::LE((password_format.len() - 2) as u16),
107 "cbAlternateShell" => U16::LE(0),
108 "cbWorkingDir" => U16::LE(0),
109 "domain" => domain_format,
110 "userName" => username_format,
111 "password" => password_format,
112 "alternateShell" => b"\x00\x00".to_vec(),
113 "workingDir" => b"\x00\x00".to_vec(),
114 "extendedInfos" => if is_extended_info { rdp_extended_infos() } else { component![] }
115 ]
116}
117
118fn security_header() -> Component {
120 component![
121 "securityFlag" => U16::LE(0),
122 "securityFlagHi" => U16::LE(0)
123 ]
124}
125
126
127pub fn connect<T: Read + Write>(mcs: &mut mcs::Client<T>, domain: &String, username: &String, password: &String, auto_logon: bool) -> RdpResult<()> {
140 mcs.write(
141 &"global".to_string(),
142 trame![
143 U16::LE(SecurityFlag::SecInfoPkt as u16),
144 U16::LE(0),
145 rdp_infos(
146 mcs.is_rdp_version_5_plus(),
147 domain,
148 username,
149 password,
150 auto_logon
151 )
152 ]
153 )?;
154
155 let (_channel_name, payload) = mcs.read()?;
156 let mut stream = try_let!(tpkt::Payload::Raw, payload)?;
157 let mut header = security_header();
158 header.read(&mut stream)?;
159 if cast!(DataType::U16, header["securityFlag"])? & SecurityFlag::SecLicensePkt as u16 == 0 {
160 return Err(Error::RdpError(RdpError::new(RdpErrorKind::InvalidData, "SEC: Invalid Licence packet")));
161 }
162
163 license::client_connect(&mut stream)?;
164 Ok(())
165}
166
167