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