/src/suricata7/rust/src/rdp/parser.rs
Line | Count | Source |
1 | | /* Copyright (C) 2019 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | // Author: Zach Kelly <zach.kelly@lmco.com> |
19 | | |
20 | | //! RDP parser |
21 | | //! |
22 | | //! References: |
23 | | //! * rdp-spec: <https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/> |
24 | | //! * t.123-spec: <https://www.itu.int/rec/T-REC-T.123-200701-I/en> |
25 | | //! * t.125-spec: <https://www.itu.int/rec/T-REC-T.125-199802-I/en> |
26 | | //! * x.224-spec: <https://www.itu.int/rec/T-REC-X.224-199511-I/en> |
27 | | //! * x.691-spec: <https://www.itu.int/rec/T-REC-X.691/en> |
28 | | |
29 | | use crate::common::nom7::{bits, take_until_and_consume}; |
30 | | use crate::rdp::error::RdpError; |
31 | | use crate::rdp::util::{le_slice_to_string, parse_per_length_determinant, utf7_slice_to_string}; |
32 | | use crate::rdp::windows; |
33 | | use nom7::bits::streaming::take as take_bits; |
34 | | use nom7::bytes::streaming::{tag, take}; |
35 | | use nom7::combinator::{map, map_opt, map_res, opt, verify}; |
36 | | use nom7::error::{make_error, ErrorKind}; |
37 | | use nom7::multi::length_data; |
38 | | use nom7::number::streaming::{be_u16, be_u8, le_u16, le_u32, le_u8}; |
39 | | use nom7::sequence::tuple; |
40 | | use nom7::{Err, IResult}; |
41 | | |
42 | | /// constrains dimension to a range, per spec |
43 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
44 | 4.92k | fn millimeters_to_opt(x: u32) -> Option<u32> { |
45 | 4.92k | if (10..=10_000).contains(&x) { |
46 | 4.44k | Some(x) |
47 | | } else { |
48 | 477 | None |
49 | | } |
50 | 4.92k | } |
51 | | |
52 | | /// constrains desktop scale to a range, per spec |
53 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
54 | 1.40k | fn desktop_scale_to_opt(x: u32) -> Option<u32> { |
55 | 1.40k | if (100..=500).contains(&x) { |
56 | 973 | Some(x) |
57 | | } else { |
58 | 430 | None |
59 | | } |
60 | 1.40k | } |
61 | | |
62 | | /// constrains device scale to a set of valid values, per spec |
63 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
64 | 777 | fn device_scale_to_opt(x: u32) -> Option<u32> { |
65 | 777 | if x == 100 || x == 140 || x == 180 { |
66 | 582 | Some(x) |
67 | | } else { |
68 | 195 | None |
69 | | } |
70 | 777 | } |
71 | | |
72 | | // ================ |
73 | | |
74 | | /// t.123-spec, section 8 |
75 | | #[derive(Clone, Debug, PartialEq, Eq)] |
76 | | pub enum TpktVersion { |
77 | | T123 = 0x3, |
78 | | } |
79 | | |
80 | | /// t.123-spec, section 8 |
81 | | #[derive(Clone, Debug, PartialEq, Eq)] |
82 | | pub struct T123Tpkt { |
83 | | pub child: T123TpktChild, |
84 | | } |
85 | | |
86 | | /// variants that a t.123 tpkt can hold |
87 | | #[derive(Clone, Debug, PartialEq, Eq)] |
88 | | pub enum T123TpktChild { |
89 | | X224ConnectionRequest(X224ConnectionRequest), |
90 | | X224ConnectionConfirm(X224ConnectionConfirm), |
91 | | Data(X223Data), |
92 | | Raw(Vec<u8>), |
93 | | } |
94 | | |
95 | | // ================ |
96 | | |
97 | | /// x.224-spec, sections 13.3.3, 13.4.3, 13.7.3 |
98 | | #[derive(Clone, Debug, PartialEq, Eq)] |
99 | | pub enum X224Type { |
100 | | ConnectionConfirm = 0xd, |
101 | | ConnectionRequest = 0xe, |
102 | | _Data = 0xf, |
103 | | } |
104 | | |
105 | | /// x.224-spec, section 13.3 |
106 | | // rdp-spec, section 2.2.1.1 |
107 | | #[derive(Clone, Debug, PartialEq, Eq)] |
108 | | pub struct X224ConnectionRequest { |
109 | | pub cdt: u8, |
110 | | pub dst_ref: u16, |
111 | | pub src_ref: u16, |
112 | | pub class: u8, |
113 | | pub options: u8, |
114 | | pub cookie: Option<RdpCookie>, |
115 | | pub negotiation_request: Option<NegotiationRequest>, |
116 | | pub data: Vec<u8>, |
117 | | } |
118 | | |
119 | | /// rdp-spec, section 2.2.1.1.1 |
120 | | #[derive(Clone, Debug, PartialEq, Eq)] |
121 | | pub struct RdpCookie { |
122 | | pub mstshash: String, |
123 | | } |
124 | | |
125 | | /// rdp-spec, sections 2.2.1.1.1, 2.2.1.2.1, 2.2.1.2.2 |
126 | | #[derive(Clone, Debug, PartialEq, Eq)] |
127 | | pub enum X224ConnectionRequestType { |
128 | | NegotiationRequest = 0x1, |
129 | | NegotiationResponse = 0x2, |
130 | | NegotiationFailure = 0x3, |
131 | | } |
132 | | |
133 | | /// rdp-spec, section 2.2.1.1.1 |
134 | | #[derive(Clone, Debug, PartialEq, Eq)] |
135 | | pub struct NegotiationRequest { |
136 | | pub flags: NegotiationRequestFlags, |
137 | | pub protocols: ProtocolFlags, |
138 | | } |
139 | | |
140 | | // rdp-spec, section 2.2.1.1.1 |
141 | | bitflags! { |
142 | | #[derive(Default)] |
143 | | pub struct NegotiationRequestFlags: u8 { |
144 | | const RESTRICTED_ADMIN_MODE_REQUIRED = 0x1; |
145 | | const REDIRECTED_AUTHENTICATION_MODE_REQUIRED = 0x2; |
146 | | const CORRELATION_INFO_PRESENT = 0x8; |
147 | | } |
148 | | } |
149 | | |
150 | | /// rdp-spec, section 2.2.1.1.1 |
151 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
152 | | pub enum Protocol { |
153 | | ProtocolRdp = 0x0, |
154 | | ProtocolSsl = 0x1, |
155 | | ProtocolHybrid = 0x2, |
156 | | ProtocolRdsTls = 0x4, |
157 | | ProtocolHybridEx = 0x8, |
158 | | } |
159 | | |
160 | | // rdp-spec, section 2.2.1.1.1 |
161 | | bitflags! { |
162 | | pub struct ProtocolFlags: u32 { |
163 | | //Protocol::ProtocolRdp is 0 as always supported |
164 | | //and bitflags crate does not like zero-bit flags |
165 | | const PROTOCOL_SSL = Protocol::ProtocolSsl as u32; |
166 | | const PROTOCOL_HYBRID = Protocol::ProtocolHybrid as u32; |
167 | | const PROTOCOL_RDSTLS = Protocol::ProtocolRdsTls as u32; |
168 | | const PROTOCOL_HYBRID_EX = Protocol::ProtocolHybridEx as u32; |
169 | | } |
170 | | } |
171 | | |
172 | | /// rdp-spec, section 2.2.1.2 |
173 | | /// x.224-spec, section 13.3 |
174 | | #[derive(Clone, Debug, PartialEq, Eq)] |
175 | | pub struct X224ConnectionConfirm { |
176 | | pub cdt: u8, |
177 | | pub dst_ref: u16, |
178 | | pub src_ref: u16, |
179 | | pub class: u8, |
180 | | pub options: u8, |
181 | | pub negotiation_from_server: Option<NegotiationFromServer>, |
182 | | } |
183 | | |
184 | | /// variants of a server negotiation |
185 | | #[derive(Clone, Debug, PartialEq, Eq)] |
186 | | pub enum NegotiationFromServer { |
187 | | Response(NegotiationResponse), |
188 | | Failure(NegotiationFailure), |
189 | | } |
190 | | |
191 | | /// rdp-spec, section 2.2.1.1.1 |
192 | | #[derive(Clone, Debug, PartialEq, Eq)] |
193 | | pub struct NegotiationResponse { |
194 | | pub flags: NegotiationResponseFlags, |
195 | | pub protocol: Protocol, |
196 | | } |
197 | | |
198 | | // rdp-spec, section 2.2.1.2.1 |
199 | | bitflags! { |
200 | | #[derive(Default)] |
201 | | pub struct NegotiationResponseFlags: u8 { |
202 | | const EXTENDED_CLIENT_DATA_SUPPORTED = 0x1; |
203 | | const DYNVC_GFX_PROTOCOL_SUPPORTED = 0x2; |
204 | | const NEGRSP_FLAG_RESERVED = 0x4; |
205 | | const RESTRICTED_ADMIN_MODE_SUPPORTED = 0x8; |
206 | | const REDIRECTED_AUTHENTICATION_MODE_SUPPORTED = 0x10; |
207 | | } |
208 | | } |
209 | | |
210 | | /// rdp-spec, section 2.2.1.1.1 |
211 | | #[derive(Clone, Debug, PartialEq, Eq)] |
212 | | pub struct NegotiationFailure { |
213 | | pub code: NegotiationFailureCode, |
214 | | } |
215 | | |
216 | | /// rdp-spec, section 2.2.1.2.2 |
217 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
218 | | pub enum NegotiationFailureCode { |
219 | | SslRequiredByServer = 0x1, |
220 | | SslNotAllowedByServer = 0x2, |
221 | | SslCertNotOnServer = 0x3, |
222 | | InconsistentFlags = 0x4, |
223 | | HybridRequiredByServer = 0x5, |
224 | | SslWithUserAuthRequiredByServer = 0x6, |
225 | | } |
226 | | |
227 | | // ================ |
228 | | |
229 | | /// x224-spec, section 13.7 |
230 | | #[derive(Clone, Debug, PartialEq, Eq)] |
231 | | pub struct X223Data { |
232 | | pub child: X223DataChild, |
233 | | } |
234 | | |
235 | | /// variants that an x.223 data message can hold |
236 | | #[derive(Clone, Debug, PartialEq, Eq)] |
237 | | pub enum X223DataChild { |
238 | | McsConnectRequest(McsConnectRequest), |
239 | | McsConnectResponse(McsConnectResponse), |
240 | | Raw(Vec<u8>), |
241 | | } |
242 | | |
243 | | /// t.125-spec, section 7, part 2 |
244 | | #[derive(Clone, Debug, PartialEq, Eq)] |
245 | | pub enum T125Type { |
246 | | T125TypeMcsConnectRequest = 0x65, // 101 |
247 | | T125TypeMcsConnectResponse = 0x66, // 102 |
248 | | } |
249 | | |
250 | | /// rdp-spec, section 2.2.1.3.2 |
251 | | #[derive(Clone, Debug, PartialEq, Eq)] |
252 | | pub struct McsConnectRequest { |
253 | | pub children: Vec<McsConnectRequestChild>, |
254 | | } |
255 | | |
256 | | /// variants that an mcs connection message can hold |
257 | | #[derive(Clone, Debug, PartialEq, Eq)] |
258 | | pub enum McsConnectRequestChild { |
259 | | CsClientCore(CsClientCoreData), |
260 | | CsNet(CsNet), |
261 | | CsUnknown(CsUnknown), |
262 | | } |
263 | | |
264 | | /// rdp-spec, section 2.2.1.3.1 |
265 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
266 | | pub enum CsType { |
267 | | Core = 0xc001, |
268 | | Net = 0xc003, |
269 | | } |
270 | | |
271 | | /// rdp-spec, section 2.2.1.3.2 |
272 | | #[derive(Clone, Debug, PartialEq, Eq)] |
273 | | pub struct CsClientCoreData { |
274 | | pub version: Option<RdpClientVersion>, |
275 | | pub desktop_width: u16, |
276 | | pub desktop_height: u16, |
277 | | pub color_depth: Option<ColorDepth>, |
278 | | pub sas_sequence: Option<SasSequence>, |
279 | | pub keyboard_layout: u32, // see windows::lcid_to_string |
280 | | pub client_build: windows::OperatingSystem, |
281 | | pub client_name: String, |
282 | | pub keyboard_type: Option<KeyboardType>, |
283 | | pub keyboard_subtype: u32, |
284 | | pub keyboard_function_key: u32, |
285 | | pub ime_file_name: String, |
286 | | // optional fields |
287 | | pub post_beta2_color_depth: Option<PostBeta2ColorDepth>, |
288 | | pub client_product_id: Option<u16>, |
289 | | pub serial_number: Option<u32>, |
290 | | pub high_color_depth: Option<HighColorDepth>, |
291 | | pub supported_color_depth: Option<SupportedColorDepth>, |
292 | | pub early_capability_flags: Option<EarlyCapabilityFlags>, |
293 | | pub client_dig_product_id: Option<String>, |
294 | | pub connection_hint: Option<ConnectionHint>, |
295 | | pub server_selected_protocol: Option<ProtocolFlags>, |
296 | | pub desktop_physical_width: Option<u32>, |
297 | | pub desktop_physical_height: Option<u32>, |
298 | | pub desktop_orientation: Option<DesktopOrientation>, |
299 | | pub desktop_scale_factor: Option<u32>, |
300 | | pub device_scale_factor: Option<u32>, |
301 | | } |
302 | | |
303 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
304 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
305 | | #[allow(non_camel_case_types)] |
306 | | pub enum RdpClientVersion { |
307 | | V4 = 0x80001, |
308 | | V5_V8_1 = 0x80004, |
309 | | V10_0 = 0x80005, |
310 | | V10_1 = 0x80006, |
311 | | V10_2 = 0x80007, |
312 | | V10_3 = 0x80008, |
313 | | V10_4 = 0x80009, |
314 | | V10_5 = 0x8000a, |
315 | | V10_6 = 0x8000b, |
316 | | V10_7 = 0x8000c, |
317 | | } |
318 | | |
319 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
320 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
321 | | pub enum ColorDepth { |
322 | | RnsUdColor4Bpp = 0xca00, |
323 | | RnsUdColor8Bpp = 0xca01, |
324 | | } |
325 | | |
326 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
327 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
328 | | pub enum SasSequence { |
329 | | RnsUdSasDel = 0xaa03, |
330 | | } |
331 | | |
332 | | // for keyboard layout, see windows::lcid_to_string |
333 | | |
334 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
335 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
336 | | pub enum KeyboardType { |
337 | | KbXt = 0x1, |
338 | | KbIco = 0x2, |
339 | | KbAt = 0x3, |
340 | | KbEnhanced = 0x4, |
341 | | Kb1050 = 0x5, |
342 | | Kb9140 = 0x6, |
343 | | KbJapanese = 0x7, |
344 | | } |
345 | | |
346 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
347 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
348 | | pub enum PostBeta2ColorDepth { |
349 | | RnsUdColorNotProvided = 0x0, |
350 | | RnsUdColor4Bpp = 0xca00, |
351 | | RnsUdColor8Bpp = 0xca01, |
352 | | RnsUdColor16Bpp555 = 0xca02, |
353 | | RnsUdColor16Bpp565 = 0xca03, |
354 | | RnsUdColor24Bpp = 0xca04, |
355 | | } |
356 | | |
357 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
358 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
359 | | pub enum HighColorDepth { |
360 | | HighColorNotProvided = 0x0, |
361 | | HighColor4Bpp = 0x4, |
362 | | HighColor8Bpp = 0x8, |
363 | | HighColor15Bpp = 0xf, |
364 | | HighColor16Bpp = 0x10, |
365 | | HighColor24Bpp = 0x18, |
366 | | } |
367 | | |
368 | | // rdp-spec, section 2.2.1.3.2 Client Core Data |
369 | | bitflags! { |
370 | | #[derive(Default)] |
371 | | pub struct SupportedColorDepth: u16 { |
372 | | const RNS_UD_24_BPP_SUPPORT = 0x1; |
373 | | const RNS_UD_16_BPP_SUPPORT = 0x2; |
374 | | const RNS_UD_15_BPP_SUPPORT = 0x4; |
375 | | const RNS_UD_32_BPP_SUPPORT = 0x8; |
376 | | } |
377 | | } |
378 | | |
379 | | // rdp-spec, section 2.2.1.3.2 Client Core Data |
380 | | bitflags! { |
381 | | #[derive(Default)] |
382 | | pub struct EarlyCapabilityFlags: u16 { |
383 | | const RNS_UD_CS_SUPPORT_ERRINFO_PDF = 0x1; |
384 | | const RNS_UD_CS_WANT_32BPP_SESSION = 0x2; |
385 | | const RNS_UD_CS_SUPPORT_STATUSINFO_PDU = 0x4; |
386 | | const RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = 0x8; |
387 | | const RNS_UD_CS_UNUSED = 0x10; |
388 | | const RNS_UD_CS_VALID_CONNECTION_TYPE = 0x20; |
389 | | const RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = 0x40; |
390 | | const RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = 0x80; |
391 | | const RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = 0x100; |
392 | | const RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = 0x200; |
393 | | const RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = 0x400; |
394 | | } |
395 | | } |
396 | | |
397 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data, `connectionType` |
398 | | #[derive(Clone, Debug, FromPrimitive, PartialEq, Eq)] |
399 | | pub enum ConnectionHint { |
400 | | ConnectionHintNotProvided = 0x0, |
401 | | ConnectionHintModem = 0x1, |
402 | | ConnectionHintBroadbandLow = 0x2, |
403 | | ConnectionHintSatellite = 0x3, |
404 | | ConnectionHintBroadbandHigh = 0x4, |
405 | | ConnectionHintWan = 0x5, |
406 | | ConnectionHintLan = 0x6, |
407 | | ConnectionHintAutoDetect = 0x7, |
408 | | } |
409 | | |
410 | | /// rdp-spec, section 2.2.1.3.2 Client Core Data |
411 | | #[derive(Clone, Copy, Debug, FromPrimitive, PartialEq, Eq)] |
412 | | pub enum DesktopOrientation { |
413 | | OrientationLandscape = 0, |
414 | | OrientationPortrait = 90, // 0x5a |
415 | | OrientationLandscapeFlipped = 180, // 0xb4 |
416 | | OrientationPortraitFlipped = 270, // 0x10e |
417 | | } |
418 | | |
419 | | /// rdp-spec, section 2.2.1.3.4 |
420 | | #[derive(Clone, Debug, PartialEq, Eq)] |
421 | | pub struct CsNet { |
422 | | pub channels: Vec<String>, |
423 | | } |
424 | | |
425 | | /// generic structure |
426 | | /// cf. rdp-spec, section 2.2.1.3.4 |
427 | | #[derive(Clone, Debug, PartialEq, Eq)] |
428 | | pub struct CsUnknown { |
429 | | pub typ: u16, |
430 | | pub data: Vec<u8>, |
431 | | } |
432 | | |
433 | | /// rdp-spec, section 2.2.1.4 |
434 | | #[derive(Clone, Debug, PartialEq, Eq)] |
435 | | pub struct McsConnectResponse {} |
436 | | |
437 | | // ================== |
438 | | |
439 | | /// parser for t.123 and children |
440 | | /// t.123-spec, section 8 |
441 | 2.58M | pub fn parse_t123_tpkt(input: &[u8]) -> IResult<&[u8], T123Tpkt, RdpError> { |
442 | 2.58M | let (i1, _version) = verify(be_u8, |&x| x == TpktVersion::T123 as u8)(input)?; |
443 | 2.57M | let (i2, _reserved) = be_u8(i1)?; |
444 | | // less u8, u8, u16 |
445 | 2.56M | let (i3, sz) = map_opt(be_u16, |x: u16| x.checked_sub(4))(i2)?; |
446 | 2.56M | let (i4, data) = take(sz)(i3)?; |
447 | | |
448 | 2.54M | let opt1: Option<T123TpktChild> = { |
449 | 2.55M | match opt(parse_x224_connection_request_class_0)(data) { |
450 | 2.54M | Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionRequest), |
451 | 8.68k | Err(e) => return Err(e), |
452 | | } |
453 | | }; |
454 | | |
455 | 2.54M | let opt2: Option<T123TpktChild> = match opt1 { |
456 | 1.09M | Some(x) => Some(x), |
457 | 1.44M | None => match opt(parse_x224_connection_confirm_class_0)(data) { |
458 | 1.44M | Ok((_remainder, opt)) => opt.map(T123TpktChild::X224ConnectionConfirm), |
459 | 3.08k | Err(e) => return Err(e), |
460 | | }, |
461 | | }; |
462 | | |
463 | 2.53M | let opt3: Option<T123TpktChild> = match opt2 { |
464 | 2.46M | Some(x) => Some(x), |
465 | 71.4k | None => match opt(parse_x223_data_class_0)(data) { |
466 | 45.5k | Ok((_remainder, opt)) => opt.map(T123TpktChild::Data), |
467 | 25.9k | Err(e) => return Err(e), |
468 | | }, |
469 | | }; |
470 | 2.51M | let child: T123TpktChild = match opt3 { |
471 | 2.47M | Some(x) => x, |
472 | 39.9k | None => T123TpktChild::Raw(data.to_vec()), |
473 | | }; |
474 | | |
475 | 2.51M | return Ok((i4, T123Tpkt { child })); |
476 | 2.58M | } |
477 | | |
478 | 3.99M | fn take_4_4_bits(input: &[u8]) -> IResult<&[u8], (u8, u8), RdpError> { |
479 | 3.99M | map(be_u8, |b| (b >> 4, b & 0xf))(input) |
480 | 3.99M | } |
481 | | |
482 | 2.48M | fn parse_class_options(i: &[u8]) -> IResult<&[u8], (u8, u8)> { |
483 | 2.48M | bits( |
484 | 2.48M | tuple(( |
485 | 2.48M | verify(take_bits(4u8), |&x| x <= 4), |
486 | 2.48M | verify(take_bits(4u8), |&x| x <= 3) |
487 | | )) |
488 | 2.48M | )(i) |
489 | 2.48M | } |
490 | | |
491 | | /// rdp-spec, section 2.2.1.1 |
492 | 2.55M | fn parse_x224_connection_request(input: &[u8]) -> IResult<&[u8], X224ConnectionRequest, RdpError> { |
493 | 2.55M | let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved |
494 | 2.54M | let (i2, cr_cdt) = take_4_4_bits(i1)?; |
495 | 2.54M | if cr_cdt.0 != X224Type::ConnectionRequest as u8 { |
496 | 1.43M | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
497 | 1.11M | } |
498 | 1.11M | if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) { |
499 | 352 | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
500 | 1.11M | } |
501 | 1.11M | let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?; |
502 | 1.10M | let (i4, src_ref) = be_u16(i3)?; |
503 | 1.10M | let (i5, class_options) = parse_class_options(i4).map_err(Err::convert)?; |
504 | | // less cr_cdt (u8), dst_ref (u16), src_ref (u16), class_options (u8) |
505 | 1.10M | if length < 6 { |
506 | 464 | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
507 | 1.10M | } |
508 | 1.10M | let i6 = i5; |
509 | 1.10M | let sz = length - 6; |
510 | | |
511 | | // |
512 | | // optionally find cookie and/or negotiation request |
513 | | // |
514 | | |
515 | 1.10M | let (i7, data) = { |
516 | 1.10M | if sz > 0 { |
517 | 179k | take(sz)(i6)? |
518 | | } else { |
519 | 925k | (i6, &[][..]) |
520 | | } |
521 | | }; |
522 | | |
523 | 1.10M | let (j1, cookie) = { |
524 | 1.10M | if !data.is_empty() { |
525 | 178k | match opt(parse_rdp_cookie)(data) { |
526 | 176k | Ok((remainder, opt)) => (remainder, opt), |
527 | 1.86k | Err(e) => return Err(e), |
528 | | } |
529 | | } else { |
530 | 925k | (&[][..], None) |
531 | | } |
532 | | }; |
533 | | |
534 | 1.10M | let (j2, negotiation_request) = { |
535 | 1.10M | if !j1.is_empty() { |
536 | 176k | match opt(parse_negotiation_request)(j1) { |
537 | 176k | Ok((remainder, opt)) => (remainder, opt), |
538 | 586 | Err(e) => return Err(e), |
539 | | } |
540 | | } else { |
541 | 925k | (&[][..], None) |
542 | | } |
543 | | }; |
544 | | |
545 | 1.10M | return Ok(( |
546 | 1.10M | i7, |
547 | 1.10M | X224ConnectionRequest { |
548 | 1.10M | cdt: cr_cdt.1, |
549 | 1.10M | dst_ref, |
550 | 1.10M | src_ref, |
551 | 1.10M | class: class_options.0, |
552 | 1.10M | options: class_options.1, |
553 | 1.10M | cookie, |
554 | 1.10M | negotiation_request, |
555 | 1.10M | data: j2.to_vec(), |
556 | 1.10M | }, |
557 | 1.10M | )); |
558 | 2.55M | } |
559 | | |
560 | | /// rdp-spec, section 2.2.1.1 |
561 | | /// "An X.224 Class 0 Connection Request TPDU, as specified in [X224] section 13.3." |
562 | 2.55M | fn parse_x224_connection_request_class_0( |
563 | 2.55M | input: &[u8], |
564 | 2.55M | ) -> IResult<&[u8], X224ConnectionRequest, RdpError> { |
565 | 2.55M | let (i1, x224) = parse_x224_connection_request(input)?; |
566 | 1.10M | if x224.class == 0 && x224.options == 0 { |
567 | 1.09M | Ok((i1, x224)) |
568 | | } else { |
569 | 4.70k | Err(Err::Error(RdpError::NotX224Class0Error)) |
570 | | } |
571 | 2.55M | } |
572 | | |
573 | | // rdp-spec, section 2.2.1.1.1 |
574 | 178k | fn parse_rdp_cookie(i: &[u8]) -> IResult<&[u8], RdpCookie, RdpError> { |
575 | 178k | let (i, _key) = tag(b"Cookie: ")(i)?; |
576 | 1.32k | let (i, _name) = tag(b"mstshash=")(i)?; |
577 | 84 | let (i, bytes) = take_until_and_consume(b"\r\n")(i)?; |
578 | | // let (i, s) = map_res(value!(bytes), std::str::from_utf8)(i)?; |
579 | 61 | let s = std::str::from_utf8(bytes).map_err(|_| Err::Error(make_error(bytes, ErrorKind::MapRes)))?; |
580 | 61 | let cookie = RdpCookie{ mstshash: String::from(s) }; |
581 | 61 | Ok((i, cookie)) |
582 | 178k | } |
583 | | |
584 | | // rdp-spec, section 2.2.1.1.1 |
585 | 176k | fn parse_negotiation_request(i: &[u8]) -> IResult<&[u8], NegotiationRequest, RdpError> { |
586 | 176k | let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationRequest as u8)(i)?; |
587 | 3.62k | let (i, flags) = map_opt(le_u8, NegotiationRequestFlags::from_bits)(i)?; |
588 | | // u8, u8, u16, and u32 give _length of 8 |
589 | 3.18k | let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; |
590 | 955 | let (i, protocols) = map_opt(le_u32, ProtocolFlags::from_bits)(i)?; |
591 | 200 | Ok((i, NegotiationRequest { flags, protocols })) |
592 | 176k | } |
593 | | |
594 | | /// rdp-spec, section 2.2.1.2 |
595 | | /// x.224-spec, section 13.3 |
596 | 1.44M | fn parse_x224_connection_confirm(input: &[u8]) -> IResult<&[u8], X224ConnectionConfirm, RdpError> { |
597 | 1.44M | let (i1, length) = verify(be_u8, |&x| x != 0xff)(input)?; // 0xff is reserved |
598 | 1.44M | let (i2, cr_cdt) = take_4_4_bits(i1)?; |
599 | 1.44M | if cr_cdt.0 != X224Type::ConnectionConfirm as u8 { |
600 | 55.6k | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
601 | 1.38M | } |
602 | 1.38M | if !(cr_cdt.1 == 0 || cr_cdt.1 == 1) { |
603 | 2.76k | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
604 | 1.38M | } |
605 | 1.38M | let (i3, dst_ref) = verify(be_u16, |&x| x == 0)(i2)?; |
606 | 1.37M | let (i4, src_ref) = be_u16(i3)?; |
607 | 1.37M | let (i5, class_options) = parse_class_options(i4).map_err(Err::convert)?; |
608 | | |
609 | | // less cr_cdt (u8), dst_ref (u16), src_ref (u16), class_options (u8) |
610 | 1.37M | if length < 6 { |
611 | 223 | return Err(Err::Error(make_error(i1, ErrorKind::Verify))); |
612 | 1.37M | } |
613 | 1.37M | let i6 = i5; |
614 | 1.37M | let sz = length - 6; |
615 | | |
616 | | // a negotiation message from the server might be absent (sz == 0) |
617 | 1.37M | let (i7, negotiation_from_server) = { |
618 | 1.37M | if sz > 0 { |
619 | 8.94k | let (i7, data) = take(sz)(i6)?; |
620 | | |
621 | | // it will be one of a response message or a failure message |
622 | 8.54k | let opt1: Option<NegotiationFromServer> = match opt(parse_negotiation_response)(data) { |
623 | 7.75k | Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Response), |
624 | 798 | Err(e) => return Err(e), |
625 | | }; |
626 | 7.75k | let opt2: Option<NegotiationFromServer> = match opt1 { |
627 | 448 | Some(x) => Some(x), |
628 | 7.30k | None => match opt(parse_negotiation_failure)(data) { |
629 | 6.68k | Ok((_remainder, opt)) => opt.map(NegotiationFromServer::Failure), |
630 | 621 | Err(e) => return Err(e), |
631 | | }, |
632 | | }; |
633 | 7.12k | (i7, opt2) |
634 | | } else { |
635 | 1.36M | (i6, None) |
636 | | } |
637 | | }; |
638 | | |
639 | 1.37M | return Ok(( |
640 | 1.37M | i7, |
641 | 1.37M | X224ConnectionConfirm { |
642 | 1.37M | cdt: cr_cdt.1, |
643 | 1.37M | dst_ref, |
644 | 1.37M | src_ref, |
645 | 1.37M | class: class_options.0, |
646 | 1.37M | options: class_options.1, |
647 | 1.37M | negotiation_from_server, |
648 | 1.37M | }, |
649 | 1.37M | )); |
650 | 1.44M | } |
651 | | |
652 | | /// rdp-spec, section 2.2.1.2 |
653 | | /// "An X.224 Class 0 Connection Confirm TPDU, as specified in [X224] section 13.4." |
654 | 1.44M | fn parse_x224_connection_confirm_class_0( |
655 | 1.44M | input: &[u8], |
656 | 1.44M | ) -> IResult<&[u8], X224ConnectionConfirm, RdpError> { |
657 | 1.44M | let (i1, x224) = parse_x224_connection_confirm(input)?; |
658 | 1.37M | if x224.class == 0 && x224.options == 0 { |
659 | 1.37M | Ok((i1, x224)) |
660 | | } else { |
661 | | // x.224, but not a class 0 x.224 message |
662 | 2.45k | Err(Err::Error(RdpError::NotX224Class0Error)) |
663 | | } |
664 | 1.44M | } |
665 | | |
666 | | // rdp-spec, section 2.2.1.1.1 |
667 | 8.54k | fn parse_negotiation_response(i: &[u8]) -> IResult<&[u8], NegotiationResponse, RdpError> { |
668 | 8.54k | let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationResponse as u8)(i)?; |
669 | 2.88k | let (i, flags) = map_opt(le_u8, NegotiationResponseFlags::from_bits)(i)?; |
670 | | // u8, u8, u16, and u32 give _length of 8 |
671 | 2.45k | let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; |
672 | 1.60k | let (i, protocol) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?; |
673 | 448 | Ok((i, NegotiationResponse { flags, protocol })) |
674 | 8.54k | } |
675 | | |
676 | | // rdp-spec, section 2.2.1.1.1 |
677 | 7.30k | fn parse_negotiation_failure(i: &[u8]) -> IResult<&[u8], NegotiationFailure, RdpError> { |
678 | 7.30k | let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationFailure as u8)(i)?; |
679 | 2.12k | let (i, _flags) = le_u8(i)?; |
680 | | // u8, u8, u16, and u32 give _length of 8 |
681 | 1.93k | let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; |
682 | 1.19k | let (i, code) = map_opt(le_u32, num::FromPrimitive::from_u32)(i)?; |
683 | 292 | Ok((i, NegotiationFailure { code })) |
684 | 7.30k | } |
685 | | |
686 | | /// x224-spec, section 13.7 |
687 | 71.4k | fn parse_x223_data_class_0(input: &[u8]) -> IResult<&[u8], X223Data, RdpError> { |
688 | 36.7k | fn parser(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> { |
689 | 36.7k | bits( |
690 | 36.7k | tuple(( |
691 | 36.7k | verify(take_bits(4u8), |&x| x == 0xf), |
692 | 36.7k | verify(take_bits(3u8), |&x| x == 0), |
693 | 36.7k | verify(take_bits(1u8), |&x| x == 0) |
694 | | )) |
695 | 36.7k | )(i) |
696 | 36.7k | } |
697 | 71.4k | let (i1, _length) = verify(be_u8, |&x| x == 2)(input)?; |
698 | 36.7k | let (i2, _dt_x_roa) = parser(i1).map_err(Err::convert)?; |
699 | 31.9k | let (i3, _eot) = verify(be_u8, |&x| x == 0x80)(i2)?; |
700 | | |
701 | | // |
702 | | // optionally find exactly one of the child messages |
703 | | // |
704 | | |
705 | 31.1k | let opt1: Option<X223DataChild> = match opt(parse_mcs_connect)(i3) { |
706 | 5.56k | Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectRequest), |
707 | 25.6k | Err(e) => return Err(e), |
708 | | }; |
709 | | |
710 | 5.56k | let opt2: Option<X223DataChild> = match opt1 { |
711 | 3.84k | Some(x) => Some(x), |
712 | 1.71k | None => match opt(parse_mcs_connect_response)(i3) { |
713 | 1.71k | Ok((_remainder, opt)) => opt.map(X223DataChild::McsConnectResponse), |
714 | 0 | Err(e) => return Err(e), |
715 | | }, |
716 | | }; |
717 | | |
718 | 5.56k | let child: X223DataChild = match opt2 { |
719 | 4.13k | Some(x) => x, |
720 | 1.42k | None => X223DataChild::Raw(i3.to_vec()), |
721 | | }; |
722 | | |
723 | 5.56k | return Ok((&[], X223Data { child })); |
724 | 71.4k | } |
725 | | |
726 | | /// rdp-spec, section 2.2.1.3.2 |
727 | 31.1k | fn parse_mcs_connect(input: &[u8]) -> IResult<&[u8], McsConnectRequest, RdpError> { |
728 | 31.1k | let (i1, _ber_type) = verify( |
729 | | le_u8, |
730 | | // BER: 0b01=application, 0b1=non-primitive, 0b11111 |
731 | 30.9k | |&x| x == 0x7f |
732 | 31.1k | )(input)?; |
733 | 30.4k | let (i2, _t125_type) = verify(le_u8, |&x| x |
734 | 30.4k | == T125Type::T125TypeMcsConnectRequest as u8)(i1)?; |
735 | | |
736 | | // skip to, and consume, H.221 client-to-server key |
737 | 29.2k | let (i3, _skipped) = take_until_and_consume(b"Duca")(i2)?; |
738 | | |
739 | 26.0k | let (i4, data) = length_data(parse_per_length_determinant)(i3)?; |
740 | 24.4k | let mut remainder: &[u8] = data; |
741 | 24.4k | let mut children = Vec::new(); |
742 | | |
743 | | // repeatedly attempt to parse optional CsClientCoreData, CsNet, and CsUnknown |
744 | | // until data buffer is exhausted |
745 | | loop { |
746 | 41.4k | remainder = match opt(parse_cs_client_core_data)(remainder) { |
747 | 29.8k | Ok((rem, o)) => match o { |
748 | | // found CsClientCoreData |
749 | 10.2k | Some(core_data) => { |
750 | 10.2k | children.push(McsConnectRequestChild::CsClientCore(core_data)); |
751 | 10.2k | rem |
752 | | } |
753 | 19.5k | None => match opt(parse_cs_net)(remainder) { |
754 | | // found CsNet |
755 | 18.0k | Ok((rem, o)) => match o { |
756 | 1.20k | Some(net) => { |
757 | 1.20k | children.push(McsConnectRequestChild::CsNet(net)); |
758 | 1.20k | rem |
759 | | } |
760 | | None => { |
761 | 16.8k | match opt(parse_cs_unknown)(remainder) { |
762 | | // was able to parse CsUnknown |
763 | 9.33k | Ok((rem, o)) => match o { |
764 | 7.41k | Some(unknown) => { |
765 | 7.41k | children.push(McsConnectRequestChild::CsUnknown(unknown)); |
766 | 7.41k | rem |
767 | | } |
768 | | None => { |
769 | 1.91k | break; |
770 | | } |
771 | | }, |
772 | 7.49k | Err(Err::Incomplete(i)) => { |
773 | 7.49k | return Err(Err::Incomplete(i)) |
774 | | } |
775 | 0 | Err(Err::Failure(_)) | Err(Err::Error(_)) => break, |
776 | | } |
777 | | } |
778 | | }, |
779 | 1.55k | Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)), |
780 | 0 | Err(Err::Failure(_)) | Err(Err::Error(_)) => break, |
781 | | }, |
782 | | }, |
783 | 11.5k | Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)), |
784 | 0 | Err(Err::Failure(_)) | Err(Err::Error(_)) => break, |
785 | | }; |
786 | 18.9k | if remainder.is_empty() { |
787 | 1.93k | break; |
788 | 16.9k | } |
789 | | } |
790 | | |
791 | 3.84k | return Ok((i4, McsConnectRequest { children })); |
792 | 31.1k | } |
793 | | |
794 | | /// rdp-spec, section 2.2.1.3.2 |
795 | 41.4k | fn parse_cs_client_core_data(input: &[u8]) -> IResult<&[u8], CsClientCoreData> { |
796 | 41.4k | let (i1, _typ) = verify(le_u16, |&x| x == CsType::Core as u16)(input)?; |
797 | | // less u16, u16 |
798 | 20.9k | let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i1)?; |
799 | 19.9k | let (i3, data) = take(sz)(i2)?; |
800 | 19.6k | let (j1, version) = map(le_u32, num::FromPrimitive::from_u32)(data)?; |
801 | 19.4k | let (j2, desktop_width) = le_u16(j1)?; |
802 | 18.9k | let (j3, desktop_height) = le_u16(j2)?; |
803 | 18.6k | let (j4, color_depth) = map(le_u16, num::FromPrimitive::from_u16)(j3)?; |
804 | 18.4k | let (j5, sas_sequence) = map(le_u16, num::FromPrimitive::from_u16)(j4)?; |
805 | 18.1k | let (j6, keyboard_layout) = le_u32(j5)?; |
806 | 17.6k | let (j7, client_build) = map(le_u32, windows::build_number_to_os)(j6)?; |
807 | 17.2k | let (j8, client_name) = map_res(take(32_usize), le_slice_to_string)(j7)?; |
808 | 12.1k | let (j9, keyboard_type) = map(le_u32, num::FromPrimitive::from_u32)(j8)?; |
809 | 11.9k | let (j10, keyboard_subtype) = le_u32(j9)?; |
810 | 11.4k | let (j11, keyboard_function_key) = le_u32(j10)?; |
811 | 10.8k | let (j12, ime_file_name) = map_res(take(64_usize), le_slice_to_string)(j11)?; |
812 | | |
813 | | // |
814 | | // optional fields below (but each requires the previous) |
815 | | // |
816 | | |
817 | 10.2k | let (j13, post_beta2_color_depth) = |
818 | 10.2k | match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j12) as IResult<&[u8], _> { |
819 | 10.0k | Ok((rem, obj)) => (rem, obj), |
820 | 199 | _ => (j12, None), |
821 | | }; |
822 | | |
823 | 10.2k | let (j14, client_product_id) = match post_beta2_color_depth { |
824 | 1.18k | None => (j13, None), |
825 | 9.11k | Some(_) => match opt(le_u16)(j13) as IResult<&[u8], _> { |
826 | 8.91k | Ok((rem, obj)) => (rem, obj), |
827 | 195 | _ => (j13, None), |
828 | | }, |
829 | | }; |
830 | | |
831 | 10.2k | let (j15, serial_number) = match client_product_id { |
832 | 1.37k | None => (j14, None), |
833 | 8.91k | Some(_) => match opt(le_u32)(j14) as IResult<&[u8], _> { |
834 | 8.68k | Ok((rem, obj)) => (rem, obj), |
835 | 230 | _ => (j14, None), |
836 | | }, |
837 | | }; |
838 | | |
839 | 10.2k | let (j16, high_color_depth) = match serial_number { |
840 | 1.60k | None => (j15, None), |
841 | | Some(_) => { |
842 | 8.68k | match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j15) as IResult<&[u8], _> { |
843 | 7.73k | Ok((rem, obj)) => (rem, obj), |
844 | 953 | _ => (j15, None), |
845 | | } |
846 | | } |
847 | | }; |
848 | | |
849 | 10.2k | let (j17, supported_color_depth) = match high_color_depth { |
850 | 3.27k | None => (j16, None), |
851 | | Some(_) => { |
852 | 7.01k | match opt(map_opt(le_u16, SupportedColorDepth::from_bits))(j16) as IResult<&[u8], _> { |
853 | 6.82k | Ok((rem, obj)) => (rem, obj), |
854 | 194 | _ => (j16, None), |
855 | | } |
856 | | } |
857 | | }; |
858 | | |
859 | 10.2k | let (j18, early_capability_flags) = match supported_color_depth { |
860 | 3.76k | None => (j17, None), |
861 | | Some(_) => { |
862 | 6.52k | match opt(map_opt(le_u16, EarlyCapabilityFlags::from_bits))(j17) as IResult<&[u8], _> |
863 | | { |
864 | 6.33k | Ok((rem, obj)) => (rem, obj), |
865 | 194 | _ => (j17, None), |
866 | | } |
867 | | } |
868 | | }; |
869 | | |
870 | 10.2k | let (j19, client_dig_product_id) = match early_capability_flags { |
871 | 4.39k | None => (j18, None), |
872 | | Some(_) => { |
873 | 5.90k | match opt(map_res(take(64usize), le_slice_to_string))(j18) as IResult<&[u8], _> { |
874 | 5.70k | Ok((rem, obj)) => (rem, obj), |
875 | 198 | _ => (j18, None), |
876 | | } |
877 | | } |
878 | | }; |
879 | | |
880 | 10.2k | let (j20, connection_hint) = match client_dig_product_id { |
881 | 5.22k | None => (j19, None), |
882 | | Some(_) => { |
883 | 5.07k | match opt(map_opt(le_u8, num::FromPrimitive::from_u8))(j19) as IResult<&[u8], _> { |
884 | 5.00k | Ok((rem, obj)) => (rem, obj), |
885 | 63 | _ => (j19, None), |
886 | | } |
887 | | } |
888 | | }; |
889 | | |
890 | 10.2k | let (j21, pad) = match connection_hint { |
891 | 6.33k | None => (j20, None), |
892 | 3.96k | Some(_) => match opt(take(1usize))(j20) as IResult<&[u8], _> { |
893 | 3.67k | Ok((rem, obj)) => (rem, obj), |
894 | 285 | _ => (j20, None), |
895 | | }, |
896 | | }; |
897 | | |
898 | 10.2k | let (j22, server_selected_protocol) = match pad { |
899 | 6.61k | None => (j21, None), |
900 | | Some(_) => { |
901 | 3.67k | match opt(map_opt(le_u32, ProtocolFlags::from_bits))(j21) as IResult<&[u8], _> { |
902 | 3.45k | Ok((rem, obj)) => (rem, obj), |
903 | 219 | _ => (j21, None), |
904 | | } |
905 | | } |
906 | | }; |
907 | | |
908 | 10.2k | let (j23, desktop_physical_width) = match server_selected_protocol { |
909 | 7.28k | None => (j22, None), |
910 | 3.01k | Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j22) as IResult<&[u8], _> { |
911 | 2.68k | Ok((rem, obj)) => (rem, obj), |
912 | 334 | _ => (j22, None), |
913 | | }, |
914 | | }; |
915 | | |
916 | 10.2k | let (j24, desktop_physical_height) = match desktop_physical_width { |
917 | 7.85k | None => (j23, None), |
918 | 2.43k | Some(_) => match opt(map_opt(le_u32, millimeters_to_opt))(j23) as IResult<&[u8], _> { |
919 | 2.24k | Ok((rem, obj)) => (rem, obj), |
920 | 194 | _ => (j23, None), |
921 | | }, |
922 | | }; |
923 | | |
924 | 10.2k | let (j25, desktop_orientation) = match desktop_physical_height { |
925 | 8.28k | None => (j24, None), |
926 | | Some(_) => { |
927 | 2.00k | match opt(map_opt(le_u16, num::FromPrimitive::from_u16))(j24) as IResult<&[u8], _> { |
928 | 1.80k | Ok((rem, obj)) => (rem, obj), |
929 | 201 | _ => (j24, None), |
930 | | } |
931 | | } |
932 | | }; |
933 | | |
934 | 10.2k | let (j26, desktop_scale_factor) = match desktop_orientation { |
935 | 8.69k | None => (j25, None), |
936 | 1.59k | Some(_) => match opt(map_opt(le_u32, desktop_scale_to_opt))(j25) as IResult<&[u8], _> { |
937 | 1.40k | Ok((rem, obj)) => (rem, obj), |
938 | 195 | _ => (j25, None), |
939 | | }, |
940 | | }; |
941 | | |
942 | 10.2k | let (_j27, device_scale_factor) = match desktop_scale_factor { |
943 | 9.32k | None => (j26, None), |
944 | 973 | Some(_) => match opt(map_opt(le_u32, device_scale_to_opt))(j26) as IResult<&[u8], _> { |
945 | 777 | Ok((rem, obj)) => (rem, obj), |
946 | 196 | _ => (j26, None), |
947 | | }, |
948 | | }; |
949 | | |
950 | 10.2k | return Ok(( |
951 | 10.2k | i3, |
952 | 10.2k | CsClientCoreData { |
953 | 10.2k | version, |
954 | 10.2k | desktop_width, |
955 | 10.2k | desktop_height, |
956 | 10.2k | color_depth, |
957 | 10.2k | sas_sequence, |
958 | 10.2k | keyboard_layout, |
959 | 10.2k | client_build, |
960 | 10.2k | client_name, |
961 | 10.2k | keyboard_type, |
962 | 10.2k | keyboard_subtype, |
963 | 10.2k | keyboard_function_key, |
964 | 10.2k | ime_file_name, |
965 | 10.2k | post_beta2_color_depth, |
966 | 10.2k | client_product_id, |
967 | 10.2k | serial_number, |
968 | 10.2k | high_color_depth, |
969 | 10.2k | supported_color_depth, |
970 | 10.2k | early_capability_flags, |
971 | 10.2k | client_dig_product_id, |
972 | 10.2k | connection_hint, |
973 | 10.2k | server_selected_protocol, |
974 | 10.2k | desktop_physical_width, |
975 | 10.2k | desktop_physical_height, |
976 | 10.2k | desktop_orientation, |
977 | 10.2k | desktop_scale_factor, |
978 | 10.2k | device_scale_factor, |
979 | 10.2k | }, |
980 | 10.2k | )); |
981 | 41.4k | } |
982 | | |
983 | | /// rdp-spec, section 2.2.1.3.4 |
984 | 19.5k | fn parse_cs_net(input: &[u8]) -> IResult<&[u8], CsNet> { |
985 | 19.5k | let (i1, _typ) = verify(le_u16, |&x| x == CsType::Net as u16)(input)?; |
986 | | // less _typ (u16), this length indicator (u16), count (u32) |
987 | 3.19k | let (i2, sz) = map_opt(le_u16, |x: u16| x.checked_sub(8))(i1)?; |
988 | 2.76k | let (i3, count) = le_u32(i2)?; |
989 | 2.53k | let (i4, data) = take(sz)(i3)?; |
990 | | |
991 | 2.28k | let mut remainder: &[u8] = data; |
992 | 2.28k | let mut channels = Vec::new(); |
993 | | |
994 | 2.35k | for _index in 0..count { |
995 | | // a channel name is 8 bytes, section 2.2.1.3.4.1 |
996 | 2.35k | let (j1, name) = map_res(take(8_usize), utf7_slice_to_string)(remainder)?; |
997 | 1.65k | channels.push(name); |
998 | | // options (u32) are discarded for now |
999 | 1.65k | let (j2, _options) = le_u32(j1)?; |
1000 | 1.27k | remainder = j2; |
1001 | | } |
1002 | | |
1003 | 1.20k | return Ok((i4, CsNet { channels })); |
1004 | 19.5k | } |
1005 | | |
1006 | | // generic CS structure parse |
1007 | | // cf. rdp-spec, section 2.2.1.3.4 |
1008 | 16.8k | fn parse_cs_unknown(i: &[u8]) -> IResult<&[u8], CsUnknown> { |
1009 | 16.8k | let (i, typ) = map_opt(le_u16, |x| { |
1010 | 16.8k | let opt: Option<CsType> = num::FromPrimitive::from_u16(x); |
1011 | 16.8k | match opt { |
1012 | | // an unknown type must not be present in CsType |
1013 | 1.37k | Some(_) => None, |
1014 | 15.4k | None => Some(x), |
1015 | | } |
1016 | 16.8k | })(i)?; |
1017 | | // less u16, u16 |
1018 | 15.4k | let (i, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i)?; |
1019 | 13.1k | let (i, data) = take(sz)(i)?; |
1020 | 7.41k | Ok((i, CsUnknown { typ, data: data.to_vec() })) |
1021 | 16.8k | } |
1022 | | |
1023 | | // rdp-spec, section 2.2.1.4 |
1024 | 1.71k | fn parse_mcs_connect_response(i: &[u8]) -> IResult<&[u8], McsConnectResponse, RdpError> { |
1025 | 1.71k | let (i, _ber_type) = verify( |
1026 | | le_u8, |
1027 | | // BER: 0b01=application, 0b1=non-primitive, 0b11111 |
1028 | 1.71k | |&x| x == 0x7f)(i)?; |
1029 | 1.21k | let (i, _t125_type) = verify(le_u8, |&x| x == T125Type::T125TypeMcsConnectResponse as u8)(i)?; |
1030 | 283 | Ok((i, McsConnectResponse {})) |
1031 | 1.71k | } |
1032 | | |
1033 | | #[cfg(test)] |
1034 | | mod tests_cookie_21182 { |
1035 | | use crate::rdp::parser::*; |
1036 | | |
1037 | | static BYTES: [u8; 37] = [ |
1038 | | 0x03, 0x00, 0x00, 0x25, 0x20, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6f, 0x6b, |
1039 | | 0x69, 0x65, 0x3a, 0x20, 0x6d, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3d, 0x75, 0x73, |
1040 | | 0x65, 0x72, 0x31, 0x32, 0x33, 0x0d, 0x0a, |
1041 | | ]; |
1042 | | |
1043 | | #[test] |
1044 | | fn test_t123_x224_cookie() { |
1045 | | let t123_bytes = &BYTES[..]; |
1046 | | let t123_tpkt: T123Tpkt = T123Tpkt { |
1047 | | child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest { |
1048 | | cdt: 0, |
1049 | | dst_ref: 0, |
1050 | | src_ref: 0, |
1051 | | class: 0, |
1052 | | options: 0, |
1053 | | cookie: Some(RdpCookie { |
1054 | | mstshash: String::from("user123"), |
1055 | | }), |
1056 | | negotiation_request: None, |
1057 | | data: Vec::new(), |
1058 | | }), |
1059 | | }; |
1060 | | assert_eq!(Ok((&[][..], t123_tpkt)), parse_t123_tpkt(t123_bytes)); |
1061 | | } |
1062 | | } |
1063 | | |
1064 | | #[cfg(test)] |
1065 | | mod tests_negotiate_49350 { |
1066 | | use crate::rdp::parser::*; |
1067 | | |
1068 | | static BYTES: [u8; 20] = [ |
1069 | | 0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, |
1070 | | 0x00, 0x00, 0x00, 0x00, 0xff, |
1071 | | ]; |
1072 | | static TPKT_BEGIN: usize = 0; |
1073 | | static X224_BEGIN: usize = TPKT_BEGIN + 4; |
1074 | | static NEG_REQ_BEGIN: usize = X224_BEGIN + 7; |
1075 | | static NEG_REQ_END: usize = NEG_REQ_BEGIN + 8; |
1076 | | static X224_END: usize = NEG_REQ_END; |
1077 | | static TPKT_END: usize = X224_END; |
1078 | | static PADDING_BEGIN: usize = TPKT_END; |
1079 | | |
1080 | | #[test] |
1081 | | fn test_t123_x224_negotiate() { |
1082 | | let t123_bytes = &BYTES[TPKT_BEGIN..]; |
1083 | | let t123_tpkt: T123Tpkt = T123Tpkt { |
1084 | | child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest { |
1085 | | cdt: 0, |
1086 | | dst_ref: 0, |
1087 | | src_ref: 0, |
1088 | | class: 0, |
1089 | | options: 0, |
1090 | | cookie: None, |
1091 | | negotiation_request: Some(NegotiationRequest { |
1092 | | flags: NegotiationRequestFlags::empty(), |
1093 | | protocols: ProtocolFlags { bits: Protocol::ProtocolRdp as u32 }, |
1094 | | }), |
1095 | | data: Vec::new(), |
1096 | | }), |
1097 | | }; |
1098 | | assert_eq!( |
1099 | | Ok((&BYTES[PADDING_BEGIN..][..], t123_tpkt)), |
1100 | | parse_t123_tpkt(t123_bytes) |
1101 | | ) |
1102 | | } |
1103 | | } |
1104 | | |
1105 | | #[cfg(test)] |
1106 | | #[allow(clippy::vec_init_then_push)] |
1107 | | mod tests_core_49350 { |
1108 | | use crate::rdp::parser::*; |
1109 | | |
1110 | | static BYTES: [u8; 429] = [ |
1111 | | 0x03, 0x00, 0x01, 0xac, 0x02, 0xf0, 0x80, 0x7f, 0x65, 0x82, 0x01, 0xa0, 0x04, 0x01, 0x01, |
1112 | | 0x04, 0x01, 0x01, 0x01, 0x01, 0xff, 0x30, 0x19, 0x02, 0x01, 0x22, 0x02, 0x01, 0x02, 0x02, |
1113 | | 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, |
1114 | | 0x02, 0x01, 0x02, 0x30, 0x19, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, |
1115 | | 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x20, 0x02, 0x01, 0x02, |
1116 | | 0x30, 0x1c, 0x02, 0x02, 0xff, 0xff, 0x02, 0x02, 0xfc, 0x17, 0x02, 0x02, 0xff, 0xff, 0x02, |
1117 | | 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, 0x02, 0x01, 0x02, |
1118 | | 0x04, 0x82, 0x01, 0x3f, 0x00, 0x05, 0x00, 0x14, 0x7c, 0x00, 0x01, 0x81, 0x36, 0x00, 0x08, |
1119 | | 0x00, 0x10, 0x00, 0x01, 0xc0, 0x00, 0x44, 0x75, 0x63, 0x61, 0x81, 0x28, 0x01, 0xc0, 0xd8, |
1120 | | 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x03, 0x01, 0xca, 0x03, 0xaa, 0x09, 0x04, |
1121 | | 0x00, 0x00, 0x71, 0x17, 0x00, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00, 0x45, |
1122 | | 0x00, 0x52, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, |
1123 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1124 | | 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1125 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1126 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1127 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1128 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xca, 0x01, 0x00, 0x00, 0x00, |
1129 | | 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1130 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1131 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1132 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1133 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1134 | | 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1135 | | 0x02, 0xc0, 0x0c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x38, |
1136 | | 0x00, 0x04, 0x00, 0x00, 0x00, 0x72, 0x64, 0x70, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, |
1137 | | 0x80, 0x80, 0x72, 0x64, 0x70, 0x73, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, |
1138 | | 0x72, 0x64, 0x79, 0x6e, 0x76, 0x63, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x63, 0x6c, 0x69, 0x70, |
1139 | | 0x72, 0x64, 0x72, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0xff, |
1140 | | ]; |
1141 | | static TPKT_BEGIN: usize = 0; |
1142 | | static X223_BEGIN: usize = TPKT_BEGIN + 4; |
1143 | | static MCS_CONNECT_BEGIN: usize = X223_BEGIN + 3; |
1144 | | static MCS_CONNECT_END: usize = MCS_CONNECT_BEGIN + 421; |
1145 | | static X223_END: usize = MCS_CONNECT_END; |
1146 | | static TPKT_END: usize = X223_END; |
1147 | | static PADDING_BEGIN: usize = TPKT_END; |
1148 | | |
1149 | | #[test] |
1150 | | fn test_t123_x223_connect_core() { |
1151 | | let t123_bytes = &BYTES[TPKT_BEGIN..]; |
1152 | | let core_data = CsClientCoreData { |
1153 | | version: Some(RdpClientVersion::V5_V8_1), |
1154 | | desktop_width: 1280, |
1155 | | desktop_height: 768, |
1156 | | color_depth: Some(ColorDepth::RnsUdColor8Bpp), |
1157 | | sas_sequence: Some(SasSequence::RnsUdSasDel), |
1158 | | keyboard_layout: 0x409, |
1159 | | client_build: windows::OperatingSystem { |
1160 | | build: windows::Build::Vista_6001, |
1161 | | suffix: windows::Suffix::Sp1, |
1162 | | }, |
1163 | | client_name: String::from("SERVER-XYZ"), |
1164 | | keyboard_type: Some(KeyboardType::KbEnhanced), |
1165 | | keyboard_subtype: 0, |
1166 | | keyboard_function_key: 12, |
1167 | | ime_file_name: String::from(""), |
1168 | | post_beta2_color_depth: Some(PostBeta2ColorDepth::RnsUdColor8Bpp), |
1169 | | client_product_id: Some(1), |
1170 | | serial_number: Some(0), |
1171 | | high_color_depth: Some(HighColorDepth::HighColor8Bpp), |
1172 | | supported_color_depth: Some( |
1173 | | SupportedColorDepth::RNS_UD_15_BPP_SUPPORT |
1174 | | | SupportedColorDepth::RNS_UD_16_BPP_SUPPORT |
1175 | | | SupportedColorDepth::RNS_UD_24_BPP_SUPPORT |
1176 | | | SupportedColorDepth::RNS_UD_32_BPP_SUPPORT, |
1177 | | ), |
1178 | | early_capability_flags: Some( |
1179 | | EarlyCapabilityFlags::RNS_UD_CS_SUPPORT_ERRINFO_PDF |
1180 | | | EarlyCapabilityFlags::RNS_UD_CS_STRONG_ASYMMETRIC_KEYS, |
1181 | | ), |
1182 | | client_dig_product_id: Some(String::from("")), |
1183 | | connection_hint: Some(ConnectionHint::ConnectionHintNotProvided), |
1184 | | server_selected_protocol: Some(ProtocolFlags { bits: Protocol::ProtocolRdp as u32 }), |
1185 | | desktop_physical_width: None, |
1186 | | desktop_physical_height: None, |
1187 | | desktop_orientation: None, |
1188 | | desktop_scale_factor: None, |
1189 | | device_scale_factor: None, |
1190 | | }; |
1191 | | let mut children = Vec::new(); |
1192 | | children.push(McsConnectRequestChild::CsClientCore(core_data)); |
1193 | | children.push(McsConnectRequestChild::CsUnknown(CsUnknown { |
1194 | | typ: 0xc004, |
1195 | | data: BYTES[0x160..0x160 + 0x8].to_vec(), |
1196 | | })); |
1197 | | children.push(McsConnectRequestChild::CsUnknown(CsUnknown { |
1198 | | typ: 0xc002, |
1199 | | data: BYTES[0x16c..0x16c + 0x8].to_vec(), |
1200 | | })); |
1201 | | let mut channels = Vec::new(); |
1202 | | channels.push(String::from("rdpdr")); |
1203 | | channels.push(String::from("rdpsnd")); |
1204 | | channels.push(String::from("drdynvc")); |
1205 | | channels.push(String::from("cliprdr")); |
1206 | | children.push(McsConnectRequestChild::CsNet(CsNet { channels })); |
1207 | | let t123_tpkt: T123Tpkt = T123Tpkt { |
1208 | | child: T123TpktChild::Data(X223Data { |
1209 | | child: X223DataChild::McsConnectRequest(McsConnectRequest { children }), |
1210 | | }), |
1211 | | }; |
1212 | | assert_eq!( |
1213 | | Ok((&BYTES[PADDING_BEGIN..][..], t123_tpkt)), |
1214 | | parse_t123_tpkt(t123_bytes) |
1215 | | ); |
1216 | | } |
1217 | | } |
1218 | | |
1219 | | #[cfg(test)] |
1220 | | mod tests_x223_response_49350 { |
1221 | | use crate::rdp::parser::*; |
1222 | | |
1223 | | // changed offset 9 from 0x65 to 0x66 so it is no longer an mcs connect |
1224 | | static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x7f, 0x66]; |
1225 | | |
1226 | | #[test] |
1227 | | fn test_x223_response() { |
1228 | | let t123_bytes = &BYTES[..]; |
1229 | | assert_eq!( |
1230 | | Ok(( |
1231 | | &[][..], |
1232 | | T123Tpkt { |
1233 | | child: T123TpktChild::Data(X223Data { |
1234 | | child: X223DataChild::McsConnectResponse(McsConnectResponse {}), |
1235 | | }) |
1236 | | } |
1237 | | )), |
1238 | | parse_t123_tpkt(t123_bytes) |
1239 | | ) |
1240 | | } |
1241 | | } |
1242 | | |
1243 | | #[cfg(test)] |
1244 | | mod tests_t123_raw_49350 { |
1245 | | use crate::rdp::parser::*; |
1246 | | |
1247 | | // changed offset 4 from 0x02 to 0x03 so it is no longer an X223 data object |
1248 | | static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x03, 0xf0, 0x80, 0x7f, 0x65]; |
1249 | | |
1250 | | #[test] |
1251 | | fn test_t123_raw() { |
1252 | | let t123_bytes = &BYTES[..]; |
1253 | | assert_eq!( |
1254 | | Ok(( |
1255 | | &[][..], |
1256 | | T123Tpkt { |
1257 | | child: T123TpktChild::Raw(BYTES[4..].to_vec()) |
1258 | | } |
1259 | | )), |
1260 | | parse_t123_tpkt(t123_bytes) |
1261 | | ) |
1262 | | } |
1263 | | } |
1264 | | |
1265 | | #[cfg(test)] |
1266 | | mod tests_x224_raw_49350 { |
1267 | | use crate::rdp::parser::*; |
1268 | | |
1269 | | // changed offset 11 from 0x01 to 0x02 so it is not a known X224 payload type |
1270 | | static BYTES: [u8; 19] = [ |
1271 | | 0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, |
1272 | | 0x00, 0x00, 0x00, 0x00, |
1273 | | ]; |
1274 | | |
1275 | | #[test] |
1276 | | fn test_x224_raw() { |
1277 | | let t123_bytes = &BYTES[..]; |
1278 | | assert_eq!( |
1279 | | Ok(( |
1280 | | &[][..], |
1281 | | T123Tpkt { |
1282 | | child: T123TpktChild::X224ConnectionRequest(X224ConnectionRequest { |
1283 | | cdt: 0, |
1284 | | dst_ref: 0, |
1285 | | src_ref: 0, |
1286 | | class: 0, |
1287 | | options: 0, |
1288 | | cookie: None, |
1289 | | negotiation_request: None, |
1290 | | data: BYTES[11..].to_vec(), |
1291 | | }) |
1292 | | } |
1293 | | )), |
1294 | | parse_t123_tpkt(t123_bytes) |
1295 | | ) |
1296 | | } |
1297 | | } |
1298 | | |
1299 | | #[cfg(test)] |
1300 | | mod tests_x223_raw_49350 { |
1301 | | use crate::rdp::parser::*; |
1302 | | |
1303 | | // changed offset 9 from 0x65 to 0xff so it is no longer an mcs connect |
1304 | | static BYTES: [u8; 9] = [0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x7f, 0xff]; |
1305 | | |
1306 | | #[test] |
1307 | | fn test_x223_raw() { |
1308 | | let t123_bytes = &BYTES[..]; |
1309 | | assert_eq!( |
1310 | | Ok(( |
1311 | | &[][..], |
1312 | | T123Tpkt { |
1313 | | child: T123TpktChild::Data(X223Data { |
1314 | | child: X223DataChild::Raw(BYTES[7..].to_vec()), |
1315 | | }) |
1316 | | } |
1317 | | )), |
1318 | | parse_t123_tpkt(t123_bytes) |
1319 | | ) |
1320 | | } |
1321 | | } |
1322 | | |
1323 | | #[cfg(test)] |
1324 | | mod tests_negotiate_incomplete_49350 { |
1325 | | use crate::rdp::parser::*; |
1326 | | use nom7::Needed; |
1327 | | |
1328 | | static BYTES: [u8; 19] = [ |
1329 | | 0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, |
1330 | | 0x00, 0x00, 0x00, 0x00, |
1331 | | ]; |
1332 | | static TPKT_BEGIN: usize = 0; |
1333 | | static X224_BEGIN: usize = TPKT_BEGIN + 4; |
1334 | | static NEG_REQ_BEGIN: usize = X224_BEGIN + 7; |
1335 | | static NEG_REQ_END: usize = NEG_REQ_BEGIN + 8; |
1336 | | static X224_END: usize = NEG_REQ_END; |
1337 | | static TPKT_END: usize = X224_END; |
1338 | | |
1339 | | #[test] |
1340 | | fn test_t123_incomplete() { |
1341 | | let t123_bytes = &BYTES[TPKT_BEGIN..TPKT_END - 1]; |
1342 | | assert_eq!( |
1343 | | // fails: map_opt!(i2, be_u16, |x: u16| x.checked_sub(4))? |
1344 | | Err(Err::Incomplete(Needed::new(1))), |
1345 | | parse_t123_tpkt(t123_bytes) |
1346 | | ) |
1347 | | } |
1348 | | |
1349 | | #[test] |
1350 | | fn test_x224_incomplete() { |
1351 | | let x224_bytes = &BYTES[X224_BEGIN..X224_END - 1]; |
1352 | | assert_eq!( |
1353 | | // fails: expr_opt!(i5, length.checked_sub(6))? |
1354 | | // not counting a u8 length read, which was also successful |
1355 | | Err(Err::Incomplete(Needed::new( 1))), |
1356 | | parse_x224_connection_request_class_0(x224_bytes) |
1357 | | ) |
1358 | | } |
1359 | | |
1360 | | #[test] |
1361 | | fn test_negotiate_incomplete() { |
1362 | | let neg_req_bytes = &BYTES[NEG_REQ_BEGIN..NEG_REQ_END - 1]; |
1363 | | assert_eq!( |
1364 | | // fails: map_opt!(le_u32, num::FromPrimitive::from_u32)? |
1365 | | Err(Err::Incomplete(Needed::new(1))), |
1366 | | parse_negotiation_request(neg_req_bytes) |
1367 | | ) |
1368 | | } |
1369 | | } |
1370 | | |
1371 | | #[cfg(test)] |
1372 | | mod tests_core_incomplete_49350 { |
1373 | | use crate::rdp::parser::*; |
1374 | | use nom7::Needed; |
1375 | | |
1376 | | static BYTES: [u8; 428] = [ |
1377 | | 0x03, 0x00, 0x01, 0xac, 0x02, 0xf0, 0x80, 0x7f, 0x65, 0x82, 0x01, 0xa0, 0x04, 0x01, 0x01, |
1378 | | 0x04, 0x01, 0x01, 0x01, 0x01, 0xff, 0x30, 0x19, 0x02, 0x01, 0x22, 0x02, 0x01, 0x02, 0x02, |
1379 | | 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, |
1380 | | 0x02, 0x01, 0x02, 0x30, 0x19, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, |
1381 | | 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x20, 0x02, 0x01, 0x02, |
1382 | | 0x30, 0x1c, 0x02, 0x02, 0xff, 0xff, 0x02, 0x02, 0xfc, 0x17, 0x02, 0x02, 0xff, 0xff, 0x02, |
1383 | | 0x01, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, 0x02, 0x01, 0x02, |
1384 | | 0x04, 0x82, 0x01, 0x3f, 0x00, 0x05, 0x00, 0x14, 0x7c, 0x00, 0x01, 0x81, 0x36, 0x00, 0x08, |
1385 | | 0x00, 0x10, 0x00, 0x01, 0xc0, 0x00, 0x44, 0x75, 0x63, 0x61, 0x81, 0x28, 0x01, 0xc0, 0xd8, |
1386 | | 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x03, 0x01, 0xca, 0x03, 0xaa, 0x09, 0x04, |
1387 | | 0x00, 0x00, 0x71, 0x17, 0x00, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00, 0x45, |
1388 | | 0x00, 0x52, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, |
1389 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1390 | | 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1391 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1392 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1393 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1394 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xca, 0x01, 0x00, 0x00, 0x00, |
1395 | | 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1396 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1397 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1398 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1399 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1400 | | 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1401 | | 0x02, 0xc0, 0x0c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x38, |
1402 | | 0x00, 0x04, 0x00, 0x00, 0x00, 0x72, 0x64, 0x70, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, |
1403 | | 0x80, 0x80, 0x72, 0x64, 0x70, 0x73, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, |
1404 | | 0x72, 0x64, 0x79, 0x6e, 0x76, 0x63, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x63, 0x6c, 0x69, 0x70, |
1405 | | 0x72, 0x64, 0x72, 0x00, 0x00, 0x00, 0xa0, 0xc0, |
1406 | | ]; |
1407 | | static X223_BEGIN: usize = 4; |
1408 | | static MCS_CONNECT_BEGIN: usize = X223_BEGIN + 3; |
1409 | | static MCS_CONNECT_END: usize = MCS_CONNECT_BEGIN + 421; |
1410 | | static _X223_END: usize = MCS_CONNECT_END; |
1411 | | |
1412 | | #[test] |
1413 | | fn test_x223_incomplete() { |
1414 | | let x223_bytes = &BYTES[X223_BEGIN..X223_BEGIN + 2]; |
1415 | | assert_eq!( |
1416 | | // fails: verify!(i2, be_u8, |x| x == 0x80)? |
1417 | | Err(Err::Incomplete(Needed::new(1))), |
1418 | | parse_x223_data_class_0(x223_bytes) |
1419 | | ) |
1420 | | } |
1421 | | |
1422 | | #[test] |
1423 | | fn test_connect_incomplete() { |
1424 | | let connect_bytes = &BYTES[MCS_CONNECT_BEGIN..MCS_CONNECT_END - 1]; |
1425 | | assert_eq!( |
1426 | | // fails: length_data!(i3, parse_per_length_determinant)? |
1427 | | // which reads the length (2) but not the full data (0x128) |
1428 | | Err(Err::Incomplete(Needed::new(1))), |
1429 | | parse_mcs_connect(connect_bytes) |
1430 | | ) |
1431 | | } |
1432 | | } |