Coverage Report

Created: 2025-07-18 07:08

/src/FreeRDP/libfreerdp/core/capabilities.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RDP Capability Sets
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *   http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/wtsapi.h>
21
#include <winpr/assert.h>
22
#include <winpr/cast.h>
23
#include <freerdp/config.h>
24
25
#include "settings.h"
26
#include "capabilities.h"
27
#include "fastpath.h"
28
29
#include <winpr/crt.h>
30
#include <winpr/rpc.h>
31
32
#include <freerdp/log.h>
33
34
static const char* const CAPSET_TYPE_STRINGS[] = { "Unknown",
35
                                                 "General",
36
                                                 "Bitmap",
37
                                                 "Order",
38
                                                 "Bitmap Cache",
39
                                                 "Control",
40
                                                 "Unknown",
41
                                                 "Window Activation",
42
                                                 "Pointer",
43
                                                 "Share",
44
                                                 "Color Cache",
45
                                                 "Unknown",
46
                                                 "Sound",
47
                                                 "Input",
48
                                                 "Font",
49
                                                 "Brush",
50
                                                 "Glyph Cache",
51
                                                 "Offscreen Bitmap Cache",
52
                                                 "Bitmap Cache Host Support",
53
                                                 "Bitmap Cache v2",
54
                                                 "Virtual Channel",
55
                                                 "DrawNineGrid Cache",
56
                                                 "Draw GDI+ Cache",
57
                                                 "Remote Programs",
58
                                                 "Window List",
59
                                                 "Desktop Composition",
60
                                                 "Multifragment Update",
61
                                                 "Large Pointer",
62
                                                 "Surface Commands",
63
                                                 "Bitmap Codecs",
64
                                                 "Frame Acknowledge" };
65
66
static const char* get_capability_name(UINT16 type)
67
1.76k
{
68
1.76k
  if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
69
1.63k
    return "<unknown>";
70
71
126
  return CAPSET_TYPE_STRINGS[type];
72
1.76k
}
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
91.8k
{
112
91.8k
  WINPR_ASSERT(s);
113
91.8k
  WINPR_ASSERT(length);
114
91.8k
  WINPR_ASSERT(type);
115
116
91.8k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
117
0
    return FALSE;
118
91.8k
  Stream_Read_UINT16(s, *type);   /* capabilitySetType */
119
91.8k
  Stream_Read_UINT16(s, *length); /* lengthCapability */
120
91.8k
  if (*length < 4)
121
1.12k
    return FALSE;
122
90.7k
  return TRUE;
123
91.8k
}
124
125
static void rdp_write_capability_set_header(wStream* s, UINT16 length, UINT16 type)
126
0
{
127
0
  WINPR_ASSERT(s);
128
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
129
0
  Stream_Write_UINT16(s, type);   /* capabilitySetType */
130
0
  Stream_Write_UINT16(s, length); /* lengthCapability */
131
0
}
132
133
static size_t rdp_capability_set_start(wLog* log, wStream* s)
134
0
{
135
0
  size_t header = Stream_GetPosition(s);
136
0
  if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), CAPSET_HEADER_LENGTH))
137
0
    return SIZE_MAX;
138
0
  Stream_Zero(s, CAPSET_HEADER_LENGTH);
139
0
  return header;
140
0
}
141
142
static BOOL rdp_capability_set_finish(wStream* s, size_t header, UINT16 type)
143
0
{
144
0
  const size_t footer = Stream_GetPosition(s);
145
0
  if (header > footer)
146
0
    return FALSE;
147
0
  if (header > UINT16_MAX)
148
0
    return FALSE;
149
0
  const size_t length = footer - header;
150
0
  if ((Stream_Capacity(s) < header + 4ULL) || (length > UINT16_MAX))
151
0
    return FALSE;
152
0
  Stream_SetPosition(s, header);
153
0
  rdp_write_capability_set_header(s, (UINT16)length, type);
154
0
  Stream_SetPosition(s, footer);
155
0
  return TRUE;
156
0
}
157
158
static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSettings* src)
159
2.03k
{
160
2.03k
  WINPR_ASSERT(settings);
161
2.03k
  WINPR_ASSERT(src);
162
163
2.03k
  if (settings->ServerMode)
164
575
  {
165
575
    settings->OsMajorType = src->OsMajorType;
166
575
    settings->OsMinorType = src->OsMinorType;
167
575
  }
168
169
2.03k
  settings->CapsProtocolVersion = src->CapsProtocolVersion;
170
2.03k
  settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
171
2.03k
  settings->LongCredentialsSupported = src->LongCredentialsSupported;
172
2.03k
  settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
173
2.03k
  if (!src->FastPathOutput)
174
1.02k
    settings->FastPathOutput = FALSE;
175
176
2.03k
  if (!src->SaltedChecksum)
177
911
    settings->SaltedChecksum = FALSE;
178
179
2.03k
  if (!settings->ServerMode)
180
1.45k
  {
181
    /*
182
     * Note: refreshRectSupport and suppressOutputSupport are
183
     * server-only flags indicating to the client weather the
184
     * respective PDUs are supported. See MS-RDPBCGR 2.2.7.1.1
185
     */
186
1.45k
    if (!src->RefreshRect)
187
525
      settings->RefreshRect = FALSE;
188
189
1.45k
    if (!src->SuppressOutput)
190
1.32k
      settings->SuppressOutput = FALSE;
191
1.45k
  }
192
2.03k
  return TRUE;
193
2.03k
}
194
195
/*
196
 * Read general capability set.
197
 * msdn{cc240549}
198
 */
199
200
static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* settings)
201
2.10k
{
202
2.10k
  UINT16 extraFlags = 0;
203
2.10k
  BYTE refreshRectSupport = 0;
204
2.10k
  BYTE suppressOutputSupport = 0;
205
206
2.10k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
207
9
    return FALSE;
208
209
2.09k
  WINPR_ASSERT(settings);
210
2.09k
  Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
211
2.09k
  Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
212
213
2.09k
  Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
214
2.09k
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
215
1.79k
  {
216
1.79k
    WLog_Print(log, WLOG_ERROR,
217
1.79k
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
218
1.79k
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
219
1.79k
               settings->CapsProtocolVersion, TS_CAPS_PROTOCOLVERSION);
220
1.79k
    if (settings->CapsProtocolVersion == 0x0000)
221
1.73k
    {
222
1.73k
      WLog_Print(log, WLOG_WARN,
223
1.73k
                 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
224
1.73k
                 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
225
1.73k
                 settings->CapsProtocolVersion);
226
1.73k
      settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
227
1.73k
    }
228
65
    else
229
65
      return FALSE;
230
1.79k
  }
231
2.03k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
232
2.03k
  Stream_Read_UINT16(
233
2.03k
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
234
2.03k
  Stream_Read_UINT16(s, extraFlags);             /* extraFlags (2 bytes) */
235
2.03k
  Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
236
2.03k
  Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
237
2.03k
  Stream_Read_UINT16(
238
2.03k
      s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
239
2.03k
  Stream_Read_UINT8(s, refreshRectSupport);      /* refreshRectSupport (1 byte) */
240
2.03k
  Stream_Read_UINT8(s, suppressOutputSupport);   /* suppressOutputSupport (1 byte) */
241
2.03k
  settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
242
2.03k
  settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE;
243
244
2.03k
  settings->AutoReconnectionPacketSupported =
245
2.03k
      (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
246
2.03k
  settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) ? TRUE : FALSE;
247
2.03k
  settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) ? TRUE : FALSE;
248
2.03k
  settings->RefreshRect = refreshRectSupport;
249
2.03k
  settings->SuppressOutput = suppressOutputSupport;
250
251
2.03k
  return TRUE;
252
2.09k
}
253
254
/*
255
 * Write general capability set.
256
 * msdn{cc240549}
257
 */
258
259
static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
260
0
{
261
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
262
0
    return FALSE;
263
264
0
  const size_t header = rdp_capability_set_start(log, s);
265
0
  UINT16 extraFlags = 0;
266
267
0
  WINPR_ASSERT(settings);
268
0
  if (settings->LongCredentialsSupported)
269
0
    extraFlags |= LONG_CREDENTIALS_SUPPORTED;
270
271
0
  if (settings->NoBitmapCompressionHeader)
272
0
    extraFlags |= NO_BITMAP_COMPRESSION_HDR;
273
274
0
  if (settings->AutoReconnectionPacketSupported)
275
0
    extraFlags |= AUTORECONNECT_SUPPORTED;
276
277
0
  if (settings->FastPathOutput)
278
0
    extraFlags |= FASTPATH_OUTPUT_SUPPORTED;
279
280
0
  if (settings->SaltedChecksum)
281
0
    extraFlags |= ENC_SALTED_CHECKSUM;
282
283
0
  if ((settings->OsMajorType > UINT16_MAX) || (settings->OsMinorType > UINT16_MAX))
284
0
  {
285
0
    WLog_Print(log, WLOG_ERROR,
286
0
               "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32
287
0
               " they need to be smaller %04" PRIx16,
288
0
               settings->OsMajorType, settings->OsMinorType, UINT16_MAX);
289
0
    return FALSE;
290
0
  }
291
0
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
292
0
  {
293
0
    WLog_Print(log, WLOG_ERROR,
294
0
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
295
0
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
296
0
               settings->CapsProtocolVersion, TS_CAPS_PROTOCOLVERSION);
297
0
    return FALSE;
298
0
  }
299
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMajorType); /* osMajorType (2 bytes) */
300
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMinorType); /* osMinorType (2 bytes) */
301
0
  Stream_Write_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
302
0
  Stream_Write_UINT16(s, 0);                             /* pad2OctetsA (2 bytes) */
303
0
  Stream_Write_UINT16(
304
0
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
305
0
  Stream_Write_UINT16(s, extraFlags);            /* extraFlags (2 bytes) */
306
0
  Stream_Write_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
307
0
  Stream_Write_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
308
0
  Stream_Write_UINT16(
309
0
      s, settings->CapsGeneralCompressionLevel);           /* generalCompressionLevel (2 bytes) */
310
0
  Stream_Write_UINT8(s, settings->RefreshRect ? 1 : 0);    /* refreshRectSupport (1 byte) */
311
0
  Stream_Write_UINT8(s, settings->SuppressOutput ? 1 : 0); /* suppressOutputSupport (1 byte) */
312
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_GENERAL);
313
0
}
314
315
#ifdef WITH_DEBUG_CAPABILITIES
316
static BOOL rdp_print_general_capability_set(wLog* log, wStream* s)
317
{
318
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
319
    return FALSE;
320
321
  WLog_Print(log, WLOG_TRACE,
322
             "GeneralCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
323
  const uint16_t osMinorType = Stream_Get_UINT16(s);     /* osMajorType (2 bytes) */
324
  const uint16_t osMajorType = Stream_Get_UINT16(s);     /* osMinorType (2 bytes) */
325
  const uint16_t protocolVersion = Stream_Get_UINT16(s); /* protocolVersion (2 bytes) */
326
  const uint16_t pad2OctetsA = Stream_Get_UINT16(s);     /* pad2OctetsA (2 bytes) */
327
  const uint16_t generalCompressionTypes =
328
      Stream_Get_UINT16(s);                         /* generalCompressionTypes (2 bytes) */
329
  const uint16_t extraFlags = Stream_Get_UINT16(s); /* extraFlags (2 bytes) */
330
  const uint16_t updateCapabilityFlag = Stream_Get_UINT16(s); /* updateCapabilityFlag (2 bytes) */
331
  const uint16_t remoteUnshareFlag = Stream_Get_UINT16(s);    /* remoteUnshareFlag (2 bytes) */
332
  const uint16_t generalCompressionLevel =
333
      Stream_Get_UINT16(s);                               /* generalCompressionLevel (2 bytes) */
334
  const uint8_t refreshRectSupport = Stream_Get_UINT8(s); /* refreshRectSupport (1 byte) */
335
  const uint8_t suppressOutputSupport = Stream_Get_UINT8(s); /* suppressOutputSupport (1 byte) */
336
  WLog_Print(log, WLOG_TRACE, "\tosMajorType: 0x%04" PRIX16 "", osMajorType);
337
  WLog_Print(log, WLOG_TRACE, "\tosMinorType: 0x%04" PRIX16 "", osMinorType);
338
  WLog_Print(log, WLOG_TRACE, "\tprotocolVersion: 0x%04" PRIX16 "", protocolVersion);
339
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
340
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionTypes: 0x%04" PRIX16 "",
341
             generalCompressionTypes);
342
  WLog_Print(log, WLOG_TRACE, "\textraFlags: 0x%04" PRIX16 "", extraFlags);
343
  WLog_Print(log, WLOG_TRACE, "\tupdateCapabilityFlag: 0x%04" PRIX16 "", updateCapabilityFlag);
344
  WLog_Print(log, WLOG_TRACE, "\tremoteUnshareFlag: 0x%04" PRIX16 "", remoteUnshareFlag);
345
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionLevel: 0x%04" PRIX16 "",
346
             generalCompressionLevel);
347
  WLog_Print(log, WLOG_TRACE, "\trefreshRectSupport: 0x%02" PRIX8 "", refreshRectSupport);
348
  WLog_Print(log, WLOG_TRACE, "\tsuppressOutputSupport: 0x%02" PRIX8 "", suppressOutputSupport);
349
  return TRUE;
350
}
351
#endif
352
static BOOL rdp_apply_bitmap_capability_set(rdpSettings* settings, const rdpSettings* src)
353
3.09k
{
354
3.09k
  WINPR_ASSERT(settings);
355
3.09k
  WINPR_ASSERT(src);
356
357
3.09k
  if (!settings->ServerMode)
358
1.47k
  {
359
1.47k
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
360
1.47k
                                     freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
361
0
      return FALSE;
362
1.47k
  }
363
364
3.09k
  if (!src->DesktopResize)
365
2.65k
    settings->DesktopResize = FALSE;
366
367
3.09k
  if (!settings->ServerMode && settings->DesktopResize)
368
101
  {
369
    /* The server may request a different desktop size during Deactivation-Reactivation sequence
370
     */
371
101
    settings->DesktopWidth = src->DesktopWidth;
372
101
    settings->DesktopHeight = src->DesktopHeight;
373
101
  }
374
375
3.09k
  if (settings->DrawAllowSkipAlpha)
376
414
    settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
377
378
3.09k
  if (settings->DrawAllowDynamicColorFidelity)
379
452
    settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
380
381
3.09k
  if (settings->DrawAllowColorSubsampling)
382
0
    settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
383
384
3.09k
  return TRUE;
385
3.09k
}
386
387
/*
388
 * Read bitmap capability set.
389
 * msdn{cc240554}
390
 */
391
392
static BOOL rdp_read_bitmap_capability_set(wLog* log, wStream* s, rdpSettings* settings)
393
3.09k
{
394
3.09k
  BYTE drawingFlags = 0;
395
3.09k
  UINT16 desktopWidth = 0;
396
3.09k
  UINT16 desktopHeight = 0;
397
3.09k
  UINT16 desktopResizeFlag = 0;
398
3.09k
  UINT16 preferredBitsPerPixel = 0;
399
400
3.09k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
401
7
    return FALSE;
402
403
3.09k
  Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
404
3.09k
  Stream_Seek_UINT16(s);                        /* receive1BitPerPixel (2 bytes) */
405
3.09k
  Stream_Seek_UINT16(s);                        /* receive4BitsPerPixel (2 bytes) */
406
3.09k
  Stream_Seek_UINT16(s);                        /* receive8BitsPerPixel (2 bytes) */
407
3.09k
  Stream_Read_UINT16(s, desktopWidth);          /* desktopWidth (2 bytes) */
408
3.09k
  Stream_Read_UINT16(s, desktopHeight);         /* desktopHeight (2 bytes) */
409
3.09k
  Stream_Seek_UINT16(s);                        /* pad2Octets (2 bytes) */
410
3.09k
  Stream_Read_UINT16(s, desktopResizeFlag);     /* desktopResizeFlag (2 bytes) */
411
3.09k
  Stream_Seek_UINT16(s);                        /* bitmapCompressionFlag (2 bytes) */
412
3.09k
  Stream_Seek_UINT8(s);                         /* highColorFlags (1 byte) */
413
3.09k
  Stream_Read_UINT8(s, drawingFlags);           /* drawingFlags (1 byte) */
414
3.09k
  Stream_Seek_UINT16(s);                        /* multipleRectangleSupport (2 bytes) */
415
3.09k
  Stream_Seek_UINT16(s);                        /* pad2OctetsB (2 bytes) */
416
417
3.09k
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
418
0
    return FALSE;
419
3.09k
  settings->DesktopResize = desktopResizeFlag;
420
3.09k
  settings->DesktopWidth = desktopWidth;
421
3.09k
  settings->DesktopHeight = desktopHeight;
422
3.09k
  settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) ? TRUE : FALSE;
423
3.09k
  settings->DrawAllowDynamicColorFidelity =
424
3.09k
      (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) ? TRUE : FALSE;
425
3.09k
  settings->DrawAllowColorSubsampling =
426
3.09k
      (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) ? TRUE : FALSE;
427
428
3.09k
  return TRUE;
429
3.09k
}
430
431
/*
432
 * Write bitmap capability set.
433
 * msdn{cc240554}
434
 */
435
436
static BOOL rdp_write_bitmap_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
437
0
{
438
0
  BYTE drawingFlags = 0;
439
0
  UINT16 preferredBitsPerPixel = 0;
440
441
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
442
0
    return FALSE;
443
444
0
  const size_t header = rdp_capability_set_start(log, s);
445
446
0
  WINPR_ASSERT(settings);
447
0
  if (settings->DrawAllowSkipAlpha)
448
0
    drawingFlags |= DRAW_ALLOW_SKIP_ALPHA;
449
450
0
  if (settings->DrawAllowDynamicColorFidelity)
451
0
    drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY;
452
453
0
  if (settings->DrawAllowColorSubsampling)
454
0
    drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; /* currently unimplemented */
455
456
  /* While bitmap_decode.c now implements YCoCg, in turning it
457
   * on we have found Microsoft is inconsistent on whether to invert R & B.
458
   * And it's not only from one server to another; on Win7/2008R2, it appears
459
   * to send the main content with a different inversion than the Windows
460
   * button!  So... don't advertise that we support YCoCg and the server
461
   * will not send it.  YCoCg is still needed for EGFX, but it at least
462
   * appears consistent in its use.
463
   */
464
465
0
  if ((freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) > UINT16_MAX) ||
466
0
      (settings->DesktopWidth > UINT16_MAX) || (settings->DesktopHeight > UINT16_MAX))
467
0
    return FALSE;
468
469
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
470
0
    preferredBitsPerPixel = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
471
0
  else
472
0
    preferredBitsPerPixel = 8;
473
474
0
  Stream_Write_UINT16(s, preferredBitsPerPixel);           /* preferredBitsPerPixel (2 bytes) */
475
0
  Stream_Write_UINT16(s, 1);                               /* receive1BitPerPixel (2 bytes) */
476
0
  Stream_Write_UINT16(s, 1);                               /* receive4BitsPerPixel (2 bytes) */
477
0
  Stream_Write_UINT16(s, 1);                               /* receive8BitsPerPixel (2 bytes) */
478
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopWidth);  /* desktopWidth (2 bytes) */
479
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopHeight); /* desktopHeight (2 bytes) */
480
0
  Stream_Write_UINT16(s, 0);                               /* pad2Octets (2 bytes) */
481
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopResize); /* desktopResizeFlag (2 bytes) */
482
0
  Stream_Write_UINT16(s, 1);                               /* bitmapCompressionFlag (2 bytes) */
483
0
  Stream_Write_UINT8(s, 0);                                /* highColorFlags (1 byte) */
484
0
  Stream_Write_UINT8(s, drawingFlags);                     /* drawingFlags (1 byte) */
485
0
  Stream_Write_UINT16(s, 1); /* multipleRectangleSupport (2 bytes) */
486
0
  Stream_Write_UINT16(s, 0); /* pad2OctetsB (2 bytes) */
487
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP);
488
0
}
489
490
#ifdef WITH_DEBUG_CAPABILITIES
491
static BOOL rdp_print_bitmap_capability_set(wLog* log, wStream* s)
492
{
493
  UINT16 preferredBitsPerPixel = 0;
494
  UINT16 receive1BitPerPixel = 0;
495
  UINT16 receive4BitsPerPixel = 0;
496
  UINT16 receive8BitsPerPixel = 0;
497
  UINT16 desktopWidth = 0;
498
  UINT16 desktopHeight = 0;
499
  UINT16 pad2Octets = 0;
500
  UINT16 desktopResizeFlag = 0;
501
  UINT16 bitmapCompressionFlag = 0;
502
  BYTE highColorFlags = 0;
503
  BYTE drawingFlags = 0;
504
  UINT16 multipleRectangleSupport = 0;
505
  UINT16 pad2OctetsB = 0;
506
  WLog_Print(log, WLOG_TRACE,
507
             "BitmapCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
508
509
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
510
    return FALSE;
511
512
  Stream_Read_UINT16(s, preferredBitsPerPixel);    /* preferredBitsPerPixel (2 bytes) */
513
  Stream_Read_UINT16(s, receive1BitPerPixel);      /* receive1BitPerPixel (2 bytes) */
514
  Stream_Read_UINT16(s, receive4BitsPerPixel);     /* receive4BitsPerPixel (2 bytes) */
515
  Stream_Read_UINT16(s, receive8BitsPerPixel);     /* receive8BitsPerPixel (2 bytes) */
516
  Stream_Read_UINT16(s, desktopWidth);             /* desktopWidth (2 bytes) */
517
  Stream_Read_UINT16(s, desktopHeight);            /* desktopHeight (2 bytes) */
518
  Stream_Read_UINT16(s, pad2Octets);               /* pad2Octets (2 bytes) */
519
  Stream_Read_UINT16(s, desktopResizeFlag);        /* desktopResizeFlag (2 bytes) */
520
  Stream_Read_UINT16(s, bitmapCompressionFlag);    /* bitmapCompressionFlag (2 bytes) */
521
  Stream_Read_UINT8(s, highColorFlags);            /* highColorFlags (1 byte) */
522
  Stream_Read_UINT8(s, drawingFlags);              /* drawingFlags (1 byte) */
523
  Stream_Read_UINT16(s, multipleRectangleSupport); /* multipleRectangleSupport (2 bytes) */
524
  Stream_Read_UINT16(s, pad2OctetsB);              /* pad2OctetsB (2 bytes) */
525
  WLog_Print(log, WLOG_TRACE, "\tpreferredBitsPerPixel: 0x%04" PRIX16 "", preferredBitsPerPixel);
526
  WLog_Print(log, WLOG_TRACE, "\treceive1BitPerPixel: 0x%04" PRIX16 "", receive1BitPerPixel);
527
  WLog_Print(log, WLOG_TRACE, "\treceive4BitsPerPixel: 0x%04" PRIX16 "", receive4BitsPerPixel);
528
  WLog_Print(log, WLOG_TRACE, "\treceive8BitsPerPixel: 0x%04" PRIX16 "", receive8BitsPerPixel);
529
  WLog_Print(log, WLOG_TRACE, "\tdesktopWidth: 0x%04" PRIX16 "", desktopWidth);
530
  WLog_Print(log, WLOG_TRACE, "\tdesktopHeight: 0x%04" PRIX16 "", desktopHeight);
531
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
532
  WLog_Print(log, WLOG_TRACE, "\tdesktopResizeFlag: 0x%04" PRIX16 "", desktopResizeFlag);
533
  WLog_Print(log, WLOG_TRACE, "\tbitmapCompressionFlag: 0x%04" PRIX16 "", bitmapCompressionFlag);
534
  WLog_Print(log, WLOG_TRACE, "\thighColorFlags: 0x%02" PRIX8 "", highColorFlags);
535
  WLog_Print(log, WLOG_TRACE, "\tdrawingFlags: 0x%02" PRIX8 "", drawingFlags);
536
  WLog_Print(log, WLOG_TRACE, "\tmultipleRectangleSupport: 0x%04" PRIX16 "",
537
             multipleRectangleSupport);
538
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsB: 0x%04" PRIX16 "", pad2OctetsB);
539
  return TRUE;
540
}
541
#endif
542
static BOOL rdp_apply_order_capability_set(rdpSettings* settings, const rdpSettings* src)
543
2.67k
{
544
2.67k
  WINPR_ASSERT(settings);
545
2.67k
  WINPR_ASSERT(src);
546
547
2.67k
  BOOL BitmapCacheV3Enabled = FALSE;
548
2.67k
  BOOL FrameMarkerCommandEnabled = FALSE;
549
550
88.3k
  for (size_t i = 0; i < 32; i++)
551
85.6k
  {
552
85.6k
    if (!src->OrderSupport[i])
553
51.7k
      settings->OrderSupport[i] = FALSE;
554
85.6k
  }
555
556
2.67k
  if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
557
376
  {
558
376
    if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
559
237
      BitmapCacheV3Enabled = TRUE;
560
561
376
    if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
562
78
      FrameMarkerCommandEnabled = TRUE;
563
376
  }
564
565
2.67k
  if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
566
0
  {
567
0
    settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
568
0
    settings->BitmapCacheVersion = src->BitmapCacheVersion;
569
0
  }
570
2.67k
  else
571
2.67k
    settings->BitmapCacheV3Enabled = FALSE;
572
573
2.67k
  if (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled)
574
78
    settings->FrameMarkerCommandEnabled = TRUE;
575
2.59k
  else
576
2.59k
    settings->FrameMarkerCommandEnabled = FALSE;
577
578
2.67k
  return TRUE;
579
2.67k
}
580
581
/*
582
 * Read order capability set.
583
 * msdn{cc240556}
584
 */
585
586
static BOOL rdp_read_order_capability_set(wLog* log, wStream* s, rdpSettings* settings)
587
2.68k
{
588
2.68k
  char terminalDescriptor[17] = { 0 };
589
2.68k
  BYTE orderSupport[32] = { 0 };
590
2.68k
  BOOL BitmapCacheV3Enabled = FALSE;
591
2.68k
  BOOL FrameMarkerCommandEnabled = FALSE;
592
593
2.68k
  WINPR_ASSERT(settings);
594
2.68k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
595
8
    return FALSE;
596
597
2.67k
  Stream_Read(s, terminalDescriptor, 16);               /* terminalDescriptor (16 bytes) */
598
2.67k
  Stream_Seek_UINT32(s);                                /* pad4OctetsA (4 bytes) */
599
2.67k
  Stream_Seek_UINT16(s);                                /* desktopSaveXGranularity (2 bytes) */
600
2.67k
  Stream_Seek_UINT16(s);                                /* desktopSaveYGranularity (2 bytes) */
601
2.67k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
602
2.67k
  Stream_Seek_UINT16(s);                                /* maximumOrderLevel (2 bytes) */
603
2.67k
  Stream_Seek_UINT16(s);                                /* numberFonts (2 bytes) */
604
2.67k
  Stream_Read_UINT16(s, settings->OrderSupportFlags);   /* orderFlags (2 bytes) */
605
2.67k
  Stream_Read(s, orderSupport, 32);                     /* orderSupport (32 bytes) */
606
2.67k
  Stream_Seek_UINT16(s);                                /* textFlags (2 bytes) */
607
2.67k
  Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
608
2.67k
  Stream_Seek_UINT32(s);                                /* pad4OctetsB (4 bytes) */
609
2.67k
  Stream_Seek_UINT32(s);                                /* desktopSaveSize (4 bytes) */
610
2.67k
  Stream_Seek_UINT16(s);                                /* pad2OctetsC (2 bytes) */
611
2.67k
  Stream_Seek_UINT16(s);                                /* pad2OctetsD (2 bytes) */
612
2.67k
  Stream_Read_UINT16(s, settings->TextANSICodePage);    /* textANSICodePage (2 bytes) */
613
2.67k
  Stream_Seek_UINT16(s);                                /* pad2OctetsE (2 bytes) */
614
615
2.67k
  if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
616
0
    return FALSE;
617
618
88.3k
  for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
619
85.6k
    settings->OrderSupport[i] = orderSupport[i];
620
621
2.67k
  if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
622
376
  {
623
376
    BitmapCacheV3Enabled =
624
376
        (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) ? TRUE : FALSE;
625
376
    FrameMarkerCommandEnabled =
626
376
        (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) ? TRUE : FALSE;
627
376
  }
628
629
2.67k
  settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
630
2.67k
  if (BitmapCacheV3Enabled)
631
237
    settings->BitmapCacheVersion = 3;
632
633
2.67k
  settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
634
635
2.67k
  return TRUE;
636
2.67k
}
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
43
{
822
43
  WINPR_ASSERT(settings);
823
43
  WINPR_ASSERT(src);
824
43
  return TRUE;
825
43
}
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
56
{
834
56
  WINPR_UNUSED(settings);
835
56
  WINPR_ASSERT(settings);
836
837
56
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
838
13
    return FALSE;
839
840
43
  Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
841
43
  Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
842
43
  Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
843
43
  Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
844
43
  Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
845
43
  Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
846
43
  Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
847
43
  Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
848
43
  Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
849
43
  Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
850
43
  Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
851
43
  Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
852
43
  return TRUE;
853
56
}
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
88
{
946
88
  WINPR_ASSERT(settings);
947
88
  WINPR_ASSERT(src);
948
949
88
  return TRUE;
950
88
}
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
95
{
959
95
  WINPR_UNUSED(settings);
960
95
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
961
7
    return FALSE;
962
963
88
  Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
964
88
  Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
965
88
  Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
966
88
  Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
967
88
  return TRUE;
968
95
}
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
204
{
1017
204
  WINPR_ASSERT(settings);
1018
204
  WINPR_ASSERT(src);
1019
1020
204
  return TRUE;
1021
204
}
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
209
{
1030
209
  WINPR_UNUSED(settings);
1031
209
  WINPR_ASSERT(settings);
1032
209
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1033
5
    return FALSE;
1034
1035
204
  Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1036
204
  Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1037
204
  Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1038
204
  Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1039
204
  return TRUE;
1040
209
}
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
24.5k
{
1090
24.5k
  WINPR_ASSERT(settings);
1091
24.5k
  WINPR_ASSERT(src);
1092
1093
24.5k
  const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1094
24.5k
  const UINT32 colorPointerCacheSize =
1095
24.5k
      freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1096
24.5k
  const UINT32 dstPointerCacheSize =
1097
24.5k
      freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1098
24.5k
  const UINT32 dstColorPointerCacheSize =
1099
24.5k
      freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1100
1101
  /* We want the minimum of our setting and the remote announced value. */
1102
24.5k
  const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1103
24.5k
  const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1104
1105
24.5k
  if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1106
24.5k
      !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1107
24.5k
                                   actualColorPointerCacheSize))
1108
0
    return FALSE;
1109
1110
24.5k
  return TRUE;
1111
24.5k
}
1112
1113
/*
1114
 * Read pointer capability set.
1115
 * msdn{cc240562}
1116
 */
1117
1118
static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1119
24.6k
{
1120
24.6k
  UINT16 colorPointerFlag = 0;
1121
24.6k
  UINT16 colorPointerCacheSize = 0;
1122
24.6k
  UINT16 pointerCacheSize = 0;
1123
1124
24.6k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1125
20
    return FALSE;
1126
1127
24.5k
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1128
24.5k
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1129
1130
24.5k
  if (colorPointerFlag == 0)
1131
705
  {
1132
705
    WLog_Print(log, WLOG_WARN,
1133
705
               "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1134
705
               "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1135
705
               ". Value is ignored and always assumed to be TRUE");
1136
705
  }
1137
1138
  /* pointerCacheSize is optional */
1139
24.5k
  if (Stream_GetRemainingLength(s) >= 2)
1140
1.08k
    Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1141
1142
24.5k
  WINPR_ASSERT(settings);
1143
24.5k
  settings->PointerCacheSize = pointerCacheSize;
1144
24.5k
  settings->ColorPointerCacheSize = colorPointerCacheSize;
1145
1146
24.5k
  return TRUE;
1147
24.5k
}
1148
1149
/*
1150
 * Write pointer capability set.
1151
 * msdn{cc240562}
1152
 */
1153
1154
static BOOL rdp_write_pointer_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1155
0
{
1156
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1157
0
    return FALSE;
1158
1159
0
  const size_t header = rdp_capability_set_start(log, s);
1160
0
  if (settings->PointerCacheSize > UINT16_MAX)
1161
0
    return FALSE;
1162
0
  if (settings->ColorPointerCacheSize > UINT16_MAX)
1163
0
    return FALSE;
1164
1165
0
  WINPR_ASSERT(settings);
1166
0
  const UINT32 colorPointerFlag =
1167
0
      1; /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1168
          * colorPointerFlag is ignored and always assumed to be TRUE */
1169
0
  Stream_Write_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1170
0
  Stream_Write_UINT16(
1171
0
      s, (UINT16)settings->ColorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1172
0
  Stream_Write_UINT16(s, (UINT16)settings->PointerCacheSize); /* pointerCacheSize (2 bytes) */
1173
1174
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_POINTER);
1175
0
}
1176
1177
#ifdef WITH_DEBUG_CAPABILITIES
1178
static BOOL rdp_print_pointer_capability_set(wLog* log, wStream* s)
1179
{
1180
  UINT16 colorPointerFlag = 0;
1181
  UINT16 colorPointerCacheSize = 0;
1182
  UINT16 pointerCacheSize = 0;
1183
1184
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
1185
    return FALSE;
1186
1187
  WLog_Print(log, WLOG_TRACE,
1188
             "PointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1189
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1190
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1191
  Stream_Read_UINT16(s, pointerCacheSize);      /* pointerCacheSize (2 bytes) */
1192
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerFlag: 0x%04" PRIX16 "", colorPointerFlag);
1193
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerCacheSize: 0x%04" PRIX16 "", colorPointerCacheSize);
1194
  WLog_Print(log, WLOG_TRACE, "\tpointerCacheSize: 0x%04" PRIX16 "", pointerCacheSize);
1195
  return TRUE;
1196
}
1197
#endif
1198
1199
static BOOL rdp_apply_share_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1200
                                           WINPR_ATTR_UNUSED const rdpSettings* src)
1201
1.78k
{
1202
1.78k
  WINPR_ASSERT(settings);
1203
1.78k
  WINPR_ASSERT(src);
1204
1205
1.78k
  return TRUE;
1206
1.78k
}
1207
1208
/*
1209
 * Read share capability set.
1210
 * msdn{cc240570}
1211
 */
1212
1213
static BOOL rdp_read_share_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1214
1.78k
{
1215
1.78k
  WINPR_UNUSED(settings);
1216
1.78k
  WINPR_ASSERT(settings);
1217
1218
1.78k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1219
4
    return FALSE;
1220
1221
1.78k
  Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1222
1.78k
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1223
1.78k
  return TRUE;
1224
1.78k
}
1225
1226
/*
1227
 * Write share capability set.
1228
 * msdn{cc240570}
1229
 */
1230
1231
static BOOL rdp_write_share_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1232
0
{
1233
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1234
0
    return FALSE;
1235
1236
0
  const size_t header = rdp_capability_set_start(log, s);
1237
1238
0
  WINPR_ASSERT(settings);
1239
0
  const UINT16 nodeId = (settings->ServerMode) ? 0x03EA : 0;
1240
0
  Stream_Write_UINT16(s, nodeId); /* nodeId (2 bytes) */
1241
0
  Stream_Write_UINT16(s, 0);      /* pad2Octets (2 bytes) */
1242
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SHARE);
1243
0
}
1244
1245
#ifdef WITH_DEBUG_CAPABILITIES
1246
static BOOL rdp_print_share_capability_set(wLog* log, wStream* s)
1247
{
1248
  UINT16 nodeId = 0;
1249
  UINT16 pad2Octets = 0;
1250
  WLog_Print(log, WLOG_TRACE,
1251
             "ShareCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1252
1253
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1254
    return FALSE;
1255
1256
  Stream_Read_UINT16(s, nodeId);     /* nodeId (2 bytes) */
1257
  Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1258
  WLog_Print(log, WLOG_TRACE, "\tnodeId: 0x%04" PRIX16 "", nodeId);
1259
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1260
  return TRUE;
1261
}
1262
#endif
1263
1264
static BOOL rdp_apply_color_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1265
                                                 WINPR_ATTR_UNUSED const rdpSettings* src)
1266
2.26k
{
1267
2.26k
  WINPR_ASSERT(settings);
1268
2.26k
  WINPR_ASSERT(src);
1269
2.26k
  return TRUE;
1270
2.26k
}
1271
1272
/*
1273
 * Read color cache capability set.
1274
 * msdn{cc241564}
1275
 */
1276
1277
static BOOL rdp_read_color_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1278
2.27k
{
1279
2.27k
  WINPR_UNUSED(settings);
1280
2.27k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1281
11
    return FALSE;
1282
1283
2.26k
  Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1284
2.26k
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1285
2.26k
  return TRUE;
1286
2.27k
}
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
360
{
1326
360
  WINPR_ASSERT(settings);
1327
360
  WINPR_ASSERT(src);
1328
1329
360
  settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1330
1331
360
  return TRUE;
1332
360
}
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
364
{
1341
364
  UINT16 soundFlags = 0;
1342
1343
364
  WINPR_ASSERT(settings);
1344
364
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1345
4
    return FALSE;
1346
1347
360
  Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1348
360
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1349
360
  settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) ? TRUE : FALSE;
1350
360
  return TRUE;
1351
364
}
1352
1353
/*
1354
 * Write sound capability set.
1355
 * msdn{cc240552}
1356
 */
1357
1358
static BOOL rdp_write_sound_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1359
0
{
1360
0
  WINPR_ASSERT(settings);
1361
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1362
0
    return FALSE;
1363
1364
0
  const size_t header = rdp_capability_set_start(log, s);
1365
0
  const UINT16 soundFlags = (settings->SoundBeepsEnabled) ? SOUND_BEEPS_FLAG : 0;
1366
0
  Stream_Write_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1367
0
  Stream_Write_UINT16(s, 0);          /* pad2OctetsA (2 bytes) */
1368
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SOUND);
1369
0
}
1370
1371
#ifdef WITH_DEBUG_CAPABILITIES
1372
static BOOL rdp_print_sound_capability_set(wLog* log, wStream* s)
1373
{
1374
  UINT16 soundFlags = 0;
1375
  UINT16 pad2OctetsA = 0;
1376
  WLog_Print(log, WLOG_TRACE,
1377
             "SoundCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1378
1379
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1380
    return FALSE;
1381
1382
  Stream_Read_UINT16(s, soundFlags);  /* soundFlags (2 bytes) */
1383
  Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1384
  WLog_Print(log, WLOG_TRACE, "\tsoundFlags: 0x%04" PRIX16 "", soundFlags);
1385
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1386
  return TRUE;
1387
}
1388
#endif
1389
1390
static BOOL rdp_apply_input_capability_set(rdpSettings* settings, const rdpSettings* src)
1391
25.5k
{
1392
25.5k
  WINPR_ASSERT(settings);
1393
25.5k
  WINPR_ASSERT(src);
1394
1395
25.5k
  if (settings->ServerMode)
1396
11.8k
  {
1397
11.8k
    settings->KeyboardLayout = src->KeyboardLayout;
1398
11.8k
    settings->KeyboardType = src->KeyboardType;
1399
11.8k
    settings->KeyboardSubType = src->KeyboardSubType;
1400
11.8k
    settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1401
11.8k
  }
1402
1403
25.5k
  if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1404
0
    return FALSE;
1405
1406
25.5k
  if (!settings->ServerMode)
1407
13.7k
  {
1408
13.7k
    settings->FastPathInput = src->FastPathInput;
1409
1410
    /* Note: These settings have split functionality:
1411
     * 1. If disabled in client pre_connect, it can disable announcing the feature
1412
     * 2. If enabled in client pre_connect, override it with the server announced support flag.
1413
     */
1414
13.7k
    if (settings->HasHorizontalWheel)
1415
482
      settings->HasHorizontalWheel = src->HasHorizontalWheel;
1416
13.7k
    const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1417
13.7k
    if (UnicodeInput)
1418
13.7k
    {
1419
13.7k
      const BOOL srcVal = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1420
13.7k
      if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1421
0
        return FALSE;
1422
13.7k
    }
1423
13.7k
    if (settings->HasExtendedMouseEvent)
1424
473
      settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1425
13.7k
    if (settings->HasRelativeMouseEvent)
1426
333
      settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1427
13.7k
    if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1428
13.7k
      settings->HasQoeEvent = freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent);
1429
13.7k
  }
1430
25.5k
  return TRUE;
1431
25.5k
}
1432
1433
/*
1434
 * Read input capability set.
1435
 * msdn{cc240563}
1436
 */
1437
1438
static BOOL rdp_read_input_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1439
25.5k
{
1440
25.5k
  UINT16 inputFlags = 0;
1441
1442
25.5k
  WINPR_ASSERT(settings);
1443
25.5k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1444
7
    return FALSE;
1445
1446
25.5k
  Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1447
25.5k
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1448
1449
25.5k
  Stream_Read_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1450
25.5k
  Stream_Read_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1451
25.5k
  Stream_Read_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1452
25.5k
  Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1453
1454
25.5k
  {
1455
25.5k
    WCHAR wstr[32] = { 0 };
1456
25.5k
    char str[65] = { 0 };
1457
1458
    /* Older windows versions report invalid UTF16
1459
     * [MS-RDPBCGR] <29> Section 2.2.7.1.6: Microsoft RDP 4.0, 5.0, 5.1, and 5.2 servers do not
1460
     * explicitly fill the imeFileName field with zeros.
1461
     */
1462
25.5k
    if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1463
0
      return FALSE;
1464
1465
25.5k
    if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1466
6.88k
      memset(str, 0, sizeof(str));
1467
1468
25.5k
    if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1469
0
      return FALSE;
1470
25.5k
  }
1471
1472
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1473
25.5k
                                 inputFlags &
1474
25.5k
                                     (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1475
0
    return FALSE;
1476
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1477
25.5k
                                 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) ? TRUE : FALSE))
1478
0
    return FALSE;
1479
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1480
25.5k
                                 (inputFlags & INPUT_FLAG_UNICODE) ? TRUE : FALSE))
1481
0
    return FALSE;
1482
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1483
25.5k
                                 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) ? TRUE : FALSE))
1484
0
    return FALSE;
1485
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1486
25.5k
                                 (inputFlags & INPUT_FLAG_MOUSEX) ? TRUE : FALSE))
1487
0
    return FALSE;
1488
25.5k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1489
25.5k
                                 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) ? TRUE : FALSE))
1490
0
    return FALSE;
1491
1492
25.5k
  return TRUE;
1493
25.5k
}
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
665
{
1575
665
  WINPR_ASSERT(settings);
1576
665
  WINPR_ASSERT(src);
1577
665
  return TRUE;
1578
665
}
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
665
{
1588
665
  WINPR_UNUSED(settings);
1589
665
  if (Stream_GetRemainingLength(s) >= 2)
1590
308
    Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1591
1592
665
  if (Stream_GetRemainingLength(s) >= 2)
1593
306
    Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1594
1595
665
  return TRUE;
1596
665
}
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
517
{
1637
517
  WINPR_ASSERT(settings);
1638
517
  WINPR_ASSERT(src);
1639
1640
  // TODO: Minimum of what?
1641
517
  settings->BrushSupportLevel = src->BrushSupportLevel;
1642
517
  return TRUE;
1643
517
}
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
520
{
1652
520
  WINPR_UNUSED(settings);
1653
520
  WINPR_ASSERT(settings);
1654
1655
520
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1656
3
    return FALSE;
1657
517
  Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1658
517
  return TRUE;
1659
520
}
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
770
{
1699
770
  WINPR_ASSERT(cache_definition);
1700
770
  Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1701
770
  Stream_Read_UINT16(s,
1702
770
                     cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1703
770
}
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
70
{
1719
70
  WINPR_ASSERT(settings);
1720
70
  WINPR_ASSERT(src);
1721
1722
70
  WINPR_ASSERT(src->GlyphCache);
1723
70
  WINPR_ASSERT(settings->GlyphCache);
1724
770
  for (size_t x = 0; x < 10; x++)
1725
700
    settings->GlyphCache[x] = src->GlyphCache[x];
1726
1727
70
  WINPR_ASSERT(src->FragCache);
1728
70
  WINPR_ASSERT(settings->FragCache);
1729
70
  settings->FragCache[0] = src->FragCache[0];
1730
70
  settings->GlyphSupportLevel = src->GlyphSupportLevel;
1731
1732
70
  return TRUE;
1733
70
}
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
76
{
1742
76
  WINPR_ASSERT(settings);
1743
76
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1744
6
    return FALSE;
1745
1746
  /* glyphCache (40 bytes) */
1747
770
  for (size_t x = 0; x < 10; x++)
1748
700
    rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1749
70
  rdp_read_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1750
70
  Stream_Read_UINT16(s, settings->GlyphSupportLevel);           /* glyphSupportLevel (2 bytes) */
1751
70
  Stream_Seek_UINT16(s);                                        /* pad2Octets (2 bytes) */
1752
70
  return TRUE;
1753
76
}
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
138
{
1836
138
  WINPR_ASSERT(settings);
1837
138
  WINPR_ASSERT(src);
1838
1839
138
  settings->OffscreenCacheSize = src->OffscreenCacheSize;
1840
138
  settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1841
138
  settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1842
1843
138
  return TRUE;
1844
138
}
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
141
{
1854
141
  UINT32 offscreenSupportLevel = 0;
1855
1856
141
  WINPR_ASSERT(settings);
1857
141
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1858
3
    return FALSE;
1859
1860
138
  Stream_Read_UINT32(s, offscreenSupportLevel);           /* offscreenSupportLevel (4 bytes) */
1861
138
  Stream_Read_UINT16(s, settings->OffscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1862
138
  Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1863
1864
138
  settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1865
1866
138
  return TRUE;
1867
141
}
1868
1869
/*
1870
 * Write offscreen bitmap cache capability set.
1871
 * msdn{cc240550}
1872
 */
1873
1874
static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1875
                                                            const rdpSettings* settings)
1876
0
{
1877
0
  UINT32 offscreenSupportLevel = 0x00;
1878
1879
0
  WINPR_ASSERT(settings);
1880
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1881
0
    return FALSE;
1882
1883
0
  const size_t header = rdp_capability_set_start(log, s);
1884
0
  if (settings->OffscreenSupportLevel)
1885
0
  {
1886
0
    offscreenSupportLevel = 0x01;
1887
0
    Stream_Write_UINT32(s, offscreenSupportLevel);        /* offscreenSupportLevel (4 bytes) */
1888
0
    Stream_Write_UINT16(
1889
0
        s, WINPR_ASSERTING_INT_CAST(
1890
0
               uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1891
0
    Stream_Write_UINT16(
1892
0
        s,
1893
0
        WINPR_ASSERTING_INT_CAST(
1894
0
            uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1895
0
  }
1896
0
  else
1897
0
    Stream_Zero(s, 8);
1898
1899
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1900
0
}
1901
1902
#ifdef WITH_DEBUG_CAPABILITIES
1903
static BOOL rdp_print_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s)
1904
{
1905
  UINT32 offscreenSupportLevel = 0;
1906
  UINT16 offscreenCacheSize = 0;
1907
  UINT16 offscreenCacheEntries = 0;
1908
  WLog_Print(log, WLOG_TRACE, "OffscreenBitmapCacheCapabilitySet (length %" PRIuz "):",
1909
             Stream_GetRemainingLength(s));
1910
1911
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1912
    return FALSE;
1913
1914
  Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1915
  Stream_Read_UINT16(s, offscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1916
  Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1917
  WLog_Print(log, WLOG_TRACE, "\toffscreenSupportLevel: 0x%08" PRIX32 "", offscreenSupportLevel);
1918
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheSize: 0x%04" PRIX16 "", offscreenCacheSize);
1919
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheEntries: 0x%04" PRIX16 "", offscreenCacheEntries);
1920
  return TRUE;
1921
}
1922
#endif
1923
1924
static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1925
                                                               const rdpSettings* src)
1926
1.64k
{
1927
1.64k
  const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1928
1.64k
                    freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1929
1.64k
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1930
1.64k
}
1931
1932
/*
1933
 * Read bitmap cache host support capability set.
1934
 * msdn{cc240557}
1935
 */
1936
1937
static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1938
                                                              rdpSettings* settings)
1939
1.64k
{
1940
1.64k
  BYTE cacheVersion = 0;
1941
1942
1.64k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1943
6
    return FALSE;
1944
1945
1.64k
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1946
1.64k
  Stream_Seek_UINT8(s);               /* pad1 (1 byte) */
1947
1.64k
  Stream_Seek_UINT16(s);              /* pad2 (2 bytes) */
1948
1949
1.64k
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1950
1.64k
                                   cacheVersion & BITMAP_CACHE_V2);
1951
1.64k
}
1952
1953
/*
1954
 * Write bitmap cache host support capability set.
1955
 * msdn{cc240557}
1956
 */
1957
1958
static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1959
                                                               const rdpSettings* settings)
1960
0
{
1961
0
  UINT8 cacheVersion = 0;
1962
1963
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
1964
0
    cacheVersion |= BITMAP_CACHE_V2;
1965
1966
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1967
0
    return FALSE;
1968
1969
0
  const size_t header = rdp_capability_set_start(log, s);
1970
0
  Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1971
0
  Stream_Write_UINT8(s, 0);            /* pad1 (1 byte) */
1972
0
  Stream_Write_UINT16(s, 0);           /* pad2 (2 bytes) */
1973
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
1974
0
}
1975
1976
#ifdef WITH_DEBUG_CAPABILITIES
1977
static BOOL rdp_print_bitmap_cache_host_support_capability_set(wLog* log, wStream* s)
1978
{
1979
  BYTE cacheVersion = 0;
1980
  BYTE pad1 = 0;
1981
  UINT16 pad2 = 0;
1982
  WLog_Print(log, WLOG_TRACE, "BitmapCacheHostSupportCapabilitySet (length %" PRIuz "):",
1983
             Stream_GetRemainingLength(s));
1984
1985
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1986
    return FALSE;
1987
1988
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1989
  Stream_Read_UINT8(s, pad1);         /* pad1 (1 byte) */
1990
  Stream_Read_UINT16(s, pad2);        /* pad2 (2 bytes) */
1991
  WLog_Print(log, WLOG_TRACE, "\tcacheVersion: 0x%02" PRIX8 "", cacheVersion);
1992
  WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%02" PRIX8 "", pad1);
1993
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%04" PRIX16 "", pad2);
1994
  return TRUE;
1995
}
1996
#endif
1997
1998
static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
1999
                                            BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2000
14.1k
{
2001
14.1k
  UINT32 info = 0;
2002
2003
14.1k
  WINPR_ASSERT(cellInfo);
2004
14.1k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2005
0
    return FALSE;
2006
2007
  /*
2008
   * numEntries is in the first 31 bits, while the last bit (k)
2009
   * is used to indicate a persistent bitmap cache.
2010
   */
2011
14.1k
  Stream_Read_UINT32(s, info);
2012
14.1k
  cellInfo->numEntries = (info & 0x7FFFFFFF);
2013
14.1k
  cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2014
14.1k
  return TRUE;
2015
14.1k
}
2016
2017
static void rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2018
0
{
2019
0
  UINT32 info = 0;
2020
  /*
2021
   * numEntries is in the first 31 bits, while the last bit (k)
2022
   * is used to indicate a persistent bitmap cache.
2023
   */
2024
0
  WINPR_ASSERT(cellInfo);
2025
0
  info = (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2026
0
  Stream_Write_UINT32(s, info);
2027
0
}
2028
2029
static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2030
9.85k
{
2031
9.85k
  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2032
9.85k
                                            FreeRDP_BitmapCachePersistEnabled };
2033
2034
29.5k
  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2035
19.7k
  {
2036
19.7k
    const FreeRDP_Settings_Keys_Bool id = keys[x];
2037
19.7k
    const BOOL val = freerdp_settings_get_bool(src, id);
2038
19.7k
    if (!freerdp_settings_set_bool(settings, id, val))
2039
0
      return FALSE;
2040
19.7k
  }
2041
2042
9.85k
  {
2043
9.85k
    const UINT32 BitmapCacheV2NumCells =
2044
9.85k
        freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2045
9.85k
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, NULL,
2046
9.85k
                                          BitmapCacheV2NumCells))
2047
0
      return FALSE;
2048
2049
23.9k
    for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2050
14.1k
    {
2051
14.1k
      const BITMAP_CACHE_V2_CELL_INFO* cdata =
2052
14.1k
          freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2053
14.1k
      if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2054
14.1k
                                              cdata))
2055
0
        return FALSE;
2056
14.1k
    }
2057
9.85k
  }
2058
2059
9.85k
  return TRUE;
2060
9.85k
}
2061
2062
/*
2063
 * Read bitmap cache v2 capability set.
2064
 * msdn{cc240560}
2065
 */
2066
2067
static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2068
9.87k
{
2069
9.87k
  UINT16 cacheFlags = 0;
2070
9.87k
  WINPR_UNUSED(settings);
2071
9.87k
  WINPR_ASSERT(settings);
2072
2073
9.87k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2074
7
    return FALSE;
2075
2076
9.86k
  Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2077
2078
9.86k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2079
0
    return FALSE;
2080
9.86k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2081
9.86k
                                 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2082
0
    return FALSE;
2083
2084
9.86k
  Stream_Seek_UINT8(s);                                  /* pad2 (1 byte) */
2085
9.86k
  Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2086
9.86k
  if (settings->BitmapCacheV2NumCells > 5)
2087
9
  {
2088
9
    WLog_Print(log, WLOG_ERROR,
2089
9
               "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2090
9
               settings->BitmapCacheV2NumCells);
2091
9
    return FALSE;
2092
9
  }
2093
2094
23.9k
  for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2095
14.1k
  {
2096
14.1k
    BITMAP_CACHE_V2_CELL_INFO* info =
2097
14.1k
        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2098
14.1k
    if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2099
0
      return FALSE;
2100
14.1k
  }
2101
2102
  /* Input must always have 5 BitmapCacheV2CellInfo values */
2103
45.0k
  for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2104
35.1k
  {
2105
35.1k
    if (!Stream_SafeSeek(s, 4))
2106
0
      return FALSE;
2107
35.1k
  }
2108
9.85k
  Stream_Seek(s, 12); /* pad3 (12 bytes) */
2109
9.85k
  return TRUE;
2110
9.85k
}
2111
2112
/*
2113
 * Write bitmap cache v2 capability set.
2114
 * msdn{cc240560}
2115
 */
2116
2117
static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2118
                                                     const rdpSettings* settings)
2119
0
{
2120
0
  WINPR_ASSERT(settings);
2121
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
2122
0
    return FALSE;
2123
2124
0
  const size_t header = rdp_capability_set_start(log, s);
2125
0
  UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2126
2127
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
2128
0
  {
2129
0
    cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2130
0
    settings->BitmapCacheV2CellInfo[0].persistent = 1;
2131
0
    settings->BitmapCacheV2CellInfo[1].persistent = 1;
2132
0
    settings->BitmapCacheV2CellInfo[2].persistent = 1;
2133
0
    settings->BitmapCacheV2CellInfo[3].persistent = 1;
2134
0
    settings->BitmapCacheV2CellInfo[4].persistent = 1;
2135
0
  }
2136
2137
0
  Stream_Write_UINT16(s, cacheFlags);                     /* cacheFlags (2 bytes) */
2138
0
  Stream_Write_UINT8(s, 0);                               /* pad2 (1 byte) */
2139
0
  Stream_Write_UINT8(
2140
0
      s, WINPR_ASSERTING_INT_CAST(uint8_t,
2141
0
                                  settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2142
0
  rdp_write_bitmap_cache_cell_info(
2143
0
      s, &settings->BitmapCacheV2CellInfo[0]); /* bitmapCache0CellInfo (4 bytes) */
2144
0
  rdp_write_bitmap_cache_cell_info(
2145
0
      s, &settings->BitmapCacheV2CellInfo[1]); /* bitmapCache1CellInfo (4 bytes) */
2146
0
  rdp_write_bitmap_cache_cell_info(
2147
0
      s, &settings->BitmapCacheV2CellInfo[2]); /* bitmapCache2CellInfo (4 bytes) */
2148
0
  rdp_write_bitmap_cache_cell_info(
2149
0
      s, &settings->BitmapCacheV2CellInfo[3]); /* bitmapCache3CellInfo (4 bytes) */
2150
0
  rdp_write_bitmap_cache_cell_info(
2151
0
      s, &settings->BitmapCacheV2CellInfo[4]); /* bitmapCache4CellInfo (4 bytes) */
2152
0
  Stream_Zero(s, 12);                          /* pad3 (12 bytes) */
2153
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2154
0
}
2155
2156
#ifdef WITH_DEBUG_CAPABILITIES
2157
static BOOL rdp_print_bitmap_cache_v2_capability_set(wLog* log, wStream* s)
2158
{
2159
  BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5] = { 0 };
2160
  WLog_Print(log, WLOG_TRACE,
2161
             "BitmapCacheV2CapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2162
2163
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2164
    return FALSE;
2165
2166
  const UINT16 cacheFlags = Stream_Get_UINT16(s);  /* cacheFlags (2 bytes) */
2167
  const UINT8 pad2 = Stream_Get_UINT8(s);          /* pad2 (1 byte) */
2168
  const UINT8 numCellCaches = Stream_Get_UINT8(s); /* numCellCaches (1 byte) */
2169
2170
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2171
  {
2172
    if (!rdp_read_bitmap_cache_cell_info(
2173
            log, s, &bitmapCacheV2CellInfo[x])) /* bitmapCache0CellInfo (4 bytes) */
2174
      return FALSE;
2175
  }
2176
2177
  if (!Stream_SafeSeek(s, 12)) /* pad3 (12 bytes) */
2178
    return FALSE;
2179
2180
  WLog_Print(log, WLOG_TRACE, "\tcacheFlags: 0x%04" PRIX16 "", cacheFlags);
2181
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%02" PRIX8 "", pad2);
2182
  WLog_Print(log, WLOG_TRACE, "\tnumCellCaches: 0x%02" PRIX8 "", numCellCaches);
2183
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2184
  {
2185
    const BITMAP_CACHE_V2_CELL_INFO* info = &bitmapCacheV2CellInfo[x];
2186
    WLog_Print(log, WLOG_TRACE,
2187
               "\tbitmapCache%" PRIuz "CellInfo: numEntries: %" PRIu32 " persistent: %" PRId32
2188
               "",
2189
               x, info->numEntries, info->persistent);
2190
  }
2191
  return TRUE;
2192
}
2193
#endif
2194
2195
static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2196
2.05k
{
2197
2.05k
  WINPR_ASSERT(settings);
2198
2.05k
  WINPR_ASSERT(src);
2199
2200
  /* MS servers and clients disregard in advertising what is relevant for their own side */
2201
2.05k
  if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2202
2.05k
      (src->VCFlags & VCCAPS_COMPR_SC))
2203
0
    settings->VCFlags |= VCCAPS_COMPR_SC;
2204
2.05k
  else
2205
2.05k
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2206
2207
2.05k
  if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2208
2.05k
      (src->VCFlags & VCCAPS_COMPR_CS_8K))
2209
0
    settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2210
2.05k
  else
2211
2.05k
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_CS_8K;
2212
2213
  /*
2214
   * When one peer does not write the VCChunkSize, the VCChunkSize must not be
2215
   * larger than CHANNEL_CHUNK_LENGTH (1600) bytes.
2216
   * Also prevent an invalid 0 size.
2217
   */
2218
2.05k
  if (!settings->ServerMode)
2219
1.53k
  {
2220
1.53k
    if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2221
1.46k
      settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2222
64
    else
2223
64
    {
2224
64
      settings->VCChunkSize = src->VCChunkSize;
2225
64
    }
2226
1.53k
  }
2227
2228
2.05k
  return TRUE;
2229
2.05k
}
2230
2231
/*
2232
 * Read virtual channel capability set.
2233
 * msdn{cc240551}
2234
 */
2235
2236
static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2237
2.05k
{
2238
2.05k
  UINT32 flags = 0;
2239
2.05k
  UINT32 VCChunkSize = 0;
2240
2241
2.05k
  WINPR_ASSERT(settings);
2242
2.05k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2243
6
    return FALSE;
2244
2245
2.05k
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2246
2247
2.05k
  if (Stream_GetRemainingLength(s) >= 4)
2248
1.61k
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2249
437
  else
2250
437
    VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2251
2252
2.05k
  settings->VCFlags = flags;
2253
2.05k
  settings->VCChunkSize = VCChunkSize;
2254
2255
2.05k
  return TRUE;
2256
2.05k
}
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
126
{
2303
126
  WINPR_ASSERT(settings);
2304
126
  WINPR_ASSERT(src);
2305
2306
126
  settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2307
126
  settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2308
126
  settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2309
2310
126
  return TRUE;
2311
126
}
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
130
{
2321
130
  UINT32 drawNineGridSupportLevel = 0;
2322
2323
130
  WINPR_ASSERT(settings);
2324
130
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2325
4
    return FALSE;
2326
2327
126
  Stream_Read_UINT32(s, drawNineGridSupportLevel);        /* drawNineGridSupportLevel (4 bytes) */
2328
126
  Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2329
126
  Stream_Read_UINT16(s,
2330
126
                     settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2331
2332
126
  settings->DrawNineGridEnabled =
2333
126
      (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) ? TRUE
2334
126
                                                                                          : FALSE;
2335
2336
126
  return TRUE;
2337
130
}
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
475
{
2390
475
  WINPR_ASSERT(settings);
2391
475
  WINPR_ASSERT(src);
2392
2393
475
  if (src->DrawGdiPlusEnabled)
2394
190
    settings->DrawGdiPlusEnabled = TRUE;
2395
2396
475
  if (src->DrawGdiPlusCacheEnabled)
2397
299
    settings->DrawGdiPlusCacheEnabled = TRUE;
2398
2399
475
  return TRUE;
2400
475
}
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
481
{
2409
481
  UINT32 drawGDIPlusSupportLevel = 0;
2410
481
  UINT32 drawGdiplusCacheLevel = 0;
2411
2412
481
  WINPR_ASSERT(settings);
2413
481
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2414
6
    return FALSE;
2415
2416
475
  Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2417
475
  Stream_Seek_UINT32(s);                          /* GdipVersion (4 bytes) */
2418
475
  Stream_Read_UINT32(s, drawGdiplusCacheLevel);   /* drawGdiplusCacheLevel (4 bytes) */
2419
475
  Stream_Seek(s, 10);                             /* GdipCacheEntries (10 bytes) */
2420
475
  Stream_Seek(s, 8);                              /* GdipCacheChunkSize (8 bytes) */
2421
475
  Stream_Seek(s, 6);                              /* GdipImageCacheProperties (6 bytes) */
2422
2423
475
  settings->DrawGdiPlusEnabled =
2424
475
      (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) ? TRUE : FALSE;
2425
475
  settings->DrawGdiPlusCacheEnabled =
2426
475
      (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) ? TRUE : FALSE;
2427
2428
475
  return TRUE;
2429
481
}
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
261
{
2488
261
  WINPR_ASSERT(settings);
2489
261
  WINPR_ASSERT(src);
2490
2491
261
  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
261
  UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2498
261
  if (settings->RemoteApplicationMode)
2499
0
    supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2500
2501
261
  settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2502
2503
261
  return TRUE;
2504
261
}
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
267
{
2513
267
  UINT32 railSupportLevel = 0;
2514
2515
267
  WINPR_ASSERT(settings);
2516
267
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2517
6
    return FALSE;
2518
2519
261
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2520
2521
261
  settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) ? TRUE : FALSE;
2522
261
  settings->RemoteApplicationSupportLevel = railSupportLevel;
2523
261
  return TRUE;
2524
267
}
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
928
{
2577
928
  WINPR_ASSERT(settings);
2578
928
  WINPR_ASSERT(src);
2579
2580
928
  settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2581
928
  settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2582
928
  settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2583
2584
928
  return TRUE;
2585
928
}
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
934
{
2594
934
  WINPR_ASSERT(settings);
2595
934
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2596
6
    return FALSE;
2597
2598
928
  Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2599
928
  Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2600
928
  Stream_Read_UINT16(s,
2601
928
                     settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2602
928
  return TRUE;
2603
934
}
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
62
{
2653
62
  WINPR_ASSERT(settings);
2654
62
  WINPR_ASSERT(src);
2655
2656
62
  settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2657
62
  return TRUE;
2658
62
}
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
66
{
2668
66
  WINPR_UNUSED(settings);
2669
66
  WINPR_ASSERT(settings);
2670
2671
66
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2672
4
    return FALSE;
2673
2674
62
  Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2675
62
  return TRUE;
2676
66
}
2677
2678
/*
2679
 * Write desktop composition capability set.
2680
 * msdn{cc240855}
2681
 */
2682
2683
static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2684
                                                         const rdpSettings* settings)
2685
0
{
2686
0
  WINPR_ASSERT(settings);
2687
2688
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2689
0
    return FALSE;
2690
2691
0
  const size_t header = rdp_capability_set_start(log, s);
2692
0
  const UINT16 compDeskSupportLevel =
2693
0
      (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2694
0
  Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2695
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2696
0
}
2697
2698
#ifdef WITH_DEBUG_CAPABILITIES
2699
static BOOL rdp_print_desktop_composition_capability_set(wLog* log, wStream* s)
2700
{
2701
  UINT16 compDeskSupportLevel = 0;
2702
  WLog_Print(log, WLOG_TRACE, "DesktopCompositionCapabilitySet (length %" PRIuz "):",
2703
             Stream_GetRemainingLength(s));
2704
2705
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2706
    return FALSE;
2707
2708
  Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2709
  WLog_Print(log, WLOG_TRACE, "\tcompDeskSupportLevel: 0x%04" PRIX16 "", compDeskSupportLevel);
2710
  return TRUE;
2711
}
2712
#endif
2713
2714
static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2715
                                                          const rdpSettings* src)
2716
1.35k
{
2717
1.35k
  UINT32 multifragMaxRequestSize = 0;
2718
2719
1.35k
  WINPR_ASSERT(settings);
2720
1.35k
  WINPR_ASSERT(src);
2721
2722
1.35k
  multifragMaxRequestSize = src->MultifragMaxRequestSize;
2723
2724
1.35k
  if (settings->ServerMode)
2725
907
  {
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
907
    if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2735
128
      multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2736
2737
907
    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
907
    else
2759
907
    {
2760
907
      settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2761
907
    }
2762
907
  }
2763
452
  else
2764
452
  {
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
452
    if (multifragMaxRequestSize > settings->MultifragMaxRequestSize)
2771
113
      settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2772
452
  }
2773
1.35k
  return TRUE;
2774
1.35k
}
2775
2776
/*
2777
 * Read multifragment update capability set.
2778
 * msdn{cc240649}
2779
 */
2780
2781
static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2782
                                                         rdpSettings* settings)
2783
1.36k
{
2784
1.36k
  UINT32 multifragMaxRequestSize = 0;
2785
2786
1.36k
  WINPR_ASSERT(settings);
2787
1.36k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2788
7
    return FALSE;
2789
2790
1.35k
  Stream_Read_UINT32(s, multifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2791
1.35k
  settings->MultifragMaxRequestSize = multifragMaxRequestSize;
2792
2793
1.35k
  return TRUE;
2794
1.36k
}
2795
2796
/*
2797
 * Write multifragment update capability set.
2798
 * msdn{cc240649}
2799
 */
2800
2801
static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2802
                                                          rdpSettings* settings)
2803
0
{
2804
0
  WINPR_ASSERT(settings);
2805
0
  if (settings->ServerMode && settings->MultifragMaxRequestSize == 0)
2806
0
  {
2807
    /*
2808
     * In server mode we prefer to use the highest useful request size that
2809
     * will allow us to pack a complete screen update into a single fast
2810
     * path PDU using any of the supported codecs.
2811
     * However, the client is completely free to accept our proposed
2812
     * max request size or send a different value in the client-to-server
2813
     * multi-fragment update capability set and we have to accept that,
2814
     * unless we are using RemoteFX where the client MUST announce a value
2815
     * greater than or equal to the value we're sending here.
2816
     * See [MS-RDPRFX 1.5 capability #2]
2817
     */
2818
0
    UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2819
0
    UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2820
0
    settings->MultifragMaxRequestSize = tileNumX * tileNumY * 16384;
2821
    /* and add room for headers, regions, frame markers, etc. */
2822
0
    settings->MultifragMaxRequestSize += 16384;
2823
0
  }
2824
2825
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2826
0
    return FALSE;
2827
0
  const size_t header = rdp_capability_set_start(log, s);
2828
0
  Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2829
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2830
0
}
2831
2832
#ifdef WITH_DEBUG_CAPABILITIES
2833
static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2834
{
2835
  UINT32 maxRequestSize = 0;
2836
  WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2837
             Stream_GetRemainingLength(s));
2838
2839
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2840
    return FALSE;
2841
2842
  Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2843
  WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2844
  return TRUE;
2845
}
2846
#endif
2847
2848
static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2849
1.29k
{
2850
1.29k
  WINPR_ASSERT(settings);
2851
1.29k
  WINPR_ASSERT(src);
2852
2853
1.29k
  settings->LargePointerFlag = src->LargePointerFlag;
2854
1.29k
  return TRUE;
2855
1.29k
}
2856
2857
/*
2858
 * Read large pointer capability set.
2859
 * msdn{cc240650}
2860
 */
2861
2862
static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2863
1.29k
{
2864
1.29k
  UINT16 largePointerSupportFlags = 0;
2865
2866
1.29k
  WINPR_ASSERT(settings);
2867
1.29k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2868
4
    return FALSE;
2869
2870
1.29k
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2871
1.29k
  settings->LargePointerFlag &= largePointerSupportFlags;
2872
1.29k
  if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2873
480
  {
2874
480
    WLog_Print(
2875
480
        log, WLOG_WARN,
2876
480
        "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2877
480
        largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384),
2878
480
        largePointerSupportFlags);
2879
480
  }
2880
1.29k
  return TRUE;
2881
1.29k
}
2882
2883
/*
2884
 * Write large pointer capability set.
2885
 * msdn{cc240650}
2886
 */
2887
2888
static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2889
                                                   const rdpSettings* settings)
2890
0
{
2891
0
  WINPR_ASSERT(settings);
2892
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2893
0
    return FALSE;
2894
2895
0
  const size_t header = rdp_capability_set_start(log, s);
2896
0
  const UINT16 largePointerSupportFlags =
2897
0
      settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2898
0
  Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2899
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2900
0
}
2901
2902
#ifdef WITH_DEBUG_CAPABILITIES
2903
static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
2904
{
2905
  UINT16 largePointerSupportFlags = 0;
2906
  WLog_Print(log, WLOG_TRACE,
2907
             "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2908
2909
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2910
    return FALSE;
2911
2912
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2913
  WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
2914
             largePointerSupportFlags);
2915
  return TRUE;
2916
}
2917
#endif
2918
2919
static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2920
2.25k
{
2921
2.25k
  WINPR_ASSERT(settings);
2922
2.25k
  WINPR_ASSERT(src);
2923
2924
  /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
2925
   *
2926
   * disable surface commands if the remote does not support fastpath
2927
   */
2928
2.25k
  if (src->FastPathOutput)
2929
1.14k
  {
2930
1.14k
    settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2931
1.14k
    settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2932
1.14k
    settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2933
1.14k
  }
2934
1.11k
  else
2935
1.11k
  {
2936
1.11k
    settings->SurfaceCommandsSupported = 0;
2937
1.11k
    settings->SurfaceCommandsEnabled = FALSE;
2938
1.11k
    settings->SurfaceFrameMarkerEnabled = FALSE;
2939
1.11k
  }
2940
2941
2.25k
  return TRUE;
2942
2.25k
}
2943
2944
/*
2945
 * Read surface commands capability set.
2946
 * msdn{dd871563}
2947
 */
2948
2949
static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2950
2.26k
{
2951
2.26k
  UINT32 cmdFlags = 0;
2952
2953
2.26k
  WINPR_ASSERT(settings);
2954
2.26k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2955
7
    return FALSE;
2956
2957
2.25k
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2958
2.25k
  Stream_Seek_UINT32(s);           /* reserved (4 bytes) */
2959
2.25k
  settings->SurfaceCommandsSupported = cmdFlags;
2960
2.25k
  settings->SurfaceCommandsEnabled =
2961
2.25k
      (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) ? TRUE : FALSE;
2962
2.25k
  settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) ? TRUE : FALSE;
2963
2.25k
  return TRUE;
2964
2.26k
}
2965
2966
/*
2967
 * Write surface commands capability set.
2968
 * msdn{dd871563}
2969
 */
2970
2971
static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2972
                                                      const rdpSettings* settings)
2973
0
{
2974
0
  WINPR_ASSERT(settings);
2975
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2976
0
    return FALSE;
2977
2978
0
  const size_t header = rdp_capability_set_start(log, s);
2979
  // TODO: Make these configurable too
2980
0
  UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2981
2982
0
  if (settings->SurfaceFrameMarkerEnabled)
2983
0
    cmdFlags |= SURFCMDS_FRAME_MARKER;
2984
2985
0
  Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2986
0
  Stream_Write_UINT32(s, 0);        /* reserved (4 bytes) */
2987
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
2988
0
}
2989
2990
static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
2991
4.92k
{
2992
4.92k
  if (!Uuid1 && !Uuid2)
2993
0
    return false;
2994
2995
4.92k
  if (Uuid1 && !Uuid2)
2996
0
    return false;
2997
2998
4.92k
  if (!Uuid1 && Uuid2)
2999
0
    return true;
3000
3001
4.92k
  if (Uuid1->Data1 != Uuid2->Data1)
3002
4.15k
    return false;
3003
3004
770
  if (Uuid1->Data2 != Uuid2->Data2)
3005
757
    return false;
3006
3007
13
  if (Uuid1->Data3 != Uuid2->Data3)
3008
7
    return false;
3009
3010
7
  for (int index = 0; index < 8; index++)
3011
7
  {
3012
7
    if (Uuid1->Data4[index] != Uuid2->Data4[index])
3013
6
      return false;
3014
7
  }
3015
3016
0
  return true;
3017
6
}
3018
3019
#ifdef WITH_DEBUG_CAPABILITIES
3020
static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3021
{
3022
  UINT32 cmdFlags = 0;
3023
  UINT32 reserved = 0;
3024
3025
  WLog_Print(log, WLOG_TRACE,
3026
             "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3027
3028
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3029
    return FALSE;
3030
3031
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3032
  Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3033
  WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3034
  WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3035
  return TRUE;
3036
}
3037
3038
static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3039
{
3040
  WINPR_ASSERT(guid);
3041
  WLog_Print(log, WLOG_TRACE,
3042
             "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3043
             "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3044
             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3045
             guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3046
             guid->Data4[7]);
3047
}
3048
3049
static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3050
{
3051
  WINPR_ASSERT(guid);
3052
  if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3053
    return "CODEC_GUID_REMOTEFX";
3054
  else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3055
    return "CODEC_GUID_NSCODEC";
3056
  else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3057
    return "CODEC_GUID_IGNORE";
3058
  else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3059
    return "CODEC_GUID_IMAGE_REMOTEFX";
3060
3061
#if defined(WITH_JPEG)
3062
  else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3063
    return "CODEC_GUID_JPEG";
3064
3065
#endif
3066
  return "CODEC_GUID_UNKNOWN";
3067
}
3068
#endif
3069
3070
static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3071
1.63k
{
3072
1.63k
  BYTE g[16] = { 0 };
3073
3074
1.63k
  WINPR_ASSERT(guid);
3075
1.63k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3076
74
    return FALSE;
3077
1.56k
  Stream_Read(s, g, 16);
3078
1.56k
  guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3079
1.56k
  guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3080
1.56k
  guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3081
1.56k
  guid->Data4[0] = g[8];
3082
1.56k
  guid->Data4[1] = g[9];
3083
1.56k
  guid->Data4[2] = g[10];
3084
1.56k
  guid->Data4[3] = g[11];
3085
1.56k
  guid->Data4[4] = g[12];
3086
1.56k
  guid->Data4[5] = g[13];
3087
1.56k
  guid->Data4[6] = g[14];
3088
1.56k
  guid->Data4[7] = g[15];
3089
1.56k
  return TRUE;
3090
1.63k
}
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
1.00k
{
3117
1.00k
  WINPR_ASSERT(settings);
3118
1.00k
  WINPR_ASSERT(src);
3119
3120
1.00k
  if (settings->ServerMode)
3121
988
  {
3122
3123
988
    settings->RemoteFxCodecId = src->RemoteFxCodecId;
3124
988
    settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3125
988
    settings->RemoteFxOnly = src->RemoteFxOnly;
3126
988
    settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3127
988
    settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3128
988
    settings->NSCodecId = src->NSCodecId;
3129
988
    settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3130
988
    settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3131
988
    settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3132
3133
    /* only enable a codec if we've announced/enabled it before */
3134
988
    settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3135
988
    settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3136
988
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3137
988
                                   settings->NSCodec && src->NSCodec))
3138
0
      return FALSE;
3139
988
    settings->JpegCodec = src->JpegCodec;
3140
988
  }
3141
1.00k
  return TRUE;
3142
1.00k
}
3143
3144
static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3145
                                       UINT16 icapLen)
3146
0
{
3147
0
  UINT16 version = 0;
3148
0
  UINT16 tileSize = 0;
3149
0
  BYTE codecFlags = 0;
3150
0
  BYTE colConvBits = 0;
3151
0
  BYTE transformBits = 0;
3152
0
  BYTE entropyBits = 0;
3153
  /* TS_RFX_ICAP */
3154
0
  if (icapLen != 8)
3155
0
  {
3156
0
    WLog_Print(log, WLOG_ERROR,
3157
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3158
0
               " unsupported, expecting size %" PRIu16 " not supported",
3159
0
               icapLen, 8);
3160
0
    return FALSE;
3161
0
  }
3162
3163
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3164
0
    return FALSE;
3165
3166
0
  Stream_Read_UINT16(sub, version);      /* version (2 bytes) */
3167
0
  Stream_Read_UINT16(sub, tileSize);     /* tileSize (2 bytes) */
3168
0
  Stream_Read_UINT8(sub, codecFlags);    /* flags (1 byte) */
3169
0
  Stream_Read_UINT8(sub, colConvBits);   /* colConvBits (1 byte) */
3170
0
  Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3171
0
  Stream_Read_UINT8(sub, entropyBits);   /* entropyBits (1 byte) */
3172
3173
0
  if (version == 0x0009)
3174
0
  {
3175
    /* Version 0.9 */
3176
0
    if (tileSize != 0x0080)
3177
0
    {
3178
0
      WLog_Print(log, WLOG_ERROR,
3179
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3180
0
                 " tile size %" PRIu16 " not supported",
3181
0
                 version, tileSize);
3182
0
      return FALSE;
3183
0
    }
3184
0
  }
3185
0
  else if (version == 0x0100)
3186
0
  {
3187
    /* Version 1.0 */
3188
0
    if (tileSize != 0x0040)
3189
0
    {
3190
0
      WLog_Print(log, WLOG_ERROR,
3191
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3192
0
                 " tile size %" PRIu16 " not supported",
3193
0
                 version, tileSize);
3194
0
      return FALSE;
3195
0
    }
3196
0
  }
3197
0
  else
3198
0
  {
3199
0
    WLog_Print(log, WLOG_ERROR,
3200
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3201
0
               version);
3202
0
    return FALSE;
3203
0
  }
3204
3205
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3206
0
  if (colConvBits != 1)
3207
0
  {
3208
0
    WLog_Print(log, WLOG_ERROR,
3209
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3210
0
               " not supported, must be CLW_COL_CONV_ICT (0x1)",
3211
0
               colConvBits);
3212
0
    return FALSE;
3213
0
  }
3214
3215
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3216
0
  if (transformBits != 1)
3217
0
  {
3218
0
    WLog_Print(log, WLOG_ERROR,
3219
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3220
0
               " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3221
0
               colConvBits);
3222
0
    return FALSE;
3223
0
  }
3224
3225
0
  const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3226
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3227
0
    return FALSE;
3228
3229
0
  if ((codecFlags & CODEC_MODE) != 0)
3230
0
  {
3231
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3232
0
      return FALSE;
3233
0
  }
3234
0
  else if ((codecFlags & ~CODEC_MODE) != 0)
3235
0
    WLog_Print(log, WLOG_WARN,
3236
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3237
0
               "0x%02" PRIx8,
3238
0
               (codecFlags & ~CODEC_MODE));
3239
3240
0
  switch (entropyBits)
3241
0
  {
3242
0
    case CLW_ENTROPY_RLGR1:
3243
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3244
0
        return FALSE;
3245
0
      break;
3246
0
    case CLW_ENTROPY_RLGR3:
3247
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3248
0
        return FALSE;
3249
0
      break;
3250
0
    default:
3251
0
      WLog_Print(log, WLOG_ERROR,
3252
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3253
0
                 "unsupported value 0x%02" PRIx8
3254
0
                 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3255
0
                 "(0x04)",
3256
0
                 entropyBits);
3257
0
      return FALSE;
3258
0
  }
3259
0
  return TRUE;
3260
0
}
3261
3262
static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3263
0
{
3264
0
  UINT16 blockType = 0;
3265
0
  UINT32 blockLen = 0;
3266
0
  BYTE rfxCodecId = 0;
3267
0
  UINT16 capsetType = 0;
3268
0
  UINT16 numIcaps = 0;
3269
0
  UINT16 icapLen = 0;
3270
3271
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3272
0
    return FALSE;
3273
3274
  /* TS_RFX_CAPSET */
3275
0
  Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3276
0
  Stream_Read_UINT32(s, blockLen);  /* blockLen (4 bytes) */
3277
0
  if (blockType != 0xCBC1)
3278
0
  {
3279
0
    WLog_Print(log, WLOG_ERROR,
3280
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3281
0
               "] != CBY_CAPSET (0xCBC1)",
3282
0
               blockType);
3283
0
    return FALSE;
3284
0
  }
3285
0
  if (blockLen < 6ull)
3286
0
  {
3287
0
    WLog_Print(log, WLOG_ERROR,
3288
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu16 "] < 6", blockLen);
3289
0
    return FALSE;
3290
0
  }
3291
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3292
0
    return FALSE;
3293
3294
0
  wStream sbuffer = { 0 };
3295
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3296
0
  WINPR_ASSERT(sub);
3297
3298
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3299
0
    return FALSE;
3300
3301
0
  Stream_Read_UINT8(sub, rfxCodecId);  /* codecId (1 byte) */
3302
0
  Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3303
0
  Stream_Read_UINT16(sub, numIcaps);   /* numIcaps (2 bytes) */
3304
0
  Stream_Read_UINT16(sub, icapLen);    /* icapLen (2 bytes) */
3305
3306
0
  if (rfxCodecId != 1)
3307
0
  {
3308
0
    WLog_Print(log, WLOG_ERROR,
3309
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3310
0
    return FALSE;
3311
0
  }
3312
3313
0
  if (capsetType != 0xCFC0)
3314
0
  {
3315
0
    WLog_Print(log, WLOG_ERROR,
3316
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3317
0
               "] != CLY_CAPSET (0xCFC0)",
3318
0
               capsetType);
3319
0
    return FALSE;
3320
0
  }
3321
3322
0
  while (numIcaps--)
3323
0
  {
3324
0
    if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3325
0
      return FALSE;
3326
0
  }
3327
0
  return TRUE;
3328
0
}
3329
3330
static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3331
0
{
3332
0
  if (Stream_GetRemainingLength(sub) == 0)
3333
0
    return TRUE;
3334
3335
0
  UINT16 blockType = 0;
3336
0
  UINT32 blockLen = 0;
3337
0
  UINT16 numCapsets = 0;
3338
3339
  /* TS_RFX_CAPS */
3340
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3341
0
    return FALSE;
3342
0
  Stream_Read_UINT16(sub, blockType);  /* blockType (2 bytes) */
3343
0
  Stream_Read_UINT32(sub, blockLen);   /* blockLen (4 bytes) */
3344
0
  Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3345
3346
0
  if (blockType != 0xCBC0)
3347
0
  {
3348
0
    WLog_Print(log, WLOG_ERROR,
3349
0
               "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3350
0
               "] != CBY_CAPS (0xCBC0)",
3351
0
               blockType);
3352
0
    return FALSE;
3353
0
  }
3354
3355
0
  if (blockLen != 8)
3356
0
  {
3357
0
    WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3358
0
               blockLen);
3359
0
    return FALSE;
3360
0
  }
3361
3362
0
  if (numCapsets != 1)
3363
0
  {
3364
0
    WLog_Print(log, WLOG_ERROR,
3365
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[" PRIu16 "] != 1", numCapsets);
3366
0
    return FALSE;
3367
0
  }
3368
3369
0
  for (UINT16 x = 0; x < numCapsets; x++)
3370
0
  {
3371
0
    if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3372
0
      return FALSE;
3373
0
  }
3374
3375
0
  return TRUE;
3376
0
}
3377
3378
static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3379
0
{
3380
0
  UINT32 rfxCapsLength = 0;
3381
0
  UINT32 rfxPropsLength = 0;
3382
0
  UINT32 captureFlags = 0;
3383
3384
  /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3385
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3386
0
    return FALSE;
3387
0
  Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3388
0
  if (rfxPropsLength < 4)
3389
0
  {
3390
0
    WLog_Print(log, WLOG_ERROR,
3391
0
               "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3392
0
               " too short, require at least 4 bytes",
3393
0
               rfxPropsLength);
3394
0
    return FALSE;
3395
0
  }
3396
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3397
0
    return FALSE;
3398
3399
0
  wStream sbuffer = { 0 };
3400
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3401
0
  WINPR_ASSERT(sub);
3402
3403
0
  Stream_Seek(s, rfxPropsLength - 4ull);
3404
3405
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3406
0
    return FALSE;
3407
3408
0
  Stream_Read_UINT32(sub, captureFlags);  /* captureFlags (4 bytes) */
3409
0
  Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3410
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3411
0
    return FALSE;
3412
3413
0
  settings->RemoteFxCaptureFlags = captureFlags;
3414
0
  settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? FALSE : TRUE;
3415
3416
  /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3417
0
  wStream tsbuffer = { 0 };
3418
0
  wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3419
0
  WINPR_ASSERT(ts_sub);
3420
0
  return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3421
0
}
3422
3423
/*
3424
 * Read bitmap codecs capability set.
3425
 * msdn{dd891377}
3426
 */
3427
3428
static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3429
                                                  BOOL isServer)
3430
1.10k
{
3431
1.10k
  BYTE codecId = 0;
3432
1.10k
  GUID codecGuid = { 0 };
3433
1.10k
  BYTE bitmapCodecCount = 0;
3434
1.10k
  UINT16 codecPropertiesLength = 0;
3435
3436
1.10k
  BOOL guidNSCodec = FALSE;
3437
1.10k
  BOOL guidRemoteFx = FALSE;
3438
1.10k
  BOOL guidRemoteFxImage = FALSE;
3439
3440
1.10k
  WINPR_ASSERT(settings);
3441
1.10k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3442
3
    return FALSE;
3443
3444
1.10k
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3445
3446
2.64k
  while (bitmapCodecCount > 0)
3447
1.63k
  {
3448
1.63k
    wStream subbuffer = { 0 };
3449
3450
1.63k
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3451
74
      return FALSE;
3452
1.56k
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3453
5
      return FALSE;
3454
1.55k
    Stream_Read_UINT8(s, codecId);                /* codecId (1 byte) */
3455
1.55k
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3456
3457
1.55k
    wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3458
1.55k
    if (!Stream_SafeSeek(s, codecPropertiesLength))
3459
19
      return FALSE;
3460
3461
1.53k
    if (isServer)
3462
1.23k
    {
3463
1.23k
      if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3464
0
      {
3465
0
        guidRemoteFx = TRUE;
3466
0
        settings->RemoteFxCodecId = codecId;
3467
0
        if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3468
0
          return FALSE;
3469
0
      }
3470
1.23k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3471
0
      {
3472
        /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3473
0
        guidRemoteFxImage = TRUE;
3474
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3475
0
          return FALSE;
3476
0
      }
3477
1.23k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3478
0
      {
3479
0
        BYTE colorLossLevel = 0;
3480
0
        BYTE fAllowSubsampling = 0;
3481
0
        BYTE fAllowDynamicFidelity = 0;
3482
0
        guidNSCodec = TRUE;
3483
0
        settings->NSCodecId = codecId;
3484
0
        if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3485
0
          return FALSE;
3486
0
        Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3487
0
        Stream_Read_UINT8(sub, fAllowSubsampling);     /* fAllowSubsampling (1 byte) */
3488
0
        Stream_Read_UINT8(sub, colorLossLevel);        /* colorLossLevel (1 byte) */
3489
3490
0
        if (colorLossLevel < 1)
3491
0
          colorLossLevel = 1;
3492
3493
0
        if (colorLossLevel > 7)
3494
0
          colorLossLevel = 7;
3495
3496
0
        settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3497
0
        settings->NSCodecAllowSubsampling = fAllowSubsampling;
3498
0
        settings->NSCodecColorLossLevel = colorLossLevel;
3499
0
      }
3500
1.23k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3501
0
      {
3502
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3503
0
          return FALSE;
3504
0
      }
3505
1.23k
      else
3506
1.23k
      {
3507
1.23k
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3508
0
          return FALSE;
3509
1.23k
      }
3510
1.23k
    }
3511
308
    else
3512
308
    {
3513
308
      if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3514
0
        return FALSE;
3515
308
    }
3516
3517
1.53k
    const size_t rest = Stream_GetRemainingLength(sub);
3518
1.53k
    if (rest > 0)
3519
0
    {
3520
0
      WLog_Print(log, WLOG_ERROR,
3521
0
                 "error while reading codec properties: actual size: %" PRIuz
3522
0
                 " expected size: %" PRIu32 "",
3523
0
                 rest + codecPropertiesLength, codecPropertiesLength);
3524
0
    }
3525
1.53k
    bitmapCodecCount--;
3526
3527
    /* only enable a codec if we've announced/enabled it before */
3528
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3529
0
      return FALSE;
3530
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3531
0
      return FALSE;
3532
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3533
0
      return FALSE;
3534
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3535
0
      return FALSE;
3536
1.53k
  }
3537
3538
1.00k
  return TRUE;
3539
1.10k
}
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
912
{
3839
912
  WINPR_ASSERT(settings);
3840
912
  WINPR_ASSERT(src);
3841
3842
912
  if (settings->ServerMode)
3843
554
    settings->FrameAcknowledge = src->FrameAcknowledge;
3844
3845
912
  return TRUE;
3846
912
}
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
918
{
3854
918
  WINPR_ASSERT(settings);
3855
918
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3856
6
    return FALSE;
3857
3858
912
  Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3859
3860
912
  return TRUE;
3861
918
}
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
578
{
3898
578
  WINPR_ASSERT(settings);
3899
578
  WINPR_ASSERT(src);
3900
3901
578
  settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3902
578
  return TRUE;
3903
578
}
3904
3905
static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3906
                                                             rdpSettings* settings)
3907
588
{
3908
588
  BYTE bitmapCacheV3CodecId = 0;
3909
3910
588
  WINPR_ASSERT(settings);
3911
588
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3912
10
    return FALSE;
3913
3914
578
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3915
578
  settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3916
578
  return TRUE;
3917
588
}
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
86.8k
{
4188
86.8k
  switch (type)
4189
86.8k
  {
4190
2.03k
    case CAPSET_TYPE_GENERAL:
4191
2.03k
      return rdp_apply_general_capability_set(dst, src);
4192
3.09k
    case CAPSET_TYPE_BITMAP:
4193
3.09k
      return rdp_apply_bitmap_capability_set(dst, src);
4194
2.67k
    case CAPSET_TYPE_ORDER:
4195
2.67k
      return rdp_apply_order_capability_set(dst, src);
4196
24.5k
    case CAPSET_TYPE_POINTER:
4197
24.5k
      return rdp_apply_pointer_capability_set(dst, src);
4198
25.5k
    case CAPSET_TYPE_INPUT:
4199
25.5k
      return rdp_apply_input_capability_set(dst, src);
4200
2.05k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4201
2.05k
      return rdp_apply_virtual_channel_capability_set(dst, src);
4202
1.78k
    case CAPSET_TYPE_SHARE:
4203
1.78k
      return rdp_apply_share_capability_set(dst, src);
4204
2.26k
    case CAPSET_TYPE_COLOR_CACHE:
4205
2.26k
      return rdp_apply_color_cache_capability_set(dst, src);
4206
665
    case CAPSET_TYPE_FONT:
4207
665
      return rdp_apply_font_capability_set(dst, src);
4208
475
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4209
475
      return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4210
261
    case CAPSET_TYPE_RAIL:
4211
261
      return rdp_apply_remote_programs_capability_set(dst, src);
4212
928
    case CAPSET_TYPE_WINDOW:
4213
928
      return rdp_apply_window_list_capability_set(dst, src);
4214
1.35k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4215
1.35k
      return rdp_apply_multifragment_update_capability_set(dst, src);
4216
1.29k
    case CAPSET_TYPE_LARGE_POINTER:
4217
1.29k
      return rdp_apply_large_pointer_capability_set(dst, src);
4218
62
    case CAPSET_TYPE_COMP_DESK:
4219
62
      return rdp_apply_desktop_composition_capability_set(dst, src);
4220
2.25k
    case CAPSET_TYPE_SURFACE_COMMANDS:
4221
2.25k
      return rdp_apply_surface_commands_capability_set(dst, src);
4222
1.00k
    case CAPSET_TYPE_BITMAP_CODECS:
4223
1.00k
      return rdp_apply_bitmap_codecs_capability_set(dst, src);
4224
912
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4225
912
      return rdp_apply_frame_acknowledge_capability_set(dst, src);
4226
578
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4227
578
      return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4228
43
    case CAPSET_TYPE_BITMAP_CACHE:
4229
43
      return rdp_apply_bitmap_cache_capability_set(dst, src);
4230
9.85k
    case CAPSET_TYPE_BITMAP_CACHE_V2:
4231
9.85k
      return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4232
517
    case CAPSET_TYPE_BRUSH:
4233
517
      return rdp_apply_brush_capability_set(dst, src);
4234
70
    case CAPSET_TYPE_GLYPH_CACHE:
4235
70
      return rdp_apply_glyph_cache_capability_set(dst, src);
4236
138
    case CAPSET_TYPE_OFFSCREEN_CACHE:
4237
138
      return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4238
360
    case CAPSET_TYPE_SOUND:
4239
360
      return rdp_apply_sound_capability_set(dst, src);
4240
88
    case CAPSET_TYPE_CONTROL:
4241
88
      return rdp_apply_control_capability_set(dst, src);
4242
204
    case CAPSET_TYPE_ACTIVATION:
4243
204
      return rdp_apply_window_activation_capability_set(dst, src);
4244
126
    case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4245
126
      return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4246
1.64k
    case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4247
1.64k
      return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4248
0
    default:
4249
0
      return TRUE;
4250
86.8k
  }
4251
86.8k
}
4252
4253
BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4254
                             BOOL isServer)
4255
89.0k
{
4256
89.0k
  WINPR_ASSERT(settings);
4257
4258
89.0k
  if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4259
87.3k
  {
4260
87.3k
    const size_t size = Stream_Length(sub);
4261
87.3k
    if (size > UINT32_MAX)
4262
0
      return FALSE;
4263
4264
87.3k
    WINPR_ASSERT(settings->ReceivedCapabilities);
4265
87.3k
    settings->ReceivedCapabilities[type] = TRUE;
4266
4267
87.3k
    WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4268
87.3k
    settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4269
4270
87.3k
    WINPR_ASSERT(settings->ReceivedCapabilityData);
4271
87.3k
    void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4272
87.3k
    if (!tmp && (size > 0))
4273
0
      return FALSE;
4274
87.3k
    memcpy(tmp, Stream_Buffer(sub), size);
4275
87.3k
    settings->ReceivedCapabilityData[type] = tmp;
4276
87.3k
  }
4277
1.63k
  else
4278
1.63k
    WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4279
4280
89.0k
  BOOL treated = TRUE;
4281
4282
89.0k
  switch (type)
4283
89.0k
  {
4284
2.10k
    case CAPSET_TYPE_GENERAL:
4285
2.10k
      if (!rdp_read_general_capability_set(log, sub, settings))
4286
74
        return FALSE;
4287
4288
2.03k
      break;
4289
4290
3.09k
    case CAPSET_TYPE_BITMAP:
4291
3.09k
      if (!rdp_read_bitmap_capability_set(log, sub, settings))
4292
7
        return FALSE;
4293
4294
3.09k
      break;
4295
4296
3.09k
    case CAPSET_TYPE_ORDER:
4297
2.68k
      if (!rdp_read_order_capability_set(log, sub, settings))
4298
8
        return FALSE;
4299
4300
2.67k
      break;
4301
4302
24.6k
    case CAPSET_TYPE_POINTER:
4303
24.6k
      if (!rdp_read_pointer_capability_set(log, sub, settings))
4304
20
        return FALSE;
4305
4306
24.5k
      break;
4307
4308
25.5k
    case CAPSET_TYPE_INPUT:
4309
25.5k
      if (!rdp_read_input_capability_set(log, sub, settings))
4310
7
        return FALSE;
4311
4312
25.5k
      break;
4313
4314
25.5k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4315
2.05k
      if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4316
6
        return FALSE;
4317
4318
2.05k
      break;
4319
4320
2.05k
    case CAPSET_TYPE_SHARE:
4321
1.78k
      if (!rdp_read_share_capability_set(log, sub, settings))
4322
4
        return FALSE;
4323
4324
1.78k
      break;
4325
4326
2.27k
    case CAPSET_TYPE_COLOR_CACHE:
4327
2.27k
      if (!rdp_read_color_cache_capability_set(log, sub, settings))
4328
11
        return FALSE;
4329
4330
2.26k
      break;
4331
4332
2.26k
    case CAPSET_TYPE_FONT:
4333
665
      if (!rdp_read_font_capability_set(log, sub, settings))
4334
0
        return FALSE;
4335
4336
665
      break;
4337
4338
665
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4339
481
      if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4340
6
        return FALSE;
4341
4342
475
      break;
4343
4344
475
    case CAPSET_TYPE_RAIL:
4345
267
      if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4346
6
        return FALSE;
4347
4348
261
      break;
4349
4350
934
    case CAPSET_TYPE_WINDOW:
4351
934
      if (!rdp_read_window_list_capability_set(log, sub, settings))
4352
6
        return FALSE;
4353
4354
928
      break;
4355
4356
1.36k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4357
1.36k
      if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4358
7
        return FALSE;
4359
4360
1.35k
      break;
4361
4362
1.35k
    case CAPSET_TYPE_LARGE_POINTER:
4363
1.29k
      if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4364
4
        return FALSE;
4365
4366
1.29k
      break;
4367
4368
1.29k
    case CAPSET_TYPE_COMP_DESK:
4369
66
      if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4370
4
        return FALSE;
4371
4372
62
      break;
4373
4374
2.26k
    case CAPSET_TYPE_SURFACE_COMMANDS:
4375
2.26k
      if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4376
7
        return FALSE;
4377
4378
2.25k
      break;
4379
4380
2.25k
    case CAPSET_TYPE_BITMAP_CODECS:
4381
1.10k
      if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4382
101
        return FALSE;
4383
4384
1.00k
      break;
4385
4386
1.00k
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4387
918
      if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4388
6
        return FALSE;
4389
4390
912
      break;
4391
4392
912
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4393
588
      if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4394
10
        return FALSE;
4395
4396
578
      break;
4397
4398
14.8k
    default:
4399
14.8k
      treated = FALSE;
4400
14.8k
      break;
4401
89.0k
  }
4402
4403
88.7k
  if (!treated)
4404
14.8k
  {
4405
14.8k
    if (isServer)
4406
12.4k
    {
4407
      /* treating capabilities that are supposed to be send only from the client */
4408
12.4k
      switch (type)
4409
12.4k
      {
4410
56
        case CAPSET_TYPE_BITMAP_CACHE:
4411
56
          if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4412
13
            return FALSE;
4413
4414
43
          break;
4415
4416
9.87k
        case CAPSET_TYPE_BITMAP_CACHE_V2:
4417
9.87k
          if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4418
16
            return FALSE;
4419
4420
9.85k
          break;
4421
4422
9.85k
        case CAPSET_TYPE_BRUSH:
4423
520
          if (!rdp_read_brush_capability_set(log, sub, settings))
4424
3
            return FALSE;
4425
4426
517
          break;
4427
4428
517
        case CAPSET_TYPE_GLYPH_CACHE:
4429
76
          if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4430
6
            return FALSE;
4431
4432
70
          break;
4433
4434
141
        case CAPSET_TYPE_OFFSCREEN_CACHE:
4435
141
          if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4436
3
            return FALSE;
4437
4438
138
          break;
4439
4440
364
        case CAPSET_TYPE_SOUND:
4441
364
          if (!rdp_read_sound_capability_set(log, sub, settings))
4442
4
            return FALSE;
4443
4444
360
          break;
4445
4446
360
        case CAPSET_TYPE_CONTROL:
4447
95
          if (!rdp_read_control_capability_set(log, sub, settings))
4448
7
            return FALSE;
4449
4450
88
          break;
4451
4452
209
        case CAPSET_TYPE_ACTIVATION:
4453
209
          if (!rdp_read_window_activation_capability_set(log, sub, settings))
4454
5
            return FALSE;
4455
4456
204
          break;
4457
4458
204
        case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4459
130
          if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4460
4
            return FALSE;
4461
4462
126
          break;
4463
4464
1.02k
        default:
4465
1.02k
          WLog_Print(log, WLOG_ERROR,
4466
1.02k
                     "capability %s(%" PRIu16 ") not expected from client",
4467
1.02k
                     get_capability_name(type), type);
4468
1.02k
          return FALSE;
4469
12.4k
      }
4470
12.4k
    }
4471
2.38k
    else
4472
2.38k
    {
4473
      /* treating capabilities that are supposed to be send only from the server */
4474
2.38k
      switch (type)
4475
2.38k
      {
4476
1.64k
        case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4477
1.64k
          if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4478
6
            return FALSE;
4479
4480
1.64k
          break;
4481
4482
1.64k
        default:
4483
742
          WLog_Print(log, WLOG_ERROR,
4484
742
                     "capability %s(%" PRIu16 ") not expected from server",
4485
742
                     get_capability_name(type), type);
4486
742
          return FALSE;
4487
2.38k
      }
4488
2.38k
    }
4489
14.8k
  }
4490
4491
86.8k
  const size_t rest = Stream_GetRemainingLength(sub);
4492
86.8k
  if (rest > 0)
4493
44.1k
  {
4494
44.1k
    const size_t length = Stream_Capacity(sub);
4495
44.1k
    WLog_Print(log, WLOG_ERROR,
4496
44.1k
               "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4497
44.1k
               type, length - rest, length);
4498
44.1k
  }
4499
86.8k
  return TRUE;
4500
88.7k
}
4501
4502
static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4503
                                     rdpSettings* rcvSettings, UINT16 totalLength)
4504
8.62k
{
4505
8.62k
  BOOL rc = FALSE;
4506
8.62k
  size_t start = 0;
4507
8.62k
  size_t end = 0;
4508
8.62k
  size_t len = 0;
4509
8.62k
  UINT16 numberCapabilities = 0;
4510
8.62k
  UINT16 count = 0;
4511
4512
#ifdef WITH_DEBUG_CAPABILITIES
4513
  const size_t capstart = Stream_GetPosition(s);
4514
#endif
4515
4516
8.62k
  WINPR_ASSERT(s);
4517
8.62k
  WINPR_ASSERT(settings);
4518
4519
8.62k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4520
0
    return FALSE;
4521
4522
8.62k
  Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4523
8.62k
  Stream_Seek(s, 2);                         /* pad2Octets (2 bytes) */
4524
8.62k
  count = numberCapabilities;
4525
4526
8.62k
  start = Stream_GetPosition(s);
4527
95.5k
  while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4528
91.8k
  {
4529
91.8k
    UINT16 type = 0;
4530
91.8k
    UINT16 length = 0;
4531
91.8k
    wStream subbuffer;
4532
91.8k
    wStream* sub = NULL;
4533
4534
91.8k
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4535
1.12k
      goto fail;
4536
90.7k
    sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4537
90.7k
    if (!Stream_SafeSeek(s, length - 4))
4538
1.68k
      goto fail;
4539
4540
89.0k
    if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4541
2.12k
      goto fail;
4542
4543
86.8k
    if (!rdp_apply_from_received(type, settings, rcvSettings))
4544
0
      goto fail;
4545
86.8k
    numberCapabilities--;
4546
86.8k
  }
4547
4548
3.69k
  end = Stream_GetPosition(s);
4549
3.69k
  len = end - start;
4550
4551
3.69k
  if (numberCapabilities)
4552
955
  {
4553
955
    WLog_Print(log, WLOG_ERROR,
4554
955
               "strange we haven't read the number of announced capacity sets, read=%d "
4555
955
               "expected=%" PRIu16 "",
4556
955
               count - numberCapabilities, count);
4557
955
  }
4558
4559
#ifdef WITH_DEBUG_CAPABILITIES
4560
  rdp_print_capability_sets(log, s, capstart, TRUE);
4561
#endif
4562
4563
3.69k
  if (len > totalLength)
4564
541
  {
4565
541
    WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIdz,
4566
541
               totalLength, len);
4567
541
    goto fail;
4568
541
  }
4569
3.14k
  rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4570
8.62k
fail:
4571
8.62k
  return rc;
4572
3.14k
}
4573
4574
BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4575
18.2k
{
4576
18.2k
  WINPR_ASSERT(rdp);
4577
18.2k
  WINPR_ASSERT(rdp->context);
4578
4579
18.2k
  if (!rdp_read_header(rdp, s, length, pChannelId))
4580
18.1k
    return FALSE;
4581
4582
72
  if (freerdp_shall_disconnect_context(rdp->context))
4583
54
    return TRUE;
4584
4585
18
  if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4586
17
  {
4587
17
    UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4588
4589
17
    if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4590
17
    {
4591
17
      WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4592
17
                 *pChannelId);
4593
17
      return FALSE;
4594
17
    }
4595
17
  }
4596
4597
1
  return TRUE;
4598
18
}
4599
4600
BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4601
18.2k
{
4602
18.2k
  UINT16 lengthSourceDescriptor = 0;
4603
18.2k
  UINT16 lengthCombinedCapabilities = 0;
4604
4605
18.2k
  WINPR_ASSERT(rdp);
4606
18.2k
  WINPR_ASSERT(rdp->settings);
4607
18.2k
  WINPR_ASSERT(rdp->context);
4608
18.2k
  WINPR_ASSERT(s);
4609
4610
18.2k
  rdp->settings->PduSource = pduSource;
4611
4612
18.2k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4613
9.01k
    return FALSE;
4614
4615
9.21k
  Stream_Read_UINT32(s, rdp->settings->ShareId);     /* shareId (4 bytes) */
4616
9.21k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4617
9.21k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4618
4619
9.21k
  if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4620
9.21k
      !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4621
4.00k
    return FALSE;
4622
4623
  /* capabilitySets */
4624
5.20k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4625
5.20k
                                lengthCombinedCapabilities))
4626
3.59k
  {
4627
3.59k
    WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4628
3.59k
    return FALSE;
4629
3.59k
  }
4630
4631
1.60k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4632
452
    return FALSE;
4633
4634
  /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4635
   * is ignored by client */
4636
1.15k
  Stream_Seek_UINT32(s); /* SessionId */
4637
4638
1.15k
  {
4639
1.15k
    rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4640
1.15k
    secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4641
1.15k
  }
4642
4643
1.15k
  return tpkt_ensure_stream_consumed(rdp->log, s, length);
4644
1.60k
}
4645
4646
static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4647
0
{
4648
0
  size_t bm = 0;
4649
0
  size_t em = 0;
4650
0
  size_t lm = 0;
4651
0
  UINT16 numberCapabilities = 0;
4652
0
  size_t lengthCombinedCapabilities = 0;
4653
4654
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
4655
0
    return FALSE;
4656
4657
0
  Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4658
0
  Stream_Write_UINT16(s, 4);                 /* lengthSourceDescriptor (2 bytes) */
4659
0
  lm = Stream_GetPosition(s);
4660
0
  Stream_Seek_UINT16(s);     /* lengthCombinedCapabilities (2 bytes) */
4661
0
  Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4662
0
  bm = Stream_GetPosition(s);
4663
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4664
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4665
0
  numberCapabilities = 14;
4666
4667
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4668
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4669
0
      !rdp_write_order_capability_set(log, s, settings) ||
4670
0
      !rdp_write_pointer_capability_set(log, s, settings) ||
4671
0
      !rdp_write_input_capability_set(log, s, settings) ||
4672
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4673
0
      !rdp_write_share_capability_set(log, s, settings) ||
4674
0
      !rdp_write_font_capability_set(log, s, settings) ||
4675
0
      !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4676
0
      !rdp_write_large_pointer_capability_set(log, s, settings) ||
4677
0
      !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4678
0
      !rdp_write_surface_commands_capability_set(log, s, settings) ||
4679
0
      !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4680
0
      !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4681
0
  {
4682
0
    return FALSE;
4683
0
  }
4684
4685
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4686
0
  {
4687
0
    numberCapabilities++;
4688
4689
0
    if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4690
0
      return FALSE;
4691
0
  }
4692
4693
0
  if (settings->RemoteApplicationMode)
4694
0
  {
4695
0
    numberCapabilities += 2;
4696
4697
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4698
0
        !rdp_write_window_list_capability_set(log, s, settings))
4699
0
      return FALSE;
4700
0
  }
4701
4702
0
  em = Stream_GetPosition(s);
4703
0
  Stream_SetPosition(s, lm); /* go back to lengthCombinedCapabilities */
4704
0
  lengthCombinedCapabilities = (em - bm);
4705
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4706
0
    return FALSE;
4707
0
  Stream_Write_UINT16(
4708
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4709
0
  Stream_SetPosition(s, bm);                  /* go back to numberCapabilities */
4710
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4711
#ifdef WITH_DEBUG_CAPABILITIES
4712
  rdp_print_capability_sets(log, s, bm, FALSE);
4713
#endif
4714
0
  Stream_SetPosition(s, em);
4715
0
  Stream_Write_UINT32(s, 0); /* sessionId */
4716
0
  return TRUE;
4717
0
}
4718
4719
BOOL rdp_send_demand_active(rdpRdp* rdp)
4720
0
{
4721
0
  UINT16 sec_flags = 0;
4722
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4723
0
  BOOL status = 0;
4724
4725
0
  if (!s)
4726
0
    return FALSE;
4727
4728
0
  rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4729
0
  status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4730
0
           rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4731
0
  Stream_Release(s);
4732
0
  return status;
4733
0
}
4734
4735
BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4736
18.2k
{
4737
18.2k
  rdpSettings* settings = NULL;
4738
18.2k
  UINT16 lengthSourceDescriptor = 0;
4739
18.2k
  UINT16 lengthCombinedCapabilities = 0;
4740
4741
18.2k
  WINPR_ASSERT(rdp);
4742
18.2k
  WINPR_ASSERT(s);
4743
18.2k
  settings = rdp->settings;
4744
18.2k
  WINPR_ASSERT(settings);
4745
4746
18.2k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4747
10.5k
    return FALSE;
4748
4749
7.67k
  Stream_Seek_UINT32(s);                             /* shareId (4 bytes) */
4750
7.67k
  Stream_Seek_UINT16(s);                             /* originatorId (2 bytes) */
4751
7.67k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4752
7.67k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4753
4754
7.67k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4755
4.25k
    return FALSE;
4756
4757
3.41k
  Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4758
3.41k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4759
3.41k
                                lengthCombinedCapabilities))
4760
1.87k
    return FALSE;
4761
4762
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4763
1.53k
  {
4764
    /* client does not support surface commands */
4765
1.53k
    settings->SurfaceCommandsEnabled = FALSE;
4766
1.53k
    settings->SurfaceFrameMarkerEnabled = FALSE;
4767
1.53k
  }
4768
4769
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4770
1.53k
  {
4771
    /* client does not support frame acks */
4772
1.53k
    settings->FrameAcknowledge = 0;
4773
1.53k
  }
4774
4775
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4776
1.53k
  {
4777
    /* client does not support bitmap cache v3 */
4778
1.53k
    settings->BitmapCacheV3Enabled = FALSE;
4779
1.53k
  }
4780
4781
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4782
1.53k
  {
4783
    /* client does not support bitmap codecs */
4784
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4785
0
      return FALSE;
4786
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4787
0
      return FALSE;
4788
1.53k
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4789
0
      return FALSE;
4790
1.53k
  }
4791
4792
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4793
1.53k
  {
4794
    /* client does not support multi fragment updates - make sure packages are not fragmented */
4795
1.53k
    settings->MultifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
4796
1.53k
  }
4797
4798
1.54k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4799
1.53k
  {
4800
    /* client does not support large pointers */
4801
1.53k
    settings->LargePointerFlag = 0;
4802
1.53k
  }
4803
4804
1.54k
  return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4805
1.54k
}
4806
4807
static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4808
0
{
4809
0
  size_t bm = 0;
4810
0
  size_t em = 0;
4811
0
  size_t lm = 0;
4812
0
  UINT16 numberCapabilities = 0;
4813
0
  UINT16 lengthSourceDescriptor = 0;
4814
0
  size_t lengthCombinedCapabilities = 0;
4815
0
  BOOL ret = 0;
4816
4817
0
  WINPR_ASSERT(settings);
4818
4819
0
  lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4820
0
  Stream_Write_UINT32(s, settings->ShareId);      /* shareId (4 bytes) */
4821
0
  Stream_Write_UINT16(s, 0x03EA);                 /* originatorId (2 bytes) */
4822
0
  Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4823
0
  lm = Stream_GetPosition(s);
4824
0
  Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4825
0
  Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4826
0
  bm = Stream_GetPosition(s);
4827
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4828
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4829
  /* Capability Sets */
4830
0
  numberCapabilities = 15;
4831
4832
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4833
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4834
0
      !rdp_write_order_capability_set(log, s, settings))
4835
0
    return FALSE;
4836
4837
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4838
0
    ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4839
0
  else
4840
0
    ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4841
4842
0
  if (!ret)
4843
0
    return FALSE;
4844
4845
0
  if (!rdp_write_pointer_capability_set(log, s, settings) ||
4846
0
      !rdp_write_input_capability_set(log, s, settings) ||
4847
0
      !rdp_write_brush_capability_set(log, s, settings) ||
4848
0
      !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4849
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4850
0
      !rdp_write_sound_capability_set(log, s, settings) ||
4851
0
      !rdp_write_share_capability_set(log, s, settings) ||
4852
0
      !rdp_write_font_capability_set(log, s, settings) ||
4853
0
      !rdp_write_control_capability_set(log, s, settings) ||
4854
0
      !rdp_write_color_cache_capability_set(log, s, settings) ||
4855
0
      !rdp_write_window_activation_capability_set(log, s, settings))
4856
0
  {
4857
0
    return FALSE;
4858
0
  }
4859
4860
0
  {
4861
0
    numberCapabilities++;
4862
4863
0
    if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4864
0
      return FALSE;
4865
0
  }
4866
4867
0
  if (settings->DrawNineGridEnabled)
4868
0
  {
4869
0
    numberCapabilities++;
4870
4871
0
    if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4872
0
      return FALSE;
4873
0
  }
4874
4875
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4876
0
  {
4877
0
    if (settings->LargePointerFlag)
4878
0
    {
4879
0
      numberCapabilities++;
4880
4881
0
      if (!rdp_write_large_pointer_capability_set(log, s, settings))
4882
0
        return FALSE;
4883
0
    }
4884
0
  }
4885
4886
0
  if (settings->RemoteApplicationMode)
4887
0
  {
4888
0
    numberCapabilities += 2;
4889
4890
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4891
0
        !rdp_write_window_list_capability_set(log, s, settings))
4892
0
      return FALSE;
4893
0
  }
4894
4895
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4896
0
  {
4897
0
    numberCapabilities++;
4898
4899
0
    if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4900
0
      return FALSE;
4901
0
  }
4902
4903
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4904
0
  {
4905
0
    numberCapabilities++;
4906
4907
0
    if (!rdp_write_surface_commands_capability_set(log, s, settings))
4908
0
      return FALSE;
4909
0
  }
4910
4911
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4912
0
  {
4913
0
    numberCapabilities++;
4914
4915
0
    if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4916
0
      return FALSE;
4917
0
  }
4918
4919
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4920
0
    settings->FrameAcknowledge = 0;
4921
4922
0
  if (settings->FrameAcknowledge)
4923
0
  {
4924
0
    numberCapabilities++;
4925
4926
0
    if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4927
0
      return FALSE;
4928
0
  }
4929
4930
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4931
0
  {
4932
0
    if (settings->BitmapCacheV3CodecId != 0)
4933
0
    {
4934
0
      numberCapabilities++;
4935
4936
0
      if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4937
0
        return FALSE;
4938
0
    }
4939
0
  }
4940
4941
0
  em = Stream_GetPosition(s);
4942
0
  Stream_SetPosition(s, lm); /* go back to lengthCombinedCapabilities */
4943
0
  lengthCombinedCapabilities = (em - bm);
4944
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4945
0
    return FALSE;
4946
0
  Stream_Write_UINT16(
4947
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4948
0
  Stream_SetPosition(s, bm);                  /* go back to numberCapabilities */
4949
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4950
#ifdef WITH_DEBUG_CAPABILITIES
4951
  rdp_print_capability_sets(log, s, bm, FALSE);
4952
#endif
4953
0
  Stream_SetPosition(s, em);
4954
4955
0
  return TRUE;
4956
0
}
4957
4958
BOOL rdp_send_confirm_active(rdpRdp* rdp)
4959
0
{
4960
0
  UINT16 sec_flags = 0;
4961
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4962
0
  BOOL status = 0;
4963
4964
0
  if (!s)
4965
0
    return FALSE;
4966
4967
0
  status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4968
0
           rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4969
0
  Stream_Release(s);
4970
0
  return status;
4971
0
}
4972
4973
const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
4974
0
{
4975
0
  char prefix[16] = { 0 };
4976
4977
0
  (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
4978
0
  winpr_str_append(prefix, buffer, len, "");
4979
0
  if ((flags & INPUT_FLAG_SCANCODES) != 0)
4980
0
    winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
4981
0
  if ((flags & INPUT_FLAG_MOUSEX) != 0)
4982
0
    winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
4983
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
4984
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
4985
0
  if ((flags & INPUT_FLAG_UNICODE) != 0)
4986
0
    winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
4987
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
4988
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
4989
0
  if ((flags & INPUT_FLAG_UNUSED1) != 0)
4990
0
    winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
4991
0
  if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
4992
0
    winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
4993
0
  if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
4994
0
    winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
4995
0
  if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
4996
0
    winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
4997
0
  winpr_str_append("]", buffer, len, "");
4998
0
  return buffer;
4999
0
}