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 size_t length = 0;
453 wStream* tmps = NULL;
454
455 if (!s || !domainParameters)
456 return FALSE;
457
458 tmps = Stream_New(NULL, Stream_Capacity(s));
459
460 if (!tmps)
461 {
462 WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
463 return FALSE;
464 }
465
466 ber_write_integer(tmps, domainParameters->maxChannelIds);
467 ber_write_integer(tmps, domainParameters->maxUserIds);
468 ber_write_integer(tmps, domainParameters->maxTokenIds);
469 ber_write_integer(tmps, domainParameters->numPriorities);
470 ber_write_integer(tmps, domainParameters->minThroughput);
471 ber_write_integer(tmps, domainParameters->maxHeight);
472 ber_write_integer(tmps, domainParameters->maxMCSPDUsize);
473 ber_write_integer(tmps, domainParameters->protocolVersion);
474 length = Stream_GetPosition(tmps);
475 ber_write_sequence_tag(s, length);
476 Stream_Write(s, Stream_Buffer(tmps), length);
477 Stream_Free(tmps, TRUE);
478 return TRUE;
479}
480
481#ifdef DEBUG_MCS
487static void mcs_print_domain_parameters(DomainParameters* domainParameters)
488{
489 WLog_INFO(TAG, "DomainParameters {");
490
491 if (domainParameters)
492 {
493 WLog_INFO(TAG, "\tmaxChannelIds:%" PRIu32 "", domainParameters->maxChannelIds);
494 WLog_INFO(TAG, "\tmaxUserIds:%" PRIu32 "", domainParameters->maxUserIds);
495 WLog_INFO(TAG, "\tmaxTokenIds:%" PRIu32 "", domainParameters->maxTokenIds);
496 WLog_INFO(TAG, "\tnumPriorities:%" PRIu32 "", domainParameters->numPriorities);
497 WLog_INFO(TAG, "\tminThroughput:%" PRIu32 "", domainParameters->minThroughput);
498 WLog_INFO(TAG, "\tmaxHeight:%" PRIu32 "", domainParameters->maxHeight);
499 WLog_INFO(TAG, "\tmaxMCSPDUsize:%" PRIu32 "", domainParameters->maxMCSPDUsize);
500 WLog_INFO(TAG, "\tprotocolVersion:%" PRIu32 "", domainParameters->protocolVersion);
501 }
502 else
503 WLog_INFO(TAG, "\tdomainParameters=%p", domainParameters);
504
505 WLog_INFO(TAG, "}");
506}
507#endif
508
519BOOL mcs_merge_domain_parameters(wLog* log, DomainParameters* targetParameters,
520 DomainParameters* minimumParameters,
521 DomainParameters* maximumParameters,
522 DomainParameters* pOutParameters)
523{
524 /* maxChannelIds */
525 if (!targetParameters || !minimumParameters || !maximumParameters || !pOutParameters)
526 return FALSE;
527
528 if (targetParameters->maxChannelIds >= 4)
529 {
530 pOutParameters->maxChannelIds = targetParameters->maxChannelIds;
531 }
532 else if (maximumParameters->maxChannelIds >= 4)
533 {
534 pOutParameters->maxChannelIds = 4;
535 }
536 else
537 {
538 WLog_Print(log, WLOG_ERROR, "invalid maxChannelIds [%" PRIu32 ", %" PRIu32 "]",
539 targetParameters->maxChannelIds, maximumParameters->maxChannelIds);
540 return FALSE;
541 }
542
543 /* maxUserIds */
544
545 if (targetParameters->maxUserIds >= 3)
546 {
547 pOutParameters->maxUserIds = targetParameters->maxUserIds;
548 }
549 else if (maximumParameters->maxUserIds >= 3)
550 {
551 pOutParameters->maxUserIds = 3;
552 }
553 else
554 {
555 WLog_Print(log, WLOG_ERROR, "invalid maxUserIds [%" PRIu32 ", %" PRIu32 "]",
556 targetParameters->maxUserIds, maximumParameters->maxUserIds);
557 return FALSE;
558 }
559
560 /* maxTokenIds */
561 pOutParameters->maxTokenIds = targetParameters->maxTokenIds;
562
563 /* numPriorities */
564
565 if (minimumParameters->numPriorities <= 1)
566 {
567 pOutParameters->numPriorities = 1;
568 }
569 else
570 {
571 WLog_Print(log, WLOG_ERROR, "invalid numPriorities [%" PRIu32 "]",
572 maximumParameters->numPriorities);
573 return FALSE;
574 }
575
576 /* minThroughput */
577 pOutParameters->minThroughput = targetParameters->minThroughput;
578
579 /* maxHeight */
580
581 if ((targetParameters->maxHeight == 1) || (minimumParameters->maxHeight <= 1))
582 {
583 pOutParameters->maxHeight = 1;
584 }
585 else
586 {
587 WLog_Print(log, WLOG_ERROR, "invalid maxHeight [%" PRIu32 ", %" PRIu32 "]",
588 targetParameters->maxHeight, minimumParameters->maxHeight);
589 return FALSE;
590 }
591
592 /* maxMCSPDUsize */
593
594 if (targetParameters->maxMCSPDUsize >= 1024)
595 {
596 if (targetParameters->maxMCSPDUsize <= 65528)
597 {
598 pOutParameters->maxMCSPDUsize = targetParameters->maxMCSPDUsize;
599 }
600 else if ((minimumParameters->maxMCSPDUsize >= 124) &&
601 (minimumParameters->maxMCSPDUsize <= 65528))
602 {
603 pOutParameters->maxMCSPDUsize = 65528;
604 }
605 else
606 {
607 WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 ", %" PRIu32 "]",
608 targetParameters->maxMCSPDUsize, minimumParameters->maxMCSPDUsize);
609 return FALSE;
610 }
611 }
612 else
613 {
614 if (maximumParameters->maxMCSPDUsize >= 124)
615 {
616 pOutParameters->maxMCSPDUsize = maximumParameters->maxMCSPDUsize;
617 }
618 else
619 {
620 WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 "]",
621 maximumParameters->maxMCSPDUsize);
622 return FALSE;
623 }
624 }
625
626 /* protocolVersion */
627
628 if ((targetParameters->protocolVersion == 2) ||
629 ((minimumParameters->protocolVersion <= 2) && (maximumParameters->protocolVersion >= 2)))
630 {
631 pOutParameters->protocolVersion = 2;
632 }
633 else
634 {
635 WLog_Print(log, WLOG_ERROR,
636 "invalid protocolVersion [%" PRIu32 ", %" PRIu32 ", %" PRIu32 "]",
637 targetParameters->protocolVersion, minimumParameters->protocolVersion,
638 maximumParameters->protocolVersion);
639 return FALSE;
640 }
641
642 return TRUE;
643}
644
652BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)
653{
654 UINT16 li = 0;
655 size_t length = 0;
656 BOOL upwardFlag = FALSE;
657 UINT16 tlength = 0;
658
659 WINPR_ASSERT(mcs);
660 WINPR_ASSERT(s);
661
662 if (!tpkt_read_header(s, &tlength))
663 return FALSE;
664
665 if (!tpdu_read_data(s, &li, tlength))
666 return FALSE;
667
668 if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
669 return FALSE;
670
671 /* callingDomainSelector (OCTET_STRING) */
672 if (!ber_read_octet_string_tag(s, &length) ||
673 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
674 return FALSE;
675
676 Stream_Seek(s, length);
677
678 /* calledDomainSelector (OCTET_STRING) */
679 if (!ber_read_octet_string_tag(s, &length) ||
680 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
681 return FALSE;
682
683 Stream_Seek(s, length);
684
685 /* upwardFlag (BOOLEAN) */
686 if (!ber_read_BOOL(s, &upwardFlag))
687 return FALSE;
688
689 /* targetParameters (DomainParameters) */
690 if (!mcs_read_domain_parameters(s, &mcs->targetParameters))
691 return FALSE;
692
693 /* minimumParameters (DomainParameters) */
694 if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))
695 return FALSE;
696
697 /* maximumParameters (DomainParameters) */
698 if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))
699 return FALSE;
700
701 if (!ber_read_octet_string_tag(s, &length) ||
702 (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
703 return FALSE;
704
705 if (!gcc_read_conference_create_request(s, mcs))
706 return FALSE;
707
708 if (!mcs_merge_domain_parameters(mcs->log, &mcs->targetParameters, &mcs->minimumParameters,
709 &mcs->maximumParameters, &mcs->domainParameters))
710 return FALSE;
711
712 return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
713}
714
723BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData)
724{
725 size_t length = 0;
726 wStream* tmps = NULL;
727 BOOL ret = FALSE;
728
729 if (!s || !mcs || !userData)
730 return FALSE;
731
732 tmps = Stream_New(NULL, Stream_Capacity(s));
733
734 if (!tmps)
735 {
736 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
737 return FALSE;
738 }
739
740 /* callingDomainSelector (OCTET_STRING) */
741 ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector));
742 /* calledDomainSelector (OCTET_STRING) */
743 ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector));
744 /* upwardFlag (BOOLEAN) */
745 ber_write_BOOL(tmps, TRUE);
746
747 /* targetParameters (DomainParameters) */
748 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->targetParameters))
749 goto out;
750
751 /* minimumParameters (DomainParameters) */
752 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->minimumParameters))
753 goto out;
754
755 /* maximumParameters (DomainParameters) */
756 if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->maximumParameters))
757 goto out;
758
759 /* userData (OCTET_STRING) */
760 ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));
761 length = Stream_GetPosition(tmps);
762 /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */
763 ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);
764 Stream_Write(s, Stream_Buffer(tmps), length);
765 ret = TRUE;
766out:
767 Stream_Free(tmps, TRUE);
768 return ret;
769}
770
781BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData)
782{
783 size_t length = 0;
784 wStream* tmps = NULL;
785 BOOL ret = FALSE;
786
787 if (!s || !mcs || !userData)
788 return FALSE;
789
790 tmps = Stream_New(NULL, Stream_Capacity(s));
791
792 if (!tmps)
793 {
794 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
795 return FALSE;
796 }
797
798 ber_write_enumerated(tmps, 0, MCS_Result_enum_length);
799 ber_write_integer(tmps, 0); /* calledConnectId */
800
801 if (!mcs_write_domain_parameters(mcs->log, tmps, &(mcs->domainParameters)))
802 goto out;
803
804 /* userData (OCTET_STRING) */
805 ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));
806 length = Stream_GetPosition(tmps);
807 ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
808 Stream_Write(s, Stream_Buffer(tmps), length);
809 ret = TRUE;
810out:
811 Stream_Free(tmps, TRUE);
812 return ret;
813}
814
821static BOOL mcs_send_connect_initial(rdpMcs* mcs)
822{
823 int status = -1;
824 size_t length = 0;
825 wStream* s = NULL;
826 size_t bm = 0;
827 size_t em = 0;
828 wStream* gcc_CCrq = NULL;
829
830 if (!mcs || !mcs->context)
831 return FALSE;
832
833 mcs_initialize_client_channels(mcs, mcs->context->settings);
834 wStream* client_data = Stream_New(NULL, 512);
835
836 if (!client_data)
837 {
838 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
839 return FALSE;
840 }
841
842 if (!gcc_write_client_data_blocks(client_data, mcs))
843 goto out;
844 gcc_CCrq = Stream_New(NULL, 1024);
845
846 if (!gcc_CCrq)
847 {
848 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
849 goto out;
850 }
851
852 if (!gcc_write_conference_create_request(gcc_CCrq, client_data))
853 goto out;
854 length = Stream_GetPosition(gcc_CCrq) + 7;
855 s = Stream_New(NULL, 1024 + length);
856
857 if (!s)
858 {
859 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
860 goto out;
861 }
862
863 bm = Stream_GetPosition(s);
864 Stream_Seek(s, 7);
865
866 if (!mcs_write_connect_initial(s, mcs, gcc_CCrq))
867 {
868 WLog_Print(mcs->log, WLOG_ERROR, "mcs_write_connect_initial failed!");
869 goto out;
870 }
871
872 em = Stream_GetPosition(s);
873 length = (em - bm);
874 if (length > UINT16_MAX)
875 goto out;
876 Stream_SetPosition(s, bm);
877 if (!tpkt_write_header(s, (UINT16)length))
878 goto out;
879 if (!tpdu_write_data(s))
880 goto out;
881 Stream_SetPosition(s, em);
882 Stream_SealLength(s);
883
884 {
885 rdpTransport* transport = freerdp_get_transport(mcs->context);
886 status = transport_write(transport, s);
887 }
888
889out:
890 Stream_Free(s, TRUE);
891 Stream_Free(gcc_CCrq, TRUE);
892 Stream_Free(client_data, TRUE);
893 return (status < 0 ? FALSE : TRUE);
894}
895
902BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
903{
904 size_t length = 0;
905 UINT16 tlength = 0;
906 BYTE result = 0;
907 UINT16 li = 0;
908 UINT32 calledConnectId = 0;
909
910 if (!mcs || !s)
911 return FALSE;
912
913 if (!tpkt_read_header(s, &tlength))
914 return FALSE;
915
916 if (!tpdu_read_data(s, &li, tlength))
917 return FALSE;
918
919 if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) ||
920 !ber_read_enumerated(s, &result, MCS_Result_enum_length) ||
921 !ber_read_integer(s, &calledConnectId) ||
922 !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||
923 !ber_read_octet_string_tag(s, &length))
924 {
925 return FALSE;
926 }
927
928 if (!gcc_read_conference_create_response(s, mcs))
929 {
930 WLog_Print(mcs->log, WLOG_ERROR, "gcc_read_conference_create_response failed");
931 return FALSE;
932 }
933
934 return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
935}
936
943BOOL mcs_send_connect_response(rdpMcs* mcs)
944{
945 size_t length = 0;
946 int status = -1;
947 wStream* s = NULL;
948 size_t bm = 0;
949 size_t em = 0;
950 wStream* gcc_CCrsp = NULL;
951
952 if (!mcs)
953 return FALSE;
954
955 wStream* server_data = Stream_New(NULL, 512);
956
957 if (!server_data)
958 {
959 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
960 return FALSE;
961 }
962
963 if (!gcc_write_server_data_blocks(server_data, mcs))
964 goto out;
965
966 gcc_CCrsp = Stream_New(NULL, 512 + Stream_Capacity(server_data));
967
968 if (!gcc_CCrsp)
969 {
970 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
971 goto out;
972 }
973
974 if (!gcc_write_conference_create_response(gcc_CCrsp, server_data))
975 goto out;
976 length = Stream_GetPosition(gcc_CCrsp) + 7;
977 s = Stream_New(NULL, length + 1024);
978
979 if (!s)
980 {
981 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
982 goto out;
983 }
984
985 bm = Stream_GetPosition(s);
986 Stream_Seek(s, 7);
987
988 if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))
989 goto out;
990
991 em = Stream_GetPosition(s);
992 length = (em - bm);
993 if (length > UINT16_MAX)
994 goto out;
995 Stream_SetPosition(s, bm);
996 if (!tpkt_write_header(s, (UINT16)length))
997 goto out;
998 if (!tpdu_write_data(s))
999 goto out;
1000 Stream_SetPosition(s, em);
1001 Stream_SealLength(s);
1002
1003 {
1004 rdpTransport* transport = freerdp_get_transport(mcs->context);
1005 status = transport_write(transport, s);
1006 }
1007
1008out:
1009 Stream_Free(s, TRUE);
1010 Stream_Free(gcc_CCrsp, TRUE);
1011 Stream_Free(server_data, TRUE);
1012 return (status < 0) ? FALSE : TRUE;
1013}
1014
1022BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)
1023{
1024 UINT16 length = 0;
1025 UINT32 subHeight = 0;
1026 UINT32 subInterval = 0;
1027
1028 WINPR_ASSERT(mcs);
1029 WINPR_ASSERT(s);
1030
1031 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ErectDomainRequest, &length, NULL))
1032 return FALSE;
1033
1034 if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */
1035 return FALSE;
1036
1037 if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */
1038 return FALSE;
1039
1040 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1041}
1042
1049BOOL mcs_send_erect_domain_request(rdpMcs* mcs)
1050{
1051 UINT16 length = 12;
1052
1053 if (!mcs)
1054 return FALSE;
1055
1056 wStream* s = Stream_New(NULL, length);
1057
1058 if (!s)
1059 {
1060 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1061 return FALSE;
1062 }
1063
1064 mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0);
1065 per_write_integer(s, 0); /* subHeight (INTEGER) */
1066 per_write_integer(s, 0); /* subInterval (INTEGER) */
1067 Stream_SealLength(s);
1068
1069 rdpTransport* transport = freerdp_get_transport(mcs->context);
1070 const int status = transport_write(transport, s);
1071 Stream_Free(s, TRUE);
1072 return (status < 0) ? FALSE : TRUE;
1073}
1074
1082BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s)
1083{
1084 UINT16 length = 0;
1085
1086 if (!mcs || !s)
1087 return FALSE;
1088
1089 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserRequest, &length, NULL))
1090 return FALSE;
1091 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1092}
1093
1100BOOL mcs_send_attach_user_request(rdpMcs* mcs)
1101{
1102 UINT16 length = 8;
1103
1104 if (!mcs)
1105 return FALSE;
1106
1107 wStream* s = Stream_New(NULL, length);
1108
1109 if (!s)
1110 {
1111 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1112 return FALSE;
1113 }
1114
1115 mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0);
1116 Stream_SealLength(s);
1117
1118 rdpTransport* transport = freerdp_get_transport(mcs->context);
1119 const int status = transport_write(transport, s);
1120 Stream_Free(s, TRUE);
1121 return (status < 0) ? FALSE : TRUE;
1122}
1123
1130BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s)
1131{
1132 BYTE result = 0;
1133 UINT16 length = 0;
1134
1135 if (!mcs || !s)
1136 return FALSE;
1137
1138 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserConfirm, &length, NULL))
1139 return FALSE;
1140 if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1141 return FALSE;
1142 if (!per_read_integer16(s, &(mcs->userId), MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1143 return FALSE;
1144 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1145}
1146
1153BOOL mcs_send_attach_user_confirm(rdpMcs* mcs)
1154{
1155 UINT16 length = 11;
1156
1157 if (!mcs)
1158 return FALSE;
1159
1160 wStream* s = Stream_New(NULL, length);
1161
1162 if (!s)
1163 {
1164 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1165 return FALSE;
1166 }
1167
1168 mcs->userId = mcs->baseChannelId++;
1169 mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2);
1170 per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
1171 per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
1172 Stream_SealLength(s);
1173
1174 rdpTransport* transport = freerdp_get_transport(mcs->context);
1175 const int status = transport_write(transport, s);
1176 Stream_Free(s, TRUE);
1177 return (status < 0) ? FALSE : TRUE;
1178}
1179
1187BOOL mcs_recv_channel_join_request(rdpMcs* mcs, const rdpSettings* settings, wStream* s,
1188 UINT16* channelId)
1189{
1190 UINT16 length = 0;
1191 UINT16 userId = 0;
1192
1193 if (!mcs || !s || !channelId)
1194 return FALSE;
1195
1196 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinRequest, &length, NULL))
1197 return FALSE;
1198
1199 if (!per_read_integer16(s, &userId, MCS_BASE_CHANNEL_ID))
1200 return FALSE;
1201 if (userId != mcs->userId)
1202 {
1203 if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
1204 mcs->userId = userId;
1205 else
1206 return FALSE;
1207 }
1208 if (!per_read_integer16(s, channelId, 0))
1209 return FALSE;
1210
1211 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1212}
1213
1224BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId)
1225{
1226 UINT16 length = 12;
1227
1228 WINPR_ASSERT(mcs);
1229
1230 wStream* s = Stream_New(NULL, length);
1231
1232 if (!s)
1233 {
1234 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1235 return FALSE;
1236 }
1237
1238 mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0);
1239 per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID);
1240 per_write_integer16(s, channelId, 0);
1241 Stream_SealLength(s);
1242
1243 rdpTransport* transport = freerdp_get_transport(mcs->context);
1244 const int status = transport_write(transport, s);
1245 Stream_Free(s, TRUE);
1246 return (status < 0) ? FALSE : TRUE;
1247}
1248
1255BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId)
1256{
1257 UINT16 length = 0;
1258 BYTE result = 0;
1259 UINT16 initiator = 0;
1260 UINT16 requested = 0;
1261
1262 WINPR_ASSERT(mcs);
1263 WINPR_ASSERT(channelId);
1264
1265 if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinConfirm, &length, NULL))
1266 return FALSE;
1267
1268 if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1269 return FALSE;
1270 if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1271 return FALSE;
1272 if (!per_read_integer16(s, &requested, 0)) /* requested (ChannelId) */
1273 return FALSE;
1274 if (!per_read_integer16(s, channelId, 0)) /* channelId */
1275 return FALSE;
1276 return tpkt_ensure_stream_consumed(mcs->log, s, length);
1277}
1278
1285BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId)
1286{
1287 int status = -1;
1288 UINT16 length = 15;
1289
1290 if (!mcs)
1291 return FALSE;
1292
1293 wStream* s = Stream_New(NULL, length);
1294
1295 if (!s)
1296 {
1297 WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1298 return FALSE;
1299 }
1300
1301 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2))
1302 goto fail;
1303 if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */
1304 goto fail;
1305 if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1306 goto fail;
1307 if (!per_write_integer16(s, channelId, 0)) /* requested (ChannelId) */
1308 goto fail;
1309 if (!per_write_integer16(s, channelId, 0)) /* channelId */
1310 goto fail;
1311 Stream_SealLength(s);
1312
1313 {
1314 rdpTransport* transport = freerdp_get_transport(mcs->context);
1315 status = transport_write(transport, s);
1316 }
1317
1318fail:
1319 Stream_Free(s, TRUE);
1320 return (status < 0) ? FALSE : TRUE;
1321}
1322
1328BOOL mcs_recv_disconnect_provider_ultimatum(WINPR_ATTR_UNUSED rdpMcs* mcs, wStream* s, int* reason)
1329{
1330 BYTE b1 = 0;
1331 BYTE b2 = 0;
1332
1333 WINPR_ASSERT(mcs);
1334 WINPR_ASSERT(s);
1335 WINPR_ASSERT(reason);
1336
1337 /*
1338 * http://msdn.microsoft.com/en-us/library/cc240872.aspx:
1339 *
1340 * PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
1341 * 21 80
1342 *
1343 * 0x21:
1344 * 0 - --\
1345 * 0 - |
1346 * 1 - | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
1347 * 0 - | of type DisconnectProviderUltimatum
1348 * 0 - |
1349 * 0 - --/
1350 * 0 - --\
1351 * 1 - |
1352 * | DisconnectProviderUltimatum::reason = rn-user-requested (3)
1353 * 0x80: |
1354 * 1 - --/
1355 * 0 - padding
1356 * 0 - padding
1357 * 0 - padding
1358 * 0 - padding
1359 * 0 - padding
1360 * 0 - padding
1361 * 0 - padding
1362 */
1363
1364 if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1365 return FALSE;
1366
1367 Stream_Rewind_UINT8(s);
1368 Stream_Read_UINT8(s, b1);
1369 Stream_Read_UINT8(s, b2);
1370 *reason = ((b1 & 0x01) << 1) | (b2 >> 7);
1371 return TRUE;
1372}
1373
1379BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs, enum Disconnect_Ultimatum reason)
1380{
1381 int status = -1;
1382 UINT16 length = 9;
1383
1384 WINPR_ASSERT(mcs);
1385
1386 wStream* s = Stream_New(NULL, length);
1387
1388 if (!s)
1389 goto fail;
1390
1391 if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1))
1392 goto fail;
1393
1394 if (!per_write_enumerated(s, 0x80, WINPR_ASSERTING_INT_CAST(BYTE, reason)))
1395 goto fail;
1396
1397 {
1398 rdpTransport* transport = freerdp_get_transport(mcs->context);
1399 status = transport_write(transport, s);
1400 }
1401
1402fail:
1403 WLog_Print(mcs->log, WLOG_DEBUG, "sending DisconnectProviderUltimatum(%s)",
1404 freerdp_disconnect_reason_string((int)reason));
1405 Stream_Free(s, TRUE);
1406 return (status < 0) ? FALSE : TRUE;
1407}
1408
1409BOOL mcs_client_begin(rdpMcs* mcs)
1410{
1411 if (!mcs || !mcs->context)
1412 return FALSE;
1413
1414 /* First transition state, we need this to trigger session recording */
1415 if (!mcs_send_connect_initial(mcs))
1416 {
1417 freerdp_set_last_error_if_not(mcs->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
1418
1419 WLog_Print(mcs->log, WLOG_ERROR, "Error: unable to send MCS Connect Initial");
1420 return FALSE;
1421 }
1422
1423 return TRUE;
1424}
1425
1432rdpMcs* mcs_new(rdpContext* context)
1433{
1434 rdpMcs* mcs = (rdpMcs*)calloc(1, sizeof(rdpMcs));
1435
1436 if (!mcs)
1437 return NULL;
1438 mcs->log = WLog_Get(MCS_TAG);
1439 WINPR_ASSERT(mcs->log);
1440
1441 mcs->context = context;
1442 mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);
1443 mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);
1444 mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);
1445 mcs_init_domain_parameters(&mcs->domainParameters, 0, 0, 0, 0xFFFF);
1446 mcs->channelCount = 0;
1447 mcs->channelMaxCount = CHANNEL_MAX_COUNT;
1448 mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;
1449 mcs->channels = (rdpMcsChannel*)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
1450
1451 if (!mcs->channels)
1452 goto out_free;
1453
1454 return mcs;
1455out_free:
1456 free(mcs);
1457 return NULL;
1458}
1459
1465void mcs_free(rdpMcs* mcs)
1466{
1467 if (mcs)
1468 {
1469 free(mcs->channels);
1470 free(mcs);
1471 }
1472}
1473
1474BOOL mcs_server_apply_to_settings(const rdpMcs* mcs, rdpSettings* settings)
1475{
1476 BOOL rc = FALSE;
1477
1478 WINPR_ASSERT(mcs);
1479 WINPR_ASSERT(settings);
1480
1481 if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, mcs->channelCount))
1482 goto fail;
1483
1484 for (UINT32 x = 0; x < mcs->channelCount; x++)
1485 {
1486 const rdpMcsChannel* current = &mcs->channels[x];
1487 CHANNEL_DEF def = { 0 };
1488 def.options = current->options;
1489 memcpy(def.name, current->Name, sizeof(def.name));
1490 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ChannelDefArray, x, &def))
1491 goto fail;
1492 }
1493
1494 rc = TRUE;
1495fail:
1496 if (!rc)
1497 WLog_Print(mcs->log, WLOG_WARN, "failed to apply settings");
1498
1499 return rc;
1500}
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_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.