Coverage Report

Created: 2025-08-03 07:10

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