Coverage Report

Created: 2024-09-08 06:20

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