Coverage Report

Created: 2026-10-28 06:54

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