Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/capabilities.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RDP Capability Sets
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *   http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/wtsapi.h>
21
#include <winpr/assert.h>
22
#include <winpr/cast.h>
23
#include <freerdp/config.h>
24
25
#include "settings.h"
26
#include "capabilities.h"
27
#include "fastpath.h"
28
29
#include <winpr/crt.h>
30
#include <winpr/rpc.h>
31
32
#include <freerdp/log.h>
33
34
/* [MS-RDPBCGR] 2.2.7.1.4.2
35
Revision 2 (TS_BITMAPCACHE_CAPABILITYSET_REV2)
36
*/
37
static const size_t bitmapCacheV2CellInfoLimits[] = { 600, 600, 65536, 4096, 2048 };
38
39
static const char* const CAPSET_TYPE_STRINGS[] = { "Unknown",
40
                                                 "General",
41
                                                 "Bitmap",
42
                                                 "Order",
43
                                                 "Bitmap Cache",
44
                                                 "Control",
45
                                                 "Unknown",
46
                                                 "Window Activation",
47
                                                 "Pointer",
48
                                                 "Share",
49
                                                 "Color Cache",
50
                                                 "Unknown",
51
                                                 "Sound",
52
                                                 "Input",
53
                                                 "Font",
54
                                                 "Brush",
55
                                                 "Glyph Cache",
56
                                                 "Offscreen Bitmap Cache",
57
                                                 "Bitmap Cache Host Support",
58
                                                 "Bitmap Cache v2",
59
                                                 "Virtual Channel",
60
                                                 "DrawNineGrid Cache",
61
                                                 "Draw GDI+ Cache",
62
                                                 "Remote Programs",
63
                                                 "Window List",
64
                                                 "Desktop Composition",
65
                                                 "Multifragment Update",
66
                                                 "Large Pointer",
67
                                                 "Surface Commands",
68
                                                 "Bitmap Codecs",
69
                                                 "Frame Acknowledge" };
70
71
WINPR_ATTR_NODISCARD
72
static const char* get_capability_name(UINT16 type)
73
2.03k
{
74
2.03k
  if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
75
1.77k
    return "<unknown>";
76
77
259
  return CAPSET_TYPE_STRINGS[type];
78
2.03k
}
79
80
#ifdef WITH_DEBUG_CAPABILITIES
81
static BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving);
82
#endif
83
84
/* CODEC_GUID_REMOTEFX: 0x76772F12BD724463AFB3B73C9C6F7886 */
85
86
static const GUID CODEC_GUID_REMOTEFX = {
87
  0x76772F12, 0xBD72, 0x4463, { 0xAF, 0xB3, 0xB7, 0x3C, 0x9C, 0x6F, 0x78, 0x86 }
88
};
89
90
/* CODEC_GUID_NSCODEC 0xCA8D1BB9000F154F589FAE2D1A87E2D6 */
91
92
static const GUID CODEC_GUID_NSCODEC = {
93
  0xCA8D1BB9, 0x000F, 0x154F, { 0x58, 0x9F, 0xAE, 0x2D, 0x1A, 0x87, 0xE2, 0xD6 }
94
};
95
96
/* CODEC_GUID_IGNORE 0x9C4351A6353542AE910CCDFCE5760B58 */
97
98
static const GUID CODEC_GUID_IGNORE = {
99
  0x9C4351A6, 0x3535, 0x42AE, { 0x91, 0x0C, 0xCD, 0xFC, 0xE5, 0x76, 0x0B, 0x58 }
100
};
101
102
/* CODEC_GUID_IMAGE_REMOTEFX 0x2744CCD49D8A4E74803C0ECBEEA19C54 */
103
104
static const GUID CODEC_GUID_IMAGE_REMOTEFX = {
105
  0x2744CCD4, 0x9D8A, 0x4E74, { 0x80, 0x3C, 0x0E, 0xCB, 0xEE, 0xA1, 0x9C, 0x54 }
106
};
107
108
#if defined(WITH_JPEG)
109
/* CODEC_GUID_JPEG 0x430C9EED1BAF4CE6869ACB8B37B66237 */
110
111
static const GUID CODEC_GUID_JPEG = {
112
  0x430C9EED, 0x1BAF, 0x4CE6, { 0x86, 0x9A, 0xCB, 0x8B, 0x37, 0xB6, 0x62, 0x37 }
113
};
114
#endif
115
116
WINPR_ATTR_NODISCARD
117
static BOOL rdp_read_capability_set_header(wLog* log, wStream* s, UINT16* length, UINT16* type)
118
39.1k
{
119
39.1k
  WINPR_ASSERT(s);
120
39.1k
  WINPR_ASSERT(length);
121
39.1k
  WINPR_ASSERT(type);
122
123
39.1k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
124
0
    return FALSE;
125
39.1k
  Stream_Read_UINT16(s, *type);   /* capabilitySetType */
126
39.1k
  Stream_Read_UINT16(s, *length); /* lengthCapability */
127
39.1k
  return (*length >= 4);
128
39.1k
}
129
130
static void rdp_write_capability_set_header(wStream* s, UINT16 length, UINT16 type)
131
0
{
132
0
  WINPR_ASSERT(s);
133
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
134
0
  Stream_Write_UINT16(s, type);   /* capabilitySetType */
135
0
  Stream_Write_UINT16(s, length); /* lengthCapability */
136
0
}
137
138
WINPR_ATTR_NODISCARD
139
static size_t rdp_capability_set_start(wLog* log, wStream* s)
140
0
{
141
0
  size_t header = Stream_GetPosition(s);
142
0
  if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), CAPSET_HEADER_LENGTH))
143
0
    return SIZE_MAX;
144
0
  Stream_Zero(s, CAPSET_HEADER_LENGTH);
145
0
  return header;
146
0
}
147
148
WINPR_ATTR_NODISCARD
149
static BOOL rdp_capability_set_finish(wStream* s, size_t header, UINT16 type)
150
0
{
151
0
  const size_t footer = Stream_GetPosition(s);
152
0
  if (header > footer)
153
0
    return FALSE;
154
0
  if (header > UINT16_MAX)
155
0
    return FALSE;
156
0
  const size_t length = footer - header;
157
0
  if ((Stream_Capacity(s) < header + 4ULL) || (length > UINT16_MAX))
158
0
    return FALSE;
159
0
  if (!Stream_SetPosition(s, header))
160
0
    return FALSE;
161
0
  rdp_write_capability_set_header(s, (UINT16)length, type);
162
0
  return Stream_SetPosition(s, footer);
163
0
}
164
165
WINPR_ATTR_NODISCARD
166
static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSettings* src)
167
1.02k
{
168
1.02k
  WINPR_ASSERT(settings);
169
1.02k
  WINPR_ASSERT(src);
170
171
1.02k
  if (settings->ServerMode)
172
903
  {
173
903
    settings->OsMajorType = src->OsMajorType;
174
903
    settings->OsMinorType = src->OsMinorType;
175
903
  }
176
177
1.02k
  settings->CapsProtocolVersion = src->CapsProtocolVersion;
178
1.02k
  settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
179
1.02k
  settings->LongCredentialsSupported = src->LongCredentialsSupported;
180
1.02k
  settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
181
1.02k
  if (!src->FastPathOutput)
182
453
    settings->FastPathOutput = FALSE;
183
184
1.02k
  if (!src->SaltedChecksum)
185
555
    settings->SaltedChecksum = FALSE;
186
187
1.02k
  if (!settings->ServerMode)
188
119
  {
189
    /*
190
     * Note: refreshRectSupport and suppressOutputSupport are
191
     * server-only flags indicating to the client weather the
192
     * respective PDUs are supported. See MS-RDPBCGR 2.2.7.1.1
193
     */
194
119
    if (!src->RefreshRect)
195
50
      settings->RefreshRect = FALSE;
196
197
119
    if (!src->SuppressOutput)
198
60
      settings->SuppressOutput = FALSE;
199
119
  }
200
1.02k
  return TRUE;
201
1.02k
}
202
203
/*
204
 * Read general capability set.
205
 * msdn{cc240549}
206
 */
207
WINPR_ATTR_NODISCARD
208
static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* settings)
209
1.06k
{
210
1.06k
  UINT16 extraFlags = 0;
211
1.06k
  BYTE refreshRectSupport = 0;
212
1.06k
  BYTE suppressOutputSupport = 0;
213
214
1.06k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
215
8
    return FALSE;
216
217
1.05k
  WINPR_ASSERT(settings);
218
1.05k
  Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
219
1.05k
  Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
220
221
1.05k
  Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
222
1.05k
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
223
593
  {
224
593
    WLog_Print(log, WLOG_ERROR,
225
593
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
226
593
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
227
593
               settings->CapsProtocolVersion,
228
593
               WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
229
593
    if (settings->CapsProtocolVersion == 0x0000)
230
558
    {
231
558
      WLog_Print(log, WLOG_WARN,
232
558
                 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
233
558
                 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
234
558
                 settings->CapsProtocolVersion);
235
558
      settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
236
558
    }
237
35
    else
238
35
      return FALSE;
239
593
  }
240
1.02k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
241
1.02k
  Stream_Read_UINT16(
242
1.02k
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
243
1.02k
  Stream_Read_UINT16(s, extraFlags);             /* extraFlags (2 bytes) */
244
1.02k
  Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
245
1.02k
  Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
246
1.02k
  Stream_Read_UINT16(
247
1.02k
      s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
248
1.02k
  Stream_Read_UINT8(s, refreshRectSupport);      /* refreshRectSupport (1 byte) */
249
1.02k
  Stream_Read_UINT8(s, suppressOutputSupport);   /* suppressOutputSupport (1 byte) */
250
1.02k
  settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) != 0;
251
1.02k
  settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) != 0;
252
253
1.02k
  settings->AutoReconnectionPacketSupported = (extraFlags & AUTORECONNECT_SUPPORTED) != 0;
254
1.02k
  settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) != 0;
255
1.02k
  settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) != 0;
256
1.02k
  settings->RefreshRect = refreshRectSupport;
257
1.02k
  settings->SuppressOutput = suppressOutputSupport;
258
259
1.02k
  return TRUE;
260
1.05k
}
261
262
/*
263
 * Write general capability set.
264
 * msdn{cc240549}
265
 */
266
WINPR_ATTR_NODISCARD
267
static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
268
0
{
269
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
270
0
    return FALSE;
271
272
0
  const size_t header = rdp_capability_set_start(log, s);
273
0
  UINT16 extraFlags = 0;
274
275
0
  WINPR_ASSERT(settings);
276
0
  if (settings->LongCredentialsSupported)
277
0
    extraFlags |= LONG_CREDENTIALS_SUPPORTED;
278
279
0
  if (settings->NoBitmapCompressionHeader)
280
0
    extraFlags |= NO_BITMAP_COMPRESSION_HDR;
281
282
0
  if (settings->AutoReconnectionPacketSupported)
283
0
    extraFlags |= AUTORECONNECT_SUPPORTED;
284
285
0
  if (settings->FastPathOutput)
286
0
    extraFlags |= FASTPATH_OUTPUT_SUPPORTED;
287
288
0
  if (settings->SaltedChecksum)
289
0
    extraFlags |= ENC_SALTED_CHECKSUM;
290
291
0
  if ((settings->OsMajorType > UINT16_MAX) || (settings->OsMinorType > UINT16_MAX))
292
0
  {
293
0
    WLog_Print(log, WLOG_ERROR,
294
0
               "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32
295
0
               " they need to be smaller %04" PRIx32,
296
0
               settings->OsMajorType, settings->OsMinorType,
297
0
               WINPR_CXX_COMPAT_CAST(UINT32, UINT16_MAX));
298
0
    return FALSE;
299
0
  }
300
0
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
301
0
  {
302
0
    WLog_Print(log, WLOG_ERROR,
303
0
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
304
0
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
305
0
               settings->CapsProtocolVersion,
306
0
               WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
307
0
    return FALSE;
308
0
  }
309
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMajorType); /* osMajorType (2 bytes) */
310
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMinorType); /* osMinorType (2 bytes) */
311
0
  Stream_Write_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
312
0
  Stream_Write_UINT16(s, 0);                             /* pad2OctetsA (2 bytes) */
313
0
  Stream_Write_UINT16(
314
0
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
315
0
  Stream_Write_UINT16(s, extraFlags);            /* extraFlags (2 bytes) */
316
0
  Stream_Write_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
317
0
  Stream_Write_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
318
0
  Stream_Write_UINT16(
319
0
      s, settings->CapsGeneralCompressionLevel);           /* generalCompressionLevel (2 bytes) */
320
0
  Stream_Write_UINT8(s, settings->RefreshRect ? 1 : 0);    /* refreshRectSupport (1 byte) */
321
0
  Stream_Write_UINT8(s, settings->SuppressOutput ? 1 : 0); /* suppressOutputSupport (1 byte) */
322
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_GENERAL);
323
0
}
324
325
#ifdef WITH_DEBUG_CAPABILITIES
326
WINPR_ATTR_NODISCARD
327
static BOOL rdp_print_general_capability_set(wLog* log, wStream* s)
328
{
329
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
330
    return FALSE;
331
332
  WLog_Print(log, WLOG_TRACE,
333
             "GeneralCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
334
  const uint16_t osMinorType = Stream_Get_UINT16(s);     /* osMajorType (2 bytes) */
335
  const uint16_t osMajorType = Stream_Get_UINT16(s);     /* osMinorType (2 bytes) */
336
  const uint16_t protocolVersion = Stream_Get_UINT16(s); /* protocolVersion (2 bytes) */
337
  const uint16_t pad2OctetsA = Stream_Get_UINT16(s);     /* pad2OctetsA (2 bytes) */
338
  const uint16_t generalCompressionTypes =
339
      Stream_Get_UINT16(s);                         /* generalCompressionTypes (2 bytes) */
340
  const uint16_t extraFlags = Stream_Get_UINT16(s); /* extraFlags (2 bytes) */
341
  const uint16_t updateCapabilityFlag = Stream_Get_UINT16(s); /* updateCapabilityFlag (2 bytes) */
342
  const uint16_t remoteUnshareFlag = Stream_Get_UINT16(s);    /* remoteUnshareFlag (2 bytes) */
343
  const uint16_t generalCompressionLevel =
344
      Stream_Get_UINT16(s);                               /* generalCompressionLevel (2 bytes) */
345
  const uint8_t refreshRectSupport = Stream_Get_UINT8(s); /* refreshRectSupport (1 byte) */
346
  const uint8_t suppressOutputSupport = Stream_Get_UINT8(s); /* suppressOutputSupport (1 byte) */
347
  WLog_Print(log, WLOG_TRACE, "\tosMajorType: 0x%04" PRIX16 "", osMajorType);
348
  WLog_Print(log, WLOG_TRACE, "\tosMinorType: 0x%04" PRIX16 "", osMinorType);
349
  WLog_Print(log, WLOG_TRACE, "\tprotocolVersion: 0x%04" PRIX16 "", protocolVersion);
350
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
351
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionTypes: 0x%04" PRIX16 "",
352
             generalCompressionTypes);
353
  WLog_Print(log, WLOG_TRACE, "\textraFlags: 0x%04" PRIX16 "", extraFlags);
354
  WLog_Print(log, WLOG_TRACE, "\tupdateCapabilityFlag: 0x%04" PRIX16 "", updateCapabilityFlag);
355
  WLog_Print(log, WLOG_TRACE, "\tremoteUnshareFlag: 0x%04" PRIX16 "", remoteUnshareFlag);
356
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionLevel: 0x%04" PRIX16 "",
357
             generalCompressionLevel);
358
  WLog_Print(log, WLOG_TRACE, "\trefreshRectSupport: 0x%02" PRIX8 "", refreshRectSupport);
359
  WLog_Print(log, WLOG_TRACE, "\tsuppressOutputSupport: 0x%02" PRIX8 "", suppressOutputSupport);
360
  return TRUE;
361
}
362
#endif
363
364
WINPR_ATTR_NODISCARD
365
static BOOL rdp_apply_bitmap_capability_set(rdpSettings* settings, const rdpSettings* src)
366
458
{
367
458
  WINPR_ASSERT(settings);
368
458
  WINPR_ASSERT(src);
369
370
458
  if (!settings->ServerMode)
371
96
  {
372
96
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
373
96
                                     freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
374
0
      return FALSE;
375
96
  }
376
377
458
  if (!src->DesktopResize)
378
262
    settings->DesktopResize = FALSE;
379
380
458
  if (!settings->ServerMode && settings->DesktopResize)
381
41
  {
382
    /* The server may request a different desktop size during Deactivation-Reactivation sequence
383
     */
384
41
    settings->DesktopWidth = src->DesktopWidth;
385
41
    settings->DesktopHeight = src->DesktopHeight;
386
41
  }
387
388
458
  if (settings->DrawAllowSkipAlpha)
389
221
    settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
390
391
458
  if (settings->DrawAllowDynamicColorFidelity)
392
250
    settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
393
394
458
  if (settings->DrawAllowColorSubsampling)
395
0
    settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
396
397
458
  return TRUE;
398
458
}
399
400
/*
401
 * Read bitmap capability set.
402
 * msdn{cc240554}
403
 */
404
WINPR_ATTR_NODISCARD
405
static BOOL rdp_read_bitmap_capability_set(wLog* log, wStream* s, rdpSettings* settings)
406
471
{
407
471
  BYTE drawingFlags = 0;
408
471
  UINT16 desktopWidth = 0;
409
471
  UINT16 desktopHeight = 0;
410
471
  UINT16 desktopResizeFlag = 0;
411
471
  UINT16 preferredBitsPerPixel = 0;
412
413
471
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
414
13
    return FALSE;
415
416
458
  Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
417
458
  Stream_Seek_UINT16(s);                        /* receive1BitPerPixel (2 bytes) */
418
458
  Stream_Seek_UINT16(s);                        /* receive4BitsPerPixel (2 bytes) */
419
458
  Stream_Seek_UINT16(s);                        /* receive8BitsPerPixel (2 bytes) */
420
458
  Stream_Read_UINT16(s, desktopWidth);          /* desktopWidth (2 bytes) */
421
458
  Stream_Read_UINT16(s, desktopHeight);         /* desktopHeight (2 bytes) */
422
458
  Stream_Seek_UINT16(s);                        /* pad2Octets (2 bytes) */
423
458
  Stream_Read_UINT16(s, desktopResizeFlag);     /* desktopResizeFlag (2 bytes) */
424
458
  Stream_Seek_UINT16(s);                        /* bitmapCompressionFlag (2 bytes) */
425
458
  Stream_Seek_UINT8(s);                         /* highColorFlags (1 byte) */
426
458
  Stream_Read_UINT8(s, drawingFlags);           /* drawingFlags (1 byte) */
427
458
  Stream_Seek_UINT16(s);                        /* multipleRectangleSupport (2 bytes) */
428
458
  Stream_Seek_UINT16(s);                        /* pad2OctetsB (2 bytes) */
429
430
458
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
431
0
    return FALSE;
432
458
  settings->DesktopResize = desktopResizeFlag;
433
458
  settings->DesktopWidth = desktopWidth;
434
458
  settings->DesktopHeight = desktopHeight;
435
458
  settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) != 0;
436
458
  settings->DrawAllowDynamicColorFidelity =
437
458
      (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) != 0;
438
458
  settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) != 0;
439
440
458
  return TRUE;
441
458
}
442
443
/*
444
 * Write bitmap capability set.
445
 * msdn{cc240554}
446
 */
447
WINPR_ATTR_NODISCARD
448
static BOOL rdp_write_bitmap_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
449
0
{
450
0
  BYTE drawingFlags = 0;
451
0
  UINT16 preferredBitsPerPixel = 0;
452
453
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
454
0
    return FALSE;
455
456
0
  const size_t header = rdp_capability_set_start(log, s);
457
458
0
  WINPR_ASSERT(settings);
459
0
  if (settings->DrawAllowSkipAlpha)
460
0
    drawingFlags |= DRAW_ALLOW_SKIP_ALPHA;
461
462
0
  if (settings->DrawAllowDynamicColorFidelity)
463
0
    drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY;
464
465
0
  if (settings->DrawAllowColorSubsampling)
466
0
    drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; /* currently unimplemented */
467
468
  /* While bitmap_decode.c now implements YCoCg, in turning it
469
   * on we have found Microsoft is inconsistent on whether to invert R & B.
470
   * And it's not only from one server to another; on Win7/2008R2, it appears
471
   * to send the main content with a different inversion than the Windows
472
   * button!  So... don't advertise that we support YCoCg and the server
473
   * will not send it.  YCoCg is still needed for EGFX, but it at least
474
   * appears consistent in its use.
475
   */
476
477
0
  if ((freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) > UINT16_MAX) ||
478
0
      (settings->DesktopWidth > UINT16_MAX) || (settings->DesktopHeight > UINT16_MAX))
479
0
    return FALSE;
480
481
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
482
0
    preferredBitsPerPixel = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
483
0
  else
484
0
    preferredBitsPerPixel = 8;
485
486
0
  Stream_Write_UINT16(s, preferredBitsPerPixel);           /* preferredBitsPerPixel (2 bytes) */
487
0
  Stream_Write_UINT16(s, 1);                               /* receive1BitPerPixel (2 bytes) */
488
0
  Stream_Write_UINT16(s, 1);                               /* receive4BitsPerPixel (2 bytes) */
489
0
  Stream_Write_UINT16(s, 1);                               /* receive8BitsPerPixel (2 bytes) */
490
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopWidth);  /* desktopWidth (2 bytes) */
491
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopHeight); /* desktopHeight (2 bytes) */
492
0
  Stream_Write_UINT16(s, 0);                               /* pad2Octets (2 bytes) */
493
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopResize); /* desktopResizeFlag (2 bytes) */
494
0
  Stream_Write_UINT16(s, 1);                               /* bitmapCompressionFlag (2 bytes) */
495
0
  Stream_Write_UINT8(s, 0);                                /* highColorFlags (1 byte) */
496
0
  Stream_Write_UINT8(s, drawingFlags);                     /* drawingFlags (1 byte) */
497
0
  Stream_Write_UINT16(s, 1); /* multipleRectangleSupport (2 bytes) */
498
0
  Stream_Write_UINT16(s, 0); /* pad2OctetsB (2 bytes) */
499
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP);
500
0
}
501
502
#ifdef WITH_DEBUG_CAPABILITIES
503
WINPR_ATTR_NODISCARD
504
static BOOL rdp_print_bitmap_capability_set(wLog* log, wStream* s)
505
{
506
  UINT16 preferredBitsPerPixel = 0;
507
  UINT16 receive1BitPerPixel = 0;
508
  UINT16 receive4BitsPerPixel = 0;
509
  UINT16 receive8BitsPerPixel = 0;
510
  UINT16 desktopWidth = 0;
511
  UINT16 desktopHeight = 0;
512
  UINT16 pad2Octets = 0;
513
  UINT16 desktopResizeFlag = 0;
514
  UINT16 bitmapCompressionFlag = 0;
515
  BYTE highColorFlags = 0;
516
  BYTE drawingFlags = 0;
517
  UINT16 multipleRectangleSupport = 0;
518
  UINT16 pad2OctetsB = 0;
519
  WLog_Print(log, WLOG_TRACE,
520
             "BitmapCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
521
522
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
523
    return FALSE;
524
525
  Stream_Read_UINT16(s, preferredBitsPerPixel);    /* preferredBitsPerPixel (2 bytes) */
526
  Stream_Read_UINT16(s, receive1BitPerPixel);      /* receive1BitPerPixel (2 bytes) */
527
  Stream_Read_UINT16(s, receive4BitsPerPixel);     /* receive4BitsPerPixel (2 bytes) */
528
  Stream_Read_UINT16(s, receive8BitsPerPixel);     /* receive8BitsPerPixel (2 bytes) */
529
  Stream_Read_UINT16(s, desktopWidth);             /* desktopWidth (2 bytes) */
530
  Stream_Read_UINT16(s, desktopHeight);            /* desktopHeight (2 bytes) */
531
  Stream_Read_UINT16(s, pad2Octets);               /* pad2Octets (2 bytes) */
532
  Stream_Read_UINT16(s, desktopResizeFlag);        /* desktopResizeFlag (2 bytes) */
533
  Stream_Read_UINT16(s, bitmapCompressionFlag);    /* bitmapCompressionFlag (2 bytes) */
534
  Stream_Read_UINT8(s, highColorFlags);            /* highColorFlags (1 byte) */
535
  Stream_Read_UINT8(s, drawingFlags);              /* drawingFlags (1 byte) */
536
  Stream_Read_UINT16(s, multipleRectangleSupport); /* multipleRectangleSupport (2 bytes) */
537
  Stream_Read_UINT16(s, pad2OctetsB);              /* pad2OctetsB (2 bytes) */
538
  WLog_Print(log, WLOG_TRACE, "\tpreferredBitsPerPixel: 0x%04" PRIX16 "", preferredBitsPerPixel);
539
  WLog_Print(log, WLOG_TRACE, "\treceive1BitPerPixel: 0x%04" PRIX16 "", receive1BitPerPixel);
540
  WLog_Print(log, WLOG_TRACE, "\treceive4BitsPerPixel: 0x%04" PRIX16 "", receive4BitsPerPixel);
541
  WLog_Print(log, WLOG_TRACE, "\treceive8BitsPerPixel: 0x%04" PRIX16 "", receive8BitsPerPixel);
542
  WLog_Print(log, WLOG_TRACE, "\tdesktopWidth: 0x%04" PRIX16 "", desktopWidth);
543
  WLog_Print(log, WLOG_TRACE, "\tdesktopHeight: 0x%04" PRIX16 "", desktopHeight);
544
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
545
  WLog_Print(log, WLOG_TRACE, "\tdesktopResizeFlag: 0x%04" PRIX16 "", desktopResizeFlag);
546
  WLog_Print(log, WLOG_TRACE, "\tbitmapCompressionFlag: 0x%04" PRIX16 "", bitmapCompressionFlag);
547
  WLog_Print(log, WLOG_TRACE, "\thighColorFlags: 0x%02" PRIX8 "", highColorFlags);
548
  WLog_Print(log, WLOG_TRACE, "\tdrawingFlags: 0x%02" PRIX8 "", drawingFlags);
549
  WLog_Print(log, WLOG_TRACE, "\tmultipleRectangleSupport: 0x%04" PRIX16 "",
550
             multipleRectangleSupport);
551
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsB: 0x%04" PRIX16 "", pad2OctetsB);
552
  return TRUE;
553
}
554
#endif
555
556
WINPR_ATTR_NODISCARD
557
static BOOL rdp_apply_order_capability_set(rdpSettings* settings, const rdpSettings* src)
558
4.83k
{
559
4.83k
  WINPR_ASSERT(settings);
560
4.83k
  WINPR_ASSERT(src);
561
562
4.83k
  BOOL BitmapCacheV3Enabled = FALSE;
563
4.83k
  BOOL FrameMarkerCommandEnabled = FALSE;
564
565
159k
  for (size_t i = 0; i < 32; i++)
566
154k
  {
567
154k
    if (!src->OrderSupport[i])
568
99.2k
      settings->OrderSupport[i] = FALSE;
569
154k
  }
570
571
4.83k
  if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
572
112
  {
573
112
    if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
574
58
      BitmapCacheV3Enabled = TRUE;
575
576
112
    if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
577
38
      FrameMarkerCommandEnabled = TRUE;
578
112
  }
579
580
4.83k
  if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
581
0
  {
582
0
    settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
583
0
    settings->BitmapCacheVersion = src->BitmapCacheVersion;
584
0
  }
585
4.83k
  else
586
4.83k
    settings->BitmapCacheV3Enabled = FALSE;
587
588
4.83k
  settings->FrameMarkerCommandEnabled =
589
4.83k
      (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled);
590
591
4.83k
  return TRUE;
592
4.83k
}
593
594
/*
595
 * Read order capability set.
596
 * msdn{cc240556}
597
 */
598
WINPR_ATTR_NODISCARD
599
static BOOL rdp_read_order_capability_set(wLog* log, wStream* s, rdpSettings* settings)
600
4.84k
{
601
4.84k
  char terminalDescriptor[17] = WINPR_C_ARRAY_INIT;
602
4.84k
  BYTE orderSupport[32] = WINPR_C_ARRAY_INIT;
603
4.84k
  BOOL BitmapCacheV3Enabled = FALSE;
604
4.84k
  BOOL FrameMarkerCommandEnabled = FALSE;
605
606
4.84k
  WINPR_ASSERT(settings);
607
4.84k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
608
9
    return FALSE;
609
610
4.83k
  Stream_Read(s, terminalDescriptor, 16);               /* terminalDescriptor (16 bytes) */
611
4.83k
  Stream_Seek_UINT32(s);                                /* pad4OctetsA (4 bytes) */
612
4.83k
  Stream_Seek_UINT16(s);                                /* desktopSaveXGranularity (2 bytes) */
613
4.83k
  Stream_Seek_UINT16(s);                                /* desktopSaveYGranularity (2 bytes) */
614
4.83k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
615
4.83k
  Stream_Seek_UINT16(s);                                /* maximumOrderLevel (2 bytes) */
616
4.83k
  Stream_Seek_UINT16(s);                                /* numberFonts (2 bytes) */
617
4.83k
  Stream_Read_UINT16(s, settings->OrderSupportFlags);   /* orderFlags (2 bytes) */
618
4.83k
  Stream_Read(s, orderSupport, 32);                     /* orderSupport (32 bytes) */
619
4.83k
  Stream_Seek_UINT16(s);                                /* textFlags (2 bytes) */
620
4.83k
  Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
621
4.83k
  Stream_Seek_UINT32(s);                                /* pad4OctetsB (4 bytes) */
622
4.83k
  Stream_Seek_UINT32(s);                                /* desktopSaveSize (4 bytes) */
623
4.83k
  Stream_Seek_UINT16(s);                                /* pad2OctetsC (2 bytes) */
624
4.83k
  Stream_Seek_UINT16(s);                                /* pad2OctetsD (2 bytes) */
625
4.83k
  Stream_Read_UINT16(s, settings->TextANSICodePage);    /* textANSICodePage (2 bytes) */
626
4.83k
  Stream_Seek_UINT16(s);                                /* pad2OctetsE (2 bytes) */
627
628
4.83k
  if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
629
0
    return FALSE;
630
631
159k
  for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
632
154k
    settings->OrderSupport[i] = orderSupport[i];
633
634
4.83k
  if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
635
112
  {
636
112
    BitmapCacheV3Enabled = (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) != 0;
637
112
    FrameMarkerCommandEnabled =
638
112
        (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) != 0;
639
112
  }
640
641
4.83k
  settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
642
4.83k
  if (BitmapCacheV3Enabled)
643
58
    settings->BitmapCacheVersion = 3;
644
645
4.83k
  settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
646
647
4.83k
  return TRUE;
648
4.83k
}
649
650
/*
651
 * Write order capability set.
652
 * msdn{cc240556}
653
 */
654
WINPR_ATTR_NODISCARD
655
static BOOL rdp_write_order_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
656
0
{
657
0
  char terminalDescriptor[16] = WINPR_C_ARRAY_INIT;
658
659
0
  WINPR_ASSERT(settings);
660
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
661
0
    return FALSE;
662
663
0
  const size_t header = rdp_capability_set_start(log, s);
664
665
0
  UINT16 orderSupportExFlags = settings->OrderSupportFlagsEx;
666
0
  UINT16 orderFlags = settings->OrderSupportFlags;
667
668
0
  if (settings->BitmapCacheV3Enabled)
669
0
  {
670
0
    if ((orderSupportExFlags & CACHE_BITMAP_V3_SUPPORT) == 0)
671
0
    {
672
0
      WLog_Print(log, WLOG_WARN,
673
0
                 "rdpSettings::BitmapCacheV3Enabled=TRUE, but CACHE_BITMAP_V3_SUPPORT not "
674
0
                 "set in rdpSettings::OrderSupportEx, aborting.");
675
0
    }
676
0
    if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
677
0
    {
678
0
      WLog_Print(log, WLOG_WARN,
679
0
                 "rdpSettings::BitmapCacheV3Enabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT not "
680
0
                 "set in rdpSettings::OrderSupport, aborting.");
681
0
    }
682
0
  }
683
684
0
  if (settings->FrameMarkerCommandEnabled)
685
0
  {
686
0
    if ((orderSupportExFlags & ALTSEC_FRAME_MARKER_SUPPORT) == 0)
687
0
    {
688
0
      WLog_Print(
689
0
          log, WLOG_WARN,
690
0
          "rdpSettings::FrameMarkerCommandEnabled=TRUE, but "
691
0
          "ALTSEC_FRAME_MARKER_SUPPORT not set in rdpSettings::OrderSupportEx, aborting.");
692
0
    }
693
0
    if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
694
0
    {
695
0
      WLog_Print(log, WLOG_WARN,
696
0
                 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT "
697
0
                 "not set in rdpSettings::OrderSupport, aborting.");
698
0
    }
699
0
  }
700
701
0
  const char* dsc = freerdp_settings_get_string(settings, FreeRDP_TerminalDescriptor);
702
0
  if (dsc)
703
0
  {
704
0
    const size_t len = strnlen(dsc, ARRAYSIZE(terminalDescriptor));
705
0
    strncpy(terminalDescriptor, dsc, len);
706
0
  }
707
0
  Stream_Write(s, terminalDescriptor,
708
0
               sizeof(terminalDescriptor));           /* terminalDescriptor (16 bytes) */
709
0
  Stream_Write_UINT32(s, 0);                          /* pad4OctetsA (4 bytes) */
710
0
  Stream_Write_UINT16(s, 1);                          /* desktopSaveXGranularity (2 bytes) */
711
0
  Stream_Write_UINT16(s, 20);                         /* desktopSaveYGranularity (2 bytes) */
712
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsA (2 bytes) */
713
0
  Stream_Write_UINT16(s, 1);                          /* maximumOrderLevel (2 bytes) */
714
0
  Stream_Write_UINT16(s, 0);                          /* numberFonts (2 bytes) */
715
0
  Stream_Write_UINT16(s, orderFlags);                 /* orderFlags (2 bytes) */
716
0
  Stream_Write(s, settings->OrderSupport, 32);        /* orderSupport (32 bytes) */
717
0
  Stream_Write_UINT16(s, 0);                          /* textFlags (2 bytes) */
718
0
  Stream_Write_UINT16(s, orderSupportExFlags);        /* orderSupportExFlags (2 bytes) */
719
0
  Stream_Write_UINT32(s, 0);                          /* pad4OctetsB (4 bytes) */
720
0
  Stream_Write_UINT32(s, 230400);                     /* desktopSaveSize (4 bytes) */
721
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsC (2 bytes) */
722
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsD (2 bytes) */
723
0
  Stream_Write_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
724
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsE (2 bytes) */
725
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_ORDER);
726
0
}
727
728
#ifdef WITH_DEBUG_CAPABILITIES
729
WINPR_ATTR_NODISCARD
730
static BOOL rdp_print_order_capability_set(wLog* log, wStream* s)
731
{
732
  BYTE terminalDescriptor[16];
733
  UINT32 pad4OctetsA = 0;
734
  UINT16 desktopSaveXGranularity = 0;
735
  UINT16 desktopSaveYGranularity = 0;
736
  UINT16 pad2OctetsA = 0;
737
  UINT16 maximumOrderLevel = 0;
738
  UINT16 numberFonts = 0;
739
  UINT16 orderFlags = 0;
740
  BYTE orderSupport[32];
741
  UINT16 textFlags = 0;
742
  UINT16 orderSupportExFlags = 0;
743
  UINT32 pad4OctetsB = 0;
744
  UINT32 desktopSaveSize = 0;
745
  UINT16 pad2OctetsC = 0;
746
  UINT16 pad2OctetsD = 0;
747
  UINT16 textANSICodePage = 0;
748
  UINT16 pad2OctetsE = 0;
749
  WLog_Print(log, WLOG_TRACE,
750
             "OrderCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
751
752
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
753
    return FALSE;
754
755
  Stream_Read(s, terminalDescriptor, 16);         /* terminalDescriptor (16 bytes) */
756
  Stream_Read_UINT32(s, pad4OctetsA);             /* pad4OctetsA (4 bytes) */
757
  Stream_Read_UINT16(s, desktopSaveXGranularity); /* desktopSaveXGranularity (2 bytes) */
758
  Stream_Read_UINT16(s, desktopSaveYGranularity); /* desktopSaveYGranularity (2 bytes) */
759
  Stream_Read_UINT16(s, pad2OctetsA);             /* pad2OctetsA (2 bytes) */
760
  Stream_Read_UINT16(s, maximumOrderLevel);       /* maximumOrderLevel (2 bytes) */
761
  Stream_Read_UINT16(s, numberFonts);             /* numberFonts (2 bytes) */
762
  Stream_Read_UINT16(s, orderFlags);              /* orderFlags (2 bytes) */
763
  Stream_Read(s, orderSupport, 32);               /* orderSupport (32 bytes) */
764
  Stream_Read_UINT16(s, textFlags);               /* textFlags (2 bytes) */
765
  Stream_Read_UINT16(s, orderSupportExFlags);     /* orderSupportExFlags (2 bytes) */
766
  Stream_Read_UINT32(s, pad4OctetsB);             /* pad4OctetsB (4 bytes) */
767
  Stream_Read_UINT32(s, desktopSaveSize);         /* desktopSaveSize (4 bytes) */
768
  Stream_Read_UINT16(s, pad2OctetsC);             /* pad2OctetsC (2 bytes) */
769
  Stream_Read_UINT16(s, pad2OctetsD);             /* pad2OctetsD (2 bytes) */
770
  Stream_Read_UINT16(s, textANSICodePage);        /* textANSICodePage (2 bytes) */
771
  Stream_Read_UINT16(s, pad2OctetsE);             /* pad2OctetsE (2 bytes) */
772
  WLog_Print(log, WLOG_TRACE, "\tpad4OctetsA: 0x%08" PRIX32 "", pad4OctetsA);
773
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveXGranularity: 0x%04" PRIX16 "",
774
             desktopSaveXGranularity);
775
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveYGranularity: 0x%04" PRIX16 "",
776
             desktopSaveYGranularity);
777
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
778
  WLog_Print(log, WLOG_TRACE, "\tmaximumOrderLevel: 0x%04" PRIX16 "", maximumOrderLevel);
779
  WLog_Print(log, WLOG_TRACE, "\tnumberFonts: 0x%04" PRIX16 "", numberFonts);
780
  WLog_Print(log, WLOG_TRACE, "\torderFlags: 0x%04" PRIX16 "", orderFlags);
781
  WLog_Print(log, WLOG_TRACE, "\torderSupport:");
782
  WLog_Print(log, WLOG_TRACE, "\t\tDSTBLT: %" PRIu8 "", orderSupport[NEG_DSTBLT_INDEX]);
783
  WLog_Print(log, WLOG_TRACE, "\t\tPATBLT: %" PRIu8 "", orderSupport[NEG_PATBLT_INDEX]);
784
  WLog_Print(log, WLOG_TRACE, "\t\tSCRBLT: %" PRIu8 "", orderSupport[NEG_SCRBLT_INDEX]);
785
  WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT: %" PRIu8 "", orderSupport[NEG_MEMBLT_INDEX]);
786
  WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT: %" PRIu8 "", orderSupport[NEG_MEM3BLT_INDEX]);
787
  WLog_Print(log, WLOG_TRACE, "\t\tATEXTOUT: %" PRIu8 "", orderSupport[NEG_ATEXTOUT_INDEX]);
788
  WLog_Print(log, WLOG_TRACE, "\t\tAEXTTEXTOUT: %" PRIu8 "", orderSupport[NEG_AEXTTEXTOUT_INDEX]);
789
  WLog_Print(log, WLOG_TRACE, "\t\tDRAWNINEGRID: %" PRIu8 "",
790
             orderSupport[NEG_DRAWNINEGRID_INDEX]);
791
  WLog_Print(log, WLOG_TRACE, "\t\tLINETO: %" PRIu8 "", orderSupport[NEG_LINETO_INDEX]);
792
  WLog_Print(log, WLOG_TRACE, "\t\tMULTI_DRAWNINEGRID: %" PRIu8 "",
793
             orderSupport[NEG_MULTI_DRAWNINEGRID_INDEX]);
794
  WLog_Print(log, WLOG_TRACE, "\t\tOPAQUE_RECT: %" PRIu8 "", orderSupport[NEG_OPAQUE_RECT_INDEX]);
795
  WLog_Print(log, WLOG_TRACE, "\t\tSAVEBITMAP: %" PRIu8 "", orderSupport[NEG_SAVEBITMAP_INDEX]);
796
  WLog_Print(log, WLOG_TRACE, "\t\tWTEXTOUT: %" PRIu8 "", orderSupport[NEG_WTEXTOUT_INDEX]);
797
  WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT_V2: %" PRIu8 "", orderSupport[NEG_MEMBLT_V2_INDEX]);
798
  WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT_V2: %" PRIu8 "", orderSupport[NEG_MEM3BLT_V2_INDEX]);
799
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIDSTBLT: %" PRIu8 "", orderSupport[NEG_MULTIDSTBLT_INDEX]);
800
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIPATBLT: %" PRIu8 "", orderSupport[NEG_MULTIPATBLT_INDEX]);
801
  WLog_Print(log, WLOG_TRACE, "\t\tMULTISCRBLT: %" PRIu8 "", orderSupport[NEG_MULTISCRBLT_INDEX]);
802
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIOPAQUERECT: %" PRIu8 "",
803
             orderSupport[NEG_MULTIOPAQUERECT_INDEX]);
804
  WLog_Print(log, WLOG_TRACE, "\t\tFAST_INDEX: %" PRIu8 "", orderSupport[NEG_FAST_INDEX_INDEX]);
805
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_SC: %" PRIu8 "", orderSupport[NEG_POLYGON_SC_INDEX]);
806
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_CB: %" PRIu8 "", orderSupport[NEG_POLYGON_CB_INDEX]);
807
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYLINE: %" PRIu8 "", orderSupport[NEG_POLYLINE_INDEX]);
808
  WLog_Print(log, WLOG_TRACE, "\t\tUNUSED23: %" PRIu8 "", orderSupport[NEG_UNUSED23_INDEX]);
809
  WLog_Print(log, WLOG_TRACE, "\t\tFAST_GLYPH: %" PRIu8 "", orderSupport[NEG_FAST_GLYPH_INDEX]);
810
  WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_SC: %" PRIu8 "", orderSupport[NEG_ELLIPSE_SC_INDEX]);
811
  WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_CB: %" PRIu8 "", orderSupport[NEG_ELLIPSE_CB_INDEX]);
812
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_INDEX: %" PRIu8 "", orderSupport[NEG_GLYPH_INDEX_INDEX]);
813
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WEXTTEXTOUT: %" PRIu8 "",
814
             orderSupport[NEG_GLYPH_WEXTTEXTOUT_INDEX]);
815
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGTEXTOUT: %" PRIu8 "",
816
             orderSupport[NEG_GLYPH_WLONGTEXTOUT_INDEX]);
817
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGEXTTEXTOUT: %" PRIu8 "",
818
             orderSupport[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX]);
819
  WLog_Print(log, WLOG_TRACE, "\t\tUNUSED31: %" PRIu8 "", orderSupport[NEG_UNUSED31_INDEX]);
820
  WLog_Print(log, WLOG_TRACE, "\ttextFlags: 0x%04" PRIX16 "", textFlags);
821
  WLog_Print(log, WLOG_TRACE, "\torderSupportExFlags: 0x%04" PRIX16 "", orderSupportExFlags);
822
  WLog_Print(log, WLOG_TRACE, "\tpad4OctetsB: 0x%08" PRIX32 "", pad4OctetsB);
823
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveSize: 0x%08" PRIX32 "", desktopSaveSize);
824
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsC: 0x%04" PRIX16 "", pad2OctetsC);
825
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsD: 0x%04" PRIX16 "", pad2OctetsD);
826
  WLog_Print(log, WLOG_TRACE, "\ttextANSICodePage: 0x%04" PRIX16 "", textANSICodePage);
827
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsE: 0x%04" PRIX16 "", pad2OctetsE);
828
  return TRUE;
829
}
830
#endif
831
832
WINPR_ATTR_NODISCARD
833
static BOOL rdp_apply_bitmap_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
834
                                                  WINPR_ATTR_UNUSED const rdpSettings* src)
835
87
{
836
87
  WINPR_ASSERT(settings);
837
87
  WINPR_ASSERT(src);
838
87
  return TRUE;
839
87
}
840
841
/*
842
 * Read bitmap cache capability set.
843
 * msdn{cc240559}
844
 */
845
WINPR_ATTR_NODISCARD
846
static BOOL rdp_read_bitmap_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
847
104
{
848
104
  WINPR_UNUSED(settings);
849
104
  WINPR_ASSERT(settings);
850
851
104
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
852
17
    return FALSE;
853
854
87
  Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
855
87
  Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
856
87
  Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
857
87
  Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
858
87
  Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
859
87
  Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
860
87
  Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
861
87
  Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
862
87
  Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
863
87
  Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
864
87
  Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
865
87
  Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
866
87
  return TRUE;
867
104
}
868
869
/*
870
 * Write bitmap cache capability set.
871
 * msdn{cc240559}
872
 */
873
WINPR_ATTR_NODISCARD
874
static BOOL rdp_write_bitmap_cache_capability_set(wLog* log, wStream* s,
875
                                                  const rdpSettings* settings)
876
0
{
877
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
878
0
    return FALSE;
879
880
0
  const size_t header = rdp_capability_set_start(log, s);
881
0
  const UINT32 bpp = (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) + 7) / 8;
882
0
  if (bpp > UINT16_MAX)
883
0
    return FALSE;
884
0
  Stream_Write_UINT32(s, 0); /* pad1 (4 bytes) */
885
0
  Stream_Write_UINT32(s, 0); /* pad2 (4 bytes) */
886
0
  Stream_Write_UINT32(s, 0); /* pad3 (4 bytes) */
887
0
  Stream_Write_UINT32(s, 0); /* pad4 (4 bytes) */
888
0
  Stream_Write_UINT32(s, 0); /* pad5 (4 bytes) */
889
0
  Stream_Write_UINT32(s, 0); /* pad6 (4 bytes) */
890
0
  UINT32 size = bpp * 256;
891
0
  if (size > UINT16_MAX)
892
0
    return FALSE;
893
0
  Stream_Write_UINT16(s, 200);          /* Cache0Entries (2 bytes) */
894
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache0MaximumCellSize (2 bytes) */
895
0
  size = bpp * 1024;
896
0
  if (size > UINT16_MAX)
897
0
    return FALSE;
898
0
  Stream_Write_UINT16(s, 600);          /* Cache1Entries (2 bytes) */
899
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache1MaximumCellSize (2 bytes) */
900
0
  size = bpp * 4096;
901
0
  if (size > UINT16_MAX)
902
0
    return FALSE;
903
0
  Stream_Write_UINT16(s, 1000);         /* Cache2Entries (2 bytes) */
904
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache2MaximumCellSize (2 bytes) */
905
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE);
906
0
}
907
908
#ifdef WITH_DEBUG_CAPABILITIES
909
WINPR_ATTR_NODISCARD
910
static BOOL rdp_print_bitmap_cache_capability_set(wLog* log, wStream* s)
911
{
912
  UINT32 pad1 = 0;
913
  UINT32 pad2 = 0;
914
  UINT32 pad3 = 0;
915
  UINT32 pad4 = 0;
916
  UINT32 pad5 = 0;
917
  UINT32 pad6 = 0;
918
  UINT16 Cache0Entries = 0;
919
  UINT16 Cache0MaximumCellSize = 0;
920
  UINT16 Cache1Entries = 0;
921
  UINT16 Cache1MaximumCellSize = 0;
922
  UINT16 Cache2Entries = 0;
923
  UINT16 Cache2MaximumCellSize = 0;
924
  WLog_Print(log, WLOG_TRACE,
925
             "BitmapCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
926
927
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
928
    return FALSE;
929
930
  Stream_Read_UINT32(s, pad1);                  /* pad1 (4 bytes) */
931
  Stream_Read_UINT32(s, pad2);                  /* pad2 (4 bytes) */
932
  Stream_Read_UINT32(s, pad3);                  /* pad3 (4 bytes) */
933
  Stream_Read_UINT32(s, pad4);                  /* pad4 (4 bytes) */
934
  Stream_Read_UINT32(s, pad5);                  /* pad5 (4 bytes) */
935
  Stream_Read_UINT32(s, pad6);                  /* pad6 (4 bytes) */
936
  Stream_Read_UINT16(s, Cache0Entries);         /* Cache0Entries (2 bytes) */
937
  Stream_Read_UINT16(s, Cache0MaximumCellSize); /* Cache0MaximumCellSize (2 bytes) */
938
  Stream_Read_UINT16(s, Cache1Entries);         /* Cache1Entries (2 bytes) */
939
  Stream_Read_UINT16(s, Cache1MaximumCellSize); /* Cache1MaximumCellSize (2 bytes) */
940
  Stream_Read_UINT16(s, Cache2Entries);         /* Cache2Entries (2 bytes) */
941
  Stream_Read_UINT16(s, Cache2MaximumCellSize); /* Cache2MaximumCellSize (2 bytes) */
942
  WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%08" PRIX32 "", pad1);
943
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%08" PRIX32 "", pad2);
944
  WLog_Print(log, WLOG_TRACE, "\tpad3: 0x%08" PRIX32 "", pad3);
945
  WLog_Print(log, WLOG_TRACE, "\tpad4: 0x%08" PRIX32 "", pad4);
946
  WLog_Print(log, WLOG_TRACE, "\tpad5: 0x%08" PRIX32 "", pad5);
947
  WLog_Print(log, WLOG_TRACE, "\tpad6: 0x%08" PRIX32 "", pad6);
948
  WLog_Print(log, WLOG_TRACE, "\tCache0Entries: 0x%04" PRIX16 "", Cache0Entries);
949
  WLog_Print(log, WLOG_TRACE, "\tCache0MaximumCellSize: 0x%04" PRIX16 "", Cache0MaximumCellSize);
950
  WLog_Print(log, WLOG_TRACE, "\tCache1Entries: 0x%04" PRIX16 "", Cache1Entries);
951
  WLog_Print(log, WLOG_TRACE, "\tCache1MaximumCellSize: 0x%04" PRIX16 "", Cache1MaximumCellSize);
952
  WLog_Print(log, WLOG_TRACE, "\tCache2Entries: 0x%04" PRIX16 "", Cache2Entries);
953
  WLog_Print(log, WLOG_TRACE, "\tCache2MaximumCellSize: 0x%04" PRIX16 "", Cache2MaximumCellSize);
954
  return TRUE;
955
}
956
#endif
957
958
WINPR_ATTR_NODISCARD
959
static BOOL rdp_apply_control_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
960
                                             WINPR_ATTR_UNUSED const rdpSettings* src)
961
70
{
962
70
  WINPR_ASSERT(settings);
963
70
  WINPR_ASSERT(src);
964
965
70
  return TRUE;
966
70
}
967
968
/*
969
 * Read control capability set.
970
 * msdn{cc240568}
971
 */
972
WINPR_ATTR_NODISCARD
973
static BOOL rdp_read_control_capability_set(wLog* log, wStream* s, rdpSettings* settings)
974
73
{
975
73
  WINPR_UNUSED(settings);
976
73
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
977
3
    return FALSE;
978
979
70
  Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
980
70
  Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
981
70
  Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
982
70
  Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
983
70
  return TRUE;
984
73
}
985
986
/*
987
 * Write control capability set.
988
 * msdn{cc240568}
989
 */
990
WINPR_ATTR_NODISCARD
991
static BOOL rdp_write_control_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
992
0
{
993
0
  WINPR_UNUSED(settings);
994
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
995
0
    return FALSE;
996
997
0
  const size_t header = rdp_capability_set_start(log, s);
998
0
  Stream_Write_UINT16(s, 0); /* controlFlags (2 bytes) */
999
0
  Stream_Write_UINT16(s, 0); /* remoteDetachFlag (2 bytes) */
1000
0
  Stream_Write_UINT16(s, 2); /* controlInterest (2 bytes) */
1001
0
  Stream_Write_UINT16(s, 2); /* detachInterest (2 bytes) */
1002
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_CONTROL);
1003
0
}
1004
1005
#ifdef WITH_DEBUG_CAPABILITIES
1006
WINPR_ATTR_NODISCARD
1007
static BOOL rdp_print_control_capability_set(wLog* log, wStream* s)
1008
{
1009
  UINT16 controlFlags = 0;
1010
  UINT16 remoteDetachFlag = 0;
1011
  UINT16 controlInterest = 0;
1012
  UINT16 detachInterest = 0;
1013
  WLog_Print(log, WLOG_TRACE,
1014
             "ControlCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1015
1016
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1017
    return FALSE;
1018
1019
  Stream_Read_UINT16(s, controlFlags);     /* controlFlags (2 bytes) */
1020
  Stream_Read_UINT16(s, remoteDetachFlag); /* remoteDetachFlag (2 bytes) */
1021
  Stream_Read_UINT16(s, controlInterest);  /* controlInterest (2 bytes) */
1022
  Stream_Read_UINT16(s, detachInterest);   /* detachInterest (2 bytes) */
1023
  WLog_Print(log, WLOG_TRACE, "\tcontrolFlags: 0x%04" PRIX16 "", controlFlags);
1024
  WLog_Print(log, WLOG_TRACE, "\tremoteDetachFlag: 0x%04" PRIX16 "", remoteDetachFlag);
1025
  WLog_Print(log, WLOG_TRACE, "\tcontrolInterest: 0x%04" PRIX16 "", controlInterest);
1026
  WLog_Print(log, WLOG_TRACE, "\tdetachInterest: 0x%04" PRIX16 "", detachInterest);
1027
  return TRUE;
1028
}
1029
#endif
1030
1031
WINPR_ATTR_NODISCARD
1032
static BOOL rdp_apply_window_activation_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1033
                                                       WINPR_ATTR_UNUSED const rdpSettings* src)
1034
28
{
1035
28
  WINPR_ASSERT(settings);
1036
28
  WINPR_ASSERT(src);
1037
1038
28
  return TRUE;
1039
28
}
1040
1041
/*
1042
 * Read window activation capability set.
1043
 * msdn{cc240569}
1044
 */
1045
WINPR_ATTR_NODISCARD
1046
static BOOL rdp_read_window_activation_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1047
31
{
1048
31
  WINPR_UNUSED(settings);
1049
31
  WINPR_ASSERT(settings);
1050
31
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1051
3
    return FALSE;
1052
1053
28
  Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1054
28
  Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1055
28
  Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1056
28
  Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1057
28
  return TRUE;
1058
31
}
1059
1060
/*
1061
 * Write window activation capability set.
1062
 * msdn{cc240569}
1063
 */
1064
WINPR_ATTR_NODISCARD
1065
static BOOL rdp_write_window_activation_capability_set(wLog* log, wStream* s,
1066
                                                       const rdpSettings* settings)
1067
0
{
1068
0
  WINPR_UNUSED(settings);
1069
0
  WINPR_ASSERT(settings);
1070
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1071
0
    return FALSE;
1072
1073
0
  const size_t header = rdp_capability_set_start(log, s);
1074
0
  Stream_Write_UINT16(s, 0); /* helpKeyFlag (2 bytes) */
1075
0
  Stream_Write_UINT16(s, 0); /* helpKeyIndexFlag (2 bytes) */
1076
0
  Stream_Write_UINT16(s, 0); /* helpExtendedKeyFlag (2 bytes) */
1077
0
  Stream_Write_UINT16(s, 0); /* windowManagerKeyFlag (2 bytes) */
1078
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_ACTIVATION);
1079
0
}
1080
1081
#ifdef WITH_DEBUG_CAPABILITIES
1082
WINPR_ATTR_NODISCARD
1083
static BOOL rdp_print_window_activation_capability_set(wLog* log, wStream* s)
1084
{
1085
  UINT16 helpKeyFlag = 0;
1086
  UINT16 helpKeyIndexFlag = 0;
1087
  UINT16 helpExtendedKeyFlag = 0;
1088
  UINT16 windowManagerKeyFlag = 0;
1089
  WLog_Print(log, WLOG_TRACE,
1090
             "WindowActivationCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1091
1092
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1093
    return FALSE;
1094
1095
  Stream_Read_UINT16(s, helpKeyFlag);          /* helpKeyFlag (2 bytes) */
1096
  Stream_Read_UINT16(s, helpKeyIndexFlag);     /* helpKeyIndexFlag (2 bytes) */
1097
  Stream_Read_UINT16(s, helpExtendedKeyFlag);  /* helpExtendedKeyFlag (2 bytes) */
1098
  Stream_Read_UINT16(s, windowManagerKeyFlag); /* windowManagerKeyFlag (2 bytes) */
1099
  WLog_Print(log, WLOG_TRACE, "\thelpKeyFlag: 0x%04" PRIX16 "", helpKeyFlag);
1100
  WLog_Print(log, WLOG_TRACE, "\thelpKeyIndexFlag: 0x%04" PRIX16 "", helpKeyIndexFlag);
1101
  WLog_Print(log, WLOG_TRACE, "\thelpExtendedKeyFlag: 0x%04" PRIX16 "", helpExtendedKeyFlag);
1102
  WLog_Print(log, WLOG_TRACE, "\twindowManagerKeyFlag: 0x%04" PRIX16 "", windowManagerKeyFlag);
1103
  return TRUE;
1104
}
1105
#endif
1106
WINPR_ATTR_NODISCARD
1107
static BOOL rdp_apply_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
1108
4.10k
{
1109
4.10k
  WINPR_ASSERT(settings);
1110
4.10k
  WINPR_ASSERT(src);
1111
1112
4.10k
  const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1113
4.10k
  const UINT32 colorPointerCacheSize =
1114
4.10k
      freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1115
4.10k
  const UINT32 dstPointerCacheSize =
1116
4.10k
      freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1117
4.10k
  const UINT32 dstColorPointerCacheSize =
1118
4.10k
      freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1119
1120
  /* We want the minimum of our setting and the remote announced value. */
1121
4.10k
  const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1122
4.10k
  const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1123
1124
4.10k
  return !(
1125
4.10k
      !freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1126
4.10k
      !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1127
4.10k
                                   actualColorPointerCacheSize));
1128
4.10k
}
1129
1130
/*
1131
 * Read pointer capability set.
1132
 * msdn{cc240562}
1133
 */
1134
WINPR_ATTR_NODISCARD
1135
static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1136
4.12k
{
1137
4.12k
  UINT16 colorPointerFlag = 0;
1138
4.12k
  UINT16 colorPointerCacheSize = 0;
1139
4.12k
  UINT16 pointerCacheSize = 0;
1140
1141
4.12k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1142
20
    return FALSE;
1143
1144
4.10k
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1145
4.10k
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1146
1147
4.10k
  if (colorPointerFlag == 0)
1148
102
  {
1149
102
    WLog_Print(log, WLOG_WARN,
1150
102
               "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1151
102
               "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1152
102
               ". Value is ignored and always assumed to be TRUE",
1153
102
               colorPointerFlag);
1154
102
  }
1155
1156
  /* pointerCacheSize is optional */
1157
4.10k
  if (Stream_GetRemainingLength(s) >= 2)
1158
395
    Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1159
1160
4.10k
  WINPR_ASSERT(settings);
1161
4.10k
  settings->PointerCacheSize = pointerCacheSize;
1162
4.10k
  settings->ColorPointerCacheSize = colorPointerCacheSize;
1163
1164
4.10k
  return TRUE;
1165
4.12k
}
1166
1167
/*
1168
 * Write pointer capability set.
1169
 * msdn{cc240562}
1170
 */
1171
WINPR_ATTR_NODISCARD
1172
static BOOL rdp_write_pointer_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1173
0
{
1174
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1175
0
    return FALSE;
1176
1177
0
  const size_t header = rdp_capability_set_start(log, s);
1178
0
  if (settings->PointerCacheSize > UINT16_MAX)
1179
0
    return FALSE;
1180
0
  if (settings->ColorPointerCacheSize > UINT16_MAX)
1181
0
    return FALSE;
1182
1183
0
  WINPR_ASSERT(settings);
1184
0
  const UINT32 colorPointerFlag =
1185
0
      1; /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1186
          * colorPointerFlag is ignored and always assumed to be TRUE */
1187
0
  Stream_Write_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1188
0
  Stream_Write_UINT16(
1189
0
      s, (UINT16)settings->ColorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1190
0
  Stream_Write_UINT16(s, (UINT16)settings->PointerCacheSize); /* pointerCacheSize (2 bytes) */
1191
1192
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_POINTER);
1193
0
}
1194
1195
#ifdef WITH_DEBUG_CAPABILITIES
1196
WINPR_ATTR_NODISCARD
1197
static BOOL rdp_print_pointer_capability_set(wLog* log, wStream* s)
1198
{
1199
  UINT16 colorPointerFlag = 0;
1200
  UINT16 colorPointerCacheSize = 0;
1201
  UINT16 pointerCacheSize = 0;
1202
1203
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
1204
    return FALSE;
1205
1206
  WLog_Print(log, WLOG_TRACE,
1207
             "PointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1208
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1209
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1210
  Stream_Read_UINT16(s, pointerCacheSize);      /* pointerCacheSize (2 bytes) */
1211
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerFlag: 0x%04" PRIX16 "", colorPointerFlag);
1212
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerCacheSize: 0x%04" PRIX16 "", colorPointerCacheSize);
1213
  WLog_Print(log, WLOG_TRACE, "\tpointerCacheSize: 0x%04" PRIX16 "", pointerCacheSize);
1214
  return TRUE;
1215
}
1216
#endif
1217
1218
WINPR_ATTR_NODISCARD
1219
static BOOL rdp_apply_share_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1220
                                           WINPR_ATTR_UNUSED const rdpSettings* src)
1221
115
{
1222
115
  WINPR_ASSERT(settings);
1223
115
  WINPR_ASSERT(src);
1224
1225
115
  return TRUE;
1226
115
}
1227
1228
/*
1229
 * Read share capability set.
1230
 * msdn{cc240570}
1231
 */
1232
WINPR_ATTR_NODISCARD
1233
static BOOL rdp_read_share_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1234
121
{
1235
121
  WINPR_UNUSED(settings);
1236
121
  WINPR_ASSERT(settings);
1237
1238
121
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1239
6
    return FALSE;
1240
1241
115
  Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1242
115
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1243
115
  return TRUE;
1244
121
}
1245
1246
/*
1247
 * Write share capability set.
1248
 * msdn{cc240570}
1249
 */
1250
WINPR_ATTR_NODISCARD
1251
static BOOL rdp_write_share_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1252
0
{
1253
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1254
0
    return FALSE;
1255
1256
0
  const size_t header = rdp_capability_set_start(log, s);
1257
1258
0
  WINPR_ASSERT(settings);
1259
0
  const UINT16 nodeId = (settings->ServerMode) ? 0x03EA : 0;
1260
0
  Stream_Write_UINT16(s, nodeId); /* nodeId (2 bytes) */
1261
0
  Stream_Write_UINT16(s, 0);      /* pad2Octets (2 bytes) */
1262
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SHARE);
1263
0
}
1264
1265
#ifdef WITH_DEBUG_CAPABILITIES
1266
WINPR_ATTR_NODISCARD
1267
static BOOL rdp_print_share_capability_set(wLog* log, wStream* s)
1268
{
1269
  UINT16 nodeId = 0;
1270
  UINT16 pad2Octets = 0;
1271
  WLog_Print(log, WLOG_TRACE,
1272
             "ShareCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1273
1274
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1275
    return FALSE;
1276
1277
  Stream_Read_UINT16(s, nodeId);     /* nodeId (2 bytes) */
1278
  Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1279
  WLog_Print(log, WLOG_TRACE, "\tnodeId: 0x%04" PRIX16 "", nodeId);
1280
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1281
  return TRUE;
1282
}
1283
#endif
1284
1285
WINPR_ATTR_NODISCARD
1286
static BOOL rdp_apply_color_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1287
                                                 WINPR_ATTR_UNUSED const rdpSettings* src)
1288
2.01k
{
1289
2.01k
  WINPR_ASSERT(settings);
1290
2.01k
  WINPR_ASSERT(src);
1291
2.01k
  return TRUE;
1292
2.01k
}
1293
1294
/*
1295
 * Read color cache capability set.
1296
 * msdn{cc241564}
1297
 */
1298
WINPR_ATTR_NODISCARD
1299
static BOOL rdp_read_color_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1300
2.02k
{
1301
2.02k
  WINPR_UNUSED(settings);
1302
2.02k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1303
12
    return FALSE;
1304
1305
2.01k
  Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1306
2.01k
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1307
2.01k
  return TRUE;
1308
2.02k
}
1309
1310
/*
1311
 * Write color cache capability set.
1312
 * msdn{cc241564}
1313
 */
1314
WINPR_ATTR_NODISCARD
1315
static BOOL rdp_write_color_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1316
0
{
1317
0
  WINPR_UNUSED(settings);
1318
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1319
0
    return FALSE;
1320
1321
0
  const size_t header = rdp_capability_set_start(log, s);
1322
0
  Stream_Write_UINT16(s, 6); /* colorTableCacheSize (2 bytes) */
1323
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1324
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_COLOR_CACHE);
1325
0
}
1326
1327
#ifdef WITH_DEBUG_CAPABILITIES
1328
WINPR_ATTR_NODISCARD
1329
static BOOL rdp_print_color_cache_capability_set(wLog* log, wStream* s)
1330
{
1331
  UINT16 colorTableCacheSize = 0;
1332
  UINT16 pad2Octets = 0;
1333
  WLog_Print(log, WLOG_TRACE,
1334
             "ColorCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1335
1336
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1337
    return FALSE;
1338
1339
  Stream_Read_UINT16(s, colorTableCacheSize); /* colorTableCacheSize (2 bytes) */
1340
  Stream_Read_UINT16(s, pad2Octets);          /* pad2Octets (2 bytes) */
1341
  WLog_Print(log, WLOG_TRACE, "\tcolorTableCacheSize: 0x%04" PRIX16 "", colorTableCacheSize);
1342
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1343
  return TRUE;
1344
}
1345
#endif
1346
1347
WINPR_ATTR_NODISCARD
1348
static BOOL rdp_apply_sound_capability_set(rdpSettings* settings, const rdpSettings* src)
1349
172
{
1350
172
  WINPR_ASSERT(settings);
1351
172
  WINPR_ASSERT(src);
1352
1353
172
  settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1354
1355
172
  return TRUE;
1356
172
}
1357
1358
/*
1359
 * Read sound capability set.
1360
 * msdn{cc240552}
1361
 */
1362
WINPR_ATTR_NODISCARD
1363
static BOOL rdp_read_sound_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1364
175
{
1365
175
  UINT16 soundFlags = 0;
1366
1367
175
  WINPR_ASSERT(settings);
1368
175
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1369
3
    return FALSE;
1370
1371
172
  Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1372
172
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1373
172
  settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) != 0;
1374
172
  return TRUE;
1375
175
}
1376
1377
/*
1378
 * Write sound capability set.
1379
 * msdn{cc240552}
1380
 */
1381
WINPR_ATTR_NODISCARD
1382
static BOOL rdp_write_sound_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1383
0
{
1384
0
  WINPR_ASSERT(settings);
1385
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1386
0
    return FALSE;
1387
1388
0
  const size_t header = rdp_capability_set_start(log, s);
1389
0
  const UINT16 soundFlags = (settings->SoundBeepsEnabled) ? SOUND_BEEPS_FLAG : 0;
1390
0
  Stream_Write_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1391
0
  Stream_Write_UINT16(s, 0);          /* pad2OctetsA (2 bytes) */
1392
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SOUND);
1393
0
}
1394
1395
#ifdef WITH_DEBUG_CAPABILITIES
1396
WINPR_ATTR_NODISCARD
1397
static BOOL rdp_print_sound_capability_set(wLog* log, wStream* s)
1398
{
1399
  UINT16 soundFlags = 0;
1400
  UINT16 pad2OctetsA = 0;
1401
  WLog_Print(log, WLOG_TRACE,
1402
             "SoundCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1403
1404
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1405
    return FALSE;
1406
1407
  Stream_Read_UINT16(s, soundFlags);  /* soundFlags (2 bytes) */
1408
  Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1409
  WLog_Print(log, WLOG_TRACE, "\tsoundFlags: 0x%04" PRIX16 "", soundFlags);
1410
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1411
  return TRUE;
1412
}
1413
#endif
1414
1415
WINPR_ATTR_NODISCARD
1416
static BOOL rdp_apply_input_capability_set(rdpSettings* settings, const rdpSettings* src)
1417
4.44k
{
1418
4.44k
  WINPR_ASSERT(settings);
1419
4.44k
  WINPR_ASSERT(src);
1420
1421
4.44k
  if (settings->ServerMode)
1422
2.68k
  {
1423
2.68k
    settings->KeyboardLayout = src->KeyboardLayout;
1424
2.68k
    settings->KeyboardType = src->KeyboardType;
1425
2.68k
    settings->KeyboardSubType = src->KeyboardSubType;
1426
2.68k
    settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1427
2.68k
  }
1428
1429
4.44k
  if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1430
0
    return FALSE;
1431
1432
4.44k
  if (!settings->ServerMode)
1433
1.76k
  {
1434
1.76k
    settings->FastPathInput = src->FastPathInput;
1435
1436
    /* Note: These settings have split functionality:
1437
     * 1. If disabled in client pre_connect, it can disable announcing the feature
1438
     * 2. If enabled in client pre_connect, override it with the server announced support flag.
1439
     */
1440
1.76k
    if (settings->HasHorizontalWheel)
1441
143
      settings->HasHorizontalWheel = src->HasHorizontalWheel;
1442
1.76k
    const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1443
1.76k
    if (UnicodeInput)
1444
143
    {
1445
143
      const BOOL srcVal = freerdp_settings_get_bool(src, FreeRDP_UnicodeInput);
1446
143
      if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1447
0
        return FALSE;
1448
143
    }
1449
1.76k
    if (settings->HasExtendedMouseEvent)
1450
88
      settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1451
1.76k
    if (settings->HasRelativeMouseEvent)
1452
143
      settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1453
1.76k
    if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1454
143
      settings->HasQoeEvent = freerdp_settings_get_bool(src, FreeRDP_HasQoeEvent);
1455
1.76k
  }
1456
4.44k
  return TRUE;
1457
4.44k
}
1458
1459
/*
1460
 * Read input capability set.
1461
 * msdn{cc240563}
1462
 */
1463
WINPR_ATTR_NODISCARD
1464
static BOOL rdp_read_input_capability_set(wLog* log, wStream* s, rdpSettings* settings,
1465
                                          BOOL isServer)
1466
4.45k
{
1467
4.45k
  UINT16 inputFlags = 0;
1468
1469
4.45k
  WINPR_ASSERT(settings);
1470
4.45k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1471
6
    return FALSE;
1472
1473
4.44k
  Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1474
4.44k
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1475
1476
4.44k
  Stream_Read_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1477
4.44k
  Stream_Read_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1478
4.44k
  Stream_Read_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1479
4.44k
  Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1480
1481
  /* Received after TS_UD_CS_CORE and copied over its (sanitized) value by
1482
   * rdp_apply_input_capability_set(), so a client's out-of-spec KeyboardType (e.g. mstsc with
1483
   * an MSKLC layout) must be checked here too. Servers send zeroed keyboard fields: skip. */
1484
4.44k
  if (isServer)
1485
2.68k
    freerdp_settings_sanitize_keyboard_type(log, settings, "TS_INPUT_CAPABILITYSET");
1486
1487
4.44k
  {
1488
4.44k
    WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1489
4.44k
    char str[65] = WINPR_C_ARRAY_INIT;
1490
1491
    /* Older windows versions report invalid UTF16
1492
     * [MS-RDPBCGR] <29> Section 2.2.7.1.6: Microsoft RDP 4.0, 5.0, 5.1, and 5.2 servers do not
1493
     * explicitly fill the imeFileName field with zeros.
1494
     */
1495
4.44k
    if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1496
0
      return FALSE;
1497
1498
4.44k
    if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1499
1.65k
      memset(str, 0, sizeof(str));
1500
1501
4.44k
    if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1502
0
      return FALSE;
1503
4.44k
  }
1504
1505
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1506
4.44k
                                 inputFlags &
1507
4.44k
                                     (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1508
0
    return FALSE;
1509
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1510
4.44k
                                 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1511
0
    return FALSE;
1512
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1513
4.44k
                                 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1514
0
    return FALSE;
1515
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1516
4.44k
                                 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1517
0
    return FALSE;
1518
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1519
4.44k
                                 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1520
0
    return FALSE;
1521
4.44k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1522
4.44k
                                 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1523
0
    return FALSE;
1524
1525
4.44k
  return TRUE;
1526
4.44k
}
1527
1528
/*
1529
 * Write input capability set.
1530
 * msdn{cc240563}
1531
 */
1532
WINPR_ATTR_NODISCARD
1533
static BOOL rdp_write_input_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1534
0
{
1535
0
  WINPR_ASSERT(settings);
1536
0
  if (!Stream_EnsureRemainingCapacity(s, 128))
1537
0
    return FALSE;
1538
1539
0
  const size_t header = rdp_capability_set_start(log, s);
1540
0
  UINT16 inputFlags = INPUT_FLAG_SCANCODES;
1541
1542
0
  if (settings->FastPathInput)
1543
0
  {
1544
0
    inputFlags |= INPUT_FLAG_FASTPATH_INPUT;
1545
0
    inputFlags |= INPUT_FLAG_FASTPATH_INPUT2;
1546
0
  }
1547
1548
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasRelativeMouseEvent))
1549
0
    inputFlags |= INPUT_FLAG_MOUSE_RELATIVE;
1550
1551
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasHorizontalWheel))
1552
0
    inputFlags |= TS_INPUT_FLAG_MOUSE_HWHEEL;
1553
1554
0
  if (freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput))
1555
0
    inputFlags |= INPUT_FLAG_UNICODE;
1556
1557
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1558
0
    inputFlags |= TS_INPUT_FLAG_QOE_TIMESTAMPS;
1559
1560
0
  if (settings->HasExtendedMouseEvent)
1561
0
    inputFlags |= INPUT_FLAG_MOUSEX;
1562
1563
0
  Stream_Write_UINT16(s, inputFlags);                    /* inputFlags (2 bytes) */
1564
0
  Stream_Write_UINT16(s, 0);                             /* pad2OctetsA (2 bytes) */
1565
0
  Stream_Write_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1566
0
  Stream_Write_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1567
0
  Stream_Write_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1568
0
  Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1569
0
  Stream_Zero(s, 64);                                    /* imeFileName (64 bytes) */
1570
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_INPUT);
1571
0
}
1572
1573
#ifdef WITH_DEBUG_CAPABILITIES
1574
WINPR_ATTR_NODISCARD
1575
static BOOL rdp_print_input_capability_set(wLog* log, wStream* s)
1576
{
1577
  UINT16 inputFlags = 0;
1578
  UINT16 pad2OctetsA = 0;
1579
  UINT32 keyboardLayout = 0;
1580
  UINT32 keyboardType = 0;
1581
  UINT32 keyboardSubType = 0;
1582
  UINT32 keyboardFunctionKey = 0;
1583
  WLog_Print(log, WLOG_TRACE, "InputCapabilitySet (length %" PRIuz ")",
1584
             Stream_GetRemainingLength(s));
1585
1586
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1587
    return FALSE;
1588
1589
  Stream_Read_UINT16(s, inputFlags);          /* inputFlags (2 bytes) */
1590
  Stream_Read_UINT16(s, pad2OctetsA);         /* pad2OctetsA (2 bytes) */
1591
  Stream_Read_UINT32(s, keyboardLayout);      /* keyboardLayout (4 bytes) */
1592
  Stream_Read_UINT32(s, keyboardType);        /* keyboardType (4 bytes) */
1593
  Stream_Read_UINT32(s, keyboardSubType);     /* keyboardSubType (4 bytes) */
1594
  Stream_Read_UINT32(s, keyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1595
  Stream_Seek(s, 64);                         /* imeFileName (64 bytes) */
1596
  WLog_Print(log, WLOG_TRACE, "\tinputFlags: 0x%04" PRIX16 "", inputFlags);
1597
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1598
  WLog_Print(log, WLOG_TRACE, "\tkeyboardLayout: 0x%08" PRIX32 "", keyboardLayout);
1599
  WLog_Print(log, WLOG_TRACE, "\tkeyboardType: 0x%08" PRIX32 "", keyboardType);
1600
  WLog_Print(log, WLOG_TRACE, "\tkeyboardSubType: 0x%08" PRIX32 "", keyboardSubType);
1601
  WLog_Print(log, WLOG_TRACE, "\tkeyboardFunctionKey: 0x%08" PRIX32 "", keyboardFunctionKey);
1602
  return TRUE;
1603
}
1604
#endif
1605
1606
WINPR_ATTR_NODISCARD
1607
static BOOL rdp_apply_font_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1608
                                          WINPR_ATTR_UNUSED const rdpSettings* src)
1609
450
{
1610
450
  WINPR_ASSERT(settings);
1611
450
  WINPR_ASSERT(src);
1612
450
  return TRUE;
1613
450
}
1614
1615
/*
1616
 * Read font capability set.
1617
 * msdn{cc240571}
1618
 */
1619
WINPR_ATTR_NODISCARD
1620
static BOOL rdp_read_font_capability_set(WINPR_ATTR_UNUSED wLog* log, wStream* s,
1621
                                         rdpSettings* settings)
1622
450
{
1623
450
  WINPR_UNUSED(settings);
1624
450
  if (Stream_GetRemainingLength(s) >= 2)
1625
165
    Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1626
1627
450
  if (Stream_GetRemainingLength(s) >= 2)
1628
165
    Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1629
1630
450
  return TRUE;
1631
450
}
1632
1633
/*
1634
 * Write font capability set.
1635
 * msdn{cc240571}
1636
 */
1637
WINPR_ATTR_NODISCARD
1638
static BOOL rdp_write_font_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1639
0
{
1640
0
  WINPR_UNUSED(settings);
1641
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1642
0
    return FALSE;
1643
1644
0
  const size_t header = rdp_capability_set_start(log, s);
1645
0
  Stream_Write_UINT16(s, FONTSUPPORT_FONTLIST); /* fontSupportFlags (2 bytes) */
1646
0
  Stream_Write_UINT16(s, 0);                    /* pad2Octets (2 bytes) */
1647
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_FONT);
1648
0
}
1649
1650
#ifdef WITH_DEBUG_CAPABILITIES
1651
WINPR_ATTR_NODISCARD
1652
static BOOL rdp_print_font_capability_set(wLog* log, wStream* s)
1653
{
1654
  UINT16 fontSupportFlags = 0;
1655
  UINT16 pad2Octets = 0;
1656
  WLog_Print(log, WLOG_TRACE,
1657
             "FontCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1658
1659
  if (Stream_GetRemainingLength(s) >= 2)
1660
    Stream_Read_UINT16(s, fontSupportFlags); /* fontSupportFlags (2 bytes) */
1661
1662
  if (Stream_GetRemainingLength(s) >= 2)
1663
    Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1664
1665
  WLog_Print(log, WLOG_TRACE, "\tfontSupportFlags: 0x%04" PRIX16 "", fontSupportFlags);
1666
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1667
  return TRUE;
1668
}
1669
#endif
1670
1671
WINPR_ATTR_NODISCARD
1672
static BOOL rdp_apply_brush_capability_set(rdpSettings* settings, const rdpSettings* src)
1673
164
{
1674
164
  WINPR_ASSERT(settings);
1675
164
  WINPR_ASSERT(src);
1676
1677
  // TODO: Minimum of what?
1678
164
  settings->BrushSupportLevel = src->BrushSupportLevel;
1679
164
  return TRUE;
1680
164
}
1681
1682
/*
1683
 * Read brush capability set.
1684
 * msdn{cc240564}
1685
 */
1686
WINPR_ATTR_NODISCARD
1687
static BOOL rdp_read_brush_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1688
165
{
1689
165
  WINPR_UNUSED(settings);
1690
165
  WINPR_ASSERT(settings);
1691
1692
165
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1693
1
    return FALSE;
1694
164
  Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1695
164
  return TRUE;
1696
165
}
1697
1698
/*
1699
 * Write brush capability set.
1700
 * msdn{cc240564}
1701
 */
1702
WINPR_ATTR_NODISCARD
1703
static BOOL rdp_write_brush_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1704
0
{
1705
0
  WINPR_ASSERT(settings);
1706
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1707
0
    return FALSE;
1708
1709
0
  const size_t header = rdp_capability_set_start(log, s);
1710
0
  Stream_Write_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1711
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BRUSH);
1712
0
}
1713
1714
#ifdef WITH_DEBUG_CAPABILITIES
1715
WINPR_ATTR_NODISCARD
1716
static BOOL rdp_print_brush_capability_set(wLog* log, wStream* s)
1717
{
1718
  UINT32 brushSupportLevel = 0;
1719
  WLog_Print(log, WLOG_TRACE,
1720
             "BrushCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1721
1722
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1723
    return FALSE;
1724
1725
  Stream_Read_UINT32(s, brushSupportLevel); /* brushSupportLevel (4 bytes) */
1726
  WLog_Print(log, WLOG_TRACE, "\tbrushSupportLevel: 0x%08" PRIX32 "", brushSupportLevel);
1727
  return TRUE;
1728
}
1729
#endif
1730
1731
/*
1732
 * Read cache definition (glyph).
1733
 * msdn{cc240566}
1734
 */
1735
static void rdp_read_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1736
792
{
1737
792
  WINPR_ASSERT(cache_definition);
1738
792
  Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1739
792
  Stream_Read_UINT16(s,
1740
792
                     cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1741
792
}
1742
1743
/*
1744
 * Write cache definition (glyph).
1745
 * msdn{cc240566}
1746
 */
1747
static void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1748
0
{
1749
0
  WINPR_ASSERT(cache_definition);
1750
0
  Stream_Write_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1751
0
  Stream_Write_UINT16(
1752
0
      s, cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1753
0
}
1754
1755
WINPR_ATTR_NODISCARD
1756
static BOOL rdp_apply_glyph_cache_capability_set(rdpSettings* settings, const rdpSettings* src)
1757
72
{
1758
72
  WINPR_ASSERT(settings);
1759
72
  WINPR_ASSERT(src);
1760
1761
72
  WINPR_ASSERT(src->GlyphCache);
1762
72
  WINPR_ASSERT(settings->GlyphCache);
1763
792
  for (size_t x = 0; x < 10; x++)
1764
720
    settings->GlyphCache[x] = src->GlyphCache[x];
1765
1766
72
  WINPR_ASSERT(src->FragCache);
1767
72
  WINPR_ASSERT(settings->FragCache);
1768
72
  settings->FragCache[0] = src->FragCache[0];
1769
72
  settings->GlyphSupportLevel = src->GlyphSupportLevel;
1770
1771
72
  return TRUE;
1772
72
}
1773
1774
/*
1775
 * Read glyph cache capability set.
1776
 * msdn{cc240565}
1777
 */
1778
WINPR_ATTR_NODISCARD
1779
static BOOL rdp_read_glyph_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1780
77
{
1781
77
  WINPR_ASSERT(settings);
1782
77
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1783
5
    return FALSE;
1784
1785
  /* glyphCache (40 bytes) */
1786
792
  for (size_t x = 0; x < 10; x++)
1787
720
    rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1788
72
  rdp_read_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1789
72
  Stream_Read_UINT16(s, settings->GlyphSupportLevel);           /* glyphSupportLevel (2 bytes) */
1790
72
  Stream_Seek_UINT16(s);                                        /* pad2Octets (2 bytes) */
1791
72
  return TRUE;
1792
77
}
1793
1794
/*
1795
 * Write glyph cache capability set.
1796
 * msdn{cc240565}
1797
 */
1798
WINPR_ATTR_NODISCARD
1799
static BOOL rdp_write_glyph_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1800
0
{
1801
0
  WINPR_ASSERT(settings);
1802
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
1803
0
    return FALSE;
1804
1805
0
  const size_t header = rdp_capability_set_start(log, s);
1806
0
  if (settings->GlyphSupportLevel > UINT16_MAX)
1807
0
    return FALSE;
1808
  /* glyphCache (40 bytes) */
1809
0
  for (size_t x = 0; x < 10; x++)
1810
0
    rdp_write_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1811
0
  rdp_write_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1812
0
  Stream_Write_UINT16(s, (UINT16)settings->GlyphSupportLevel);   /* glyphSupportLevel (2 bytes) */
1813
0
  Stream_Write_UINT16(s, 0);                                     /* pad2Octets (2 bytes) */
1814
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_GLYPH_CACHE);
1815
0
}
1816
1817
#ifdef WITH_DEBUG_CAPABILITIES
1818
WINPR_ATTR_NODISCARD
1819
static BOOL rdp_print_glyph_cache_capability_set(wLog* log, wStream* s)
1820
{
1821
  GLYPH_CACHE_DEFINITION glyphCache[10] = WINPR_C_ARRAY_INIT;
1822
  GLYPH_CACHE_DEFINITION fragCache = WINPR_C_ARRAY_INIT;
1823
  UINT16 glyphSupportLevel = 0;
1824
  UINT16 pad2Octets = 0;
1825
  WLog_Print(log, WLOG_TRACE,
1826
             "GlyphCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1827
1828
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1829
    return FALSE;
1830
1831
  /* glyphCache (40 bytes) */
1832
  rdp_read_cache_definition(s, &glyphCache[0]); /* glyphCache0 (4 bytes) */
1833
  rdp_read_cache_definition(s, &glyphCache[1]); /* glyphCache1 (4 bytes) */
1834
  rdp_read_cache_definition(s, &glyphCache[2]); /* glyphCache2 (4 bytes) */
1835
  rdp_read_cache_definition(s, &glyphCache[3]); /* glyphCache3 (4 bytes) */
1836
  rdp_read_cache_definition(s, &glyphCache[4]); /* glyphCache4 (4 bytes) */
1837
  rdp_read_cache_definition(s, &glyphCache[5]); /* glyphCache5 (4 bytes) */
1838
  rdp_read_cache_definition(s, &glyphCache[6]); /* glyphCache6 (4 bytes) */
1839
  rdp_read_cache_definition(s, &glyphCache[7]); /* glyphCache7 (4 bytes) */
1840
  rdp_read_cache_definition(s, &glyphCache[8]); /* glyphCache8 (4 bytes) */
1841
  rdp_read_cache_definition(s, &glyphCache[9]); /* glyphCache9 (4 bytes) */
1842
  rdp_read_cache_definition(s, &fragCache);     /* fragCache (4 bytes) */
1843
  Stream_Read_UINT16(s, glyphSupportLevel);     /* glyphSupportLevel (2 bytes) */
1844
  Stream_Read_UINT16(s, pad2Octets);            /* pad2Octets (2 bytes) */
1845
  WLog_Print(log, WLOG_TRACE, "\tglyphCache0: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1846
             glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize);
1847
  WLog_Print(log, WLOG_TRACE, "\tglyphCache1: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1848
             glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize);
1849
  WLog_Print(log, WLOG_TRACE, "\tglyphCache2: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1850
             glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize);
1851
  WLog_Print(log, WLOG_TRACE, "\tglyphCache3: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1852
             glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize);
1853
  WLog_Print(log, WLOG_TRACE, "\tglyphCache4: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1854
             glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize);
1855
  WLog_Print(log, WLOG_TRACE, "\tglyphCache5: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1856
             glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize);
1857
  WLog_Print(log, WLOG_TRACE, "\tglyphCache6: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1858
             glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize);
1859
  WLog_Print(log, WLOG_TRACE, "\tglyphCache7: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1860
             glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize);
1861
  WLog_Print(log, WLOG_TRACE, "\tglyphCache8: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1862
             glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize);
1863
  WLog_Print(log, WLOG_TRACE, "\tglyphCache9: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1864
             glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize);
1865
  WLog_Print(log, WLOG_TRACE, "\tfragCache: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1866
             fragCache.cacheEntries, fragCache.cacheMaximumCellSize);
1867
  WLog_Print(log, WLOG_TRACE, "\tglyphSupportLevel: 0x%04" PRIX16 "", glyphSupportLevel);
1868
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1869
  return TRUE;
1870
}
1871
#endif
1872
WINPR_ATTR_NODISCARD
1873
static BOOL rdp_apply_offscreen_bitmap_cache_capability_set(rdpSettings* settings,
1874
                                                            const rdpSettings* src)
1875
91
{
1876
91
  WINPR_ASSERT(settings);
1877
91
  WINPR_ASSERT(src);
1878
1879
91
  settings->OffscreenCacheSize = src->OffscreenCacheSize;
1880
91
  settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1881
91
  settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1882
1883
91
  return TRUE;
1884
91
}
1885
1886
/*
1887
 * Read offscreen bitmap cache capability set.
1888
 * msdn{cc240550}
1889
 */
1890
WINPR_ATTR_NODISCARD
1891
static BOOL rdp_read_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1892
                                                           rdpSettings* settings)
1893
95
{
1894
95
  UINT32 offscreenSupportLevel = 0;
1895
1896
95
  WINPR_ASSERT(settings);
1897
95
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1898
4
    return FALSE;
1899
1900
91
  Stream_Read_UINT32(s, offscreenSupportLevel);           /* offscreenSupportLevel (4 bytes) */
1901
91
  Stream_Read_UINT16(s, settings->OffscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1902
91
  Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1903
1904
91
  settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1905
1906
91
  return TRUE;
1907
95
}
1908
1909
/*
1910
 * Write offscreen bitmap cache capability set.
1911
 * msdn{cc240550}
1912
 */
1913
WINPR_ATTR_NODISCARD
1914
static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1915
                                                            const rdpSettings* settings)
1916
0
{
1917
0
  UINT32 offscreenSupportLevel = 0x00;
1918
1919
0
  WINPR_ASSERT(settings);
1920
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1921
0
    return FALSE;
1922
1923
0
  const size_t header = rdp_capability_set_start(log, s);
1924
0
  if (settings->OffscreenSupportLevel)
1925
0
  {
1926
0
    offscreenSupportLevel = 0x01;
1927
0
    Stream_Write_UINT32(s, offscreenSupportLevel);        /* offscreenSupportLevel (4 bytes) */
1928
0
    Stream_Write_UINT16(
1929
0
        s, WINPR_ASSERTING_INT_CAST(
1930
0
               uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1931
0
    Stream_Write_UINT16(
1932
0
        s,
1933
0
        WINPR_ASSERTING_INT_CAST(
1934
0
            uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1935
0
  }
1936
0
  else
1937
0
    Stream_Zero(s, 8);
1938
1939
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1940
0
}
1941
1942
#ifdef WITH_DEBUG_CAPABILITIES
1943
WINPR_ATTR_NODISCARD
1944
static BOOL rdp_print_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s)
1945
{
1946
  UINT32 offscreenSupportLevel = 0;
1947
  UINT16 offscreenCacheSize = 0;
1948
  UINT16 offscreenCacheEntries = 0;
1949
  WLog_Print(log, WLOG_TRACE, "OffscreenBitmapCacheCapabilitySet (length %" PRIuz "):",
1950
             Stream_GetRemainingLength(s));
1951
1952
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1953
    return FALSE;
1954
1955
  Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1956
  Stream_Read_UINT16(s, offscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1957
  Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1958
  WLog_Print(log, WLOG_TRACE, "\toffscreenSupportLevel: 0x%08" PRIX32 "", offscreenSupportLevel);
1959
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheSize: 0x%04" PRIX16 "", offscreenCacheSize);
1960
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheEntries: 0x%04" PRIX16 "", offscreenCacheEntries);
1961
  return TRUE;
1962
}
1963
#endif
1964
1965
WINPR_ATTR_NODISCARD
1966
static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1967
                                                               const rdpSettings* src)
1968
73
{
1969
73
  const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1970
40
                    freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1971
73
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1972
73
}
1973
1974
/*
1975
 * Read bitmap cache host support capability set.
1976
 * msdn{cc240557}
1977
 */
1978
WINPR_ATTR_NODISCARD
1979
static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1980
                                                              rdpSettings* settings)
1981
74
{
1982
74
  BYTE cacheVersion = 0;
1983
1984
74
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1985
1
    return FALSE;
1986
1987
73
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1988
73
  Stream_Seek_UINT8(s);               /* pad1 (1 byte) */
1989
73
  Stream_Seek_UINT16(s);              /* pad2 (2 bytes) */
1990
1991
73
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1992
73
                                   cacheVersion & BITMAP_CACHE_V2);
1993
74
}
1994
1995
/*
1996
 * Write bitmap cache host support capability set.
1997
 * msdn{cc240557}
1998
 */
1999
WINPR_ATTR_NODISCARD
2000
static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
2001
                                                               const rdpSettings* settings)
2002
0
{
2003
0
  UINT8 cacheVersion = 0;
2004
2005
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
2006
0
    cacheVersion |= BITMAP_CACHE_V2;
2007
2008
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2009
0
    return FALSE;
2010
2011
0
  const size_t header = rdp_capability_set_start(log, s);
2012
0
  Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
2013
0
  Stream_Write_UINT8(s, 0);            /* pad1 (1 byte) */
2014
0
  Stream_Write_UINT16(s, 0);           /* pad2 (2 bytes) */
2015
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
2016
0
}
2017
2018
#ifdef WITH_DEBUG_CAPABILITIES
2019
WINPR_ATTR_NODISCARD
2020
static BOOL rdp_print_bitmap_cache_host_support_capability_set(wLog* log, wStream* s)
2021
{
2022
  BYTE cacheVersion = 0;
2023
  BYTE pad1 = 0;
2024
  UINT16 pad2 = 0;
2025
  WLog_Print(log, WLOG_TRACE, "BitmapCacheHostSupportCapabilitySet (length %" PRIuz "):",
2026
             Stream_GetRemainingLength(s));
2027
2028
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2029
    return FALSE;
2030
2031
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
2032
  Stream_Read_UINT8(s, pad1);         /* pad1 (1 byte) */
2033
  Stream_Read_UINT16(s, pad2);        /* pad2 (2 bytes) */
2034
  WLog_Print(log, WLOG_TRACE, "\tcacheVersion: 0x%02" PRIX8 "", cacheVersion);
2035
  WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%02" PRIX8 "", pad1);
2036
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%04" PRIX16 "", pad2);
2037
  return TRUE;
2038
}
2039
#endif
2040
2041
WINPR_ATTR_NODISCARD
2042
static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
2043
                                            BITMAP_CACHE_V2_CELL_INFO* cellInfo, size_t limit)
2044
33.6k
{
2045
33.6k
  UINT32 info = 0;
2046
2047
33.6k
  WINPR_ASSERT(cellInfo);
2048
33.6k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2049
0
    return FALSE;
2050
2051
  /*
2052
   * numEntries is in the first 31 bits, while the last bit (k)
2053
   * is used to indicate a persistent bitmap cache.
2054
   */
2055
33.6k
  Stream_Read_UINT32(s, info);
2056
2057
33.6k
  cellInfo->numEntries = (info & 0x7FFFFFFF);
2058
33.6k
  if (cellInfo->numEntries > limit)
2059
27.8k
  {
2060
27.8k
    WLog_Print(log, WLOG_ERROR,
2061
27.8k
               "BITMAP_CACHE_V2_CELL_INFO::numEntries (%" PRIu32 ") > limit(%" PRIuz ")",
2062
27.8k
               cellInfo->numEntries, limit);
2063
27.8k
  }
2064
33.6k
  cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2065
33.6k
  return TRUE;
2066
33.6k
}
2067
2068
WINPR_ATTR_NODISCARD
2069
static BOOL rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2070
0
{
2071
  /*
2072
   * numEntries is in the first 31 bits, while the last bit (k)
2073
   * is used to indicate a persistent bitmap cache.
2074
   */
2075
0
  WINPR_ASSERT(cellInfo);
2076
0
  const UINT32 info =
2077
0
      (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2078
0
  if (!Stream_EnsureRemainingCapacity(s, 4))
2079
0
    return FALSE;
2080
0
  Stream_Write_UINT32(s, info);
2081
0
  return TRUE;
2082
0
}
2083
2084
WINPR_ATTR_NODISCARD
2085
static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2086
8.37k
{
2087
8.37k
  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2088
8.37k
                                            FreeRDP_BitmapCachePersistEnabled };
2089
2090
25.1k
  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2091
16.7k
  {
2092
16.7k
    const FreeRDP_Settings_Keys_Bool id = keys[x];
2093
16.7k
    const BOOL val = freerdp_settings_get_bool(src, id);
2094
16.7k
    if (!freerdp_settings_set_bool(settings, id, val))
2095
0
      return FALSE;
2096
16.7k
  }
2097
2098
8.37k
  {
2099
8.37k
    const UINT32 BitmapCacheV2NumCells =
2100
8.37k
        freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2101
8.37k
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2102
8.37k
                                          BitmapCacheV2NumCells))
2103
0
      return FALSE;
2104
2105
42.0k
    for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2106
33.6k
    {
2107
33.6k
      const BITMAP_CACHE_V2_CELL_INFO* cdata =
2108
33.6k
          freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2109
33.6k
      if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2110
33.6k
                                              cdata))
2111
0
        return FALSE;
2112
33.6k
    }
2113
8.37k
  }
2114
2115
8.37k
  return TRUE;
2116
8.37k
}
2117
2118
/*
2119
 * Read bitmap cache v2 capability set.
2120
 * msdn{cc240560}
2121
 */
2122
WINPR_ATTR_NODISCARD
2123
static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2124
8.38k
{
2125
8.38k
  UINT16 cacheFlags = 0;
2126
8.38k
  WINPR_UNUSED(settings);
2127
8.38k
  WINPR_ASSERT(settings);
2128
2129
8.38k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2130
5
    return FALSE;
2131
2132
8.37k
  Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2133
2134
8.37k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2135
0
    return FALSE;
2136
8.37k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2137
8.37k
                                 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2138
0
    return FALSE;
2139
2140
8.37k
  Stream_Seek_UINT8(s);                                  /* pad2 (1 byte) */
2141
8.37k
  Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2142
8.37k
  if (settings->BitmapCacheV2NumCells > 5)
2143
6
  {
2144
6
    WLog_Print(log, WLOG_ERROR,
2145
6
               "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2146
6
               settings->BitmapCacheV2NumCells);
2147
6
    return FALSE;
2148
6
  }
2149
2150
42.0k
  for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2151
33.6k
  {
2152
33.6k
    BITMAP_CACHE_V2_CELL_INFO* info =
2153
33.6k
        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2154
33.6k
    if (!rdp_read_bitmap_cache_cell_info(log, s, info, bitmapCacheV2CellInfoLimits[x]))
2155
0
      return FALSE;
2156
33.6k
  }
2157
2158
  /* Input must always have 5 BitmapCacheV2CellInfo values */
2159
16.5k
  for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2160
8.21k
  {
2161
8.21k
    if (!Stream_SafeSeek(s, 4))
2162
0
      return FALSE;
2163
8.21k
  }
2164
8.37k
  Stream_Seek(s, 12); /* pad3 (12 bytes) */
2165
8.37k
  return TRUE;
2166
8.37k
}
2167
2168
/*
2169
 * Write bitmap cache v2 capability set.
2170
 * msdn{cc240560}
2171
 */
2172
WINPR_ATTR_NODISCARD
2173
static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2174
                                                     const rdpSettings* settings)
2175
0
{
2176
0
  WINPR_ASSERT(settings);
2177
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
2178
0
    return FALSE;
2179
2180
0
  const UINT32 BitmapCacheV2NumCells =
2181
0
      freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells);
2182
0
  BITMAP_CACHE_V2_CELL_INFO CellInfo[5] = WINPR_C_ARRAY_INIT;
2183
2184
0
  const size_t header = rdp_capability_set_start(log, s);
2185
0
  UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2186
2187
0
  const BOOL persist = freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled);
2188
0
  if (persist)
2189
0
    cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2190
2191
0
  for (UINT32 x = 0; x < BitmapCacheV2NumCells; x++)
2192
0
  {
2193
0
    BITMAP_CACHE_V2_CELL_INFO* cur = &settings->BitmapCacheV2CellInfo[x];
2194
0
    if (persist)
2195
0
      cur->persistent = 1;
2196
0
    CellInfo[x] = *cur;
2197
0
  }
2198
2199
0
  Stream_Write_UINT16(s, cacheFlags);                     /* cacheFlags (2 bytes) */
2200
0
  Stream_Write_UINT8(s, 0);                               /* pad2 (1 byte) */
2201
0
  Stream_Write_UINT8(
2202
0
      s, WINPR_ASSERTING_INT_CAST(uint8_t,
2203
0
                                  settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2204
2205
0
  for (UINT32 x = 0; x < ARRAYSIZE(CellInfo); x++)
2206
0
  {
2207
0
    if (!rdp_write_bitmap_cache_cell_info(s, &CellInfo[x])) /* bitmapCache0CellInfo (4 bytes) */
2208
0
      return FALSE;
2209
0
  }
2210
0
  Stream_Zero(s, 12);                          /* pad3 (12 bytes) */
2211
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2212
0
}
2213
2214
#ifdef WITH_DEBUG_CAPABILITIES
2215
WINPR_ATTR_NODISCARD
2216
static BOOL rdp_print_bitmap_cache_v2_capability_set(wLog* log, wStream* s)
2217
{
2218
  BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5] = WINPR_C_ARRAY_INIT;
2219
  WLog_Print(log, WLOG_TRACE,
2220
             "BitmapCacheV2CapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2221
2222
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2223
    return FALSE;
2224
2225
  const UINT16 cacheFlags = Stream_Get_UINT16(s);  /* cacheFlags (2 bytes) */
2226
  const UINT8 pad2 = Stream_Get_UINT8(s);          /* pad2 (1 byte) */
2227
  const UINT8 numCellCaches = Stream_Get_UINT8(s); /* numCellCaches (1 byte) */
2228
2229
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2230
  {
2231
    if (!rdp_read_bitmap_cache_cell_info(
2232
            log, s, &bitmapCacheV2CellInfo[x],
2233
            bitmapCacheV2CellInfoLimits[x])) /* bitmapCache0CellInfo (4 bytes) */
2234
      return FALSE;
2235
  }
2236
2237
  if (!Stream_SafeSeek(s, 12)) /* pad3 (12 bytes) */
2238
    return FALSE;
2239
2240
  WLog_Print(log, WLOG_TRACE, "\tcacheFlags: 0x%04" PRIX16 "", cacheFlags);
2241
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%02" PRIX8 "", pad2);
2242
  WLog_Print(log, WLOG_TRACE, "\tnumCellCaches: 0x%02" PRIX8 "", numCellCaches);
2243
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2244
  {
2245
    const BITMAP_CACHE_V2_CELL_INFO* info = &bitmapCacheV2CellInfo[x];
2246
    WLog_Print(log, WLOG_TRACE,
2247
               "\tbitmapCache%" PRIuz "CellInfo: numEntries: %" PRIu32 " persistent: %" PRId32
2248
               "",
2249
               x, info->numEntries, info->persistent);
2250
  }
2251
  return TRUE;
2252
}
2253
#endif
2254
2255
WINPR_ATTR_NODISCARD
2256
static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2257
1.19k
{
2258
1.19k
  WINPR_ASSERT(settings);
2259
1.19k
  WINPR_ASSERT(src);
2260
2261
  /* MS servers and clients disregard in advertising what is relevant for their own side */
2262
1.19k
  if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2263
0
      (src->VCFlags & VCCAPS_COMPR_SC))
2264
0
    settings->VCFlags |= VCCAPS_COMPR_SC;
2265
1.19k
  else
2266
1.19k
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2267
2268
1.19k
  if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2269
0
      (src->VCFlags & VCCAPS_COMPR_CS_8K))
2270
0
    settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2271
1.19k
  else
2272
1.19k
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_CS_8K;
2273
2274
  /*
2275
   * When one peer does not write the VCChunkSize, the VCChunkSize must not be
2276
   * larger than CHANNEL_CHUNK_LENGTH (1600) bytes.
2277
   * Also prevent an invalid 0 size.
2278
   */
2279
1.19k
  if (!settings->ServerMode)
2280
344
  {
2281
344
    if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2282
301
      settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2283
43
    else
2284
43
    {
2285
43
      settings->VCChunkSize = src->VCChunkSize;
2286
43
    }
2287
344
  }
2288
2289
1.19k
  return TRUE;
2290
1.19k
}
2291
2292
/*
2293
 * Read virtual channel capability set.
2294
 * msdn{cc240551}
2295
 */
2296
WINPR_ATTR_NODISCARD
2297
static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2298
1.19k
{
2299
1.19k
  UINT32 flags = 0;
2300
1.19k
  UINT32 VCChunkSize = 0;
2301
2302
1.19k
  WINPR_ASSERT(settings);
2303
1.19k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2304
4
    return FALSE;
2305
2306
1.19k
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2307
2308
1.19k
  if (Stream_GetRemainingLength(s) >= 4)
2309
688
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2310
503
  else
2311
503
    VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2312
2313
1.19k
  settings->VCFlags = flags;
2314
1.19k
  settings->VCChunkSize = VCChunkSize;
2315
2316
1.19k
  return TRUE;
2317
1.19k
}
2318
2319
/*
2320
 * Write virtual channel capability set.
2321
 * msdn{cc240551}
2322
 */
2323
WINPR_ATTR_NODISCARD
2324
static BOOL rdp_write_virtual_channel_capability_set(wLog* log, wStream* s,
2325
                                                     const rdpSettings* settings)
2326
0
{
2327
0
  WINPR_ASSERT(settings);
2328
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2329
0
    return FALSE;
2330
2331
0
  const size_t header = rdp_capability_set_start(log, s);
2332
0
  Stream_Write_UINT32(s, settings->VCFlags);     /* flags (4 bytes) */
2333
0
  Stream_Write_UINT32(s, settings->VCChunkSize); /* VCChunkSize (4 bytes) */
2334
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_VIRTUAL_CHANNEL);
2335
0
}
2336
2337
#ifdef WITH_DEBUG_CAPABILITIES
2338
WINPR_ATTR_NODISCARD
2339
static BOOL rdp_print_virtual_channel_capability_set(wLog* log, wStream* s)
2340
{
2341
  UINT32 flags = 0;
2342
  UINT32 VCChunkSize = 0;
2343
  WLog_Print(log, WLOG_TRACE,
2344
             "VirtualChannelCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2345
2346
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2347
    return FALSE;
2348
2349
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2350
2351
  if (Stream_GetRemainingLength(s) >= 4)
2352
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2353
  else
2354
    VCChunkSize = 1600;
2355
2356
  WLog_Print(log, WLOG_TRACE, "\tflags: 0x%08" PRIX32 "", flags);
2357
  WLog_Print(log, WLOG_TRACE, "\tVCChunkSize: 0x%08" PRIX32 "", VCChunkSize);
2358
  return TRUE;
2359
}
2360
#endif
2361
2362
WINPR_ATTR_NODISCARD
2363
static BOOL rdp_apply_draw_nine_grid_cache_capability_set(rdpSettings* settings,
2364
                                                          const rdpSettings* src)
2365
99
{
2366
99
  WINPR_ASSERT(settings);
2367
99
  WINPR_ASSERT(src);
2368
2369
99
  settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2370
99
  settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2371
99
  settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2372
2373
99
  return TRUE;
2374
99
}
2375
2376
/*
2377
 * Read drawn nine grid cache capability set.
2378
 * msdn{cc241565}
2379
 */
2380
WINPR_ATTR_NODISCARD
2381
static BOOL rdp_read_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2382
                                                         rdpSettings* settings)
2383
102
{
2384
102
  UINT32 drawNineGridSupportLevel = 0;
2385
2386
102
  WINPR_ASSERT(settings);
2387
102
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2388
3
    return FALSE;
2389
2390
99
  Stream_Read_UINT32(s, drawNineGridSupportLevel);        /* drawNineGridSupportLevel (4 bytes) */
2391
99
  Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2392
99
  Stream_Read_UINT16(s,
2393
99
                     settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2394
2395
99
  settings->DrawNineGridEnabled =
2396
99
      (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2397
2398
99
  return TRUE;
2399
102
}
2400
2401
/*
2402
 * Write drawn nine grid cache capability set.
2403
 * msdn{cc241565}
2404
 */
2405
WINPR_ATTR_NODISCARD
2406
static BOOL rdp_write_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2407
                                                          const rdpSettings* settings)
2408
0
{
2409
0
  WINPR_ASSERT(settings);
2410
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2411
0
    return FALSE;
2412
2413
0
  const size_t header = rdp_capability_set_start(log, s);
2414
0
  const UINT32 drawNineGridSupportLevel =
2415
0
      (settings->DrawNineGridEnabled) ? DRAW_NINEGRID_SUPPORTED_V2 : DRAW_NINEGRID_NO_SUPPORT;
2416
0
  Stream_Write_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2417
0
  Stream_Write_UINT16(
2418
0
      s, WINPR_ASSERTING_INT_CAST(
2419
0
             uint16_t, settings->DrawNineGridCacheSize)); /* drawNineGridCacheSize (2 bytes) */
2420
0
  Stream_Write_UINT16(
2421
0
      s,
2422
0
      WINPR_ASSERTING_INT_CAST(
2423
0
          uint16_t, settings->DrawNineGridCacheEntries)); /* drawNineGridCacheEntries (2 bytes) */
2424
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_DRAW_NINE_GRID_CACHE);
2425
0
}
2426
2427
#ifdef WITH_DEBUG_CAPABILITIES
2428
WINPR_ATTR_NODISCARD
2429
static BOOL rdp_print_draw_nine_grid_cache_capability_set(wLog* log, wStream* s)
2430
{
2431
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2432
    return FALSE;
2433
2434
  const uint32_t drawNineGridSupportLevel =
2435
      Stream_Get_UINT32(s); /* drawNineGridSupportLevel (4 bytes) */
2436
  const uint32_t DrawNineGridCacheSize =
2437
      Stream_Get_UINT16(s); /* drawNineGridCacheSize (2 bytes) */
2438
  const uint32_t DrawNineGridCacheEntries =
2439
      Stream_Get_UINT16(s); /* drawNineGridCacheEntries (2 bytes) */
2440
2441
  WLog_Print(log, WLOG_TRACE,
2442
             "DrawNineGridCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2443
  WLog_Print(log, WLOG_TRACE, "drawNineGridSupportLevel=0x%08" PRIx32, drawNineGridSupportLevel);
2444
  WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheSize=0x%08" PRIx32, DrawNineGridCacheSize);
2445
  WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheEntries=0x%08" PRIx32, DrawNineGridCacheEntries);
2446
  return TRUE;
2447
}
2448
#endif
2449
2450
WINPR_ATTR_NODISCARD
2451
static BOOL rdp_apply_draw_gdiplus_cache_capability_set(rdpSettings* settings,
2452
                                                        const rdpSettings* src)
2453
83
{
2454
83
  WINPR_ASSERT(settings);
2455
83
  WINPR_ASSERT(src);
2456
2457
83
  if (src->DrawGdiPlusEnabled)
2458
41
    settings->DrawGdiPlusEnabled = TRUE;
2459
2460
83
  if (src->DrawGdiPlusCacheEnabled)
2461
42
    settings->DrawGdiPlusCacheEnabled = TRUE;
2462
2463
83
  return TRUE;
2464
83
}
2465
2466
/*
2467
 * Read GDI+ cache capability set.
2468
 * msdn{cc241566}
2469
 */
2470
WINPR_ATTR_NODISCARD
2471
static BOOL rdp_read_draw_gdiplus_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2472
89
{
2473
89
  UINT32 drawGDIPlusSupportLevel = 0;
2474
89
  UINT32 drawGdiplusCacheLevel = 0;
2475
2476
89
  WINPR_ASSERT(settings);
2477
89
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2478
6
    return FALSE;
2479
2480
83
  Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2481
83
  Stream_Seek_UINT32(s);                          /* GdipVersion (4 bytes) */
2482
83
  Stream_Read_UINT32(s, drawGdiplusCacheLevel);   /* drawGdiplusCacheLevel (4 bytes) */
2483
83
  Stream_Seek(s, 10);                             /* GdipCacheEntries (10 bytes) */
2484
83
  Stream_Seek(s, 8);                              /* GdipCacheChunkSize (8 bytes) */
2485
83
  Stream_Seek(s, 6);                              /* GdipImageCacheProperties (6 bytes) */
2486
2487
83
  settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2488
83
  settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2489
2490
83
  return TRUE;
2491
89
}
2492
2493
#ifdef WITH_DEBUG_CAPABILITIES
2494
WINPR_ATTR_NODISCARD
2495
static BOOL rdp_print_draw_gdiplus_cache_capability_set(wLog* log, wStream* s)
2496
{
2497
  WLog_Print(log, WLOG_TRACE,
2498
             "DrawGdiPlusCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2499
2500
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2501
    return FALSE;
2502
2503
  const uint32_t drawGdiPlusSupportLevel =
2504
      Stream_Get_UINT32(s);                          /* drawGdiPlusSupportLevel (4 bytes) */
2505
  const uint32_t GdipVersion = Stream_Get_UINT32(s); /* GdipVersion (4 bytes) */
2506
  const uint32_t drawGdiplusCacheLevel =
2507
      Stream_Get_UINT32(s); /* drawGdiPlusCacheLevel (4 bytes) */
2508
  WLog_Print(log, WLOG_TRACE,
2509
             "drawGdiPlusSupportLevel=0x%08" PRIx32 ", GdipVersion=0x%08" PRIx32
2510
             ", drawGdiplusdrawGdiplusCacheLevelCacheLevel=0x%08" PRIx32,
2511
             drawGdiPlusSupportLevel, GdipVersion, drawGdiplusCacheLevel);
2512
  /* GdipCacheEntries (10 bytes) */
2513
  const uint16_t GdipGraphicsCacheEntries = Stream_Get_UINT16(s);
2514
  const uint16_t GdipBrushCacheEntries = Stream_Get_UINT16(s);
2515
  const uint16_t GdipPenCacheEntries = Stream_Get_UINT16(s);
2516
  const uint16_t GdipImageCacheEntries = Stream_Get_UINT16(s);
2517
  const uint16_t GdipImageAttributesCacheEntries = Stream_Get_UINT16(s);
2518
  WLog_Print(log, WLOG_TRACE,
2519
             "GdipGraphicsCacheEntries=0x%04" PRIx16 ", GdipBrushCacheEntries=0x%04" PRIx16
2520
             ", GdipPenCacheEntries=0x%04" PRIx16 ", GdipImageCacheEntries=0x%04" PRIx16
2521
             ", GdipImageAttributesCacheEntries=0x%04" PRIx16,
2522
             GdipGraphicsCacheEntries, GdipBrushCacheEntries, GdipPenCacheEntries,
2523
             GdipImageCacheEntries, GdipImageAttributesCacheEntries);
2524
  /* GdipCacheChunkSize (8 bytes) */
2525
  const uint16_t GdipGraphicsCacheChunkSize = Stream_Get_UINT16(s);
2526
  const uint16_t GdipObjectBrushCacheChunkSize = Stream_Get_UINT16(s);
2527
  const uint16_t GdipObjectPenCacheChunkSize = Stream_Get_UINT16(s);
2528
  const uint16_t GdipObjectImageAttributesCacheChunkSize = Stream_Get_UINT16(s);
2529
  WLog_Print(log, WLOG_TRACE,
2530
             "GdipGraphicsCacheChunkSize=0x%04" PRIx16
2531
             ", GdipObjectBrushCacheChunkSize=0x%04" PRIx16
2532
             ", GdipObjectPenCacheChunkSize=0x%04" PRIx16
2533
             ",GdipObjectImageAttributesCacheChunkSize=0x%04" PRIx16,
2534
             GdipGraphicsCacheChunkSize, GdipObjectBrushCacheChunkSize,
2535
             GdipObjectPenCacheChunkSize, GdipObjectImageAttributesCacheChunkSize);
2536
  /* GdipImageCacheProperties (6 bytes) */
2537
  const uint16_t GdipObjectImageCacheChunkSize = Stream_Get_UINT16(s);
2538
  const uint16_t GdipObjectImageCacheTotalSize = Stream_Get_UINT16(s);
2539
  const uint16_t GdipObjectImageCacheMaxSize = Stream_Get_UINT16(s);
2540
  WLog_Print(
2541
      log, WLOG_TRACE,
2542
      "GdipObjectImageCacheChunkSize=0x%04" PRIx16 ", GdipObjectImageCacheTotalSize=0x%04" PRIx16
2543
      ", GdipObjectImageCacheMaxSize=0x%04" PRIx16,
2544
      GdipObjectImageCacheChunkSize, GdipObjectImageCacheTotalSize, GdipObjectImageCacheMaxSize);
2545
  return TRUE;
2546
}
2547
#endif
2548
2549
WINPR_ATTR_NODISCARD
2550
static BOOL rdp_apply_remote_programs_capability_set(rdpSettings* settings, const rdpSettings* src)
2551
57
{
2552
57
  WINPR_ASSERT(settings);
2553
57
  WINPR_ASSERT(src);
2554
2555
57
  if (settings->RemoteApplicationMode)
2556
0
    settings->RemoteApplicationMode = src->RemoteApplicationMode;
2557
2558
  /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
2559
   * the handshake ex pdu is supported when both, client and server announce
2560
   * it OR if we are ready to begin enhanced remoteAPP mode. */
2561
57
  UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2562
57
  if (settings->RemoteApplicationMode)
2563
0
    supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2564
2565
57
  settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2566
2567
57
  return TRUE;
2568
57
}
2569
2570
/*
2571
 * Read remote programs capability set.
2572
 * msdn{cc242518}
2573
 */
2574
WINPR_ATTR_NODISCARD
2575
static BOOL rdp_read_remote_programs_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2576
62
{
2577
62
  UINT32 railSupportLevel = 0;
2578
2579
62
  WINPR_ASSERT(settings);
2580
62
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2581
5
    return FALSE;
2582
2583
57
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2584
2585
57
  settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2586
57
  settings->RemoteApplicationSupportLevel = railSupportLevel;
2587
57
  return TRUE;
2588
62
}
2589
2590
/*
2591
 * Write remote programs capability set.
2592
 * msdn{cc242518}
2593
 */
2594
WINPR_ATTR_NODISCARD
2595
static BOOL rdp_write_remote_programs_capability_set(wLog* log, wStream* s,
2596
                                                     const rdpSettings* settings)
2597
0
{
2598
0
  WINPR_ASSERT(settings);
2599
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
2600
0
    return FALSE;
2601
2602
0
  const size_t header = rdp_capability_set_start(log, s);
2603
0
  UINT32 railSupportLevel = RAIL_LEVEL_SUPPORTED;
2604
2605
0
  if (settings->RemoteApplicationSupportLevel & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)
2606
0
  {
2607
0
    if (settings->RemoteAppLanguageBarSupported)
2608
0
      railSupportLevel |= RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED;
2609
0
  }
2610
2611
0
  railSupportLevel |= RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED;
2612
0
  railSupportLevel |= RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED;
2613
0
  railSupportLevel |= RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED;
2614
0
  railSupportLevel |= RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED;
2615
0
  railSupportLevel |= RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED;
2616
0
  railSupportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2617
  /* Mask out everything the server does not support. */
2618
0
  railSupportLevel &= settings->RemoteApplicationSupportLevel;
2619
0
  Stream_Write_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2620
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_RAIL);
2621
0
}
2622
2623
#ifdef WITH_DEBUG_CAPABILITIES
2624
WINPR_ATTR_NODISCARD
2625
static BOOL rdp_print_remote_programs_capability_set(wLog* log, wStream* s)
2626
{
2627
  UINT32 railSupportLevel = 0;
2628
  WLog_Print(log, WLOG_TRACE,
2629
             "RemoteProgramsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2630
2631
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2632
    return FALSE;
2633
2634
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2635
  WLog_Print(log, WLOG_TRACE, "\trailSupportLevel: 0x%08" PRIX32 "", railSupportLevel);
2636
  return TRUE;
2637
}
2638
#endif
2639
2640
WINPR_ATTR_NODISCARD
2641
static BOOL rdp_apply_window_list_capability_set(rdpSettings* settings, const rdpSettings* src)
2642
394
{
2643
394
  WINPR_ASSERT(settings);
2644
394
  WINPR_ASSERT(src);
2645
2646
394
  settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2647
394
  settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2648
394
  settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2649
2650
394
  return TRUE;
2651
394
}
2652
2653
/*
2654
 * Read window list capability set.
2655
 * msdn{cc242564}
2656
 */
2657
WINPR_ATTR_NODISCARD
2658
static BOOL rdp_read_window_list_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2659
400
{
2660
400
  WINPR_ASSERT(settings);
2661
400
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2662
6
    return FALSE;
2663
2664
394
  Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2665
394
  Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2666
394
  Stream_Read_UINT16(s,
2667
394
                     settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2668
394
  return TRUE;
2669
400
}
2670
2671
/*
2672
 * Write window list capability set.
2673
 * msdn{cc242564}
2674
 */
2675
WINPR_ATTR_NODISCARD
2676
static BOOL rdp_write_window_list_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
2677
0
{
2678
0
  WINPR_ASSERT(settings);
2679
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2680
0
    return FALSE;
2681
2682
0
  const size_t header = rdp_capability_set_start(log, s);
2683
0
  Stream_Write_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2684
0
  Stream_Write_UINT8(
2685
0
      s, WINPR_ASSERTING_INT_CAST(uint8_t,
2686
0
                                  settings->RemoteAppNumIconCaches)); /* numIconCaches (1 byte) */
2687
0
  Stream_Write_UINT16(
2688
0
      s,
2689
0
      WINPR_ASSERTING_INT_CAST(
2690
0
          uint16_t, settings->RemoteAppNumIconCacheEntries)); /* numIconCacheEntries (2 bytes) */
2691
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_WINDOW);
2692
0
}
2693
2694
#ifdef WITH_DEBUG_CAPABILITIES
2695
WINPR_ATTR_NODISCARD
2696
static BOOL rdp_print_window_list_capability_set(wLog* log, wStream* s)
2697
{
2698
  UINT32 wndSupportLevel = 0;
2699
  BYTE numIconCaches = 0;
2700
  UINT16 numIconCacheEntries = 0;
2701
  WLog_Print(log, WLOG_TRACE,
2702
             "WindowListCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2703
2704
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2705
    return FALSE;
2706
2707
  Stream_Read_UINT32(s, wndSupportLevel);     /* wndSupportLevel (4 bytes) */
2708
  Stream_Read_UINT8(s, numIconCaches);        /* numIconCaches (1 byte) */
2709
  Stream_Read_UINT16(s, numIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2710
  WLog_Print(log, WLOG_TRACE, "\twndSupportLevel: 0x%08" PRIX32 "", wndSupportLevel);
2711
  WLog_Print(log, WLOG_TRACE, "\tnumIconCaches: 0x%02" PRIX8 "", numIconCaches);
2712
  WLog_Print(log, WLOG_TRACE, "\tnumIconCacheEntries: 0x%04" PRIX16 "", numIconCacheEntries);
2713
  return TRUE;
2714
}
2715
#endif
2716
2717
WINPR_ATTR_NODISCARD
2718
static BOOL rdp_apply_desktop_composition_capability_set(rdpSettings* settings,
2719
                                                         const rdpSettings* src)
2720
24
{
2721
24
  WINPR_ASSERT(settings);
2722
24
  WINPR_ASSERT(src);
2723
2724
24
  settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2725
24
  return TRUE;
2726
24
}
2727
2728
/*
2729
 * Read desktop composition capability set.
2730
 * msdn{cc240855}
2731
 */
2732
WINPR_ATTR_NODISCARD
2733
static BOOL rdp_read_desktop_composition_capability_set(wLog* log, wStream* s,
2734
                                                        rdpSettings* settings)
2735
29
{
2736
29
  WINPR_UNUSED(settings);
2737
29
  WINPR_ASSERT(settings);
2738
2739
29
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2740
5
    return FALSE;
2741
2742
24
  Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2743
24
  return TRUE;
2744
29
}
2745
2746
/*
2747
 * Write desktop composition capability set.
2748
 * msdn{cc240855}
2749
 */
2750
WINPR_ATTR_NODISCARD
2751
static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2752
                                                         const rdpSettings* settings)
2753
0
{
2754
0
  WINPR_ASSERT(settings);
2755
2756
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2757
0
    return FALSE;
2758
2759
0
  const size_t header = rdp_capability_set_start(log, s);
2760
0
  const UINT16 compDeskSupportLevel =
2761
0
      (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2762
0
  Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2763
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2764
0
}
2765
2766
#ifdef WITH_DEBUG_CAPABILITIES
2767
WINPR_ATTR_NODISCARD
2768
static BOOL rdp_print_desktop_composition_capability_set(wLog* log, wStream* s)
2769
{
2770
  UINT16 compDeskSupportLevel = 0;
2771
  WLog_Print(log, WLOG_TRACE, "DesktopCompositionCapabilitySet (length %" PRIuz "):",
2772
             Stream_GetRemainingLength(s));
2773
2774
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2775
    return FALSE;
2776
2777
  Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2778
  WLog_Print(log, WLOG_TRACE, "\tcompDeskSupportLevel: 0x%04" PRIX16 "", compDeskSupportLevel);
2779
  return TRUE;
2780
}
2781
#endif
2782
2783
WINPR_ATTR_NODISCARD
2784
static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2785
                                                          const rdpSettings* src)
2786
1.67k
{
2787
1.67k
  WINPR_ASSERT(settings);
2788
1.67k
  WINPR_ASSERT(src);
2789
2790
1.67k
  UINT32 multifragMaxRequestSize =
2791
1.67k
      freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2792
2793
1.67k
  if (settings->ServerMode)
2794
1.44k
  {
2795
    /*
2796
     * Special case: The client announces multifragment update support but sets the maximum
2797
     * request size to something smaller than maximum size for *one* fast-path PDU. In this case
2798
     * behave like no multifragment updates were supported and make sure no fragmentation
2799
     * happens by setting FASTPATH_FRAGMENT_SAFE_SIZE.
2800
     *
2801
     * This behaviour was observed with some windows ce rdp clients.
2802
     */
2803
1.44k
    if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2804
78
      multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2805
2806
1.44k
    if (settings->RemoteFxCodec)
2807
0
    {
2808
      /*
2809
       * If we are using RemoteFX the client MUST use a value greater
2810
       * than or equal to the value we've previously sent in the server to
2811
       * client multi-fragment update capability set (MS-RDPRFX 1.5)
2812
       */
2813
0
      if (multifragMaxRequestSize <
2814
0
          freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2815
0
      {
2816
        /*
2817
         * If it happens to be smaller we honor the client's value but
2818
         * have to disable RemoteFX
2819
         */
2820
0
        settings->RemoteFxCodec = FALSE;
2821
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2822
0
                                         multifragMaxRequestSize))
2823
0
          return FALSE;
2824
0
      }
2825
0
      else
2826
0
      {
2827
        /* no need to increase server's max request size setting here */
2828
0
      }
2829
0
    }
2830
1.44k
    else
2831
1.44k
    {
2832
1.44k
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2833
1.44k
                                       multifragMaxRequestSize))
2834
0
        return FALSE;
2835
1.44k
    }
2836
1.44k
  }
2837
236
  else
2838
236
  {
2839
    /*
2840
     * In client mode we keep up with the server's capabilities.
2841
     * In RemoteFX mode we MUST do this but it might also be useful to
2842
     * receive larger related bitmap updates.
2843
     */
2844
236
    if (multifragMaxRequestSize >
2845
236
        freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2846
50
    {
2847
50
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2848
50
                                       multifragMaxRequestSize))
2849
0
        return FALSE;
2850
50
    }
2851
236
  }
2852
1.67k
  return TRUE;
2853
1.67k
}
2854
2855
/*
2856
 * Read multifragment update capability set.
2857
 * msdn{cc240649}
2858
 */
2859
WINPR_ATTR_NODISCARD
2860
static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2861
                                                         rdpSettings* settings)
2862
1.68k
{
2863
1.68k
  WINPR_ASSERT(settings);
2864
1.68k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2865
4
    return FALSE;
2866
2867
1.67k
  const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2868
1.67k
  return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2869
1.67k
                                     multifragMaxRequestSize);
2870
1.68k
}
2871
2872
/*
2873
 * Write multifragment update capability set.
2874
 * msdn{cc240649}
2875
 */
2876
WINPR_ATTR_NODISCARD
2877
static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2878
                                                          rdpSettings* settings)
2879
0
{
2880
0
  WINPR_ASSERT(settings);
2881
0
  if (settings->ServerMode &&
2882
0
      (freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize) == 0))
2883
0
  {
2884
    /*
2885
     * In server mode we prefer to use the highest useful request size that
2886
     * will allow us to pack a complete screen update into a single fast
2887
     * path PDU using any of the supported codecs.
2888
     * However, the client is completely free to accept our proposed
2889
     * max request size or send a different value in the client-to-server
2890
     * multi-fragment update capability set and we have to accept that,
2891
     * unless we are using RemoteFX where the client MUST announce a value
2892
     * greater than or equal to the value we're sending here.
2893
     * See [MS-RDPRFX 1.5 capability #2]
2894
     */
2895
0
    const UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2896
0
    const UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2897
0
    const UINT32 limit = UINT32_MAX / 16384u;
2898
2899
0
    if (tileNumX >= limit / tileNumY)
2900
0
    {
2901
0
      WLog_Print(log, WLOG_ERROR,
2902
0
                 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2903
0
      return FALSE;
2904
0
    }
2905
0
    if (tileNumY >= limit / tileNumX)
2906
0
    {
2907
0
      WLog_Print(log, WLOG_ERROR,
2908
0
                 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2909
0
      return FALSE;
2910
0
    }
2911
2912
    /* and add room for headers, regions, frame markers, etc. */
2913
0
    const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2914
2915
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2916
0
                                     MultifragMaxRequestSize))
2917
0
      return FALSE;
2918
0
  }
2919
2920
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2921
0
    return FALSE;
2922
0
  const size_t header = rdp_capability_set_start(log, s);
2923
0
  Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2924
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2925
0
}
2926
2927
#ifdef WITH_DEBUG_CAPABILITIES
2928
WINPR_ATTR_NODISCARD
2929
static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2930
{
2931
  UINT32 maxRequestSize = 0;
2932
  WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2933
             Stream_GetRemainingLength(s));
2934
2935
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2936
    return FALSE;
2937
2938
  Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2939
  WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2940
  return TRUE;
2941
}
2942
#endif
2943
2944
WINPR_ATTR_NODISCARD
2945
static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2946
1.59k
{
2947
1.59k
  WINPR_ASSERT(settings);
2948
1.59k
  WINPR_ASSERT(src);
2949
2950
1.59k
  settings->LargePointerFlag = src->LargePointerFlag;
2951
1.59k
  return TRUE;
2952
1.59k
}
2953
2954
/*
2955
 * Read large pointer capability set.
2956
 * msdn{cc240650}
2957
 */
2958
WINPR_ATTR_NODISCARD
2959
static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2960
1.59k
{
2961
1.59k
  UINT16 largePointerSupportFlags = 0;
2962
2963
1.59k
  WINPR_ASSERT(settings);
2964
1.59k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2965
2
    return FALSE;
2966
2967
1.59k
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2968
1.59k
  settings->LargePointerFlag &= largePointerSupportFlags;
2969
1.59k
  if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2970
1.04k
  {
2971
1.04k
    WLog_Print(
2972
1.04k
        log, WLOG_WARN,
2973
1.04k
        "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2974
1.04k
        WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2975
1.04k
                                                                   LARGE_POINTER_FLAG_384x384)),
2976
1.04k
        largePointerSupportFlags);
2977
1.04k
  }
2978
1.59k
  return TRUE;
2979
1.59k
}
2980
2981
/*
2982
 * Write large pointer capability set.
2983
 * msdn{cc240650}
2984
 */
2985
WINPR_ATTR_NODISCARD
2986
static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2987
                                                   const rdpSettings* settings)
2988
0
{
2989
0
  WINPR_ASSERT(settings);
2990
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2991
0
    return FALSE;
2992
2993
0
  const size_t header = rdp_capability_set_start(log, s);
2994
0
  const UINT16 largePointerSupportFlags =
2995
0
      settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2996
0
  Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2997
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2998
0
}
2999
3000
#ifdef WITH_DEBUG_CAPABILITIES
3001
WINPR_ATTR_NODISCARD
3002
static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
3003
{
3004
  UINT16 largePointerSupportFlags = 0;
3005
  WLog_Print(log, WLOG_TRACE,
3006
             "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3007
3008
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
3009
    return FALSE;
3010
3011
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
3012
  WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
3013
             largePointerSupportFlags);
3014
  return TRUE;
3015
}
3016
#endif
3017
3018
WINPR_ATTR_NODISCARD
3019
static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
3020
557
{
3021
557
  WINPR_ASSERT(settings);
3022
557
  WINPR_ASSERT(src);
3023
3024
  /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
3025
   *
3026
   * disable surface commands if the remote does not support fastpath
3027
   */
3028
557
  if (src->FastPathOutput)
3029
502
  {
3030
502
    settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
3031
502
    settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
3032
502
    settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
3033
502
  }
3034
55
  else
3035
55
  {
3036
55
    settings->SurfaceCommandsSupported = 0;
3037
55
    settings->SurfaceCommandsEnabled = FALSE;
3038
55
    settings->SurfaceFrameMarkerEnabled = FALSE;
3039
55
  }
3040
3041
557
  return TRUE;
3042
557
}
3043
3044
/*
3045
 * Read surface commands capability set.
3046
 * msdn{dd871563}
3047
 */
3048
WINPR_ATTR_NODISCARD
3049
static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3050
565
{
3051
565
  UINT32 cmdFlags = 0;
3052
3053
565
  WINPR_ASSERT(settings);
3054
565
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3055
8
    return FALSE;
3056
3057
557
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3058
557
  Stream_Seek_UINT32(s);           /* reserved (4 bytes) */
3059
557
  settings->SurfaceCommandsSupported = cmdFlags;
3060
557
  settings->SurfaceCommandsEnabled =
3061
557
      (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
3062
557
  settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
3063
557
  return TRUE;
3064
565
}
3065
3066
/*
3067
 * Write surface commands capability set.
3068
 * msdn{dd871563}
3069
 */
3070
WINPR_ATTR_NODISCARD
3071
static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
3072
                                                      const rdpSettings* settings)
3073
0
{
3074
0
  WINPR_ASSERT(settings);
3075
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3076
0
    return FALSE;
3077
3078
0
  const size_t header = rdp_capability_set_start(log, s);
3079
  // TODO: Make these configurable too
3080
0
  UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
3081
3082
0
  if (settings->SurfaceFrameMarkerEnabled)
3083
0
    cmdFlags |= SURFCMDS_FRAME_MARKER;
3084
3085
0
  Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3086
0
  Stream_Write_UINT32(s, 0);        /* reserved (4 bytes) */
3087
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
3088
0
}
3089
3090
WINPR_ATTR_NODISCARD
3091
static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
3092
3.28k
{
3093
3.28k
  if (!Uuid1 && !Uuid2)
3094
0
    return false;
3095
3096
3.28k
  if (Uuid1 && !Uuid2)
3097
0
    return false;
3098
3099
3.28k
  if (!Uuid1 && Uuid2)
3100
0
    return false;
3101
3102
3.28k
  if (Uuid1->Data1 != Uuid2->Data1)
3103
3.11k
    return false;
3104
3105
169
  if (Uuid1->Data2 != Uuid2->Data2)
3106
159
    return false;
3107
3108
10
  if (Uuid1->Data3 != Uuid2->Data3)
3109
3
    return false;
3110
3111
16
  for (int index = 0; index < 8; index++)
3112
16
  {
3113
16
    if (Uuid1->Data4[index] != Uuid2->Data4[index])
3114
7
      return false;
3115
16
  }
3116
3117
0
  return true;
3118
7
}
3119
3120
#ifdef WITH_DEBUG_CAPABILITIES
3121
WINPR_ATTR_NODISCARD
3122
static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3123
{
3124
  UINT32 cmdFlags = 0;
3125
  UINT32 reserved = 0;
3126
3127
  WLog_Print(log, WLOG_TRACE,
3128
             "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3129
3130
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3131
    return FALSE;
3132
3133
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3134
  Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3135
  WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3136
  WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3137
  return TRUE;
3138
}
3139
3140
static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3141
{
3142
  WINPR_ASSERT(guid);
3143
  WLog_Print(log, WLOG_TRACE,
3144
             "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3145
             "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3146
             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3147
             guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3148
             guid->Data4[7]);
3149
}
3150
3151
WINPR_ATTR_NODISCARD
3152
static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3153
{
3154
  WINPR_ASSERT(guid);
3155
  if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3156
    return "CODEC_GUID_REMOTEFX";
3157
  else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3158
    return "CODEC_GUID_NSCODEC";
3159
  else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3160
    return "CODEC_GUID_IGNORE";
3161
  else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3162
    return "CODEC_GUID_IMAGE_REMOTEFX";
3163
3164
#if defined(WITH_JPEG)
3165
  else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3166
    return "CODEC_GUID_JPEG";
3167
3168
#endif
3169
  return "CODEC_GUID_UNKNOWN";
3170
}
3171
#endif
3172
3173
WINPR_ATTR_NODISCARD
3174
static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3175
1.16k
{
3176
1.16k
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3177
3178
1.16k
  WINPR_ASSERT(guid);
3179
1.16k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3180
60
    return FALSE;
3181
1.10k
  Stream_Read(s, g, 16);
3182
1.10k
  guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3183
1.10k
  guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3184
1.10k
  guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3185
1.10k
  guid->Data4[0] = g[8];
3186
1.10k
  guid->Data4[1] = g[9];
3187
1.10k
  guid->Data4[2] = g[10];
3188
1.10k
  guid->Data4[3] = g[11];
3189
1.10k
  guid->Data4[4] = g[12];
3190
1.10k
  guid->Data4[5] = g[13];
3191
1.10k
  guid->Data4[6] = g[14];
3192
1.10k
  guid->Data4[7] = g[15];
3193
1.10k
  return TRUE;
3194
1.16k
}
3195
3196
static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3197
0
{
3198
0
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3199
0
  WINPR_ASSERT(guid);
3200
0
  g[0] = guid->Data1 & 0xFF;
3201
0
  g[1] = (guid->Data1 >> 8) & 0xFF;
3202
0
  g[2] = (guid->Data1 >> 16) & 0xFF;
3203
0
  g[3] = (guid->Data1 >> 24) & 0xFF;
3204
0
  g[4] = (guid->Data2) & 0xFF;
3205
0
  g[5] = (guid->Data2 >> 8) & 0xFF;
3206
0
  g[6] = (guid->Data3) & 0xFF;
3207
0
  g[7] = (guid->Data3 >> 8) & 0xFF;
3208
0
  g[8] = guid->Data4[0];
3209
0
  g[9] = guid->Data4[1];
3210
0
  g[10] = guid->Data4[2];
3211
0
  g[11] = guid->Data4[3];
3212
0
  g[12] = guid->Data4[4];
3213
0
  g[13] = guid->Data4[5];
3214
0
  g[14] = guid->Data4[6];
3215
0
  g[15] = guid->Data4[7];
3216
0
  Stream_Write(s, g, 16);
3217
0
}
3218
3219
WINPR_ATTR_NODISCARD
3220
static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3221
639
{
3222
639
  WINPR_ASSERT(settings);
3223
639
  WINPR_ASSERT(src);
3224
3225
639
  if (settings->ServerMode)
3226
628
  {
3227
3228
628
    settings->RemoteFxCodecId = src->RemoteFxCodecId;
3229
628
    settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3230
628
    settings->RemoteFxOnly = src->RemoteFxOnly;
3231
628
    settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3232
628
    settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3233
628
    settings->NSCodecId = src->NSCodecId;
3234
628
    settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3235
628
    settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3236
628
    settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3237
3238
    /* only enable a codec if we've announced/enabled it before */
3239
628
    settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3240
628
    settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3241
628
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3242
628
                                   settings->NSCodec && src->NSCodec))
3243
0
      return FALSE;
3244
628
    settings->JpegCodec = src->JpegCodec;
3245
628
  }
3246
639
  return TRUE;
3247
639
}
3248
3249
WINPR_ATTR_NODISCARD
3250
static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3251
                                       UINT16 icapLen)
3252
0
{
3253
0
  UINT16 version = 0;
3254
0
  UINT16 tileSize = 0;
3255
0
  BYTE codecFlags = 0;
3256
0
  BYTE colConvBits = 0;
3257
0
  BYTE transformBits = 0;
3258
0
  BYTE entropyBits = 0;
3259
  /* TS_RFX_ICAP */
3260
0
  if (icapLen != 8)
3261
0
  {
3262
0
    WLog_Print(log, WLOG_ERROR,
3263
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3264
0
               " unsupported, expecting size %" PRIu16 " not supported",
3265
0
               icapLen, 8u);
3266
0
    return FALSE;
3267
0
  }
3268
3269
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3270
0
    return FALSE;
3271
3272
0
  Stream_Read_UINT16(sub, version);      /* version (2 bytes) */
3273
0
  Stream_Read_UINT16(sub, tileSize);     /* tileSize (2 bytes) */
3274
0
  Stream_Read_UINT8(sub, codecFlags);    /* flags (1 byte) */
3275
0
  Stream_Read_UINT8(sub, colConvBits);   /* colConvBits (1 byte) */
3276
0
  Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3277
0
  Stream_Read_UINT8(sub, entropyBits);   /* entropyBits (1 byte) */
3278
3279
0
  if (version == 0x0009)
3280
0
  {
3281
    /* Version 0.9 */
3282
0
    if (tileSize != 0x0080)
3283
0
    {
3284
0
      WLog_Print(log, WLOG_ERROR,
3285
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3286
0
                 " tile size %" PRIu16 " not supported",
3287
0
                 version, tileSize);
3288
0
      return FALSE;
3289
0
    }
3290
0
  }
3291
0
  else if (version == 0x0100)
3292
0
  {
3293
    /* Version 1.0 */
3294
0
    if (tileSize != 0x0040)
3295
0
    {
3296
0
      WLog_Print(log, WLOG_ERROR,
3297
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3298
0
                 " tile size %" PRIu16 " not supported",
3299
0
                 version, tileSize);
3300
0
      return FALSE;
3301
0
    }
3302
0
  }
3303
0
  else
3304
0
  {
3305
0
    WLog_Print(log, WLOG_ERROR,
3306
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3307
0
               version);
3308
0
    return FALSE;
3309
0
  }
3310
3311
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3312
0
  if (colConvBits != 1)
3313
0
  {
3314
0
    WLog_Print(log, WLOG_ERROR,
3315
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3316
0
               " not supported, must be CLW_COL_CONV_ICT (0x1)",
3317
0
               colConvBits);
3318
0
    return FALSE;
3319
0
  }
3320
3321
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3322
0
  if (transformBits != 1)
3323
0
  {
3324
0
    WLog_Print(log, WLOG_ERROR,
3325
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3326
0
               " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3327
0
               colConvBits);
3328
0
    return FALSE;
3329
0
  }
3330
3331
0
  const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3332
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3333
0
    return FALSE;
3334
3335
0
  if ((codecFlags & CODEC_MODE) != 0)
3336
0
  {
3337
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3338
0
      return FALSE;
3339
0
  }
3340
0
  else if ((codecFlags & ~CODEC_MODE) != 0)
3341
0
    WLog_Print(log, WLOG_WARN,
3342
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3343
0
               "0x%02" PRIx32,
3344
0
               WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3345
3346
0
  switch (entropyBits)
3347
0
  {
3348
0
    case CLW_ENTROPY_RLGR1:
3349
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3350
0
        return FALSE;
3351
0
      break;
3352
0
    case CLW_ENTROPY_RLGR3:
3353
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3354
0
        return FALSE;
3355
0
      break;
3356
0
    default:
3357
0
      WLog_Print(log, WLOG_ERROR,
3358
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3359
0
                 "unsupported value 0x%02" PRIx8
3360
0
                 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3361
0
                 "(0x04)",
3362
0
                 entropyBits);
3363
0
      return FALSE;
3364
0
  }
3365
0
  return TRUE;
3366
0
}
3367
3368
WINPR_ATTR_NODISCARD
3369
static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3370
0
{
3371
0
  UINT16 blockType = 0;
3372
0
  UINT32 blockLen = 0;
3373
0
  BYTE rfxCodecId = 0;
3374
0
  UINT16 capsetType = 0;
3375
0
  UINT16 numIcaps = 0;
3376
0
  UINT16 icapLen = 0;
3377
3378
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3379
0
    return FALSE;
3380
3381
  /* TS_RFX_CAPSET */
3382
0
  Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3383
0
  Stream_Read_UINT32(s, blockLen);  /* blockLen (4 bytes) */
3384
0
  if (blockType != 0xCBC1)
3385
0
  {
3386
0
    WLog_Print(log, WLOG_ERROR,
3387
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3388
0
               "] != CBY_CAPSET (0xCBC1)",
3389
0
               blockType);
3390
0
    return FALSE;
3391
0
  }
3392
0
  if (blockLen < 6ull)
3393
0
  {
3394
0
    WLog_Print(log, WLOG_ERROR,
3395
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu32 "] < 6", blockLen);
3396
0
    return FALSE;
3397
0
  }
3398
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3399
0
    return FALSE;
3400
3401
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3402
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3403
0
  WINPR_ASSERT(sub);
3404
3405
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3406
0
    return FALSE;
3407
3408
0
  Stream_Read_UINT8(sub, rfxCodecId);  /* codecId (1 byte) */
3409
0
  Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3410
0
  Stream_Read_UINT16(sub, numIcaps);   /* numIcaps (2 bytes) */
3411
0
  Stream_Read_UINT16(sub, icapLen);    /* icapLen (2 bytes) */
3412
3413
0
  if (rfxCodecId != 1)
3414
0
  {
3415
0
    WLog_Print(log, WLOG_ERROR,
3416
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3417
0
    return FALSE;
3418
0
  }
3419
3420
0
  if (capsetType != 0xCFC0)
3421
0
  {
3422
0
    WLog_Print(log, WLOG_ERROR,
3423
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3424
0
               "] != CLY_CAPSET (0xCFC0)",
3425
0
               capsetType);
3426
0
    return FALSE;
3427
0
  }
3428
3429
0
  while (numIcaps--)
3430
0
  {
3431
0
    if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3432
0
      return FALSE;
3433
0
  }
3434
0
  return TRUE;
3435
0
}
3436
3437
WINPR_ATTR_NODISCARD
3438
static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3439
0
{
3440
0
  if (Stream_GetRemainingLength(sub) == 0)
3441
0
    return TRUE;
3442
3443
0
  UINT16 blockType = 0;
3444
0
  UINT32 blockLen = 0;
3445
0
  UINT16 numCapsets = 0;
3446
3447
  /* TS_RFX_CAPS */
3448
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3449
0
    return FALSE;
3450
0
  Stream_Read_UINT16(sub, blockType);  /* blockType (2 bytes) */
3451
0
  Stream_Read_UINT32(sub, blockLen);   /* blockLen (4 bytes) */
3452
0
  Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3453
3454
0
  if (blockType != 0xCBC0)
3455
0
  {
3456
0
    WLog_Print(log, WLOG_ERROR,
3457
0
               "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3458
0
               "] != CBY_CAPS (0xCBC0)",
3459
0
               blockType);
3460
0
    return FALSE;
3461
0
  }
3462
3463
0
  if (blockLen != 8)
3464
0
  {
3465
0
    WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3466
0
               blockLen);
3467
0
    return FALSE;
3468
0
  }
3469
3470
0
  if (numCapsets != 1)
3471
0
  {
3472
0
    WLog_Print(log, WLOG_ERROR,
3473
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3474
0
    return FALSE;
3475
0
  }
3476
3477
0
  for (UINT16 x = 0; x < numCapsets; x++)
3478
0
  {
3479
0
    if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3480
0
      return FALSE;
3481
0
  }
3482
3483
0
  return TRUE;
3484
0
}
3485
3486
WINPR_ATTR_NODISCARD
3487
static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3488
0
{
3489
0
  UINT32 rfxCapsLength = 0;
3490
0
  UINT32 rfxPropsLength = 0;
3491
0
  UINT32 captureFlags = 0;
3492
3493
  /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3494
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3495
0
    return FALSE;
3496
0
  Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3497
0
  if (rfxPropsLength < 4)
3498
0
  {
3499
0
    WLog_Print(log, WLOG_ERROR,
3500
0
               "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3501
0
               " too short, require at least 4 bytes",
3502
0
               rfxPropsLength);
3503
0
    return FALSE;
3504
0
  }
3505
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3506
0
    return FALSE;
3507
3508
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3509
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3510
0
  WINPR_ASSERT(sub);
3511
3512
0
  Stream_Seek(s, rfxPropsLength - 4ull);
3513
3514
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3515
0
    return FALSE;
3516
3517
0
  Stream_Read_UINT32(sub, captureFlags);  /* captureFlags (4 bytes) */
3518
0
  Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3519
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3520
0
    return FALSE;
3521
3522
0
  settings->RemoteFxCaptureFlags = captureFlags;
3523
0
  settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3524
3525
  /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3526
0
  wStream tsbuffer = WINPR_C_ARRAY_INIT;
3527
0
  wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3528
0
  WINPR_ASSERT(ts_sub);
3529
0
  return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3530
0
}
3531
3532
/*
3533
 * Read bitmap codecs capability set.
3534
 * msdn{dd891377}
3535
 */
3536
WINPR_ATTR_NODISCARD
3537
static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3538
                                                  BOOL isServer)
3539
728
{
3540
728
  BYTE codecId = 0;
3541
728
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3542
728
  BYTE bitmapCodecCount = 0;
3543
728
  UINT16 codecPropertiesLength = 0;
3544
3545
728
  BOOL guidNSCodec = FALSE;
3546
728
  BOOL guidRemoteFx = FALSE;
3547
728
  BOOL guidRemoteFxImage = FALSE;
3548
3549
728
  WINPR_ASSERT(settings);
3550
728
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3551
5
    return FALSE;
3552
3553
723
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3554
3555
1.80k
  while (bitmapCodecCount > 0)
3556
1.16k
  {
3557
1.16k
    wStream subbuffer = WINPR_C_ARRAY_INIT;
3558
3559
1.16k
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3560
60
      return FALSE;
3561
1.10k
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3562
5
      return FALSE;
3563
1.09k
    Stream_Read_UINT8(s, codecId);                /* codecId (1 byte) */
3564
1.09k
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3565
3566
1.09k
    wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3567
1.09k
    if (!Stream_SafeSeek(s, codecPropertiesLength))
3568
19
      return FALSE;
3569
3570
1.07k
    if (isServer)
3571
820
    {
3572
820
      if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3573
0
      {
3574
0
        guidRemoteFx = TRUE;
3575
0
        settings->RemoteFxCodecId = codecId;
3576
0
        if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3577
0
          return FALSE;
3578
0
      }
3579
820
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3580
0
      {
3581
        /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3582
0
        guidRemoteFxImage = TRUE;
3583
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3584
0
          return FALSE;
3585
0
      }
3586
820
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3587
0
      {
3588
0
        BYTE colorLossLevel = 0;
3589
0
        BYTE fAllowSubsampling = 0;
3590
0
        BYTE fAllowDynamicFidelity = 0;
3591
0
        guidNSCodec = TRUE;
3592
0
        settings->NSCodecId = codecId;
3593
0
        if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3594
0
          return FALSE;
3595
0
        Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3596
0
        Stream_Read_UINT8(sub, fAllowSubsampling);     /* fAllowSubsampling (1 byte) */
3597
0
        Stream_Read_UINT8(sub, colorLossLevel);        /* colorLossLevel (1 byte) */
3598
3599
0
        if (colorLossLevel < 1)
3600
0
          colorLossLevel = 1;
3601
3602
0
        if (colorLossLevel > 7)
3603
0
          colorLossLevel = 7;
3604
3605
0
        settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3606
0
        settings->NSCodecAllowSubsampling = fAllowSubsampling;
3607
0
        settings->NSCodecColorLossLevel = colorLossLevel;
3608
0
      }
3609
820
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3610
0
      {
3611
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3612
0
          return FALSE;
3613
0
      }
3614
820
      else
3615
820
      {
3616
820
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3617
0
          return FALSE;
3618
820
      }
3619
820
    }
3620
259
    else
3621
259
    {
3622
259
      if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3623
0
        return FALSE;
3624
259
    }
3625
3626
1.07k
    const size_t rest = Stream_GetRemainingLength(sub);
3627
1.07k
    if (rest > 0)
3628
0
    {
3629
0
      WLog_Print(log, WLOG_ERROR,
3630
0
                 "error while reading codec properties: actual size: %" PRIuz
3631
0
                 " expected size: %" PRIu32 "",
3632
0
                 rest + codecPropertiesLength, codecPropertiesLength);
3633
0
    }
3634
1.07k
    bitmapCodecCount--;
3635
3636
    /* only enable a codec if we've announced/enabled it before */
3637
1.07k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3638
0
      return FALSE;
3639
1.07k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3640
0
      return FALSE;
3641
1.07k
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3642
0
      return FALSE;
3643
1.07k
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3644
0
      return FALSE;
3645
1.07k
  }
3646
3647
639
  return TRUE;
3648
723
}
3649
3650
/*
3651
 * Write RemoteFX Client Capability Container.
3652
 */
3653
WINPR_ATTR_NODISCARD
3654
static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3655
0
{
3656
0
  WINPR_ASSERT(settings);
3657
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3658
0
    return FALSE;
3659
3660
0
  const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3661
3662
0
  WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3663
0
  const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3664
0
  Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3665
  /* TS_RFX_CLNT_CAPS_CONTAINER */
3666
0
  Stream_Write_UINT32(s, 49);           /* length */
3667
0
  Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3668
0
  Stream_Write_UINT32(s, 37);           /* capsLength */
3669
  /* TS_RFX_CAPS */
3670
0
  Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3671
0
  Stream_Write_UINT32(s, 8);        /* blockLen */
3672
0
  Stream_Write_UINT16(s, 1);        /* numCapsets */
3673
  /* TS_RFX_CAPSET */
3674
0
  Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3675
0
  Stream_Write_UINT32(s, 29);         /* blockLen */
3676
0
  Stream_Write_UINT8(s, 0x01);        /* codecId (MUST be set to 0x01) */
3677
0
  Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3678
0
  Stream_Write_UINT16(s, 2);          /* numIcaps */
3679
0
  Stream_Write_UINT16(s, 8);          /* icapLen */
3680
  /* TS_RFX_ICAP (RLGR1) */
3681
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3682
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3683
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3684
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3685
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3686
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1);  /* entropyBits */
3687
  /* TS_RFX_ICAP (RLGR3) */
3688
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3689
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3690
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3691
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3692
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3693
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3);  /* entropyBits */
3694
0
  return TRUE;
3695
0
}
3696
3697
/*
3698
 * Write NSCODEC Client Capability Container.
3699
 */
3700
WINPR_ATTR_NODISCARD
3701
static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3702
0
{
3703
0
  WINPR_ASSERT(settings);
3704
3705
0
  const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3706
0
  const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3707
0
  UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3708
3709
0
  if (colorLossLevel < 1)
3710
0
    colorLossLevel = 1;
3711
3712
0
  if (colorLossLevel > 7)
3713
0
    colorLossLevel = 7;
3714
3715
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3716
0
    return FALSE;
3717
3718
0
  Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3719
  /* TS_NSCODEC_CAPABILITYSET */
3720
0
  Stream_Write_UINT8(s, fAllowDynamicFidelity != 0);        /* fAllowDynamicFidelity (1 byte) */
3721
0
  Stream_Write_UINT8(s, fAllowSubsampling != 0);            /* fAllowSubsampling (1 byte) */
3722
0
  Stream_Write_UINT8(s, (UINT8)colorLossLevel);             /* colorLossLevel (1 byte) */
3723
0
  return TRUE;
3724
0
}
3725
3726
#if defined(WITH_JPEG)
3727
WINPR_ATTR_NODISCARD
3728
static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3729
{
3730
  WINPR_ASSERT(settings);
3731
  if (!Stream_EnsureRemainingCapacity(s, 8))
3732
    return FALSE;
3733
3734
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3735
3736
  const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3737
  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3738
  return TRUE;
3739
}
3740
#endif
3741
3742
/*
3743
 * Write RemoteFX Server Capability Container.
3744
 */
3745
WINPR_ATTR_NODISCARD
3746
static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3747
0
{
3748
0
  WINPR_UNUSED(settings);
3749
0
  WINPR_ASSERT(settings);
3750
3751
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3752
0
    return FALSE;
3753
3754
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3755
0
  Stream_Write_UINT32(s, 0); /* reserved */
3756
0
  return TRUE;
3757
0
}
3758
3759
#if defined(WITH_JPEG)
3760
WINPR_ATTR_NODISCARD
3761
static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3762
{
3763
  WINPR_UNUSED(settings);
3764
  WINPR_ASSERT(settings);
3765
3766
  if (!Stream_EnsureRemainingCapacity(s, 8))
3767
    return FALSE;
3768
3769
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3770
  Stream_Write_UINT8(s, 75);
3771
  return TRUE;
3772
}
3773
#endif
3774
3775
/*
3776
 * Write NSCODEC Server Capability Container.
3777
 */
3778
WINPR_ATTR_NODISCARD
3779
static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3780
0
{
3781
0
  WINPR_UNUSED(settings);
3782
0
  WINPR_ASSERT(settings);
3783
3784
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3785
0
    return FALSE;
3786
3787
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3788
0
  Stream_Write_UINT32(s, 0); /* reserved */
3789
0
  return TRUE;
3790
0
}
3791
3792
/*
3793
 * Write bitmap codecs capability set.
3794
 * msdn{dd891377}
3795
 */
3796
3797
WINPR_ATTR_NODISCARD
3798
static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3799
                                                   const rdpSettings* settings)
3800
0
{
3801
0
  WINPR_ASSERT(settings);
3802
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3803
0
    return FALSE;
3804
3805
0
  const size_t header = rdp_capability_set_start(log, s);
3806
0
  BYTE bitmapCodecCount = 0;
3807
3808
0
  if (settings->RemoteFxCodec)
3809
0
    bitmapCodecCount++;
3810
3811
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3812
0
    bitmapCodecCount++;
3813
3814
#if defined(WITH_JPEG)
3815
3816
  if (settings->JpegCodec)
3817
    bitmapCodecCount++;
3818
3819
#endif
3820
3821
0
  if (settings->RemoteFxImageCodec)
3822
0
    bitmapCodecCount++;
3823
3824
0
  Stream_Write_UINT8(s, bitmapCodecCount);
3825
3826
0
  if (settings->RemoteFxCodec)
3827
0
  {
3828
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3829
3830
0
    if (settings->ServerMode)
3831
0
    {
3832
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3833
3834
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3835
0
        return FALSE;
3836
0
    }
3837
0
    else
3838
0
    {
3839
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3840
3841
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3842
0
        return FALSE;
3843
0
    }
3844
0
  }
3845
3846
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3847
0
  {
3848
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3849
3850
0
    if (settings->ServerMode)
3851
0
    {
3852
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3853
3854
0
      if (!rdp_write_nsc_server_capability_container(s, settings))
3855
0
        return FALSE;
3856
0
    }
3857
0
    else
3858
0
    {
3859
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3860
3861
0
      if (!rdp_write_nsc_client_capability_container(s, settings))
3862
0
        return FALSE;
3863
0
    }
3864
0
  }
3865
3866
#if defined(WITH_JPEG)
3867
3868
  if (settings->JpegCodec)
3869
  {
3870
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3871
3872
    if (settings->ServerMode)
3873
    {
3874
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3875
3876
      if (!rdp_write_jpeg_server_capability_container(s, settings))
3877
        return FALSE;
3878
    }
3879
    else
3880
    {
3881
      Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3882
3883
      if (!rdp_write_jpeg_client_capability_container(s, settings))
3884
        return FALSE;
3885
    }
3886
  }
3887
3888
#endif
3889
3890
0
  if (settings->RemoteFxImageCodec)
3891
0
  {
3892
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3893
3894
0
    if (settings->ServerMode)
3895
0
    {
3896
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3897
3898
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3899
0
        return FALSE;
3900
0
    }
3901
0
    else
3902
0
    {
3903
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3904
3905
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3906
0
        return FALSE;
3907
0
    }
3908
0
  }
3909
3910
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3911
0
}
3912
3913
#ifdef WITH_DEBUG_CAPABILITIES
3914
WINPR_ATTR_NODISCARD
3915
static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3916
{
3917
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3918
  BYTE bitmapCodecCount = 0;
3919
  BYTE codecId = 0;
3920
  UINT16 codecPropertiesLength = 0;
3921
3922
  WLog_Print(log, WLOG_TRACE,
3923
             "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3924
3925
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3926
    return FALSE;
3927
3928
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3929
  WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3930
3931
  while (bitmapCodecCount > 0)
3932
  {
3933
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3934
      return FALSE;
3935
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3936
      return FALSE;
3937
    Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3938
    WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3939
    rdp_print_bitmap_codec_guid(log, &codecGuid);
3940
    WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3941
    WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3942
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3943
    WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3944
3945
    if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3946
      return FALSE;
3947
    bitmapCodecCount--;
3948
  }
3949
3950
  return TRUE;
3951
}
3952
#endif
3953
3954
WINPR_ATTR_NODISCARD
3955
static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3956
                                                       const rdpSettings* src)
3957
510
{
3958
510
  WINPR_ASSERT(settings);
3959
510
  WINPR_ASSERT(src);
3960
3961
510
  if (settings->ServerMode)
3962
382
    settings->FrameAcknowledge = src->FrameAcknowledge;
3963
3964
510
  return TRUE;
3965
510
}
3966
3967
/*
3968
 * Read frame acknowledge capability set.
3969
 */
3970
WINPR_ATTR_NODISCARD
3971
static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3972
515
{
3973
515
  WINPR_ASSERT(settings);
3974
515
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3975
5
    return FALSE;
3976
3977
510
  Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3978
3979
510
  return TRUE;
3980
515
}
3981
3982
/*
3983
 * Write frame acknowledge capability set.
3984
 */
3985
WINPR_ATTR_NODISCARD
3986
static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3987
                                                       const rdpSettings* settings)
3988
0
{
3989
0
  WINPR_ASSERT(settings);
3990
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3991
0
    return FALSE;
3992
3993
0
  const size_t header = rdp_capability_set_start(log, s);
3994
0
  Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3995
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3996
0
}
3997
3998
#ifdef WITH_DEBUG_CAPABILITIES
3999
WINPR_ATTR_NODISCARD
4000
static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
4001
{
4002
  UINT32 frameAcknowledge = 0;
4003
  WLog_Print(log, WLOG_TRACE,
4004
             "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
4005
4006
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4007
    return FALSE;
4008
4009
  Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
4010
  WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
4011
  return TRUE;
4012
}
4013
#endif
4014
4015
WINPR_ATTR_NODISCARD
4016
static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
4017
                                                              const rdpSettings* src)
4018
291
{
4019
291
  WINPR_ASSERT(settings);
4020
291
  WINPR_ASSERT(src);
4021
4022
291
  settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
4023
291
  return TRUE;
4024
291
}
4025
4026
WINPR_ATTR_NODISCARD
4027
static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
4028
                                                             rdpSettings* settings)
4029
297
{
4030
297
  BYTE bitmapCacheV3CodecId = 0;
4031
4032
297
  WINPR_ASSERT(settings);
4033
297
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
4034
6
    return FALSE;
4035
4036
291
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
4037
291
  settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
4038
291
  return TRUE;
4039
297
}
4040
4041
WINPR_ATTR_NODISCARD
4042
static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
4043
                                                              const rdpSettings* settings)
4044
0
{
4045
0
  WINPR_ASSERT(settings);
4046
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
4047
0
    return FALSE;
4048
4049
0
  const size_t header = rdp_capability_set_start(log, s);
4050
0
  if (settings->BitmapCacheV3CodecId > UINT8_MAX)
4051
0
    return FALSE;
4052
0
  Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
4053
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
4054
0
}
4055
4056
#ifdef WITH_DEBUG_CAPABILITIES
4057
WINPR_ATTR_NODISCARD
4058
static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
4059
{
4060
  BYTE bitmapCacheV3CodecId = 0;
4061
  WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
4062
             Stream_GetRemainingLength(s));
4063
4064
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
4065
    return FALSE;
4066
4067
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
4068
  WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
4069
  return TRUE;
4070
}
4071
4072
BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
4073
{
4074
  BOOL rc = FALSE;
4075
  UINT16 type = 0;
4076
  UINT16 length = 0;
4077
  UINT16 numberCapabilities = 0;
4078
4079
  size_t pos = Stream_GetPosition(s);
4080
4081
  if (!Stream_SetPosition(s, start))
4082
    goto fail;
4083
4084
  if (receiving)
4085
  {
4086
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4087
      goto fail;
4088
  }
4089
  else
4090
  {
4091
    if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
4092
      goto fail;
4093
  }
4094
4095
  Stream_Read_UINT16(s, numberCapabilities);
4096
  Stream_Seek(s, 2);
4097
4098
  while (numberCapabilities > 0)
4099
  {
4100
    size_t rest = 0;
4101
    wStream subBuffer;
4102
    wStream* sub = nullptr;
4103
4104
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4105
      goto fail;
4106
4107
    WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
4108
    sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
4109
    if (!Stream_SafeSeek(s, length - 4))
4110
      goto fail;
4111
4112
    switch (type)
4113
    {
4114
      case CAPSET_TYPE_GENERAL:
4115
        if (!rdp_print_general_capability_set(log, sub))
4116
          goto fail;
4117
4118
        break;
4119
4120
      case CAPSET_TYPE_BITMAP:
4121
        if (!rdp_print_bitmap_capability_set(log, sub))
4122
          goto fail;
4123
4124
        break;
4125
4126
      case CAPSET_TYPE_ORDER:
4127
        if (!rdp_print_order_capability_set(log, sub))
4128
          goto fail;
4129
4130
        break;
4131
4132
      case CAPSET_TYPE_BITMAP_CACHE:
4133
        if (!rdp_print_bitmap_cache_capability_set(log, sub))
4134
          goto fail;
4135
4136
        break;
4137
4138
      case CAPSET_TYPE_CONTROL:
4139
        if (!rdp_print_control_capability_set(log, sub))
4140
          goto fail;
4141
4142
        break;
4143
4144
      case CAPSET_TYPE_ACTIVATION:
4145
        if (!rdp_print_window_activation_capability_set(log, sub))
4146
          goto fail;
4147
4148
        break;
4149
4150
      case CAPSET_TYPE_POINTER:
4151
        if (!rdp_print_pointer_capability_set(log, sub))
4152
          goto fail;
4153
4154
        break;
4155
4156
      case CAPSET_TYPE_SHARE:
4157
        if (!rdp_print_share_capability_set(log, sub))
4158
          goto fail;
4159
4160
        break;
4161
4162
      case CAPSET_TYPE_COLOR_CACHE:
4163
        if (!rdp_print_color_cache_capability_set(log, sub))
4164
          goto fail;
4165
4166
        break;
4167
4168
      case CAPSET_TYPE_SOUND:
4169
        if (!rdp_print_sound_capability_set(log, sub))
4170
          goto fail;
4171
4172
        break;
4173
4174
      case CAPSET_TYPE_INPUT:
4175
        if (!rdp_print_input_capability_set(log, sub))
4176
          goto fail;
4177
4178
        break;
4179
4180
      case CAPSET_TYPE_FONT:
4181
        if (!rdp_print_font_capability_set(log, sub))
4182
          goto fail;
4183
4184
        break;
4185
4186
      case CAPSET_TYPE_BRUSH:
4187
        if (!rdp_print_brush_capability_set(log, sub))
4188
          goto fail;
4189
4190
        break;
4191
4192
      case CAPSET_TYPE_GLYPH_CACHE:
4193
        if (!rdp_print_glyph_cache_capability_set(log, sub))
4194
          goto fail;
4195
4196
        break;
4197
4198
      case CAPSET_TYPE_OFFSCREEN_CACHE:
4199
        if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4200
          goto fail;
4201
4202
        break;
4203
4204
      case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4205
        if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4206
          goto fail;
4207
4208
        break;
4209
4210
      case CAPSET_TYPE_BITMAP_CACHE_V2:
4211
        if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4212
          goto fail;
4213
4214
        break;
4215
4216
      case CAPSET_TYPE_VIRTUAL_CHANNEL:
4217
        if (!rdp_print_virtual_channel_capability_set(log, sub))
4218
          goto fail;
4219
4220
        break;
4221
4222
      case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4223
        if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4224
          goto fail;
4225
4226
        break;
4227
4228
      case CAPSET_TYPE_DRAW_GDI_PLUS:
4229
        if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4230
          goto fail;
4231
4232
        break;
4233
4234
      case CAPSET_TYPE_RAIL:
4235
        if (!rdp_print_remote_programs_capability_set(log, sub))
4236
          goto fail;
4237
4238
        break;
4239
4240
      case CAPSET_TYPE_WINDOW:
4241
        if (!rdp_print_window_list_capability_set(log, sub))
4242
          goto fail;
4243
4244
        break;
4245
4246
      case CAPSET_TYPE_COMP_DESK:
4247
        if (!rdp_print_desktop_composition_capability_set(log, sub))
4248
          goto fail;
4249
4250
        break;
4251
4252
      case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4253
        if (!rdp_print_multifragment_update_capability_set(log, sub))
4254
          goto fail;
4255
4256
        break;
4257
4258
      case CAPSET_TYPE_LARGE_POINTER:
4259
        if (!rdp_print_large_pointer_capability_set(log, sub))
4260
          goto fail;
4261
4262
        break;
4263
4264
      case CAPSET_TYPE_SURFACE_COMMANDS:
4265
        if (!rdp_print_surface_commands_capability_set(log, sub))
4266
          goto fail;
4267
4268
        break;
4269
4270
      case CAPSET_TYPE_BITMAP_CODECS:
4271
        if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4272
          goto fail;
4273
4274
        break;
4275
4276
      case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4277
        if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4278
          goto fail;
4279
4280
        break;
4281
4282
      case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4283
        if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4284
          goto fail;
4285
4286
        break;
4287
4288
      default:
4289
        WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4290
        break;
4291
    }
4292
4293
    rest = Stream_GetRemainingLength(sub);
4294
    if (rest > 0)
4295
    {
4296
      WLog_Print(log, WLOG_WARN,
4297
                 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4298
                 " bytes expected, %" PRIuz "bytes remaining",
4299
                 type, length, rest);
4300
    }
4301
4302
    numberCapabilities--;
4303
  }
4304
4305
  rc = TRUE;
4306
fail:
4307
  if (!Stream_SetPosition(s, pos))
4308
    return FALSE;
4309
4310
  return rc;
4311
}
4312
#endif
4313
4314
WINPR_ATTR_NODISCARD
4315
static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4316
33.6k
{
4317
33.6k
  switch (type)
4318
33.6k
  {
4319
1.02k
    case CAPSET_TYPE_GENERAL:
4320
1.02k
      return rdp_apply_general_capability_set(dst, src);
4321
458
    case CAPSET_TYPE_BITMAP:
4322
458
      return rdp_apply_bitmap_capability_set(dst, src);
4323
4.83k
    case CAPSET_TYPE_ORDER:
4324
4.83k
      return rdp_apply_order_capability_set(dst, src);
4325
4.10k
    case CAPSET_TYPE_POINTER:
4326
4.10k
      return rdp_apply_pointer_capability_set(dst, src);
4327
4.44k
    case CAPSET_TYPE_INPUT:
4328
4.44k
      return rdp_apply_input_capability_set(dst, src);
4329
1.19k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4330
1.19k
      return rdp_apply_virtual_channel_capability_set(dst, src);
4331
115
    case CAPSET_TYPE_SHARE:
4332
115
      return rdp_apply_share_capability_set(dst, src);
4333
2.01k
    case CAPSET_TYPE_COLOR_CACHE:
4334
2.01k
      return rdp_apply_color_cache_capability_set(dst, src);
4335
450
    case CAPSET_TYPE_FONT:
4336
450
      return rdp_apply_font_capability_set(dst, src);
4337
83
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4338
83
      return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4339
57
    case CAPSET_TYPE_RAIL:
4340
57
      return rdp_apply_remote_programs_capability_set(dst, src);
4341
394
    case CAPSET_TYPE_WINDOW:
4342
394
      return rdp_apply_window_list_capability_set(dst, src);
4343
1.67k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4344
1.67k
      return rdp_apply_multifragment_update_capability_set(dst, src);
4345
1.59k
    case CAPSET_TYPE_LARGE_POINTER:
4346
1.59k
      return rdp_apply_large_pointer_capability_set(dst, src);
4347
24
    case CAPSET_TYPE_COMP_DESK:
4348
24
      return rdp_apply_desktop_composition_capability_set(dst, src);
4349
557
    case CAPSET_TYPE_SURFACE_COMMANDS:
4350
557
      return rdp_apply_surface_commands_capability_set(dst, src);
4351
639
    case CAPSET_TYPE_BITMAP_CODECS:
4352
639
      return rdp_apply_bitmap_codecs_capability_set(dst, src);
4353
510
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4354
510
      return rdp_apply_frame_acknowledge_capability_set(dst, src);
4355
291
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4356
291
      return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4357
87
    case CAPSET_TYPE_BITMAP_CACHE:
4358
87
      return rdp_apply_bitmap_cache_capability_set(dst, src);
4359
8.37k
    case CAPSET_TYPE_BITMAP_CACHE_V2:
4360
8.37k
      return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4361
164
    case CAPSET_TYPE_BRUSH:
4362
164
      return rdp_apply_brush_capability_set(dst, src);
4363
72
    case CAPSET_TYPE_GLYPH_CACHE:
4364
72
      return rdp_apply_glyph_cache_capability_set(dst, src);
4365
91
    case CAPSET_TYPE_OFFSCREEN_CACHE:
4366
91
      return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4367
172
    case CAPSET_TYPE_SOUND:
4368
172
      return rdp_apply_sound_capability_set(dst, src);
4369
70
    case CAPSET_TYPE_CONTROL:
4370
70
      return rdp_apply_control_capability_set(dst, src);
4371
28
    case CAPSET_TYPE_ACTIVATION:
4372
28
      return rdp_apply_window_activation_capability_set(dst, src);
4373
99
    case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4374
99
      return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4375
73
    case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4376
73
      return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4377
0
    default:
4378
0
      return TRUE;
4379
33.6k
  }
4380
33.6k
}
4381
4382
BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4383
                             BOOL isServer)
4384
36.0k
{
4385
36.0k
  WINPR_ASSERT(settings);
4386
4387
36.0k
  if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4388
34.2k
  {
4389
34.2k
    const size_t size = Stream_Length(sub);
4390
34.2k
    if (size > UINT32_MAX)
4391
0
      return FALSE;
4392
4393
34.2k
    WINPR_ASSERT(settings->ReceivedCapabilities);
4394
34.2k
    settings->ReceivedCapabilities[type] = TRUE;
4395
4396
34.2k
    WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4397
34.2k
    settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4398
4399
34.2k
    WINPR_ASSERT(settings->ReceivedCapabilityData);
4400
34.2k
    void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4401
34.2k
    if (!tmp && (size > 0))
4402
0
      return FALSE;
4403
34.2k
    if (tmp)
4404
34.0k
      memcpy(tmp, Stream_Buffer(sub), size);
4405
34.2k
    settings->ReceivedCapabilityData[type] = tmp;
4406
34.2k
  }
4407
1.77k
  else
4408
1.77k
    WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4409
4410
36.0k
  BOOL treated = TRUE;
4411
4412
36.0k
  switch (type)
4413
36.0k
  {
4414
1.06k
    case CAPSET_TYPE_GENERAL:
4415
1.06k
      if (!rdp_read_general_capability_set(log, sub, settings))
4416
43
        return FALSE;
4417
4418
1.02k
      break;
4419
4420
1.02k
    case CAPSET_TYPE_BITMAP:
4421
471
      if (!rdp_read_bitmap_capability_set(log, sub, settings))
4422
13
        return FALSE;
4423
4424
458
      break;
4425
4426
4.84k
    case CAPSET_TYPE_ORDER:
4427
4.84k
      if (!rdp_read_order_capability_set(log, sub, settings))
4428
9
        return FALSE;
4429
4430
4.83k
      break;
4431
4432
4.83k
    case CAPSET_TYPE_POINTER:
4433
4.12k
      if (!rdp_read_pointer_capability_set(log, sub, settings))
4434
20
        return FALSE;
4435
4436
4.10k
      break;
4437
4438
4.45k
    case CAPSET_TYPE_INPUT:
4439
4.45k
      if (!rdp_read_input_capability_set(log, sub, settings, isServer))
4440
6
        return FALSE;
4441
4442
4.44k
      break;
4443
4444
4.44k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4445
1.19k
      if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4446
4
        return FALSE;
4447
4448
1.19k
      break;
4449
4450
1.19k
    case CAPSET_TYPE_SHARE:
4451
121
      if (!rdp_read_share_capability_set(log, sub, settings))
4452
6
        return FALSE;
4453
4454
115
      break;
4455
4456
2.02k
    case CAPSET_TYPE_COLOR_CACHE:
4457
2.02k
      if (!rdp_read_color_cache_capability_set(log, sub, settings))
4458
12
        return FALSE;
4459
4460
2.01k
      break;
4461
4462
2.01k
    case CAPSET_TYPE_FONT:
4463
450
      if (!rdp_read_font_capability_set(log, sub, settings))
4464
0
        return FALSE;
4465
4466
450
      break;
4467
4468
450
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4469
89
      if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4470
6
        return FALSE;
4471
4472
83
      break;
4473
4474
83
    case CAPSET_TYPE_RAIL:
4475
62
      if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4476
5
        return FALSE;
4477
4478
57
      break;
4479
4480
400
    case CAPSET_TYPE_WINDOW:
4481
400
      if (!rdp_read_window_list_capability_set(log, sub, settings))
4482
6
        return FALSE;
4483
4484
394
      break;
4485
4486
1.68k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4487
1.68k
      if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4488
4
        return FALSE;
4489
4490
1.67k
      break;
4491
4492
1.67k
    case CAPSET_TYPE_LARGE_POINTER:
4493
1.59k
      if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4494
2
        return FALSE;
4495
4496
1.59k
      break;
4497
4498
1.59k
    case CAPSET_TYPE_COMP_DESK:
4499
29
      if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4500
5
        return FALSE;
4501
4502
24
      break;
4503
4504
565
    case CAPSET_TYPE_SURFACE_COMMANDS:
4505
565
      if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4506
8
        return FALSE;
4507
4508
557
      break;
4509
4510
728
    case CAPSET_TYPE_BITMAP_CODECS:
4511
728
      if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4512
89
        return FALSE;
4513
4514
639
      break;
4515
4516
639
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4517
515
      if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4518
5
        return FALSE;
4519
4520
510
      break;
4521
4522
510
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4523
297
      if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4524
6
        return FALSE;
4525
4526
291
      break;
4527
4528
11.3k
    default:
4529
11.3k
      treated = FALSE;
4530
11.3k
      break;
4531
36.0k
  }
4532
4533
35.7k
  if (!treated)
4534
11.3k
  {
4535
11.3k
    if (isServer)
4536
10.1k
    {
4537
      /* treating capabilities that are supposed to be send only from the client */
4538
10.1k
      switch (type)
4539
10.1k
      {
4540
104
        case CAPSET_TYPE_BITMAP_CACHE:
4541
104
          if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4542
17
            return FALSE;
4543
4544
87
          break;
4545
4546
8.38k
        case CAPSET_TYPE_BITMAP_CACHE_V2:
4547
8.38k
          if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4548
11
            return FALSE;
4549
4550
8.37k
          break;
4551
4552
8.37k
        case CAPSET_TYPE_BRUSH:
4553
165
          if (!rdp_read_brush_capability_set(log, sub, settings))
4554
1
            return FALSE;
4555
4556
164
          break;
4557
4558
164
        case CAPSET_TYPE_GLYPH_CACHE:
4559
77
          if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4560
5
            return FALSE;
4561
4562
72
          break;
4563
4564
95
        case CAPSET_TYPE_OFFSCREEN_CACHE:
4565
95
          if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4566
4
            return FALSE;
4567
4568
91
          break;
4569
4570
175
        case CAPSET_TYPE_SOUND:
4571
175
          if (!rdp_read_sound_capability_set(log, sub, settings))
4572
3
            return FALSE;
4573
4574
172
          break;
4575
4576
172
        case CAPSET_TYPE_CONTROL:
4577
73
          if (!rdp_read_control_capability_set(log, sub, settings))
4578
3
            return FALSE;
4579
4580
70
          break;
4581
4582
70
        case CAPSET_TYPE_ACTIVATION:
4583
31
          if (!rdp_read_window_activation_capability_set(log, sub, settings))
4584
3
            return FALSE;
4585
4586
28
          break;
4587
4588
102
        case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4589
102
          if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4590
3
            return FALSE;
4591
4592
99
          break;
4593
4594
940
        default:
4595
940
          WLog_Print(log, WLOG_ERROR,
4596
940
                     "capability %s(%" PRIu16 ") not expected from client",
4597
940
                     get_capability_name(type), type);
4598
940
          return FALSE;
4599
10.1k
      }
4600
10.1k
    }
4601
1.17k
    else
4602
1.17k
    {
4603
      /* treating capabilities that are supposed to be send only from the server */
4604
1.17k
      switch (type)
4605
1.17k
      {
4606
74
        case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4607
74
          if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4608
1
            return FALSE;
4609
4610
73
          break;
4611
4612
1.09k
        default:
4613
1.09k
          WLog_Print(log, WLOG_ERROR,
4614
1.09k
                     "capability %s(%" PRIu16 ") not expected from server",
4615
1.09k
                     get_capability_name(type), type);
4616
1.09k
          return FALSE;
4617
1.17k
      }
4618
1.17k
    }
4619
11.3k
  }
4620
4621
33.6k
  const size_t rest = Stream_GetRemainingLength(sub);
4622
33.6k
  if (rest > 0)
4623
17.7k
  {
4624
17.7k
    const size_t length = Stream_Capacity(sub);
4625
17.7k
    WLog_Print(log, WLOG_ERROR,
4626
17.7k
               "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4627
17.7k
               type, length - rest, length);
4628
17.7k
  }
4629
33.6k
  return TRUE;
4630
35.7k
}
4631
4632
WINPR_ATTR_NODISCARD
4633
static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4634
                                     rdpSettings* rcvSettings, UINT16 totalLength)
4635
8.03k
{
4636
8.03k
  BOOL rc = FALSE;
4637
8.03k
  size_t start = 0;
4638
8.03k
  size_t end = 0;
4639
8.03k
  size_t len = 0;
4640
8.03k
  UINT16 numberCapabilities = 0;
4641
8.03k
  UINT16 count = 0;
4642
4643
#ifdef WITH_DEBUG_CAPABILITIES
4644
  const size_t capstart = Stream_GetPosition(s);
4645
#endif
4646
4647
8.03k
  WINPR_ASSERT(s);
4648
8.03k
  WINPR_ASSERT(settings);
4649
4650
8.03k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4651
0
    return FALSE;
4652
4653
8.03k
  Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4654
8.03k
  Stream_Seek(s, 2);                         /* pad2Octets (2 bytes) */
4655
8.03k
  count = numberCapabilities;
4656
4657
8.03k
  start = Stream_GetPosition(s);
4658
41.7k
  while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4659
39.1k
  {
4660
39.1k
    UINT16 type = 0;
4661
39.1k
    UINT16 length = 0;
4662
39.1k
    wStream subbuffer;
4663
39.1k
    wStream* sub = nullptr;
4664
4665
39.1k
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4666
1.03k
      goto fail;
4667
38.1k
    sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4668
38.1k
    if (!Stream_SafeSeek(s, length - 4))
4669
2.11k
      goto fail;
4670
4671
36.0k
    if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4672
2.33k
      goto fail;
4673
4674
33.6k
    if (!rdp_apply_from_received(type, settings, rcvSettings))
4675
0
      goto fail;
4676
33.6k
    numberCapabilities--;
4677
33.6k
  }
4678
4679
2.54k
  end = Stream_GetPosition(s);
4680
2.54k
  len = end - start;
4681
4682
2.54k
  if (numberCapabilities)
4683
623
  {
4684
623
    WLog_Print(log, WLOG_ERROR,
4685
623
               "strange we haven't read the number of announced capacity sets, read=%d "
4686
623
               "expected=%" PRIu16 "",
4687
623
               count - numberCapabilities, count);
4688
623
  }
4689
4690
#ifdef WITH_DEBUG_CAPABILITIES
4691
  rdp_print_capability_sets(log, s, capstart, TRUE);
4692
#endif
4693
4694
2.54k
  if (len > totalLength)
4695
316
  {
4696
316
    WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4697
316
               totalLength, len);
4698
316
    goto fail;
4699
316
  }
4700
2.23k
  rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4701
8.03k
fail:
4702
8.03k
  return rc;
4703
2.23k
}
4704
4705
BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4706
15.0k
{
4707
15.0k
  WINPR_ASSERT(rdp);
4708
15.0k
  WINPR_ASSERT(rdp->context);
4709
4710
15.0k
  if (!rdp_read_header(rdp, s, length, pChannelId))
4711
15.0k
    return FALSE;
4712
4713
26
  if (freerdp_shall_disconnect_context(rdp->context))
4714
11
    return TRUE;
4715
4716
15
  if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4717
15
  {
4718
15
    UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4719
4720
15
    if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4721
15
    {
4722
15
      WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4723
15
                 *pChannelId);
4724
15
      return FALSE;
4725
15
    }
4726
15
  }
4727
4728
0
  return TRUE;
4729
15
}
4730
4731
BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4732
15.0k
{
4733
15.0k
  UINT16 lengthSourceDescriptor = 0;
4734
15.0k
  UINT16 lengthCombinedCapabilities = 0;
4735
4736
15.0k
  WINPR_ASSERT(rdp);
4737
15.0k
  WINPR_ASSERT(rdp->settings);
4738
15.0k
  WINPR_ASSERT(rdp->context);
4739
15.0k
  WINPR_ASSERT(s);
4740
4741
15.0k
  rdp->settings->PduSource = pduSource;
4742
4743
15.0k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4744
5.33k
    return FALSE;
4745
4746
9.75k
  Stream_Read_UINT32(s, rdp->settings->ShareId);     /* shareId (4 bytes) */
4747
9.75k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4748
9.75k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4749
4750
9.75k
  if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4751
4.54k
      !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4752
5.24k
    return FALSE;
4753
4754
  /* capabilitySets */
4755
4.51k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4756
4.51k
                                lengthCombinedCapabilities))
4757
3.26k
  {
4758
3.26k
    WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4759
3.26k
    return FALSE;
4760
3.26k
  }
4761
4762
1.25k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4763
298
    return FALSE;
4764
4765
  /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4766
   * is ignored by client */
4767
952
  Stream_Seek_UINT32(s); /* SessionId */
4768
4769
952
  {
4770
952
    rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4771
952
    secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4772
952
  }
4773
4774
952
  return tpkt_ensure_stream_consumed(rdp->log, s, length);
4775
1.25k
}
4776
4777
WINPR_ATTR_NODISCARD
4778
static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4779
0
{
4780
0
  size_t bm = 0;
4781
0
  size_t em = 0;
4782
0
  size_t lm = 0;
4783
0
  UINT16 numberCapabilities = 0;
4784
0
  size_t lengthCombinedCapabilities = 0;
4785
4786
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
4787
0
    return FALSE;
4788
4789
0
  Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4790
0
  Stream_Write_UINT16(s, 4);                 /* lengthSourceDescriptor (2 bytes) */
4791
0
  lm = Stream_GetPosition(s);
4792
0
  Stream_Seek_UINT16(s);     /* lengthCombinedCapabilities (2 bytes) */
4793
0
  Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4794
0
  bm = Stream_GetPosition(s);
4795
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4796
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4797
0
  numberCapabilities = 14;
4798
4799
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4800
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4801
0
      !rdp_write_order_capability_set(log, s, settings) ||
4802
0
      !rdp_write_pointer_capability_set(log, s, settings) ||
4803
0
      !rdp_write_input_capability_set(log, s, settings) ||
4804
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4805
0
      !rdp_write_share_capability_set(log, s, settings) ||
4806
0
      !rdp_write_font_capability_set(log, s, settings) ||
4807
0
      !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4808
0
      !rdp_write_large_pointer_capability_set(log, s, settings) ||
4809
0
      !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4810
0
      !rdp_write_surface_commands_capability_set(log, s, settings) ||
4811
0
      !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4812
0
      !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4813
0
  {
4814
0
    return FALSE;
4815
0
  }
4816
4817
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4818
0
  {
4819
0
    numberCapabilities++;
4820
4821
0
    if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4822
0
      return FALSE;
4823
0
  }
4824
4825
0
  if (settings->RemoteApplicationMode)
4826
0
  {
4827
0
    numberCapabilities += 2;
4828
4829
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4830
0
        !rdp_write_window_list_capability_set(log, s, settings))
4831
0
      return FALSE;
4832
0
  }
4833
4834
0
  em = Stream_GetPosition(s);
4835
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4836
0
    return FALSE;
4837
0
  lengthCombinedCapabilities = (em - bm);
4838
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4839
0
    return FALSE;
4840
0
  Stream_Write_UINT16(
4841
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4842
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
4843
0
    return FALSE;
4844
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4845
#ifdef WITH_DEBUG_CAPABILITIES
4846
  rdp_print_capability_sets(log, s, bm, FALSE);
4847
#endif
4848
0
  if (!Stream_SetPosition(s, em))
4849
0
    return FALSE;
4850
0
  Stream_Write_UINT32(s, 0); /* sessionId */
4851
0
  return TRUE;
4852
0
}
4853
4854
BOOL rdp_send_demand_active(rdpRdp* rdp)
4855
0
{
4856
0
  UINT16 sec_flags = 0;
4857
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4858
0
  BOOL status = 0;
4859
4860
0
  if (!s)
4861
0
    return FALSE;
4862
4863
0
  rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4864
0
  status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4865
0
           rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4866
0
  Stream_Release(s);
4867
0
  return status;
4868
0
}
4869
4870
BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4871
15.0k
{
4872
15.0k
  rdpSettings* settings = nullptr;
4873
15.0k
  UINT16 lengthSourceDescriptor = 0;
4874
15.0k
  UINT16 lengthCombinedCapabilities = 0;
4875
4876
15.0k
  WINPR_ASSERT(rdp);
4877
15.0k
  WINPR_ASSERT(s);
4878
15.0k
  settings = rdp->settings;
4879
15.0k
  WINPR_ASSERT(settings);
4880
4881
15.0k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4882
6.58k
    return FALSE;
4883
4884
8.50k
  Stream_Seek_UINT32(s);                             /* shareId (4 bytes) */
4885
8.50k
  Stream_Seek_UINT16(s);                             /* originatorId (2 bytes) */
4886
8.50k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4887
8.50k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4888
4889
8.50k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4890
4.99k
    return FALSE;
4891
4892
3.51k
  Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4893
3.51k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4894
3.51k
                                lengthCombinedCapabilities))
4895
2.53k
    return FALSE;
4896
4897
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4898
978
  {
4899
    /* client does not support surface commands */
4900
978
    settings->SurfaceCommandsEnabled = FALSE;
4901
978
    settings->SurfaceFrameMarkerEnabled = FALSE;
4902
978
  }
4903
4904
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4905
977
  {
4906
    /* client does not support frame acks */
4907
977
    settings->FrameAcknowledge = 0;
4908
977
  }
4909
4910
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4911
977
  {
4912
    /* client does not support bitmap cache v3 */
4913
977
    settings->BitmapCacheV3Enabled = FALSE;
4914
977
  }
4915
4916
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4917
970
  {
4918
    /* client does not support bitmap codecs */
4919
970
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4920
0
      return FALSE;
4921
970
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4922
0
      return FALSE;
4923
970
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4924
0
      return FALSE;
4925
970
  }
4926
4927
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4928
975
  {
4929
    /* client does not support multi fragment updates - make sure packages are not fragmented */
4930
975
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4931
975
                                     FASTPATH_FRAGMENT_SAFE_SIZE))
4932
0
      return FALSE;
4933
975
  }
4934
4935
981
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4936
976
  {
4937
    /* client does not support large pointers */
4938
976
    settings->LargePointerFlag = 0;
4939
976
  }
4940
4941
981
  return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4942
981
}
4943
4944
WINPR_ATTR_NODISCARD
4945
static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4946
0
{
4947
0
  size_t bm = 0;
4948
0
  size_t em = 0;
4949
0
  size_t lm = 0;
4950
0
  UINT16 numberCapabilities = 0;
4951
0
  UINT16 lengthSourceDescriptor = 0;
4952
0
  size_t lengthCombinedCapabilities = 0;
4953
0
  BOOL ret = 0;
4954
4955
0
  WINPR_ASSERT(settings);
4956
4957
0
  lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4958
0
  Stream_Write_UINT32(s, settings->ShareId);      /* shareId (4 bytes) */
4959
0
  Stream_Write_UINT16(s, 0x03EA);                 /* originatorId (2 bytes) */
4960
0
  Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4961
0
  lm = Stream_GetPosition(s);
4962
0
  Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4963
0
  Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4964
0
  bm = Stream_GetPosition(s);
4965
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4966
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4967
  /* Capability Sets */
4968
0
  numberCapabilities = 15;
4969
4970
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4971
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4972
0
      !rdp_write_order_capability_set(log, s, settings))
4973
0
    return FALSE;
4974
4975
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4976
0
    ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4977
0
  else
4978
0
    ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4979
4980
0
  if (!ret)
4981
0
    return FALSE;
4982
4983
0
  if (!rdp_write_pointer_capability_set(log, s, settings) ||
4984
0
      !rdp_write_input_capability_set(log, s, settings) ||
4985
0
      !rdp_write_brush_capability_set(log, s, settings) ||
4986
0
      !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4987
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4988
0
      !rdp_write_sound_capability_set(log, s, settings) ||
4989
0
      !rdp_write_share_capability_set(log, s, settings) ||
4990
0
      !rdp_write_font_capability_set(log, s, settings) ||
4991
0
      !rdp_write_control_capability_set(log, s, settings) ||
4992
0
      !rdp_write_color_cache_capability_set(log, s, settings) ||
4993
0
      !rdp_write_window_activation_capability_set(log, s, settings))
4994
0
  {
4995
0
    return FALSE;
4996
0
  }
4997
4998
0
  {
4999
0
    numberCapabilities++;
5000
5001
0
    if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
5002
0
      return FALSE;
5003
0
  }
5004
5005
0
  if (settings->DrawNineGridEnabled)
5006
0
  {
5007
0
    numberCapabilities++;
5008
5009
0
    if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
5010
0
      return FALSE;
5011
0
  }
5012
5013
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
5014
0
  {
5015
0
    if (settings->LargePointerFlag)
5016
0
    {
5017
0
      numberCapabilities++;
5018
5019
0
      if (!rdp_write_large_pointer_capability_set(log, s, settings))
5020
0
        return FALSE;
5021
0
    }
5022
0
  }
5023
5024
0
  if (settings->RemoteApplicationMode)
5025
0
  {
5026
0
    numberCapabilities += 2;
5027
5028
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
5029
0
        !rdp_write_window_list_capability_set(log, s, settings))
5030
0
      return FALSE;
5031
0
  }
5032
5033
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
5034
0
  {
5035
0
    numberCapabilities++;
5036
5037
0
    if (!rdp_write_multifragment_update_capability_set(log, s, settings))
5038
0
      return FALSE;
5039
0
  }
5040
5041
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
5042
0
  {
5043
0
    numberCapabilities++;
5044
5045
0
    if (!rdp_write_surface_commands_capability_set(log, s, settings))
5046
0
      return FALSE;
5047
0
  }
5048
5049
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
5050
0
  {
5051
0
    numberCapabilities++;
5052
5053
0
    if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
5054
0
      return FALSE;
5055
0
  }
5056
5057
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
5058
0
    settings->FrameAcknowledge = 0;
5059
5060
0
  if (settings->FrameAcknowledge)
5061
0
  {
5062
0
    numberCapabilities++;
5063
5064
0
    if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
5065
0
      return FALSE;
5066
0
  }
5067
5068
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
5069
0
  {
5070
0
    if (settings->BitmapCacheV3CodecId != 0)
5071
0
    {
5072
0
      numberCapabilities++;
5073
5074
0
      if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
5075
0
        return FALSE;
5076
0
    }
5077
0
  }
5078
5079
0
  em = Stream_GetPosition(s);
5080
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
5081
0
    return FALSE;
5082
0
  lengthCombinedCapabilities = (em - bm);
5083
0
  if (lengthCombinedCapabilities > UINT16_MAX)
5084
0
    return FALSE;
5085
0
  Stream_Write_UINT16(
5086
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
5087
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
5088
0
    return FALSE;
5089
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
5090
#ifdef WITH_DEBUG_CAPABILITIES
5091
  rdp_print_capability_sets(log, s, bm, FALSE);
5092
#endif
5093
0
  return Stream_SetPosition(s, em);
5094
0
}
5095
5096
BOOL rdp_send_confirm_active(rdpRdp* rdp)
5097
0
{
5098
0
  UINT16 sec_flags = 0;
5099
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
5100
0
  BOOL status = 0;
5101
5102
0
  if (!s)
5103
0
    return FALSE;
5104
5105
0
  status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
5106
0
           rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
5107
0
  Stream_Release(s);
5108
0
  return status;
5109
0
}
5110
5111
const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
5112
0
{
5113
0
  char prefix[16] = WINPR_C_ARRAY_INIT;
5114
5115
0
  (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
5116
0
  winpr_str_append(prefix, buffer, len, "");
5117
0
  if ((flags & INPUT_FLAG_SCANCODES) != 0)
5118
0
    winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
5119
0
  if ((flags & INPUT_FLAG_MOUSEX) != 0)
5120
0
    winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5121
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5122
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5123
0
  if ((flags & INPUT_FLAG_UNICODE) != 0)
5124
0
    winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5125
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5126
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5127
0
  if ((flags & INPUT_FLAG_UNUSED1) != 0)
5128
0
    winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5129
0
  if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5130
0
    winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5131
0
  if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5132
0
    winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5133
0
  if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5134
0
    winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5135
0
  winpr_str_append("]", buffer, len, "");
5136
0
  return buffer;
5137
0
}