Coverage Report

Created: 2026-03-04 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/mcs.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * T.125 Multipoint Communication Service (MCS) Protocol
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
9
 * Copyright 2017 Thincast Technologies GmbH
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
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
46.2k
#define MCS_TAG FREERDP_TAG("core")
39
40
/**
41
 * T.125 MCS is defined in:
42
 *
43
 * http://www.itu.int/rec/T-REC-T.125-199802-I/
44
 * ITU-T T.125 Multipoint Communication Service Protocol Specification
45
 */
46
47
/**
48
 * Connect-Initial ::= [APPLICATION 101] IMPLICIT SEQUENCE
49
 * {
50
 *  callingDomainSelector   OCTET_STRING,
51
 *  calledDomainSelector    OCTET_STRING,
52
 *  upwardFlag      BOOLEAN,
53
 *  targetParameters    DomainParameters,
54
 *  minimumParameters   DomainParameters,
55
 *  maximumParameters   DomainParameters,
56
 *  userData      OCTET_STRING
57
 * }
58
 *
59
 * DomainParameters ::= SEQUENCE
60
 * {
61
 *  maxChannelIds     INTEGER (0..MAX),
62
 *  maxUserIds      INTEGER (0..MAX),
63
 *  maxTokenIds     INTEGER (0..MAX),
64
 *  numPriorities     INTEGER (0..MAX),
65
 *  minThroughput     INTEGER (0..MAX),
66
 *  maxHeight     INTEGER (0..MAX),
67
 *  maxMCSPDUsize     INTEGER (0..MAX),
68
 *  protocolVersion     INTEGER (0..MAX)
69
 * }
70
 *
71
 * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE
72
 * {
73
 *  result        Result,
74
 *  calledConnectId     INTEGER (0..MAX),
75
 *  domainParameters    DomainParameters,
76
 *  userData      OCTET_STRING
77
 * }
78
 *
79
 * Result ::= ENUMERATED
80
 * {
81
 *  rt-successful     (0),
82
 *  rt-domain-merging   (1),
83
 *  rt-domain-not-hierarchical  (2),
84
 *  rt-no-such-channel    (3),
85
 *  rt-no-such-domain   (4),
86
 *  rt-no-such-user     (5),
87
 *  rt-not-admitted     (6),
88
 *  rt-other-user-id    (7),
89
 *  rt-parameters-unacceptable  (8),
90
 *  rt-token-not-available    (9),
91
 *  rt-token-not-possessed    (10),
92
 *  rt-too-many-channels    (11),
93
 *  rt-too-many-tokens    (12),
94
 *  rt-too-many-users   (13),
95
 *  rt-unspecified-failure    (14),
96
 *  rt-user-rejected    (15)
97
 * }
98
 *
99
 * ErectDomainRequest ::= [APPLICATION 1] IMPLICIT SEQUENCE
100
 * {
101
 *  subHeight     INTEGER (0..MAX),
102
 *  subInterval     INTEGER (0..MAX)
103
 * }
104
 *
105
 * AttachUserRequest ::= [APPLICATION 10] IMPLICIT SEQUENCE
106
 * {
107
 * }
108
 *
109
 * AttachUserConfirm ::= [APPLICATION 11] IMPLICIT SEQUENCE
110
 * {
111
 *  result        Result,
112
 *  initiator     UserId OPTIONAL
113
 * }
114
 *
115
 * ChannelJoinRequest ::= [APPLICATION 14] IMPLICIT SEQUENCE
116
 * {
117
 *  initiator     UserId,
118
 *  channelId     ChannelId
119
 * }
120
 *
121
 * ChannelJoinConfirm ::= [APPLICATION 15] IMPLICIT SEQUENCE
122
 * {
123
 *  result        Result,
124
 *  initiator     UserId,
125
 *  requested     ChannelId,
126
 *  channelId     ChannelId OPTIONAL
127
 * }
128
 *
129
 * SendDataRequest ::= [APPLICATION 25] IMPLICIT SEQUENCE
130
 * {
131
 *  initiator     UserId,
132
 *  channelId     ChannelId,
133
 *  dataPriority      DataPriority,
134
 *  segmentation      Segmentation,
135
 *  userData      OCTET_STRING
136
 * }
137
 *
138
 * DataPriority ::= CHOICE
139
 * {
140
 *  top       nullptr,
141
 *  high        nullptr,
142
 *  medium        nullptr,
143
 *  low       nullptr,
144
 *  ...
145
 * }
146
 *
147
 * Segmentation ::= BIT_STRING
148
 * {
149
 *  begin       (0),
150
 *  end       (1)
151
 * } (SIZE(2))
152
 *
153
 * SendDataIndication ::= SEQUENCE
154
 * {
155
 *  initiator     UserId,
156
 *  channelId     ChannelId,
157
 *  reliability     BOOLEAN,
158
 *  domainReferenceID   INTEGER (0..65535) OPTIONAL,
159
 *  dataPriority      DataPriority,
160
 *  segmentation      Segmentation,
161
 *  userData      OCTET_STRING,
162
 *  totalDataSize     INTEGER OPTIONAL,
163
 *  nonStandard     SEQUENCE OF NonStandardParameter OPTIONAL,
164
 *  ...
165
 * }
166
 *
167
 */
168
169
static const BYTE callingDomainSelector[1] = { 0x01 };
170
static const BYTE calledDomainSelector[1] = { 0x01 };
171
172
/*
173
static 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
194
const char* mcs_domain_pdu_string(DomainMCSPDU pdu)
195
100
{
196
100
  switch (pdu)
197
100
  {
198
7
    case DomainMCSPDU_PlumbDomainIndication:
199
7
      return "DomainMCSPDU_PlumbDomainIndication";
200
1
    case DomainMCSPDU_ErectDomainRequest:
201
1
      return "DomainMCSPDU_ErectDomainRequest";
202
1
    case DomainMCSPDU_MergeChannelsRequest:
203
1
      return "DomainMCSPDU_MergeChannelsRequest";
204
1
    case DomainMCSPDU_MergeChannelsConfirm:
205
1
      return "DomainMCSPDU_MergeChannelsConfirm";
206
1
    case DomainMCSPDU_PurgeChannelsIndication:
207
1
      return "DomainMCSPDU_PurgeChannelsIndication";
208
2
    case DomainMCSPDU_MergeTokensRequest:
209
2
      return "DomainMCSPDU_MergeTokensRequest";
210
0
    case DomainMCSPDU_MergeTokensConfirm:
211
0
      return "DomainMCSPDU_MergeTokensConfirm";
212
0
    case DomainMCSPDU_PurgeTokensIndication:
213
0
      return "DomainMCSPDU_PurgeTokensIndication";
214
0
    case DomainMCSPDU_DisconnectProviderUltimatum:
215
0
      return "DomainMCSPDU_DisconnectProviderUltimatum";
216
0
    case DomainMCSPDU_RejectMCSPDUUltimatum:
217
0
      return "DomainMCSPDU_RejectMCSPDUUltimatum";
218
0
    case DomainMCSPDU_AttachUserRequest:
219
0
      return "DomainMCSPDU_AttachUserRequest";
220
0
    case DomainMCSPDU_AttachUserConfirm:
221
0
      return "DomainMCSPDU_AttachUserConfirm";
222
2
    case DomainMCSPDU_DetachUserRequest:
223
2
      return "DomainMCSPDU_DetachUserRequest";
224
0
    case DomainMCSPDU_DetachUserIndication:
225
0
      return "DomainMCSPDU_DetachUserIndication";
226
0
    case DomainMCSPDU_ChannelJoinRequest:
227
0
      return "DomainMCSPDU_ChannelJoinRequest";
228
0
    case DomainMCSPDU_ChannelJoinConfirm:
229
0
      return "DomainMCSPDU_ChannelJoinConfirm";
230
0
    case DomainMCSPDU_ChannelLeaveRequest:
231
0
      return "DomainMCSPDU_ChannelLeaveRequest";
232
0
    case DomainMCSPDU_ChannelConveneRequest:
233
0
      return "DomainMCSPDU_ChannelConveneRequest";
234
1
    case DomainMCSPDU_ChannelConveneConfirm:
235
1
      return "DomainMCSPDU_ChannelConveneConfirm";
236
0
    case DomainMCSPDU_ChannelDisbandRequest:
237
0
      return "DomainMCSPDU_ChannelDisbandRequest";
238
0
    case DomainMCSPDU_ChannelDisbandIndication:
239
0
      return "DomainMCSPDU_ChannelDisbandIndication";
240
0
    case DomainMCSPDU_ChannelAdmitRequest:
241
0
      return "DomainMCSPDU_ChannelAdmitRequest";
242
0
    case DomainMCSPDU_ChannelAdmitIndication:
243
0
      return "DomainMCSPDU_ChannelAdmitIndication";
244
1
    case DomainMCSPDU_ChannelExpelRequest:
245
1
      return "DomainMCSPDU_ChannelExpelRequest";
246
1
    case DomainMCSPDU_ChannelExpelIndication:
247
1
      return "DomainMCSPDU_ChannelExpelIndication";
248
22
    case DomainMCSPDU_SendDataRequest:
249
22
      return "DomainMCSPDU_SendDataRequest";
250
28
    case DomainMCSPDU_SendDataIndication:
251
28
      return "DomainMCSPDU_SendDataIndication";
252
1
    case DomainMCSPDU_UniformSendDataRequest:
253
1
      return "DomainMCSPDU_UniformSendDataRequest";
254
0
    case DomainMCSPDU_UniformSendDataIndication:
255
0
      return "DomainMCSPDU_UniformSendDataIndication";
256
0
    case DomainMCSPDU_TokenGrabRequest:
257
0
      return "DomainMCSPDU_TokenGrabRequest";
258
0
    case DomainMCSPDU_TokenGrabConfirm:
259
0
      return "DomainMCSPDU_TokenGrabConfirm";
260
9
    case DomainMCSPDU_TokenInhibitRequest:
261
9
      return "DomainMCSPDU_TokenInhibitRequest";
262
0
    case DomainMCSPDU_TokenInhibitConfirm:
263
0
      return "DomainMCSPDU_TokenInhibitConfirm";
264
0
    case DomainMCSPDU_TokenGiveRequest:
265
0
      return "DomainMCSPDU_TokenGiveRequest";
266
0
    case DomainMCSPDU_TokenGiveIndication:
267
0
      return "DomainMCSPDU_TokenGiveIndication";
268
1
    case DomainMCSPDU_TokenGiveResponse:
269
1
      return "DomainMCSPDU_TokenGiveResponse";
270
1
    case DomainMCSPDU_TokenGiveConfirm:
271
1
      return "DomainMCSPDU_TokenGiveConfirm";
272
0
    case DomainMCSPDU_TokenPleaseRequest:
273
0
      return "DomainMCSPDU_TokenPleaseRequest";
274
2
    case DomainMCSPDU_TokenPleaseConfirm:
275
2
      return "DomainMCSPDU_TokenPleaseConfirm";
276
0
    case DomainMCSPDU_TokenReleaseRequest:
277
0
      return "DomainMCSPDU_TokenReleaseRequest";
278
1
    case DomainMCSPDU_TokenReleaseConfirm:
279
1
      return "DomainMCSPDU_TokenReleaseConfirm";
280
2
    case DomainMCSPDU_TokenTestRequest:
281
2
      return "DomainMCSPDU_TokenTestRequest";
282
1
    case DomainMCSPDU_TokenTestConfirm:
283
1
      return "DomainMCSPDU_TokenTestConfirm";
284
0
    case DomainMCSPDU_enum_length:
285
0
      return "DomainMCSPDU_enum_length";
286
14
    default:
287
14
      return "DomainMCSPDU_UNKNOWN";
288
100
  }
289
100
}
290
291
static BOOL mcs_merge_domain_parameters(wLog* log, DomainParameters* targetParameters,
292
                                        DomainParameters* minimumParameters,
293
                                        DomainParameters* maximumParameters,
294
                                        DomainParameters* pOutParameters);
295
296
static BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData);
297
static BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData);
298
static BOOL mcs_read_domain_mcspdu_header(wLog* log, wStream* s, DomainMCSPDU domainMCSPDU,
299
                                          UINT16* length, DomainMCSPDU* actual);
300
301
static int mcs_initialize_client_channels(rdpMcs* mcs, const rdpSettings* settings)
302
0
{
303
0
  if (!mcs || !settings)
304
0
    return -1;
305
306
0
  mcs->channelCount = freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount);
307
308
0
  if (mcs->channelCount > mcs->channelMaxCount)
309
0
    mcs->channelCount = mcs->channelMaxCount;
310
311
0
  ZeroMemory(mcs->channels, sizeof(rdpMcsChannel) * mcs->channelMaxCount);
312
313
0
  for (UINT32 index = 0; index < mcs->channelCount; index++)
314
0
  {
315
0
    const CHANNEL_DEF* defchannel =
316
0
        freerdp_settings_get_pointer_array(settings, FreeRDP_ChannelDefArray, index);
317
0
    rdpMcsChannel* cur = &mcs->channels[index];
318
0
    WINPR_ASSERT(defchannel);
319
0
    CopyMemory(cur->Name, defchannel->name, CHANNEL_NAME_LEN);
320
0
    cur->options = defchannel->options;
321
0
  }
322
323
0
  return 0;
324
0
}
325
326
/**
327
 * Read a DomainMCSPDU header.
328
 * @param s stream
329
 * @param domainMCSPDU DomainMCSPDU type
330
 * @param length TPKT length
331
 *
332
 * @return \b TRUE for success, \b FALSE otherwise
333
 */
334
335
BOOL mcs_read_domain_mcspdu_header(wLog* log, wStream* s, DomainMCSPDU domainMCSPDU, UINT16* length,
336
                                   DomainMCSPDU* actual)
337
0
{
338
0
  UINT16 li = 0;
339
0
  BYTE choice = 0;
340
341
0
  if (actual)
342
0
    *actual = DomainMCSPDU_invalid;
343
344
0
  WINPR_ASSERT(s);
345
0
  WINPR_ASSERT(domainMCSPDU);
346
0
  WINPR_ASSERT(length);
347
348
0
  if (!tpkt_read_header(s, length))
349
0
    return FALSE;
350
351
0
  if (!tpdu_read_data(s, &li, *length))
352
0
    return FALSE;
353
354
0
  if (!per_read_choice(s, &choice))
355
0
    return FALSE;
356
357
0
  const BYTE val = choice >> 2;
358
0
  const DomainMCSPDU MCSPDU =
359
0
      (val > DomainMCSPDU_enum_length) ? DomainMCSPDU_invalid : (DomainMCSPDU)(val);
360
0
  if (actual)
361
0
    *actual = MCSPDU;
362
363
0
  if (domainMCSPDU != MCSPDU)
364
0
  {
365
0
    WLog_Print(log, WLOG_ERROR, "Expected MCS %s, got %s", mcs_domain_pdu_string(domainMCSPDU),
366
0
               mcs_domain_pdu_string(MCSPDU));
367
0
    return FALSE;
368
0
  }
369
370
0
  return TRUE;
371
0
}
372
373
/**
374
 * Write a DomainMCSPDU header.
375
 * @param s stream
376
 * @param domainMCSPDU DomainMCSPDU type
377
 * @param length TPKT length
378
 */
379
380
BOOL mcs_write_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU, UINT16 length,
381
                                    BYTE options)
382
2.70k
{
383
2.70k
  WINPR_ASSERT(s);
384
2.70k
  WINPR_ASSERT((options & ~0x03) == 0);
385
2.70k
  WINPR_ASSERT((domainMCSPDU & ~0x3F) == 0);
386
387
2.70k
  if (!tpkt_write_header(s, length))
388
0
    return FALSE;
389
2.70k
  if (!tpdu_write_data(s))
390
0
    return FALSE;
391
2.70k
  return per_write_choice(s, (BYTE)((domainMCSPDU << 2) | options));
392
2.70k
}
393
394
/**
395
 * Initialize MCS Domain Parameters.
396
 * @param domainParameters domain parameters
397
 * @param maxChannelIds max channel ids
398
 * @param maxUserIds max user ids
399
 * @param maxTokenIds max token ids
400
 * @param maxMCSPDUsize max MCS PDU size
401
 */
402
403
static BOOL mcs_init_domain_parameters(DomainParameters* domainParameters, UINT32 maxChannelIds,
404
                                       UINT32 maxUserIds, UINT32 maxTokenIds, UINT32 maxMCSPDUsize)
405
185k
{
406
185k
  if (!domainParameters)
407
0
    return FALSE;
408
409
185k
  domainParameters->maxChannelIds = maxChannelIds;
410
185k
  domainParameters->maxUserIds = maxUserIds;
411
185k
  domainParameters->maxTokenIds = maxTokenIds;
412
185k
  domainParameters->maxMCSPDUsize = maxMCSPDUsize;
413
185k
  domainParameters->numPriorities = 1;
414
185k
  domainParameters->minThroughput = 0;
415
185k
  domainParameters->maxHeight = 1;
416
185k
  domainParameters->protocolVersion = 2;
417
185k
  return TRUE;
418
185k
}
419
420
/**
421
 * Read MCS Domain Parameters.
422
 * @param s stream
423
 * @param domainParameters domain parameters
424
 */
425
426
static BOOL mcs_read_domain_parameters(wStream* s, DomainParameters* domainParameters)
427
5.14k
{
428
5.14k
  size_t length = 0;
429
430
5.14k
  if (!s || !domainParameters)
431
0
    return FALSE;
432
433
5.14k
  return ber_read_sequence_tag(s, &length) &&
434
5.08k
         ber_read_integer(s, &(domainParameters->maxChannelIds)) &&
435
5.06k
         ber_read_integer(s, &(domainParameters->maxUserIds)) &&
436
5.02k
         ber_read_integer(s, &(domainParameters->maxTokenIds)) &&
437
4.98k
         ber_read_integer(s, &(domainParameters->numPriorities)) &&
438
4.91k
         ber_read_integer(s, &(domainParameters->minThroughput)) &&
439
4.90k
         ber_read_integer(s, &(domainParameters->maxHeight)) &&
440
4.89k
         ber_read_integer(s, &(domainParameters->maxMCSPDUsize)) &&
441
4.87k
         ber_read_integer(s, &(domainParameters->protocolVersion));
442
5.14k
}
443
444
/**
445
 * Write MCS Domain Parameters.
446
 * @param s stream
447
 * @param domainParameters domain parameters
448
 */
449
450
static BOOL mcs_write_domain_parameters(wLog* log, wStream* s, DomainParameters* domainParameters)
451
0
{
452
0
  BOOL rc = FALSE;
453
0
  size_t length = 0;
454
455
0
  if (!s || !domainParameters)
456
0
    return FALSE;
457
458
0
  wStream* tmps = Stream_New(nullptr, Stream_Capacity(s));
459
460
0
  if (!tmps)
461
0
  {
462
0
    WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
463
0
    return FALSE;
464
0
  }
465
466
0
  if (!ber_write_integer(tmps, domainParameters->maxChannelIds))
467
0
    goto fail;
468
0
  if (!ber_write_integer(tmps, domainParameters->maxUserIds))
469
0
    goto fail;
470
0
  if (!ber_write_integer(tmps, domainParameters->maxTokenIds))
471
0
    goto fail;
472
0
  if (!ber_write_integer(tmps, domainParameters->numPriorities))
473
0
    goto fail;
474
0
  if (!ber_write_integer(tmps, domainParameters->minThroughput))
475
0
    goto fail;
476
0
  if (!ber_write_integer(tmps, domainParameters->maxHeight))
477
0
    goto fail;
478
0
  if (!ber_write_integer(tmps, domainParameters->maxMCSPDUsize))
479
0
    goto fail;
480
0
  if (!ber_write_integer(tmps, domainParameters->protocolVersion))
481
0
    goto fail;
482
0
  length = Stream_GetPosition(tmps);
483
0
  if (!ber_write_sequence_tag(s, length))
484
0
    goto fail;
485
0
  Stream_Write(s, Stream_Buffer(tmps), length);
486
487
0
  rc = TRUE;
488
0
fail:
489
0
  Stream_Free(tmps, TRUE);
490
0
  return rc;
491
0
}
492
493
#ifdef DEBUG_MCS
494
/**
495
 * Print MCS Domain Parameters.
496
 * @param domainParameters domain parameters
497
 */
498
499
static 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
521
/**
522
 * Merge MCS Domain Parameters.
523
 * @param targetParameters target parameters
524
 * @param minimumParameters minimum parameters
525
 * @param maximumParameters maximum parameters
526
 * @param pOutParameters output parameters
527
 *
528
 * @return \b TRUE for success, \b FALSE otherwise
529
 */
530
531
BOOL mcs_merge_domain_parameters(wLog* log, DomainParameters* targetParameters,
532
                                 DomainParameters* minimumParameters,
533
                                 DomainParameters* maximumParameters,
534
                                 DomainParameters* pOutParameters)
535
393
{
536
  /* maxChannelIds */
537
393
  if (!targetParameters || !minimumParameters || !maximumParameters || !pOutParameters)
538
0
    return FALSE;
539
540
393
  if (targetParameters->maxChannelIds >= 4)
541
354
  {
542
354
    pOutParameters->maxChannelIds = targetParameters->maxChannelIds;
543
354
  }
544
39
  else if (maximumParameters->maxChannelIds >= 4)
545
37
  {
546
37
    pOutParameters->maxChannelIds = 4;
547
37
  }
548
2
  else
549
2
  {
550
2
    WLog_Print(log, WLOG_ERROR, "invalid maxChannelIds [%" PRIu32 ", %" PRIu32 "]",
551
2
               targetParameters->maxChannelIds, maximumParameters->maxChannelIds);
552
2
    return FALSE;
553
2
  }
554
555
  /* maxUserIds */
556
557
391
  if (targetParameters->maxUserIds >= 3)
558
375
  {
559
375
    pOutParameters->maxUserIds = targetParameters->maxUserIds;
560
375
  }
561
16
  else if (maximumParameters->maxUserIds >= 3)
562
14
  {
563
14
    pOutParameters->maxUserIds = 3;
564
14
  }
565
2
  else
566
2
  {
567
2
    WLog_Print(log, WLOG_ERROR, "invalid maxUserIds [%" PRIu32 ", %" PRIu32 "]",
568
2
               targetParameters->maxUserIds, maximumParameters->maxUserIds);
569
2
    return FALSE;
570
2
  }
571
572
  /* maxTokenIds */
573
389
  pOutParameters->maxTokenIds = targetParameters->maxTokenIds;
574
575
  /* numPriorities */
576
577
389
  if (minimumParameters->numPriorities <= 1)
578
62
  {
579
62
    pOutParameters->numPriorities = 1;
580
62
  }
581
327
  else
582
327
  {
583
327
    WLog_Print(log, WLOG_ERROR, "invalid numPriorities [%" PRIu32 "]",
584
327
               maximumParameters->numPriorities);
585
327
    return FALSE;
586
327
  }
587
588
  /* minThroughput */
589
62
  pOutParameters->minThroughput = targetParameters->minThroughput;
590
591
  /* maxHeight */
592
593
62
  if ((targetParameters->maxHeight == 1) || (minimumParameters->maxHeight <= 1))
594
55
  {
595
55
    pOutParameters->maxHeight = 1;
596
55
  }
597
7
  else
598
7
  {
599
7
    WLog_Print(log, WLOG_ERROR, "invalid maxHeight [%" PRIu32 ", %" PRIu32 "]",
600
7
               targetParameters->maxHeight, minimumParameters->maxHeight);
601
7
    return FALSE;
602
7
  }
603
604
  /* maxMCSPDUsize */
605
606
55
  if (targetParameters->maxMCSPDUsize >= 1024)
607
47
  {
608
47
    if (targetParameters->maxMCSPDUsize <= 65528)
609
13
    {
610
13
      pOutParameters->maxMCSPDUsize = targetParameters->maxMCSPDUsize;
611
13
    }
612
34
    else if ((minimumParameters->maxMCSPDUsize >= 124) &&
613
34
             (minimumParameters->maxMCSPDUsize <= 65528))
614
1
    {
615
1
      pOutParameters->maxMCSPDUsize = 65528;
616
1
    }
617
33
    else
618
33
    {
619
33
      WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 ", %" PRIu32 "]",
620
33
                 targetParameters->maxMCSPDUsize, minimumParameters->maxMCSPDUsize);
621
33
      return FALSE;
622
33
    }
623
47
  }
624
8
  else
625
8
  {
626
8
    if (maximumParameters->maxMCSPDUsize >= 124)
627
7
    {
628
7
      pOutParameters->maxMCSPDUsize = maximumParameters->maxMCSPDUsize;
629
7
    }
630
1
    else
631
1
    {
632
1
      WLog_Print(log, WLOG_ERROR, "invalid maxMCSPDUsize [%" PRIu32 "]",
633
1
                 maximumParameters->maxMCSPDUsize);
634
1
      return FALSE;
635
1
    }
636
8
  }
637
638
  /* protocolVersion */
639
640
21
  if ((targetParameters->protocolVersion == 2) ||
641
20
      ((minimumParameters->protocolVersion <= 2) && (maximumParameters->protocolVersion >= 2)))
642
3
  {
643
3
    pOutParameters->protocolVersion = 2;
644
3
  }
645
18
  else
646
18
  {
647
18
    WLog_Print(log, WLOG_ERROR,
648
18
               "invalid protocolVersion [%" PRIu32 ", %" PRIu32 ", %" PRIu32 "]",
649
18
               targetParameters->protocolVersion, minimumParameters->protocolVersion,
650
18
               maximumParameters->protocolVersion);
651
18
    return FALSE;
652
18
  }
653
654
3
  return TRUE;
655
21
}
656
657
/**
658
 * Read an MCS Connect Initial PDU.
659
 * msdn{cc240508}
660
 * @param mcs MCS module
661
 * @param s stream
662
 */
663
664
BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)
665
15.4k
{
666
15.4k
  UINT16 li = 0;
667
15.4k
  size_t length = 0;
668
15.4k
  BOOL upwardFlag = FALSE;
669
15.4k
  UINT16 tlength = 0;
670
671
15.4k
  WINPR_ASSERT(mcs);
672
15.4k
  WINPR_ASSERT(s);
673
674
15.4k
  if (!tpkt_read_header(s, &tlength))
675
373
    return FALSE;
676
677
15.0k
  if (!tpdu_read_data(s, &li, tlength))
678
12.0k
    return FALSE;
679
680
3.05k
  if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
681
1.70k
    return FALSE;
682
683
  /* callingDomainSelector (OCTET_STRING) */
684
1.35k
  if (!ber_read_octet_string_tag(s, &length) ||
685
1.32k
      (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
686
28
    return FALSE;
687
688
1.32k
  Stream_Seek(s, length);
689
690
  /* calledDomainSelector (OCTET_STRING) */
691
1.32k
  if (!ber_read_octet_string_tag(s, &length) ||
692
1.30k
      (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
693
19
    return FALSE;
694
695
1.30k
  Stream_Seek(s, length);
696
697
  /* upwardFlag (BOOLEAN) */
698
1.30k
  if (!ber_read_BOOL(s, &upwardFlag))
699
31
    return FALSE;
700
701
  /* targetParameters (DomainParameters) */
702
1.27k
  if (!mcs_read_domain_parameters(s, &mcs->targetParameters))
703
93
    return FALSE;
704
705
  /* minimumParameters (DomainParameters) */
706
1.17k
  if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))
707
47
    return FALSE;
708
709
  /* maximumParameters (DomainParameters) */
710
1.13k
  if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))
711
34
    return FALSE;
712
713
1.09k
  if (!ber_read_octet_string_tag(s, &length) ||
714
1.09k
      (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, length)))
715
9
    return FALSE;
716
717
1.08k
  if (!gcc_read_conference_create_request(s, mcs))
718
696
    return FALSE;
719
720
393
  if (!mcs_merge_domain_parameters(mcs->log, &mcs->targetParameters, &mcs->minimumParameters,
721
393
                                   &mcs->maximumParameters, &mcs->domainParameters))
722
390
    return FALSE;
723
724
3
  return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
725
393
}
726
727
/**
728
 * Write an MCS Connect Initial PDU.
729
 * msdn{cc240508}
730
 * @param s stream
731
 * @param mcs MCS module
732
 * @param userData GCC Conference Create Request
733
 */
734
735
BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData)
736
0
{
737
0
  size_t length = 0;
738
0
  wStream* tmps = nullptr;
739
0
  BOOL ret = FALSE;
740
741
0
  if (!s || !mcs || !userData)
742
0
    return FALSE;
743
744
0
  tmps = Stream_New(nullptr, Stream_Capacity(s));
745
746
0
  if (!tmps)
747
0
  {
748
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
749
0
    return FALSE;
750
0
  }
751
752
  /* callingDomainSelector (OCTET_STRING) */
753
0
  if (!ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector)))
754
0
    goto out;
755
  /* calledDomainSelector (OCTET_STRING) */
756
0
  if (!ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector)))
757
0
    goto out;
758
  /* upwardFlag (BOOLEAN) */
759
0
  ber_write_BOOL(tmps, TRUE);
760
761
  /* targetParameters (DomainParameters) */
762
0
  if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->targetParameters))
763
0
    goto out;
764
765
  /* minimumParameters (DomainParameters) */
766
0
  if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->minimumParameters))
767
0
    goto out;
768
769
  /* maximumParameters (DomainParameters) */
770
0
  if (!mcs_write_domain_parameters(mcs->log, tmps, &mcs->maximumParameters))
771
0
    goto out;
772
773
  /* userData (OCTET_STRING) */
774
0
  if (!ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)))
775
0
    goto out;
776
0
  length = Stream_GetPosition(tmps);
777
  /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */
778
0
  ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);
779
0
  Stream_Write(s, Stream_Buffer(tmps), length);
780
0
  ret = TRUE;
781
0
out:
782
0
  Stream_Free(tmps, TRUE);
783
0
  return ret;
784
0
}
785
786
/**
787
 * Write an MCS Connect Response PDU.
788
 * msdn{cc240508}
789
 * @param s stream
790
 * @param mcs MCS module
791
 * @param userData GCC Conference Create Response
792
 *
793
 * @return \b TRUE for success, \b FALSE otherwise
794
 */
795
796
BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData)
797
0
{
798
0
  size_t length = 0;
799
0
  wStream* tmps = nullptr;
800
0
  BOOL ret = FALSE;
801
802
0
  if (!s || !mcs || !userData)
803
0
    return FALSE;
804
805
0
  tmps = Stream_New(nullptr, Stream_Capacity(s));
806
807
0
  if (!tmps)
808
0
  {
809
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
810
0
    return FALSE;
811
0
  }
812
813
0
  ber_write_enumerated(tmps, 0, MCS_Result_enum_length);
814
0
  if (!ber_write_integer(tmps, 0)) /* calledConnectId */
815
0
    goto out;
816
817
0
  if (!mcs_write_domain_parameters(mcs->log, tmps, &(mcs->domainParameters)))
818
0
    goto out;
819
820
  /* userData (OCTET_STRING) */
821
0
  if (!ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)))
822
0
    goto out;
823
0
  length = Stream_GetPosition(tmps);
824
0
  ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
825
0
  Stream_Write(s, Stream_Buffer(tmps), length);
826
0
  ret = TRUE;
827
0
out:
828
0
  Stream_Free(tmps, TRUE);
829
0
  return ret;
830
0
}
831
832
/**
833
 * Send MCS Connect Initial.
834
 * msdn{cc240508}
835
 * @param mcs mcs module
836
 */
837
838
static BOOL mcs_send_connect_initial(rdpMcs* mcs)
839
0
{
840
0
  int status = -1;
841
0
  size_t length = 0;
842
0
  wStream* s = nullptr;
843
0
  size_t bm = 0;
844
0
  size_t em = 0;
845
0
  wStream* gcc_CCrq = nullptr;
846
847
0
  if (!mcs || !mcs->context)
848
0
    return FALSE;
849
850
0
  mcs_initialize_client_channels(mcs, mcs->context->settings);
851
0
  wStream* client_data = Stream_New(nullptr, 512);
852
853
0
  if (!client_data)
854
0
  {
855
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
856
0
    return FALSE;
857
0
  }
858
859
0
  if (!gcc_write_client_data_blocks(client_data, mcs))
860
0
    goto out;
861
0
  gcc_CCrq = Stream_New(nullptr, 1024);
862
863
0
  if (!gcc_CCrq)
864
0
  {
865
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
866
0
    goto out;
867
0
  }
868
869
0
  if (!gcc_write_conference_create_request(gcc_CCrq, client_data))
870
0
    goto out;
871
0
  length = Stream_GetPosition(gcc_CCrq) + 7;
872
0
  s = Stream_New(nullptr, 1024 + length);
873
874
0
  if (!s)
875
0
  {
876
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
877
0
    goto out;
878
0
  }
879
880
0
  bm = Stream_GetPosition(s);
881
0
  Stream_Seek(s, 7);
882
883
0
  if (!mcs_write_connect_initial(s, mcs, gcc_CCrq))
884
0
  {
885
0
    WLog_Print(mcs->log, WLOG_ERROR, "mcs_write_connect_initial failed!");
886
0
    goto out;
887
0
  }
888
889
0
  em = Stream_GetPosition(s);
890
0
  length = (em - bm);
891
0
  if (length > UINT16_MAX)
892
0
    goto out;
893
0
  if (!Stream_SetPosition(s, bm))
894
0
    goto out;
895
0
  if (!tpkt_write_header(s, (UINT16)length))
896
0
    goto out;
897
0
  if (!tpdu_write_data(s))
898
0
    goto out;
899
0
  if (!Stream_SetPosition(s, em))
900
0
    goto out;
901
0
  Stream_SealLength(s);
902
903
0
  {
904
0
    rdpTransport* transport = freerdp_get_transport(mcs->context);
905
0
    status = transport_write(transport, s);
906
0
  }
907
908
0
out:
909
0
  Stream_Free(s, TRUE);
910
0
  Stream_Free(gcc_CCrq, TRUE);
911
0
  Stream_Free(client_data, TRUE);
912
0
  return ((status >= 0));
913
0
}
914
915
/**
916
 * Read MCS Connect Response.
917
 * msdn{cc240501}
918
 * @param mcs mcs module
919
 */
920
921
BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
922
15.4k
{
923
15.4k
  size_t length = 0;
924
15.4k
  UINT16 tlength = 0;
925
15.4k
  BYTE result = 0;
926
15.4k
  UINT16 li = 0;
927
15.4k
  UINT32 calledConnectId = 0;
928
929
15.4k
  if (!mcs || !s)
930
0
    return FALSE;
931
932
15.4k
  if (!tpkt_read_header(s, &tlength))
933
373
    return FALSE;
934
935
15.0k
  if (!tpdu_read_data(s, &li, tlength))
936
12.0k
    return FALSE;
937
938
3.05k
  if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) ||
939
1.62k
      !ber_read_enumerated(s, &result, MCS_Result_enum_length) ||
940
1.58k
      !ber_read_integer(s, &calledConnectId) ||
941
1.56k
      !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||
942
1.44k
      !ber_read_octet_string_tag(s, &length))
943
1.61k
  {
944
1.61k
    return FALSE;
945
1.61k
  }
946
947
1.43k
  if (!gcc_read_conference_create_response(s, mcs))
948
1.33k
  {
949
1.33k
    WLog_Print(mcs->log, WLOG_ERROR, "gcc_read_conference_create_response failed");
950
1.33k
    return FALSE;
951
1.33k
  }
952
953
103
  return tpkt_ensure_stream_consumed(mcs->log, s, tlength);
954
1.43k
}
955
956
/**
957
 * Send MCS Connect Response.
958
 * msdn{cc240501}
959
 * @param mcs mcs module
960
 */
961
962
BOOL mcs_send_connect_response(rdpMcs* mcs)
963
0
{
964
0
  size_t length = 0;
965
0
  int status = -1;
966
0
  wStream* s = nullptr;
967
0
  size_t bm = 0;
968
0
  size_t em = 0;
969
0
  wStream* gcc_CCrsp = nullptr;
970
971
0
  if (!mcs)
972
0
    return FALSE;
973
974
0
  wStream* server_data = Stream_New(nullptr, 512);
975
976
0
  if (!server_data)
977
0
  {
978
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
979
0
    return FALSE;
980
0
  }
981
982
0
  if (!gcc_write_server_data_blocks(server_data, mcs))
983
0
    goto out;
984
985
0
  gcc_CCrsp = Stream_New(nullptr, 512 + Stream_Capacity(server_data));
986
987
0
  if (!gcc_CCrsp)
988
0
  {
989
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
990
0
    goto out;
991
0
  }
992
993
0
  if (!gcc_write_conference_create_response(gcc_CCrsp, server_data))
994
0
    goto out;
995
0
  length = Stream_GetPosition(gcc_CCrsp) + 7;
996
0
  s = Stream_New(nullptr, length + 1024);
997
998
0
  if (!s)
999
0
  {
1000
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1001
0
    goto out;
1002
0
  }
1003
1004
0
  bm = Stream_GetPosition(s);
1005
0
  Stream_Seek(s, 7);
1006
1007
0
  if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))
1008
0
    goto out;
1009
1010
0
  em = Stream_GetPosition(s);
1011
0
  length = (em - bm);
1012
0
  if (length > UINT16_MAX)
1013
0
    goto out;
1014
0
  if (!Stream_SetPosition(s, bm))
1015
0
    goto out;
1016
0
  if (!tpkt_write_header(s, (UINT16)length))
1017
0
    goto out;
1018
0
  if (!tpdu_write_data(s))
1019
0
    goto out;
1020
0
  if (!Stream_SetPosition(s, em))
1021
0
    goto out;
1022
0
  Stream_SealLength(s);
1023
1024
0
  {
1025
0
    rdpTransport* transport = freerdp_get_transport(mcs->context);
1026
0
    status = transport_write(transport, s);
1027
0
  }
1028
1029
0
out:
1030
0
  Stream_Free(s, TRUE);
1031
0
  Stream_Free(gcc_CCrsp, TRUE);
1032
0
  Stream_Free(server_data, TRUE);
1033
0
  return (status >= 0);
1034
0
}
1035
1036
/**
1037
 * Read MCS Erect Domain Request.
1038
 * msdn{cc240523}
1039
 * @param mcs MCS module to use
1040
 * @param s stream
1041
 */
1042
1043
BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)
1044
0
{
1045
0
  UINT16 length = 0;
1046
0
  UINT32 subHeight = 0;
1047
0
  UINT32 subInterval = 0;
1048
1049
0
  WINPR_ASSERT(mcs);
1050
0
  WINPR_ASSERT(s);
1051
1052
0
  if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ErectDomainRequest, &length,
1053
0
                                     nullptr))
1054
0
    return FALSE;
1055
1056
0
  if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */
1057
0
    return FALSE;
1058
1059
0
  if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */
1060
0
    return FALSE;
1061
1062
0
  return tpkt_ensure_stream_consumed(mcs->log, s, length);
1063
0
}
1064
1065
/**
1066
 * Send MCS Erect Domain Request.
1067
 * msdn{cc240523}
1068
 * @param mcs MCS module to use
1069
 */
1070
1071
BOOL mcs_send_erect_domain_request(rdpMcs* mcs)
1072
0
{
1073
0
  int status = -1;
1074
0
  UINT16 length = 12;
1075
1076
0
  if (!mcs)
1077
0
    return FALSE;
1078
1079
0
  wStream* s = Stream_New(nullptr, length);
1080
1081
0
  if (!s)
1082
0
  {
1083
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1084
0
    return FALSE;
1085
0
  }
1086
1087
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0))
1088
0
    goto out;
1089
0
  if (!per_write_integer(s, 0)) /* subHeight (INTEGER) */
1090
0
    goto out;
1091
0
  if (!per_write_integer(s, 0)) /* subInterval (INTEGER) */
1092
0
    goto out;
1093
0
  Stream_SealLength(s);
1094
1095
0
  rdpTransport* transport = freerdp_get_transport(mcs->context);
1096
0
  status = transport_write(transport, s);
1097
0
out:
1098
0
  Stream_Free(s, TRUE);
1099
0
  return (status >= 0);
1100
0
}
1101
1102
/**
1103
 * Read MCS Attach User Request.
1104
 * msdn{cc240524}
1105
 * @param mcs mcs module
1106
 * @param s stream
1107
 */
1108
1109
BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s)
1110
0
{
1111
0
  UINT16 length = 0;
1112
1113
0
  if (!mcs || !s)
1114
0
    return FALSE;
1115
1116
0
  if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserRequest, &length,
1117
0
                                     nullptr))
1118
0
    return FALSE;
1119
0
  return tpkt_ensure_stream_consumed(mcs->log, s, length);
1120
0
}
1121
1122
/**
1123
 * Send MCS Attach User Request.
1124
 * msdn{cc240524}
1125
 * @param mcs mcs module
1126
 */
1127
1128
BOOL mcs_send_attach_user_request(rdpMcs* mcs)
1129
0
{
1130
0
  int status = -1;
1131
0
  UINT16 length = 8;
1132
1133
0
  if (!mcs)
1134
0
    return FALSE;
1135
1136
0
  wStream* s = Stream_New(nullptr, length);
1137
1138
0
  if (!s)
1139
0
  {
1140
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1141
0
    return FALSE;
1142
0
  }
1143
1144
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0))
1145
0
    goto fail;
1146
1147
0
  Stream_SealLength(s);
1148
1149
0
  rdpTransport* transport = freerdp_get_transport(mcs->context);
1150
0
  status = transport_write(transport, s);
1151
1152
0
fail:
1153
0
  Stream_Free(s, TRUE);
1154
0
  return (status >= 0);
1155
0
}
1156
1157
/**
1158
 * Read MCS Attach User Confirm.
1159
 * msdn{cc240525}
1160
 * @param mcs mcs module
1161
 */
1162
1163
BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s)
1164
0
{
1165
0
  BYTE result = 0;
1166
0
  UINT16 length = 0;
1167
1168
0
  if (!mcs || !s)
1169
0
    return FALSE;
1170
1171
0
  if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_AttachUserConfirm, &length,
1172
0
                                     nullptr))
1173
0
    return FALSE;
1174
0
  if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1175
0
    return FALSE;
1176
0
  if (!per_read_integer16(s, &(mcs->userId), MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1177
0
    return FALSE;
1178
0
  return tpkt_ensure_stream_consumed(mcs->log, s, length);
1179
0
}
1180
1181
/**
1182
 * Send MCS Attach User Confirm.
1183
 * msdn{cc240525}
1184
 * @param mcs mcs module
1185
 */
1186
1187
BOOL mcs_send_attach_user_confirm(rdpMcs* mcs)
1188
0
{
1189
0
  int status = -1;
1190
0
  UINT16 length = 11;
1191
1192
0
  if (!mcs)
1193
0
    return FALSE;
1194
1195
0
  wStream* s = Stream_New(nullptr, length);
1196
1197
0
  if (!s)
1198
0
  {
1199
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1200
0
    return FALSE;
1201
0
  }
1202
1203
0
  mcs->userId = mcs->baseChannelId++;
1204
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2))
1205
0
    goto out;
1206
0
  if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */
1207
0
    goto out;
1208
0
  if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1209
0
    goto out;
1210
0
  Stream_SealLength(s);
1211
1212
0
  rdpTransport* transport = freerdp_get_transport(mcs->context);
1213
0
  status = transport_write(transport, s);
1214
0
out:
1215
0
  Stream_Free(s, TRUE);
1216
0
  return (status >= 0);
1217
0
}
1218
1219
/**
1220
 * Read MCS Channel Join Request.
1221
 * msdn{cc240526}
1222
 * @param mcs mcs module
1223
 * @param s stream
1224
 */
1225
1226
BOOL mcs_recv_channel_join_request(rdpMcs* mcs, const rdpSettings* settings, wStream* s,
1227
                                   UINT16* channelId)
1228
0
{
1229
0
  UINT16 length = 0;
1230
0
  UINT16 userId = 0;
1231
1232
0
  if (!mcs || !s || !channelId)
1233
0
    return FALSE;
1234
1235
0
  if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinRequest, &length,
1236
0
                                     nullptr))
1237
0
    return FALSE;
1238
1239
0
  if (!per_read_integer16(s, &userId, MCS_BASE_CHANNEL_ID))
1240
0
    return FALSE;
1241
0
  if (userId != mcs->userId)
1242
0
  {
1243
0
    if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
1244
0
      mcs->userId = userId;
1245
0
    else
1246
0
      return FALSE;
1247
0
  }
1248
0
  if (!per_read_integer16(s, channelId, 0))
1249
0
    return FALSE;
1250
1251
0
  return tpkt_ensure_stream_consumed(mcs->log, s, length);
1252
0
}
1253
1254
/**
1255
 * Send MCS Channel Join Request.
1256
 * msdn{cc240526}
1257
 *
1258
 * @param mcs mcs module
1259
 * @param channelId channel id
1260
 *
1261
 * @return \b TRUE for success, \b FALSE otherwise
1262
 */
1263
1264
BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId)
1265
0
{
1266
0
  int status = -1;
1267
0
  UINT16 length = 12;
1268
1269
0
  WINPR_ASSERT(mcs);
1270
1271
0
  wStream* s = Stream_New(nullptr, length);
1272
1273
0
  if (!s)
1274
0
  {
1275
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1276
0
    return FALSE;
1277
0
  }
1278
1279
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0))
1280
0
    goto out;
1281
0
  if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID))
1282
0
    goto out;
1283
0
  if (!per_write_integer16(s, channelId, 0))
1284
0
    goto out;
1285
0
  Stream_SealLength(s);
1286
1287
0
  rdpTransport* transport = freerdp_get_transport(mcs->context);
1288
0
  status = transport_write(transport, s);
1289
1290
0
out:
1291
0
  Stream_Free(s, TRUE);
1292
0
  return (status >= 0);
1293
0
}
1294
1295
/**
1296
 * Read MCS Channel Join Confirm.
1297
 * msdn{cc240527}
1298
 * @param mcs mcs module
1299
 */
1300
1301
BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId)
1302
0
{
1303
0
  UINT16 length = 0;
1304
0
  BYTE result = 0;
1305
0
  UINT16 initiator = 0;
1306
0
  UINT16 requested = 0;
1307
1308
0
  WINPR_ASSERT(mcs);
1309
0
  WINPR_ASSERT(channelId);
1310
1311
0
  if (!mcs_read_domain_mcspdu_header(mcs->log, s, DomainMCSPDU_ChannelJoinConfirm, &length,
1312
0
                                     nullptr))
1313
0
    return FALSE;
1314
1315
0
  if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */
1316
0
    return FALSE;
1317
0
  if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1318
0
    return FALSE;
1319
0
  if (!per_read_integer16(s, &requested, 0)) /* requested (ChannelId) */
1320
0
    return FALSE;
1321
0
  if (!per_read_integer16(s, channelId, 0)) /* channelId */
1322
0
    return FALSE;
1323
0
  return tpkt_ensure_stream_consumed(mcs->log, s, length);
1324
0
}
1325
1326
/**
1327
 * Send MCS Channel Join Confirm.
1328
 * msdn{cc240527}
1329
 * @param mcs mcs module
1330
 */
1331
1332
BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId)
1333
0
{
1334
0
  int status = -1;
1335
0
  UINT16 length = 15;
1336
1337
0
  if (!mcs)
1338
0
    return FALSE;
1339
1340
0
  wStream* s = Stream_New(nullptr, length);
1341
1342
0
  if (!s)
1343
0
  {
1344
0
    WLog_Print(mcs->log, WLOG_ERROR, "Stream_New failed!");
1345
0
    return FALSE;
1346
0
  }
1347
1348
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2))
1349
0
    goto fail;
1350
0
  if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */
1351
0
    goto fail;
1352
0
  if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
1353
0
    goto fail;
1354
0
  if (!per_write_integer16(s, channelId, 0)) /* requested (ChannelId) */
1355
0
    goto fail;
1356
0
  if (!per_write_integer16(s, channelId, 0)) /* channelId */
1357
0
    goto fail;
1358
0
  Stream_SealLength(s);
1359
1360
0
  {
1361
0
    rdpTransport* transport = freerdp_get_transport(mcs->context);
1362
0
    status = transport_write(transport, s);
1363
0
  }
1364
1365
0
fail:
1366
0
  Stream_Free(s, TRUE);
1367
0
  return (status >= 0);
1368
0
}
1369
1370
/**
1371
 * Receive MCS Disconnect Provider Ultimatum PDU.
1372
 * @param mcs mcs module
1373
 */
1374
1375
BOOL mcs_recv_disconnect_provider_ultimatum(WINPR_ATTR_UNUSED rdpMcs* mcs, wStream* s, int* reason)
1376
748
{
1377
748
  BYTE b1 = 0;
1378
748
  BYTE b2 = 0;
1379
1380
748
  WINPR_ASSERT(mcs);
1381
748
  WINPR_ASSERT(s);
1382
748
  WINPR_ASSERT(reason);
1383
1384
  /*
1385
   * http://msdn.microsoft.com/en-us/library/cc240872.aspx:
1386
   *
1387
   * PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
1388
   * 21 80
1389
   *
1390
   * 0x21:
1391
   * 0 - --\
1392
   * 0 -   |
1393
   * 1 -   | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
1394
   * 0 -   | of type DisconnectProviderUltimatum
1395
   * 0 -   |
1396
   * 0 - --/
1397
   * 0 - --\
1398
   * 1 -   |
1399
   *       | DisconnectProviderUltimatum::reason = rn-user-requested (3)
1400
   * 0x80: |
1401
   * 1 - --/
1402
   * 0 - padding
1403
   * 0 - padding
1404
   * 0 - padding
1405
   * 0 - padding
1406
   * 0 - padding
1407
   * 0 - padding
1408
   * 0 - padding
1409
   */
1410
1411
748
  if (!Stream_CheckAndLogRequiredLengthWLog(mcs->log, s, 1))
1412
2
    return FALSE;
1413
1414
746
  Stream_Rewind_UINT8(s);
1415
746
  Stream_Read_UINT8(s, b1);
1416
746
  Stream_Read_UINT8(s, b2);
1417
746
  *reason = ((b1 & 0x01) << 1) | (b2 >> 7);
1418
746
  return TRUE;
1419
748
}
1420
1421
/**
1422
 * Send MCS Disconnect Provider Ultimatum PDU.
1423
 * @param mcs mcs module
1424
 */
1425
1426
BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs, enum Disconnect_Ultimatum reason)
1427
0
{
1428
0
  int status = -1;
1429
0
  UINT16 length = 9;
1430
1431
0
  WINPR_ASSERT(mcs);
1432
1433
0
  wStream* s = Stream_New(nullptr, length);
1434
1435
0
  if (!s)
1436
0
    goto fail;
1437
1438
0
  if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1))
1439
0
    goto fail;
1440
1441
0
  if (!per_write_enumerated(s, 0x80, WINPR_ASSERTING_INT_CAST(BYTE, reason)))
1442
0
    goto fail;
1443
1444
0
  {
1445
0
    rdpTransport* transport = freerdp_get_transport(mcs->context);
1446
0
    status = transport_write(transport, s);
1447
0
  }
1448
1449
0
fail:
1450
0
  WLog_Print(mcs->log, WLOG_DEBUG, "sending DisconnectProviderUltimatum(%s)",
1451
0
             freerdp_disconnect_reason_string((int)reason));
1452
0
  Stream_Free(s, TRUE);
1453
0
  return (status >= 0);
1454
0
}
1455
1456
BOOL mcs_client_begin(rdpMcs* mcs)
1457
0
{
1458
0
  if (!mcs || !mcs->context)
1459
0
    return FALSE;
1460
1461
  /* First transition state, we need this to trigger session recording */
1462
0
  if (!mcs_send_connect_initial(mcs))
1463
0
  {
1464
0
    freerdp_set_last_error_if_not(mcs->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
1465
1466
0
    WLog_Print(mcs->log, WLOG_ERROR, "Error: unable to send MCS Connect Initial");
1467
0
    return FALSE;
1468
0
  }
1469
1470
0
  return TRUE;
1471
0
}
1472
1473
/**
1474
 * Instantiate new MCS module.
1475
 * @param context rdpContext to use
1476
 * @return new MCS module
1477
 */
1478
1479
rdpMcs* mcs_new(rdpContext* context)
1480
46.2k
{
1481
46.2k
  rdpMcs* mcs = (rdpMcs*)calloc(1, sizeof(rdpMcs));
1482
1483
46.2k
  if (!mcs)
1484
0
    return nullptr;
1485
46.2k
  mcs->log = WLog_Get(MCS_TAG);
1486
46.2k
  WINPR_ASSERT(mcs->log);
1487
1488
46.2k
  mcs->context = context;
1489
46.2k
  mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);
1490
46.2k
  mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);
1491
46.2k
  mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);
1492
46.2k
  mcs_init_domain_parameters(&mcs->domainParameters, 0, 0, 0, 0xFFFF);
1493
46.2k
  mcs->channelCount = 0;
1494
46.2k
  mcs->channelMaxCount = CHANNEL_MAX_COUNT;
1495
46.2k
  mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;
1496
46.2k
  mcs->channels = (rdpMcsChannel*)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
1497
1498
46.2k
  if (!mcs->channels)
1499
0
    goto out_free;
1500
1501
46.2k
  return mcs;
1502
0
out_free:
1503
0
  free(mcs);
1504
0
  return nullptr;
1505
46.2k
}
1506
1507
/**
1508
 * Free MCS module.
1509
 * @param mcs MCS module to be freed
1510
 */
1511
1512
void mcs_free(rdpMcs* mcs)
1513
46.2k
{
1514
46.2k
  if (mcs)
1515
46.2k
  {
1516
46.2k
    free(mcs->channels);
1517
46.2k
    free(mcs);
1518
46.2k
  }
1519
46.2k
}
1520
1521
BOOL mcs_server_apply_to_settings(const rdpMcs* mcs, rdpSettings* settings)
1522
0
{
1523
0
  BOOL rc = FALSE;
1524
1525
0
  WINPR_ASSERT(mcs);
1526
0
  WINPR_ASSERT(settings);
1527
1528
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, mcs->channelCount))
1529
0
    goto fail;
1530
1531
0
  for (UINT32 x = 0; x < mcs->channelCount; x++)
1532
0
  {
1533
0
    const rdpMcsChannel* current = &mcs->channels[x];
1534
0
    CHANNEL_DEF def = WINPR_C_ARRAY_INIT;
1535
0
    def.options = current->options;
1536
0
    memcpy(def.name, current->Name, sizeof(def.name));
1537
0
    if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ChannelDefArray, x, &def))
1538
0
      goto fail;
1539
0
  }
1540
1541
0
  rc = TRUE;
1542
0
fail:
1543
0
  if (!rc)
1544
0
    WLog_Print(mcs->log, WLOG_WARN, "failed to apply settings");
1545
1546
0
  return rc;
1547
0
}