FreeRDP
Loading...
Searching...
No Matches
gcc.c
1
24#include <freerdp/config.h>
25
26#include "settings.h"
27
28#include <winpr/crt.h>
29#include <winpr/crypto.h>
30#include <winpr/assert.h>
31#include <winpr/cast.h>
32
33#include <freerdp/log.h>
34#include <freerdp/utils/string.h>
35#include <freerdp/crypto/certificate.h>
36
37#include "utils.h"
38#include "gcc.h"
39#include "nego.h"
40
41#include "../crypto/certificate.h"
42
43typedef enum
44{
45 HIGH_COLOR_4BPP = 0x04,
46 HIGH_COLOR_8BPP = 0x08,
47 HIGH_COLOR_15BPP = 0x0F,
48 HIGH_COLOR_16BPP = 0x10,
49 HIGH_COLOR_24BPP = 0x18,
50} HIGH_COLOR_DEPTH;
51
52static const char* HighColorToString(HIGH_COLOR_DEPTH color)
53{
54 switch (color)
55 {
56 case HIGH_COLOR_4BPP:
57 return "HIGH_COLOR_4BPP";
58 case HIGH_COLOR_8BPP:
59 return "HIGH_COLOR_8BPP";
60 case HIGH_COLOR_15BPP:
61 return "HIGH_COLOR_15BPP";
62 case HIGH_COLOR_16BPP:
63 return "HIGH_COLOR_16BPP";
64 case HIGH_COLOR_24BPP:
65 return "HIGH_COLOR_24BPP";
66 default:
67 return "HIGH_COLOR_UNKNOWN";
68 }
69}
70
71static HIGH_COLOR_DEPTH ColorDepthToHighColor(UINT32 bpp)
72{
73 switch (bpp)
74 {
75 case 4:
76 return HIGH_COLOR_4BPP;
77 case 8:
78 return HIGH_COLOR_8BPP;
79 case 15:
80 return HIGH_COLOR_15BPP;
81 case 16:
82 return HIGH_COLOR_16BPP;
83 default:
84 return HIGH_COLOR_24BPP;
85 }
86}
87
88static char* gcc_block_type_string(UINT16 type, char* buffer, size_t size);
89static BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs);
90static BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs);
91static BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length);
92static BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length);
93static BOOL gcc_read_user_data_header(wLog* log, wStream* s, UINT16* type, UINT16* length);
94static BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length);
95
96static BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs);
97static BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs);
98static BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs);
99static BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs);
100static BOOL gcc_write_client_security_data(wStream* s, const rdpMcs* mcs);
101static BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs);
102static BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs);
103static BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs);
104static BOOL gcc_write_client_network_data(wStream* s, const rdpMcs* mcs);
105static BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs);
106static BOOL gcc_write_server_network_data(wStream* s, const rdpMcs* mcs);
107static BOOL gcc_write_client_cluster_data(wStream* s, const rdpMcs* mcs);
108static BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs);
109static BOOL gcc_write_client_monitor_data(wStream* s, const rdpMcs* mcs);
110static BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs);
111static BOOL gcc_write_client_monitor_extended_data(wStream* s, const rdpMcs* mcs);
112static BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs);
113static BOOL gcc_write_client_message_channel_data(wStream* s, const rdpMcs* mcs);
114static BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs);
115static BOOL gcc_write_server_message_channel_data(wStream* s, const rdpMcs* mcs);
116static BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs);
117static BOOL gcc_write_client_multitransport_channel_data(wStream* s, const rdpMcs* mcs);
118static BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs);
119static BOOL gcc_write_server_multitransport_channel_data(wStream* s, const rdpMcs* mcs);
120
121static rdpSettings* mcs_get_settings(rdpMcs* mcs)
122{
123 WINPR_ASSERT(mcs);
124 WINPR_ASSERT(mcs->context);
125
126 return mcs->context->settings;
127}
128
129static const rdpSettings* mcs_get_const_settings(const rdpMcs* mcs)
130{
131 WINPR_ASSERT(mcs);
132 WINPR_ASSERT(mcs->context);
133
134 return mcs->context->settings;
135}
136
137static char* rdp_early_server_caps_string(UINT32 flags, char* buffer, size_t size)
138{
139 char msg[32] = WINPR_C_ARRAY_INIT;
140 const UINT32 mask = RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
141 RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
142 const UINT32 unknown = flags & (~mask);
143
144 if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1)
145 winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1", buffer, size, "|");
146 if (flags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED)
147 winpr_str_append("RNS_UD_SC_DYNAMIC_DST_SUPPORTED", buffer, size, "|");
148 if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2)
149 winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2", buffer, size, "|");
150 if (flags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED)
151 winpr_str_append("RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED", buffer, size, "|");
152
153 if (unknown != 0)
154 {
155 (void)_snprintf(msg, sizeof(msg), "RNS_UD_SC_UNKNOWN[0x%08" PRIx32 "]", unknown);
156 winpr_str_append(msg, buffer, size, "|");
157 }
158 (void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
159 winpr_str_append(msg, buffer, size, "|");
160 return buffer;
161}
162
163static const char* rdp_early_client_caps_string(UINT32 flags, char* buffer, size_t size)
164{
165 char msg[32] = WINPR_C_ARRAY_INIT;
166 const UINT32 mask = RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
167 RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
168 RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
169 RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU |
170 RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
171 RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
172 RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
173 const UINT32 unknown = flags & (~mask);
174
175 if (flags & RNS_UD_CS_SUPPORT_ERRINFO_PDU)
176 winpr_str_append("RNS_UD_CS_SUPPORT_ERRINFO_PDU", buffer, size, "|");
177 if (flags & RNS_UD_CS_WANT_32BPP_SESSION)
178 winpr_str_append("RNS_UD_CS_WANT_32BPP_SESSION", buffer, size, "|");
179 if (flags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU)
180 winpr_str_append("RNS_UD_CS_SUPPORT_STATUSINFO_PDU", buffer, size, "|");
181 if (flags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS)
182 winpr_str_append("RNS_UD_CS_STRONG_ASYMMETRIC_KEYS", buffer, size, "|");
183 if (flags & RNS_UD_CS_RELATIVE_MOUSE_INPUT)
184 winpr_str_append("RNS_UD_CS_RELATIVE_MOUSE_INPUT", buffer, size, "|");
185 if (flags & RNS_UD_CS_VALID_CONNECTION_TYPE)
186 winpr_str_append("RNS_UD_CS_VALID_CONNECTION_TYPE", buffer, size, "|");
187 if (flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU)
188 winpr_str_append("RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU", buffer, size, "|");
189 if (flags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT)
190 winpr_str_append("RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT", buffer, size, "|");
191 if (flags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)
192 winpr_str_append("RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL", buffer, size, "|");
193 if (flags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE)
194 winpr_str_append("RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE", buffer, size, "|");
195 if (flags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU)
196 winpr_str_append("RNS_UD_CS_SUPPORT_HEARTBEAT_PDU", buffer, size, "|");
197 if (flags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN)
198 winpr_str_append("RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN", buffer, size, "|");
199
200 if (unknown != 0)
201 {
202 (void)_snprintf(msg, sizeof(msg), "RNS_UD_CS_UNKNOWN[0x%08" PRIx32 "]", unknown);
203 winpr_str_append(msg, buffer, size, "|");
204 }
205 (void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
206 winpr_str_append(msg, buffer, size, "|");
207 return buffer;
208}
209
210static DWORD rdp_version_common(wLog* log, DWORD serverVersion, DWORD clientVersion)
211{
212 DWORD version = MIN(serverVersion, clientVersion);
213
214 switch (version)
215 {
216 case RDP_VERSION_4:
217 case RDP_VERSION_5_PLUS:
218 case RDP_VERSION_10_0:
219 case RDP_VERSION_10_1:
220 case RDP_VERSION_10_2:
221 case RDP_VERSION_10_3:
222 case RDP_VERSION_10_4:
223 case RDP_VERSION_10_5:
224 case RDP_VERSION_10_6:
225 case RDP_VERSION_10_7:
226 case RDP_VERSION_10_8:
227 case RDP_VERSION_10_9:
228 case RDP_VERSION_10_10:
229 case RDP_VERSION_10_11:
230 case RDP_VERSION_10_12:
231 return version;
232
233 default:
234 WLog_Print(log, WLOG_ERROR,
235 "Invalid client [%" PRIu32 "] and server [%" PRIu32 "] versions",
236 serverVersion, clientVersion);
237 return version;
238 }
239}
240
335/*
336 * OID = 0.0.20.124.0.1
337 * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
338 * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
339 */
340static const BYTE t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
341
342static const BYTE h221_cs_key[4] = { 'D', 'u', 'c', 'a' };
343static const BYTE h221_sc_key[4] = { 'M', 'c', 'D', 'n' };
344
355BOOL gcc_read_conference_create_request(wStream* s, rdpMcs* mcs)
356{
357 UINT16 length = 0;
358 BYTE choice = 0;
359 BYTE number = 0;
360 BYTE selection = 0;
361
362 WINPR_ASSERT(s);
363 WINPR_ASSERT(mcs);
364 /* ConnectData */
365 if (!per_read_choice(s, &choice))
366 return FALSE;
367
368 if (!per_read_object_identifier(s, t124_02_98_oid))
369 return FALSE;
370
371 /* ConnectData::connectPDU (OCTET_STRING) */
372 if (!per_read_length(s, &length))
373 return FALSE;
374
375 /* ConnectGCCPDU */
376 if (!per_read_choice(s, &choice))
377 return FALSE;
378
379 if (!per_read_selection(s, &selection))
380 return FALSE;
381
382 /* ConferenceCreateRequest::conferenceName */
383 if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
384 return FALSE;
385
386 if (!per_read_padding(s, 1)) /* padding */
387 return FALSE;
388
389 /* UserData (SET OF SEQUENCE) */
390 if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
391 return FALSE;
392
393 if (!per_read_choice(s, &choice) ||
394 choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
395 return FALSE;
396
397 /* h221NonStandard */
398 if (!per_read_octet_string(s, h221_cs_key, 4,
399 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
400 return FALSE;
401
402 /* userData::value (OCTET_STRING) */
403 if (!per_read_length(s, &length))
404 return FALSE;
405
406 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length))
407 return FALSE;
408
409 if (!gcc_read_client_data_blocks(s, mcs, length))
410 return FALSE;
411
412 return TRUE;
413}
414
425BOOL gcc_write_conference_create_request(wStream* s, wStream* userData)
426{
427 WINPR_ASSERT(s);
428 WINPR_ASSERT(userData);
429 /* ConnectData */
430 if (!per_write_choice(s, 0)) /* From Key select object (0) of type OBJECT_IDENTIFIER */
431 return FALSE;
432 if (!per_write_object_identifier(s, t124_02_98_oid)) /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
433 return FALSE;
434 /* ConnectData::connectPDU (OCTET_STRING) */
435 const size_t pos = Stream_GetPosition(userData);
436 WINPR_ASSERT(pos <= UINT16_MAX - 14);
437 if (!per_write_length(s, (UINT16)pos + 14)) /* connectPDU length */
438 return FALSE;
439 /* ConnectGCCPDU */
440 if (!per_write_choice(s, 0)) /* From ConnectGCCPDU select conferenceCreateRequest (0) of type
441 ConferenceCreateRequest */
442 return FALSE;
443 if (!per_write_selection(s, 0x08)) /* select optional userData from ConferenceCreateRequest */
444 return FALSE;
445 /* ConferenceCreateRequest::conferenceName */
446 if (!per_write_numeric_string(s, (BYTE*)"1", 1, 1)) /* ConferenceName::numeric */
447 return FALSE;
448 if (!per_write_padding(s, 1)) /* padding */
449 return FALSE;
450 /* UserData (SET OF SEQUENCE) */
451 if (!per_write_number_of_sets(s, 1)) /* one set of UserData */
452 return FALSE;
453 if (!per_write_choice(s, 0xC0)) /* UserData::value present + select h221NonStandard (1) */
454 return FALSE;
455 /* h221NonStandard */
456 if (!per_write_octet_string(s, h221_cs_key, 4,
457 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
458 return FALSE;
459 /* userData::value (OCTET_STRING) */
460 const size_t upos = Stream_GetPosition(userData);
461 WINPR_ASSERT(upos <= UINT16_MAX);
462 return per_write_octet_string(s, Stream_Buffer(userData), (UINT16)upos,
463 0); /* array of client data blocks */
464}
465
466BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs)
467{
468 UINT16 length = 0;
469 UINT32 tag = 0;
470 UINT16 nodeID = 0;
471 BYTE result = 0;
472 BYTE choice = 0;
473 BYTE number = 0;
474 WINPR_ASSERT(s);
475 WINPR_ASSERT(mcs);
476 /* ConnectData */
477 if (!per_read_choice(s, &choice) || !per_read_object_identifier(s, t124_02_98_oid))
478 return FALSE;
479
480 /* ConnectData::connectPDU (OCTET_STRING) */
481 if (!per_read_length(s, &length))
482 return FALSE;
483
484 /* ConnectGCCPDU */
485 if (!per_read_choice(s, &choice))
486 return FALSE;
487
488 /* ConferenceCreateResponse::nodeID (UserID) */
489 if (!per_read_integer16(s, &nodeID, 1001))
490 return FALSE;
491
492 /* ConferenceCreateResponse::tag (INTEGER) */
493 if (!per_read_integer(s, &tag))
494 return FALSE;
495
496 /* ConferenceCreateResponse::result (ENUMERATED) */
497 if (!per_read_enumerated(s, &result, MCS_Result_enum_length))
498 return FALSE;
499
500 /* number of UserData sets */
501 if (!per_read_number_of_sets(s, &number))
502 return FALSE;
503
504 /* UserData::value present + select h221NonStandard (1) */
505 if (!per_read_choice(s, &choice))
506 return FALSE;
507
508 /* h221NonStandard */
509 if (!per_read_octet_string(s, h221_sc_key, 4,
510 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
511 return FALSE;
512
513 /* userData (OCTET_STRING) */
514 if (!per_read_length(s, &length))
515 return FALSE;
516
517 if (!gcc_read_server_data_blocks(s, mcs, length))
518 {
519 WLog_Print(mcs->log, WLOG_ERROR,
520 "gcc_read_conference_create_response: gcc_read_server_data_blocks failed");
521 return FALSE;
522 }
523
524 return TRUE;
525}
526
527BOOL gcc_write_conference_create_response(wStream* s, wStream* userData)
528{
529 WINPR_ASSERT(s);
530 WINPR_ASSERT(userData);
531 /* ConnectData */
532 if (!per_write_choice(s, 0))
533 return FALSE;
534 if (!per_write_object_identifier(s, t124_02_98_oid))
535 return FALSE;
536 /* ConnectData::connectPDU (OCTET_STRING) */
537 /* This length MUST be ignored by the client according to [MS-RDPBCGR] */
538 if (!per_write_length(s, 0x2A))
539 return FALSE;
540 /* ConnectGCCPDU */
541 if (!per_write_choice(s, 0x14))
542 return FALSE;
543 /* ConferenceCreateResponse::nodeID (UserID) */
544 if (!per_write_integer16(s, 0x79F3, 1001))
545 return FALSE;
546 /* ConferenceCreateResponse::tag (INTEGER) */
547 if (!per_write_integer(s, 1))
548 return FALSE;
549 /* ConferenceCreateResponse::result (ENUMERATED) */
550 if (!per_write_enumerated(s, 0, MCS_Result_enum_length))
551 return FALSE;
552 /* number of UserData sets */
553 if (!per_write_number_of_sets(s, 1))
554 return FALSE;
555 /* UserData::value present + select h221NonStandard (1) */
556 if (!per_write_choice(s, 0xC0))
557 return FALSE;
558 /* h221NonStandard */
559 if (!per_write_octet_string(s, h221_sc_key, 4,
560 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
561 return FALSE;
562 /* userData (OCTET_STRING) */
563 const size_t pos = Stream_GetPosition(userData);
564 WINPR_ASSERT(pos <= UINT16_MAX);
565 return per_write_octet_string(s, Stream_Buffer(userData), (UINT16)pos,
566 0); /* array of server data blocks */
567}
568
569static BOOL gcc_read_client_unused1_data(wStream* s)
570{
571 return Stream_SafeSeek(s, 2);
572}
573
574BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length)
575{
576 WINPR_ASSERT(s);
577 WINPR_ASSERT(mcs);
578
579 BOOL gotMultitransport = FALSE;
580
581 while (length > 0)
582 {
583 wStream sbuffer = WINPR_C_ARRAY_INIT;
584 UINT16 type = 0;
585 UINT16 blockLength = 0;
586
587 if (!gcc_read_user_data_header(mcs->log, s, &type, &blockLength))
588 return FALSE;
589
590 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, (size_t)(blockLength - 4)))
591 return FALSE;
592
593 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLength - 4);
594 WINPR_ASSERT(sub);
595
596 Stream_Seek(s, blockLength - 4);
597
598 {
599 char buffer[64] = WINPR_C_ARRAY_INIT;
600 WLog_Print(mcs->log, WLOG_TRACE, "Processing block %s",
601 gcc_block_type_string(type, buffer, sizeof(buffer)));
602 }
603 switch (type)
604 {
605 case CS_CORE:
606 if (!gcc_read_client_core_data(sub, mcs))
607 return FALSE;
608
609 break;
610
611 case CS_SECURITY:
612 if (!gcc_read_client_security_data(sub, mcs))
613 return FALSE;
614
615 break;
616
617 case CS_NET:
618 if (!gcc_read_client_network_data(sub, mcs))
619 return FALSE;
620
621 break;
622
623 case CS_CLUSTER:
624 if (!gcc_read_client_cluster_data(sub, mcs))
625 return FALSE;
626
627 break;
628
629 case CS_MONITOR:
630 if (!gcc_read_client_monitor_data(sub, mcs))
631 return FALSE;
632
633 break;
634
635 case CS_MCS_MSGCHANNEL:
636 if (!gcc_read_client_message_channel_data(sub, mcs))
637 return FALSE;
638
639 break;
640
641 case CS_MONITOR_EX:
642 if (!gcc_read_client_monitor_extended_data(sub, mcs))
643 return FALSE;
644
645 break;
646
647 case CS_UNUSED1:
648 if (!gcc_read_client_unused1_data(sub))
649 return FALSE;
650
651 break;
652
653 case 0xC009:
654 case CS_MULTITRANSPORT:
655 gotMultitransport = TRUE;
656 if (!gcc_read_client_multitransport_channel_data(sub, mcs))
657 return FALSE;
658
659 break;
660
661 default:
662 WLog_Print(mcs->log, WLOG_ERROR, "Unknown GCC client data block: 0x%04" PRIX16 "",
663 type);
664 winpr_HexLogDump(mcs->log, WLOG_TRACE, Stream_Pointer(sub),
665 Stream_GetRemainingLength(sub));
666 break;
667 }
668
669 const size_t rem = Stream_GetRemainingLength(sub);
670 if (rem > 0)
671 {
672 char buffer[128] = WINPR_C_ARRAY_INIT;
673 const size_t total = Stream_Length(sub);
674 WLog_Print(mcs->log, WLOG_ERROR,
675 "Error parsing GCC client data block %s: Actual Offset: %" PRIuz
676 " Expected Offset: %" PRIuz,
677 gcc_block_type_string(type, buffer, sizeof(buffer)), total - rem, total);
678 }
679
680 if (blockLength > length)
681 {
682 char buffer[128] = WINPR_C_ARRAY_INIT;
683 WLog_Print(mcs->log, WLOG_ERROR,
684 "Error parsing GCC client data block %s: got blockLength 0x%04" PRIx16
685 ", but only 0x%04" PRIx16 "remaining",
686 gcc_block_type_string(type, buffer, sizeof(buffer)), blockLength, length);
687 length = 0;
688 }
689 else
690 length -= blockLength;
691 }
692
693 if (!gotMultitransport)
694 {
695 rdpSettings* settings = mcs_get_settings(mcs);
696 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, FALSE))
697 return FALSE;
698 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags, 0))
699 return FALSE;
700 }
701 return TRUE;
702}
703
704BOOL gcc_write_client_data_blocks(wStream* s, const rdpMcs* mcs)
705{
706 const rdpSettings* settings = mcs_get_const_settings(mcs);
707
708 WINPR_ASSERT(s);
709 WINPR_ASSERT(settings);
710
711 if (!gcc_write_client_core_data(s, mcs) || !gcc_write_client_cluster_data(s, mcs) ||
712 !gcc_write_client_security_data(s, mcs) || !gcc_write_client_network_data(s, mcs))
713 return FALSE;
714
715 /* extended client data supported */
716
717 if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
718 {
719 if (settings->UseMultimon && !settings->SpanMonitors)
720 {
721 if (!gcc_write_client_monitor_data(s, mcs) ||
722 !gcc_write_client_monitor_extended_data(s, mcs))
723 return FALSE;
724 }
725
726 if (!gcc_write_client_message_channel_data(s, mcs) ||
727 !gcc_write_client_multitransport_channel_data(s, mcs))
728 return FALSE;
729 }
730 else
731 {
732 if (settings->UseMultimon && !settings->SpanMonitors)
733 {
734 WLog_Print(mcs->log, WLOG_ERROR,
735 "WARNING: true multi monitor support was not advertised by server!");
736
737 if (settings->ForceMultimon)
738 {
739 WLog_Print(mcs->log, WLOG_ERROR,
740 "Sending multi monitor information anyway (may break connectivity!)");
741 if (!gcc_write_client_monitor_data(s, mcs) ||
742 !gcc_write_client_monitor_extended_data(s, mcs))
743 return FALSE;
744 }
745 else
746 {
747 WLog_Print(mcs->log, WLOG_ERROR,
748 "Use /multimon:force to force sending multi monitor information");
749 }
750 }
751 }
752 return TRUE;
753}
754
755char* gcc_block_type_string(UINT16 type, char* buffer, size_t size)
756{
757 switch (type)
758 {
759 case CS_CORE:
760 (void)_snprintf(buffer, size, "CS_CORE [0x%04" PRIx16 "]", type);
761 break;
762 case CS_SECURITY:
763 (void)_snprintf(buffer, size, "CS_SECURITY [0x%04" PRIx16 "]", type);
764 break;
765 case CS_NET:
766 (void)_snprintf(buffer, size, "CS_NET [0x%04" PRIx16 "]", type);
767 break;
768 case CS_CLUSTER:
769 (void)_snprintf(buffer, size, "CS_CLUSTER [0x%04" PRIx16 "]", type);
770 break;
771 case CS_MONITOR:
772 (void)_snprintf(buffer, size, "CS_MONITOR [0x%04" PRIx16 "]", type);
773 break;
774 case CS_MCS_MSGCHANNEL:
775 (void)_snprintf(buffer, size, "CS_MONITOR [0x%04" PRIx16 "]", type);
776 break;
777 case CS_MONITOR_EX:
778 (void)_snprintf(buffer, size, "CS_MONITOR_EX [0x%04" PRIx16 "]", type);
779 break;
780 case CS_UNUSED1:
781 (void)_snprintf(buffer, size, "CS_UNUSED1 [0x%04" PRIx16 "]", type);
782 break;
783 case CS_MULTITRANSPORT:
784 (void)_snprintf(buffer, size, "CS_MONITOR_EX [0x%04" PRIx16 "]", type);
785 break;
786 case SC_CORE:
787 (void)_snprintf(buffer, size, "SC_CORE [0x%04" PRIx16 "]", type);
788 break;
789 case SC_SECURITY:
790 (void)_snprintf(buffer, size, "SC_SECURITY [0x%04" PRIx16 "]", type);
791 break;
792 case SC_NET:
793 (void)_snprintf(buffer, size, "SC_NET [0x%04" PRIx16 "]", type);
794 break;
795 case SC_MCS_MSGCHANNEL:
796 (void)_snprintf(buffer, size, "SC_MCS_MSGCHANNEL [0x%04" PRIx16 "]", type);
797 break;
798 case SC_MULTITRANSPORT:
799 (void)_snprintf(buffer, size, "SC_MULTITRANSPORT [0x%04" PRIx16 "]", type);
800 break;
801 default:
802 (void)_snprintf(buffer, size, "UNKNOWN [0x%04" PRIx16 "]", type);
803 break;
804 }
805 return buffer;
806}
807
808BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length)
809{
810 UINT16 type = 0;
811 UINT16 offset = 0;
812 UINT16 blockLength = 0;
813 BYTE* holdp = nullptr;
814
815 WINPR_ASSERT(s);
816 WINPR_ASSERT(mcs);
817
818 while (offset < length)
819 {
820 char buffer[64] = WINPR_C_ARRAY_INIT;
821 size_t rest = 0;
822 wStream subbuffer;
823 wStream* sub = nullptr;
824
825 if (!gcc_read_user_data_header(mcs->log, s, &type, &blockLength))
826 {
827 WLog_Print(mcs->log, WLOG_ERROR,
828 "gcc_read_server_data_blocks: gcc_read_user_data_header failed");
829 return FALSE;
830 }
831 holdp = Stream_Pointer(s);
832 sub = Stream_StaticInit(&subbuffer, holdp, blockLength - 4);
833 if (!Stream_SafeSeek(s, blockLength - 4))
834 {
835 WLog_Print(mcs->log, WLOG_ERROR, "gcc_read_server_data_blocks: stream too short");
836 return FALSE;
837 }
838 offset += blockLength;
839
840 switch (type)
841 {
842 case SC_CORE:
843 if (!gcc_read_server_core_data(sub, mcs))
844 {
845 WLog_Print(mcs->log, WLOG_ERROR,
846 "gcc_read_server_data_blocks: gcc_read_server_core_data failed");
847 return FALSE;
848 }
849
850 break;
851
852 case SC_SECURITY:
853 if (!gcc_read_server_security_data(sub, mcs))
854 return FALSE;
855 break;
856
857 case SC_NET:
858 if (!gcc_read_server_network_data(sub, mcs))
859 {
860 WLog_Print(mcs->log, WLOG_ERROR,
861 "gcc_read_server_data_blocks: gcc_read_server_network_data failed");
862 return FALSE;
863 }
864
865 break;
866
867 case SC_MCS_MSGCHANNEL:
868 if (!gcc_read_server_message_channel_data(sub, mcs))
869 {
870 WLog_Print(
871 mcs->log, WLOG_ERROR,
872 "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed");
873 return FALSE;
874 }
875
876 break;
877
878 case SC_MULTITRANSPORT:
879 if (!gcc_read_server_multitransport_channel_data(sub, mcs))
880 {
881 WLog_Print(mcs->log, WLOG_ERROR,
882 "gcc_read_server_data_blocks: "
883 "gcc_read_server_multitransport_channel_data failed");
884 return FALSE;
885 }
886
887 break;
888
889 default:
890 WLog_Print(mcs->log, WLOG_ERROR, "gcc_read_server_data_blocks: ignoring type=%s",
891 gcc_block_type_string(type, buffer, sizeof(buffer)));
892 winpr_HexLogDump(mcs->log, WLOG_TRACE, Stream_Pointer(sub),
893 Stream_GetRemainingLength(sub));
894 break;
895 }
896
897 rest = Stream_GetRemainingLength(sub);
898 if (rest > 0)
899 {
900 WLog_Print(mcs->log, WLOG_WARN,
901 "gcc_read_server_data_blocks: ignoring %" PRIuz " bytes with type=%s", rest,
902 gcc_block_type_string(type, buffer, sizeof(buffer)));
903 }
904 }
905
906 return TRUE;
907}
908
909BOOL gcc_write_server_data_blocks(wStream* s, rdpMcs* mcs)
910{
911 WINPR_ASSERT(s);
912 WINPR_ASSERT(mcs);
913
914 if (!gcc_write_server_core_data(s, mcs) || /* serverCoreData */
915 !gcc_write_server_network_data(s, mcs) || /* serverNetworkData */
916 !gcc_write_server_security_data(s, mcs) || /* serverSecurityData */
917 !gcc_write_server_message_channel_data(s, mcs)) /* serverMessageChannelData */
918 return FALSE;
919
920 const rdpSettings* settings = mcs_get_const_settings(mcs);
921 WINPR_ASSERT(settings);
922
923 if (settings->SupportMultitransport && (settings->MultitransportFlags != 0))
924 /* serverMultitransportChannelData */
925 return gcc_write_server_multitransport_channel_data(s, mcs);
926
927 return TRUE;
928}
929
930BOOL gcc_read_user_data_header(wLog* log, wStream* s, UINT16* type, UINT16* length)
931{
932 WINPR_ASSERT(s);
933 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
934 return FALSE;
935
936 Stream_Read_UINT16(s, *type); /* type */
937 Stream_Read_UINT16(s, *length); /* length */
938
939 return !((*length < 4) ||
940 (!Stream_CheckAndLogRequiredLengthWLog(log, s, (size_t)(*length - 4))));
941}
942
954BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length)
955{
956
957 WINPR_ASSERT(s);
958 if (!Stream_EnsureRemainingCapacity(s, 4 + length))
959 return FALSE;
960 Stream_Write_UINT16(s, type); /* type */
961 Stream_Write_UINT16(s, length); /* length */
962 return TRUE;
963}
964
965static UINT32 filterAndLogEarlyServerCapabilityFlags(wLog* log, UINT32 flags)
966{
967 const UINT32 mask =
968 (RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
969 RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED);
970 const UINT32 filtered = flags & mask;
971 const UINT32 unknown = flags & (~mask);
972 if (unknown != 0)
973 {
974 char buffer[256] = WINPR_C_ARRAY_INIT;
975 WLog_Print(log, WLOG_WARN,
976 "TS_UD_SC_CORE::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
977 " --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
978 flags, ~mask, unknown,
979 rdp_early_server_caps_string(unknown, buffer, sizeof(buffer)));
980 }
981 return filtered;
982}
983
984static UINT32 earlyServerCapsFromSettings(wLog* log, const rdpSettings* settings)
985{
986 UINT32 EarlyCapabilityFlags = 0;
987
988 if (settings->SupportEdgeActionV1)
989 EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1;
990 if (settings->SupportDynamicTimeZone)
991 EarlyCapabilityFlags |= RNS_UD_SC_DYNAMIC_DST_SUPPORTED;
992 if (settings->SupportEdgeActionV2)
993 EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2;
994 if (settings->SupportSkipChannelJoin)
995 EarlyCapabilityFlags |= RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
996
997 return filterAndLogEarlyServerCapabilityFlags(log, EarlyCapabilityFlags);
998}
999
1000static UINT16 filterAndLogEarlyClientCapabilityFlags(wLog* log, UINT32 flags)
1001{
1002 const UINT32 mask =
1003 (RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
1004 RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
1005 RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
1006 RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
1007 RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
1008 RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN);
1009 const UINT32 filtered = flags & mask;
1010 const UINT32 unknown = flags & ~mask;
1011 if (unknown != 0)
1012 {
1013 char buffer[256] = WINPR_C_ARRAY_INIT;
1014 WLog_Print(log, WLOG_WARN,
1015 "(TS_UD_CS_CORE)::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
1016 " --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
1017 flags, ~mask, unknown,
1018 rdp_early_client_caps_string(unknown, buffer, sizeof(buffer)));
1019 }
1020
1021 WINPR_ASSERT(filtered <= UINT16_MAX);
1022 return (UINT16)filtered;
1023}
1024
1025static UINT16 earlyClientCapsFromSettings(wLog* log, const rdpSettings* settings)
1026{
1027 UINT32 earlyCapabilityFlags = 0;
1028
1029 WINPR_ASSERT(settings);
1030 if (settings->SupportErrorInfoPdu)
1031 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_ERRINFO_PDU;
1032
1033 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 32)
1034 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
1035
1036 if (settings->SupportStatusInfoPdu)
1037 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_STATUSINFO_PDU;
1038
1039 if (settings->ConnectionType)
1040 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
1041
1042 if (settings->SupportMonitorLayoutPdu)
1043 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU;
1044
1045 if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
1046 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT;
1047
1048 if (settings->SupportGraphicsPipeline)
1049 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL;
1050
1051 if (settings->SupportDynamicTimeZone)
1052 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE;
1053
1054 if (settings->SupportHeartbeatPdu)
1055 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_HEARTBEAT_PDU;
1056
1057 if (settings->SupportAsymetricKeys)
1058 earlyCapabilityFlags |= RNS_UD_CS_STRONG_ASYMMETRIC_KEYS;
1059
1060 if (settings->HasRelativeMouseEvent)
1061 earlyCapabilityFlags |= RNS_UD_CS_RELATIVE_MOUSE_INPUT;
1062
1063 if (settings->SupportSkipChannelJoin)
1064 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
1065
1066 return filterAndLogEarlyClientCapabilityFlags(log, earlyCapabilityFlags);
1067}
1068
1069static BOOL updateEarlyClientCaps(wLog* log, rdpSettings* settings, UINT32 earlyCapabilityFlags,
1070 UINT32 connectionType)
1071{
1072 WINPR_ASSERT(settings);
1073
1074 if (settings->SupportErrorInfoPdu)
1075 settings->SupportErrorInfoPdu = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU) != 0;
1076
1077 /* RNS_UD_CS_WANT_32BPP_SESSION is already handled in gcc_read_client_core_data:
1078 *
1079 * it is evaluated in combination with highColorDepth and the server side
1080 * settings to determine the session color depth to use.
1081 */
1082
1083 if (settings->SupportStatusInfoPdu)
1084 settings->SupportStatusInfoPdu =
1085 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU) != 0;
1086
1087 if (settings->SupportAsymetricKeys)
1088 settings->SupportAsymetricKeys =
1089 (earlyCapabilityFlags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS) != 0;
1090
1091 if (settings->HasRelativeMouseEvent)
1092 {
1093 /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1094 * the flag must be ignored if the RDP version is < 0x00080011 */
1095 if (settings->RdpVersion >= RDP_VERSION_10_12)
1096 {
1097 settings->HasRelativeMouseEvent =
1098 (earlyCapabilityFlags & RNS_UD_CS_RELATIVE_MOUSE_INPUT) != 0;
1099 }
1100 else
1101 settings->HasRelativeMouseEvent = FALSE;
1102 }
1103
1104 if (settings->NetworkAutoDetect)
1105 settings->NetworkAutoDetect =
1106 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT) != 0;
1107
1108 if (settings->SupportSkipChannelJoin)
1109 settings->SupportSkipChannelJoin =
1110 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN) != 0;
1111
1112 if (settings->SupportMonitorLayoutPdu)
1113 settings->SupportMonitorLayoutPdu =
1114 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) != 0;
1115
1116 if (settings->SupportHeartbeatPdu)
1117 settings->SupportHeartbeatPdu =
1118 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) != 0;
1119
1120 if (settings->SupportGraphicsPipeline)
1121 settings->SupportGraphicsPipeline =
1122 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) != 0;
1123
1124 if (settings->SupportDynamicTimeZone)
1125 settings->SupportDynamicTimeZone =
1126 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) != 0;
1127
1128 if ((earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE) == 0)
1129 connectionType = 0;
1130 settings->ConnectionType = connectionType;
1131
1132 filterAndLogEarlyClientCapabilityFlags(log, earlyCapabilityFlags);
1133 return TRUE;
1134}
1135
1136static BOOL updateEarlyServerCaps(wLog* log, rdpSettings* settings, UINT32 earlyCapabilityFlags,
1137 WINPR_ATTR_UNUSED UINT32 connectionType)
1138{
1139 WINPR_ASSERT(settings);
1140
1141 settings->SupportEdgeActionV1 = (settings->SupportEdgeActionV1 &&
1142 (earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1));
1143 settings->SupportDynamicTimeZone = (settings->SupportDynamicTimeZone &&
1144 (earlyCapabilityFlags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED));
1145 settings->SupportEdgeActionV2 = (settings->SupportEdgeActionV2 &&
1146 (earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2));
1147 settings->SupportSkipChannelJoin =
1148 (settings->SupportSkipChannelJoin &&
1149 (earlyCapabilityFlags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED));
1150
1151 filterAndLogEarlyServerCapabilityFlags(log, earlyCapabilityFlags);
1152 return TRUE;
1153}
1154
1164BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs)
1165{
1166 char buffer[2048] = WINPR_C_ARRAY_INIT;
1167 char strbuffer[130] = WINPR_C_ARRAY_INIT;
1168 BYTE connectionType = 0;
1169 UINT32 clientColorDepth = 0;
1170 UINT16 postBeta2ColorDepth = 0;
1171 UINT16 highColorDepth = 0;
1172 rdpSettings* settings = mcs_get_settings(mcs);
1173
1174 WINPR_ASSERT(s);
1175 WINPR_ASSERT(settings);
1176
1177 /* Length of all required fields, until imeFileName */
1178 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 128))
1179 return FALSE;
1180
1181 const UINT32 version = Stream_Get_UINT32(s); /* version (4 bytes) */
1182 settings->RdpVersion = rdp_version_common(mcs->log, version, settings->RdpVersion);
1183 Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */
1184 if (settings->DesktopWidth == 0)
1185 {
1186 WLog_Print(mcs->log, WLOG_ERROR, "Invalid DesktopWidth=0");
1187 return FALSE;
1188 }
1189 Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
1190 if (settings->DesktopHeight == 0)
1191 {
1192 WLog_Print(mcs->log, WLOG_ERROR, "Invalid DesktopHeight=0");
1193 return FALSE;
1194 }
1195 const UINT16 colorDepth = Stream_Get_UINT16(s); /* ColorDepth (2 bytes) */
1196 Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
1197 Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
1198 Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */
1199
1200 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
1201 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 32 / sizeof(WCHAR), strbuffer,
1202 ARRAYSIZE(strbuffer)) < 0)
1203 {
1204 WLog_Print(mcs->log, WLOG_ERROR, "failed to convert client host name");
1205 return FALSE;
1206 }
1207
1208 if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, strbuffer))
1209 return FALSE;
1210
1211 Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */
1212 Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */
1213 Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */
1214 Stream_Seek(s, 64); /* imeFileName (64 bytes) */
1215
1223 do
1224 {
1225 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1226 break;
1227
1228 postBeta2ColorDepth = Stream_Get_UINT16(s); /* postBeta2ColorDepth (2 bytes) */
1229
1230 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1231 break;
1232
1233 const UINT16 clientProductId = Stream_Get_UINT16(s); /* clientProductID (2 bytes) */
1234
1235 /* [MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::clientProductId (optional)
1236 * should be initialized to 1
1237 */
1238 if (clientProductId != 1)
1239 {
1240 WLog_Print(mcs->log, WLOG_WARN,
1241 "[MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::clientProductId "
1242 "(optional) expected 1, got %" PRIu32,
1243 clientProductId);
1244 }
1245
1246 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1247 break;
1248
1249 const UINT32 serialNumber = Stream_Get_UINT32(s); /* serialNumber (4 bytes) */
1250
1251 /* [MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::serialNumber (optional)
1252 * should be initialized to 0
1253 */
1254 if (serialNumber != 0)
1255 {
1256 WLog_Print(mcs->log, WLOG_WARN,
1257 "[MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::serialNumber "
1258 "(optional) expected 0, got %" PRIu32,
1259 serialNumber);
1260 }
1261
1262 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1263 break;
1264
1265 highColorDepth = Stream_Get_UINT16(s); /* highColorDepth (2 bytes) */
1266
1267 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1268 break;
1269
1270 Stream_Read_UINT16(s, settings->SupportedColorDepths); /* supportedColorDepths (2 bytes) */
1271
1272 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1273 break;
1274
1275 Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
1276
1277 /* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */
1278 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 64))
1279 break;
1280
1281 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 64 / sizeof(WCHAR), strbuffer,
1282 ARRAYSIZE(strbuffer)) < 0)
1283 {
1284 WLog_Print(mcs->log, WLOG_ERROR, "failed to convert the client product identifier");
1285 return FALSE;
1286 }
1287
1288 if (!freerdp_settings_set_string(settings, FreeRDP_ClientProductId, strbuffer))
1289 return FALSE;
1290
1291 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1292 break;
1293
1294 connectionType = Stream_Get_UINT8(s); /* connectionType (1 byte) */
1295
1296 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1297 break;
1298
1299 Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
1300
1301 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1302 break;
1303
1304 const UINT32 serverSelectedProtocol =
1305 Stream_Get_UINT32(s); /* serverSelectedProtocol (4 bytes) */
1306
1307 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1308 break;
1309
1310 Stream_Read_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
1311
1312 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1313 break;
1314
1315 Stream_Read_UINT32(s,
1316 settings->DesktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
1317
1318 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1319 break;
1320
1321 Stream_Read_UINT16(s, settings->DesktopOrientation); /* desktopOrientation (2 bytes) */
1322
1323 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1324 break;
1325
1326 Stream_Read_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor (4 bytes) */
1327
1328 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1329 break;
1330
1331 Stream_Read_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor (4 bytes) */
1332
1333 if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
1334 settings->SelectedProtocol = serverSelectedProtocol;
1335 else if (settings->SelectedProtocol != serverSelectedProtocol)
1336 return FALSE;
1337 } while (0);
1338
1339 if (highColorDepth > 0)
1340 {
1341 if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
1342 clientColorDepth = 32;
1343 else
1344 clientColorDepth = highColorDepth;
1345 }
1346 else if (postBeta2ColorDepth > 0)
1347 {
1348 switch (postBeta2ColorDepth)
1349 {
1350 case RNS_UD_COLOR_4BPP:
1351 clientColorDepth = 4;
1352 break;
1353
1354 case RNS_UD_COLOR_8BPP:
1355 clientColorDepth = 8;
1356 break;
1357
1358 case RNS_UD_COLOR_16BPP_555:
1359 clientColorDepth = 15;
1360 break;
1361
1362 case RNS_UD_COLOR_16BPP_565:
1363 clientColorDepth = 16;
1364 break;
1365
1366 case RNS_UD_COLOR_24BPP:
1367 clientColorDepth = 24;
1368 break;
1369
1370 default:
1371 return FALSE;
1372 }
1373 }
1374 else
1375 {
1376 switch (colorDepth)
1377 {
1378 case RNS_UD_COLOR_4BPP:
1379 clientColorDepth = 4;
1380 break;
1381
1382 case RNS_UD_COLOR_8BPP:
1383 clientColorDepth = 8;
1384 break;
1385
1386 default:
1387 return FALSE;
1388 }
1389 }
1390
1391 /*
1392 * If we are in server mode, accept client's color depth only if
1393 * it is smaller than ours. This is what Windows server does.
1394 */
1395 if ((clientColorDepth < freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth)) ||
1396 !settings->ServerMode)
1397 {
1398 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, clientColorDepth))
1399 return FALSE;
1400 }
1401
1402 WLog_Print(
1403 mcs->log, WLOG_DEBUG, "Received EarlyCapabilityFlags=%s",
1404 rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
1405
1406 return updateEarlyClientCaps(mcs->log, settings, settings->EarlyCapabilityFlags,
1407 connectionType);
1408}
1409
1419BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs)
1420{
1421 char buffer[2048] = WINPR_C_ARRAY_INIT;
1422 char dbuffer[2048] = WINPR_C_ARRAY_INIT;
1423 BYTE connectionType = 0;
1424 HIGH_COLOR_DEPTH highColorDepth = HIGH_COLOR_4BPP;
1425
1426 UINT16 earlyCapabilityFlags = 0;
1427 const rdpSettings* settings = mcs_get_const_settings(mcs);
1428
1429 WINPR_ASSERT(s);
1430 WINPR_ASSERT(settings);
1431
1432 const UINT16 SupportedColorDepths =
1433 freerdp_settings_get_uint16(settings, FreeRDP_SupportedColorDepths);
1434 const UINT32 ColorDepth = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
1435
1436 if (!gcc_write_user_data_header(s, CS_CORE, 234))
1437 return FALSE;
1438
1439 Stream_Write_UINT32(s, settings->RdpVersion); /* Version */
1440 Stream_Write_UINT16(
1441 s, WINPR_ASSERTING_INT_CAST(uint16_t, settings->DesktopWidth)); /* DesktopWidth */
1442 Stream_Write_UINT16(
1443 s, WINPR_ASSERTING_INT_CAST(uint16_t, settings->DesktopHeight)); /* DesktopHeight */
1444 Stream_Write_UINT16(s,
1445 RNS_UD_COLOR_8BPP); /* ColorDepth, ignored because of postBeta2ColorDepth */
1446 Stream_Write_UINT16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
1447 Stream_Write_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */
1448 Stream_Write_UINT32(s, settings->ClientBuild); /* ClientBuild */
1449
1450 if (!Stream_EnsureRemainingCapacity(s, 32 + 12 + 64 + 8))
1451 return FALSE;
1452
1453 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
1454 size_t clientNameLength = 0;
1455 WCHAR* clientName = ConvertUtf8ToWCharAlloc(settings->ClientHostname, &clientNameLength);
1456 if (clientNameLength >= 16)
1457 {
1458 clientNameLength = 16;
1459 clientName[clientNameLength - 1] = 0;
1460 }
1461
1462 Stream_Write(s, clientName, (clientNameLength * 2));
1463 Stream_Zero(s, 32 - (clientNameLength * 2));
1464 free(clientName);
1465 Stream_Write_UINT32(s, settings->KeyboardType); /* KeyboardType */
1466 Stream_Write_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */
1467 Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */
1468 Stream_Zero(s, 64); /* imeFileName */
1469 Stream_Write_UINT16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
1470 Stream_Write_UINT16(s, 1); /* clientProductID */
1471 Stream_Write_UINT32(s, 0); /* serialNumber (should be initialized to 0) */
1472 highColorDepth = ColorDepthToHighColor(ColorDepth);
1473 earlyCapabilityFlags = earlyClientCapsFromSettings(mcs->log, settings);
1474
1475 WINPR_ASSERT(settings->ConnectionType <= UINT8_MAX);
1476 connectionType = (UINT8)settings->ConnectionType;
1477
1478 if (!Stream_EnsureRemainingCapacity(s, 6))
1479 return FALSE;
1480
1481 WLog_Print(
1482 mcs->log, WLOG_DEBUG,
1483 "Sending highColorDepth=%s, supportedColorDepths=%s, earlyCapabilityFlags=%s",
1484 HighColorToString(highColorDepth),
1485 freerdp_supported_color_depths_string(SupportedColorDepths, dbuffer, sizeof(dbuffer)),
1486 rdp_early_client_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer)));
1487 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, highColorDepth)); /* highColorDepth */
1488 Stream_Write_UINT16(s, SupportedColorDepths); /* supportedColorDepths */
1489 Stream_Write_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
1490
1491 if (!Stream_EnsureRemainingCapacity(s, 64 + 24))
1492 return FALSE;
1493
1494 /* clientDigProductId (64 bytes, assume WCHAR, not \0 terminated */
1495 const char* str = freerdp_settings_get_string(settings, FreeRDP_ClientProductId);
1496 if (str)
1497 {
1498 if (Stream_Write_UTF16_String_From_UTF8(s, 32, str, strnlen(str, 32), TRUE) < 0)
1499 return FALSE;
1500 }
1501 else
1502 Stream_Zero(s, 32 * sizeof(WCHAR));
1503
1504 Stream_Write_UINT8(s, connectionType); /* connectionType */
1505 Stream_Write_UINT8(s, 0); /* pad1octet */
1506 Stream_Write_UINT32(s, settings->SelectedProtocol); /* serverSelectedProtocol */
1507 Stream_Write_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth */
1508 Stream_Write_UINT32(s, settings->DesktopPhysicalHeight); /* desktopPhysicalHeight */
1509 Stream_Write_UINT16(s, settings->DesktopOrientation); /* desktopOrientation */
1510 Stream_Write_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor */
1511 Stream_Write_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor */
1512 return TRUE;
1513}
1514
1515BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs)
1516{
1517 UINT32 serverVersion = 0;
1518 rdpSettings* settings = mcs_get_settings(mcs);
1519
1520 WINPR_ASSERT(s);
1521 WINPR_ASSERT(settings);
1522
1523 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1524 return FALSE;
1525
1526 Stream_Read_UINT32(s, serverVersion); /* version */
1527 settings->RdpVersion = rdp_version_common(mcs->log, serverVersion, settings->RdpVersion);
1528
1529 if (Stream_GetRemainingLength(s) >= 4)
1530 {
1531 Stream_Read_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */
1532 }
1533
1534 if (Stream_GetRemainingLength(s) >= 4)
1535 {
1536 char buffer[2048] = WINPR_C_ARRAY_INIT;
1537
1538 Stream_Read_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */
1539 WLog_Print(
1540 mcs->log, WLOG_DEBUG, "Received EarlyCapabilityFlags=%s",
1541 rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
1542 }
1543
1544 return updateEarlyServerCaps(mcs->log, settings, settings->EarlyCapabilityFlags,
1545 settings->ConnectionType);
1546}
1547
1548/* TODO: This function modifies rdpMcs
1549 * TODO: Split this out of this function
1550 */
1551BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs)
1552{
1553 const rdpSettings* settings = mcs_get_const_settings(mcs);
1554
1555 WINPR_ASSERT(s);
1556 WINPR_ASSERT(settings);
1557
1558 if (!gcc_write_user_data_header(s, SC_CORE, 16))
1559 return FALSE;
1560
1561 const UINT32 EarlyCapabilityFlags = earlyServerCapsFromSettings(mcs->log, settings);
1562 Stream_Write_UINT32(s, settings->RdpVersion); /* version (4 bytes) */
1563 Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */
1564 Stream_Write_UINT32(s, EarlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */
1565 return TRUE;
1566}
1567
1577BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs)
1578{
1579 rdpSettings* settings = mcs_get_settings(mcs);
1580
1581 WINPR_ASSERT(s);
1582 WINPR_ASSERT(settings);
1583
1584 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
1585 return FALSE;
1586
1587 if (settings->UseRdpSecurityLayer)
1588 {
1589 Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
1590
1591 if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
1592 Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
1593 else
1594 Stream_Seek(s, 4);
1595 }
1596 else
1597 {
1598 Stream_Seek(s, 8);
1599 }
1600
1601 return TRUE;
1602}
1603
1613BOOL gcc_write_client_security_data(wStream* s, const rdpMcs* mcs)
1614{
1615 const rdpSettings* settings = mcs_get_const_settings(mcs);
1616
1617 WINPR_ASSERT(s);
1618 WINPR_ASSERT(settings);
1619
1620 if (!gcc_write_user_data_header(s, CS_SECURITY, 12))
1621 return FALSE;
1622
1623 if (settings->UseRdpSecurityLayer)
1624 {
1625 Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
1626 Stream_Write_UINT32(s, 0); /* extEncryptionMethods */
1627 }
1628 else
1629 {
1630 /* French locale, disable encryption */
1631 Stream_Write_UINT32(s, 0); /* encryptionMethods */
1632 Stream_Write_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
1633 }
1634 return TRUE;
1635}
1636
1637BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
1638{
1639 BOOL validCryptoConfig = FALSE;
1640 UINT32 EncryptionMethod = 0;
1641 UINT32 EncryptionLevel = 0;
1642 rdpSettings* settings = mcs_get_settings(mcs);
1643
1644 WINPR_ASSERT(s);
1645 WINPR_ASSERT(settings);
1646
1647 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
1648 return FALSE;
1649
1650 Stream_Read_UINT32(s, EncryptionMethod); /* encryptionMethod */
1651 Stream_Read_UINT32(s, EncryptionLevel); /* encryptionLevel */
1652
1653 /* Only accept valid/known encryption methods */
1654 switch (EncryptionMethod)
1655 {
1656 case ENCRYPTION_METHOD_NONE:
1657 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: NONE");
1658 break;
1659
1660 case ENCRYPTION_METHOD_40BIT:
1661 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 40BIT");
1662 break;
1663
1664 case ENCRYPTION_METHOD_56BIT:
1665 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 56BIT");
1666 break;
1667
1668 case ENCRYPTION_METHOD_128BIT:
1669 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 128BIT");
1670 break;
1671
1672 case ENCRYPTION_METHOD_FIPS:
1673 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: FIPS");
1674 break;
1675
1676 default:
1677 WLog_Print(mcs->log, WLOG_ERROR, "Received unknown encryption method %08" PRIX32 "",
1678 EncryptionMethod);
1679 return FALSE;
1680 }
1681
1682 if (settings->UseRdpSecurityLayer && (EncryptionMethod != ENCRYPTION_METHOD_NONE) &&
1683 !(settings->EncryptionMethods & EncryptionMethod))
1684 {
1685 WLog_Print(mcs->log, WLOG_WARN,
1686 "Server uses non-advertised encryption method 0x%08" PRIX32 "",
1687 EncryptionMethod);
1688 /* FIXME: Should we return FALSE; in this case ?? */
1689 }
1690
1691 settings->EncryptionMethods = EncryptionMethod;
1692 settings->EncryptionLevel = EncryptionLevel;
1693 /* Verify encryption level/method combinations according to MS-RDPBCGR Section 5.3.2 */
1694 switch (settings->EncryptionLevel)
1695 {
1696 case ENCRYPTION_LEVEL_NONE:
1697 if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
1698 {
1699 validCryptoConfig = TRUE;
1700 }
1701
1702 break;
1703
1704 case ENCRYPTION_LEVEL_FIPS:
1705 if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1706 {
1707 validCryptoConfig = TRUE;
1708 }
1709
1710 break;
1711
1712 case ENCRYPTION_LEVEL_LOW:
1713 case ENCRYPTION_LEVEL_HIGH:
1714 case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
1715 if (settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT ||
1716 settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT ||
1717 settings->EncryptionMethods == ENCRYPTION_METHOD_128BIT ||
1718 settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
1719 {
1720 validCryptoConfig = TRUE;
1721 }
1722
1723 break;
1724
1725 default:
1726 WLog_Print(mcs->log, WLOG_ERROR, "Received unknown encryption level 0x%08" PRIX32 "",
1727 settings->EncryptionLevel);
1728 }
1729
1730 if (!validCryptoConfig)
1731 {
1732 WLog_Print(mcs->log, WLOG_ERROR,
1733 "Received invalid cryptographic configuration (level=0x%08" PRIX32
1734 " method=0x%08" PRIX32 ")",
1735 settings->EncryptionLevel, settings->EncryptionMethods);
1736 return FALSE;
1737 }
1738
1739 if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
1740 {
1741 /* serverRandomLen and serverCertLen must not be present */
1742 settings->UseRdpSecurityLayer = FALSE;
1743 return TRUE;
1744 }
1745
1746 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
1747 return FALSE;
1748
1749 Stream_Read_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */
1750 Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */
1751
1752 if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0))
1753 {
1754 WLog_Print(mcs->log, WLOG_ERROR,
1755 "Invalid ServerRandom (length=%" PRIu32 ") or ServerCertificate (length=%" PRIu32
1756 ")",
1757 settings->ServerRandomLength, settings->ServerCertificateLength);
1758 return FALSE;
1759 }
1760
1761 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, settings->ServerRandomLength))
1762 return FALSE;
1763
1764 /* serverRandom */
1765 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, nullptr,
1766 settings->ServerRandomLength))
1767 goto fail;
1768
1769 Stream_Read(s, settings->ServerRandom, settings->ServerRandomLength);
1770
1771 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, settings->ServerCertificateLength))
1772 goto fail;
1773
1774 /* serverCertificate */
1775 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerCertificate, nullptr,
1776 settings->ServerCertificateLength))
1777 goto fail;
1778
1779 Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength);
1780
1781 {
1782 const BYTE* data = settings->ServerCertificate;
1783 const uint32_t length = settings->ServerCertificateLength;
1784
1785 if (!freerdp_certificate_read_server_cert(settings->RdpServerCertificate, data, length))
1786 goto fail;
1787 }
1788 return TRUE;
1789fail:
1790 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, nullptr, 0))
1791 WLog_Print(
1792 mcs->log, WLOG_ERROR,
1793 "freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, nullptr, 0) failed");
1794 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerCertificate, nullptr, 0))
1795 WLog_Print(mcs->log, WLOG_ERROR,
1796 "freerdp_settings_set_pointer_len(settings, FreeRDP_ServerCertificate, nullptr, "
1797 "0) failed");
1798 return FALSE;
1799}
1800
1801static BOOL gcc_update_server_random(rdpSettings* settings)
1802{
1803 const size_t length = 32;
1804 WINPR_ASSERT(settings);
1805 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, nullptr, length))
1806 return FALSE;
1807 BYTE* data = freerdp_settings_get_pointer_writable(settings, FreeRDP_ServerRandom);
1808 if (!data)
1809 return FALSE;
1810 return winpr_RAND(data, length) >= 0;
1811}
1812
1813/* TODO: This function does manipulate data in rdpMcs
1814 * TODO: Split this out of this function
1815 */
1816BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
1817{
1818 if (!gcc_update_server_random(mcs_get_settings(mcs)))
1819 return FALSE;
1820
1821 const rdpSettings* settings = mcs_get_const_settings(mcs);
1822
1823 WINPR_ASSERT(s);
1824 WINPR_ASSERT(settings);
1825
1826 const size_t posHeader = Stream_GetPosition(s);
1827 if (!gcc_write_user_data_header(s, SC_SECURITY, 12))
1828 return FALSE;
1829
1830 Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */
1831 Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
1832
1833 if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
1834 return TRUE;
1835
1836 if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32) + settings->ServerRandomLength))
1837 return FALSE;
1838 Stream_Write_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */
1839 const size_t posCertLen = Stream_GetPosition(s);
1840 Stream_Seek_UINT32(s); /* serverCertLen */
1841 Stream_Write(s, settings->ServerRandom, settings->ServerRandomLength);
1842
1843 const SSIZE_T len = freerdp_certificate_write_server_cert(
1844 settings->RdpServerCertificate, CERT_TEMPORARILY_ISSUED | CERT_CHAIN_VERSION_1, s);
1845 if (len < 0)
1846 return FALSE;
1847 const size_t end = Stream_GetPosition(s);
1848
1849 WINPR_ASSERT(end >= posHeader);
1850 const size_t diff = end - posHeader;
1851 WINPR_ASSERT(diff <= UINT16_MAX);
1852 if (!Stream_SetPosition(s, posHeader))
1853 return FALSE;
1854 if (!gcc_write_user_data_header(s, SC_SECURITY, (UINT16)diff))
1855 return FALSE;
1856 if (!Stream_SetPosition(s, posCertLen))
1857 return FALSE;
1858 WINPR_ASSERT(len <= UINT32_MAX);
1859 Stream_Write_UINT32(s, (UINT32)len);
1860 return Stream_SetPosition(s, end);
1861}
1862
1873BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs)
1874{
1875 WINPR_ASSERT(s);
1876 WINPR_ASSERT(mcs);
1877
1878 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1879 return FALSE;
1880
1881 Stream_Read_UINT32(s, mcs->channelCount); /* channelCount */
1882
1883 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, mcs->channelCount, 12ull))
1884 return FALSE;
1885
1886 if (mcs->channelCount > CHANNEL_MAX_COUNT)
1887 {
1888 WLog_Print(mcs->log, WLOG_ERROR, "rdpMcs::channelCount %" PRIu32 " > maximum %d",
1889 mcs->channelCount, CHANNEL_MAX_COUNT);
1890 return FALSE;
1891 }
1892
1893 /* channelDefArray */
1894 for (UINT32 i = 0; i < mcs->channelCount; i++)
1895 {
1902 rdpMcsChannel* channel = &mcs->channels[i];
1903 Stream_Read(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
1904
1905 if (!memchr(channel->Name, 0, CHANNEL_NAME_LEN + 1))
1906 {
1907 WLog_Print(
1908 mcs->log, WLOG_ERROR,
1909 "protocol violation: received a static channel name with missing null-termination");
1910 return FALSE;
1911 }
1912
1913 Stream_Read_UINT32(s, channel->options); /* options (4 bytes) */
1914 channel->ChannelId = mcs->baseChannelId++;
1915 }
1916
1917 return TRUE;
1918}
1919
1929BOOL gcc_write_client_network_data(wStream* s, const rdpMcs* mcs)
1930{
1931 WINPR_ASSERT(s);
1932 WINPR_ASSERT(mcs);
1933 if (mcs->channelCount > 0)
1934 {
1935 const size_t length = mcs->channelCount * 12 + 8;
1936 WINPR_ASSERT(length <= UINT16_MAX);
1937 if (!gcc_write_user_data_header(s, CS_NET, (UINT16)length))
1938 return FALSE;
1939 Stream_Write_UINT32(s, mcs->channelCount); /* channelCount */
1940
1941 /* channelDefArray */
1942 for (UINT32 i = 0; i < mcs->channelCount; i++)
1943 {
1944 /* CHANNEL_DEF */
1945 rdpMcsChannel* channel = &mcs->channels[i];
1946 Stream_Write(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
1947 Stream_Write_UINT32(s, channel->options); /* options (4 bytes) */
1948 }
1949 }
1950 return TRUE;
1951}
1952
1953BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs)
1954{
1955 UINT16 channelId = 0;
1956 UINT32 parsedChannelCount = 0;
1957 WINPR_ASSERT(s);
1958 WINPR_ASSERT(mcs);
1959 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1960 return FALSE;
1961
1962 mcs->IOChannelId = Stream_Get_UINT16(s); /* MCSChannelId */
1963 const uint16_t channelCount = Stream_Get_UINT16(s); /* channelCount */
1964 parsedChannelCount = channelCount;
1965
1966 if (channelCount != mcs->channelCount)
1967 {
1968 WLog_Print(mcs->log, WLOG_ERROR, "requested %" PRIu32 " channels, got %" PRIu16 " instead",
1969 mcs->channelCount, channelCount);
1970
1971 /* we ensure that the response is not bigger than the request */
1972
1973 mcs->channelCount = channelCount;
1974 }
1975
1976 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, channelCount, 2ull))
1977 return FALSE;
1978
1979 if (mcs->channelMaxCount < parsedChannelCount)
1980 {
1981 WLog_Print(mcs->log, WLOG_ERROR,
1982 "requested %" PRIu32 " channels > channelMaxCount %" PRIu16, mcs->channelCount,
1983 mcs->channelMaxCount);
1984 return FALSE;
1985 }
1986
1987 for (UINT32 i = 0; i < parsedChannelCount; i++)
1988 {
1989 rdpMcsChannel* channel = &mcs->channels[i];
1990 Stream_Read_UINT16(s, channelId); /* channelId */
1991 channel->ChannelId = channelId;
1992 }
1993
1994 if (channelCount % 2 == 1)
1995 return Stream_SafeSeek(s, 2); /* padding */
1996
1997 return TRUE;
1998}
1999
2000BOOL gcc_write_server_network_data(wStream* s, const rdpMcs* mcs)
2001{
2002 WINPR_ASSERT(s);
2003 WINPR_ASSERT(mcs);
2004 const size_t payloadLen =
2005 8ull + mcs->channelCount * 2ull + (mcs->channelCount % 2 == 1 ? 2ull : 0ull);
2006
2007 WINPR_ASSERT(payloadLen <= UINT16_MAX);
2008 if (!gcc_write_user_data_header(s, SC_NET, (UINT16)payloadLen))
2009 return FALSE;
2010
2011 Stream_Write_UINT16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
2012 Stream_Write_UINT16(s,
2013 WINPR_ASSERTING_INT_CAST(uint16_t, mcs->channelCount)); /* channelCount */
2014
2015 for (UINT32 i = 0; i < mcs->channelCount; i++)
2016 {
2017 const rdpMcsChannel* channel = &mcs->channels[i];
2018 Stream_Write_UINT16(s, channel->ChannelId);
2019 }
2020
2021 if (mcs->channelCount % 2 == 1)
2022 Stream_Write_UINT16(s, 0);
2023
2024 return TRUE;
2025}
2026
2036BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs)
2037{
2038 char buffer[128] = WINPR_C_ARRAY_INIT;
2039 UINT32 redirectedSessionId = 0;
2040 rdpSettings* settings = mcs_get_settings(mcs);
2041
2042 WINPR_ASSERT(s);
2043 WINPR_ASSERT(settings);
2044
2045 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
2046 return FALSE;
2047
2048 Stream_Read_UINT32(s, settings->ClusterInfoFlags); /* flags */
2049 Stream_Read_UINT32(s, redirectedSessionId); /* redirectedSessionId */
2050
2051 WLog_Print(mcs->log, WLOG_TRACE, "read ClusterInfoFlags=%s, RedirectedSessionId=0x%08" PRIx32,
2052 rdp_cluster_info_flags_to_string(settings->ClusterInfoFlags, buffer, sizeof(buffer)),
2053 redirectedSessionId);
2054 if (settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID)
2055 settings->RedirectedSessionId = redirectedSessionId;
2056
2057 settings->ConsoleSession = (settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID) != 0;
2058 settings->RedirectSmartCards = (settings->ClusterInfoFlags & REDIRECTED_SMARTCARD) != 0;
2059
2060 if (Stream_GetRemainingLength(s) > 0)
2061 {
2062 /* The old Microsoft Mac RDP client can send a pad here */
2063 Stream_Seek(s, Stream_GetRemainingLength(s));
2064 }
2065
2066 return TRUE;
2067}
2068
2078BOOL gcc_write_client_cluster_data(wStream* s, const rdpMcs* mcs)
2079{
2080 char buffer[128] = WINPR_C_ARRAY_INIT;
2081 UINT32 flags = 0;
2082 const rdpSettings* settings = mcs_get_const_settings(mcs);
2083
2084 WINPR_ASSERT(s);
2085 WINPR_ASSERT(settings);
2086
2087 if (!gcc_write_user_data_header(s, CS_CLUSTER, 12))
2088 return FALSE;
2089 flags = settings->ClusterInfoFlags;
2090
2091 if (settings->ConsoleSession || settings->RedirectedSessionId)
2092 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
2093
2094 if (settings->RedirectSmartCards && settings->SmartcardLogon)
2095 flags |= REDIRECTED_SMARTCARD;
2096
2097 if (flags & REDIRECTION_SUPPORTED)
2098 {
2099 /* REDIRECTION_VERSION6 requires multitransport enabled.
2100 * if we run without that use REDIRECTION_VERSION5 */
2101 if (freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))
2102 flags |= (REDIRECTION_VERSION6 << 2);
2103 else
2104 flags |= (REDIRECTION_VERSION5 << 2);
2105 }
2106
2107 WLog_Print(mcs->log, WLOG_TRACE, "write ClusterInfoFlags=%s, RedirectedSessionId=0x%08" PRIx32,
2108 rdp_cluster_info_flags_to_string(flags, buffer, sizeof(buffer)),
2109 settings->RedirectedSessionId);
2110 Stream_Write_UINT32(s, flags); /* flags */
2111 Stream_Write_UINT32(s, settings->RedirectedSessionId); /* redirectedSessionID */
2112 return TRUE;
2113}
2114
2124BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs)
2125{
2126 UINT32 monitorCount = 0;
2127 rdpSettings* settings = mcs_get_settings(mcs);
2128
2129 WINPR_ASSERT(s);
2130 WINPR_ASSERT(settings);
2131
2132 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
2133 return FALSE;
2134
2135 Stream_Read_UINT32(s, settings->MonitorFlags); /* flags */
2136 Stream_Read_UINT32(s, monitorCount); /* monitorCount */
2137
2138 /* 2.2.1.3.6 Client Monitor Data -
2139 * monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display
2140 * monitor definitions in the monitorDefArray field (the maximum allowed is 16).
2141 */
2142 if (monitorCount > 16)
2143 {
2144 WLog_Print(mcs->log, WLOG_ERROR, "announced monitors(%" PRIu32 ") exceed the 16 limit",
2145 monitorCount);
2146 return FALSE;
2147 }
2148
2149 if (monitorCount > settings->MonitorDefArraySize)
2150 {
2151 WLog_Print(mcs->log, WLOG_ERROR,
2152 "too many announced monitors(%" PRIu32 "), clamping to %" PRIu32 "",
2153 monitorCount, settings->MonitorDefArraySize);
2154 monitorCount = settings->MonitorDefArraySize;
2155 }
2156
2157 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, monitorCount, 20))
2158 return FALSE;
2159
2160 settings->MonitorCount = monitorCount;
2161
2162 for (UINT32 index = 0; index < monitorCount; index++)
2163 {
2164 rdpMonitor* current = &settings->MonitorDefArray[index];
2165
2166 const INT32 left = Stream_Get_INT32(s); /* left */
2167 const INT32 top = Stream_Get_INT32(s); /* top */
2168 const INT32 right = Stream_Get_INT32(s); /* right */
2169 const INT32 bottom = Stream_Get_INT32(s); /* bottom */
2170 const UINT32 flags = Stream_Get_UINT32(s); /* flags */
2171
2172 if ((1ll * left > right) || (1ll * top > bottom))
2173 {
2174 WLog_Print(mcs->log, WLOG_ERROR, "rdpMonitor::rect %dx%d-%dx%d invalid", left, top,
2175 right, bottom);
2176 return FALSE;
2177 }
2178
2179 const INT64 w = 1ll * right - left;
2180 const INT64 h = 1ll * bottom - top;
2181 if ((w >= INT32_MAX) || (h >= INT32_MAX) || (w < 0) || (h < 0))
2182 {
2183 WLog_Print(mcs->log, WLOG_ERROR,
2184 "rdpMonitor::width/height %" PRId64 "/%" PRId64 " invalid", w, h);
2185 return FALSE;
2186 }
2187
2188 current->x = left;
2189 current->y = top;
2190 current->width = WINPR_ASSERTING_INT_CAST(int32_t, w + 1);
2191 current->height = WINPR_ASSERTING_INT_CAST(int32_t, h + 1);
2192 current->is_primary = (flags & MONITOR_PRIMARY) != 0;
2193 }
2194
2195 return TRUE;
2196}
2197
2207BOOL gcc_write_client_monitor_data(wStream* s, const rdpMcs* mcs)
2208{
2209 INT32 baseX = 0;
2210 INT32 baseY = 0;
2211 const rdpSettings* settings = mcs_get_const_settings(mcs);
2212
2213 WINPR_ASSERT(s);
2214 WINPR_ASSERT(settings);
2215
2216 WLog_Print(mcs->log, WLOG_DEBUG, "MonitorCount=%" PRIu32, settings->MonitorCount);
2217 if (settings->MonitorCount > 1)
2218 {
2219 const size_t len = (20 * settings->MonitorCount) + 12;
2220 WINPR_ASSERT(len <= UINT16_MAX);
2221 const UINT16 length = (UINT16)len;
2222 if (!gcc_write_user_data_header(s, CS_MONITOR, length))
2223 return FALSE;
2224 Stream_Write_UINT32(s, settings->MonitorFlags); /* flags */
2225 Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
2226
2227 /* first pass to get the primary monitor coordinates (it is supposed to be
2228 * in (0,0) */
2229 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2230 {
2231 const rdpMonitor* current = &settings->MonitorDefArray[i];
2232 if (current->is_primary)
2233 {
2234 baseX = current->x;
2235 baseY = current->y;
2236 break;
2237 }
2238 }
2239
2240 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2241 {
2242 const rdpMonitor* current = &settings->MonitorDefArray[i];
2243 const INT32 left = current->x - baseX;
2244 const INT32 top = current->y - baseY;
2245 const INT32 right = left + current->width - 1;
2246 const INT32 bottom = top + current->height - 1;
2247 const UINT32 flags = current->is_primary ? MONITOR_PRIMARY : 0;
2248 WLog_Print(mcs->log, WLOG_DEBUG,
2249 "Monitor[%" PRIu32 "]: top=%" PRId32 ", left=%" PRId32 ", bottom=%" PRId32
2250 ", right=%" PRId32 ", flags=%" PRIu32,
2251 i, top, left, bottom, right, flags);
2252 Stream_Write_INT32(s, left); /* left */
2253 Stream_Write_INT32(s, top); /* top */
2254 Stream_Write_INT32(s, right); /* right */
2255 Stream_Write_INT32(s, bottom); /* bottom */
2256 Stream_Write_UINT32(s, flags); /* flags */
2257 }
2258 }
2259 WLog_Print(mcs->log, WLOG_DEBUG, "FINISHED");
2260 return TRUE;
2261}
2262
2263BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs)
2264{
2265 UINT32 monitorCount = 0;
2266 UINT32 monitorAttributeSize = 0;
2267 rdpSettings* settings = mcs_get_settings(mcs);
2268
2269 WINPR_ASSERT(s);
2270 WINPR_ASSERT(settings);
2271
2272 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 12))
2273 return FALSE;
2274
2275 Stream_Read_UINT32(s, settings->MonitorAttributeFlags); /* flags */
2276 Stream_Read_UINT32(s, monitorAttributeSize); /* monitorAttributeSize */
2277 Stream_Read_UINT32(s, monitorCount); /* monitorCount */
2278
2279 if (monitorAttributeSize != 20)
2280 {
2281 WLog_Print(mcs->log, WLOG_ERROR,
2282 "TS_UD_CS_MONITOR_EX::monitorAttributeSize %" PRIu32 " != 20",
2283 monitorAttributeSize);
2284 return FALSE;
2285 }
2286
2287 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, monitorCount,
2288 monitorAttributeSize))
2289 return FALSE;
2290
2291 if (settings->MonitorCount != monitorCount)
2292 {
2293 WLog_Print(mcs->log, WLOG_ERROR,
2294 "(TS_UD_CS_MONITOR_EX)::monitorCount %" PRIu32 " != expected %" PRIu32,
2295 monitorCount, settings->MonitorCount);
2296 return FALSE;
2297 }
2298
2299 settings->HasMonitorAttributes = TRUE;
2300
2301 for (UINT32 index = 0; index < monitorCount; index++)
2302 {
2303 rdpMonitor* current = &settings->MonitorDefArray[index];
2304 Stream_Read_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
2305 Stream_Read_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
2306 Stream_Read_UINT32(s, current->attributes.orientation); /* orientation */
2307 Stream_Read_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
2308 Stream_Read_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
2309 }
2310
2311 return TRUE;
2312}
2313
2314BOOL gcc_write_client_monitor_extended_data(wStream* s, const rdpMcs* mcs)
2315{
2316 const rdpSettings* settings = mcs_get_const_settings(mcs);
2317
2318 WINPR_ASSERT(s);
2319 WINPR_ASSERT(settings);
2320
2321 if (settings->HasMonitorAttributes)
2322 {
2323 const size_t length = (20 * settings->MonitorCount) + 16;
2324 WINPR_ASSERT(length <= UINT16_MAX);
2325 if (!gcc_write_user_data_header(s, CS_MONITOR_EX, (UINT16)length))
2326 return FALSE;
2327 Stream_Write_UINT32(s, settings->MonitorAttributeFlags); /* flags */
2328 Stream_Write_UINT32(s, 20); /* monitorAttributeSize */
2329 Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
2330
2331 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2332 {
2333 const rdpMonitor* current = &settings->MonitorDefArray[i];
2334 Stream_Write_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
2335 Stream_Write_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
2336 Stream_Write_UINT32(s, current->attributes.orientation); /* orientation */
2337 Stream_Write_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
2338 Stream_Write_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
2339 }
2340 }
2341 return TRUE;
2342}
2343
2353BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs)
2354{
2355 WINPR_ASSERT(s);
2356 WINPR_ASSERT(mcs);
2357
2358 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2359 return FALSE;
2360
2361 Stream_Read_UINT32(s, mcs->flags);
2362 mcs->messageChannelId = mcs->baseChannelId++;
2363 return TRUE;
2364}
2365
2375BOOL gcc_write_client_message_channel_data(wStream* s, const rdpMcs* mcs)
2376{
2377 const rdpSettings* settings = mcs_get_const_settings(mcs);
2378
2379 WINPR_ASSERT(s);
2380 WINPR_ASSERT(mcs);
2381 WINPR_ASSERT(settings);
2382 if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ||
2383 settings->SupportHeartbeatPdu || settings->SupportMultitransport)
2384 {
2385 if (!gcc_write_user_data_header(s, CS_MCS_MSGCHANNEL, 8))
2386 return FALSE;
2387 Stream_Write_UINT32(s, mcs->flags); /* flags */
2388 }
2389 return TRUE;
2390}
2391
2392BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs)
2393{
2394 UINT16 MCSChannelId = 0;
2395 WINPR_ASSERT(s);
2396 WINPR_ASSERT(mcs);
2397 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
2398 return FALSE;
2399
2400 Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
2401 /* Save the MCS message channel id */
2402 mcs->messageChannelId = MCSChannelId;
2403 return TRUE;
2404}
2405
2406BOOL gcc_write_server_message_channel_data(wStream* s, const rdpMcs* mcs)
2407{
2408 WINPR_ASSERT(s);
2409 WINPR_ASSERT(mcs);
2410 if (mcs->messageChannelId == 0)
2411 return TRUE;
2412
2413 if (!gcc_write_user_data_header(s, SC_MCS_MSGCHANNEL, 6))
2414 return FALSE;
2415
2416 Stream_Write_UINT16(s, mcs->messageChannelId); /* mcsChannelId (2 bytes) */
2417 return TRUE;
2418}
2419
2429BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs)
2430{
2431 rdpSettings* settings = mcs_get_settings(mcs);
2432
2433 WINPR_ASSERT(s);
2434 WINPR_ASSERT(settings);
2435
2436 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2437 return FALSE;
2438
2439 UINT32 remoteFlags = 0;
2440 Stream_Read_UINT32(s, remoteFlags);
2441 settings->MultitransportFlags &= remoteFlags; /* merge local and remote flags */
2442 return TRUE;
2443}
2444
2455BOOL gcc_write_client_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
2456{
2457 const rdpSettings* settings = mcs_get_const_settings(mcs);
2458
2459 WINPR_ASSERT(s);
2460 WINPR_ASSERT(settings);
2461 if (!gcc_write_user_data_header(s, CS_MULTITRANSPORT, 8))
2462 return FALSE;
2463 Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags */
2464 return TRUE;
2465}
2466
2467BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs)
2468{
2469 rdpSettings* settings = mcs_get_settings(mcs);
2470 UINT32 remoteFlags = 0;
2471
2472 WINPR_ASSERT(s);
2473 WINPR_ASSERT(settings);
2474 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2475 return FALSE;
2476
2477 Stream_Read_UINT32(s, remoteFlags);
2478 settings->MultitransportFlags &= remoteFlags; /* merge with client setting */
2479 return TRUE;
2480}
2481
2482BOOL gcc_write_server_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
2483{
2484 const rdpSettings* settings = mcs_get_const_settings(mcs);
2485
2486 WINPR_ASSERT(s);
2487 WINPR_ASSERT(settings);
2488
2489 if (!gcc_write_user_data_header(s, SC_MULTITRANSPORT, 8))
2490 return FALSE;
2491
2492 Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags (4 bytes) */
2493 return TRUE;
2494}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_supported_color_depths_string(UINT16 mask, char *buffer, size_t size)
returns a string representation of RNS_UD_XXBPP_SUPPORT values
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.