1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * RAIL common functions
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
7  * Copyright 2011 Vic Lee
8  * Copyright 2015 Thincast Technologies GmbH
9  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *     http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 #include "rail_common.h"
24 
25 #include <winpr/crt.h>
26 #include <freerdp/channels/log.h>
27 
28 #define TAG CHANNELS_TAG("rail.common")
29 
30 static const char* const RAIL_ORDER_TYPE_STRINGS[] = { "",
31 	                                                   "Execute",
32 	                                                   "Activate",
33 	                                                   "System Parameters Update",
34 	                                                   "System Command",
35 	                                                   "Handshake",
36 	                                                   "Notify Event",
37 	                                                   "",
38 	                                                   "Window Move",
39 	                                                   "Local Move/Size",
40 	                                                   "Min Max Info",
41 	                                                   "Client Status",
42 	                                                   "System Menu",
43 	                                                   "Language Bar Info",
44 	                                                   "Get Application ID Request",
45 	                                                   "Get Application ID Response",
46 	                                                   "Execute Result",
47 	                                                   "",
48 	                                                   "",
49 	                                                   "",
50 	                                                   "",
51 	                                                   "",
52 	                                                   "" };
53 
rail_get_order_type_string(UINT16 orderType)54 const char* rail_get_order_type_string(UINT16 orderType)
55 {
56 	UINT32 index = ((orderType & 0xF0) >> 3) + (orderType & 0x0F);
57 	if (index >= ARRAYSIZE(RAIL_ORDER_TYPE_STRINGS))
58 		return "UNKNOWN";
59 
60 	return RAIL_ORDER_TYPE_STRINGS[index];
61 }
62 
63 /**
64  * Function description
65  *
66  * @return 0 on success, otherwise a Win32 error code
67  */
rail_read_pdu_header(wStream * s,UINT16 * orderType,UINT16 * orderLength)68 UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength)
69 {
70 	if (!s || !orderType || !orderLength)
71 		return ERROR_INVALID_PARAMETER;
72 
73 	if (Stream_GetRemainingLength(s) < 4)
74 		return ERROR_INVALID_DATA;
75 
76 	Stream_Read_UINT16(s, *orderType);   /* orderType (2 bytes) */
77 	Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */
78 	return CHANNEL_RC_OK;
79 }
80 
rail_write_pdu_header(wStream * s,UINT16 orderType,UINT16 orderLength)81 void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength)
82 {
83 	Stream_Write_UINT16(s, orderType);   /* orderType (2 bytes) */
84 	Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */
85 }
86 
rail_pdu_init(size_t length)87 wStream* rail_pdu_init(size_t length)
88 {
89 	wStream* s;
90 	s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH);
91 
92 	if (!s)
93 		return NULL;
94 
95 	Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
96 	return s;
97 }
98 
99 /**
100  * Function description
101  *
102  * @return 0 on success, otherwise a Win32 error code
103  */
rail_read_handshake_order(wStream * s,RAIL_HANDSHAKE_ORDER * handshake)104 UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
105 {
106 	if (Stream_GetRemainingLength(s) < 4)
107 		return ERROR_INVALID_DATA;
108 
109 	Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
110 	return CHANNEL_RC_OK;
111 }
112 
rail_write_handshake_order(wStream * s,const RAIL_HANDSHAKE_ORDER * handshake)113 void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake)
114 {
115 	Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
116 }
117 
118 /**
119  * Function description
120  *
121  * @return 0 on success, otherwise a Win32 error code
122  */
rail_read_handshake_ex_order(wStream * s,RAIL_HANDSHAKE_EX_ORDER * handshakeEx)123 UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
124 {
125 	if (Stream_GetRemainingLength(s) < 8)
126 		return ERROR_INVALID_DATA;
127 
128 	Stream_Read_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
129 	Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
130 	return CHANNEL_RC_OK;
131 }
132 
rail_write_handshake_ex_order(wStream * s,const RAIL_HANDSHAKE_EX_ORDER * handshakeEx)133 void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
134 {
135 	Stream_Write_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
136 	Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
137 }
138 
139 /**
140  * Function description
141  *
142  * @return 0 on success, otherwise a Win32 error code
143  */
rail_write_unicode_string(wStream * s,const RAIL_UNICODE_STRING * unicode_string)144 UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
145 {
146 	if (!s || !unicode_string)
147 		return ERROR_INVALID_PARAMETER;
148 
149 	if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
150 	{
151 		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
152 		return CHANNEL_RC_NO_MEMORY;
153 	}
154 
155 	Stream_Write_UINT16(s, unicode_string->length);                  /* cbString (2 bytes) */
156 	Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
157 	return CHANNEL_RC_OK;
158 }
159 
160 /**
161  * Function description
162  *
163  * @return 0 on success, otherwise a Win32 error code
164  */
rail_write_unicode_string_value(wStream * s,const RAIL_UNICODE_STRING * unicode_string)165 UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
166 {
167 	size_t length;
168 
169 	if (!s || !unicode_string)
170 		return ERROR_INVALID_PARAMETER;
171 
172 	length = unicode_string->length;
173 
174 	if (length > 0)
175 	{
176 		if (!Stream_EnsureRemainingCapacity(s, length))
177 		{
178 			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
179 			return CHANNEL_RC_NO_MEMORY;
180 		}
181 
182 		Stream_Write(s, unicode_string->string, length); /* string */
183 	}
184 
185 	return CHANNEL_RC_OK;
186 }
187 
188 /**
189  * Function description
190  *
191  * @return 0 on success, otherwise a Win32 error code
192  */
rail_read_high_contrast(wStream * s,RAIL_HIGH_CONTRAST * highContrast)193 static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
194 {
195 	if (!s || !highContrast)
196 		return ERROR_INVALID_PARAMETER;
197 
198 	if (Stream_GetRemainingLength(s) < 8)
199 		return ERROR_INVALID_DATA;
200 
201 	Stream_Read_UINT32(s, highContrast->flags);             /* flags (4 bytes) */
202 	Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
203 
204 	if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
205 		return ERROR_INTERNAL_ERROR;
206 	return CHANNEL_RC_OK;
207 }
208 
209 /**
210  * Function description
211  *
212  * @return 0 on success, otherwise a Win32 error code
213  */
rail_write_high_contrast(wStream * s,const RAIL_HIGH_CONTRAST * highContrast)214 static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
215 {
216 	UINT32 colorSchemeLength;
217 
218 	if (!s || !highContrast)
219 		return ERROR_INVALID_PARAMETER;
220 
221 	if (!Stream_EnsureRemainingCapacity(s, 8))
222 		return CHANNEL_RC_NO_MEMORY;
223 
224 	colorSchemeLength = highContrast->colorScheme.length + 2;
225 	Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
226 	Stream_Write_UINT32(s, colorSchemeLength);   /* colorSchemeLength (4 bytes) */
227 	return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
228 }
229 
230 /**
231  * Function description
232  *
233  * @return 0 on success, otherwise a Win32 error code
234  */
rail_read_filterkeys(wStream * s,TS_FILTERKEYS * filterKeys)235 static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
236 {
237 	if (!s || !filterKeys)
238 		return ERROR_INVALID_PARAMETER;
239 
240 	if (Stream_GetRemainingLength(s) < 20)
241 		return ERROR_INVALID_DATA;
242 
243 	Stream_Read_UINT32(s, filterKeys->Flags);
244 	Stream_Read_UINT32(s, filterKeys->WaitTime);
245 	Stream_Read_UINT32(s, filterKeys->DelayTime);
246 	Stream_Read_UINT32(s, filterKeys->RepeatTime);
247 	Stream_Read_UINT32(s, filterKeys->BounceTime);
248 	return CHANNEL_RC_OK;
249 }
250 
251 /**
252  * Function description
253  *
254  * @return 0 on success, otherwise a Win32 error code
255  */
rail_write_filterkeys(wStream * s,const TS_FILTERKEYS * filterKeys)256 static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
257 {
258 	if (!s || !filterKeys)
259 		return ERROR_INVALID_PARAMETER;
260 
261 	if (!Stream_EnsureRemainingCapacity(s, 20))
262 		return CHANNEL_RC_NO_MEMORY;
263 
264 	Stream_Write_UINT32(s, filterKeys->Flags);
265 	Stream_Write_UINT32(s, filterKeys->WaitTime);
266 	Stream_Write_UINT32(s, filterKeys->DelayTime);
267 	Stream_Write_UINT32(s, filterKeys->RepeatTime);
268 	Stream_Write_UINT32(s, filterKeys->BounceTime);
269 	return CHANNEL_RC_OK;
270 }
271 
272 /**
273  * Function description
274  *
275  * @return 0 on success, otherwise a Win32 error code
276  */
rail_read_sysparam_order(wStream * s,RAIL_SYSPARAM_ORDER * sysparam,BOOL extendedSpiSupported)277 UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
278 {
279 	BYTE body;
280 	UINT error = CHANNEL_RC_OK;
281 
282 	if (!s || !sysparam)
283 		return ERROR_INVALID_PARAMETER;
284 
285 	if (Stream_GetRemainingLength(s) < 5)
286 	{
287 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
288 		return ERROR_INVALID_DATA;
289 	}
290 
291 	Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
292 
293 	sysparam->params = 0; /* bitflags of received params */
294 
295 	switch (sysparam->param)
296 	{
297 		/* Client sysparams */
298 		case SPI_SET_DRAG_FULL_WINDOWS:
299 			sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
300 			Stream_Read_UINT8(s, body); /* body (1 byte) */
301 			sysparam->dragFullWindows = body != 0;
302 			break;
303 
304 		case SPI_SET_KEYBOARD_CUES:
305 			sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
306 			Stream_Read_UINT8(s, body); /* body (1 byte) */
307 			sysparam->keyboardCues = body != 0;
308 			break;
309 
310 		case SPI_SET_KEYBOARD_PREF:
311 			sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
312 			Stream_Read_UINT8(s, body); /* body (1 byte) */
313 			sysparam->keyboardPref = body != 0;
314 			break;
315 
316 		case SPI_SET_MOUSE_BUTTON_SWAP:
317 			sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
318 			Stream_Read_UINT8(s, body); /* body (1 byte) */
319 			sysparam->mouseButtonSwap = body != 0;
320 			break;
321 
322 		case SPI_SET_WORK_AREA:
323 			sysparam->params |= SPI_MASK_SET_WORK_AREA;
324 
325 			if (Stream_GetRemainingLength(s) < 8)
326 			{
327 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
328 				return ERROR_INVALID_DATA;
329 			}
330 
331 			Stream_Read_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
332 			Stream_Read_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
333 			Stream_Read_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
334 			Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
335 			break;
336 
337 		case SPI_DISPLAY_CHANGE:
338 			sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
339 
340 			if (Stream_GetRemainingLength(s) < 8)
341 			{
342 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
343 				return ERROR_INVALID_DATA;
344 			}
345 
346 			Stream_Read_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
347 			Stream_Read_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
348 			Stream_Read_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
349 			Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
350 			break;
351 
352 		case SPI_TASKBAR_POS:
353 			sysparam->params |= SPI_MASK_TASKBAR_POS;
354 
355 			if (Stream_GetRemainingLength(s) < 8)
356 			{
357 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
358 				return ERROR_INVALID_DATA;
359 			}
360 
361 			Stream_Read_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
362 			Stream_Read_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
363 			Stream_Read_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
364 			Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
365 			break;
366 
367 		case SPI_SET_HIGH_CONTRAST:
368 			sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
369 			if (Stream_GetRemainingLength(s) < 8)
370 			{
371 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
372 				return ERROR_INVALID_DATA;
373 			}
374 
375 			error = rail_read_high_contrast(s, &sysparam->highContrast);
376 			break;
377 
378 		case SPI_SETCARETWIDTH:
379 			sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
380 
381 			if (!extendedSpiSupported)
382 				return ERROR_INVALID_DATA;
383 
384 			if (Stream_GetRemainingLength(s) < 4)
385 			{
386 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
387 				return ERROR_INVALID_DATA;
388 			}
389 
390 			Stream_Read_UINT32(s, sysparam->caretWidth);
391 
392 			if (sysparam->caretWidth < 0x0001)
393 				return ERROR_INVALID_DATA;
394 
395 			break;
396 
397 		case SPI_SETSTICKYKEYS:
398 			sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
399 
400 			if (!extendedSpiSupported)
401 				return ERROR_INVALID_DATA;
402 
403 			if (Stream_GetRemainingLength(s) < 4)
404 			{
405 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
406 				return ERROR_INVALID_DATA;
407 			}
408 
409 			Stream_Read_UINT32(s, sysparam->stickyKeys);
410 			break;
411 
412 		case SPI_SETTOGGLEKEYS:
413 			sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
414 
415 			if (!extendedSpiSupported)
416 				return ERROR_INVALID_DATA;
417 
418 			if (Stream_GetRemainingLength(s) < 4)
419 			{
420 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
421 				return ERROR_INVALID_DATA;
422 			}
423 
424 			Stream_Read_UINT32(s, sysparam->toggleKeys);
425 			break;
426 
427 		case SPI_SETFILTERKEYS:
428 			sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
429 
430 			if (!extendedSpiSupported)
431 				return ERROR_INVALID_DATA;
432 
433 			if (Stream_GetRemainingLength(s) < 20)
434 			{
435 				WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
436 				return ERROR_INVALID_DATA;
437 			}
438 
439 			error = rail_read_filterkeys(s, &sysparam->filterKeys);
440 			break;
441 
442 		/* Server sysparams */
443 		case SPI_SETSCREENSAVEACTIVE:
444 			sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
445 
446 			Stream_Read_UINT8(s, body); /* body (1 byte) */
447 			sysparam->setScreenSaveActive = body != 0;
448 			break;
449 
450 		case SPI_SETSCREENSAVESECURE:
451 			sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
452 
453 			Stream_Read_UINT8(s, body); /* body (1 byte) */
454 			sysparam->setScreenSaveSecure = body != 0;
455 			break;
456 
457 		default:
458 			break;
459 	}
460 
461 	return CHANNEL_RC_OK;
462 }
463 
464 /**
465  * Function description
466  *
467  * @return 0 on success, otherwise a Win32 err2or code
468  */
rail_write_sysparam_order(wStream * s,const RAIL_SYSPARAM_ORDER * sysparam,BOOL extendedSpiSupported)469 UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
470                                BOOL extendedSpiSupported)
471 {
472 	BYTE body;
473 	UINT error = CHANNEL_RC_OK;
474 
475 	if (!s || !sysparam)
476 		return ERROR_INVALID_PARAMETER;
477 
478 	if (!Stream_EnsureRemainingCapacity(s, 12))
479 		return CHANNEL_RC_NO_MEMORY;
480 
481 	Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
482 
483 	switch (sysparam->param)
484 	{
485 		/* Client sysparams */
486 		case SPI_SET_DRAG_FULL_WINDOWS:
487 			body = sysparam->dragFullWindows ? 1 : 0;
488 			Stream_Write_UINT8(s, body);
489 			break;
490 
491 		case SPI_SET_KEYBOARD_CUES:
492 			body = sysparam->keyboardCues ? 1 : 0;
493 			Stream_Write_UINT8(s, body);
494 			break;
495 
496 		case SPI_SET_KEYBOARD_PREF:
497 			body = sysparam->keyboardPref ? 1 : 0;
498 			Stream_Write_UINT8(s, body);
499 			break;
500 
501 		case SPI_SET_MOUSE_BUTTON_SWAP:
502 			body = sysparam->mouseButtonSwap ? 1 : 0;
503 			Stream_Write_UINT8(s, body);
504 			break;
505 
506 		case SPI_SET_WORK_AREA:
507 			Stream_Write_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
508 			Stream_Write_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
509 			Stream_Write_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
510 			Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
511 			break;
512 
513 		case SPI_DISPLAY_CHANGE:
514 			Stream_Write_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
515 			Stream_Write_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
516 			Stream_Write_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
517 			Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
518 			break;
519 
520 		case SPI_TASKBAR_POS:
521 			Stream_Write_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
522 			Stream_Write_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
523 			Stream_Write_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
524 			Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
525 			break;
526 
527 		case SPI_SET_HIGH_CONTRAST:
528 			error = rail_write_high_contrast(s, &sysparam->highContrast);
529 			break;
530 
531 		case SPI_SETCARETWIDTH:
532 			if (!extendedSpiSupported)
533 				return ERROR_INVALID_DATA;
534 
535 			if (sysparam->caretWidth < 0x0001)
536 				return ERROR_INVALID_DATA;
537 
538 			Stream_Write_UINT32(s, sysparam->caretWidth);
539 			break;
540 
541 		case SPI_SETSTICKYKEYS:
542 			if (!extendedSpiSupported)
543 				return ERROR_INVALID_DATA;
544 
545 			Stream_Write_UINT32(s, sysparam->stickyKeys);
546 			break;
547 
548 		case SPI_SETTOGGLEKEYS:
549 			if (!extendedSpiSupported)
550 				return ERROR_INVALID_DATA;
551 
552 			Stream_Write_UINT32(s, sysparam->toggleKeys);
553 			break;
554 
555 		case SPI_SETFILTERKEYS:
556 			if (!extendedSpiSupported)
557 				return ERROR_INVALID_DATA;
558 
559 			error = rail_write_filterkeys(s, &sysparam->filterKeys);
560 			break;
561 
562 		/* Server sysparams */
563 		case SPI_SETSCREENSAVEACTIVE:
564 			body = sysparam->setScreenSaveActive ? 1 : 0;
565 			Stream_Write_UINT8(s, body);
566 			break;
567 
568 		case SPI_SETSCREENSAVESECURE:
569 			body = sysparam->setScreenSaveSecure ? 1 : 0;
570 			Stream_Write_UINT8(s, body);
571 			break;
572 
573 		default:
574 			return ERROR_INVALID_PARAMETER;
575 	}
576 
577 	return error;
578 }
579 
rail_is_extended_spi_supported(UINT32 channelFlags)580 BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
581 {
582 	return channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED;
583 }
584