rdp/core/tpkt.rs
1use model::link::{Link};
2use model::data::{Message, U16, Component, Trame};
3use model::error::{RdpResult, RdpError, RdpErrorKind, Error};
4use std::io::{Cursor, Write, Read};
5use nla::cssp::cssp_connect;
6use nla::sspi::AuthenticationProtocol;
7
8/// TPKT must implement this two kind of payload
9pub enum Payload {
10 Raw(Cursor<Vec<u8>>),
11 FastPath(u8, Cursor<Vec<u8>>)
12}
13
14/// TPKT action header
15/// # see : https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/b8e7c588-51cb-455b-bb73-92d480903133
16/// # see : https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/68b5ee54-d0d5-4d65-8d81-e1c4025f7597
17#[derive(Copy, Clone)]
18pub enum Action {
19 FastPathActionFastPath = 0x0,
20 FastPathActionX224 = 0x3
21}
22
23/// TPKT layer header
24///
25/// This the header layout of any RDP packet
26fn tpkt_header(size: u16) -> Component {
27 component![
28 "action" => Action::FastPathActionX224 as u8,
29 "flag" => 0 as u8,
30 "size" => U16::BE(size + 4)
31 ]
32}
33
34/// Client Context of TPKT layer
35///
36/// # Example
37/// ```
38/// use std::io::Cursor;
39/// use rdp::model::link::{Link, Stream};
40/// use rdp::core::tpkt::Client;
41/// let mut stream = Cursor::new(vec![]);
42/// let tpkt_client = Client::new(Link::new(Stream::Raw(stream)));
43/// ```
44pub struct Client<S> {
45 transport: Link<S>
46}
47
48impl<S: Read + Write> Client<S> {
49 /// Ctor of TPKT client layer
50 pub fn new (transport: Link<S>) -> Self {
51 Client {
52 transport
53 }
54 }
55
56 /// Send a message to the link layer
57 /// with appropriate header
58 /// Move to avoid copy
59 ///
60 /// # Example
61 /// ```
62 /// #[macro_use]
63 /// # extern crate rdp;
64 /// # use rdp::core::tpkt;
65 /// # use rdp::model::link;
66 /// # use std::io::Cursor;
67 /// # use rdp::model::data::{U16, Trame, U32};
68 /// # fn main() {
69 /// let mut tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![]))));
70 /// tpkt.write(trame![U16::BE(4), U32::LE(3)]).unwrap();
71 /// // get_link and get_stream are not available on Crate
72 /// // only use for integration test [features = integration]
73 /// if let link::Stream::Raw(e) = tpkt.get_link().get_stream() {
74 /// assert_eq!(e.into_inner(), [3, 0, 0, 10, 0, 4, 3, 0, 0, 0])
75 /// }
76 /// else {
77 /// panic!("Must not happen")
78 /// }
79 /// }
80 /// ```
81 pub fn write<T: 'static>(&mut self, message: T) -> RdpResult<()>
82 where T: Message {
83 self.transport.write(
84 &trame![
85 tpkt_header(message.length() as u16),
86 message
87 ]
88 )
89 }
90
91 /// Read a payload from the underlying layer
92 /// Check the tpkt header and provide a well
93 /// formed payload
94 ///
95 /// # Example
96 /// ```
97 /// use rdp::core::tpkt;
98 /// use rdp::model::link;
99 /// use std::io::Cursor;
100 /// let mut tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![3, 0, 0, 10, 0, 4, 3, 0, 0, 0]))));
101 /// if let tpkt::Payload::Raw(c) = tpkt.read().unwrap() {
102 /// assert_eq!(c.into_inner(), vec![0, 4, 3, 0, 0, 0])
103 /// }
104 /// else {
105 /// panic!("unexpected result")
106 /// }
107 ///
108 /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 6, 0, 0, 0, 0]))));
109 /// if let tpkt::Payload::FastPath(_, c) = tpkt.read().unwrap() {
110 /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0])
111 /// }
112 /// else {
113 /// panic!("unexpected result")
114 /// }
115 ///
116 /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 0x80, 7, 0, 0, 0, 0]))));
117 /// if let tpkt::Payload::FastPath(_, c) = tpkt.read().unwrap() {
118 /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0])
119 /// }
120 /// else {
121 /// panic!("unexpected result")
122 /// }
123 /// ```
124 pub fn read(&mut self) -> RdpResult<Payload> {
125 let mut buffer = Cursor::new(self.transport.read(2)?);
126 let mut action: u8 = 0;
127 action.read(&mut buffer)?;
128 if action == Action::FastPathActionX224 as u8 {
129
130 // read padding
131 let mut padding: u8 = 0;
132 padding.read(&mut buffer)?;
133 // now wait extended header
134 buffer = Cursor::new(self.transport.read(2)?);
135
136 let mut size = U16::BE(0);
137 size.read(&mut buffer)?;
138
139 // now wait for body
140 Ok(Payload::Raw(Cursor::new(self.transport.read(size.inner() as usize - 4)?)))
141
142 } else {
143 // fast path
144 let sec_flag = (action >> 6) & 0x3;
145 let mut short_length: u8 = 0;
146 short_length.read(&mut buffer)?;
147 if short_length & 0x80 != 0 {
148 let mut hi_length: u8 = 0;
149 hi_length.read(&mut Cursor::new(self.transport.read(1)?))?;
150 let length :u16 = ((short_length & !0x80) as u16) << 8;
151 let length = length | hi_length as u16;
152 Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(length as usize - 3)?)))
153 }
154 else {
155 Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(short_length as usize - 2)?)))
156 }
157 }
158 }
159
160 /// This function transform the link layer with
161 /// raw data stream into a SSL data stream
162 ///
163 /// # Example
164 /// ```no_run
165 /// use std::net::{SocketAddr, TcpStream};
166 /// use rdp::core::tpkt;
167 /// use rdp::model::link;
168 /// let addr = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
169 /// let mut tcp = TcpStream::connect(&addr).unwrap();
170 /// let mut tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(tcp)));
171 /// let mut tpkt_ssl = tpkt.start_ssl(false).unwrap();
172 /// ```
173 pub fn start_ssl(self, check_certificate: bool) -> RdpResult<Client<S>> {
174 Ok(Client::new(self.transport.start_ssl(check_certificate)?))
175 }
176
177 /// This function is used when NLA (Network Level Authentication)
178 /// Authentication is negotiated
179 ///
180 /// # Example
181 /// ```no_run
182 /// use std::net::{SocketAddr, TcpStream};
183 /// use rdp::core::tpkt;
184 /// use rdp::nla::ntlm::Ntlm;
185 /// use rdp::model::link;
186 /// let addr = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
187 /// let mut tcp = TcpStream::connect(&addr).unwrap();
188 /// let mut tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(tcp)));
189 /// let mut tpkt_nla = tpkt.start_nla(false, &mut Ntlm::new("domain".to_string(), "username".to_string(), "password".to_string()), false);
190 /// ```
191 pub fn start_nla(self, check_certificate: bool, authentication_protocol: &mut dyn AuthenticationProtocol, restricted_admin_mode: bool) -> RdpResult<Client<S>> {
192 let mut link = self.transport.start_ssl(check_certificate)?;
193 cssp_connect(&mut link, authentication_protocol, restricted_admin_mode)?;
194 Ok(Client::new(link))
195 }
196
197 /// Shutdown current connection
198 pub fn shutdown(&mut self) -> RdpResult<()> {
199 self.transport.shutdown()
200 }
201
202 #[cfg(feature = "integration")]
203 pub fn get_link(self) -> Link<S> {
204 self.transport
205 }
206}
207
208#[cfg(test)]
209mod test {
210 use super::*;
211 use std::io::Cursor;
212 use model::data::{U32, DataType};
213
214 /// Test the tpkt header type in write context
215 #[test]
216 fn test_write_tpkt_header() {
217 let x = U32::BE(1);
218 let message = trame![
219 tpkt_header(x.length() as u16),
220 x
221 ];
222 let mut buffer = Cursor::new(Vec::new());
223 message.write(&mut buffer).unwrap();
224 assert_eq!(buffer.get_ref().as_slice(), [3, 0, 0, 8, 0, 0, 0, 1]);
225 }
226
227 /// Test read of TPKT header
228 #[test]
229 fn test_read_tpkt_header() {
230 let mut message = tpkt_header(0);
231 let mut buffer = Cursor::new([3, 0, 0, 8, 0, 0, 0, 1]);
232 message.read(&mut buffer).unwrap();
233 assert_eq!(cast!(DataType::U16, message["size"]).unwrap(), 8);
234 assert_eq!(cast!(DataType::U8, message["action"]).unwrap(), Action::FastPathActionX224 as u8);
235 }
236}