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