rdp/core/client.rs
1use core::x224;
2use core::gcc::KeyboardLayout;
3use core::mcs;
4use core::tpkt;
5use core::sec;
6use core::global;
7use std::io::{Read, Write};
8use model::error::{RdpResult, Error, RdpError, RdpErrorKind};
9use model::link::{Link, Stream};
10use core::event::{RdpEvent, PointerButton};
11use core::global::{ts_pointer_event, PointerFlag, ts_keyboard_event, KeyboardFlag};
12use nla::ntlm::Ntlm;
13
14impl From<&str> for KeyboardLayout {
15 fn from(e: &str) -> Self {
16 match e {
17 "us" => KeyboardLayout::US,
18 "fr" => KeyboardLayout::French,
19 _ => KeyboardLayout::US,
20 }
21 }
22}
23
24pub struct RdpClient<S> {
25 /// Multi channel
26 /// This is the main switch layer of the protocol
27 mcs: mcs::Client<S>,
28 /// Global channel that implement the basic layer
29 global: global::Client
30}
31
32impl<S: Read + Write> RdpClient<S> {
33 /// Read a payload from the server
34 /// RDpClient use a callback pattern that can be called more than once
35 /// during a read call
36 ///
37 /// # Example
38 /// ```no_run
39 /// use std::net::{SocketAddr, TcpStream};
40 /// use rdp::core::client::Connector;
41 /// use rdp::core::event::RdpEvent;
42 /// let addr = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
43 /// let tcp = TcpStream::connect(&addr).unwrap();
44 /// let mut connector = Connector::new()
45 /// .screen(800, 600)
46 /// .credentials("domain".to_string(), "username".to_string(), "password".to_string());
47 /// let mut client = connector.connect(tcp).unwrap();
48 /// client.read(|rdp_event| {
49 /// match rdp_event {
50 /// RdpEvent::Bitmap(bitmap) => {
51 /// // do something with bitmap
52 /// }
53 /// _ => println!("Unhandled event")
54 /// }
55 /// }).unwrap()
56 /// ```
57 pub fn read<T>(&mut self, callback: T) -> RdpResult<()>
58 where T: FnMut(RdpEvent) {
59 let (channel_name, message) = self.mcs.read()?;
60 match channel_name.as_str() {
61 "global" => self.global.read(message, &mut self.mcs, callback),
62 _ => Err(Error::RdpError(RdpError::new(RdpErrorKind::UnexpectedType, &format!("Invalid channel name {:?}", channel_name))))
63 }
64 }
65
66 /// Write an event to the server
67 /// Typically is all about input event like mouse and keyboard
68 ///
69 /// # Example
70 /// ```no_run
71 /// use std::net::{SocketAddr, TcpStream};
72 /// use rdp::core::client::Connector;
73 /// use rdp::core::event::{RdpEvent, PointerEvent, PointerButton};
74 /// let addr = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
75 /// let tcp = TcpStream::connect(&addr).unwrap();
76 /// let mut connector = Connector::new()
77 /// .screen(800, 600)
78 /// .credentials("domain".to_string(), "username".to_string(), "password".to_string());
79 /// let mut client = connector.connect(tcp).unwrap();
80 /// client.write(RdpEvent::Pointer(
81 /// // Send a mouse click down at 100x100
82 /// PointerEvent {
83 /// x: 100 as u16,
84 /// y: 100 as u16,
85 /// button: PointerButton::Left,
86 /// down: true
87 /// }
88 /// )).unwrap()
89 /// ```
90 pub fn write(&mut self, event: RdpEvent) -> RdpResult<()> {
91 match event {
92 // Pointer event
93 // Mouse position an d button position
94 RdpEvent::Pointer(pointer) => {
95 // Pointer are sent to global channel
96 // Compute flags
97 let mut flags: u16 = 0;
98 match pointer.button {
99 PointerButton::Left => flags |= PointerFlag::PtrflagsButton1 as u16,
100 PointerButton::Right => flags |= PointerFlag::PtrflagsButton2 as u16,
101 PointerButton::Middle => flags |= PointerFlag::PtrflagsButton3 as u16,
102 _ => flags |= PointerFlag::PtrflagsMove as u16,
103 }
104
105 if pointer.down {
106 flags |= PointerFlag::PtrflagsDown as u16;
107 }
108
109 self.global.write_input_event(ts_pointer_event(Some(flags), Some(pointer.x), Some(pointer.y)), &mut self.mcs)
110 },
111 // Raw keyboard input
112 RdpEvent::Key(key) => {
113 let mut flags: u16 = 0;
114 if !key.down {
115 flags |= KeyboardFlag::KbdflagsRelease as u16;
116 }
117 self.global.write_input_event(ts_keyboard_event(Some(flags), Some(key.code)), &mut self.mcs)
118 }
119 _ => Err(Error::RdpError(RdpError::new(RdpErrorKind::UnexpectedType, "RDPCLIENT: This event can't be sent")))
120 }
121 }
122
123 /// Close client is indeed close the switch layer
124 pub fn shutdown(&mut self) -> RdpResult<()> {
125 self.mcs.shutdown()
126 }
127}
128
129pub struct Connector {
130 /// Screen width
131 width: u16,
132 /// Screen height
133 height: u16,
134 /// Keyboard layout
135 layout: KeyboardLayout,
136 /// Restricted admin mode
137 /// This mode protect againt credential forward
138 restricted_admin_mode: bool,
139 /// Microsoft Domain
140 /// If you don't care keep empty
141 domain: String,
142 /// Username
143 username: String,
144 /// Password
145 password: String,
146 /// When you only want to pass the hash
147 password_hash: Option<Vec<u8>>,
148 /// Set autologon flags during security logon
149 auto_logon: bool,
150 /// Do not send creds to CredSSP
151 blank_creds: bool,
152 /// When using SSL check or not
153 /// the certificate during SSL handshake
154 check_certificate: bool,
155 /// Client name exposed to the server
156 name: String,
157 /// Use network level authentication
158 /// default TRUE
159 use_nla: bool
160}
161
162impl Connector {
163 /// Create a new RDP client
164 /// You can configure your client
165 ///
166 /// # Example
167 /// ```no_run
168 /// use rdp::core::client::Connector;
169 /// let mut connector = Connector::new()
170 /// .screen(800, 600)
171 /// .credentials("domain".to_string(), "username".to_string(), "password".to_string());
172 /// ```
173 pub fn new() -> Self {
174 Connector {
175 width: 800,
176 height: 600,
177 layout: KeyboardLayout::US,
178 restricted_admin_mode: false,
179 domain: "".to_string(),
180 username: "".to_string(),
181 password: "".to_string(),
182 password_hash: None,
183 auto_logon: false,
184 blank_creds: false,
185 check_certificate: false,
186 name: "rdp-rs".to_string(),
187 use_nla: true
188 }
189 }
190
191 /// Connect to a target server
192 /// This function will produce a RdpClient object
193 /// use to interact with server
194 ///
195 /// # Example
196 /// ```no_run
197 /// use std::net::{SocketAddr, TcpStream};
198 /// use rdp::core::client::Connector;
199 /// let addr = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
200 /// let tcp = TcpStream::connect(&addr).unwrap();
201 /// let mut connector = Connector::new()
202 /// .screen(800, 600)
203 /// .credentials("domain".to_string(), "username".to_string(), "password".to_string());
204 /// let mut client = connector.connect(tcp).unwrap();
205 /// ```
206 pub fn connect<S: Read + Write>(&mut self, stream: S) -> RdpResult<RdpClient<S>> {
207
208 // Create a wrapper around the stream
209 let tcp = Link::new( Stream::Raw(stream));
210
211 // Compute authentication method
212 let mut authentication = if let Some(hash) = &self.password_hash {
213 Ntlm::from_hash(self.domain.clone(), self.username.clone(), hash)
214 }
215 else {
216 Ntlm::new(self.domain.clone(), self.username.clone(), self.password.clone())
217 };
218 // Create the x224 layer
219 // With all negotiated security stuff and credentials
220 let mut protocols = x224::Protocols::ProtocolSSL as u32;
221 if self.use_nla {
222 protocols |= x224::Protocols::ProtocolHybrid as u32
223 }
224
225 let x224 = x224::Client::connect(
226 tpkt::Client::new(tcp),
227 protocols,
228 self.check_certificate,
229 Some(&mut authentication),
230 self.restricted_admin_mode,
231 self.blank_creds
232 )?;
233
234 // Create MCS layer and connect it
235 let mut mcs = mcs::Client::new(x224);
236 mcs.connect(self.name.clone(), self.width, self.height, self.layout)?;
237 // state less connection for old secure layer
238 if self.restricted_admin_mode {
239 sec::connect(
240 &mut mcs,
241 &"".to_string(),
242 &"".to_string(),
243 &"".to_string(),
244 self.auto_logon
245 )?;
246 } else {
247 sec::connect(
248 &mut mcs,
249 &self.domain,
250 &self.username,
251 &self.password,
252 self.auto_logon
253 )?;
254 }
255
256 // Now the global channel
257 let global = global::Client::new(
258 mcs.get_user_id(),
259 mcs.get_global_channel_id(),
260 self.width,
261 self.height,
262 self.layout,
263 &self.name
264 );
265
266 Ok(RdpClient {
267 mcs,
268 global
269 })
270 }
271
272 /// Configure the screen size of the session
273 /// You need to set a power of two definition
274 pub fn screen(mut self, width: u16, height: u16) -> Self {
275 self.width = width;
276 self.height = height;
277 self
278 }
279
280 /// Configure credentials for the session
281 /// Credentials use to logon on server
282 pub fn credentials(mut self, domain: String, username: String, password: String) -> Self {
283 self.domain = domain;
284 self.username = username;
285 self.password = password;
286 self
287 }
288
289 /// Enable or disable restricted admin mode
290 pub fn set_restricted_admin_mode(mut self, state: bool) -> Self {
291 self.restricted_admin_mode = state;
292 self
293 }
294
295 /// Try authenticate using NTLM hashes and restricted admin mode
296 pub fn set_password_hash(mut self, password_hash: Vec<u8>) -> Self {
297 self.password_hash = Some(password_hash);
298 self
299 }
300
301 /// Set the keyboard layout
302 pub fn layout(mut self, layout: KeyboardLayout) -> Self {
303 self.layout = layout;
304 self
305 }
306
307 /// Switch on the AutoLogon flag
308 pub fn auto_logon(mut self, auto_logon: bool) -> Self {
309 self.auto_logon = auto_logon;
310 self
311 }
312
313 /// Send blank creds at the end of CRedSSP
314 pub fn blank_creds(mut self, blank_creds: bool) -> Self {
315 self.blank_creds = blank_creds;
316 self
317 }
318
319 /// Enable or not the check of SSL certificate
320 pub fn check_certificate(mut self, check_certificate: bool) -> Self {
321 self.check_certificate = check_certificate;
322 self
323 }
324
325 /// Set the default name send to server
326 pub fn name(mut self, name: String) -> Self {
327 self.name = name;
328 self
329 }
330
331 /// Enable or disable Network Level Authentication
332 pub fn use_nla(mut self, use_nla: bool) -> Self {
333 self.use_nla = use_nla;
334 self
335 }
336}