FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
rail_common.c
1
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
30const char* rail_get_order_type_string(UINT16 orderType)
31{
32 switch (orderType)
33 {
34 case TS_RAIL_ORDER_EXEC:
35 return "TS_RAIL_ORDER_EXEC";
36 case TS_RAIL_ORDER_ACTIVATE:
37 return "TS_RAIL_ORDER_ACTIVATE";
38 case TS_RAIL_ORDER_SYSPARAM:
39 return "TS_RAIL_ORDER_SYSPARAM";
40 case TS_RAIL_ORDER_SYSCOMMAND:
41 return "TS_RAIL_ORDER_SYSCOMMAND";
42 case TS_RAIL_ORDER_HANDSHAKE:
43 return "TS_RAIL_ORDER_HANDSHAKE";
44 case TS_RAIL_ORDER_NOTIFY_EVENT:
45 return "TS_RAIL_ORDER_NOTIFY_EVENT";
46 case TS_RAIL_ORDER_WINDOWMOVE:
47 return "TS_RAIL_ORDER_WINDOWMOVE";
48 case TS_RAIL_ORDER_LOCALMOVESIZE:
49 return "TS_RAIL_ORDER_LOCALMOVESIZE";
50 case TS_RAIL_ORDER_MINMAXINFO:
51 return "TS_RAIL_ORDER_MINMAXINFO";
52 case TS_RAIL_ORDER_CLIENTSTATUS:
53 return "TS_RAIL_ORDER_CLIENTSTATUS";
54 case TS_RAIL_ORDER_SYSMENU:
55 return "TS_RAIL_ORDER_SYSMENU";
56 case TS_RAIL_ORDER_LANGBARINFO:
57 return "TS_RAIL_ORDER_LANGBARINFO";
58 case TS_RAIL_ORDER_GET_APPID_REQ:
59 return "TS_RAIL_ORDER_GET_APPID_REQ";
60 case TS_RAIL_ORDER_GET_APPID_RESP:
61 return "TS_RAIL_ORDER_GET_APPID_RESP";
62 case TS_RAIL_ORDER_TASKBARINFO:
63 return "TS_RAIL_ORDER_TASKBARINFO";
64 case TS_RAIL_ORDER_LANGUAGEIMEINFO:
65 return "TS_RAIL_ORDER_LANGUAGEIMEINFO";
66 case TS_RAIL_ORDER_COMPARTMENTINFO:
67 return "TS_RAIL_ORDER_COMPARTMENTINFO";
68 case TS_RAIL_ORDER_HANDSHAKE_EX:
69 return "TS_RAIL_ORDER_HANDSHAKE_EX";
70 case TS_RAIL_ORDER_ZORDER_SYNC:
71 return "TS_RAIL_ORDER_ZORDER_SYNC";
72 case TS_RAIL_ORDER_CLOAK:
73 return "TS_RAIL_ORDER_CLOAK";
74 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
75 return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST";
76 case TS_RAIL_ORDER_SNAP_ARRANGE:
77 return "TS_RAIL_ORDER_SNAP_ARRANGE";
78 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
79 return "TS_RAIL_ORDER_GET_APPID_RESP_EX";
80 case TS_RAIL_ORDER_EXEC_RESULT:
81 return "TS_RAIL_ORDER_EXEC_RESULT";
82 case TS_RAIL_ORDER_TEXTSCALEINFO:
83 return "TS_RAIL_ORDER_TEXTSCALEINFO";
84 case TS_RAIL_ORDER_CARETBLINKINFO:
85 return "TS_RAIL_ORDER_CARETBLINKINFO";
86 default:
87 return "TS_RAIL_ORDER_UNKNOWN";
88 }
89}
90
91const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length)
92{
93 (void)_snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType),
94 orderType);
95 return buffer;
96}
97
103UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength)
104{
105 if (!s || !orderType || !orderLength)
106 return ERROR_INVALID_PARAMETER;
107
108 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
109 return ERROR_INVALID_DATA;
110
111 Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */
112 Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */
113 return CHANNEL_RC_OK;
114}
115
116void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength)
117{
118 Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */
119 Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */
120}
121
122wStream* rail_pdu_init(size_t length)
123{
124 wStream* s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH);
125
126 if (!s)
127 return NULL;
128
129 Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
130 return s;
131}
132
138UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
139{
140 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
141 return ERROR_INVALID_DATA;
142
143 Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
144 return CHANNEL_RC_OK;
145}
146
147void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake)
148{
149 Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
150}
151
157UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
158{
159 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
160 return ERROR_INVALID_DATA;
161
162 Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
163 Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
164 return CHANNEL_RC_OK;
165}
166
167void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
168{
169 Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
170 Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
171}
172
178UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
179{
180 if (!s || !unicode_string)
181 return ERROR_INVALID_PARAMETER;
182
183 if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
184 {
185 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
186 return CHANNEL_RC_NO_MEMORY;
187 }
188
189 Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
190 Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
191 return CHANNEL_RC_OK;
192}
193
199UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
200{
201 size_t length = 0;
202
203 if (!s || !unicode_string)
204 return ERROR_INVALID_PARAMETER;
205
206 length = unicode_string->length;
207
208 if (length > 0)
209 {
210 if (!Stream_EnsureRemainingCapacity(s, length))
211 {
212 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
213 return CHANNEL_RC_NO_MEMORY;
214 }
215
216 Stream_Write(s, unicode_string->string, length); /* string */
217 }
218
219 return CHANNEL_RC_OK;
220}
221
227static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
228{
229 if (!s || !highContrast)
230 return ERROR_INVALID_PARAMETER;
231
232 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
233 return ERROR_INVALID_DATA;
234
235 Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */
236 Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
237
238 if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
239 return ERROR_INTERNAL_ERROR;
240 return CHANNEL_RC_OK;
241}
242
248static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
249{
250 UINT32 colorSchemeLength = 0;
251
252 if (!s || !highContrast)
253 return ERROR_INVALID_PARAMETER;
254
255 if (!Stream_EnsureRemainingCapacity(s, 8))
256 return CHANNEL_RC_NO_MEMORY;
257
258 colorSchemeLength = highContrast->colorScheme.length + 2;
259 Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
260 Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
261 return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
262}
263
269static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
270{
271 if (!s || !filterKeys)
272 return ERROR_INVALID_PARAMETER;
273
274 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
275 return ERROR_INVALID_DATA;
276
277 Stream_Read_UINT32(s, filterKeys->Flags);
278 Stream_Read_UINT32(s, filterKeys->WaitTime);
279 Stream_Read_UINT32(s, filterKeys->DelayTime);
280 Stream_Read_UINT32(s, filterKeys->RepeatTime);
281 Stream_Read_UINT32(s, filterKeys->BounceTime);
282 return CHANNEL_RC_OK;
283}
284
290static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
291{
292 if (!s || !filterKeys)
293 return ERROR_INVALID_PARAMETER;
294
295 if (!Stream_EnsureRemainingCapacity(s, 20))
296 return CHANNEL_RC_NO_MEMORY;
297
298 Stream_Write_UINT32(s, filterKeys->Flags);
299 Stream_Write_UINT32(s, filterKeys->WaitTime);
300 Stream_Write_UINT32(s, filterKeys->DelayTime);
301 Stream_Write_UINT32(s, filterKeys->RepeatTime);
302 Stream_Write_UINT32(s, filterKeys->BounceTime);
303 return CHANNEL_RC_OK;
304}
305
311UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
312{
313 BYTE body = 0;
314 UINT error = CHANNEL_RC_OK;
315
316 if (!s || !sysparam)
317 return ERROR_INVALID_PARAMETER;
318
319 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
320 return ERROR_INVALID_DATA;
321
322 Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
323
324 sysparam->params = 0; /* bitflags of received params */
325
326 switch (sysparam->param)
327 {
328 /* Client sysparams */
329 case SPI_SET_DRAG_FULL_WINDOWS:
330 sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
331 Stream_Read_UINT8(s, body); /* body (1 byte) */
332 sysparam->dragFullWindows = body != 0;
333 break;
334
335 case SPI_SET_KEYBOARD_CUES:
336 sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
337 Stream_Read_UINT8(s, body); /* body (1 byte) */
338 sysparam->keyboardCues = body != 0;
339 break;
340
341 case SPI_SET_KEYBOARD_PREF:
342 sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
343 Stream_Read_UINT8(s, body); /* body (1 byte) */
344 sysparam->keyboardPref = body != 0;
345 break;
346
347 case SPI_SET_MOUSE_BUTTON_SWAP:
348 sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
349 Stream_Read_UINT8(s, body); /* body (1 byte) */
350 sysparam->mouseButtonSwap = body != 0;
351 break;
352
353 case SPI_SET_WORK_AREA:
354 sysparam->params |= SPI_MASK_SET_WORK_AREA;
355
356 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
357 return ERROR_INVALID_DATA;
358
359 Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
360 Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
361 Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
362 Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
363 break;
364
365 case SPI_DISPLAY_CHANGE:
366 sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
367
368 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
369 return ERROR_INVALID_DATA;
370
371 Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
372 Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
373 Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
374 Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
375 break;
376
377 case SPI_TASKBAR_POS:
378 sysparam->params |= SPI_MASK_TASKBAR_POS;
379
380 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
381 return ERROR_INVALID_DATA;
382
383 Stream_Read_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
384 Stream_Read_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
385 Stream_Read_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
386 Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
387 break;
388
389 case SPI_SET_HIGH_CONTRAST:
390 sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
391 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
392 return ERROR_INVALID_DATA;
393
394 error = rail_read_high_contrast(s, &sysparam->highContrast);
395 break;
396
397 case SPI_SETCARETWIDTH:
398 sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
399
400 if (!extendedSpiSupported)
401 return ERROR_INVALID_DATA;
402
403 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
404 return ERROR_INVALID_DATA;
405
406 Stream_Read_UINT32(s, sysparam->caretWidth);
407
408 if (sysparam->caretWidth < 0x0001)
409 return ERROR_INVALID_DATA;
410
411 break;
412
413 case SPI_SETSTICKYKEYS:
414 sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
415
416 if (!extendedSpiSupported)
417 return ERROR_INVALID_DATA;
418
419 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
420 return ERROR_INVALID_DATA;
421
422 Stream_Read_UINT32(s, sysparam->stickyKeys);
423 break;
424
425 case SPI_SETTOGGLEKEYS:
426 sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
427
428 if (!extendedSpiSupported)
429 return ERROR_INVALID_DATA;
430
431 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
432 return ERROR_INVALID_DATA;
433
434 Stream_Read_UINT32(s, sysparam->toggleKeys);
435 break;
436
437 case SPI_SETFILTERKEYS:
438 sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
439
440 if (!extendedSpiSupported)
441 return ERROR_INVALID_DATA;
442
443 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
444 return ERROR_INVALID_DATA;
445
446 error = rail_read_filterkeys(s, &sysparam->filterKeys);
447 break;
448
449 /* Server sysparams */
450 case SPI_SETSCREENSAVEACTIVE:
451 sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
452
453 Stream_Read_UINT8(s, body); /* body (1 byte) */
454 sysparam->setScreenSaveActive = body != 0;
455 break;
456
457 case SPI_SETSCREENSAVESECURE:
458 sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
459
460 Stream_Read_UINT8(s, body); /* body (1 byte) */
461 sysparam->setScreenSaveSecure = body != 0;
462 break;
463
464 default:
465 break;
466 }
467
468 return error;
469}
470
476UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
477 BOOL extendedSpiSupported)
478{
479 BYTE body = 0;
480 UINT error = CHANNEL_RC_OK;
481
482 if (!s || !sysparam)
483 return ERROR_INVALID_PARAMETER;
484
485 if (!Stream_EnsureRemainingCapacity(s, 12))
486 return CHANNEL_RC_NO_MEMORY;
487
488 Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
489
490 switch (sysparam->param)
491 {
492 /* Client sysparams */
493 case SPI_SET_DRAG_FULL_WINDOWS:
494 body = sysparam->dragFullWindows ? 1 : 0;
495 Stream_Write_UINT8(s, body);
496 break;
497
498 case SPI_SET_KEYBOARD_CUES:
499 body = sysparam->keyboardCues ? 1 : 0;
500 Stream_Write_UINT8(s, body);
501 break;
502
503 case SPI_SET_KEYBOARD_PREF:
504 body = sysparam->keyboardPref ? 1 : 0;
505 Stream_Write_UINT8(s, body);
506 break;
507
508 case SPI_SET_MOUSE_BUTTON_SWAP:
509 body = sysparam->mouseButtonSwap ? 1 : 0;
510 Stream_Write_UINT8(s, body);
511 break;
512
513 case SPI_SET_WORK_AREA:
514 Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
515 Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
516 Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
517 Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
518 break;
519
520 case SPI_DISPLAY_CHANGE:
521 Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
522 Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
523 Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
524 Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
525 break;
526
527 case SPI_TASKBAR_POS:
528 Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
529 Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
530 Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
531 Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
532 break;
533
534 case SPI_SET_HIGH_CONTRAST:
535 error = rail_write_high_contrast(s, &sysparam->highContrast);
536 break;
537
538 case SPI_SETCARETWIDTH:
539 if (!extendedSpiSupported)
540 return ERROR_INVALID_DATA;
541
542 if (sysparam->caretWidth < 0x0001)
543 return ERROR_INVALID_DATA;
544
545 Stream_Write_UINT32(s, sysparam->caretWidth);
546 break;
547
548 case SPI_SETSTICKYKEYS:
549 if (!extendedSpiSupported)
550 return ERROR_INVALID_DATA;
551
552 Stream_Write_UINT32(s, sysparam->stickyKeys);
553 break;
554
555 case SPI_SETTOGGLEKEYS:
556 if (!extendedSpiSupported)
557 return ERROR_INVALID_DATA;
558
559 Stream_Write_UINT32(s, sysparam->toggleKeys);
560 break;
561
562 case SPI_SETFILTERKEYS:
563 if (!extendedSpiSupported)
564 return ERROR_INVALID_DATA;
565
566 error = rail_write_filterkeys(s, &sysparam->filterKeys);
567 break;
568
569 /* Server sysparams */
570 case SPI_SETSCREENSAVEACTIVE:
571 body = sysparam->setScreenSaveActive ? 1 : 0;
572 Stream_Write_UINT8(s, body);
573 break;
574
575 case SPI_SETSCREENSAVESECURE:
576 body = sysparam->setScreenSaveSecure ? 1 : 0;
577 Stream_Write_UINT8(s, body);
578 break;
579
580 default:
581 return ERROR_INVALID_PARAMETER;
582 }
583
584 return error;
585}
586
587BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
588{
589 return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) ? TRUE : FALSE;
590}
591
592const char* rail_handshake_ex_flags_to_string(UINT32 flags, char* buffer, size_t len)
593{
594 if (len < 1)
595 return NULL;
596
597 (void)_snprintf(buffer, len, "{");
598 char* fbuffer = &buffer[1];
599 len--;
600
601 if (flags & TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF)
602 winpr_str_append("HIDEF", fbuffer, len, "|");
603 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED)
604 winpr_str_append("EXTENDED_SPI_SUPPORTED", fbuffer, len, "|");
605 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED)
606 winpr_str_append("SNAP_ARRANGE_SUPPORTED", fbuffer, len, "|");
607 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED)
608 winpr_str_append("TEXT_SCALE_SUPPORTED", fbuffer, len, "|");
609 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED)
610 winpr_str_append("CARET_BLINK_SUPPORTED", fbuffer, len, "|");
611 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED)
612 winpr_str_append("EXTENDED_SPI_2_SUPPORTED", fbuffer, len, "|");
613
614 char number[16] = { 0 };
615 (void)_snprintf(number, sizeof(number), "[0x%08" PRIx32 "]", flags);
616 winpr_str_append(number, buffer, len, "}");
617 return buffer;
618}