FreeRDP
Loading...
Searching...
No Matches
mcs.c
1
24#include <freerdp/config.h>
25
26#include <winpr/crt.h>
27#include <winpr/assert.h>
28#include <freerdp/log.h>
29
30#include "gcc.h"
31
32#include "mcs.h"
33#include "tpdu.h"
34#include "tpkt.h"
35#include "client.h"
36#include "connection.h"
37
38#define MCS_TAG FREERDP_TAG("core")
39
169static const BYTE callingDomainSelector[1] = { 0x01 };
170static const BYTE calledDomainSelector[1] = { 0x01 };
171
172/*
173static const char* const mcs_result_enumerated[] =
174{
175 "rt-successful",
176 "rt-domain-merging",
177 "rt-domain-not-hierarchical",
178 "rt-no-such-channel",
179 "rt-no-such-domain",
180 "rt-no-such-user",
181 "rt-not-admitted",
182 "rt-other-user-id",
183 "rt-parameters-unacceptable",
184 "rt-token-not-available",
185 "rt-token-not-possessed",
186 "rt-too-many-channels",
187 "rt-too-many-tokens",
188 "rt-too-many-users",
189 "rt-unspecified-failure",
190 "rt-user-rejected"
191};
192*/
193
194const char* mcs_domain_pdu_string(DomainMCSPDU pdu)
195{
196 switch (pdu)
197 {
198 case DomainMCSPDU_PlumbDomainIndication:
199 return "DomainMCSPDU_PlumbDomainIndication";
200 case DomainMCSPDU_ErectDomainRequest:
201 return "DomainMCSPDU_ErectDomainRequest";
202 case DomainMCSPDU_MergeChannelsRequest:
203 return "DomainMCSPDU_MergeChannelsRequest";
204 case DomainMCSPDU_MergeChannelsConfirm:
205 return "DomainMCSPDU_MergeChannelsConfirm";
206 case DomainMCSPDU_PurgeChannelsIndication:
207 return "DomainMCSPDU_PurgeChannelsIndication";
208 case DomainMCSPDU_MergeTokensRequest:
209 return "DomainMCSPDU_MergeTokensRequest";
210 case DomainMCSPDU_MergeTokensConfirm:
211 return "DomainMCSPDU_MergeTokensConfirm";
212 case DomainMCSPDU_PurgeTokensIndication:
213 return "DomainMCSPDU_PurgeTokensIndication";
214 case DomainMCSPDU_DisconnectProviderUltimatum:
215 return "DomainMCSPDU_DisconnectProviderUltimatum";
216 case DomainMCSPDU_RejectMCSPDUUltimatum:
217 return "DomainMCSPDU_RejectMCSPDUUltimatum";
218 case DomainMCSPDU_AttachUserRequest:
219 return "DomainMCSPDU_AttachUserRequest";
220 case DomainMCSPDU_AttachUserConfirm:
221 return "DomainMCSPDU_AttachUserConfirm";
222 case DomainMCSPDU_DetachUserRequest:
223 return "DomainMCSPDU_DetachUserRequest";
224 case DomainMCSPDU_DetachUserIndication:
225 return "DomainMCSPDU_DetachUserIndication";
226 case DomainMCSPDU_ChannelJoinRequest:
227 return "DomainMCSPDU_ChannelJoinRequest";
228 case DomainMCSPDU_ChannelJoinConfirm:
229 return "DomainMCSPDU_ChannelJoinConfirm";
230 case DomainMCSPDU_ChannelLeaveRequest:
231 return "DomainMCSPDU_ChannelLeaveRequest";
232 case DomainMCSPDU_ChannelConveneRequest:
233 return "DomainMCSPDU_ChannelConveneRequest";
234 case DomainMCSPDU_ChannelConveneConfirm:
235 return "DomainMCSPDU_ChannelConveneConfirm";
236 case DomainMCSPDU_ChannelDisbandRequest:
237 return "DomainMCSPDU_ChannelDisbandRequest";
238 case DomainMCSPDU_ChannelDisbandIndication:
239 return "DomainMCSPDU_ChannelDisbandIndication";
240 case DomainMCSPDU_ChannelAdmitRequest:
241 return "DomainMCSPDU_ChannelAdmitRequest";
242 case DomainMCSPDU_ChannelAdmitIndication:
243 return "DomainMCSPDU_ChannelAdmitIndication";
244 case DomainMCSPDU_ChannelExpelRequest:
245 return "DomainMCSPDU_ChannelExpelRequest";
246 case DomainMCSPDU_ChannelExpelIndication:
247 return "DomainMCSPDU_ChannelExpelIndication";
248 case DomainMCSPDU_SendDataRequest:
249 return "DomainMCSPDU_SendDataRequest";
250 case DomainMCSPDU_SendDataIndication:
251 return "DomainMCSPDU_SendDataIndication";
252 case DomainMCSPDU_UniformSendDataRequest:
253 return "DomainMCSPDU_UniformSendDataRequest";
254 case DomainMCSPDU_UniformSendDataIndication:
255 return "DomainMCSPDU_UniformSendDataIndication";
256 case DomainMCSPDU_TokenGrabRequest:
257 return "DomainMCSPDU_TokenGrabRequest";
258 case DomainMCSPDU_TokenGrabConfirm:
259 return "DomainMCSPDU_TokenGrabConfirm";
260 case DomainMCSPDU_TokenInhibitRequest:
261 return "DomainMCSPDU_TokenInhibitRequest";
262 case DomainMCSPDU_TokenInhibitConfirm:
263 return "DomainMCSPDU_TokenInhibitConfirm";
264 case DomainMCSPDU_TokenGiveRequest:
265 return "DomainMCSPDU_TokenGiveRequest";
266 case DomainMCSPDU_TokenGiveIndication:
267 return "DomainMCSPDU_TokenGiveIndication";
268 case DomainMCSPDU_TokenGiveResponse:
269 return "DomainMCSPDU_TokenGiveResponse";
270 case DomainMCSPDU_TokenGiveConfirm:
271 return "DomainMCSPDU_TokenGiveConfirm";
272 case DomainMCSPDU_TokenPleaseRequest:
273 return "DomainMCSPDU_TokenPleaseRequest";
274 case DomainMCSPDU_TokenPleaseConfirm:
275 return "DomainMCSPDU_TokenPleaseConfirm";
276 case DomainMCSPDU_TokenReleaseRequest:
277 return "DomainMCSPDU_TokenReleaseRequest";
278 case DomainMCSPDU_TokenReleaseConfirm:
279 return "DomainMCSPDU_TokenReleaseConfirm";
280 case DomainMCSPDU_TokenTestRequest:
281 return "DomainMCSPDU_TokenTestRequest";
282 case DomainMCSPDU_TokenTestConfirm:
283 return "DomainMCSPDU_TokenTestConfirm";
284 case DomainMCSPDU_enum_length:
285 return "DomainMCSPDU_enum_length";
286 default:
287 return "DomainMCSPDU_UNKNOWN";
288 }
289}
290
291static BOOL mcs_merge_domain_parameters(wLog* log, DomainParameters* targetParameters,
292 DomainParameters* minimumParameters,
293 DomainParameters* maximumParameters,
294 DomainParameters* pOutParameters);
295
296static BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData);
297static BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData);
298static BOOL mcs_read_domain_mcspdu_header(wLog* log, wStream* s, DomainMCSPDU domainMCSPDU,
299 UINT16* length, DomainMCSPDU* actual);
300
301static int mcs_initialize_client_channels(rdpMcs* mcs, const rdpSettings* settings)
302{
303 if (!mcs || !settings)
304 return -1;
305
306 mcs->channelCount = freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount);
307
308 if (mcs->channelCount > mcs->channelMaxCount)
309 mcs->channelCount = mcs->channelMaxCount;
310
311 ZeroMemory(mcs->channels, sizeof(rdpMcsChannel) * mcs->channelMaxCount);
312
313 for (UINT32 index = 0; index < mcs->channelCount; index++)
314 {
315 const CHANNEL_DEF* defchannel =
316 freerdp_settings_get_pointer_array(settings, FreeRDP_ChannelDefArray, index);
317 rdpMcsChannel* cur = &mcs->channels[index];
318 WINPR_ASSERT(defchannel);
319 CopyMemory(cur->Name, defchannel->name, CHANNEL_NAME_LEN);
320 cur->options = defchannel->options;
321 }
322
323 return 0;
324}
325
335BOOL mcs_read_domain_mcspdu_header(wLog* log, wStream* s, DomainMCSPDU domainMCSPDU, UINT16* length,
336 DomainMCSPDU* actual)
337{
338 UINT16 li = 0;
339 BYTE choice = 0;
340
341 if (actual)
342 *actual = DomainMCSPDU_invalid;
343
344 WINPR_ASSERT(s);
345 WINPR_ASSERT(domainMCSPDU);
346 WINPR_ASSERT(length);
347
348 if (!tpkt_read_header(s, length))
349 return FALSE;
350
351 if (!tpdu_read_data(s, &li, *length))
352 return FALSE;
353
354 if (!per_read_choice(s, &choice))
355 return FALSE;
356
357 const BYTE val = choice >> 2;
358 const DomainMCSPDU MCSPDU =
359 (val > DomainMCSPDU_enum_length) ? DomainMCSPDU_invalid : (DomainMCSPDU)(val);
360 if (actual)
361 *actual = MCSPDU;
362
363 if (domainMCSPDU != MCSPDU)
364 {
365 WLog_Print(log, WLOG_ERROR, "Expected MCS %s, got %s", mcs_domain_pdu_string(domainMCSPDU),
366 mcs_domain_pdu_string(MCSPDU));
367 return FALSE;
368 }
369
370 return TRUE;
371}
372
380BOOL mcs_write_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU, UINT16 length,
381 BYTE options)
382{
383 WINPR_ASSERT(s);
384 WINPR_ASSERT((options & ~0x03) == 0);
385 WINPR_ASSERT((domainMCSPDU & ~0x3F) == 0);
386
387 if (!tpkt_write_header(s, length))
388 return FALSE;
389 if (!tpdu_write_data(s))
390 return FALSE;
391 return per_write_choice(s, (BYTE)((domainMCSPDU << 2) | options));
392}
393
403static BOOL mcs_init_domain_parameters(DomainParameters* domainParameters, UINT32 maxChannelIds,
404 UINT32 maxUserIds, UINT32 maxTokenIds, UINT32 maxMCSPDUsize)
405{
406 if (!domainParameters)
407 return FALSE;
408
409 domainParameters->maxChannelIds = maxChannelIds;
410 domainParameters->maxUserIds = maxUserIds;
411 domainParameters->maxTokenIds = maxTokenIds;
412 domainParameters->maxMCSPDUsize = maxMCSPDUsize;
413 domainParameters->numPriorities = 1;
414 domainParameters->minThroughput = 0;
415 domainParameters->maxHeight = 1;
416 domainParameters->protocolVersion = 2;
417 return TRUE;
418}
419
426static BOOL mcs_read_domain_parameters(wStream* s, DomainParameters* domainParameters)
427{
428 size_t length = 0;
429
430 if (!s || !domainParameters)
431 return FALSE;
432
433 return ber_read_sequence_tag(s, &length) &&
434 ber_read_integer(s, &(domainParameters->maxChannelIds)) &&
435 ber_read_integer(s, &(domainParameters->maxUserIds)) &&
436 ber_read_integer(s, &(domainParameters->maxTokenIds)) &&
437 ber_read_integer(s, &(domainParameters->numPriorities)) &&
438 ber_read_integer(s, &(domainParameters->minThroughput)) &&
439 ber_read_integer(s, &(domainParameters->maxHeight)) &&
440 ber_read_integer(s, &(domainParameters->maxMCSPDUsize)) &&
441 ber_read_integer(s, &(domainParameters->protocolVersion));
442}
443
450static BOOL mcs_write_domain_parameters(wLog* log, wStream* s, DomainParameters* domainParameters)
451{
452 BOOL rc = FALSE;
453 size_t length = 0;
454
455 if (!s || !domainParameters)
456 return FALSE;
457
458 wStream* tmps = Stream_New(nullptr, Stream_Capacity(s));
459
460 if (!tmps)
461 {
462 WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
463 return FALSE;
464 }
465
466 if (!ber_write_integer(tmps, domainParameters->maxChannelIds))
467 goto fail;
468 if (!ber_write_integer(tmps, domainParameters->maxUserIds))
469 goto fail;
470 if (!ber_write_integer(tmps, domainParameters->maxTokenIds))
471 goto fail;
472 if (!ber_write_integer(tmps, domainParameters->numPriorities))
473 goto fail;
474 if (!ber_write_integer(tmps, domainParameters->minThroughput))
475 goto fail;
476 if (!ber_write_integer(tmps, domainParameters->maxHeight))
477 goto fail;
478 if (!ber_write_integer(tmps, domainParameters->maxMCSPDUsize))
479 goto fail;
480 if (!ber_write_integer(tmps, domainParameters->protocolVersion))
481 goto fail;
482 length = Stream_GetPosition(tmps);
483 if (!ber_write_sequence_tag(s, length))
484 goto fail;
485 Stream_Write(s, Stream_Buffer(tmps), length);
486
487 rc = TRUE;
488fail:
489 Stream_Free(tmps, TRUE);
490 return rc;
491}
492
493#ifdef DEBUG_MCS
499static void mcs_print_domain_parameters(DomainParameters* domainParameters)
500{
501 WLog_INFO(TAG, "DomainParameters {");
502
503 if (domainParameters)
504 {
505 WLog_INFO(TAG, "\tmaxChannelIds:%" PRIu32 "", domainParameters->maxChannelIds);
506 WLog_INFO(TAG, "\tmaxUserIds:%" PRIu32 "", domainParameters->maxUserIds);
507 WLog_INFO(TAG, "\tmaxTokenIds:%" PRIu32 "", domainParameters->maxTokenIds);
508 WLog_INFO(TAG, "\tnumPriorities:%" PRIu32 "", domainParameters->numPriorities);
509 WLog_INFO(TAG, "\tminThroughput:%" PRIu32 "", domainParameters->minThroughput);
510 WLog_INFO(TAG, "\tmaxHeight:%" PRIu32 "", domainParameters->maxHeight);
511 WLog_INFO(TAG, "\tmaxMCSPDUsize:%" PRIu32 "", domainParameters->maxMCSPDUsize);
512 WLog_INFO(TAG, "\tprotocolVersion:%" PRIu32 "", domainParameters->protocolVersion);
513 }
514 else
515 WLog_INFO(TAG, "\tdomainParameters=%p", domainParameters);
516
517 WLog_INFO(TAG, "}");
518}
519#endif
520
531BOOL mcs_merge_domain_parameters(wLog* log, DomainParameters* targetParameters,
532 DomainParameters* minimumParameters,
533 DomainParameters* maximumParameters,
534 DomainParameters* pOutParameters)
535{
536 /* maxChannelIds */
537 if (!targetParameters || !minimumParameters || !maximumParameters || !pOutParameters)
538 return FALSE;
539
540 if (targetParameters->maxChannelIds >= 4)
541 {
542 pOutParameters->maxChannelIds = targetParameters->maxChannelIds;
543 }
544 else if (maximumParameters->maxChannelIds >= 4)
545 {
546 pOutParameters->maxChannelIds = 4;
547 }
548 else
549 {
550 WLog_Print(log, WLOG_ERROR, "invalid maxChannelIds [%" PRIu32 ", %" PRIu32 "]",
551 targetParameters->maxChannelIds, maximumParameters->maxChannelIds);
552 return FALSE;
553 }
554
555 /* maxUserIds */
556
557 if (targetParameters->maxUserIds >= 3)
558 {
559 pOutParameters->maxUserIds = targetParameters->maxUserIds;
560 }
561 else if (maximumParameters->maxUserIds >= 3)
562 {
563 pOutParameters->maxUserIds = 3;
564 }
565 else
566 {
567 WLog_Print(log, WLOG_ERROR, "invalid maxUserIds [%" PRIu32 ", %" PRIu32 "]",
568 targetParameters->maxUserIds, maximumParameters->maxUserIds);
569 return FALSE;
570 }
571
572 /* maxTokenIds */
573 pOutParameters->maxTokenIds = targetParameters->maxTokenIds;
574
575 /* numPriorities */
576
577 if (minimumParameters->numPriorities <= 1)
578 {
579 pOutParameters->numPriorities = 1;
580 }
581 else
582 {
583 WLog_Print(log, WLOG_ERROR, "invalid numPriorities [%" PRIu32 "]",
584 maximumParameters->numPriorities);
585 return FALSE;
586 }
587
588 /* minThroughput */
589 pOutParameters->minThroughput = targetParameters->minThroughput;
590
591 /* maxHeight */
592
593 if ((targetParameters->maxHeight == 1) || (minimumParameters->maxHeight <= 1))
594 {
595 pOutParameters->maxHeight = 1;
596 }
597 else
598 {
599 WLog_Print(log, WLOG_ERROR, "invalid maxHeight [%" PRIu32 ", %" PRIu32 "]",
600 targetParameters->maxHeight, minimumParameters->maxHeight);
601 return FALSE;
602 }
603
604 /* maxMCSPDUsize */
605
606 if (targetParameters->maxMCSPDUsize >= 1024)
607 {
608 if (targetParameters->maxMCSPDUsize <= 65528)
609 {
610 pOutParameters->maxMCSPDUsize = targetParameters->maxMCSPDUsize;
611 }
612 else if ((minimumParameters->maxMCSPDUsize >= 124) &&
613 (minimumParameters->maxMCSPDUsize <= 65528))
614 {
615 pOutParameters->maxMCSPDUsize = 65528;
616 }
617 else
618 {
619 WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 ", %" PRIu32 "]",
620 targetParameters->maxMCSPDUsize, minimumParameters->maxMCSPDUsize);
621 return FALSE;
622 }
623 }
624 else
625 {
626 if (maximumParameters->maxMCSPDUsize >= 124)
627 {
628 pOutParameters->maxMCSPDUsize = maximumParameters->maxMCSPDUsize;
629 }
630 else
631 {
632 WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 "]",
633 maximumParameters->maxMCSPDUsize);
634 return FALSE;
635 }
636 }
637
638 /* protocolVersion */
639
640 if ((targetParameters->protocolVersion == 2) ||
641 ((minimumParameters->protocolVersion <= 2) && (maximumParameters->protocolVersion >= 2)))
642 {
643 pOutParameters->protocolVersion = 2;
644 }
645 else
646 {
647 WLog_Print(log, WLOG_ERROR,
648 "invalid protocolVersion [%" PRIu32 ", %" PRIu32 ", %" PRIu32 "]",
649 targetParameters->protocolVersion, minimumParameters->protocolVersion,
650 maximumParameters->protocolVersion);
651 return FALSE;
652 }
653
654 return TRUE;
655}
656
664BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)
665{
666 UINT16 li = 0;
667 size_t length = 0;
668 BOOL upwardFlag = FALSE;
669 UINT16 tlength = 0;
670
671 WINPR_ASSERT(mcs);
672 WINPR_ASSERT(s);
673
674 if (!tpkt_read_header(s, &tlength))
675 return FALSE;
676
677 if (!tpdu_read_data(s, &li, tlength))
678 return FALSE;
679
680 if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
681 return FALSE;
682
683 /* callingDomainSelector (OCTET_STRING) */
684 if (!ber_read_octet_string_tag(s, &length) ||
685 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
686 return FALSE;
687
688 Stream_Seek(s, length);
689
690 /* calledDomainSelector (OCTET_STRING) */
691 if (!ber_read_octet_string_tag(s, &length) ||
692 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
693 return FALSE;
694
695 Stream_Seek(s, length);
696
697 /* upwardFlag (BOOLEAN) */
698 if (!ber_read_BOOL(s, &upwardFlag))
699 return FALSE;
700
701 /* targetParameters (DomainParameters) */
702 if (!mcs_read_domain_parameters(s, &mcs->targetParameters))
703 return FALSE;
704
705 /* minimumParameters (DomainParameters) */
706 if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))
707 return FALSE;
708
709 /* maximumParameters (DomainParameters) */
710 if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))
711 return FALSE;
712
713 if (!ber_read_octet_string_tag(s, &length) ||
714 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
715 return FALSE;
716
717 if (!gcc_read_conference_create_request(s, mcs))
718 return FALSE;
719
720 if (!mcs_merge_domain_parameters(mcs->log, &mcs->targetParameters, &mcs->minimumParameters,
721 &mcs->maximumParameters, &mcs->domainParameters))
722 return FALSE;
723
724 return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
725}
726
735BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData)
736{
737 size_t length = 0;
738 wStream* tmps = nullptr;
739 BOOL ret = FALSE;
740
741 if (!s || !mcs || !userData)
742 return FALSE;
743
744 tmps = Stream_New(nullptr, Stream_Capacity(s));
745
746 if (!tmps)
747 {
748 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
749 return FALSE;
750 }
751
752 /* callingDomainSelector (OCTET_STRING) */
753 if (!ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector)))
754 goto out;
755 /* calledDomainSelector (OCTET_STRING) */
756 if (!ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector)))
757 goto out;
758 /* upwardFlag (BOOLEAN) */
759 ber_write_BOOL(tmps, TRUE);
760
761 /* targetParameters (DomainParameters) */
762 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->targetParameters))
763 goto out;
764
765 /* minimumParameters (DomainParameters) */
766 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->minimumParameters))
767 goto out;
768
769 /* maximumParameters (DomainParameters) */
770 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->maximumParameters))
771 goto out;
772
773 /* userData (OCTET_STRING) */
774 if (!ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)))
775 goto out;
776 length = Stream_GetPosition(tmps);
777 /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */
778 ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);
779 Stream_Write(s, Stream_Buffer(tmps), length);
780 ret = TRUE;
781out:
782 Stream_Free(tmps, TRUE);
783 return ret;
784}
785
796BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData)
797{
798 size_t length = 0;
799 wStream* tmps = nullptr;
800 BOOL ret = FALSE;
801
802 if (!s || !mcs || !userData)
803 return FALSE;
804
805 tmps = Stream_New(nullptr, Stream_Capacity(s));
806
807 if (!tmps)
808 {
809 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
810 return FALSE;
811 }
812
813 ber_write_enumerated(tmps, 0, MCS_Result_enum_length);
814 if (!ber_write_integer(tmps, 0)) /* calledConnectId */
815 goto out;
816
817 if (!mcs_write_domain_parameters(mcs->log, tmps, &(mcs->domainParameters)))
818 goto out;
819
820 /* userData (OCTET_STRING) */
821 if (!ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)))
822 goto out;
823 length = Stream_GetPosition(tmps);
824 ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
825 Stream_Write(s, Stream_Buffer(tmps), length);
826 ret = TRUE;
827out:
828 Stream_Free(tmps, TRUE);
829 return ret;
830}
831
838static BOOL mcs_send_connect_initial(rdpMcs* mcs)
839{
840 int status = -1;
841 size_t length = 0;
842 wStream* s = nullptr;
843 size_t bm = 0;
844 size_t em = 0;
845 wStream* gcc_CCrq = nullptr;
846
847 if (!mcs || !mcs->context)
848 return FALSE;
849
850 mcs_initialize_client_channels(mcs, mcs->context->settings);
851 wStream* client_data = Stream_New(nullptr, 512);
852
853 if (!client_data)
854 {
855 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
856 return FALSE;
857 }
858
859 if (!gcc_write_client_data_blocks(client_data, mcs))
860 goto out;
861 gcc_CCrq = Stream_New(nullptr, 1024);
862
863 if (!gcc_CCrq)
864 {
865 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
866 goto out;
867 }
868
869 if (!gcc_write_conference_create_request(gcc_CCrq, client_data))
870 goto out;
871 length = Stream_GetPosition(gcc_CCrq) + 7;
872 s = Stream_New(nullptr, 1024 + length);
873
874 if (!s)
875 {
876 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
877 goto out;
878 }
879
880 bm = Stream_GetPosition(s);
881 Stream_Seek(s, 7);
882
883 if (!mcs_write_connect_initial(s, mcs, gcc_CCrq))
884 {
885 WLog_Print(mcs->log, WLOG_ERROR, "mcs_write_connect_initial failed!");
886 goto out;
887 }
888
889 em = Stream_GetPosition(s);
890 length = (em - bm);
891 if (length > UINT16_MAX)
892 goto out;
893 Stream_SetPosition(s, bm);
894 if (!tpkt_write_header(s, (UINT16)length))
895 goto out;
896 if (!tpdu_write_data(s))
897 goto out;
898 Stream_SetPosition(s, em);
899 Stream_SealLength(s);
900
901 {
902 rdpTransport* transport = freerdp_get_transport(mcs->context);
903 status = transport_write(transport, s);
904 }
905
906out:
907 Stream_Free(s, TRUE);
908 Stream_Free(gcc_CCrq, TRUE);
909 Stream_Free(client_data, TRUE);
910 return ((status >= 0));
911}
912
919BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
920{
921 size_t length = 0;
922 UINT16 tlength = 0;
923 BYTE result = 0;
924 UINT16 li = 0;
925 UINT32 calledConnectId = 0;
926
927 if (!mcs || !s)
928 return FALSE;
929
930 if (!tpkt_read_header(s, &tlength))
931 return FALSE;
932
933 if (!tpdu_read_data(s, &li, tlength))
934 return FALSE;
935
936 if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) ||
937 !ber_read_enumerated(s, &result, MCS_Result_enum_length) ||
938 !ber_read_integer(s, &calledConnectId) ||
939 !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||
940 !ber_read_octet_string_tag(s, &length))
941 {
942 return FALSE;
943 }
944
945 if (!gcc_read_conference_create_response(s, mcs))
946 {
947 WLog_Print(mcs->log, WLOG_ERROR, "gcc_read_conference_create_response failed");
948 return FALSE;
949 }
950
951 return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
952}
953
960BOOL mcs_send_connect_response(rdpMcs* mcs)
961{
962 size_t length = 0;
963 int status = -1;
964 wStream* s = nullptr;
965 size_t bm = 0;
966 size_t em = 0;
967 wStream* gcc_CCrsp = nullptr;
968
969 if (!mcs)
970 return FALSE;
971
972 wStream* server_data = Stream_New(nullptr, 512);
973
974 if (!server_data)
975 {
976 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
977 return FALSE;
978 }
979
980 if (!gcc_write_server_data_blocks(server_data, mcs))
981 goto out;
982
983 gcc_CCrsp = Stream_New(nullptr, 512 + Stream_Capacity(server_data));
984
985 if (!gcc_CCrsp)
986 {
987 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
988 goto out;
989 }
990
991 if (!gcc_write_conference_create_response(gcc_CCrsp, server_data))
992 goto out;
993 length = Stream_GetPosition(gcc_CCrsp) + 7;
994 s = Stream_New(nullptr, length + 1024);
995
996 if (!s)
997 {
998 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
999 goto out;
1000 }
1001
1002 bm = Stream_GetPosition(s);
1003 Stream_Seek(s, 7);
1004
1005 if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))
1006 goto out;
1007
1008 em = Stream_GetPosition(s);
1009 length = (em - bm);
1010 if (length > UINT16_MAX)
1011 goto out;
1012 Stream_SetPosition(s, bm);
1013 if (!tpkt_write_header(s, (UINT16)length))
1014 goto out;
1015 if (!tpdu_write_data(s))
1016 goto out;
1017 Stream_SetPosition(s, em);
1018 Stream_SealLength(s);
1019
1020 {
1021 rdpTransport* transport = freerdp_get_transport(mcs->context);
1022 status = transport_write(transport, s);
1023 }
1024
1025out:
1026 Stream_Free(s, TRUE);
1027 Stream_Free(gcc_CCrsp, TRUE);
1028 Stream_Free(server_data, TRUE);
1029 return (status >= 0);
1030}
1031
1039BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)
1040{
1041 UINT16 length = 0;
1042 UINT32 subHeight = 0;
1043 UINT32 subInterval = 0;
1044
1045 WINPR_ASSERT(mcs);
1046 WINPR_ASSERT(s);
1047
1048 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ErectDomainRequest, &length,
1049 nullptr))
1050 return FALSE;
1051
1052 if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */
1053 return FALSE;
1054
1055 if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */
1056 return FALSE;
1057
1058 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1059}
1060
1067BOOL mcs_send_erect_domain_request(rdpMcs* mcs)
1068{
1069 int status = -1;
1070 UINT16 length = 12;
1071
1072 if (!mcs)
1073 return FALSE;
1074
1075 wStream* s = Stream_New(nullptr, length);
1076
1077 if (!s)
1078 {
1079 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1080 return FALSE;
1081 }
1082
1083 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0))
1084 goto out;
1085 if (!per_write_integer(s, 0)) /* subHeight (INTEGER) */
1086 goto out;
1087 if (!per_write_integer(s, 0)) /* subInterval (INTEGER) */
1088 goto out;
1089 Stream_SealLength(s);
1090
1091 rdpTransport* transport = freerdp_get_transport(mcs->context);
1092 status = transport_write(transport, s);
1093out:
1094 Stream_Free(s, TRUE);
1095 return (status >= 0);
1096}
1097
1105BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s)
1106{
1107 UINT16 length = 0;
1108
1109 if (!mcs || !s)
1110 return FALSE;
1111
1112 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserRequest, &length,
1113 nullptr))
1114 return FALSE;
1115 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1116}
1117
1124BOOL mcs_send_attach_user_request(rdpMcs* mcs)
1125{
1126 int status = -1;
1127 UINT16 length = 8;
1128
1129 if (!mcs)
1130 return FALSE;
1131
1132 wStream* s = Stream_New(nullptr, length);
1133
1134 if (!s)
1135 {
1136 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1137 return FALSE;
1138 }
1139
1140 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0))
1141 goto fail;
1142
1143 Stream_SealLength(s);
1144
1145 rdpTransport* transport = freerdp_get_transport(mcs->context);
1146 status = transport_write(transport, s);
1147
1148fail:
1149 Stream_Free(s, TRUE);
1150 return (status >= 0);
1151}
1152
1159BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s)
1160{
1161 BYTE result = 0;
1162 UINT16 length = 0;
1163
1164 if (!mcs || !s)
1165 return FALSE;
1166
1167 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserConfirm, &length,
1168 nullptr))
1169 return FALSE;
1170 if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1171 return FALSE;
1172 if (!per_read_integer16(s, &(mcs->userId), MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1173 return FALSE;
1174 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1175}
1176
1183BOOL mcs_send_attach_user_confirm(rdpMcs* mcs)
1184{
1185 int status = -1;
1186 UINT16 length = 11;
1187
1188 if (!mcs)
1189 return FALSE;
1190
1191 wStream* s = Stream_New(nullptr, length);
1192
1193 if (!s)
1194 {
1195 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1196 return FALSE;
1197 }
1198
1199 mcs->userId = mcs->baseChannelId++;
1200 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2))
1201 goto out;
1202 if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */
1203 goto out;
1204 if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1205 goto out;
1206 Stream_SealLength(s);
1207
1208 rdpTransport* transport = freerdp_get_transport(mcs->context);
1209 status = transport_write(transport, s);
1210out:
1211 Stream_Free(s, TRUE);
1212 return (status >= 0);
1213}
1214
1222BOOL mcs_recv_channel_join_request(rdpMcs* mcs, const rdpSettings* settings, wStream* s,
1223 UINT16* channelId)
1224{
1225 UINT16 length = 0;
1226 UINT16 userId = 0;
1227
1228 if (!mcs || !s || !channelId)
1229 return FALSE;
1230
1231 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinRequest, &length,
1232 nullptr))
1233 return FALSE;
1234
1235 if (!per_read_integer16(s, &userId, MCS_BASE_CHANNEL_ID))
1236 return FALSE;
1237 if (userId != mcs->userId)
1238 {
1239 if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
1240 mcs->userId = userId;
1241 else
1242 return FALSE;
1243 }
1244 if (!per_read_integer16(s, channelId, 0))
1245 return FALSE;
1246
1247 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1248}
1249
1260BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId)
1261{
1262 int status = -1;
1263 UINT16 length = 12;
1264
1265 WINPR_ASSERT(mcs);
1266
1267 wStream* s = Stream_New(nullptr, length);
1268
1269 if (!s)
1270 {
1271 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1272 return FALSE;
1273 }
1274
1275 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0))
1276 goto out;
1277 if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID))
1278 goto out;
1279 if (!per_write_integer16(s, channelId, 0))
1280 goto out;
1281 Stream_SealLength(s);
1282
1283 rdpTransport* transport = freerdp_get_transport(mcs->context);
1284 status = transport_write(transport, s);
1285
1286out:
1287 Stream_Free(s, TRUE);
1288 return (status >= 0);
1289}
1290
1297BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId)
1298{
1299 UINT16 length = 0;
1300 BYTE result = 0;
1301 UINT16 initiator = 0;
1302 UINT16 requested = 0;
1303
1304 WINPR_ASSERT(mcs);
1305 WINPR_ASSERT(channelId);
1306
1307 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinConfirm, &length,
1308 nullptr))
1309 return FALSE;
1310
1311 if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1312 return FALSE;
1313 if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1314 return FALSE;
1315 if (!per_read_integer16(s, &requested, 0)) /* requested (ChannelId) */
1316 return FALSE;
1317 if (!per_read_integer16(s, channelId, 0)) /* channelId */
1318 return FALSE;
1319 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1320}
1321
1328BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId)
1329{
1330 int status = -1;
1331 UINT16 length = 15;
1332
1333 if (!mcs)
1334 return FALSE;
1335
1336 wStream* s = Stream_New(nullptr, length);
1337
1338 if (!s)
1339 {
1340 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1341 return FALSE;
1342 }
1343
1344 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2))
1345 goto fail;
1346 if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */
1347 goto fail;
1348 if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1349 goto fail;
1350 if (!per_write_integer16(s, channelId, 0)) /* requested (ChannelId) */
1351 goto fail;
1352 if (!per_write_integer16(s, channelId, 0)) /* channelId */
1353 goto fail;
1354 Stream_SealLength(s);
1355
1356 {
1357 rdpTransport* transport = freerdp_get_transport(mcs->context);
1358 status = transport_write(transport, s);
1359 }
1360
1361fail:
1362 Stream_Free(s, TRUE);
1363 return (status >= 0);
1364}
1365
1371BOOL mcs_recv_disconnect_provider_ultimatum(WINPR_ATTR_UNUSED rdpMcs* mcs, wStream* s, int* reason)
1372{
1373 BYTE b1 = 0;
1374 BYTE b2 = 0;
1375
1376 WINPR_ASSERT(mcs);
1377 WINPR_ASSERT(s);
1378 WINPR_ASSERT(reason);
1379
1380 /*
1381 * http://msdn.microsoft.com/en-us/library/cc240872.aspx:
1382 *
1383 * PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
1384 * 21 80
1385 *
1386 * 0x21:
1387 * 0 - --\
1388 * 0 - |
1389 * 1 - | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
1390 * 0 - | of type DisconnectProviderUltimatum
1391 * 0 - |
1392 * 0 - --/
1393 * 0 - --\
1394 * 1 - |
1395 * | DisconnectProviderUltimatum::reason = rn-user-requested (3)
1396 * 0x80: |
1397 * 1 - --/
1398 * 0 - padding
1399 * 0 - padding
1400 * 0 - padding
1401 * 0 - padding
1402 * 0 - padding
1403 * 0 - padding
1404 * 0 - padding
1405 */
1406
1407 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1408 return FALSE;
1409
1410 Stream_Rewind_UINT8(s);
1411 Stream_Read_UINT8(s, b1);
1412 Stream_Read_UINT8(s, b2);
1413 *reason = ((b1 & 0x01) << 1) | (b2 >> 7);
1414 return TRUE;
1415}
1416
1422BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs, enum Disconnect_Ultimatum reason)
1423{
1424 int status = -1;
1425 UINT16 length = 9;
1426
1427 WINPR_ASSERT(mcs);
1428
1429 wStream* s = Stream_New(nullptr, length);
1430
1431 if (!s)
1432 goto fail;
1433
1434 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1))
1435 goto fail;
1436
1437 if (!per_write_enumerated(s, 0x80, WINPR_ASSERTING_INT_CAST(BYTE, reason)))
1438 goto fail;
1439
1440 {
1441 rdpTransport* transport = freerdp_get_transport(mcs->context);
1442 status = transport_write(transport, s);
1443 }
1444
1445fail:
1446 WLog_Print(mcs->log, WLOG_DEBUG, "sending DisconnectProviderUltimatum(%s)",
1447 freerdp_disconnect_reason_string((int)reason));
1448 Stream_Free(s, TRUE);
1449 return (status >= 0);
1450}
1451
1452BOOL mcs_client_begin(rdpMcs* mcs)
1453{
1454 if (!mcs || !mcs->context)
1455 return FALSE;
1456
1457 /* First transition state, we need this to trigger session recording */
1458 if (!mcs_send_connect_initial(mcs))
1459 {
1460 freerdp_set_last_error_if_not(mcs->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
1461
1462 WLog_Print(mcs->log, WLOG_ERROR, "Error: unable to send MCS Connect Initial");
1463 return FALSE;
1464 }
1465
1466 return TRUE;
1467}
1468
1475rdpMcs* mcs_new(rdpContext* context)
1476{
1477 rdpMcs* mcs = (rdpMcs*)calloc(1, sizeof(rdpMcs));
1478
1479 if (!mcs)
1480 return nullptr;
1481 mcs->log = WLog_Get(MCS_TAG);
1482 WINPR_ASSERT(mcs->log);
1483
1484 mcs->context = context;
1485 mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);
1486 mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);
1487 mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);
1488 mcs_init_domain_parameters(&mcs->domainParameters, 0, 0, 0, 0xFFFF);
1489 mcs->channelCount = 0;
1490 mcs->channelMaxCount = CHANNEL_MAX_COUNT;
1491 mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;
1492 mcs->channels = (rdpMcsChannel*)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
1493
1494 if (!mcs->channels)
1495 goto out_free;
1496
1497 return mcs;
1498out_free:
1499 free(mcs);
1500 return nullptr;
1501}
1502
1508void mcs_free(rdpMcs* mcs)
1509{
1510 if (mcs)
1511 {
1512 free(mcs->channels);
1513 free(mcs);
1514 }
1515}
1516
1517BOOL mcs_server_apply_to_settings(const rdpMcs* mcs, rdpSettings* settings)
1518{
1519 BOOL rc = FALSE;
1520
1521 WINPR_ASSERT(mcs);
1522 WINPR_ASSERT(settings);
1523
1524 if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, mcs->channelCount))
1525 goto fail;
1526
1527 for (UINT32 x = 0; x < mcs->channelCount; x++)
1528 {
1529 const rdpMcsChannel* current = &mcs->channels[x];
1530 CHANNEL_DEF def = WINPR_C_ARRAY_INIT;
1531 def.options = current->options;
1532 memcpy(def.name, current->Name, sizeof(def.name));
1533 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ChannelDefArray, x, &def))
1534 goto fail;
1535 }
1536
1537 rc = TRUE;
1538fail:
1539 if (!rc)
1540 WLog_Print(mcs->log, WLOG_WARN, "failed to apply settings");
1541
1542 return rc;
1543}
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.