Coverage Report

Created: 2024-09-08 06:20

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