Coverage Report

Created: 2026-10-15 06:31

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