Coverage Report

Created: 2024-05-20 06:11

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