1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Fast Path
4 *
5 * Copyright 2011 Vic Lee
6 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
7 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
8 * Copyright 2017 Thincast Technologies GmbH
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <winpr/crt.h>
32 #include <winpr/stream.h>
33
34 #include <freerdp/api.h>
35 #include <freerdp/log.h>
36 #include <freerdp/crypto/per.h>
37
38 #include "orders.h"
39 #include "update.h"
40 #include "surface.h"
41 #include "fastpath.h"
42 #include "rdp.h"
43
44 #include "../cache/pointer.h"
45 #include "../cache/palette.h"
46 #include "../cache/bitmap.h"
47
48 #define TAG FREERDP_TAG("core.fastpath")
49
50 /**
51 * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises
52 * server output packets from the first byte with the goal of improving
53 * bandwidth.
54 *
55 * Slow-Path packet always starts with TPKT header, which has the first
56 * byte 0x03, while Fast-Path packet starts with 2 zero bits in the first
57 * two less significant bits of the first byte.
58 */
59
60 static const char* const FASTPATH_UPDATETYPE_STRINGS[] = {
61 "Orders", /* 0x0 */
62 "Bitmap", /* 0x1 */
63 "Palette", /* 0x2 */
64 "Synchronize", /* 0x3 */
65 "Surface Commands", /* 0x4 */
66 "System Pointer Hidden", /* 0x5 */
67 "System Pointer Default", /* 0x6 */
68 "???", /* 0x7 */
69 "Pointer Position", /* 0x8 */
70 "Color Pointer", /* 0x9 */
71 "Cached Pointer", /* 0xA */
72 "New Pointer", /* 0xB */
73 };
74
fastpath_update_to_string(UINT8 update)75 static const char* fastpath_update_to_string(UINT8 update)
76 {
77 if (update >= ARRAYSIZE(FASTPATH_UPDATETYPE_STRINGS))
78 return "UNKNOWN";
79
80 return FASTPATH_UPDATETYPE_STRINGS[update];
81 }
82
83 /*
84 * The fastpath header may be two or three bytes long.
85 * This function assumes that at least two bytes are available in the stream
86 * and doesn't touch third byte.
87 */
fastpath_header_length(wStream * s)88 UINT16 fastpath_header_length(wStream* s)
89 {
90 BYTE length1;
91
92 if (!s || (Stream_GetRemainingLength(s) < 2))
93 return 0;
94
95 Stream_Seek_UINT8(s);
96 Stream_Read_UINT8(s, length1);
97 Stream_Rewind(s, 2);
98 return ((length1 & 0x80) != 0 ? 3 : 2);
99 }
100
101 /**
102 * Read a Fast-Path packet header.\n
103 * @param s stream
104 * @param encryptionFlags
105 * @return length
106 */
fastpath_read_header(rdpFastPath * fastpath,wStream * s)107 UINT16 fastpath_read_header(rdpFastPath* fastpath, wStream* s)
108 {
109 BYTE header;
110 UINT16 length;
111
112 if (!s || (Stream_GetRemainingLength(s) < 1))
113 return 0;
114
115 Stream_Read_UINT8(s, header);
116
117 if (fastpath)
118 {
119 fastpath->encryptionFlags = (header & 0xC0) >> 6;
120 fastpath->numberEvents = (header & 0x3C) >> 2;
121 }
122
123 if (!per_read_length(s, &length))
124 return 0;
125
126 return length;
127 }
128
fastpath_read_update_header(wStream * s,BYTE * updateCode,BYTE * fragmentation,BYTE * compression)129 static BOOL fastpath_read_update_header(wStream* s, BYTE* updateCode, BYTE* fragmentation,
130 BYTE* compression)
131 {
132 BYTE updateHeader;
133
134 if (!s || !updateCode || !fragmentation || !compression)
135 return FALSE;
136
137 if (Stream_GetRemainingLength(s) < 1)
138 return FALSE;
139
140 Stream_Read_UINT8(s, updateHeader);
141 *updateCode = updateHeader & 0x0F;
142 *fragmentation = (updateHeader >> 4) & 0x03;
143 *compression = (updateHeader >> 6) & 0x03;
144 return TRUE;
145 }
146
fastpath_write_update_header(wStream * s,FASTPATH_UPDATE_HEADER * fpUpdateHeader)147 static BOOL fastpath_write_update_header(wStream* s, FASTPATH_UPDATE_HEADER* fpUpdateHeader)
148 {
149 if (!s || !fpUpdateHeader)
150 return FALSE;
151
152 fpUpdateHeader->updateHeader = 0;
153 fpUpdateHeader->updateHeader |= fpUpdateHeader->updateCode & 0x0F;
154 fpUpdateHeader->updateHeader |= (fpUpdateHeader->fragmentation & 0x03) << 4;
155 fpUpdateHeader->updateHeader |= (fpUpdateHeader->compression & 0x03) << 6;
156 Stream_Write_UINT8(s, fpUpdateHeader->updateHeader);
157
158 if (fpUpdateHeader->compression)
159 {
160 if (Stream_GetRemainingCapacity(s) < 1)
161 return FALSE;
162
163 Stream_Write_UINT8(s, fpUpdateHeader->compressionFlags);
164 }
165
166 if (Stream_GetRemainingCapacity(s) < 2)
167 return FALSE;
168
169 Stream_Write_UINT16(s, fpUpdateHeader->size);
170 return TRUE;
171 }
172
fastpath_get_update_header_size(FASTPATH_UPDATE_HEADER * fpUpdateHeader)173 static UINT32 fastpath_get_update_header_size(FASTPATH_UPDATE_HEADER* fpUpdateHeader)
174 {
175 if (!fpUpdateHeader)
176 return 0;
177
178 return (fpUpdateHeader->compression) ? 4 : 3;
179 }
180
fastpath_write_update_pdu_header(wStream * s,FASTPATH_UPDATE_PDU_HEADER * fpUpdatePduHeader,rdpRdp * rdp)181 static BOOL fastpath_write_update_pdu_header(wStream* s,
182 FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader,
183 rdpRdp* rdp)
184 {
185 if (!s || !fpUpdatePduHeader || !rdp)
186 return FALSE;
187
188 if (Stream_GetRemainingCapacity(s) < 3)
189 return FALSE;
190
191 fpUpdatePduHeader->fpOutputHeader = 0;
192 fpUpdatePduHeader->fpOutputHeader |= (fpUpdatePduHeader->action & 0x03);
193 fpUpdatePduHeader->fpOutputHeader |= (fpUpdatePduHeader->secFlags & 0x03) << 6;
194 Stream_Write_UINT8(s, fpUpdatePduHeader->fpOutputHeader); /* fpOutputHeader (1 byte) */
195 Stream_Write_UINT8(s, 0x80 | (fpUpdatePduHeader->length >> 8)); /* length1 */
196 Stream_Write_UINT8(s, fpUpdatePduHeader->length & 0xFF); /* length2 */
197
198 if (fpUpdatePduHeader->secFlags)
199 {
200 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
201 {
202 if (Stream_GetRemainingCapacity(s) < 4)
203 return FALSE;
204
205 Stream_Write(s, fpUpdatePduHeader->fipsInformation, 4);
206 }
207
208 if (Stream_GetRemainingCapacity(s) < 8)
209 return FALSE;
210
211 Stream_Write(s, fpUpdatePduHeader->dataSignature, 8);
212 }
213
214 return FALSE;
215 }
216
fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER * fpUpdatePduHeader,rdpRdp * rdp)217 static UINT32 fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader,
218 rdpRdp* rdp)
219 {
220 UINT32 size = 3; /* fpUpdatePduHeader + length1 + length2 */
221
222 if (!fpUpdatePduHeader || !rdp)
223 return 0;
224
225 if (fpUpdatePduHeader->secFlags)
226 {
227 size += 8; /* dataSignature */
228
229 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
230 size += 4; /* fipsInformation */
231 }
232
233 return size;
234 }
235
fastpath_read_header_rdp(rdpFastPath * fastpath,wStream * s,UINT16 * length)236 BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16* length)
237 {
238 BYTE header;
239
240 if (!s || !length)
241 return FALSE;
242
243 if (Stream_GetRemainingLength(s) < 1)
244 return FALSE;
245
246 Stream_Read_UINT8(s, header);
247
248 if (fastpath)
249 {
250 fastpath->encryptionFlags = (header & 0xC0) >> 6;
251 fastpath->numberEvents = (header & 0x3C) >> 2;
252 }
253
254 if (!per_read_length(s, length))
255 return FALSE;
256
257 *length = *length - Stream_GetPosition(s);
258 return TRUE;
259 }
260
fastpath_recv_orders(rdpFastPath * fastpath,wStream * s)261 static BOOL fastpath_recv_orders(rdpFastPath* fastpath, wStream* s)
262 {
263 rdpUpdate* update;
264 UINT16 numberOrders;
265
266 if (!fastpath || !fastpath->rdp || !s)
267 {
268 WLog_ERR(TAG, "Invalid arguments");
269 return FALSE;
270 }
271
272 update = fastpath->rdp->update;
273
274 if (!update)
275 {
276 WLog_ERR(TAG, "Invalid configuration");
277 return FALSE;
278 }
279
280 if (Stream_GetRemainingLength(s) < 2)
281 {
282 WLog_ERR(TAG, "Stream short");
283 return FALSE;
284 }
285
286 Stream_Read_UINT16(s, numberOrders); /* numberOrders (2 bytes) */
287
288 while (numberOrders > 0)
289 {
290 if (!update_recv_order(update, s))
291 return FALSE;
292
293 numberOrders--;
294 }
295
296 return TRUE;
297 }
298
fastpath_recv_update_common(rdpFastPath * fastpath,wStream * s)299 static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s)
300 {
301 BOOL rc = FALSE;
302 UINT16 updateType;
303 rdpUpdate* update;
304 rdpContext* context;
305
306 if (!fastpath || !s || !fastpath->rdp)
307 return FALSE;
308
309 update = fastpath->rdp->update;
310
311 if (!update || !update->context)
312 return FALSE;
313
314 context = update->context;
315
316 if (Stream_GetRemainingLength(s) < 2)
317 return FALSE;
318
319 Stream_Read_UINT16(s, updateType); /* updateType (2 bytes) */
320 switch (updateType)
321 {
322 case UPDATE_TYPE_BITMAP:
323 {
324 BITMAP_UPDATE* bitmap_update = update_read_bitmap_update(update, s);
325
326 if (!bitmap_update)
327 return FALSE;
328
329 rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap_update);
330 free_bitmap_update(context, bitmap_update);
331 }
332 break;
333
334 case UPDATE_TYPE_PALETTE:
335 {
336 PALETTE_UPDATE* palette_update = update_read_palette(update, s);
337
338 if (!palette_update)
339 return FALSE;
340
341 rc = IFCALLRESULT(FALSE, update->Palette, context, palette_update);
342 free_palette_update(context, palette_update);
343 }
344 break;
345
346 default:
347 break;
348 }
349
350 return rc;
351 }
352
fastpath_recv_update_synchronize(rdpFastPath * fastpath,wStream * s)353 static BOOL fastpath_recv_update_synchronize(rdpFastPath* fastpath, wStream* s)
354 {
355 /* server 2008 can send invalid synchronize packet with missing padding,
356 so don't return FALSE even if the packet is invalid */
357 Stream_SafeSeek(s, 2); /* size (2 bytes), MUST be set to zero */
358 return TRUE;
359 }
360
fastpath_recv_update(rdpFastPath * fastpath,BYTE updateCode,wStream * s)361 static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, wStream* s)
362 {
363 BOOL rc = FALSE;
364 int status = 0;
365 rdpUpdate* update;
366 rdpContext* context;
367 rdpPointerUpdate* pointer;
368
369 if (!fastpath || !fastpath->rdp || !s)
370 return -1;
371
372 update = fastpath->rdp->update;
373
374 if (!update || !update->pointer || !update->context)
375 return -1;
376
377 context = update->context;
378 pointer = update->pointer;
379 #ifdef WITH_DEBUG_RDP
380 DEBUG_RDP("recv Fast-Path %s Update (0x%02" PRIX8 "), length:%" PRIuz "",
381 fastpath_update_to_string(updateCode), updateCode, Stream_GetRemainingLength(s));
382 #endif
383
384 switch (updateCode)
385 {
386 case FASTPATH_UPDATETYPE_ORDERS:
387 rc = fastpath_recv_orders(fastpath, s);
388 break;
389
390 case FASTPATH_UPDATETYPE_BITMAP:
391 case FASTPATH_UPDATETYPE_PALETTE:
392 rc = fastpath_recv_update_common(fastpath, s);
393 break;
394
395 case FASTPATH_UPDATETYPE_SYNCHRONIZE:
396 if (!fastpath_recv_update_synchronize(fastpath, s))
397 WLog_ERR(TAG, "fastpath_recv_update_synchronize failure but we continue");
398 else
399 rc = IFCALLRESULT(TRUE, update->Synchronize, context);
400
401 break;
402
403 case FASTPATH_UPDATETYPE_SURFCMDS:
404 status = update_recv_surfcmds(update, s);
405 rc = (status < 0) ? FALSE : TRUE;
406 break;
407
408 case FASTPATH_UPDATETYPE_PTR_NULL:
409 {
410 POINTER_SYSTEM_UPDATE pointer_system;
411 pointer_system.type = SYSPTR_NULL;
412 rc = IFCALLRESULT(FALSE, pointer->PointerSystem, context, &pointer_system);
413 }
414 break;
415
416 case FASTPATH_UPDATETYPE_PTR_DEFAULT:
417 {
418 POINTER_SYSTEM_UPDATE pointer_system;
419 pointer_system.type = SYSPTR_DEFAULT;
420 rc = IFCALLRESULT(FALSE, pointer->PointerSystem, context, &pointer_system);
421 }
422 break;
423
424 case FASTPATH_UPDATETYPE_PTR_POSITION:
425 {
426 POINTER_POSITION_UPDATE* pointer_position = update_read_pointer_position(update, s);
427
428 if (pointer_position)
429 {
430 rc = IFCALLRESULT(FALSE, pointer->PointerPosition, context, pointer_position);
431 free_pointer_position_update(context, pointer_position);
432 }
433 }
434 break;
435
436 case FASTPATH_UPDATETYPE_COLOR:
437 {
438 POINTER_COLOR_UPDATE* pointer_color = update_read_pointer_color(update, s, 24);
439
440 if (pointer_color)
441 {
442 rc = IFCALLRESULT(FALSE, pointer->PointerColor, context, pointer_color);
443 free_pointer_color_update(context, pointer_color);
444 }
445 }
446 break;
447
448 case FASTPATH_UPDATETYPE_CACHED:
449 {
450 POINTER_CACHED_UPDATE* pointer_cached = update_read_pointer_cached(update, s);
451
452 if (pointer_cached)
453 {
454 rc = IFCALLRESULT(FALSE, pointer->PointerCached, context, pointer_cached);
455 free_pointer_cached_update(context, pointer_cached);
456 }
457 }
458 break;
459
460 case FASTPATH_UPDATETYPE_POINTER:
461 {
462 POINTER_NEW_UPDATE* pointer_new = update_read_pointer_new(update, s);
463
464 if (pointer_new)
465 {
466 rc = IFCALLRESULT(FALSE, pointer->PointerNew, context, pointer_new);
467 free_pointer_new_update(context, pointer_new);
468 }
469 }
470 break;
471
472 case FASTPATH_UPDATETYPE_LARGE_POINTER:
473 {
474 POINTER_LARGE_UPDATE* pointer_large = update_read_pointer_large(update, s);
475
476 if (pointer_large)
477 {
478 rc = IFCALLRESULT(FALSE, pointer->PointerLarge, context, pointer_large);
479 free_pointer_large_update(context, pointer_large);
480 }
481 }
482 break;
483 default:
484 break;
485 }
486
487 if (!rc)
488 {
489 WLog_ERR(TAG, "Fastpath update %s [%" PRIx8 "] failed, status %d",
490 fastpath_update_to_string(updateCode), updateCode, status);
491 return -1;
492 }
493
494 return status;
495 }
496
fastpath_recv_update_data(rdpFastPath * fastpath,wStream * s)497 static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
498 {
499 int status;
500 UINT16 size;
501 rdpRdp* rdp;
502 int bulkStatus;
503 BYTE updateCode;
504 BYTE fragmentation;
505 BYTE compression;
506 BYTE compressionFlags;
507 UINT32 DstSize = 0;
508 BYTE* pDstData = NULL;
509 rdpTransport* transport;
510
511 if (!fastpath || !s)
512 return -1;
513
514 status = 0;
515 rdp = fastpath->rdp;
516
517 if (!rdp)
518 return -1;
519
520 transport = fastpath->rdp->transport;
521
522 if (!transport)
523 return -1;
524
525 if (!fastpath_read_update_header(s, &updateCode, &fragmentation, &compression))
526 return -1;
527
528 if (compression == FASTPATH_OUTPUT_COMPRESSION_USED)
529 {
530 if (Stream_GetRemainingLength(s) < 1)
531 return -1;
532
533 Stream_Read_UINT8(s, compressionFlags);
534 }
535 else
536 compressionFlags = 0;
537
538 if (Stream_GetRemainingLength(s) < 2)
539 return -1;
540
541 Stream_Read_UINT16(s, size);
542
543 if (Stream_GetRemainingLength(s) < size)
544 {
545 WLog_ERR(TAG, "Stream_GetRemainingLength() < size");
546 return -1;
547 }
548
549 bulkStatus =
550 bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags);
551 Stream_Seek(s, size);
552
553 if (bulkStatus < 0)
554 {
555 WLog_ERR(TAG, "bulk_decompress() failed");
556 return -1;
557 }
558
559 if (!Stream_EnsureRemainingCapacity(fastpath->updateData, DstSize))
560 return -1;
561
562 Stream_Write(fastpath->updateData, pDstData, DstSize);
563
564 if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
565 {
566 if (fastpath->fragmentation != -1)
567 {
568 WLog_ERR(TAG, "Unexpected FASTPATH_FRAGMENT_SINGLE");
569 goto out_fail;
570 }
571
572 Stream_SealLength(fastpath->updateData);
573 Stream_SetPosition(fastpath->updateData, 0);
574 status = fastpath_recv_update(fastpath, updateCode, fastpath->updateData);
575 Stream_SetPosition(fastpath->updateData, 0);
576
577 if (status < 0)
578 {
579 WLog_ERR(TAG, "fastpath_recv_update() - %i", status);
580 goto out_fail;
581 }
582 }
583 else
584 {
585 const size_t totalSize = Stream_GetPosition(fastpath->updateData);
586
587 if (totalSize > transport->settings->MultifragMaxRequestSize)
588 {
589 WLog_ERR(TAG, "Total size (%" PRIuz ") exceeds MultifragMaxRequestSize (%" PRIu32 ")",
590 totalSize, transport->settings->MultifragMaxRequestSize);
591 goto out_fail;
592 }
593
594 if (fragmentation == FASTPATH_FRAGMENT_FIRST)
595 {
596 if (fastpath->fragmentation != -1)
597 {
598 WLog_ERR(TAG, "fastpath_recv_update_data: Unexpected FASTPATH_FRAGMENT_FIRST");
599 goto out_fail;
600 }
601
602 fastpath->fragmentation = FASTPATH_FRAGMENT_FIRST;
603 }
604 else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
605 {
606 if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
607 (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
608 {
609 WLog_ERR(TAG, "fastpath_recv_update_data: Unexpected FASTPATH_FRAGMENT_NEXT");
610 goto out_fail;
611 }
612
613 fastpath->fragmentation = FASTPATH_FRAGMENT_NEXT;
614 }
615 else if (fragmentation == FASTPATH_FRAGMENT_LAST)
616 {
617 if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
618 (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
619 {
620 WLog_ERR(TAG, "fastpath_recv_update_data: Unexpected FASTPATH_FRAGMENT_LAST");
621 goto out_fail;
622 }
623
624 fastpath->fragmentation = -1;
625 Stream_SealLength(fastpath->updateData);
626 Stream_SetPosition(fastpath->updateData, 0);
627 status = fastpath_recv_update(fastpath, updateCode, fastpath->updateData);
628 Stream_SetPosition(fastpath->updateData, 0);
629
630 if (status < 0)
631 {
632 WLog_ERR(TAG, "fastpath_recv_update_data: fastpath_recv_update() - %i", status);
633 goto out_fail;
634 }
635 }
636 }
637
638 return status;
639 out_fail:
640 return -1;
641 }
642
fastpath_recv_updates(rdpFastPath * fastpath,wStream * s)643 int fastpath_recv_updates(rdpFastPath* fastpath, wStream* s)
644 {
645 int rc = -2;
646 rdpUpdate* update;
647
648 if (!fastpath || !fastpath->rdp || !fastpath->rdp->update || !s)
649 return -1;
650
651 update = fastpath->rdp->update;
652
653 if (!update_begin_paint(update))
654 goto fail;
655
656 while (Stream_GetRemainingLength(s) >= 3)
657 {
658 if (fastpath_recv_update_data(fastpath, s) < 0)
659 {
660 WLog_ERR(TAG, "fastpath_recv_update_data() fail");
661 rc = -3;
662 goto fail;
663 }
664 }
665
666 rc = 0;
667 fail:
668
669 if (!update_end_paint(update))
670 return -4;
671
672 return rc;
673 }
674
fastpath_read_input_event_header(wStream * s,BYTE * eventFlags,BYTE * eventCode)675 static BOOL fastpath_read_input_event_header(wStream* s, BYTE* eventFlags, BYTE* eventCode)
676 {
677 BYTE eventHeader;
678
679 if (!s || !eventFlags || !eventCode)
680 return FALSE;
681
682 if (Stream_GetRemainingLength(s) < 1)
683 return FALSE;
684
685 Stream_Read_UINT8(s, eventHeader); /* eventHeader (1 byte) */
686 *eventFlags = (eventHeader & 0x1F);
687 *eventCode = (eventHeader >> 5);
688 return TRUE;
689 }
690
fastpath_recv_input_event_scancode(rdpFastPath * fastpath,wStream * s,BYTE eventFlags)691 static BOOL fastpath_recv_input_event_scancode(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
692 {
693 rdpInput* input;
694 UINT16 flags;
695 UINT16 code;
696
697 if (!fastpath || !fastpath->rdp || !fastpath->rdp->input || !s)
698 return FALSE;
699
700 input = fastpath->rdp->input;
701
702 if (Stream_GetRemainingLength(s) < 1)
703 return FALSE;
704
705 Stream_Read_UINT8(s, code); /* keyCode (1 byte) */
706 flags = 0;
707
708 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
709 flags |= KBD_FLAGS_RELEASE;
710 else
711 flags |= KBD_FLAGS_DOWN;
712
713 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED))
714 flags |= KBD_FLAGS_EXTENDED;
715
716 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_PREFIX_E1))
717 flags |= KBD_FLAGS_EXTENDED1;
718
719 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
720 }
721
fastpath_recv_input_event_mouse(rdpFastPath * fastpath,wStream * s,BYTE eventFlags)722 static BOOL fastpath_recv_input_event_mouse(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
723 {
724 rdpInput* input;
725 UINT16 pointerFlags;
726 UINT16 xPos;
727 UINT16 yPos;
728
729 if (!fastpath || !fastpath->rdp || !fastpath->rdp->input || !s)
730 return FALSE;
731
732 input = fastpath->rdp->input;
733
734 if (Stream_GetRemainingLength(s) < 6)
735 return FALSE;
736
737 Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
738 Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
739 Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
740 return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
741 }
742
fastpath_recv_input_event_mousex(rdpFastPath * fastpath,wStream * s,BYTE eventFlags)743 static BOOL fastpath_recv_input_event_mousex(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
744 {
745 rdpInput* input;
746 UINT16 pointerFlags;
747 UINT16 xPos;
748 UINT16 yPos;
749
750 if (!fastpath || !fastpath->rdp || !fastpath->rdp->input || !s)
751 return FALSE;
752
753 input = fastpath->rdp->input;
754
755 if (Stream_GetRemainingLength(s) < 6)
756 return FALSE;
757
758 Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
759 Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
760 Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
761 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
762 }
763
fastpath_recv_input_event_sync(rdpFastPath * fastpath,wStream * s,BYTE eventFlags)764 static BOOL fastpath_recv_input_event_sync(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
765 {
766 rdpInput* input;
767
768 if (!fastpath || !fastpath->rdp || !fastpath->rdp->input || !s)
769 return FALSE;
770
771 input = fastpath->rdp->input;
772 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, eventFlags);
773 }
774
fastpath_recv_input_event_unicode(rdpFastPath * fastpath,wStream * s,BYTE eventFlags)775 static BOOL fastpath_recv_input_event_unicode(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
776 {
777 UINT16 unicodeCode;
778 UINT16 flags;
779
780 if (!fastpath || !s)
781 return FALSE;
782
783 if (Stream_GetRemainingLength(s) < 2)
784 return FALSE;
785
786 Stream_Read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */
787 flags = 0;
788
789 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
790 flags |= KBD_FLAGS_RELEASE;
791 else
792 flags |= KBD_FLAGS_DOWN;
793
794 return IFCALLRESULT(FALSE, fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input,
795 flags, unicodeCode);
796 }
797
fastpath_recv_input_event(rdpFastPath * fastpath,wStream * s)798 static BOOL fastpath_recv_input_event(rdpFastPath* fastpath, wStream* s)
799 {
800 BYTE eventFlags;
801 BYTE eventCode;
802
803 if (!fastpath || !s)
804 return FALSE;
805
806 if (!fastpath_read_input_event_header(s, &eventFlags, &eventCode))
807 return FALSE;
808
809 switch (eventCode)
810 {
811 case FASTPATH_INPUT_EVENT_SCANCODE:
812 if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags))
813 return FALSE;
814
815 break;
816
817 case FASTPATH_INPUT_EVENT_MOUSE:
818 if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags))
819 return FALSE;
820
821 break;
822
823 case FASTPATH_INPUT_EVENT_MOUSEX:
824 if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags))
825 return FALSE;
826
827 break;
828
829 case FASTPATH_INPUT_EVENT_SYNC:
830 if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags))
831 return FALSE;
832
833 break;
834
835 case FASTPATH_INPUT_EVENT_UNICODE:
836 if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags))
837 return FALSE;
838
839 break;
840
841 default:
842 WLog_ERR(TAG, "Unknown eventCode %" PRIu8 "", eventCode);
843 break;
844 }
845
846 return TRUE;
847 }
848
fastpath_recv_inputs(rdpFastPath * fastpath,wStream * s)849 int fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s)
850 {
851 BYTE i;
852
853 if (!fastpath || !s)
854 return -1;
855
856 if (fastpath->numberEvents == 0)
857 {
858 /**
859 * If numberEvents is not provided in fpInputHeader, it will be provided
860 * as one additional byte here.
861 */
862 if (Stream_GetRemainingLength(s) < 1)
863 return -1;
864
865 Stream_Read_UINT8(s, fastpath->numberEvents); /* eventHeader (1 byte) */
866 }
867
868 for (i = 0; i < fastpath->numberEvents; i++)
869 {
870 if (!fastpath_recv_input_event(fastpath, s))
871 return -1;
872 }
873
874 return 0;
875 }
876
fastpath_get_sec_bytes(rdpRdp * rdp)877 static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp)
878 {
879 UINT32 sec_bytes;
880 sec_bytes = 0;
881
882 if (!rdp)
883 return 0;
884
885 if (rdp->do_crypt)
886 {
887 sec_bytes = 8;
888
889 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
890 sec_bytes += 4;
891 }
892
893 return sec_bytes;
894 }
895
fastpath_input_pdu_init_header(rdpFastPath * fastpath)896 wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath)
897 {
898 rdpRdp* rdp;
899 wStream* s;
900
901 if (!fastpath || !fastpath->rdp)
902 return NULL;
903
904 rdp = fastpath->rdp;
905 s = transport_send_stream_init(rdp->transport, 256);
906
907 if (!s)
908 return NULL;
909
910 Stream_Seek(s, 3); /* fpInputHeader, length1 and length2 */
911
912 if (rdp->do_crypt)
913 {
914 rdp->sec_flags |= SEC_ENCRYPT;
915
916 if (rdp->do_secure_checksum)
917 rdp->sec_flags |= SEC_SECURE_CHECKSUM;
918 }
919
920 Stream_Seek(s, fastpath_get_sec_bytes(rdp));
921 return s;
922 }
923
fastpath_input_pdu_init(rdpFastPath * fastpath,BYTE eventFlags,BYTE eventCode)924 wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode)
925 {
926 wStream* s;
927 s = fastpath_input_pdu_init_header(fastpath);
928
929 if (!s)
930 return NULL;
931
932 Stream_Write_UINT8(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */
933 return s;
934 }
935
fastpath_send_multiple_input_pdu(rdpFastPath * fastpath,wStream * s,size_t iNumEvents)936 BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, size_t iNumEvents)
937 {
938 int state;
939 BOOL rc = FALSE;
940 rdpRdp* rdp;
941 UINT16 length;
942 BYTE eventHeader;
943
944 if (!s)
945 return FALSE;
946
947 if (!fastpath)
948 goto fail;
949
950 rdp = fastpath->rdp;
951 state = rdp_client_get_state(rdp);
952 if (state != CONNECTION_STATE_ACTIVE)
953 {
954 WLog_WARN(TAG, "[%s] called before activation [%s]", __FUNCTION__,
955 rdp_client_connection_state_string(state));
956 goto fail;
957 }
958
959 /*
960 * A maximum of 15 events are allowed per request
961 * if the optional numEvents field isn't used
962 * see MS-RDPBCGR 2.2.8.1.2 for details
963 */
964 if (iNumEvents > 15)
965 goto fail;
966
967 length = Stream_GetPosition(s);
968
969 if (length >= (2 << 14))
970 {
971 WLog_ERR(TAG, "Maximum FastPath PDU length is 32767");
972 goto fail;
973 }
974
975 eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
976 eventHeader |= (iNumEvents << 2); /* numberEvents */
977
978 if (rdp->sec_flags & SEC_ENCRYPT)
979 eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
980
981 if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
982 eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
983
984 Stream_SetPosition(s, 0);
985 Stream_Write_UINT8(s, eventHeader);
986 /* Write length later, RDP encryption might add a padding */
987 Stream_Seek(s, 2);
988
989 if (rdp->sec_flags & SEC_ENCRYPT)
990 {
991 int sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
992 BYTE* fpInputEvents = Stream_Pointer(s) + sec_bytes;
993 UINT16 fpInputEvents_length = length - 3 - sec_bytes;
994
995 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
996 {
997 BYTE pad;
998
999 if ((pad = 8 - (fpInputEvents_length % 8)) == 8)
1000 pad = 0;
1001
1002 Stream_Write_UINT16(s, 0x10); /* length */
1003 Stream_Write_UINT8(s, 0x1); /* TSFIPS_VERSION 1*/
1004 Stream_Write_UINT8(s, pad); /* padding */
1005
1006 if (!security_hmac_signature(fpInputEvents, fpInputEvents_length, Stream_Pointer(s),
1007 rdp))
1008 goto fail;
1009
1010 if (pad)
1011 memset(fpInputEvents + fpInputEvents_length, 0, pad);
1012
1013 if (!security_fips_encrypt(fpInputEvents, fpInputEvents_length + pad, rdp))
1014 goto fail;
1015
1016 length += pad;
1017 }
1018 else
1019 {
1020 BOOL status;
1021
1022 if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1023 status = security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length,
1024 TRUE, Stream_Pointer(s));
1025 else
1026 status = security_mac_signature(rdp, fpInputEvents, fpInputEvents_length,
1027 Stream_Pointer(s));
1028
1029 if (!status || !security_encrypt(fpInputEvents, fpInputEvents_length, rdp))
1030 goto fail;
1031 }
1032 }
1033
1034 rdp->sec_flags = 0;
1035 /*
1036 * We always encode length in two bytes, even though we could use
1037 * only one byte if length <= 0x7F. It is just easier that way,
1038 * because we can leave room for fixed-length header, store all
1039 * the data first and then store the header.
1040 */
1041 Stream_SetPosition(s, 1);
1042 Stream_Write_UINT16_BE(s, 0x8000 | length);
1043 Stream_SetPosition(s, length);
1044 Stream_SealLength(s);
1045
1046 if (transport_write(fastpath->rdp->transport, s) < 0)
1047 goto fail;
1048
1049 rc = TRUE;
1050 fail:
1051 Stream_Release(s);
1052 return rc;
1053 }
1054
fastpath_send_input_pdu(rdpFastPath * fastpath,wStream * s)1055 BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s)
1056 {
1057 return fastpath_send_multiple_input_pdu(fastpath, s, 1);
1058 }
1059
fastpath_update_pdu_init(rdpFastPath * fastpath)1060 wStream* fastpath_update_pdu_init(rdpFastPath* fastpath)
1061 {
1062 return transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
1063 }
1064
fastpath_update_pdu_init_new(rdpFastPath * fastpath)1065 wStream* fastpath_update_pdu_init_new(rdpFastPath* fastpath)
1066 {
1067 wStream* s;
1068 s = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1069 return s;
1070 }
1071
fastpath_send_update_pdu(rdpFastPath * fastpath,BYTE updateCode,wStream * s,BOOL skipCompression)1072 BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s,
1073 BOOL skipCompression)
1074 {
1075 int fragment;
1076 UINT16 maxLength;
1077 UINT32 totalLength;
1078 BOOL status = TRUE;
1079 wStream* fs = NULL;
1080 rdpSettings* settings;
1081 rdpRdp* rdp;
1082 UINT32 fpHeaderSize = 6;
1083 UINT32 fpUpdatePduHeaderSize;
1084 UINT32 fpUpdateHeaderSize;
1085 UINT32 CompressionMaxSize;
1086 FASTPATH_UPDATE_PDU_HEADER fpUpdatePduHeader = { 0 };
1087 FASTPATH_UPDATE_HEADER fpUpdateHeader = { 0 };
1088
1089 if (!fastpath || !fastpath->rdp || !fastpath->fs || !s)
1090 return FALSE;
1091
1092 rdp = fastpath->rdp;
1093 fs = fastpath->fs;
1094 settings = rdp->settings;
1095
1096 if (!settings)
1097 return FALSE;
1098
1099 maxLength = FASTPATH_MAX_PACKET_SIZE - 20;
1100
1101 if (settings->CompressionEnabled && !skipCompression)
1102 {
1103 CompressionMaxSize = bulk_compression_max_size(rdp->bulk);
1104 maxLength = (maxLength < CompressionMaxSize) ? maxLength : CompressionMaxSize;
1105 maxLength -= 20;
1106 }
1107
1108 totalLength = Stream_GetPosition(s);
1109 Stream_SetPosition(s, 0);
1110
1111 /* check if fast path output is possible */
1112 if (!settings->FastPathOutput)
1113 {
1114 WLog_ERR(TAG, "client does not support fast path output");
1115 return FALSE;
1116 }
1117
1118 /* check if the client's fast path pdu buffer is large enough */
1119 if (totalLength > settings->MultifragMaxRequestSize)
1120 {
1121 WLog_ERR(TAG,
1122 "fast path update size (%" PRIu32
1123 ") exceeds the client's maximum request size (%" PRIu32 ")",
1124 totalLength, settings->MultifragMaxRequestSize);
1125 return FALSE;
1126 }
1127
1128 if (rdp->do_crypt)
1129 {
1130 rdp->sec_flags |= SEC_ENCRYPT;
1131
1132 if (rdp->do_secure_checksum)
1133 rdp->sec_flags |= SEC_SECURE_CHECKSUM;
1134 }
1135
1136 for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
1137 {
1138 BYTE* pSrcData;
1139 UINT32 SrcSize;
1140 UINT32 DstSize = 0;
1141 BYTE* pDstData = NULL;
1142 UINT32 compressionFlags = 0;
1143 BYTE pad = 0;
1144 BYTE* pSignature = NULL;
1145 fpUpdatePduHeader.action = 0;
1146 fpUpdatePduHeader.secFlags = 0;
1147 fpUpdateHeader.compression = 0;
1148 fpUpdateHeader.compressionFlags = 0;
1149 fpUpdateHeader.updateCode = updateCode;
1150 fpUpdateHeader.size = (totalLength > maxLength) ? maxLength : totalLength;
1151 pSrcData = pDstData = Stream_Pointer(s);
1152 SrcSize = DstSize = fpUpdateHeader.size;
1153
1154 if (rdp->sec_flags & SEC_ENCRYPT)
1155 fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_ENCRYPTED;
1156
1157 if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1158 fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_SECURE_CHECKSUM;
1159
1160 if (settings->CompressionEnabled && !skipCompression)
1161 {
1162 if (bulk_compress(rdp->bulk, pSrcData, SrcSize, &pDstData, &DstSize,
1163 &compressionFlags) >= 0)
1164 {
1165 if (compressionFlags)
1166 {
1167 fpUpdateHeader.compressionFlags = compressionFlags;
1168 fpUpdateHeader.compression = FASTPATH_OUTPUT_COMPRESSION_USED;
1169 }
1170 }
1171 }
1172
1173 if (!fpUpdateHeader.compression)
1174 {
1175 pDstData = Stream_Pointer(s);
1176 DstSize = fpUpdateHeader.size;
1177 }
1178
1179 fpUpdateHeader.size = DstSize;
1180 totalLength -= SrcSize;
1181
1182 if (totalLength == 0)
1183 fpUpdateHeader.fragmentation =
1184 (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
1185 else
1186 fpUpdateHeader.fragmentation =
1187 (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
1188
1189 fpUpdateHeaderSize = fastpath_get_update_header_size(&fpUpdateHeader);
1190 fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader, rdp);
1191 fpHeaderSize = fpUpdateHeaderSize + fpUpdatePduHeaderSize;
1192
1193 if (rdp->sec_flags & SEC_ENCRYPT)
1194 {
1195 pSignature = Stream_Buffer(fs) + 3;
1196
1197 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1198 {
1199 pSignature += 4;
1200
1201 if ((pad = 8 - ((DstSize + fpUpdateHeaderSize) % 8)) == 8)
1202 pad = 0;
1203
1204 fpUpdatePduHeader.fipsInformation[0] = 0x10;
1205 fpUpdatePduHeader.fipsInformation[1] = 0x00;
1206 fpUpdatePduHeader.fipsInformation[2] = 0x01;
1207 fpUpdatePduHeader.fipsInformation[3] = pad;
1208 }
1209 }
1210
1211 fpUpdatePduHeader.length = fpUpdateHeader.size + fpHeaderSize + pad;
1212 Stream_SetPosition(fs, 0);
1213 fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader, rdp);
1214 fastpath_write_update_header(fs, &fpUpdateHeader);
1215 Stream_Write(fs, pDstData, DstSize);
1216
1217 if (pad)
1218 Stream_Zero(fs, pad);
1219
1220 if (rdp->sec_flags & SEC_ENCRYPT)
1221 {
1222 UINT32 dataSize = fpUpdateHeaderSize + DstSize + pad;
1223 BYTE* data = Stream_Pointer(fs) - dataSize;
1224
1225 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1226 {
1227 if (!security_hmac_signature(data, dataSize - pad, pSignature, rdp))
1228 return FALSE;
1229
1230 security_fips_encrypt(data, dataSize, rdp);
1231 }
1232 else
1233 {
1234 if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1235 status = security_salted_mac_signature(rdp, data, dataSize, TRUE, pSignature);
1236 else
1237 status = security_mac_signature(rdp, data, dataSize, pSignature);
1238
1239 if (!status || !security_encrypt(data, dataSize, rdp))
1240 return FALSE;
1241 }
1242 }
1243
1244 Stream_SealLength(fs);
1245
1246 if (transport_write(rdp->transport, fs) < 0)
1247 {
1248 status = FALSE;
1249 break;
1250 }
1251
1252 Stream_Seek(s, SrcSize);
1253 }
1254
1255 rdp->sec_flags = 0;
1256 return status;
1257 }
1258
fastpath_new(rdpRdp * rdp)1259 rdpFastPath* fastpath_new(rdpRdp* rdp)
1260 {
1261 rdpFastPath* fastpath;
1262 fastpath = (rdpFastPath*)calloc(1, sizeof(rdpFastPath));
1263
1264 if (!fastpath)
1265 return NULL;
1266
1267 fastpath->rdp = rdp;
1268 fastpath->fragmentation = -1;
1269 fastpath->fs = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1270 fastpath->updateData = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1271
1272 if (!fastpath->fs || !fastpath->updateData)
1273 goto out_free;
1274
1275 return fastpath;
1276 out_free:
1277 fastpath_free(fastpath);
1278 return NULL;
1279 }
1280
fastpath_free(rdpFastPath * fastpath)1281 void fastpath_free(rdpFastPath* fastpath)
1282 {
1283 if (fastpath)
1284 {
1285 Stream_Free(fastpath->updateData, TRUE);
1286 Stream_Free(fastpath->fs, TRUE);
1287 free(fastpath);
1288 }
1289 }
1290