1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * RAIL Virtual Channel Plugin
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 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
11 * Copyright 2017 Thincast Technologies GmbH
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <winpr/crt.h>
31
32 #include <freerdp/types.h>
33 #include <freerdp/constants.h>
34
35 #include "rail_orders.h"
36 #include "rail_main.h"
37
rail_get_client_interface(railPlugin * rail)38 RailClientContext* rail_get_client_interface(railPlugin* rail)
39 {
40 RailClientContext* pInterface;
41
42 if (!rail)
43 return NULL;
44
45 pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
46 return pInterface;
47 }
48
49 /**
50 * Function description
51 *
52 * @return 0 on success, otherwise a Win32 error code
53 */
rail_send(railPlugin * rail,wStream * s)54 static UINT rail_send(railPlugin* rail, wStream* s)
55 {
56 UINT status;
57
58 if (!rail)
59 {
60 Stream_Free(s, TRUE);
61 return CHANNEL_RC_BAD_INIT_HANDLE;
62 }
63
64 status = rail->channelEntryPoints.pVirtualChannelWriteEx(
65 rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
66
67 if (status != CHANNEL_RC_OK)
68 {
69 Stream_Free(s, TRUE);
70 WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
71 WTSErrorToString(status), status);
72 }
73
74 return status;
75 }
76
77 /**
78 * Function description
79 *
80 * @return 0 on success, otherwise a Win32 error code
81 */
rail_send_channel_data(railPlugin * rail,wStream * src)82 UINT rail_send_channel_data(railPlugin* rail, wStream* src)
83 {
84 wStream* s;
85 size_t length;
86
87 if (!rail || !src)
88 return ERROR_INVALID_PARAMETER;
89
90 length = Stream_GetPosition(src);
91 s = Stream_New(NULL, length);
92
93 if (!s)
94 {
95 WLog_ERR(TAG, "Stream_New failed!");
96 return CHANNEL_RC_NO_MEMORY;
97 }
98
99 Stream_Write(s, Stream_Buffer(src), length);
100 return rail_send(rail, s);
101 }
102
103 /**
104 * Callback Interface
105 */
106
107 /**
108 * Function description
109 *
110 * @return 0 on success, otherwise a Win32 error code
111 */
rail_client_execute(RailClientContext * context,const RAIL_EXEC_ORDER * exec)112 static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec)
113 {
114 char* exeOrFile;
115 UINT error;
116 railPlugin* rail;
117 UINT16 flags;
118 RAIL_UNICODE_STRING ruExeOrFile = { 0 };
119 RAIL_UNICODE_STRING ruWorkingDir = { 0 };
120 RAIL_UNICODE_STRING ruArguments = { 0 };
121
122 if (!context || !exec)
123 return ERROR_INVALID_PARAMETER;
124
125 rail = (railPlugin*)context->handle;
126 exeOrFile = exec->RemoteApplicationProgram;
127 flags = exec->flags;
128
129 if (!exeOrFile)
130 return ERROR_INVALID_PARAMETER;
131
132 if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
133 &ruExeOrFile) || /* RemoteApplicationProgram */
134 !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
135 &ruWorkingDir) || /* ShellWorkingDirectory */
136 !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
137 &ruArguments)) /* RemoteApplicationCmdLine */
138 error = ERROR_INTERNAL_ERROR;
139 else
140 error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
141
142 free(ruExeOrFile.string);
143 free(ruWorkingDir.string);
144 free(ruArguments.string);
145 return error;
146 }
147
148 /**
149 * Function description
150 *
151 * @return 0 on success, otherwise a Win32 error code
152 */
rail_client_activate(RailClientContext * context,const RAIL_ACTIVATE_ORDER * activate)153 static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate)
154 {
155 railPlugin* rail;
156
157 if (!context || !activate)
158 return ERROR_INVALID_PARAMETER;
159
160 rail = (railPlugin*)context->handle;
161 return rail_send_client_activate_order(rail, activate);
162 }
163
164 /**
165 * Function description
166 *
167 * @return 0 on success, otherwise a Win32 error code
168 */
rail_send_client_sysparam(RailClientContext * context,RAIL_SYSPARAM_ORDER * sysparam)169 static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam)
170 {
171 wStream* s;
172 size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
173 railPlugin* rail;
174 UINT error;
175 BOOL extendedSpiSupported;
176
177 if (!context || !sysparam)
178 return ERROR_INVALID_PARAMETER;
179
180 rail = (railPlugin*)context->handle;
181
182 switch (sysparam->param)
183 {
184 case SPI_SET_DRAG_FULL_WINDOWS:
185 case SPI_SET_KEYBOARD_CUES:
186 case SPI_SET_KEYBOARD_PREF:
187 case SPI_SET_MOUSE_BUTTON_SWAP:
188 length += 1;
189 break;
190
191 case SPI_SET_WORK_AREA:
192 case SPI_DISPLAY_CHANGE:
193 case SPI_TASKBAR_POS:
194 length += 8;
195 break;
196
197 case SPI_SET_HIGH_CONTRAST:
198 length += sysparam->highContrast.colorSchemeLength + 10;
199 break;
200
201 case SPI_SETFILTERKEYS:
202 length += 20;
203 break;
204
205 case SPI_SETSTICKYKEYS:
206 case SPI_SETCARETWIDTH:
207 case SPI_SETTOGGLEKEYS:
208 length += 4;
209 break;
210
211 default:
212 return ERROR_BAD_ARGUMENTS;
213 }
214
215 s = rail_pdu_init(length);
216
217 if (!s)
218 {
219 WLog_ERR(TAG, "rail_pdu_init failed!");
220 return CHANNEL_RC_NO_MEMORY;
221 }
222
223 extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
224 if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
225 {
226 WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
227 Stream_Free(s, TRUE);
228 return error;
229 }
230
231 if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM)))
232 {
233 WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error);
234 }
235
236 Stream_Free(s, TRUE);
237 return error;
238 }
239
240 /**
241 * Function description
242 *
243 * @return 0 on success, otherwise a Win32 error code
244 */
rail_client_system_param(RailClientContext * context,const RAIL_SYSPARAM_ORDER * sysInParam)245 static UINT rail_client_system_param(RailClientContext* context,
246 const RAIL_SYSPARAM_ORDER* sysInParam)
247 {
248 UINT error = CHANNEL_RC_OK;
249 RAIL_SYSPARAM_ORDER sysparam;
250
251 if (!context || !sysInParam)
252 return ERROR_INVALID_PARAMETER;
253
254 sysparam = *sysInParam;
255
256 if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
257 {
258 sysparam.param = SPI_SET_HIGH_CONTRAST;
259
260 if ((error = rail_send_client_sysparam(context, &sysparam)))
261 {
262 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
263 return error;
264 }
265 }
266
267 if (sysparam.params & SPI_MASK_TASKBAR_POS)
268 {
269 sysparam.param = SPI_TASKBAR_POS;
270
271 if ((error = rail_send_client_sysparam(context, &sysparam)))
272 {
273 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
274 return error;
275 }
276 }
277
278 if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
279 {
280 sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
281
282 if ((error = rail_send_client_sysparam(context, &sysparam)))
283 {
284 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
285 return error;
286 }
287 }
288
289 if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
290 {
291 sysparam.param = SPI_SET_KEYBOARD_PREF;
292
293 if ((error = rail_send_client_sysparam(context, &sysparam)))
294 {
295 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
296 return error;
297 }
298 }
299
300 if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
301 {
302 sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
303
304 if ((error = rail_send_client_sysparam(context, &sysparam)))
305 {
306 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
307 return error;
308 }
309 }
310
311 if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
312 {
313 sysparam.param = SPI_SET_KEYBOARD_CUES;
314
315 if ((error = rail_send_client_sysparam(context, &sysparam)))
316 {
317 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
318 return error;
319 }
320 }
321
322 if (sysparam.params & SPI_MASK_SET_WORK_AREA)
323 {
324 sysparam.param = SPI_SET_WORK_AREA;
325
326 if ((error = rail_send_client_sysparam(context, &sysparam)))
327 {
328 WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
329 return error;
330 }
331 }
332
333 return error;
334 }
335
336 /**
337 * Function description
338 *
339 * @return 0 on success, otherwise a Win32 error code
340 */
rail_client_system_command(RailClientContext * context,const RAIL_SYSCOMMAND_ORDER * syscommand)341 static UINT rail_client_system_command(RailClientContext* context,
342 const RAIL_SYSCOMMAND_ORDER* syscommand)
343 {
344 railPlugin* rail;
345
346 if (!context || !syscommand)
347 return ERROR_INVALID_PARAMETER;
348
349 rail = (railPlugin*)context->handle;
350 return rail_send_client_syscommand_order(rail, syscommand);
351 }
352
353 /**
354 * Function description
355 *
356 * @return 0 on success, otherwise a Win32 error code
357 */
rail_client_handshake(RailClientContext * context,const RAIL_HANDSHAKE_ORDER * handshake)358 static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
359 {
360 railPlugin* rail;
361
362 if (!context || !handshake)
363 return ERROR_INVALID_PARAMETER;
364
365 rail = (railPlugin*)context->handle;
366 return rail_send_handshake_order(rail, handshake);
367 }
368
369 /**
370 * Function description
371 *
372 * @return 0 on success, otherwise a Win32 error code
373 */
rail_client_notify_event(RailClientContext * context,const RAIL_NOTIFY_EVENT_ORDER * notifyEvent)374 static UINT rail_client_notify_event(RailClientContext* context,
375 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
376 {
377 railPlugin* rail;
378
379 if (!context || !notifyEvent)
380 return ERROR_INVALID_PARAMETER;
381
382 rail = (railPlugin*)context->handle;
383 return rail_send_client_notify_event_order(rail, notifyEvent);
384 }
385
386 /**
387 * Function description
388 *
389 * @return 0 on success, otherwise a Win32 error code
390 */
rail_client_window_move(RailClientContext * context,const RAIL_WINDOW_MOVE_ORDER * windowMove)391 static UINT rail_client_window_move(RailClientContext* context,
392 const RAIL_WINDOW_MOVE_ORDER* windowMove)
393 {
394 railPlugin* rail;
395
396 if (!context || !windowMove)
397 return ERROR_INVALID_PARAMETER;
398
399 rail = (railPlugin*)context->handle;
400 return rail_send_client_window_move_order(rail, windowMove);
401 }
402
403 /**
404 * Function description
405 *
406 * @return 0 on success, otherwise a Win32 error code
407 */
rail_client_information(RailClientContext * context,const RAIL_CLIENT_STATUS_ORDER * clientStatus)408 static UINT rail_client_information(RailClientContext* context,
409 const RAIL_CLIENT_STATUS_ORDER* clientStatus)
410 {
411 railPlugin* rail;
412
413 if (!context || !clientStatus)
414 return ERROR_INVALID_PARAMETER;
415
416 rail = (railPlugin*)context->handle;
417 return rail_send_client_status_order(rail, clientStatus);
418 }
419
420 /**
421 * Function description
422 *
423 * @return 0 on success, otherwise a Win32 error code
424 */
rail_client_system_menu(RailClientContext * context,const RAIL_SYSMENU_ORDER * sysmenu)425 static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
426 {
427 railPlugin* rail;
428
429 if (!context || !sysmenu)
430 return ERROR_INVALID_PARAMETER;
431
432 rail = (railPlugin*)context->handle;
433 return rail_send_client_sysmenu_order(rail, sysmenu);
434 }
435
436 /**
437 * Function description
438 *
439 * @return 0 on success, otherwise a Win32 error code
440 */
rail_client_language_bar_info(RailClientContext * context,const RAIL_LANGBAR_INFO_ORDER * langBarInfo)441 static UINT rail_client_language_bar_info(RailClientContext* context,
442 const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
443 {
444 railPlugin* rail;
445
446 if (!context || !langBarInfo)
447 return ERROR_INVALID_PARAMETER;
448
449 rail = (railPlugin*)context->handle;
450 return rail_send_client_langbar_info_order(rail, langBarInfo);
451 }
452
rail_client_language_ime_info(RailClientContext * context,const RAIL_LANGUAGEIME_INFO_ORDER * langImeInfo)453 static UINT rail_client_language_ime_info(RailClientContext* context,
454 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
455 {
456 railPlugin* rail;
457
458 if (!context || !langImeInfo)
459 return ERROR_INVALID_PARAMETER;
460
461 rail = (railPlugin*)context->handle;
462 return rail_send_client_languageime_info_order(rail, langImeInfo);
463 }
464
465 /**
466 * Function description
467 *
468 * @return 0 on success, otherwise a Win32 error code
469 */
rail_client_get_appid_request(RailClientContext * context,const RAIL_GET_APPID_REQ_ORDER * getAppIdReq)470 static UINT rail_client_get_appid_request(RailClientContext* context,
471 const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
472 {
473 railPlugin* rail;
474
475 if (!context || !getAppIdReq || !context->handle)
476 return ERROR_INVALID_PARAMETER;
477
478 rail = (railPlugin*)context->handle;
479 return rail_send_client_get_appid_req_order(rail, getAppIdReq);
480 }
481
rail_client_compartment_info(RailClientContext * context,const RAIL_COMPARTMENT_INFO_ORDER * compartmentInfo)482 static UINT rail_client_compartment_info(RailClientContext* context,
483 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
484 {
485 railPlugin* rail;
486
487 if (!context || !compartmentInfo || !context->handle)
488 return ERROR_INVALID_PARAMETER;
489
490 rail = (railPlugin*)context->handle;
491 return rail_send_client_compartment_info_order(rail, compartmentInfo);
492 }
493
rail_client_cloak(RailClientContext * context,const RAIL_CLOAK * cloak)494 static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
495 {
496 railPlugin* rail;
497
498 if (!context || !cloak || !context->handle)
499 return ERROR_INVALID_PARAMETER;
500
501 rail = (railPlugin*)context->handle;
502 return rail_send_client_cloak_order(rail, cloak);
503 }
504
rail_client_snap_arrange(RailClientContext * context,const RAIL_SNAP_ARRANGE * snap)505 static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
506 {
507 railPlugin* rail;
508
509 if (!context || !snap || !context->handle)
510 return ERROR_INVALID_PARAMETER;
511
512 rail = (railPlugin*)context->handle;
513 return rail_send_client_snap_arrange_order(rail, snap);
514 }
515
516 /**
517 * Function description
518 *
519 * @return 0 on success, otherwise a Win32 error code
520 */
rail_virtual_channel_event_data_received(railPlugin * rail,void * pData,UINT32 dataLength,UINT32 totalLength,UINT32 dataFlags)521 static UINT rail_virtual_channel_event_data_received(railPlugin* rail, void* pData,
522 UINT32 dataLength, UINT32 totalLength,
523 UINT32 dataFlags)
524 {
525 wStream* data_in;
526
527 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
528 {
529 return CHANNEL_RC_OK;
530 }
531
532 if (dataFlags & CHANNEL_FLAG_FIRST)
533 {
534 if (rail->data_in)
535 Stream_Free(rail->data_in, TRUE);
536
537 rail->data_in = Stream_New(NULL, totalLength);
538
539 if (!rail->data_in)
540 {
541 WLog_ERR(TAG, "Stream_New failed!");
542 return CHANNEL_RC_NO_MEMORY;
543 }
544 }
545
546 data_in = rail->data_in;
547
548 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
549 {
550 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
551 return CHANNEL_RC_NO_MEMORY;
552 }
553
554 Stream_Write(data_in, pData, dataLength);
555
556 if (dataFlags & CHANNEL_FLAG_LAST)
557 {
558 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
559 {
560 WLog_ERR(TAG, "rail_plugin_process_received: read error");
561 return ERROR_INTERNAL_ERROR;
562 }
563
564 rail->data_in = NULL;
565 Stream_SealLength(data_in);
566 Stream_SetPosition(data_in, 0);
567
568 if (!MessageQueue_Post(rail->queue, NULL, 0, (void*)data_in, NULL))
569 {
570 WLog_ERR(TAG, "MessageQueue_Post failed!");
571 return ERROR_INTERNAL_ERROR;
572 }
573 }
574
575 return CHANNEL_RC_OK;
576 }
577
rail_virtual_channel_open_event_ex(LPVOID lpUserParam,DWORD openHandle,UINT event,LPVOID pData,UINT32 dataLength,UINT32 totalLength,UINT32 dataFlags)578 static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
579 UINT event, LPVOID pData,
580 UINT32 dataLength, UINT32 totalLength,
581 UINT32 dataFlags)
582 {
583 UINT error = CHANNEL_RC_OK;
584 railPlugin* rail = (railPlugin*)lpUserParam;
585
586 switch (event)
587 {
588 case CHANNEL_EVENT_DATA_RECEIVED:
589 if (!rail || (rail->OpenHandle != openHandle))
590 {
591 WLog_ERR(TAG, "error no match");
592 return;
593 }
594 if ((error = rail_virtual_channel_event_data_received(rail, pData, dataLength,
595 totalLength, dataFlags)))
596 WLog_ERR(TAG,
597 "rail_virtual_channel_event_data_received failed with error %" PRIu32 "!",
598 error);
599
600 break;
601
602 case CHANNEL_EVENT_WRITE_CANCELLED:
603 case CHANNEL_EVENT_WRITE_COMPLETE:
604 {
605 wStream* s = (wStream*)pData;
606 Stream_Free(s, TRUE);
607 }
608 break;
609
610 case CHANNEL_EVENT_USER:
611 break;
612 }
613
614 if (error && rail && rail->rdpcontext)
615 setChannelError(rail->rdpcontext, error,
616 "rail_virtual_channel_open_event reported an error");
617
618 return;
619 }
620
rail_virtual_channel_client_thread(LPVOID arg)621 static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
622 {
623 wStream* data;
624 wMessage message;
625 railPlugin* rail = (railPlugin*)arg;
626 UINT error = CHANNEL_RC_OK;
627
628 while (1)
629 {
630 if (!MessageQueue_Wait(rail->queue))
631 {
632 WLog_ERR(TAG, "MessageQueue_Wait failed!");
633 error = ERROR_INTERNAL_ERROR;
634 break;
635 }
636
637 if (!MessageQueue_Peek(rail->queue, &message, TRUE))
638 {
639 WLog_ERR(TAG, "MessageQueue_Peek failed!");
640 error = ERROR_INTERNAL_ERROR;
641 break;
642 }
643
644 if (message.id == WMQ_QUIT)
645 break;
646
647 if (message.id == 0)
648 {
649 data = (wStream*)message.wParam;
650 error = rail_order_recv(rail, data);
651 Stream_Free(data, TRUE);
652
653 if (error)
654 {
655 WLog_ERR(TAG, "rail_order_recv failed with error %" PRIu32 "!", error);
656 break;
657 }
658 }
659 }
660
661 if (error && rail->rdpcontext)
662 setChannelError(rail->rdpcontext, error,
663 "rail_virtual_channel_client_thread reported an error");
664
665 ExitThread(error);
666 return error;
667 }
668
669 /**
670 * Function description
671 *
672 * @return 0 on success, otherwise a Win32 error code
673 */
rail_virtual_channel_event_connected(railPlugin * rail,LPVOID pData,UINT32 dataLength)674 static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
675 {
676 RailClientContext* context = rail_get_client_interface(rail);
677 UINT status;
678 status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
679 rail->channelDef.name,
680 rail_virtual_channel_open_event_ex);
681
682 if (status != CHANNEL_RC_OK)
683 {
684 WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]",
685 WTSErrorToString(status), status);
686 return status;
687 }
688
689 if (context)
690 {
691 IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
692
693 if (status != CHANNEL_RC_OK)
694 WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]",
695 WTSErrorToString(status), status);
696 }
697
698 rail->queue = MessageQueue_New(NULL);
699
700 if (!rail->queue)
701 {
702 WLog_ERR(TAG, "MessageQueue_New failed!");
703 return CHANNEL_RC_NO_MEMORY;
704 }
705
706 if (!(rail->thread =
707 CreateThread(NULL, 0, rail_virtual_channel_client_thread, (void*)rail, 0, NULL)))
708 {
709 WLog_ERR(TAG, "CreateThread failed!");
710 MessageQueue_Free(rail->queue);
711 rail->queue = NULL;
712 return ERROR_INTERNAL_ERROR;
713 }
714
715 return CHANNEL_RC_OK;
716 }
717
718 /**
719 * Function description
720 *
721 * @return 0 on success, otherwise a Win32 error code
722 */
rail_virtual_channel_event_disconnected(railPlugin * rail)723 static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
724 {
725 UINT rc;
726
727 if (rail->OpenHandle == 0)
728 return CHANNEL_RC_OK;
729
730 if (MessageQueue_PostQuit(rail->queue, 0) &&
731 (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED))
732 {
733 rc = GetLastError();
734 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
735 return rc;
736 }
737
738 MessageQueue_Free(rail->queue);
739 CloseHandle(rail->thread);
740 rail->queue = NULL;
741 rail->thread = NULL;
742 rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
743
744 if (CHANNEL_RC_OK != rc)
745 {
746 WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
747 rc);
748 return rc;
749 }
750
751 rail->OpenHandle = 0;
752
753 if (rail->data_in)
754 {
755 Stream_Free(rail->data_in, TRUE);
756 rail->data_in = NULL;
757 }
758
759 return CHANNEL_RC_OK;
760 }
761
rail_virtual_channel_event_terminated(railPlugin * rail)762 static void rail_virtual_channel_event_terminated(railPlugin* rail)
763 {
764 rail->InitHandle = 0;
765 free(rail->context);
766 free(rail);
767 }
768
rail_virtual_channel_init_event_ex(LPVOID lpUserParam,LPVOID pInitHandle,UINT event,LPVOID pData,UINT dataLength)769 static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
770 UINT event, LPVOID pData, UINT dataLength)
771 {
772 UINT error = CHANNEL_RC_OK;
773 railPlugin* rail = (railPlugin*)lpUserParam;
774
775 if (!rail || (rail->InitHandle != pInitHandle))
776 {
777 WLog_ERR(TAG, "error no match");
778 return;
779 }
780
781 switch (event)
782 {
783 case CHANNEL_EVENT_CONNECTED:
784 if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
785 WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
786 error);
787
788 break;
789
790 case CHANNEL_EVENT_DISCONNECTED:
791 if ((error = rail_virtual_channel_event_disconnected(rail)))
792 WLog_ERR(TAG,
793 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
794 error);
795
796 break;
797
798 case CHANNEL_EVENT_TERMINATED:
799 rail_virtual_channel_event_terminated(rail);
800 break;
801
802 case CHANNEL_EVENT_ATTACHED:
803 case CHANNEL_EVENT_DETACHED:
804 default:
805 break;
806 }
807
808 if (error && rail->rdpcontext)
809 setChannelError(rail->rdpcontext, error,
810 "rail_virtual_channel_init_event_ex reported an error");
811 }
812
813 /* rail is always built-in */
814 #define VirtualChannelEntryEx rail_VirtualChannelEntryEx
815
VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,PVOID pInitHandle)816 BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
817 {
818 UINT rc;
819 railPlugin* rail;
820 RailClientContext* context = NULL;
821 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
822 BOOL isFreerdp = FALSE;
823 rail = (railPlugin*)calloc(1, sizeof(railPlugin));
824
825 if (!rail)
826 {
827 WLog_ERR(TAG, "calloc failed!");
828 return FALSE;
829 }
830
831 /* Default to automatically replying to server handshakes */
832 rail->sendHandshake = TRUE;
833 rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
834 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
835 sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
836 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
837
838 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
839 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
840 {
841 context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
842
843 if (!context)
844 {
845 WLog_ERR(TAG, "calloc failed!");
846 free(rail);
847 return FALSE;
848 }
849
850 context->handle = (void*)rail;
851 context->custom = NULL;
852 context->ClientExecute = rail_client_execute;
853 context->ClientActivate = rail_client_activate;
854 context->ClientSystemParam = rail_client_system_param;
855 context->ClientSystemCommand = rail_client_system_command;
856 context->ClientHandshake = rail_client_handshake;
857 context->ClientNotifyEvent = rail_client_notify_event;
858 context->ClientWindowMove = rail_client_window_move;
859 context->ClientInformation = rail_client_information;
860 context->ClientSystemMenu = rail_client_system_menu;
861 context->ClientLanguageBarInfo = rail_client_language_bar_info;
862 context->ClientLanguageIMEInfo = rail_client_language_ime_info;
863 context->ClientGetAppIdRequest = rail_client_get_appid_request;
864 context->ClientSnapArrange = rail_client_snap_arrange;
865 context->ClientCloak = rail_client_cloak;
866 context->ClientCompartmentInfo = rail_client_compartment_info;
867 rail->rdpcontext = pEntryPointsEx->context;
868 rail->context = context;
869 isFreerdp = TRUE;
870 }
871
872 rail->log = WLog_Get("com.freerdp.channels.rail.client");
873 WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
874 CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
875 rail->InitHandle = pInitHandle;
876 rc = rail->channelEntryPoints.pVirtualChannelInitEx(
877 rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
878 rail_virtual_channel_init_event_ex);
879
880 if (CHANNEL_RC_OK != rc)
881 {
882 WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
883 goto error_out;
884 }
885
886 rail->channelEntryPoints.pInterface = context;
887 return TRUE;
888 error_out:
889
890 if (isFreerdp)
891 free(rail->context);
892
893 free(rail);
894 return FALSE;
895 }
896