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