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