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  WINPR_ASSERT(fastpath);
683  WINPR_ASSERT(fastpath->rdp);
684  WINPR_ASSERT(fastpath->rdp->input);
685  WINPR_ASSERT(s);
686 
687  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
688  return FALSE;
689 
690  rdpInput* input = fastpath->rdp->input;
691 
692  const UINT8 code = Stream_Get_UINT8(s); /* keyCode (1 byte) */
693 
694  UINT16 flags = 0;
695  if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
696  flags |= KBD_FLAGS_RELEASE;
697 
698  if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED))
699  flags |= KBD_FLAGS_EXTENDED;
700 
701  if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_PREFIX_E1))
702  flags |= KBD_FLAGS_EXTENDED1;
703 
704  return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
705 }
706 
707 static BOOL fastpath_recv_input_event_mouse(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
708 {
709  rdpInput* input = NULL;
710  UINT16 pointerFlags = 0;
711  UINT16 xPos = 0;
712  UINT16 yPos = 0;
713  WINPR_ASSERT(fastpath);
714  WINPR_ASSERT(fastpath->rdp);
715  WINPR_ASSERT(fastpath->rdp->input);
716  WINPR_ASSERT(s);
717 
718  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
719  return FALSE;
720 
721  input = fastpath->rdp->input;
722 
723  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
724  Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
725  Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
726  return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
727 }
728 
729 static BOOL fastpath_recv_input_event_relmouse(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
730 {
731  rdpInput* input = NULL;
732  UINT16 pointerFlags = 0;
733  INT16 xDelta = 0;
734  INT16 yDelta = 0;
735  WINPR_ASSERT(fastpath);
736  WINPR_ASSERT(fastpath->rdp);
737  WINPR_ASSERT(fastpath->rdp->context);
738  WINPR_ASSERT(fastpath->rdp->input);
739  WINPR_ASSERT(s);
740 
741  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
742  return FALSE;
743 
744  input = fastpath->rdp->input;
745 
746  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
747  Stream_Read_INT16(s, xDelta); /* xDelta (2 bytes) */
748  Stream_Read_INT16(s, yDelta); /* yDelta (2 bytes) */
749 
750  if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent))
751  {
752  WLog_ERR(TAG,
753  "Received relative mouse event(flags=0x%04" PRIx16 ", xPos=%" PRId16
754  ", yPos=%" PRId16 "), but we did not announce support for that",
755  pointerFlags, xDelta, yDelta);
756  return FALSE;
757  }
758 
759  return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta);
760 }
761 
762 static BOOL fastpath_recv_input_event_qoe(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
763 {
764  WINPR_ASSERT(fastpath);
765  WINPR_ASSERT(fastpath->rdp);
766  WINPR_ASSERT(fastpath->rdp->context);
767  WINPR_ASSERT(fastpath->rdp->input);
768  WINPR_ASSERT(s);
769 
770  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
771  return FALSE;
772 
773  rdpInput* input = fastpath->rdp->input;
774 
775  UINT32 timestampMS = 0;
776  Stream_Read_UINT32(s, timestampMS); /* timestamp (4 bytes) */
777 
778  if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasQoeEvent))
779  {
780  WLog_ERR(TAG,
781  "Received qoe event(timestamp=%" PRIu32
782  "ms), but we did not announce support for that",
783  timestampMS);
784  return FALSE;
785  }
786 
787  return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS);
788 }
789 
790 static BOOL fastpath_recv_input_event_mousex(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
791 {
792  rdpInput* input = NULL;
793  UINT16 pointerFlags = 0;
794  UINT16 xPos = 0;
795  UINT16 yPos = 0;
796 
797  WINPR_ASSERT(fastpath);
798  WINPR_ASSERT(fastpath->rdp);
799  WINPR_ASSERT(fastpath->rdp->context);
800  WINPR_ASSERT(fastpath->rdp->input);
801  WINPR_ASSERT(s);
802 
803  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
804  return FALSE;
805 
806  input = fastpath->rdp->input;
807 
808  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
809  Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
810  Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
811 
812  if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent))
813  {
814  WLog_ERR(TAG,
815  "Received extended mouse event(flags=0x%04" PRIx16 ", xPos=%" PRIu16
816  ", yPos=%" PRIu16 "), but we did not announce support for that",
817  pointerFlags, xPos, yPos);
818  return FALSE;
819  }
820 
821  return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
822 }
823 
824 static BOOL fastpath_recv_input_event_sync(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
825 {
826  rdpInput* input = NULL;
827 
828  WINPR_ASSERT(fastpath);
829  WINPR_ASSERT(fastpath->rdp);
830  WINPR_ASSERT(fastpath->rdp->input);
831  WINPR_ASSERT(s);
832 
833  input = fastpath->rdp->input;
834  return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, eventFlags);
835 }
836 
837 static BOOL fastpath_recv_input_event_unicode(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
838 {
839  UINT16 unicodeCode = 0;
840  UINT16 flags = 0;
841 
842  WINPR_ASSERT(fastpath);
843  WINPR_ASSERT(s);
844 
845  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
846  return FALSE;
847 
848  Stream_Read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */
849  flags = 0;
850 
851  if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
852  flags |= KBD_FLAGS_RELEASE;
853 
854  WINPR_ASSERT(fastpath->rdp);
855  WINPR_ASSERT(fastpath->rdp);
856  WINPR_ASSERT(fastpath->rdp->input);
857  return IFCALLRESULT(FALSE, fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input,
858  flags, unicodeCode);
859 }
860 
861 static BOOL fastpath_recv_input_event(rdpFastPath* fastpath, wStream* s)
862 {
863  BYTE eventFlags = 0;
864  BYTE eventCode = 0;
865 
866  WINPR_ASSERT(fastpath);
867  WINPR_ASSERT(s);
868 
869  if (!fastpath_read_input_event_header(s, &eventFlags, &eventCode))
870  return FALSE;
871 
872  switch (eventCode)
873  {
874  case FASTPATH_INPUT_EVENT_SCANCODE:
875  if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags))
876  return FALSE;
877 
878  break;
879 
880  case FASTPATH_INPUT_EVENT_MOUSE:
881  if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags))
882  return FALSE;
883 
884  break;
885 
886  case FASTPATH_INPUT_EVENT_MOUSEX:
887  if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags))
888  return FALSE;
889 
890  break;
891 
892  case FASTPATH_INPUT_EVENT_SYNC:
893  if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags))
894  return FALSE;
895 
896  break;
897 
898  case FASTPATH_INPUT_EVENT_UNICODE:
899  if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags))
900  return FALSE;
901 
902  break;
903 
904  case TS_FP_RELPOINTER_EVENT:
905  if (!fastpath_recv_input_event_relmouse(fastpath, s, eventFlags))
906  return FALSE;
907 
908  break;
909 
910  case TS_FP_QOETIMESTAMP_EVENT:
911  if (!fastpath_recv_input_event_qoe(fastpath, s, eventFlags))
912  return FALSE;
913  break;
914 
915  default:
916  WLog_ERR(TAG, "Unknown eventCode %" PRIu8 "", eventCode);
917  break;
918  }
919 
920  return TRUE;
921 }
922 
923 state_run_t fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s)
924 {
925  WINPR_ASSERT(fastpath);
926  WINPR_ASSERT(s);
927 
928  if (fastpath->numberEvents == 0)
929  {
934  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
935  return STATE_RUN_FAILED;
936 
937  Stream_Read_UINT8(s, fastpath->numberEvents); /* eventHeader (1 byte) */
938  }
939 
940  for (BYTE i = 0; i < fastpath->numberEvents; i++)
941  {
942  if (!fastpath_recv_input_event(fastpath, s))
943  return STATE_RUN_FAILED;
944  }
945 
946  return STATE_RUN_SUCCESS;
947 }
948 
949 static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp)
950 {
951  UINT32 sec_bytes = 0;
952  sec_bytes = 0;
953 
954  if (!rdp)
955  return 0;
956 
957  if (rdp->do_crypt)
958  {
959  sec_bytes = 8;
960 
961  if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
962  sec_bytes += 4;
963  }
964 
965  return sec_bytes;
966 }
967 
968 wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath)
969 {
970  rdpRdp* rdp = NULL;
971  wStream* s = NULL;
972 
973  if (!fastpath || !fastpath->rdp)
974  return NULL;
975 
976  rdp = fastpath->rdp;
977  s = transport_send_stream_init(rdp->transport, 256);
978 
979  if (!s)
980  return NULL;
981 
982  Stream_Seek(s, 3); /* fpInputHeader, length1 and length2 */
983 
984  if (rdp->do_crypt)
985  {
986  rdp->sec_flags |= SEC_ENCRYPT;
987 
988  if (rdp->do_secure_checksum)
989  rdp->sec_flags |= SEC_SECURE_CHECKSUM;
990  }
991 
992  Stream_Seek(s, fastpath_get_sec_bytes(rdp));
993  return s;
994 }
995 
996 wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode)
997 {
998  wStream* s = NULL;
999  s = fastpath_input_pdu_init_header(fastpath);
1000 
1001  if (!s)
1002  return NULL;
1003 
1004  WINPR_ASSERT(eventCode < 8);
1005  WINPR_ASSERT(eventFlags < 0x20);
1006  Stream_Write_UINT8(s, (UINT8)(eventFlags | (eventCode << 5))); /* eventHeader (1 byte) */
1007  return s;
1008 }
1009 
1010 BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, size_t iNumEvents)
1011 {
1012  BOOL rc = FALSE;
1013  BYTE eventHeader = 0;
1014 
1015  WINPR_ASSERT(iNumEvents > 0);
1016  if (!s)
1017  return FALSE;
1018 
1019  if (!fastpath)
1020  goto fail;
1021 
1022  rdpRdp* rdp = fastpath->rdp;
1023  WINPR_ASSERT(rdp);
1024 
1025  CONNECTION_STATE state = rdp_get_state(rdp);
1026  if (!rdp_is_active_state(rdp))
1027  {
1028  WLog_WARN(TAG, "called before activation [%s]", rdp_state_string(state));
1029  goto fail;
1030  }
1031 
1032  /*
1033  * A maximum of 15 events are allowed per request
1034  * if the optional numEvents field isn't used
1035  * see MS-RDPBCGR 2.2.8.1.2 for details
1036  */
1037  if (iNumEvents > 15)
1038  goto fail;
1039 
1040  size_t length = Stream_GetPosition(s);
1041 
1042  if (length >= (2 << 14))
1043  {
1044  WLog_ERR(TAG, "Maximum FastPath PDU length is 32767");
1045  goto fail;
1046  }
1047 
1048  eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
1049  eventHeader |= (iNumEvents << 2); /* numberEvents */
1050 
1051  if (rdp->sec_flags & SEC_ENCRYPT)
1052  eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
1053 
1054  if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1055  eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
1056 
1057  Stream_SetPosition(s, 0);
1058  Stream_Write_UINT8(s, eventHeader);
1059  /* Write length later, RDP encryption might add a padding */
1060  Stream_Seek(s, 2);
1061 
1062  if (rdp->sec_flags & SEC_ENCRYPT)
1063  {
1064  BOOL status = FALSE;
1065  if (!security_lock(rdp))
1066  goto fail;
1067 
1068  const size_t sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
1069  if (sec_bytes + 3ULL > length)
1070  goto unlock;
1071 
1072  BYTE* fpInputEvents = Stream_PointerAs(s, BYTE) + sec_bytes;
1073  const UINT16 fpInputEvents_length = (UINT16)(length - 3 - sec_bytes);
1074 
1075  WINPR_ASSERT(rdp->settings);
1076  if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1077  {
1078  BYTE pad = 0;
1079 
1080  if ((pad = 8 - (fpInputEvents_length % 8)) == 8)
1081  pad = 0;
1082 
1083  Stream_Write_UINT16(s, 0x10); /* length */
1084  Stream_Write_UINT8(s, 0x1); /* TSFIPS_VERSION 1*/
1085  Stream_Write_UINT8(s, pad); /* padding */
1086 
1087  if (!Stream_CheckAndLogRequiredCapacity(TAG, s, 8))
1088  goto unlock;
1089 
1090  if (!security_hmac_signature(fpInputEvents, fpInputEvents_length, Stream_Pointer(s), 8,
1091  rdp))
1092  goto unlock;
1093 
1094  if (pad)
1095  memset(fpInputEvents + fpInputEvents_length, 0, pad);
1096 
1097  if (!security_fips_encrypt(fpInputEvents, fpInputEvents_length + pad, rdp))
1098  goto unlock;
1099 
1100  length += pad;
1101  }
1102  else
1103  {
1104  BOOL res = 0;
1105  if (!Stream_CheckAndLogRequiredCapacity(TAG, s, 8))
1106  goto unlock;
1107  if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1108  res = security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE,
1109  Stream_Pointer(s), 8);
1110  else
1111  res = security_mac_signature(rdp, fpInputEvents, fpInputEvents_length,
1112  Stream_Pointer(s), 8);
1113 
1114  if (!res || !security_encrypt(fpInputEvents, fpInputEvents_length, rdp))
1115  goto unlock;
1116  }
1117 
1118  status = TRUE;
1119  unlock:
1120  if (!security_unlock(rdp))
1121  goto fail;
1122  if (!status)
1123  goto fail;
1124  }
1125 
1126  rdp->sec_flags = 0;
1127  /*
1128  * We always encode length in two bytes, even though we could use
1129  * only one byte if length <= 0x7F. It is just easier that way,
1130  * because we can leave room for fixed-length header, store all
1131  * the data first and then store the header.
1132  */
1133  WINPR_ASSERT(length < UINT16_MAX);
1134  Stream_SetPosition(s, 1);
1135  Stream_Write_UINT16_BE(s, 0x8000 | (UINT16)length);
1136  Stream_SetPosition(s, length);
1137  Stream_SealLength(s);
1138 
1139  if (transport_write(rdp->transport, s) < 0)
1140  goto fail;
1141 
1142  rc = TRUE;
1143 fail:
1144  Stream_Release(s);
1145  return rc;
1146 }
1147 
1148 BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s)
1149 {
1150  return fastpath_send_multiple_input_pdu(fastpath, s, 1);
1151 }
1152 
1153 wStream* fastpath_update_pdu_init(rdpFastPath* fastpath)
1154 {
1155  return transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
1156 }
1157 
1158 wStream* fastpath_update_pdu_init_new(rdpFastPath* fastpath)
1159 {
1160  wStream* s = NULL;
1161  s = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1162  return s;
1163 }
1164 
1165 BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s,
1166  BOOL skipCompression)
1167 {
1168  BOOL status = TRUE;
1169  wStream* fs = NULL;
1170  rdpSettings* settings = NULL;
1171  rdpRdp* rdp = NULL;
1172  UINT32 fpHeaderSize = 6;
1173  UINT32 fpUpdatePduHeaderSize = 0;
1174  UINT32 fpUpdateHeaderSize = 0;
1175  FASTPATH_UPDATE_PDU_HEADER fpUpdatePduHeader = { 0 };
1176  FASTPATH_UPDATE_HEADER fpUpdateHeader = { 0 };
1177 
1178  if (!fastpath || !fastpath->rdp || !fastpath->fs || !s)
1179  return FALSE;
1180 
1181  rdp = fastpath->rdp;
1182  fs = fastpath->fs;
1183  settings = rdp->settings;
1184 
1185  if (!settings)
1186  return FALSE;
1187 
1188  UINT16 maxLength = FASTPATH_MAX_PACKET_SIZE - 20;
1189 
1190  if (settings->CompressionEnabled && !skipCompression)
1191  {
1192  const UINT16 CompressionMaxSize = bulk_compression_max_size(rdp->bulk);
1193  maxLength = (maxLength < CompressionMaxSize) ? maxLength : CompressionMaxSize;
1194  maxLength -= 20;
1195  }
1196 
1197  size_t totalLength = Stream_GetPosition(s);
1198  Stream_SetPosition(s, 0);
1199 
1200  /* check if fast path output is possible */
1201  if (!settings->FastPathOutput)
1202  {
1203  WLog_ERR(TAG, "client does not support fast path output");
1204  return FALSE;
1205  }
1206 
1207  /* check if the client's fast path pdu buffer is large enough */
1208  if (totalLength > settings->MultifragMaxRequestSize)
1209  {
1210  WLog_ERR(TAG,
1211  "fast path update size (%" PRIuz
1212  ") exceeds the client's maximum request size (%" PRIu32 ")",
1213  totalLength, settings->MultifragMaxRequestSize);
1214  return FALSE;
1215  }
1216 
1217  if (rdp->do_crypt)
1218  {
1219  rdp->sec_flags |= SEC_ENCRYPT;
1220 
1221  if (rdp->do_secure_checksum)
1222  rdp->sec_flags |= SEC_SECURE_CHECKSUM;
1223  }
1224 
1225  for (int fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
1226  {
1227  UINT32 DstSize = 0;
1228  const BYTE* pDstData = NULL;
1229  UINT32 compressionFlags = 0;
1230  BYTE pad = 0;
1231  BYTE* pSignature = NULL;
1232  fpUpdatePduHeader.action = 0;
1233  fpUpdatePduHeader.secFlags = 0;
1234  fpUpdateHeader.compression = 0;
1235  fpUpdateHeader.compressionFlags = 0;
1236  fpUpdateHeader.updateCode = updateCode;
1237  fpUpdateHeader.size = (UINT16)(totalLength > maxLength) ? maxLength : (UINT16)totalLength;
1238  const BYTE* pSrcData = Stream_Pointer(s);
1239  UINT32 SrcSize = DstSize = fpUpdateHeader.size;
1240 
1241  if (rdp->sec_flags & SEC_ENCRYPT)
1242  fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_ENCRYPTED;
1243 
1244  if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1245  fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_SECURE_CHECKSUM;
1246 
1247  if (settings->CompressionEnabled && !skipCompression)
1248  {
1249  if (bulk_compress(rdp->bulk, pSrcData, SrcSize, &pDstData, &DstSize,
1250  &compressionFlags) >= 0)
1251  {
1252  if (compressionFlags)
1253  {
1254  WINPR_ASSERT(compressionFlags <= UINT8_MAX);
1255  fpUpdateHeader.compressionFlags = (UINT8)compressionFlags;
1256  fpUpdateHeader.compression = FASTPATH_OUTPUT_COMPRESSION_USED;
1257  }
1258  }
1259  }
1260 
1261  if (!fpUpdateHeader.compression)
1262  {
1263  pDstData = Stream_Pointer(s);
1264  DstSize = fpUpdateHeader.size;
1265  }
1266 
1267  if (DstSize > UINT16_MAX)
1268  return FALSE;
1269  fpUpdateHeader.size = (UINT16)DstSize;
1270  totalLength -= SrcSize;
1271 
1272  if (totalLength == 0)
1273  fpUpdateHeader.fragmentation =
1274  (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
1275  else
1276  fpUpdateHeader.fragmentation =
1277  (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
1278 
1279  fpUpdateHeaderSize = fastpath_get_update_header_size(&fpUpdateHeader);
1280  fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader, rdp);
1281  fpHeaderSize = fpUpdateHeaderSize + fpUpdatePduHeaderSize;
1282 
1283  if (rdp->sec_flags & SEC_ENCRYPT)
1284  {
1285  pSignature = Stream_Buffer(fs) + 3;
1286 
1287  if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1288  {
1289  pSignature += 4;
1290 
1291  if ((pad = 8 - ((DstSize + fpUpdateHeaderSize) % 8)) == 8)
1292  pad = 0;
1293 
1294  fpUpdatePduHeader.fipsInformation[0] = 0x10;
1295  fpUpdatePduHeader.fipsInformation[1] = 0x00;
1296  fpUpdatePduHeader.fipsInformation[2] = 0x01;
1297  fpUpdatePduHeader.fipsInformation[3] = pad;
1298  }
1299  }
1300 
1301  const size_t len = fpUpdateHeader.size + fpHeaderSize + pad;
1302  if (len > UINT16_MAX)
1303  return FALSE;
1304 
1305  fpUpdatePduHeader.length = (UINT16)len;
1306  Stream_SetPosition(fs, 0);
1307  if (!fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader, rdp))
1308  return FALSE;
1309  if (!fastpath_write_update_header(fs, &fpUpdateHeader))
1310  return FALSE;
1311 
1312  if (!Stream_CheckAndLogRequiredCapacity(TAG, (fs), (size_t)DstSize + pad))
1313  return FALSE;
1314  Stream_Write(fs, pDstData, DstSize);
1315 
1316  if (pad)
1317  Stream_Zero(fs, pad);
1318 
1319  if (rdp->sec_flags & SEC_ENCRYPT)
1320  {
1321  BOOL res = FALSE;
1322  if (!security_lock(rdp))
1323  return FALSE;
1324  UINT32 dataSize = fpUpdateHeaderSize + DstSize + pad;
1325  BYTE* data = Stream_PointerAs(fs, BYTE) - dataSize;
1326 
1327  if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1328  {
1329  // TODO: Ensure stream capacity
1330  if (!security_hmac_signature(data, dataSize - pad, pSignature, 8, rdp))
1331  goto unlock;
1332 
1333  if (!security_fips_encrypt(data, dataSize, rdp))
1334  goto unlock;
1335  }
1336  else
1337  {
1338  // TODO: Ensure stream capacity
1339  if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
1340  status =
1341  security_salted_mac_signature(rdp, data, dataSize, TRUE, pSignature, 8);
1342  else
1343  status = security_mac_signature(rdp, data, dataSize, pSignature, 8);
1344 
1345  if (!status || !security_encrypt(data, dataSize, rdp))
1346  goto unlock;
1347  }
1348  res = TRUE;
1349 
1350  unlock:
1351  if (!security_unlock(rdp))
1352  return FALSE;
1353  if (!res)
1354  return FALSE;
1355  }
1356 
1357  Stream_SealLength(fs);
1358 
1359  if (transport_write(rdp->transport, fs) < 0)
1360  {
1361  status = FALSE;
1362  break;
1363  }
1364 
1365  Stream_Seek(s, SrcSize);
1366  }
1367 
1368  rdp->sec_flags = 0;
1369  return status;
1370 }
1371 
1372 rdpFastPath* fastpath_new(rdpRdp* rdp)
1373 {
1374  rdpFastPath* fastpath = NULL;
1375 
1376  WINPR_ASSERT(rdp);
1377 
1378  fastpath = (rdpFastPath*)calloc(1, sizeof(rdpFastPath));
1379 
1380  if (!fastpath)
1381  return NULL;
1382 
1383  fastpath->rdp = rdp;
1384  fastpath->fragmentation = -1;
1385  fastpath->fs = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1386  fastpath->updateData = Stream_New(NULL, FASTPATH_MAX_PACKET_SIZE);
1387 
1388  if (!fastpath->fs || !fastpath->updateData)
1389  goto out_free;
1390 
1391  return fastpath;
1392 out_free:
1393  fastpath_free(fastpath);
1394  return NULL;
1395 }
1396 
1397 void fastpath_free(rdpFastPath* fastpath)
1398 {
1399  if (fastpath)
1400  {
1401  Stream_Free(fastpath->updateData, TRUE);
1402  Stream_Free(fastpath->fs, TRUE);
1403  free(fastpath);
1404  }
1405 }
1406 
1407 BYTE fastpath_get_encryption_flags(rdpFastPath* fastpath)
1408 {
1409  WINPR_ASSERT(fastpath);
1410  return fastpath->encryptionFlags;
1411 }
1412 
1413 BOOL fastpath_decrypt(rdpFastPath* fastpath, wStream* s, UINT16* length)
1414 {
1415  WINPR_ASSERT(fastpath);
1416  if (fastpath_get_encryption_flags(fastpath) & FASTPATH_OUTPUT_ENCRYPTED)
1417  {
1418  const UINT16 flags =
1419  (fastpath_get_encryption_flags(fastpath) & FASTPATH_OUTPUT_SECURE_CHECKSUM)
1420  ? SEC_SECURE_CHECKSUM
1421  : 0;
1422 
1423  if (!rdp_decrypt(fastpath->rdp, s, length, flags))
1424  return FALSE;
1425  }
1426 
1427  return TRUE;
1428 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.