FreeRDP
Loading...
Searching...
No Matches
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 if (*orderLength < RAIL_PDU_HEADER_LENGTH)
114 {
115 WLog_ERR(TAG, "invalid order length %" PRIu16 " < RAIL_PDU_HEADER_LENGTH(%u)", *orderLength,
116 RAIL_PDU_HEADER_LENGTH);
117 return ERROR_INVALID_DATA;
118 }
119
120 if (!Stream_CheckAndLogRequiredLength(TAG, s, *orderLength - RAIL_PDU_HEADER_LENGTH))
121 return ERROR_INVALID_DATA;
122
123 if (*orderLength > RAIL_PDU_MAX_LENGTH)
124 {
125 WLog_ERR(TAG, "invalid order length %" PRIu16 " < RAIL_PDU_MAX_LENGTH(%llu)", *orderLength,
126 RAIL_PDU_MAX_LENGTH);
127 return ERROR_INVALID_DATA;
128 }
129
130 return CHANNEL_RC_OK;
131}
132
133BOOL rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength)
134{
135 if (!Stream_EnsureRemainingCapacity(s, 4))
136 return FALSE;
137 Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */
138 Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */
139 return TRUE;
140}
141
142wStream* rail_pdu_init(size_t length)
143{
144 wStream* s = Stream_New(nullptr, length + RAIL_PDU_HEADER_LENGTH);
145
146 if (!s)
147 return nullptr;
148
149 Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
150 return s;
151}
152
158UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
159{
160 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
161 return ERROR_INVALID_DATA;
162
163 Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
164 return CHANNEL_RC_OK;
165}
166
167void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake)
168{
169 WINPR_ASSERT(s);
170 WINPR_ASSERT(handshake);
171 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, 4));
172 Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
173}
174
180UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
181{
182 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
183 return ERROR_INVALID_DATA;
184
185 Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
186 Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
187 return CHANNEL_RC_OK;
188}
189
190void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
191{
192 WINPR_ASSERT(s);
193 WINPR_ASSERT(handshakeEx);
194 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, 8));
195
196 Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
197 Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
198}
199
205static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
206{
207 if (!s || !highContrast)
208 return ERROR_INVALID_PARAMETER;
209
210 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
211 return ERROR_INVALID_DATA;
212
213 Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */
214 Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
215
216 if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
217 return ERROR_INTERNAL_ERROR;
218 return CHANNEL_RC_OK;
219}
220
226static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
227{
228 UINT32 colorSchemeLength = 0;
229
230 if (!s || !highContrast)
231 return ERROR_INVALID_PARAMETER;
232
233 if (!Stream_EnsureRemainingCapacity(s, 8))
234 return CHANNEL_RC_NO_MEMORY;
235
236 colorSchemeLength = highContrast->colorScheme.length + 2;
237 Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
238 Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
239 return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
240}
241
247static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
248{
249 if (!s || !filterKeys)
250 return ERROR_INVALID_PARAMETER;
251
252 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
253 return ERROR_INVALID_DATA;
254
255 Stream_Read_UINT32(s, filterKeys->Flags);
256 Stream_Read_UINT32(s, filterKeys->WaitTime);
257 Stream_Read_UINT32(s, filterKeys->DelayTime);
258 Stream_Read_UINT32(s, filterKeys->RepeatTime);
259 Stream_Read_UINT32(s, filterKeys->BounceTime);
260 return CHANNEL_RC_OK;
261}
262
268static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
269{
270 if (!s || !filterKeys)
271 return ERROR_INVALID_PARAMETER;
272
273 if (!Stream_EnsureRemainingCapacity(s, 20))
274 return CHANNEL_RC_NO_MEMORY;
275
276 Stream_Write_UINT32(s, filterKeys->Flags);
277 Stream_Write_UINT32(s, filterKeys->WaitTime);
278 Stream_Write_UINT32(s, filterKeys->DelayTime);
279 Stream_Write_UINT32(s, filterKeys->RepeatTime);
280 Stream_Write_UINT32(s, filterKeys->BounceTime);
281 return CHANNEL_RC_OK;
282}
283
289UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
290{
291 BYTE body = 0;
292 UINT error = CHANNEL_RC_OK;
293
294 if (!s || !sysparam)
295 return ERROR_INVALID_PARAMETER;
296
297 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
298 return ERROR_INVALID_DATA;
299
300 Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
301
302 sysparam->params = 0; /* bitflags of received params */
303
304 switch (sysparam->param)
305 {
306 /* Client sysparams */
307 case SPI_SET_DRAG_FULL_WINDOWS:
308 sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
309 Stream_Read_UINT8(s, body); /* body (1 byte) */
310 sysparam->dragFullWindows = body != 0;
311 break;
312
313 case SPI_SET_KEYBOARD_CUES:
314 sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
315 Stream_Read_UINT8(s, body); /* body (1 byte) */
316 sysparam->keyboardCues = body != 0;
317 break;
318
319 case SPI_SET_KEYBOARD_PREF:
320 sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
321 Stream_Read_UINT8(s, body); /* body (1 byte) */
322 sysparam->keyboardPref = body != 0;
323 break;
324
325 case SPI_SET_MOUSE_BUTTON_SWAP:
326 sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
327 Stream_Read_UINT8(s, body); /* body (1 byte) */
328 sysparam->mouseButtonSwap = body != 0;
329 break;
330
331 case SPI_SET_WORK_AREA:
332 sysparam->params |= SPI_MASK_SET_WORK_AREA;
333
334 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
335 return ERROR_INVALID_DATA;
336
337 Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
338 Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
339 Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
340 Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
341 break;
342
343 case SPI_DISPLAY_CHANGE:
344 sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
345
346 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
347 return ERROR_INVALID_DATA;
348
349 Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
350 Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
351 Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
352 Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
353 break;
354
355 case SPI_TASKBAR_POS:
356 sysparam->params |= SPI_MASK_TASKBAR_POS;
357
358 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
359 return ERROR_INVALID_DATA;
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_CheckAndLogRequiredLength(TAG, s, 8))
370 return ERROR_INVALID_DATA;
371
372 error = rail_read_high_contrast(s, &sysparam->highContrast);
373 break;
374
375 case SPI_SETCARETWIDTH:
376 sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
377
378 if (!extendedSpiSupported)
379 return ERROR_INVALID_DATA;
380
381 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
382 return ERROR_INVALID_DATA;
383
384 Stream_Read_UINT32(s, sysparam->caretWidth);
385
386 if (sysparam->caretWidth < 0x0001)
387 return ERROR_INVALID_DATA;
388
389 break;
390
391 case SPI_SETSTICKYKEYS:
392 sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
393
394 if (!extendedSpiSupported)
395 return ERROR_INVALID_DATA;
396
397 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
398 return ERROR_INVALID_DATA;
399
400 Stream_Read_UINT32(s, sysparam->stickyKeys);
401 break;
402
403 case SPI_SETTOGGLEKEYS:
404 sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
405
406 if (!extendedSpiSupported)
407 return ERROR_INVALID_DATA;
408
409 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
410 return ERROR_INVALID_DATA;
411
412 Stream_Read_UINT32(s, sysparam->toggleKeys);
413 break;
414
415 case SPI_SETFILTERKEYS:
416 sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
417
418 if (!extendedSpiSupported)
419 return ERROR_INVALID_DATA;
420
421 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
422 return ERROR_INVALID_DATA;
423
424 error = rail_read_filterkeys(s, &sysparam->filterKeys);
425 break;
426
427 /* Server sysparams */
428 case SPI_SETSCREENSAVEACTIVE:
429 sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
430
431 Stream_Read_UINT8(s, body); /* body (1 byte) */
432 sysparam->setScreenSaveActive = body != 0;
433 break;
434
435 case SPI_SETSCREENSAVESECURE:
436 sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
437
438 Stream_Read_UINT8(s, body); /* body (1 byte) */
439 sysparam->setScreenSaveSecure = body != 0;
440 break;
441
442 default:
443 break;
444 }
445
446 return error;
447}
448
449UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
450 BOOL extendedSpiSupported)
451{
452 BYTE body = 0;
453 UINT error = CHANNEL_RC_OK;
454
455 if (!s || !sysparam)
456 return ERROR_INVALID_PARAMETER;
457
458 if (!Stream_EnsureRemainingCapacity(s, 12))
459 return CHANNEL_RC_NO_MEMORY;
460
461 Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
462
463 switch (sysparam->param)
464 {
465 /* Client sysparams */
466 case SPI_SET_DRAG_FULL_WINDOWS:
467 body = sysparam->dragFullWindows ? 1 : 0;
468 Stream_Write_UINT8(s, body);
469 break;
470
471 case SPI_SET_KEYBOARD_CUES:
472 body = sysparam->keyboardCues ? 1 : 0;
473 Stream_Write_UINT8(s, body);
474 break;
475
476 case SPI_SET_KEYBOARD_PREF:
477 body = sysparam->keyboardPref ? 1 : 0;
478 Stream_Write_UINT8(s, body);
479 break;
480
481 case SPI_SET_MOUSE_BUTTON_SWAP:
482 body = sysparam->mouseButtonSwap ? 1 : 0;
483 Stream_Write_UINT8(s, body);
484 break;
485
486 case SPI_SET_WORK_AREA:
487 Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
488 Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
489 Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
490 Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
491 break;
492
493 case SPI_DISPLAY_CHANGE:
494 Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
495 Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
496 Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
497 Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
498 break;
499
500 case SPI_TASKBAR_POS:
501 Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
502 Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
503 Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
504 Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
505 break;
506
507 case SPI_SET_HIGH_CONTRAST:
508 error = rail_write_high_contrast(s, &sysparam->highContrast);
509 break;
510
511 case SPI_SETCARETWIDTH:
512 if (!extendedSpiSupported)
513 return ERROR_INVALID_DATA;
514
515 if (sysparam->caretWidth < 0x0001)
516 return ERROR_INVALID_DATA;
517
518 Stream_Write_UINT32(s, sysparam->caretWidth);
519 break;
520
521 case SPI_SETSTICKYKEYS:
522 if (!extendedSpiSupported)
523 return ERROR_INVALID_DATA;
524
525 Stream_Write_UINT32(s, sysparam->stickyKeys);
526 break;
527
528 case SPI_SETTOGGLEKEYS:
529 if (!extendedSpiSupported)
530 return ERROR_INVALID_DATA;
531
532 Stream_Write_UINT32(s, sysparam->toggleKeys);
533 break;
534
535 case SPI_SETFILTERKEYS:
536 if (!extendedSpiSupported)
537 return ERROR_INVALID_DATA;
538
539 error = rail_write_filterkeys(s, &sysparam->filterKeys);
540 break;
541
542 /* Server sysparams */
543 case SPI_SETSCREENSAVEACTIVE:
544 body = sysparam->setScreenSaveActive ? 1 : 0;
545 Stream_Write_UINT8(s, body);
546 break;
547
548 case SPI_SETSCREENSAVESECURE:
549 body = sysparam->setScreenSaveSecure ? 1 : 0;
550 Stream_Write_UINT8(s, body);
551 break;
552
553 default:
554 return ERROR_INVALID_PARAMETER;
555 }
556
557 return error;
558}
559
560BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
561{
562 return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) != 0;
563}
564
565const char* rail_handshake_ex_flags_to_string(UINT32 flags, char* buffer, size_t len)
566{
567 if (len < 1)
568 return nullptr;
569
570 (void)_snprintf(buffer, len, "{");
571 char* fbuffer = &buffer[1];
572 len--;
573
574 if (flags & TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF)
575 winpr_str_append("HIDEF", fbuffer, len, "|");
576 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED)
577 winpr_str_append("EXTENDED_SPI_SUPPORTED", fbuffer, len, "|");
578 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED)
579 winpr_str_append("SNAP_ARRANGE_SUPPORTED", fbuffer, len, "|");
580 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED)
581 winpr_str_append("TEXT_SCALE_SUPPORTED", fbuffer, len, "|");
582 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED)
583 winpr_str_append("CARET_BLINK_SUPPORTED", fbuffer, len, "|");
584 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED)
585 winpr_str_append("EXTENDED_SPI_2_SUPPORTED", fbuffer, len, "|");
586
587 char number[16] = WINPR_C_ARRAY_INIT;
588 (void)_snprintf(number, sizeof(number), "[0x%08" PRIx32 "]", flags);
589 winpr_str_append(number, buffer, len, "}");
590 return buffer;
591}