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