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