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
125 rdpContext* context = transport_get_context(mcs->transport);
126 WINPR_ASSERT(context);
127
128 return context->settings;
129}
130
131static const rdpSettings* mcs_get_const_settings(const rdpMcs* mcs)
132{
133 WINPR_ASSERT(mcs);
134
135 const rdpContext* context = transport_get_context(mcs->transport);
136 WINPR_ASSERT(context);
137
138 return context->settings;
139}
140
141static char* rdp_early_server_caps_string(UINT32 flags, char* buffer, size_t size)
142{
143 char msg[32] = { 0 };
144 const UINT32 mask = RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
145 RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
146 const UINT32 unknown = flags & (~mask);
147
148 if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1)
149 winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1", buffer, size, "|");
150 if (flags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED)
151 winpr_str_append("RNS_UD_SC_DYNAMIC_DST_SUPPORTED", buffer, size, "|");
152 if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2)
153 winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2", buffer, size, "|");
154 if (flags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED)
155 winpr_str_append("RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED", buffer, size, "|");
156
157 if (unknown != 0)
158 {
159 (void)_snprintf(msg, sizeof(msg), "RNS_UD_SC_UNKNOWN[0x%08" PRIx32 "]", unknown);
160 winpr_str_append(msg, buffer, size, "|");
161 }
162 (void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
163 winpr_str_append(msg, buffer, size, "|");
164 return buffer;
165}
166
167static const char* rdp_early_client_caps_string(UINT32 flags, char* buffer, size_t size)
168{
169 char msg[32] = { 0 };
170 const UINT32 mask = RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
171 RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
172 RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
173 RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU |
174 RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
175 RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
176 RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
177 const UINT32 unknown = flags & (~mask);
178
179 if (flags & RNS_UD_CS_SUPPORT_ERRINFO_PDU)
180 winpr_str_append("RNS_UD_CS_SUPPORT_ERRINFO_PDU", buffer, size, "|");
181 if (flags & RNS_UD_CS_WANT_32BPP_SESSION)
182 winpr_str_append("RNS_UD_CS_WANT_32BPP_SESSION", buffer, size, "|");
183 if (flags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU)
184 winpr_str_append("RNS_UD_CS_SUPPORT_STATUSINFO_PDU", buffer, size, "|");
185 if (flags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS)
186 winpr_str_append("RNS_UD_CS_STRONG_ASYMMETRIC_KEYS", buffer, size, "|");
187 if (flags & RNS_UD_CS_RELATIVE_MOUSE_INPUT)
188 winpr_str_append("RNS_UD_CS_RELATIVE_MOUSE_INPUT", buffer, size, "|");
189 if (flags & RNS_UD_CS_VALID_CONNECTION_TYPE)
190 winpr_str_append("RNS_UD_CS_VALID_CONNECTION_TYPE", buffer, size, "|");
191 if (flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU)
192 winpr_str_append("RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU", buffer, size, "|");
193 if (flags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT)
194 winpr_str_append("RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT", buffer, size, "|");
195 if (flags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)
196 winpr_str_append("RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL", buffer, size, "|");
197 if (flags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE)
198 winpr_str_append("RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE", buffer, size, "|");
199 if (flags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU)
200 winpr_str_append("RNS_UD_CS_SUPPORT_HEARTBEAT_PDU", buffer, size, "|");
201 if (flags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN)
202 winpr_str_append("RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN", buffer, size, "|");
203
204 if (unknown != 0)
205 {
206 (void)_snprintf(msg, sizeof(msg), "RNS_UD_CS_UNKNOWN[0x%08" PRIx32 "]", unknown);
207 winpr_str_append(msg, buffer, size, "|");
208 }
209 (void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
210 winpr_str_append(msg, buffer, size, "|");
211 return buffer;
212}
213
214static DWORD rdp_version_common(wLog* log, DWORD serverVersion, DWORD clientVersion)
215{
216 DWORD version = MIN(serverVersion, clientVersion);
217
218 switch (version)
219 {
220 case RDP_VERSION_4:
221 case RDP_VERSION_5_PLUS:
222 case RDP_VERSION_10_0:
223 case RDP_VERSION_10_1:
224 case RDP_VERSION_10_2:
225 case RDP_VERSION_10_3:
226 case RDP_VERSION_10_4:
227 case RDP_VERSION_10_5:
228 case RDP_VERSION_10_6:
229 case RDP_VERSION_10_7:
230 case RDP_VERSION_10_8:
231 case RDP_VERSION_10_9:
232 case RDP_VERSION_10_10:
233 case RDP_VERSION_10_11:
234 case RDP_VERSION_10_12:
235 return version;
236
237 default:
238 WLog_Print(log, WLOG_ERROR,
239 "Invalid client [%" PRId32 "] and server [%" PRId32 "] 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] = "Duca";
347static const BYTE h221_sc_key[4] = "McDn";
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 = { 0 };
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] = { 0 };
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] = { 0 };
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] = { 0 };
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 = NULL;
818
819 WINPR_ASSERT(s);
820 WINPR_ASSERT(mcs);
821
822 while (offset < length)
823 {
824 char buffer[64] = { 0 };
825 size_t rest = 0;
826 wStream subbuffer;
827 wStream* sub = NULL;
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 if ((*length < 4) || (!Stream_CheckAndLogRequiredLengthWLog(log, s, (size_t)(*length - 4))))
944 return FALSE;
945
946 return TRUE;
947}
948
960BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length)
961{
962
963 WINPR_ASSERT(s);
964 if (!Stream_EnsureRemainingCapacity(s, 4 + length))
965 return FALSE;
966 Stream_Write_UINT16(s, type); /* type */
967 Stream_Write_UINT16(s, length); /* length */
968 return TRUE;
969}
970
971static UINT32 filterAndLogEarlyServerCapabilityFlags(wLog* log, UINT32 flags)
972{
973 const UINT32 mask =
974 (RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
975 RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED);
976 const UINT32 filtered = flags & mask;
977 const UINT32 unknown = flags & (~mask);
978 if (unknown != 0)
979 {
980 char buffer[256] = { 0 };
981 WLog_Print(log, WLOG_WARN,
982 "TS_UD_SC_CORE::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
983 " --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
984 flags, ~mask, unknown,
985 rdp_early_server_caps_string(unknown, buffer, sizeof(buffer)));
986 }
987 return filtered;
988}
989
990static UINT32 earlyServerCapsFromSettings(wLog* log, const rdpSettings* settings)
991{
992 UINT32 EarlyCapabilityFlags = 0;
993
994 if (settings->SupportEdgeActionV1)
995 EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1;
996 if (settings->SupportDynamicTimeZone)
997 EarlyCapabilityFlags |= RNS_UD_SC_DYNAMIC_DST_SUPPORTED;
998 if (settings->SupportEdgeActionV2)
999 EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2;
1000 if (settings->SupportSkipChannelJoin)
1001 EarlyCapabilityFlags |= RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
1002
1003 return filterAndLogEarlyServerCapabilityFlags(log, EarlyCapabilityFlags);
1004}
1005
1006static UINT16 filterAndLogEarlyClientCapabilityFlags(wLog* log, UINT32 flags)
1007{
1008 const UINT32 mask =
1009 (RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
1010 RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
1011 RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
1012 RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
1013 RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
1014 RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN);
1015 const UINT32 filtered = flags & mask;
1016 const UINT32 unknown = flags & ~mask;
1017 if (unknown != 0)
1018 {
1019 char buffer[256] = { 0 };
1020 WLog_Print(log, WLOG_WARN,
1021 "(TS_UD_CS_CORE)::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
1022 " --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
1023 flags, ~mask, unknown,
1024 rdp_early_client_caps_string(unknown, buffer, sizeof(buffer)));
1025 }
1026
1027 WINPR_ASSERT(filtered <= UINT16_MAX);
1028 return (UINT16)filtered;
1029}
1030
1031static UINT16 earlyClientCapsFromSettings(wLog* log, const rdpSettings* settings)
1032{
1033 UINT32 earlyCapabilityFlags = 0;
1034
1035 WINPR_ASSERT(settings);
1036 if (settings->SupportErrorInfoPdu)
1037 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_ERRINFO_PDU;
1038
1039 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 32)
1040 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
1041
1042 if (settings->SupportStatusInfoPdu)
1043 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_STATUSINFO_PDU;
1044
1045 if (settings->ConnectionType)
1046 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
1047
1048 if (settings->SupportMonitorLayoutPdu)
1049 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU;
1050
1051 if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
1052 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT;
1053
1054 if (settings->SupportGraphicsPipeline)
1055 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL;
1056
1057 if (settings->SupportDynamicTimeZone)
1058 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE;
1059
1060 if (settings->SupportHeartbeatPdu)
1061 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_HEARTBEAT_PDU;
1062
1063 if (settings->SupportAsymetricKeys)
1064 earlyCapabilityFlags |= RNS_UD_CS_STRONG_ASYMMETRIC_KEYS;
1065
1066 if (settings->HasRelativeMouseEvent)
1067 earlyCapabilityFlags |= RNS_UD_CS_RELATIVE_MOUSE_INPUT;
1068
1069 if (settings->SupportSkipChannelJoin)
1070 earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
1071
1072 return filterAndLogEarlyClientCapabilityFlags(log, earlyCapabilityFlags);
1073}
1074
1075static BOOL updateEarlyClientCaps(wLog* log, rdpSettings* settings, UINT32 earlyCapabilityFlags,
1076 UINT32 connectionType)
1077{
1078 WINPR_ASSERT(settings);
1079
1080 if (settings->SupportErrorInfoPdu)
1081 settings->SupportErrorInfoPdu =
1082 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU) ? TRUE : FALSE;
1083
1084 /* RNS_UD_CS_WANT_32BPP_SESSION is already handled in gcc_read_client_core_data:
1085 *
1086 * it is evaluated in combination with highColorDepth and the server side
1087 * settings to determine the session color depth to use.
1088 */
1089
1090 if (settings->SupportStatusInfoPdu)
1091 settings->SupportStatusInfoPdu =
1092 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU) ? TRUE : FALSE;
1093
1094 if (settings->SupportAsymetricKeys)
1095 settings->SupportAsymetricKeys =
1096 (earlyCapabilityFlags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS) ? TRUE : FALSE;
1097
1098 if (settings->HasRelativeMouseEvent)
1099 {
1100 /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1101 * the flag must be ignored if the RDP version is < 0x00080011 */
1102 if (settings->RdpVersion >= RDP_VERSION_10_12)
1103 {
1104 settings->HasRelativeMouseEvent =
1105 (earlyCapabilityFlags & RNS_UD_CS_RELATIVE_MOUSE_INPUT) ? TRUE : FALSE;
1106 }
1107 else
1108 settings->HasRelativeMouseEvent = FALSE;
1109 }
1110
1111 if (settings->NetworkAutoDetect)
1112 settings->NetworkAutoDetect =
1113 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT) ? TRUE : FALSE;
1114
1115 if (settings->SupportSkipChannelJoin)
1116 settings->SupportSkipChannelJoin =
1117 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN) ? TRUE : FALSE;
1118
1119 if (settings->SupportMonitorLayoutPdu)
1120 settings->SupportMonitorLayoutPdu =
1121 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) ? TRUE : FALSE;
1122
1123 if (settings->SupportHeartbeatPdu)
1124 settings->SupportHeartbeatPdu =
1125 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE;
1126
1127 if (settings->SupportGraphicsPipeline)
1128 settings->SupportGraphicsPipeline =
1129 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE;
1130
1131 if (settings->SupportDynamicTimeZone)
1132 settings->SupportDynamicTimeZone =
1133 (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE;
1134
1135 if ((earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE) == 0)
1136 connectionType = 0;
1137 settings->ConnectionType = connectionType;
1138
1139 filterAndLogEarlyClientCapabilityFlags(log, earlyCapabilityFlags);
1140 return TRUE;
1141}
1142
1143static BOOL updateEarlyServerCaps(wLog* log, rdpSettings* settings, UINT32 earlyCapabilityFlags,
1144 WINPR_ATTR_UNUSED UINT32 connectionType)
1145{
1146 WINPR_ASSERT(settings);
1147
1148 settings->SupportEdgeActionV1 =
1149 settings->SupportEdgeActionV1 &&
1150 (earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1)
1151 ? TRUE
1152 : FALSE;
1153 settings->SupportDynamicTimeZone =
1154 settings->SupportDynamicTimeZone && (earlyCapabilityFlags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED)
1155 ? TRUE
1156 : FALSE;
1157 settings->SupportEdgeActionV2 =
1158 settings->SupportEdgeActionV2 &&
1159 (earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2)
1160 ? TRUE
1161 : FALSE;
1162 settings->SupportSkipChannelJoin =
1163 settings->SupportSkipChannelJoin &&
1164 (earlyCapabilityFlags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED)
1165 ? TRUE
1166 : FALSE;
1167
1168 filterAndLogEarlyServerCapabilityFlags(log, earlyCapabilityFlags);
1169 return TRUE;
1170}
1171
1181BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs)
1182{
1183 char buffer[2048] = { 0 };
1184 char strbuffer[130] = { 0 };
1185 UINT32 version = 0;
1186 BYTE connectionType = 0;
1187 UINT32 clientColorDepth = 0;
1188 UINT16 colorDepth = 0;
1189 UINT16 postBeta2ColorDepth = 0;
1190 UINT16 highColorDepth = 0;
1191 UINT32 serverSelectedProtocol = 0;
1192 rdpSettings* settings = mcs_get_settings(mcs);
1193
1194 WINPR_ASSERT(s);
1195 WINPR_ASSERT(settings);
1196
1197 /* Length of all required fields, until imeFileName */
1198 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 128))
1199 return FALSE;
1200
1201 Stream_Read_UINT32(s, version); /* version (4 bytes) */
1202 settings->RdpVersion = rdp_version_common(mcs->log, version, settings->RdpVersion);
1203 Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */
1204 Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
1205 Stream_Read_UINT16(s, colorDepth); /* ColorDepth (2 bytes) */
1206 Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
1207 Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
1208 Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */
1209
1210 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
1211 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 32 / sizeof(WCHAR), strbuffer,
1212 ARRAYSIZE(strbuffer)) < 0)
1213 {
1214 WLog_Print(mcs->log, WLOG_ERROR, "failed to convert client host name");
1215 return FALSE;
1216 }
1217
1218 if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, strbuffer))
1219 return FALSE;
1220
1221 Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */
1222 Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */
1223 Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */
1224 Stream_Seek(s, 64); /* imeFileName (64 bytes) */
1225
1233 do
1234 {
1235 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1236 break;
1237
1238 Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */
1239
1240 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1241 break;
1242
1243 const UINT16 clientProductId = Stream_Get_UINT16(s); /* clientProductID (2 bytes) */
1244
1245 /* [MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::clientProductId (optional)
1246 * should be initialized to 1
1247 */
1248 if (clientProductId != 1)
1249 {
1250 WLog_Print(mcs->log, WLOG_WARN,
1251 "[MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::clientProductId "
1252 "(optional) expected 1, got %" PRIu32,
1253 clientProductId);
1254 }
1255
1256 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1257 break;
1258
1259 const UINT32 serialNumber = Stream_Get_UINT32(s); /* serialNumber (4 bytes) */
1260
1261 /* [MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::serialNumber (optional)
1262 * should be initialized to 0
1263 */
1264 if (serialNumber != 0)
1265 {
1266 WLog_Print(mcs->log, WLOG_WARN,
1267 "[MS-RDPBCGR] 2.2.1.3.2 Client Core Data (TS_UD_CS_CORE)::serialNumber "
1268 "(optional) expected 0, got %" PRIu32,
1269 serialNumber);
1270 }
1271
1272 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1273 break;
1274
1275 Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */
1276
1277 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1278 break;
1279
1280 Stream_Read_UINT16(s, settings->SupportedColorDepths); /* supportedColorDepths (2 bytes) */
1281
1282 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1283 break;
1284
1285 Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
1286
1287 /* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */
1288 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 64))
1289 break;
1290
1291 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 64 / sizeof(WCHAR), strbuffer,
1292 ARRAYSIZE(strbuffer)) < 0)
1293 {
1294 WLog_Print(mcs->log, WLOG_ERROR, "failed to convert the client product identifier");
1295 return FALSE;
1296 }
1297
1298 if (!freerdp_settings_set_string(settings, FreeRDP_ClientProductId, strbuffer))
1299 return FALSE;
1300
1301 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1302 break;
1303
1304 Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */
1305
1306 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1307 break;
1308
1309 Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
1310
1311 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1312 break;
1313
1314 Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */
1315
1316 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1317 break;
1318
1319 Stream_Read_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
1320
1321 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1322 break;
1323
1324 Stream_Read_UINT32(s,
1325 settings->DesktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
1326
1327 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
1328 break;
1329
1330 Stream_Read_UINT16(s, settings->DesktopOrientation); /* desktopOrientation (2 bytes) */
1331
1332 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1333 break;
1334
1335 Stream_Read_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor (4 bytes) */
1336
1337 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1338 break;
1339
1340 Stream_Read_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor (4 bytes) */
1341
1342 if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
1343 settings->SelectedProtocol = serverSelectedProtocol;
1344 else if (settings->SelectedProtocol != serverSelectedProtocol)
1345 return FALSE;
1346 } while (0);
1347
1348 if (highColorDepth > 0)
1349 {
1350 if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
1351 clientColorDepth = 32;
1352 else
1353 clientColorDepth = highColorDepth;
1354 }
1355 else if (postBeta2ColorDepth > 0)
1356 {
1357 switch (postBeta2ColorDepth)
1358 {
1359 case RNS_UD_COLOR_4BPP:
1360 clientColorDepth = 4;
1361 break;
1362
1363 case RNS_UD_COLOR_8BPP:
1364 clientColorDepth = 8;
1365 break;
1366
1367 case RNS_UD_COLOR_16BPP_555:
1368 clientColorDepth = 15;
1369 break;
1370
1371 case RNS_UD_COLOR_16BPP_565:
1372 clientColorDepth = 16;
1373 break;
1374
1375 case RNS_UD_COLOR_24BPP:
1376 clientColorDepth = 24;
1377 break;
1378
1379 default:
1380 return FALSE;
1381 }
1382 }
1383 else
1384 {
1385 switch (colorDepth)
1386 {
1387 case RNS_UD_COLOR_4BPP:
1388 clientColorDepth = 4;
1389 break;
1390
1391 case RNS_UD_COLOR_8BPP:
1392 clientColorDepth = 8;
1393 break;
1394
1395 default:
1396 return FALSE;
1397 }
1398 }
1399
1400 /*
1401 * If we are in server mode, accept client's color depth only if
1402 * it is smaller than ours. This is what Windows server does.
1403 */
1404 if ((clientColorDepth < freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth)) ||
1405 !settings->ServerMode)
1406 {
1407 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, clientColorDepth))
1408 return FALSE;
1409 }
1410
1411 WLog_Print(
1412 mcs->log, WLOG_DEBUG, "Received EarlyCapabilityFlags=%s",
1413 rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
1414
1415 return updateEarlyClientCaps(mcs->log, settings, settings->EarlyCapabilityFlags,
1416 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(mcs->log, 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_Print(
1491 mcs->log, WLOG_DEBUG,
1492 "Sending highColorDepth=%s, supportedColorDepths=%s, earlyCapabilityFlags=%s",
1493 HighColorToString(highColorDepth),
1494 freerdp_supported_color_depths_string(SupportedColorDepths, dbuffer, sizeof(dbuffer)),
1495 rdp_early_client_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer)));
1496 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, highColorDepth)); /* highColorDepth */
1497 Stream_Write_UINT16(s, SupportedColorDepths); /* supportedColorDepths */
1498 Stream_Write_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
1499
1500 if (!Stream_EnsureRemainingCapacity(s, 64 + 24))
1501 return FALSE;
1502
1503 /* clientDigProductId (64 bytes, assume WCHAR, not \0 terminated */
1504 const char* str = freerdp_settings_get_string(settings, FreeRDP_ClientProductId);
1505 if (str)
1506 {
1507 if (Stream_Write_UTF16_String_From_UTF8(s, 32, str, strnlen(str, 32), TRUE) < 0)
1508 return FALSE;
1509 }
1510 else
1511 Stream_Zero(s, 32 * sizeof(WCHAR));
1512
1513 Stream_Write_UINT8(s, connectionType); /* connectionType */
1514 Stream_Write_UINT8(s, 0); /* pad1octet */
1515 Stream_Write_UINT32(s, settings->SelectedProtocol); /* serverSelectedProtocol */
1516 Stream_Write_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth */
1517 Stream_Write_UINT32(s, settings->DesktopPhysicalHeight); /* desktopPhysicalHeight */
1518 Stream_Write_UINT16(s, settings->DesktopOrientation); /* desktopOrientation */
1519 Stream_Write_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor */
1520 Stream_Write_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor */
1521 return TRUE;
1522}
1523
1524BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs)
1525{
1526 UINT32 serverVersion = 0;
1527 rdpSettings* settings = mcs_get_settings(mcs);
1528
1529 WINPR_ASSERT(s);
1530 WINPR_ASSERT(settings);
1531
1532 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1533 return FALSE;
1534
1535 Stream_Read_UINT32(s, serverVersion); /* version */
1536 settings->RdpVersion = rdp_version_common(mcs->log, serverVersion, settings->RdpVersion);
1537
1538 if (Stream_GetRemainingLength(s) >= 4)
1539 {
1540 Stream_Read_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */
1541 }
1542
1543 if (Stream_GetRemainingLength(s) >= 4)
1544 {
1545 char buffer[2048] = { 0 };
1546
1547 Stream_Read_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */
1548 WLog_Print(
1549 mcs->log, WLOG_DEBUG, "Received EarlyCapabilityFlags=%s",
1550 rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
1551 }
1552
1553 return updateEarlyServerCaps(mcs->log, settings, settings->EarlyCapabilityFlags,
1554 settings->ConnectionType);
1555}
1556
1557/* TODO: This function modifies rdpMcs
1558 * TODO: Split this out of this function
1559 */
1560BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs)
1561{
1562 const rdpSettings* settings = mcs_get_const_settings(mcs);
1563
1564 WINPR_ASSERT(s);
1565 WINPR_ASSERT(settings);
1566
1567 if (!gcc_write_user_data_header(s, SC_CORE, 16))
1568 return FALSE;
1569
1570 const UINT32 EarlyCapabilityFlags = earlyServerCapsFromSettings(mcs->log, settings);
1571 Stream_Write_UINT32(s, settings->RdpVersion); /* version (4 bytes) */
1572 Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */
1573 Stream_Write_UINT32(s, EarlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */
1574 return TRUE;
1575}
1576
1586BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs)
1587{
1588 rdpSettings* settings = mcs_get_settings(mcs);
1589
1590 WINPR_ASSERT(s);
1591 WINPR_ASSERT(settings);
1592
1593 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
1594 return FALSE;
1595
1596 if (settings->UseRdpSecurityLayer)
1597 {
1598 Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
1599
1600 if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
1601 Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
1602 else
1603 Stream_Seek(s, 4);
1604 }
1605 else
1606 {
1607 Stream_Seek(s, 8);
1608 }
1609
1610 return TRUE;
1611}
1612
1622BOOL gcc_write_client_security_data(wStream* s, const rdpMcs* mcs)
1623{
1624 const rdpSettings* settings = mcs_get_const_settings(mcs);
1625
1626 WINPR_ASSERT(s);
1627 WINPR_ASSERT(settings);
1628
1629 if (!gcc_write_user_data_header(s, CS_SECURITY, 12))
1630 return FALSE;
1631
1632 if (settings->UseRdpSecurityLayer)
1633 {
1634 Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
1635 Stream_Write_UINT32(s, 0); /* extEncryptionMethods */
1636 }
1637 else
1638 {
1639 /* French locale, disable encryption */
1640 Stream_Write_UINT32(s, 0); /* encryptionMethods */
1641 Stream_Write_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
1642 }
1643 return TRUE;
1644}
1645
1646BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
1647{
1648 BOOL validCryptoConfig = FALSE;
1649 UINT32 EncryptionMethod = 0;
1650 UINT32 EncryptionLevel = 0;
1651 rdpSettings* settings = mcs_get_settings(mcs);
1652
1653 WINPR_ASSERT(s);
1654 WINPR_ASSERT(settings);
1655
1656 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
1657 return FALSE;
1658
1659 Stream_Read_UINT32(s, EncryptionMethod); /* encryptionMethod */
1660 Stream_Read_UINT32(s, EncryptionLevel); /* encryptionLevel */
1661
1662 /* Only accept valid/known encryption methods */
1663 switch (EncryptionMethod)
1664 {
1665 case ENCRYPTION_METHOD_NONE:
1666 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: NONE");
1667 break;
1668
1669 case ENCRYPTION_METHOD_40BIT:
1670 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 40BIT");
1671 break;
1672
1673 case ENCRYPTION_METHOD_56BIT:
1674 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 56BIT");
1675 break;
1676
1677 case ENCRYPTION_METHOD_128BIT:
1678 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: 128BIT");
1679 break;
1680
1681 case ENCRYPTION_METHOD_FIPS:
1682 WLog_Print(mcs->log, WLOG_DEBUG, "Server rdp encryption method: FIPS");
1683 break;
1684
1685 default:
1686 WLog_Print(mcs->log, WLOG_ERROR, "Received unknown encryption method %08" PRIX32 "",
1687 EncryptionMethod);
1688 return FALSE;
1689 }
1690
1691 if (settings->UseRdpSecurityLayer && !(settings->EncryptionMethods & EncryptionMethod))
1692 {
1693 WLog_Print(mcs->log, WLOG_WARN,
1694 "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_Print(mcs->log, WLOG_ERROR, "Received unknown encryption level 0x%08" PRIX32 "",
1735 settings->EncryptionLevel);
1736 }
1737
1738 if (!validCryptoConfig)
1739 {
1740 WLog_Print(mcs->log, WLOG_ERROR,
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_CheckAndLogRequiredLengthWLog(mcs->log, 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_Print(mcs->log, WLOG_ERROR,
1763 "Invalid ServerRandom (length=%" PRIu32 ") or ServerCertificate (length=%" PRIu32
1764 ")",
1765 settings->ServerRandomLength, settings->ServerCertificateLength);
1766 return FALSE;
1767 }
1768
1769 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, 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_CheckAndLogRequiredLengthWLog(mcs->log, 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 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1880 return FALSE;
1881
1882 Stream_Read_UINT32(s, mcs->channelCount); /* channelCount */
1883
1884 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, mcs->channelCount, 12ull))
1885 return FALSE;
1886
1887 if (mcs->channelCount > CHANNEL_MAX_COUNT)
1888 {
1889 WLog_Print(mcs->log, WLOG_ERROR, "rdpMcs::channelCount %" PRIu32 " > maximum %" PRIu32,
1890 mcs->channelCount, CHANNEL_MAX_COUNT);
1891 return FALSE;
1892 }
1893
1894 /* channelDefArray */
1895 for (UINT32 i = 0; i < mcs->channelCount; i++)
1896 {
1903 rdpMcsChannel* channel = &mcs->channels[i];
1904 Stream_Read(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
1905
1906 if (!memchr(channel->Name, 0, CHANNEL_NAME_LEN + 1))
1907 {
1908 WLog_Print(
1909 mcs->log, WLOG_ERROR,
1910 "protocol violation: received a static channel name with missing null-termination");
1911 return FALSE;
1912 }
1913
1914 Stream_Read_UINT32(s, channel->options); /* options (4 bytes) */
1915 channel->ChannelId = mcs->baseChannelId++;
1916 }
1917
1918 return TRUE;
1919}
1920
1930BOOL gcc_write_client_network_data(wStream* s, const rdpMcs* mcs)
1931{
1932 WINPR_ASSERT(s);
1933 WINPR_ASSERT(mcs);
1934 if (mcs->channelCount > 0)
1935 {
1936 const size_t length = mcs->channelCount * 12 + 8;
1937 WINPR_ASSERT(length <= UINT16_MAX);
1938 if (!gcc_write_user_data_header(s, CS_NET, (UINT16)length))
1939 return FALSE;
1940 Stream_Write_UINT32(s, mcs->channelCount); /* channelCount */
1941
1942 /* channelDefArray */
1943 for (UINT32 i = 0; i < mcs->channelCount; i++)
1944 {
1945 /* CHANNEL_DEF */
1946 rdpMcsChannel* channel = &mcs->channels[i];
1947 Stream_Write(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
1948 Stream_Write_UINT32(s, channel->options); /* options (4 bytes) */
1949 }
1950 }
1951 return TRUE;
1952}
1953
1954BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs)
1955{
1956 UINT16 channelId = 0;
1957 UINT32 parsedChannelCount = 0;
1958 WINPR_ASSERT(s);
1959 WINPR_ASSERT(mcs);
1960 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
1961 return FALSE;
1962
1963 mcs->IOChannelId = Stream_Get_UINT16(s); /* MCSChannelId */
1964 const uint16_t channelCount = Stream_Get_UINT16(s); /* channelCount */
1965 parsedChannelCount = channelCount;
1966
1967 if (channelCount != mcs->channelCount)
1968 {
1969 WLog_Print(mcs->log, WLOG_ERROR, "requested %" PRIu32 " channels, got %" PRIu16 " instead",
1970 mcs->channelCount, channelCount);
1971
1972 /* we ensure that the response is not bigger than the request */
1973
1974 mcs->channelCount = channelCount;
1975 }
1976
1977 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, channelCount, 2ull))
1978 return FALSE;
1979
1980 if (mcs->channelMaxCount < parsedChannelCount)
1981 {
1982 WLog_Print(mcs->log, WLOG_ERROR,
1983 "requested %" PRIu32 " channels > channelMaxCount %" PRIu16, mcs->channelCount,
1984 mcs->channelMaxCount);
1985 return FALSE;
1986 }
1987
1988 for (UINT32 i = 0; i < parsedChannelCount; i++)
1989 {
1990 rdpMcsChannel* channel = &mcs->channels[i];
1991 Stream_Read_UINT16(s, channelId); /* channelId */
1992 channel->ChannelId = channelId;
1993 }
1994
1995 if (channelCount % 2 == 1)
1996 return Stream_SafeSeek(s, 2); /* padding */
1997
1998 return TRUE;
1999}
2000
2001BOOL gcc_write_server_network_data(wStream* s, const rdpMcs* mcs)
2002{
2003 WINPR_ASSERT(s);
2004 WINPR_ASSERT(mcs);
2005 const size_t payloadLen = 8 + mcs->channelCount * 2 + (mcs->channelCount % 2 == 1 ? 2 : 0);
2006
2007 WINPR_ASSERT(payloadLen <= UINT16_MAX);
2008 if (!gcc_write_user_data_header(s, SC_NET, (UINT16)payloadLen))
2009 return FALSE;
2010
2011 Stream_Write_UINT16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
2012 Stream_Write_UINT16(s,
2013 WINPR_ASSERTING_INT_CAST(uint16_t, mcs->channelCount)); /* channelCount */
2014
2015 for (UINT32 i = 0; i < mcs->channelCount; i++)
2016 {
2017 const rdpMcsChannel* channel = &mcs->channels[i];
2018 Stream_Write_UINT16(s, channel->ChannelId);
2019 }
2020
2021 if (mcs->channelCount % 2 == 1)
2022 Stream_Write_UINT16(s, 0);
2023
2024 return TRUE;
2025}
2026
2036BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs)
2037{
2038 char buffer[128] = { 0 };
2039 UINT32 redirectedSessionId = 0;
2040 rdpSettings* settings = mcs_get_settings(mcs);
2041
2042 WINPR_ASSERT(s);
2043 WINPR_ASSERT(settings);
2044
2045 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
2046 return FALSE;
2047
2048 Stream_Read_UINT32(s, settings->ClusterInfoFlags); /* flags */
2049 Stream_Read_UINT32(s, redirectedSessionId); /* redirectedSessionId */
2050
2051 WLog_Print(mcs->log, WLOG_TRACE, "read ClusterInfoFlags=%s, RedirectedSessionId=0x%08" PRIx32,
2052 rdp_cluster_info_flags_to_string(settings->ClusterInfoFlags, buffer, sizeof(buffer)),
2053 redirectedSessionId);
2054 if (settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID)
2055 settings->RedirectedSessionId = redirectedSessionId;
2056
2057 settings->ConsoleSession =
2058 (settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID) ? TRUE : FALSE;
2059 settings->RedirectSmartCards =
2060 (settings->ClusterInfoFlags & REDIRECTED_SMARTCARD) ? TRUE : FALSE;
2061
2062 if (Stream_GetRemainingLength(s) > 0)
2063 {
2064 /* The old Microsoft Mac RDP client can send a pad here */
2065 Stream_Seek(s, Stream_GetRemainingLength(s));
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_Print(mcs->log, WLOG_TRACE, "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 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 8))
2135 return FALSE;
2136
2137 Stream_Read_UINT32(s, settings->MonitorFlags); /* flags */
2138 Stream_Read_UINT32(s, monitorCount); /* monitorCount */
2139
2140 /* 2.2.1.3.6 Client Monitor Data -
2141 * monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display
2142 * monitor definitions in the monitorDefArray field (the maximum allowed is 16).
2143 */
2144 if (monitorCount > 16)
2145 {
2146 WLog_Print(mcs->log, WLOG_ERROR, "announced monitors(%" PRIu32 ") exceed the 16 limit",
2147 monitorCount);
2148 return FALSE;
2149 }
2150
2151 if (monitorCount > settings->MonitorDefArraySize)
2152 {
2153 WLog_Print(mcs->log, WLOG_ERROR,
2154 "too many announced monitors(%" PRIu32 "), clamping to %" PRIu32 "",
2155 monitorCount, settings->MonitorDefArraySize);
2156 monitorCount = settings->MonitorDefArraySize;
2157 }
2158
2159 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(mcs->log, s, monitorCount, 20))
2160 return FALSE;
2161
2162 settings->MonitorCount = monitorCount;
2163
2164 for (UINT32 index = 0; index < monitorCount; index++)
2165 {
2166 rdpMonitor* current = &settings->MonitorDefArray[index];
2167
2168 const INT32 left = Stream_Get_INT32(s); /* left */
2169 const INT32 top = Stream_Get_INT32(s); /* top */
2170 const INT32 right = Stream_Get_INT32(s); /* right */
2171 const INT32 bottom = Stream_Get_INT32(s); /* bottom */
2172 const UINT32 flags = Stream_Get_UINT32(s); /* flags */
2173
2174 if ((left > right) || (top > bottom))
2175 {
2176 WLog_Print(mcs->log, WLOG_ERROR, "rdpMonitor::rect %dx%d-%dx%d invalid", left, top,
2177 right, bottom);
2178 return FALSE;
2179 }
2180
2181 const INT64 w = right - left;
2182 const INT64 h = bottom - top;
2183 if ((w >= INT32_MAX) || (h >= INT32_MAX) || (w < 0) || (h < 0))
2184 {
2185 WLog_Print(mcs->log, WLOG_ERROR,
2186 "rdpMonitor::width/height %" PRId64 "/%" PRId64 " invalid", w, h);
2187 return FALSE;
2188 }
2189
2190 current->x = left;
2191 current->y = top;
2192 current->width = WINPR_ASSERTING_INT_CAST(int32_t, w + 1);
2193 current->height = WINPR_ASSERTING_INT_CAST(int32_t, h + 1);
2194 current->is_primary = (flags & MONITOR_PRIMARY) ? TRUE : FALSE;
2195 }
2196
2197 return TRUE;
2198}
2199
2209BOOL gcc_write_client_monitor_data(wStream* s, const rdpMcs* mcs)
2210{
2211 INT32 baseX = 0;
2212 INT32 baseY = 0;
2213 const rdpSettings* settings = mcs_get_const_settings(mcs);
2214
2215 WINPR_ASSERT(s);
2216 WINPR_ASSERT(settings);
2217
2218 WLog_Print(mcs->log, WLOG_DEBUG, "MonitorCount=%" PRIu32, settings->MonitorCount);
2219 if (settings->MonitorCount > 1)
2220 {
2221 const size_t len = (20 * settings->MonitorCount) + 12;
2222 WINPR_ASSERT(len <= UINT16_MAX);
2223 const UINT16 length = (UINT16)len;
2224 if (!gcc_write_user_data_header(s, CS_MONITOR, length))
2225 return FALSE;
2226 Stream_Write_UINT32(s, settings->MonitorFlags); /* flags */
2227 Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
2228
2229 /* first pass to get the primary monitor coordinates (it is supposed to be
2230 * in (0,0) */
2231 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2232 {
2233 const rdpMonitor* current = &settings->MonitorDefArray[i];
2234 if (current->is_primary)
2235 {
2236 baseX = current->x;
2237 baseY = current->y;
2238 break;
2239 }
2240 }
2241
2242 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2243 {
2244 const rdpMonitor* current = &settings->MonitorDefArray[i];
2245 const INT32 left = current->x - baseX;
2246 const INT32 top = current->y - baseY;
2247 const INT32 right = left + current->width - 1;
2248 const INT32 bottom = top + current->height - 1;
2249 const UINT32 flags = current->is_primary ? MONITOR_PRIMARY : 0;
2250 WLog_Print(mcs->log, WLOG_DEBUG,
2251 "Monitor[%" PRIu32 "]: top=%" PRId32 ", left=%" PRId32 ", bottom=%" PRId32
2252 ", right=%" PRId32 ", flags=%" PRIu32,
2253 i, top, left, bottom, right, flags);
2254 Stream_Write_INT32(s, left); /* left */
2255 Stream_Write_INT32(s, top); /* top */
2256 Stream_Write_INT32(s, right); /* right */
2257 Stream_Write_INT32(s, bottom); /* bottom */
2258 Stream_Write_UINT32(s, flags); /* flags */
2259 }
2260 }
2261 WLog_Print(mcs->log, WLOG_DEBUG, "FINISHED");
2262 return TRUE;
2263}
2264
2265BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs)
2266{
2267 UINT32 monitorCount = 0;
2268 UINT32 monitorAttributeSize = 0;
2269 rdpSettings* settings = mcs_get_settings(mcs);
2270
2271 WINPR_ASSERT(s);
2272 WINPR_ASSERT(settings);
2273
2274 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 12))
2275 return FALSE;
2276
2277 Stream_Read_UINT32(s, settings->MonitorAttributeFlags); /* flags */
2278 Stream_Read_UINT32(s, monitorAttributeSize); /* monitorAttributeSize */
2279 Stream_Read_UINT32(s, monitorCount); /* monitorCount */
2280
2281 if (monitorAttributeSize != 20)
2282 {
2283 WLog_Print(mcs->log, WLOG_ERROR,
2284 "TS_UD_CS_MONITOR_EX::monitorAttributeSize %" PRIu32 " != 20",
2285 monitorAttributeSize);
2286 return FALSE;
2287 }
2288
2289 if (!Stream_CheckAndLogRequiredCapacityOfSizeWLog(mcs->log, s, monitorCount,
2290 monitorAttributeSize))
2291 return FALSE;
2292
2293 if (settings->MonitorCount != monitorCount)
2294 {
2295 WLog_Print(mcs->log, WLOG_ERROR,
2296 "(TS_UD_CS_MONITOR_EX)::monitorCount %" PRIu32 " != expected %" PRIu32,
2297 monitorCount, settings->MonitorCount);
2298 return FALSE;
2299 }
2300
2301 settings->HasMonitorAttributes = TRUE;
2302
2303 for (UINT32 index = 0; index < monitorCount; index++)
2304 {
2305 rdpMonitor* current = &settings->MonitorDefArray[index];
2306 Stream_Read_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
2307 Stream_Read_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
2308 Stream_Read_UINT32(s, current->attributes.orientation); /* orientation */
2309 Stream_Read_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
2310 Stream_Read_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
2311 }
2312
2313 return TRUE;
2314}
2315
2316BOOL gcc_write_client_monitor_extended_data(wStream* s, const rdpMcs* mcs)
2317{
2318 const rdpSettings* settings = mcs_get_const_settings(mcs);
2319
2320 WINPR_ASSERT(s);
2321 WINPR_ASSERT(settings);
2322
2323 if (settings->HasMonitorAttributes)
2324 {
2325 const size_t length = (20 * settings->MonitorCount) + 16;
2326 WINPR_ASSERT(length <= UINT16_MAX);
2327 if (!gcc_write_user_data_header(s, CS_MONITOR_EX, (UINT16)length))
2328 return FALSE;
2329 Stream_Write_UINT32(s, settings->MonitorAttributeFlags); /* flags */
2330 Stream_Write_UINT32(s, 20); /* monitorAttributeSize */
2331 Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
2332
2333 for (UINT32 i = 0; i < settings->MonitorCount; i++)
2334 {
2335 const rdpMonitor* current = &settings->MonitorDefArray[i];
2336 Stream_Write_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
2337 Stream_Write_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
2338 Stream_Write_UINT32(s, current->attributes.orientation); /* orientation */
2339 Stream_Write_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
2340 Stream_Write_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
2341 }
2342 }
2343 return TRUE;
2344}
2345
2355BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs)
2356{
2357 WINPR_ASSERT(s);
2358 WINPR_ASSERT(mcs);
2359
2360 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2361 return FALSE;
2362
2363 Stream_Read_UINT32(s, mcs->flags);
2364 mcs->messageChannelId = mcs->baseChannelId++;
2365 return TRUE;
2366}
2367
2377BOOL gcc_write_client_message_channel_data(wStream* s, const rdpMcs* mcs)
2378{
2379 const rdpSettings* settings = mcs_get_const_settings(mcs);
2380
2381 WINPR_ASSERT(s);
2382 WINPR_ASSERT(mcs);
2383 WINPR_ASSERT(settings);
2384 if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ||
2385 settings->SupportHeartbeatPdu || settings->SupportMultitransport)
2386 {
2387 if (!gcc_write_user_data_header(s, CS_MCS_MSGCHANNEL, 8))
2388 return FALSE;
2389 Stream_Write_UINT32(s, mcs->flags); /* flags */
2390 }
2391 return TRUE;
2392}
2393
2394BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs)
2395{
2396 UINT16 MCSChannelId = 0;
2397 WINPR_ASSERT(s);
2398 WINPR_ASSERT(mcs);
2399 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 2))
2400 return FALSE;
2401
2402 Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
2403 /* Save the MCS message channel id */
2404 mcs->messageChannelId = MCSChannelId;
2405 return TRUE;
2406}
2407
2408BOOL gcc_write_server_message_channel_data(wStream* s, const rdpMcs* mcs)
2409{
2410 WINPR_ASSERT(s);
2411 WINPR_ASSERT(mcs);
2412 if (mcs->messageChannelId == 0)
2413 return TRUE;
2414
2415 if (!gcc_write_user_data_header(s, SC_MCS_MSGCHANNEL, 6))
2416 return FALSE;
2417
2418 Stream_Write_UINT16(s, mcs->messageChannelId); /* mcsChannelId (2 bytes) */
2419 return TRUE;
2420}
2421
2431BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs)
2432{
2433 rdpSettings* settings = mcs_get_settings(mcs);
2434
2435 WINPR_ASSERT(s);
2436 WINPR_ASSERT(settings);
2437
2438 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2439 return FALSE;
2440
2441 UINT32 remoteFlags = 0;
2442 Stream_Read_UINT32(s, remoteFlags);
2443 settings->MultitransportFlags &= remoteFlags; /* merge local and remote flags */
2444 return TRUE;
2445}
2446
2457BOOL gcc_write_client_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
2458{
2459 const rdpSettings* settings = mcs_get_const_settings(mcs);
2460
2461 WINPR_ASSERT(s);
2462 WINPR_ASSERT(settings);
2463 if (!gcc_write_user_data_header(s, CS_MULTITRANSPORT, 8))
2464 return FALSE;
2465 Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags */
2466 return TRUE;
2467}
2468
2469BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs)
2470{
2471 rdpSettings* settings = mcs_get_settings(mcs);
2472 UINT32 remoteFlags = 0;
2473
2474 WINPR_ASSERT(s);
2475 WINPR_ASSERT(settings);
2476 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 4))
2477 return FALSE;
2478
2479 Stream_Read_UINT32(s, remoteFlags);
2480 settings->MultitransportFlags &= remoteFlags; /* merge with client setting */
2481 return TRUE;
2482}
2483
2484BOOL gcc_write_server_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
2485{
2486 const rdpSettings* settings = mcs_get_const_settings(mcs);
2487
2488 WINPR_ASSERT(s);
2489 WINPR_ASSERT(settings);
2490
2491 if (!gcc_write_user_data_header(s, SC_MULTITRANSPORT, 8))
2492 return FALSE;
2493
2494 Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags (4 bytes) */
2495 return TRUE;
2496}
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 const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.