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