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