Coverage Report

Created: 2025-07-01 06:46

/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
0
{
68
0
  if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
69
0
    return "<unknown>";
70
71
0
  return CAPSET_TYPE_STRINGS[type];
72
0
}
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
0
{
112
0
  WINPR_ASSERT(s);
113
0
  WINPR_ASSERT(length);
114
0
  WINPR_ASSERT(type);
115
116
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
117
0
    return FALSE;
118
0
  Stream_Read_UINT16(s, *type);   /* capabilitySetType */
119
0
  Stream_Read_UINT16(s, *length); /* lengthCapability */
120
0
  if (*length < 4)
121
0
    return FALSE;
122
0
  return TRUE;
123
0
}
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
0
{
160
0
  WINPR_ASSERT(settings);
161
0
  WINPR_ASSERT(src);
162
163
0
  if (settings->ServerMode)
164
0
  {
165
0
    settings->OsMajorType = src->OsMajorType;
166
0
    settings->OsMinorType = src->OsMinorType;
167
0
  }
168
169
0
  settings->CapsProtocolVersion = src->CapsProtocolVersion;
170
0
  settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
171
0
  settings->LongCredentialsSupported = src->LongCredentialsSupported;
172
0
  settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
173
0
  if (!src->FastPathOutput)
174
0
    settings->FastPathOutput = FALSE;
175
176
0
  if (!src->SaltedChecksum)
177
0
    settings->SaltedChecksum = FALSE;
178
179
0
  if (!settings->ServerMode)
180
0
  {
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
0
    if (!src->RefreshRect)
187
0
      settings->RefreshRect = FALSE;
188
189
0
    if (!src->SuppressOutput)
190
0
      settings->SuppressOutput = FALSE;
191
0
  }
192
0
  return TRUE;
193
0
}
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
0
{
202
0
  UINT16 extraFlags = 0;
203
0
  BYTE refreshRectSupport = 0;
204
0
  BYTE suppressOutputSupport = 0;
205
206
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
207
0
    return FALSE;
208
209
0
  WINPR_ASSERT(settings);
210
0
  Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
211
0
  Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
212
213
0
  Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
214
0
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
215
0
  {
216
0
    WLog_Print(log, WLOG_ERROR,
217
0
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
218
0
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
219
0
               settings->CapsProtocolVersion, TS_CAPS_PROTOCOLVERSION);
220
0
    if (settings->CapsProtocolVersion == 0x0000)
221
0
    {
222
0
      WLog_Print(log, WLOG_WARN,
223
0
                 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
224
0
                 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
225
0
                 settings->CapsProtocolVersion);
226
0
      settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
227
0
    }
228
0
    else
229
0
      return FALSE;
230
0
  }
231
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
232
0
  Stream_Read_UINT16(
233
0
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
234
0
  Stream_Read_UINT16(s, extraFlags);             /* extraFlags (2 bytes) */
235
0
  Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
236
0
  Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
237
0
  Stream_Read_UINT16(
238
0
      s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
239
0
  Stream_Read_UINT8(s, refreshRectSupport);      /* refreshRectSupport (1 byte) */
240
0
  Stream_Read_UINT8(s, suppressOutputSupport);   /* suppressOutputSupport (1 byte) */
241
0
  settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
242
0
  settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE;
243
244
0
  settings->AutoReconnectionPacketSupported =
245
0
      (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
246
0
  settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) ? TRUE : FALSE;
247
0
  settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) ? TRUE : FALSE;
248
0
  settings->RefreshRect = refreshRectSupport;
249
0
  settings->SuppressOutput = suppressOutputSupport;
250
251
0
  return TRUE;
252
0
}
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
0
{
354
0
  WINPR_ASSERT(settings);
355
0
  WINPR_ASSERT(src);
356
357
0
  if (!settings->ServerMode)
358
0
  {
359
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
360
0
                                     freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
361
0
      return FALSE;
362
0
  }
363
364
0
  if (!src->DesktopResize)
365
0
    settings->DesktopResize = FALSE;
366
367
0
  if (!settings->ServerMode && settings->DesktopResize)
368
0
  {
369
    /* The server may request a different desktop size during Deactivation-Reactivation sequence
370
     */
371
0
    settings->DesktopWidth = src->DesktopWidth;
372
0
    settings->DesktopHeight = src->DesktopHeight;
373
0
  }
374
375
0
  if (settings->DrawAllowSkipAlpha)
376
0
    settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
377
378
0
  if (settings->DrawAllowDynamicColorFidelity)
379
0
    settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
380
381
0
  if (settings->DrawAllowColorSubsampling)
382
0
    settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
383
384
0
  return TRUE;
385
0
}
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
0
{
394
0
  BYTE drawingFlags = 0;
395
0
  UINT16 desktopWidth = 0;
396
0
  UINT16 desktopHeight = 0;
397
0
  UINT16 desktopResizeFlag = 0;
398
0
  UINT16 preferredBitsPerPixel = 0;
399
400
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
401
0
    return FALSE;
402
403
0
  Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
404
0
  Stream_Seek_UINT16(s);                        /* receive1BitPerPixel (2 bytes) */
405
0
  Stream_Seek_UINT16(s);                        /* receive4BitsPerPixel (2 bytes) */
406
0
  Stream_Seek_UINT16(s);                        /* receive8BitsPerPixel (2 bytes) */
407
0
  Stream_Read_UINT16(s, desktopWidth);          /* desktopWidth (2 bytes) */
408
0
  Stream_Read_UINT16(s, desktopHeight);         /* desktopHeight (2 bytes) */
409
0
  Stream_Seek_UINT16(s);                        /* pad2Octets (2 bytes) */
410
0
  Stream_Read_UINT16(s, desktopResizeFlag);     /* desktopResizeFlag (2 bytes) */
411
0
  Stream_Seek_UINT16(s);                        /* bitmapCompressionFlag (2 bytes) */
412
0
  Stream_Seek_UINT8(s);                         /* highColorFlags (1 byte) */
413
0
  Stream_Read_UINT8(s, drawingFlags);           /* drawingFlags (1 byte) */
414
0
  Stream_Seek_UINT16(s);                        /* multipleRectangleSupport (2 bytes) */
415
0
  Stream_Seek_UINT16(s);                        /* pad2OctetsB (2 bytes) */
416
417
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
418
0
    return FALSE;
419
0
  settings->DesktopResize = desktopResizeFlag;
420
0
  settings->DesktopWidth = desktopWidth;
421
0
  settings->DesktopHeight = desktopHeight;
422
0
  settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) ? TRUE : FALSE;
423
0
  settings->DrawAllowDynamicColorFidelity =
424
0
      (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) ? TRUE : FALSE;
425
0
  settings->DrawAllowColorSubsampling =
426
0
      (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) ? TRUE : FALSE;
427
428
0
  return TRUE;
429
0
}
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
0
{
544
0
  WINPR_ASSERT(settings);
545
0
  WINPR_ASSERT(src);
546
547
0
  BOOL BitmapCacheV3Enabled = FALSE;
548
0
  BOOL FrameMarkerCommandEnabled = FALSE;
549
550
0
  for (size_t i = 0; i < 32; i++)
551
0
  {
552
0
    if (!src->OrderSupport[i])
553
0
      settings->OrderSupport[i] = FALSE;
554
0
  }
555
556
0
  if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
557
0
  {
558
0
    if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
559
0
      BitmapCacheV3Enabled = TRUE;
560
561
0
    if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
562
0
      FrameMarkerCommandEnabled = TRUE;
563
0
  }
564
565
0
  if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
566
0
  {
567
0
    settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
568
0
    settings->BitmapCacheVersion = src->BitmapCacheVersion;
569
0
  }
570
0
  else
571
0
    settings->BitmapCacheV3Enabled = FALSE;
572
573
0
  if (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled)
574
0
    settings->FrameMarkerCommandEnabled = TRUE;
575
0
  else
576
0
    settings->FrameMarkerCommandEnabled = FALSE;
577
578
0
  return TRUE;
579
0
}
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
0
{
588
0
  char terminalDescriptor[17] = { 0 };
589
0
  BYTE orderSupport[32] = { 0 };
590
0
  BOOL BitmapCacheV3Enabled = FALSE;
591
0
  BOOL FrameMarkerCommandEnabled = FALSE;
592
593
0
  WINPR_ASSERT(settings);
594
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
595
0
    return FALSE;
596
597
0
  Stream_Read(s, terminalDescriptor, 16);               /* terminalDescriptor (16 bytes) */
598
0
  Stream_Seek_UINT32(s);                                /* pad4OctetsA (4 bytes) */
599
0
  Stream_Seek_UINT16(s);                                /* desktopSaveXGranularity (2 bytes) */
600
0
  Stream_Seek_UINT16(s);                                /* desktopSaveYGranularity (2 bytes) */
601
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
602
0
  Stream_Seek_UINT16(s);                                /* maximumOrderLevel (2 bytes) */
603
0
  Stream_Seek_UINT16(s);                                /* numberFonts (2 bytes) */
604
0
  Stream_Read_UINT16(s, settings->OrderSupportFlags);   /* orderFlags (2 bytes) */
605
0
  Stream_Read(s, orderSupport, 32);                     /* orderSupport (32 bytes) */
606
0
  Stream_Seek_UINT16(s);                                /* textFlags (2 bytes) */
607
0
  Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
608
0
  Stream_Seek_UINT32(s);                                /* pad4OctetsB (4 bytes) */
609
0
  Stream_Seek_UINT32(s);                                /* desktopSaveSize (4 bytes) */
610
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsC (2 bytes) */
611
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsD (2 bytes) */
612
0
  Stream_Read_UINT16(s, settings->TextANSICodePage);    /* textANSICodePage (2 bytes) */
613
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsE (2 bytes) */
614
615
0
  if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
616
0
    return FALSE;
617
618
0
  for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
619
0
    settings->OrderSupport[i] = orderSupport[i];
620
621
0
  if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
622
0
  {
623
0
    BitmapCacheV3Enabled =
624
0
        (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) ? TRUE : FALSE;
625
0
    FrameMarkerCommandEnabled =
626
0
        (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) ? TRUE : FALSE;
627
0
  }
628
629
0
  settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
630
0
  if (BitmapCacheV3Enabled)
631
0
    settings->BitmapCacheVersion = 3;
632
633
0
  settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
634
635
0
  return TRUE;
636
0
}
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
0
{
822
0
  WINPR_ASSERT(settings);
823
0
  WINPR_ASSERT(src);
824
0
  return TRUE;
825
0
}
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
0
{
834
0
  WINPR_UNUSED(settings);
835
0
  WINPR_ASSERT(settings);
836
837
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
838
0
    return FALSE;
839
840
0
  Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
841
0
  Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
842
0
  Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
843
0
  Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
844
0
  Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
845
0
  Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
846
0
  Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
847
0
  Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
848
0
  Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
849
0
  Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
850
0
  Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
851
0
  Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
852
0
  return TRUE;
853
0
}
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
0
{
946
0
  WINPR_ASSERT(settings);
947
0
  WINPR_ASSERT(src);
948
949
0
  return TRUE;
950
0
}
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
0
{
959
0
  WINPR_UNUSED(settings);
960
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
961
0
    return FALSE;
962
963
0
  Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
964
0
  Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
965
0
  Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
966
0
  Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
967
0
  return TRUE;
968
0
}
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
0
{
1017
0
  WINPR_ASSERT(settings);
1018
0
  WINPR_ASSERT(src);
1019
1020
0
  return TRUE;
1021
0
}
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
0
{
1030
0
  WINPR_UNUSED(settings);
1031
0
  WINPR_ASSERT(settings);
1032
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1033
0
    return FALSE;
1034
1035
0
  Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1036
0
  Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1037
0
  Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1038
0
  Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1039
0
  return TRUE;
1040
0
}
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
0
{
1090
0
  WINPR_ASSERT(settings);
1091
0
  WINPR_ASSERT(src);
1092
1093
0
  const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1094
0
  const UINT32 colorPointerCacheSize =
1095
0
      freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1096
0
  const UINT32 dstPointerCacheSize =
1097
0
      freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1098
0
  const UINT32 dstColorPointerCacheSize =
1099
0
      freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1100
1101
  /* We want the minimum of our setting and the remote announced value. */
1102
0
  const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1103
0
  const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1104
1105
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1106
0
      !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1107
0
                                   actualColorPointerCacheSize))
1108
0
    return FALSE;
1109
1110
0
  return TRUE;
1111
0
}
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
0
{
1120
0
  UINT16 colorPointerFlag = 0;
1121
0
  UINT16 colorPointerCacheSize = 0;
1122
0
  UINT16 pointerCacheSize = 0;
1123
1124
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1125
0
    return FALSE;
1126
1127
0
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1128
0
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1129
1130
0
  if (colorPointerFlag == 0)
1131
0
  {
1132
0
    WLog_Print(log, WLOG_WARN,
1133
0
               "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1134
0
               "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1135
0
               ". Value is ignored and always assumed to be TRUE");
1136
0
  }
1137
1138
  /* pointerCacheSize is optional */
1139
0
  if (Stream_GetRemainingLength(s) >= 2)
1140
0
    Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1141
1142
0
  WINPR_ASSERT(settings);
1143
0
  settings->PointerCacheSize = pointerCacheSize;
1144
0
  settings->ColorPointerCacheSize = colorPointerCacheSize;
1145
1146
0
  return TRUE;
1147
0
}
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
0
{
1202
0
  WINPR_ASSERT(settings);
1203
0
  WINPR_ASSERT(src);
1204
1205
0
  return TRUE;
1206
0
}
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
0
{
1215
0
  WINPR_UNUSED(settings);
1216
0
  WINPR_ASSERT(settings);
1217
1218
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1219
0
    return FALSE;
1220
1221
0
  Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1222
0
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1223
0
  return TRUE;
1224
0
}
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
0
{
1267
0
  WINPR_ASSERT(settings);
1268
0
  WINPR_ASSERT(src);
1269
0
  return TRUE;
1270
0
}
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
0
{
1279
0
  WINPR_UNUSED(settings);
1280
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1281
0
    return FALSE;
1282
1283
0
  Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1284
0
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1285
0
  return TRUE;
1286
0
}
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
0
{
1326
0
  WINPR_ASSERT(settings);
1327
0
  WINPR_ASSERT(src);
1328
1329
0
  settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1330
1331
0
  return TRUE;
1332
0
}
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
0
{
1341
0
  UINT16 soundFlags = 0;
1342
1343
0
  WINPR_ASSERT(settings);
1344
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1345
0
    return FALSE;
1346
1347
0
  Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1348
0
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1349
0
  settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) ? TRUE : FALSE;
1350
0
  return TRUE;
1351
0
}
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
0
{
1392
0
  WINPR_ASSERT(settings);
1393
0
  WINPR_ASSERT(src);
1394
1395
0
  if (settings->ServerMode)
1396
0
  {
1397
0
    settings->KeyboardLayout = src->KeyboardLayout;
1398
0
    settings->KeyboardType = src->KeyboardType;
1399
0
    settings->KeyboardSubType = src->KeyboardSubType;
1400
0
    settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1401
0
  }
1402
1403
0
  if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1404
0
    return FALSE;
1405
1406
0
  if (!settings->ServerMode)
1407
0
  {
1408
0
    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
0
    if (settings->HasHorizontalWheel)
1415
0
      settings->HasHorizontalWheel = src->HasHorizontalWheel;
1416
0
    const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1417
0
    if (UnicodeInput)
1418
0
    {
1419
0
      const BOOL srcVal = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1420
0
      if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1421
0
        return FALSE;
1422
0
    }
1423
0
    if (settings->HasExtendedMouseEvent)
1424
0
      settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1425
0
    if (settings->HasRelativeMouseEvent)
1426
0
      settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1427
0
    if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1428
0
      settings->HasQoeEvent = freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent);
1429
0
  }
1430
0
  return TRUE;
1431
0
}
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
0
{
1440
0
  UINT16 inputFlags = 0;
1441
1442
0
  WINPR_ASSERT(settings);
1443
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1444
0
    return FALSE;
1445
1446
0
  Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1447
0
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1448
1449
0
  Stream_Read_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1450
0
  Stream_Read_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1451
0
  Stream_Read_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1452
0
  Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1453
1454
0
  {
1455
0
    WCHAR wstr[32] = { 0 };
1456
0
    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
0
    if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1463
0
      return FALSE;
1464
1465
0
    if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1466
0
      memset(str, 0, sizeof(str));
1467
1468
0
    if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1469
0
      return FALSE;
1470
0
  }
1471
1472
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1473
0
                                 inputFlags &
1474
0
                                     (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1475
0
    return FALSE;
1476
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1477
0
                                 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) ? TRUE : FALSE))
1478
0
    return FALSE;
1479
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1480
0
                                 (inputFlags & INPUT_FLAG_UNICODE) ? TRUE : FALSE))
1481
0
    return FALSE;
1482
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1483
0
                                 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) ? TRUE : FALSE))
1484
0
    return FALSE;
1485
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1486
0
                                 (inputFlags & INPUT_FLAG_MOUSEX) ? TRUE : FALSE))
1487
0
    return FALSE;
1488
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1489
0
                                 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) ? TRUE : FALSE))
1490
0
    return FALSE;
1491
1492
0
  return TRUE;
1493
0
}
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
0
{
1575
0
  WINPR_ASSERT(settings);
1576
0
  WINPR_ASSERT(src);
1577
0
  return TRUE;
1578
0
}
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
0
{
1588
0
  WINPR_UNUSED(settings);
1589
0
  if (Stream_GetRemainingLength(s) >= 2)
1590
0
    Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1591
1592
0
  if (Stream_GetRemainingLength(s) >= 2)
1593
0
    Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1594
1595
0
  return TRUE;
1596
0
}
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
0
{
1637
0
  WINPR_ASSERT(settings);
1638
0
  WINPR_ASSERT(src);
1639
1640
  // TODO: Minimum of what?
1641
0
  settings->BrushSupportLevel = src->BrushSupportLevel;
1642
0
  return TRUE;
1643
0
}
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
0
{
1652
0
  WINPR_UNUSED(settings);
1653
0
  WINPR_ASSERT(settings);
1654
1655
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1656
0
    return FALSE;
1657
0
  Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1658
0
  return TRUE;
1659
0
}
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
0
{
1699
0
  WINPR_ASSERT(cache_definition);
1700
0
  Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1701
0
  Stream_Read_UINT16(s,
1702
0
                     cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1703
0
}
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
0
{
1719
0
  WINPR_ASSERT(settings);
1720
0
  WINPR_ASSERT(src);
1721
1722
0
  WINPR_ASSERT(src->GlyphCache);
1723
0
  WINPR_ASSERT(settings->GlyphCache);
1724
0
  for (size_t x = 0; x < 10; x++)
1725
0
    settings->GlyphCache[x] = src->GlyphCache[x];
1726
1727
0
  WINPR_ASSERT(src->FragCache);
1728
0
  WINPR_ASSERT(settings->FragCache);
1729
0
  settings->FragCache[0] = src->FragCache[0];
1730
0
  settings->GlyphSupportLevel = src->GlyphSupportLevel;
1731
1732
0
  return TRUE;
1733
0
}
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
0
{
1742
0
  WINPR_ASSERT(settings);
1743
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1744
0
    return FALSE;
1745
1746
  /* glyphCache (40 bytes) */
1747
0
  for (size_t x = 0; x < 10; x++)
1748
0
    rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1749
0
  rdp_read_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1750
0
  Stream_Read_UINT16(s, settings->GlyphSupportLevel);           /* glyphSupportLevel (2 bytes) */
1751
0
  Stream_Seek_UINT16(s);                                        /* pad2Octets (2 bytes) */
1752
0
  return TRUE;
1753
0
}
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
0
{
1836
0
  WINPR_ASSERT(settings);
1837
0
  WINPR_ASSERT(src);
1838
1839
0
  settings->OffscreenCacheSize = src->OffscreenCacheSize;
1840
0
  settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1841
0
  settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1842
1843
0
  return TRUE;
1844
0
}
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
0
{
1854
0
  UINT32 offscreenSupportLevel = 0;
1855
1856
0
  WINPR_ASSERT(settings);
1857
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1858
0
    return FALSE;
1859
1860
0
  Stream_Read_UINT32(s, offscreenSupportLevel);           /* offscreenSupportLevel (4 bytes) */
1861
0
  Stream_Read_UINT16(s, settings->OffscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1862
0
  Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1863
1864
0
  settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1865
1866
0
  return TRUE;
1867
0
}
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
0
{
1927
0
  const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1928
0
                    freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1929
0
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1930
0
}
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
0
{
1940
0
  BYTE cacheVersion = 0;
1941
1942
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1943
0
    return FALSE;
1944
1945
0
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1946
0
  Stream_Seek_UINT8(s);               /* pad1 (1 byte) */
1947
0
  Stream_Seek_UINT16(s);              /* pad2 (2 bytes) */
1948
1949
0
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1950
0
                                   cacheVersion & BITMAP_CACHE_V2);
1951
0
}
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
0
{
2001
0
  UINT32 info = 0;
2002
2003
0
  WINPR_ASSERT(cellInfo);
2004
0
  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
0
  Stream_Read_UINT32(s, info);
2012
0
  cellInfo->numEntries = (info & 0x7FFFFFFF);
2013
0
  cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2014
0
  return TRUE;
2015
0
}
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
0
{
2031
0
  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2032
0
                                            FreeRDP_BitmapCachePersistEnabled };
2033
2034
0
  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2035
0
  {
2036
0
    const FreeRDP_Settings_Keys_Bool id = keys[x];
2037
0
    const BOOL val = freerdp_settings_get_bool(src, id);
2038
0
    if (!freerdp_settings_set_bool(settings, id, val))
2039
0
      return FALSE;
2040
0
  }
2041
2042
0
  {
2043
0
    const UINT32 BitmapCacheV2NumCells =
2044
0
        freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2045
0
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, NULL,
2046
0
                                          BitmapCacheV2NumCells))
2047
0
      return FALSE;
2048
2049
0
    for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2050
0
    {
2051
0
      const BITMAP_CACHE_V2_CELL_INFO* cdata =
2052
0
          freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2053
0
      if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2054
0
                                              cdata))
2055
0
        return FALSE;
2056
0
    }
2057
0
  }
2058
2059
0
  return TRUE;
2060
0
}
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
0
{
2069
0
  UINT16 cacheFlags = 0;
2070
0
  WINPR_UNUSED(settings);
2071
0
  WINPR_ASSERT(settings);
2072
2073
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2074
0
    return FALSE;
2075
2076
0
  Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2077
2078
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2079
0
    return FALSE;
2080
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2081
0
                                 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2082
0
    return FALSE;
2083
2084
0
  Stream_Seek_UINT8(s);                                  /* pad2 (1 byte) */
2085
0
  Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2086
0
  if (settings->BitmapCacheV2NumCells > 5)
2087
0
  {
2088
0
    WLog_Print(log, WLOG_ERROR,
2089
0
               "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2090
0
               settings->BitmapCacheV2NumCells);
2091
0
    return FALSE;
2092
0
  }
2093
2094
0
  for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2095
0
  {
2096
0
    BITMAP_CACHE_V2_CELL_INFO* info =
2097
0
        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2098
0
    if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2099
0
      return FALSE;
2100
0
  }
2101
2102
  /* Input must always have 5 BitmapCacheV2CellInfo values */
2103
0
  for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2104
0
  {
2105
0
    if (!Stream_SafeSeek(s, 4))
2106
0
      return FALSE;
2107
0
  }
2108
0
  Stream_Seek(s, 12); /* pad3 (12 bytes) */
2109
0
  return TRUE;
2110
0
}
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
0
{
2197
0
  WINPR_ASSERT(settings);
2198
0
  WINPR_ASSERT(src);
2199
2200
  /* MS servers and clients disregard in advertising what is relevant for their own side */
2201
0
  if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2202
0
      (src->VCFlags & VCCAPS_COMPR_SC))
2203
0
    settings->VCFlags |= VCCAPS_COMPR_SC;
2204
0
  else
2205
0
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2206
2207
0
  if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2208
0
      (src->VCFlags & VCCAPS_COMPR_CS_8K))
2209
0
    settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2210
0
  else
2211
0
    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
0
  if (!settings->ServerMode)
2219
0
  {
2220
0
    if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2221
0
      settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2222
0
    else
2223
0
    {
2224
0
      settings->VCChunkSize = src->VCChunkSize;
2225
0
    }
2226
0
  }
2227
2228
0
  return TRUE;
2229
0
}
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
0
{
2238
0
  UINT32 flags = 0;
2239
0
  UINT32 VCChunkSize = 0;
2240
2241
0
  WINPR_ASSERT(settings);
2242
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2243
0
    return FALSE;
2244
2245
0
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2246
2247
0
  if (Stream_GetRemainingLength(s) >= 4)
2248
0
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2249
0
  else
2250
0
    VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2251
2252
0
  settings->VCFlags = flags;
2253
0
  settings->VCChunkSize = VCChunkSize;
2254
2255
0
  return TRUE;
2256
0
}
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
0
{
2303
0
  WINPR_ASSERT(settings);
2304
0
  WINPR_ASSERT(src);
2305
2306
0
  settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2307
0
  settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2308
0
  settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2309
2310
0
  return TRUE;
2311
0
}
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
0
{
2321
0
  UINT32 drawNineGridSupportLevel = 0;
2322
2323
0
  WINPR_ASSERT(settings);
2324
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2325
0
    return FALSE;
2326
2327
0
  Stream_Read_UINT32(s, drawNineGridSupportLevel);        /* drawNineGridSupportLevel (4 bytes) */
2328
0
  Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2329
0
  Stream_Read_UINT16(s,
2330
0
                     settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2331
2332
0
  settings->DrawNineGridEnabled =
2333
0
      (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) ? TRUE
2334
0
                                                                                          : FALSE;
2335
2336
0
  return TRUE;
2337
0
}
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
0
{
2390
0
  WINPR_ASSERT(settings);
2391
0
  WINPR_ASSERT(src);
2392
2393
0
  if (src->DrawGdiPlusEnabled)
2394
0
    settings->DrawGdiPlusEnabled = TRUE;
2395
2396
0
  if (src->DrawGdiPlusCacheEnabled)
2397
0
    settings->DrawGdiPlusCacheEnabled = TRUE;
2398
2399
0
  return TRUE;
2400
0
}
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
0
{
2409
0
  UINT32 drawGDIPlusSupportLevel = 0;
2410
0
  UINT32 drawGdiplusCacheLevel = 0;
2411
2412
0
  WINPR_ASSERT(settings);
2413
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2414
0
    return FALSE;
2415
2416
0
  Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2417
0
  Stream_Seek_UINT32(s);                          /* GdipVersion (4 bytes) */
2418
0
  Stream_Read_UINT32(s, drawGdiplusCacheLevel);   /* drawGdiplusCacheLevel (4 bytes) */
2419
0
  Stream_Seek(s, 10);                             /* GdipCacheEntries (10 bytes) */
2420
0
  Stream_Seek(s, 8);                              /* GdipCacheChunkSize (8 bytes) */
2421
0
  Stream_Seek(s, 6);                              /* GdipImageCacheProperties (6 bytes) */
2422
2423
0
  settings->DrawGdiPlusEnabled =
2424
0
      (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) ? TRUE : FALSE;
2425
0
  settings->DrawGdiPlusCacheEnabled =
2426
0
      (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) ? TRUE : FALSE;
2427
2428
0
  return TRUE;
2429
0
}
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
0
{
2488
0
  WINPR_ASSERT(settings);
2489
0
  WINPR_ASSERT(src);
2490
2491
0
  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
0
  UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2498
0
  if (settings->RemoteApplicationMode)
2499
0
    supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2500
2501
0
  settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2502
2503
0
  return TRUE;
2504
0
}
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
0
{
2513
0
  UINT32 railSupportLevel = 0;
2514
2515
0
  WINPR_ASSERT(settings);
2516
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2517
0
    return FALSE;
2518
2519
0
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2520
2521
0
  settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) ? TRUE : FALSE;
2522
0
  settings->RemoteApplicationSupportLevel = railSupportLevel;
2523
0
  return TRUE;
2524
0
}
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
0
{
2577
0
  WINPR_ASSERT(settings);
2578
0
  WINPR_ASSERT(src);
2579
2580
0
  settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2581
0
  settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2582
0
  settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2583
2584
0
  return TRUE;
2585
0
}
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
0
{
2594
0
  WINPR_ASSERT(settings);
2595
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2596
0
    return FALSE;
2597
2598
0
  Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2599
0
  Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2600
0
  Stream_Read_UINT16(s,
2601
0
                     settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2602
0
  return TRUE;
2603
0
}
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
0
{
2653
0
  WINPR_ASSERT(settings);
2654
0
  WINPR_ASSERT(src);
2655
2656
0
  settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2657
0
  return TRUE;
2658
0
}
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
0
{
2668
0
  WINPR_UNUSED(settings);
2669
0
  WINPR_ASSERT(settings);
2670
2671
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2672
0
    return FALSE;
2673
2674
0
  Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2675
0
  return TRUE;
2676
0
}
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
0
{
2717
0
  UINT32 multifragMaxRequestSize = 0;
2718
2719
0
  WINPR_ASSERT(settings);
2720
0
  WINPR_ASSERT(src);
2721
2722
0
  multifragMaxRequestSize = src->MultifragMaxRequestSize;
2723
2724
0
  if (settings->ServerMode)
2725
0
  {
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
0
    if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2735
0
      multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2736
2737
0
    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
0
    else
2759
0
    {
2760
0
      settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2761
0
    }
2762
0
  }
2763
0
  else
2764
0
  {
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
0
    if (multifragMaxRequestSize > settings->MultifragMaxRequestSize)
2771
0
      settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2772
0
  }
2773
0
  return TRUE;
2774
0
}
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
0
{
2784
0
  UINT32 multifragMaxRequestSize = 0;
2785
2786
0
  WINPR_ASSERT(settings);
2787
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2788
0
    return FALSE;
2789
2790
0
  Stream_Read_UINT32(s, multifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2791
0
  settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2792
2793
0
  return TRUE;
2794
0
}
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
0
{
2850
0
  WINPR_ASSERT(settings);
2851
0
  WINPR_ASSERT(src);
2852
2853
0
  settings->LargePointerFlag = src->LargePointerFlag;
2854
0
  return TRUE;
2855
0
}
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
0
{
2864
0
  UINT16 largePointerSupportFlags = 0;
2865
2866
0
  WINPR_ASSERT(settings);
2867
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2868
0
    return FALSE;
2869
2870
0
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2871
0
  settings->LargePointerFlag &= largePointerSupportFlags;
2872
0
  if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2873
0
  {
2874
0
    WLog_Print(
2875
0
        log, WLOG_WARN,
2876
0
        "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2877
0
        largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384),
2878
0
        largePointerSupportFlags);
2879
0
  }
2880
0
  return TRUE;
2881
0
}
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
0
{
2921
0
  WINPR_ASSERT(settings);
2922
0
  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
0
  if (src->FastPathOutput)
2929
0
  {
2930
0
    settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2931
0
    settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2932
0
    settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2933
0
  }
2934
0
  else
2935
0
  {
2936
0
    settings->SurfaceCommandsSupported = 0;
2937
0
    settings->SurfaceCommandsEnabled = FALSE;
2938
0
    settings->SurfaceFrameMarkerEnabled = FALSE;
2939
0
  }
2940
2941
0
  return TRUE;
2942
0
}
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
0
{
2951
0
  UINT32 cmdFlags = 0;
2952
2953
0
  WINPR_ASSERT(settings);
2954
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2955
0
    return FALSE;
2956
2957
0
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2958
0
  Stream_Seek_UINT32(s);           /* reserved (4 bytes) */
2959
0
  settings->SurfaceCommandsSupported = cmdFlags;
2960
0
  settings->SurfaceCommandsEnabled =
2961
0
      (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) ? TRUE : FALSE;
2962
0
  settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) ? TRUE : FALSE;
2963
0
  return TRUE;
2964
0
}
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
0
{
2992
0
  if (!Uuid1 && !Uuid2)
2993
0
    return false;
2994
2995
0
  if (Uuid1 && !Uuid2)
2996
0
    return false;
2997
2998
0
  if (!Uuid1 && Uuid2)
2999
0
    return true;
3000
3001
0
  if (Uuid1->Data1 != Uuid2->Data1)
3002
0
    return false;
3003
3004
0
  if (Uuid1->Data2 != Uuid2->Data2)
3005
0
    return false;
3006
3007
0
  if (Uuid1->Data3 != Uuid2->Data3)
3008
0
    return false;
3009
3010
0
  for (int index = 0; index < 8; index++)
3011
0
  {
3012
0
    if (Uuid1->Data4[index] != Uuid2->Data4[index])
3013
0
      return false;
3014
0
  }
3015
3016
0
  return true;
3017
0
}
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
0
{
3072
0
  BYTE g[16] = { 0 };
3073
3074
0
  WINPR_ASSERT(guid);
3075
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3076
0
    return FALSE;
3077
0
  Stream_Read(s, g, 16);
3078
0
  guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3079
0
  guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3080
0
  guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3081
0
  guid->Data4[0] = g[8];
3082
0
  guid->Data4[1] = g[9];
3083
0
  guid->Data4[2] = g[10];
3084
0
  guid->Data4[3] = g[11];
3085
0
  guid->Data4[4] = g[12];
3086
0
  guid->Data4[5] = g[13];
3087
0
  guid->Data4[6] = g[14];
3088
0
  guid->Data4[7] = g[15];
3089
0
  return TRUE;
3090
0
}
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
0
{
3117
0
  WINPR_ASSERT(settings);
3118
0
  WINPR_ASSERT(src);
3119
3120
0
  if (settings->ServerMode)
3121
0
  {
3122
3123
0
    settings->RemoteFxCodecId = src->RemoteFxCodecId;
3124
0
    settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3125
0
    settings->RemoteFxOnly = src->RemoteFxOnly;
3126
0
    settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3127
0
    settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3128
0
    settings->NSCodecId = src->NSCodecId;
3129
0
    settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3130
0
    settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3131
0
    settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3132
3133
    /* only enable a codec if we've announced/enabled it before */
3134
0
    settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3135
0
    settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3136
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3137
0
                                   settings->NSCodec && src->NSCodec))
3138
0
      return FALSE;
3139
0
    settings->JpegCodec = src->JpegCodec;
3140
0
  }
3141
0
  return TRUE;
3142
0
}
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
0
{
3431
0
  BYTE codecId = 0;
3432
0
  GUID codecGuid = { 0 };
3433
0
  BYTE bitmapCodecCount = 0;
3434
0
  UINT16 codecPropertiesLength = 0;
3435
3436
0
  BOOL guidNSCodec = FALSE;
3437
0
  BOOL guidRemoteFx = FALSE;
3438
0
  BOOL guidRemoteFxImage = FALSE;
3439
3440
0
  WINPR_ASSERT(settings);
3441
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3442
0
    return FALSE;
3443
3444
0
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3445
3446
0
  while (bitmapCodecCount > 0)
3447
0
  {
3448
0
    wStream subbuffer = { 0 };
3449
3450
0
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3451
0
      return FALSE;
3452
0
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3453
0
      return FALSE;
3454
0
    Stream_Read_UINT8(s, codecId);                /* codecId (1 byte) */
3455
0
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3456
3457
0
    wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3458
0
    if (!Stream_SafeSeek(s, codecPropertiesLength))
3459
0
      return FALSE;
3460
3461
0
    if (isServer)
3462
0
    {
3463
0
      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
0
      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
0
      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
0
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3501
0
      {
3502
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3503
0
          return FALSE;
3504
0
      }
3505
0
      else
3506
0
      {
3507
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3508
0
          return FALSE;
3509
0
      }
3510
0
    }
3511
0
    else
3512
0
    {
3513
0
      if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3514
0
        return FALSE;
3515
0
    }
3516
3517
0
    const size_t rest = Stream_GetRemainingLength(sub);
3518
0
    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
0
    bitmapCodecCount--;
3526
3527
    /* only enable a codec if we've announced/enabled it before */
3528
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3529
0
      return FALSE;
3530
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3531
0
      return FALSE;
3532
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3533
0
      return FALSE;
3534
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3535
0
      return FALSE;
3536
0
  }
3537
3538
0
  return TRUE;
3539
0
}
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
0
{
3839
0
  WINPR_ASSERT(settings);
3840
0
  WINPR_ASSERT(src);
3841
3842
0
  if (settings->ServerMode)
3843
0
    settings->FrameAcknowledge = src->FrameAcknowledge;
3844
3845
0
  return TRUE;
3846
0
}
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
0
{
3854
0
  WINPR_ASSERT(settings);
3855
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3856
0
    return FALSE;
3857
3858
0
  Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3859
3860
0
  return TRUE;
3861
0
}
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
0
{
3898
0
  WINPR_ASSERT(settings);
3899
0
  WINPR_ASSERT(src);
3900
3901
0
  settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3902
0
  return TRUE;
3903
0
}
3904
3905
static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3906
                                                             rdpSettings* settings)
3907
0
{
3908
0
  BYTE bitmapCacheV3CodecId = 0;
3909
3910
0
  WINPR_ASSERT(settings);
3911
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3912
0
    return FALSE;
3913
3914
0
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3915
0
  settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3916
0
  return TRUE;
3917
0
}
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
0
{
4188
0
  switch (type)
4189
0
  {
4190
0
    case CAPSET_TYPE_GENERAL:
4191
0
      return rdp_apply_general_capability_set(dst, src);
4192
0
    case CAPSET_TYPE_BITMAP:
4193
0
      return rdp_apply_bitmap_capability_set(dst, src);
4194
0
    case CAPSET_TYPE_ORDER:
4195
0
      return rdp_apply_order_capability_set(dst, src);
4196
0
    case CAPSET_TYPE_POINTER:
4197
0
      return rdp_apply_pointer_capability_set(dst, src);
4198
0
    case CAPSET_TYPE_INPUT:
4199
0
      return rdp_apply_input_capability_set(dst, src);
4200
0
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4201
0
      return rdp_apply_virtual_channel_capability_set(dst, src);
4202
0
    case CAPSET_TYPE_SHARE:
4203
0
      return rdp_apply_share_capability_set(dst, src);
4204
0
    case CAPSET_TYPE_COLOR_CACHE:
4205
0
      return rdp_apply_color_cache_capability_set(dst, src);
4206
0
    case CAPSET_TYPE_FONT:
4207
0
      return rdp_apply_font_capability_set(dst, src);
4208
0
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4209
0
      return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4210
0
    case CAPSET_TYPE_RAIL:
4211
0
      return rdp_apply_remote_programs_capability_set(dst, src);
4212
0
    case CAPSET_TYPE_WINDOW:
4213
0
      return rdp_apply_window_list_capability_set(dst, src);
4214
0
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4215
0
      return rdp_apply_multifragment_update_capability_set(dst, src);
4216
0
    case CAPSET_TYPE_LARGE_POINTER:
4217
0
      return rdp_apply_large_pointer_capability_set(dst, src);
4218
0
    case CAPSET_TYPE_COMP_DESK:
4219
0
      return rdp_apply_desktop_composition_capability_set(dst, src);
4220
0
    case CAPSET_TYPE_SURFACE_COMMANDS:
4221
0
      return rdp_apply_surface_commands_capability_set(dst, src);
4222
0
    case CAPSET_TYPE_BITMAP_CODECS:
4223
0
      return rdp_apply_bitmap_codecs_capability_set(dst, src);
4224
0
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4225
0
      return rdp_apply_frame_acknowledge_capability_set(dst, src);
4226
0
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4227
0
      return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4228
0
    case CAPSET_TYPE_BITMAP_CACHE:
4229
0
      return rdp_apply_bitmap_cache_capability_set(dst, src);
4230
0
    case CAPSET_TYPE_BITMAP_CACHE_V2:
4231
0
      return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4232
0
    case CAPSET_TYPE_BRUSH:
4233
0
      return rdp_apply_brush_capability_set(dst, src);
4234
0
    case CAPSET_TYPE_GLYPH_CACHE:
4235
0
      return rdp_apply_glyph_cache_capability_set(dst, src);
4236
0
    case CAPSET_TYPE_OFFSCREEN_CACHE:
4237
0
      return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4238
0
    case CAPSET_TYPE_SOUND:
4239
0
      return rdp_apply_sound_capability_set(dst, src);
4240
0
    case CAPSET_TYPE_CONTROL:
4241
0
      return rdp_apply_control_capability_set(dst, src);
4242
0
    case CAPSET_TYPE_ACTIVATION:
4243
0
      return rdp_apply_window_activation_capability_set(dst, src);
4244
0
    case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4245
0
      return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4246
0
    case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4247
0
      return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4248
0
    default:
4249
0
      return TRUE;
4250
0
  }
4251
0
}
4252
4253
BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4254
                             BOOL isServer)
4255
0
{
4256
0
  WINPR_ASSERT(settings);
4257
4258
0
  if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4259
0
  {
4260
0
    const size_t size = Stream_Length(sub);
4261
0
    if (size > UINT32_MAX)
4262
0
      return FALSE;
4263
4264
0
    WINPR_ASSERT(settings->ReceivedCapabilities);
4265
0
    settings->ReceivedCapabilities[type] = TRUE;
4266
4267
0
    WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4268
0
    settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4269
4270
0
    WINPR_ASSERT(settings->ReceivedCapabilityData);
4271
0
    void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4272
0
    if (!tmp && (size > 0))
4273
0
      return FALSE;
4274
0
    memcpy(tmp, Stream_Buffer(sub), size);
4275
0
    settings->ReceivedCapabilityData[type] = tmp;
4276
0
  }
4277
0
  else
4278
0
    WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4279
4280
0
  BOOL treated = TRUE;
4281
4282
0
  switch (type)
4283
0
  {
4284
0
    case CAPSET_TYPE_GENERAL:
4285
0
      if (!rdp_read_general_capability_set(log, sub, settings))
4286
0
        return FALSE;
4287
4288
0
      break;
4289
4290
0
    case CAPSET_TYPE_BITMAP:
4291
0
      if (!rdp_read_bitmap_capability_set(log, sub, settings))
4292
0
        return FALSE;
4293
4294
0
      break;
4295
4296
0
    case CAPSET_TYPE_ORDER:
4297
0
      if (!rdp_read_order_capability_set(log, sub, settings))
4298
0
        return FALSE;
4299
4300
0
      break;
4301
4302
0
    case CAPSET_TYPE_POINTER:
4303
0
      if (!rdp_read_pointer_capability_set(log, sub, settings))
4304
0
        return FALSE;
4305
4306
0
      break;
4307
4308
0
    case CAPSET_TYPE_INPUT:
4309
0
      if (!rdp_read_input_capability_set(log, sub, settings))
4310
0
        return FALSE;
4311
4312
0
      break;
4313
4314
0
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4315
0
      if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4316
0
        return FALSE;
4317
4318
0
      break;
4319
4320
0
    case CAPSET_TYPE_SHARE:
4321
0
      if (!rdp_read_share_capability_set(log, sub, settings))
4322
0
        return FALSE;
4323
4324
0
      break;
4325
4326
0
    case CAPSET_TYPE_COLOR_CACHE:
4327
0
      if (!rdp_read_color_cache_capability_set(log, sub, settings))
4328
0
        return FALSE;
4329
4330
0
      break;
4331
4332
0
    case CAPSET_TYPE_FONT:
4333
0
      if (!rdp_read_font_capability_set(log, sub, settings))
4334
0
        return FALSE;
4335
4336
0
      break;
4337
4338
0
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4339
0
      if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4340
0
        return FALSE;
4341
4342
0
      break;
4343
4344
0
    case CAPSET_TYPE_RAIL:
4345
0
      if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4346
0
        return FALSE;
4347
4348
0
      break;
4349
4350
0
    case CAPSET_TYPE_WINDOW:
4351
0
      if (!rdp_read_window_list_capability_set(log, sub, settings))
4352
0
        return FALSE;
4353
4354
0
      break;
4355
4356
0
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4357
0
      if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4358
0
        return FALSE;
4359
4360
0
      break;
4361
4362
0
    case CAPSET_TYPE_LARGE_POINTER:
4363
0
      if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4364
0
        return FALSE;
4365
4366
0
      break;
4367
4368
0
    case CAPSET_TYPE_COMP_DESK:
4369
0
      if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4370
0
        return FALSE;
4371
4372
0
      break;
4373
4374
0
    case CAPSET_TYPE_SURFACE_COMMANDS:
4375
0
      if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4376
0
        return FALSE;
4377
4378
0
      break;
4379
4380
0
    case CAPSET_TYPE_BITMAP_CODECS:
4381
0
      if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4382
0
        return FALSE;
4383
4384
0
      break;
4385
4386
0
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4387
0
      if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4388
0
        return FALSE;
4389
4390
0
      break;
4391
4392
0
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4393
0
      if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4394
0
        return FALSE;
4395
4396
0
      break;
4397
4398
0
    default:
4399
0
      treated = FALSE;
4400
0
      break;
4401
0
  }
4402
4403
0
  if (!treated)
4404
0
  {
4405
0
    if (isServer)
4406
0
    {
4407
      /* treating capabilities that are supposed to be send only from the client */
4408
0
      switch (type)
4409
0
      {
4410
0
        case CAPSET_TYPE_BITMAP_CACHE:
4411
0
          if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4412
0
            return FALSE;
4413
4414
0
          break;
4415
4416
0
        case CAPSET_TYPE_BITMAP_CACHE_V2:
4417
0
          if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4418
0
            return FALSE;
4419
4420
0
          break;
4421
4422
0
        case CAPSET_TYPE_BRUSH:
4423
0
          if (!rdp_read_brush_capability_set(log, sub, settings))
4424
0
            return FALSE;
4425
4426
0
          break;
4427
4428
0
        case CAPSET_TYPE_GLYPH_CACHE:
4429
0
          if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4430
0
            return FALSE;
4431
4432
0
          break;
4433
4434
0
        case CAPSET_TYPE_OFFSCREEN_CACHE:
4435
0
          if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4436
0
            return FALSE;
4437
4438
0
          break;
4439
4440
0
        case CAPSET_TYPE_SOUND:
4441
0
          if (!rdp_read_sound_capability_set(log, sub, settings))
4442
0
            return FALSE;
4443
4444
0
          break;
4445
4446
0
        case CAPSET_TYPE_CONTROL:
4447
0
          if (!rdp_read_control_capability_set(log, sub, settings))
4448
0
            return FALSE;
4449
4450
0
          break;
4451
4452
0
        case CAPSET_TYPE_ACTIVATION:
4453
0
          if (!rdp_read_window_activation_capability_set(log, sub, settings))
4454
0
            return FALSE;
4455
4456
0
          break;
4457
4458
0
        case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4459
0
          if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4460
0
            return FALSE;
4461
4462
0
          break;
4463
4464
0
        default:
4465
0
          WLog_Print(log, WLOG_ERROR,
4466
0
                     "capability %s(%" PRIu16 ") not expected from client",
4467
0
                     get_capability_name(type), type);
4468
0
          return FALSE;
4469
0
      }
4470
0
    }
4471
0
    else
4472
0
    {
4473
      /* treating capabilities that are supposed to be send only from the server */
4474
0
      switch (type)
4475
0
      {
4476
0
        case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4477
0
          if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4478
0
            return FALSE;
4479
4480
0
          break;
4481
4482
0
        default:
4483
0
          WLog_Print(log, WLOG_ERROR,
4484
0
                     "capability %s(%" PRIu16 ") not expected from server",
4485
0
                     get_capability_name(type), type);
4486
0
          return FALSE;
4487
0
      }
4488
0
    }
4489
0
  }
4490
4491
0
  const size_t rest = Stream_GetRemainingLength(sub);
4492
0
  if (rest > 0)
4493
0
  {
4494
0
    const size_t length = Stream_Capacity(sub);
4495
0
    WLog_Print(log, WLOG_ERROR,
4496
0
               "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4497
0
               type, length - rest, length);
4498
0
  }
4499
0
  return TRUE;
4500
0
}
4501
4502
static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4503
                                     rdpSettings* rcvSettings, UINT16 totalLength)
4504
0
{
4505
0
  BOOL rc = FALSE;
4506
0
  size_t start = 0;
4507
0
  size_t end = 0;
4508
0
  size_t len = 0;
4509
0
  UINT16 numberCapabilities = 0;
4510
0
  UINT16 count = 0;
4511
4512
#ifdef WITH_DEBUG_CAPABILITIES
4513
  const size_t capstart = Stream_GetPosition(s);
4514
#endif
4515
4516
0
  WINPR_ASSERT(s);
4517
0
  WINPR_ASSERT(settings);
4518
4519
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4520
0
    return FALSE;
4521
4522
0
  Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4523
0
  Stream_Seek(s, 2);                         /* pad2Octets (2 bytes) */
4524
0
  count = numberCapabilities;
4525
4526
0
  start = Stream_GetPosition(s);
4527
0
  while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4528
0
  {
4529
0
    UINT16 type = 0;
4530
0
    UINT16 length = 0;
4531
0
    wStream subbuffer;
4532
0
    wStream* sub = NULL;
4533
4534
0
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4535
0
      goto fail;
4536
0
    sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4537
0
    if (!Stream_SafeSeek(s, length - 4))
4538
0
      goto fail;
4539
4540
0
    if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4541
0
      goto fail;
4542
4543
0
    if (!rdp_apply_from_received(type, settings, rcvSettings))
4544
0
      goto fail;
4545
0
    numberCapabilities--;
4546
0
  }
4547
4548
0
  end = Stream_GetPosition(s);
4549
0
  len = end - start;
4550
4551
0
  if (numberCapabilities)
4552
0
  {
4553
0
    WLog_Print(log, WLOG_ERROR,
4554
0
               "strange we haven't read the number of announced capacity sets, read=%d "
4555
0
               "expected=%" PRIu16 "",
4556
0
               count - numberCapabilities, count);
4557
0
  }
4558
4559
#ifdef WITH_DEBUG_CAPABILITIES
4560
  rdp_print_capability_sets(log, s, capstart, TRUE);
4561
#endif
4562
4563
0
  if (len > totalLength)
4564
0
  {
4565
0
    WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIdz,
4566
0
               totalLength, len);
4567
0
    goto fail;
4568
0
  }
4569
0
  rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4570
0
fail:
4571
0
  return rc;
4572
0
}
4573
4574
BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4575
0
{
4576
0
  WINPR_ASSERT(rdp);
4577
0
  WINPR_ASSERT(rdp->context);
4578
4579
0
  if (!rdp_read_header(rdp, s, length, pChannelId))
4580
0
    return FALSE;
4581
4582
0
  if (freerdp_shall_disconnect_context(rdp->context))
4583
0
    return TRUE;
4584
4585
0
  if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4586
0
  {
4587
0
    UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4588
4589
0
    if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4590
0
    {
4591
0
      WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4592
0
                 *pChannelId);
4593
0
      return FALSE;
4594
0
    }
4595
0
  }
4596
4597
0
  return TRUE;
4598
0
}
4599
4600
BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4601
0
{
4602
0
  UINT16 lengthSourceDescriptor = 0;
4603
0
  UINT16 lengthCombinedCapabilities = 0;
4604
4605
0
  WINPR_ASSERT(rdp);
4606
0
  WINPR_ASSERT(rdp->settings);
4607
0
  WINPR_ASSERT(rdp->context);
4608
0
  WINPR_ASSERT(s);
4609
4610
0
  rdp->settings->PduSource = pduSource;
4611
4612
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4613
0
    return FALSE;
4614
4615
0
  Stream_Read_UINT32(s, rdp->settings->ShareId);     /* shareId (4 bytes) */
4616
0
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4617
0
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4618
4619
0
  if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4620
0
      !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4621
0
    return FALSE;
4622
4623
  /* capabilitySets */
4624
0
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4625
0
                                lengthCombinedCapabilities))
4626
0
  {
4627
0
    WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4628
0
    return FALSE;
4629
0
  }
4630
4631
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4632
0
    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
0
  Stream_Seek_UINT32(s); /* SessionId */
4637
4638
0
  {
4639
0
    rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4640
0
    secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4641
0
  }
4642
4643
0
  return tpkt_ensure_stream_consumed(rdp->log, s, length);
4644
0
}
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
0
{
4737
0
  rdpSettings* settings = NULL;
4738
0
  UINT16 lengthSourceDescriptor = 0;
4739
0
  UINT16 lengthCombinedCapabilities = 0;
4740
4741
0
  WINPR_ASSERT(rdp);
4742
0
  WINPR_ASSERT(s);
4743
0
  settings = rdp->settings;
4744
0
  WINPR_ASSERT(settings);
4745
4746
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4747
0
    return FALSE;
4748
4749
0
  Stream_Seek_UINT32(s);                             /* shareId (4 bytes) */
4750
0
  Stream_Seek_UINT16(s);                             /* originatorId (2 bytes) */
4751
0
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4752
0
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4753
4754
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4755
0
    return FALSE;
4756
4757
0
  Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4758
0
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4759
0
                                lengthCombinedCapabilities))
4760
0
    return FALSE;
4761
4762
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4763
0
  {
4764
    /* client does not support surface commands */
4765
0
    settings->SurfaceCommandsEnabled = FALSE;
4766
0
    settings->SurfaceFrameMarkerEnabled = FALSE;
4767
0
  }
4768
4769
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4770
0
  {
4771
    /* client does not support frame acks */
4772
0
    settings->FrameAcknowledge = 0;
4773
0
  }
4774
4775
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4776
0
  {
4777
    /* client does not support bitmap cache v3 */
4778
0
    settings->BitmapCacheV3Enabled = FALSE;
4779
0
  }
4780
4781
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4782
0
  {
4783
    /* client does not support bitmap codecs */
4784
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4785
0
      return FALSE;
4786
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4787
0
      return FALSE;
4788
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4789
0
      return FALSE;
4790
0
  }
4791
4792
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4793
0
  {
4794
    /* client does not support multi fragment updates - make sure packages are not fragmented */
4795
0
    settings->MultifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
4796
0
  }
4797
4798
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4799
0
  {
4800
    /* client does not support large pointers */
4801
0
    settings->LargePointerFlag = 0;
4802
0
  }
4803
4804
0
  return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4805
0
}
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
}