Coverage Report

Created: 2025-07-11 06:46

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