Coverage Report

Created: 2025-10-10 06:50

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