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