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