Coverage Report

Created: 2026-10-28 06:54

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