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}