1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Device Redirection Virtual Channel
4  *
5  * Copyright 2010-2011 Vic Lee
6  * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7  * Copyright 2015-2016 Thincast Technologies GmbH
8  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9  * Copyright 2016 Armin Novak <armin.novak@thincast.com>
10  * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <winpr/crt.h>
34 #include <winpr/stream.h>
35 
36 #include <freerdp/types.h>
37 #include <freerdp/constants.h>
38 #include <freerdp/channels/log.h>
39 #include <freerdp/channels/rdpdr.h>
40 
41 #ifdef _WIN32
42 #include <windows.h>
43 #include <dbt.h>
44 #else
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #endif
49 
50 #ifdef __MACOSX__
51 #include <CoreFoundation/CoreFoundation.h>
52 #include <stdio.h>
53 #include <dirent.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #endif
58 
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 
63 #include "rdpdr_capabilities.h"
64 
65 #include "devman.h"
66 #include "irp.h"
67 
68 #include "rdpdr_main.h"
69 
70 typedef struct _DEVICE_DRIVE_EXT DEVICE_DRIVE_EXT;
71 /* IMPORTANT: Keep in sync with DRIVE_DEVICE */
72 struct _DEVICE_DRIVE_EXT
73 {
74 	DEVICE device;
75 	WCHAR* path;
76 	BOOL automount;
77 };
78 
79 /**
80  * Function description
81  *
82  * @return 0 on success, otherwise a Win32 error code
83  */
84 static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn);
85 
86 /**
87  * Function description
88  *
89  * @return 0 on success, otherwise a Win32 error code
90  */
rdpdr_send_device_list_remove_request(rdpdrPlugin * rdpdr,UINT32 count,UINT32 ids[])91 static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 count, UINT32 ids[])
92 {
93 	UINT32 i;
94 	wStream* s;
95 	s = Stream_New(NULL, count * sizeof(UINT32) + 8);
96 
97 	if (!s)
98 	{
99 		WLog_ERR(TAG, "Stream_New failed!");
100 		return CHANNEL_RC_NO_MEMORY;
101 	}
102 
103 	Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
104 	Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
105 	Stream_Write_UINT32(s, count);
106 
107 	for (i = 0; i < count; i++)
108 		Stream_Write_UINT32(s, ids[i]);
109 
110 	Stream_SealLength(s);
111 	return rdpdr_send(rdpdr, s);
112 }
113 
114 #if defined(_UWP) || defined(__IOS__)
115 
first_hotplug(rdpdrPlugin * rdpdr)116 void first_hotplug(rdpdrPlugin* rdpdr)
117 {
118 }
119 
drive_hotplug_thread_func(LPVOID arg)120 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
121 {
122 	return CHANNEL_RC_OK;
123 }
124 
drive_hotplug_thread_terminate(rdpdrPlugin * rdpdr)125 static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
126 {
127 	return CHANNEL_RC_OK;
128 }
129 
130 #elif _WIN32
131 
check_path(const char * path)132 BOOL check_path(const char* path)
133 {
134 	UINT type = GetDriveTypeA(path);
135 
136 	if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
137 	      type == DRIVE_REMOTE))
138 		return FALSE;
139 
140 	return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
141 }
142 
first_hotplug(rdpdrPlugin * rdpdr)143 void first_hotplug(rdpdrPlugin* rdpdr)
144 {
145 	size_t i;
146 	DWORD unitmask = GetLogicalDrives();
147 
148 	for (i = 0; i < 26; i++)
149 	{
150 		if (unitmask & 0x01)
151 		{
152 			char drive_path[] = { 'c', ':', '\\', '\0' };
153 			char drive_name[] = { 'c', '\0' };
154 			RDPDR_DRIVE drive = { 0 };
155 			drive_path[0] = 'A' + (char)i;
156 			drive_name[0] = 'A' + (char)i;
157 
158 			if (check_path(drive_path))
159 			{
160 				drive.Type = RDPDR_DTYP_FILESYSTEM;
161 				drive.Path = drive_path;
162 				drive.Name = drive_name;
163 				drive.automount = TRUE;
164 				devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive,
165 				                           rdpdr->rdpcontext);
166 			}
167 		}
168 
169 		unitmask = unitmask >> 1;
170 	}
171 }
172 
hotplug_proc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)173 LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
174 {
175 	rdpdrPlugin* rdpdr;
176 	PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
177 	UINT error;
178 	rdpdr = (rdpdrPlugin*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
179 
180 	switch (Msg)
181 	{
182 		case WM_DEVICECHANGE:
183 			switch (wParam)
184 			{
185 				case DBT_DEVICEARRIVAL:
186 					if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
187 					{
188 						PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
189 						DWORD unitmask = lpdbv->dbcv_unitmask;
190 						int i;
191 
192 						for (i = 0; i < 26; i++)
193 						{
194 							if (unitmask & 0x01)
195 							{
196 								char drive_path[] = { 'c', ':', '/', '\0' };
197 								char drive_name[] = { 'c', '\0' };
198 								drive_path[0] = 'A' + (char)i;
199 								drive_name[0] = 'A' + (char)i;
200 
201 								if (check_path(drive_path))
202 								{
203 									RDPDR_DRIVE drive = { 0 };
204 
205 									drive.Type = RDPDR_DTYP_FILESYSTEM;
206 									drive.Path = drive_path;
207 									drive_path[1] = '\0';
208 									drive.automount = TRUE;
209 									drive.Name = drive_name;
210 									devman_load_device_service(rdpdr->devman,
211 									                           (const RDPDR_DEVICE*)&drive,
212 									                           rdpdr->rdpcontext);
213 									rdpdr_send_device_list_announce_request(rdpdr, TRUE);
214 								}
215 							}
216 
217 							unitmask = unitmask >> 1;
218 						}
219 					}
220 
221 					break;
222 
223 				case DBT_DEVICEREMOVECOMPLETE:
224 					if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
225 					{
226 						PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
227 						DWORD unitmask = lpdbv->dbcv_unitmask;
228 						int i, j, count;
229 						char drive_name_upper, drive_name_lower;
230 						ULONG_PTR* keys = NULL;
231 						DEVICE_DRIVE_EXT* device_ext;
232 						UINT32 ids[1];
233 
234 						for (i = 0; i < 26; i++)
235 						{
236 							if (unitmask & 0x01)
237 							{
238 								drive_name_upper = 'A' + i;
239 								drive_name_lower = 'a' + i;
240 								count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
241 
242 								for (j = 0; j < count; j++)
243 								{
244 									device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
245 									    rdpdr->devman->devices, (void*)keys[j]);
246 
247 									if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
248 										continue;
249 
250 									if (device_ext->path[0] == drive_name_upper ||
251 									    device_ext->path[0] == drive_name_lower)
252 									{
253 										if (device_ext->automount)
254 										{
255 											devman_unregister_device(rdpdr->devman, (void*)keys[j]);
256 											ids[0] = keys[j];
257 
258 											if ((error = rdpdr_send_device_list_remove_request(
259 											         rdpdr, 1, ids)))
260 											{
261 												// dont end on error, just report ?
262 												WLog_ERR(
263 												    TAG,
264 												    "rdpdr_send_device_list_remove_request failed "
265 												    "with error %" PRIu32 "!",
266 												    error);
267 											}
268 
269 											break;
270 										}
271 									}
272 								}
273 
274 								free(keys);
275 							}
276 
277 							unitmask = unitmask >> 1;
278 						}
279 					}
280 
281 					break;
282 
283 				default:
284 					break;
285 			}
286 
287 			break;
288 
289 		default:
290 			return DefWindowProc(hWnd, Msg, wParam, lParam);
291 	}
292 
293 	return DefWindowProc(hWnd, Msg, wParam, lParam);
294 }
295 
drive_hotplug_thread_func(LPVOID arg)296 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
297 {
298 	rdpdrPlugin* rdpdr;
299 	WNDCLASSEX wnd_cls;
300 	HWND hwnd;
301 	MSG msg;
302 	BOOL bRet;
303 	DEV_BROADCAST_HANDLE NotificationFilter;
304 	HDEVNOTIFY hDevNotify;
305 	rdpdr = (rdpdrPlugin*)arg;
306 	/* init windows class */
307 	wnd_cls.cbSize = sizeof(WNDCLASSEX);
308 	wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
309 	wnd_cls.lpfnWndProc = hotplug_proc;
310 	wnd_cls.cbClsExtra = 0;
311 	wnd_cls.cbWndExtra = 0;
312 	wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
313 	wnd_cls.hCursor = NULL;
314 	wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
315 	wnd_cls.lpszMenuName = NULL;
316 	wnd_cls.lpszClassName = L"DRIVE_HOTPLUG";
317 	wnd_cls.hInstance = NULL;
318 	wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
319 	RegisterClassEx(&wnd_cls);
320 	/* create window */
321 	hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
322 	SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr);
323 	rdpdr->hotplug_wnd = hwnd;
324 	/* register device interface to hwnd */
325 	NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
326 	NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
327 	hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
328 
329 	/* message loop */
330 	while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
331 	{
332 		if (bRet == -1)
333 		{
334 			break;
335 		}
336 		else
337 		{
338 			TranslateMessage(&msg);
339 			DispatchMessage(&msg);
340 		}
341 	}
342 
343 	UnregisterDeviceNotification(hDevNotify);
344 	return CHANNEL_RC_OK;
345 }
346 
347 /**
348  * Function description
349  *
350  * @return 0 on success, otherwise a Win32 error code
351  */
drive_hotplug_thread_terminate(rdpdrPlugin * rdpdr)352 static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
353 {
354 	UINT error = CHANNEL_RC_OK;
355 
356 	if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0))
357 	{
358 		error = GetLastError();
359 		WLog_ERR(TAG, "PostMessage failed with error %" PRIu32 "", error);
360 	}
361 
362 	return error;
363 }
364 
365 #elif defined(__MACOSX__)
366 
367 #define MAX_USB_DEVICES 100
368 
369 typedef struct _hotplug_dev
370 {
371 	char* path;
372 	BOOL to_add;
373 } hotplug_dev;
374 
375 /**
376  * Function description
377  *
378  * @return 0 on success, otherwise a Win32 error code
379  */
handle_hotplug(rdpdrPlugin * rdpdr)380 static UINT handle_hotplug(rdpdrPlugin* rdpdr)
381 {
382 	struct dirent* pDirent;
383 	DIR* pDir;
384 	char fullpath[PATH_MAX];
385 	char* szdir = (char*)"/Volumes";
386 	struct stat buf;
387 	hotplug_dev dev_array[MAX_USB_DEVICES];
388 	int count;
389 	DEVICE_DRIVE_EXT* device_ext;
390 	ULONG_PTR* keys = NULL;
391 	int i, j;
392 	int size = 0;
393 	UINT error;
394 	UINT32 ids[1];
395 	pDir = opendir(szdir);
396 
397 	if (pDir == NULL)
398 	{
399 		printf("Cannot open directory\n");
400 		return ERROR_OPEN_FAILED;
401 	}
402 
403 	while ((pDirent = readdir(pDir)) != NULL)
404 	{
405 		if (pDirent->d_name[0] != '.')
406 		{
407 			sprintf_s(fullpath, ARRAYSIZE(fullpath), "%s/%s", szdir, pDirent->d_name);
408 			if (stat(fullpath, &buf) != 0)
409 				continue;
410 
411 			if (S_ISDIR(buf.st_mode))
412 			{
413 				dev_array[size].path = _strdup(fullpath);
414 
415 				if (!dev_array[size].path)
416 				{
417 					closedir(pDir);
418 					error = CHANNEL_RC_NO_MEMORY;
419 					goto cleanup;
420 				}
421 
422 				dev_array[size++].to_add = TRUE;
423 			}
424 		}
425 	}
426 
427 	closedir(pDir);
428 	/* delete removed devices */
429 	count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
430 
431 	for (j = 0; j < count; j++)
432 	{
433 		char* path = NULL;
434 		BOOL dev_found = FALSE;
435 		device_ext =
436 		    (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[j]);
437 
438 		if (!device_ext || !device_ext->automount)
439 			continue;
440 
441 		if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
442 			continue;
443 
444 		if (device_ext->path == NULL)
445 			continue;
446 
447 		if (ConvertFromUnicode(CP_UTF8, 0, device_ext->path, -1, &path, 0, NULL, FALSE) <= 0)
448 			continue;
449 
450 		/* not plugable device */
451 		if (strstr(path, "/Volumes/") == NULL)
452 		{
453 			free(path);
454 			continue;
455 		}
456 
457 		for (i = 0; i < size; i++)
458 		{
459 			if (strstr(path, dev_array[i].path) != NULL)
460 			{
461 				dev_found = TRUE;
462 				dev_array[i].to_add = FALSE;
463 				break;
464 			}
465 		}
466 
467 		free(path);
468 
469 		if (!dev_found)
470 		{
471 			devman_unregister_device(rdpdr->devman, (void*)keys[j]);
472 			ids[0] = keys[j];
473 
474 			if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids)))
475 			{
476 				WLog_ERR(TAG,
477 				         "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!",
478 				         error);
479 				goto cleanup;
480 			}
481 		}
482 	}
483 
484 	/* add new devices */
485 	for (i = 0; i < size; i++)
486 	{
487 		if (dev_array[i].to_add)
488 		{
489 			RDPDR_DRIVE drive = { 0 };
490 			char* name;
491 
492 			drive.Type = RDPDR_DTYP_FILESYSTEM;
493 			drive.Path = dev_array[i].path;
494 			drive.automount = TRUE;
495 			name = strrchr(drive.Path, '/') + 1;
496 			drive.Name = name;
497 
498 			if (!drive.Name)
499 			{
500 				error = CHANNEL_RC_NO_MEMORY;
501 				goto cleanup;
502 			}
503 
504 			if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)&drive,
505 			                                        rdpdr->rdpcontext)))
506 			{
507 				WLog_ERR(TAG, "devman_load_device_service failed!");
508 				error = CHANNEL_RC_NO_MEMORY;
509 				goto cleanup;
510 			}
511 		}
512 	}
513 
514 cleanup:
515 	free(keys);
516 
517 	for (i = 0; i < size; i++)
518 		free(dev_array[i].path);
519 
520 	return error;
521 }
522 
drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,void * clientCallBackInfo,size_t numEvents,void * eventPaths,const FSEventStreamEventFlags eventFlags[],const FSEventStreamEventId eventIds[])523 static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,
524                                            void* clientCallBackInfo, size_t numEvents,
525                                            void* eventPaths,
526                                            const FSEventStreamEventFlags eventFlags[],
527                                            const FSEventStreamEventId eventIds[])
528 {
529 	rdpdrPlugin* rdpdr;
530 	size_t i;
531 	UINT error;
532 	char** paths = (char**)eventPaths;
533 	rdpdr = (rdpdrPlugin*)clientCallBackInfo;
534 
535 	for (i = 0; i < numEvents; i++)
536 	{
537 		if (strcmp(paths[i], "/Volumes/") == 0)
538 		{
539 			if ((error = handle_hotplug(rdpdr)))
540 			{
541 				WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error);
542 			}
543 			else
544 				rdpdr_send_device_list_announce_request(rdpdr, TRUE);
545 
546 			return;
547 		}
548 	}
549 }
550 
first_hotplug(rdpdrPlugin * rdpdr)551 void first_hotplug(rdpdrPlugin* rdpdr)
552 {
553 	UINT error;
554 
555 	if ((error = handle_hotplug(rdpdr)))
556 	{
557 		WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error);
558 	}
559 }
560 
drive_hotplug_thread_func(LPVOID arg)561 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
562 {
563 	rdpdrPlugin* rdpdr;
564 	FSEventStreamRef fsev;
565 	rdpdr = (rdpdrPlugin*)arg;
566 	CFStringRef path = CFSTR("/Volumes/");
567 	CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (const void**)&path, 1, NULL);
568 	FSEventStreamContext ctx;
569 	ZeroMemory(&ctx, sizeof(ctx));
570 	ctx.info = arg;
571 	fsev =
572 	    FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch,
573 	                        kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
574 	rdpdr->runLoop = CFRunLoopGetCurrent();
575 	FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode);
576 	FSEventStreamStart(fsev);
577 	CFRunLoopRun();
578 	FSEventStreamStop(fsev);
579 	FSEventStreamRelease(fsev);
580 	ExitThread(CHANNEL_RC_OK);
581 	return CHANNEL_RC_OK;
582 }
583 
584 #else
585 
586 
587 static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s",
588 	                                        "/media", "/mnt" };
589 
isAutomountLocation(const char * path)590 static BOOL isAutomountLocation(const char* path)
591 {
592 	const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]);
593 	size_t x;
594 	char buffer[MAX_PATH];
595 	uid_t uid = getuid();
596 	char uname[MAX_PATH] = { 0 };
597 
598 #ifndef HAVE_GETLOGIN_R
599 	strncpy(uname, getlogin(), sizeof(uname));
600 #else
601 	if (getlogin_r(uname, sizeof(uname)) != 0)
602 		return FALSE;
603 #endif
604 
605 	if (!path)
606 		return FALSE;
607 
608 	for (x = 0; x < nrLocations; x++)
609 	{
610 		const char* location = automountLocations[x];
611 		size_t length;
612 
613 		if (strstr(location, "%lu"))
614 			snprintf(buffer, sizeof(buffer), location, (unsigned long)uid);
615 		else if (strstr(location, "%s"))
616 			snprintf(buffer, sizeof(buffer), location, uname);
617 		else
618 			snprintf(buffer, sizeof(buffer), "%s", location);
619 
620 		length = strnlen(buffer, sizeof(buffer));
621 
622 		if (strncmp(buffer, path, length) == 0)
623 		{
624 			const char* rest = &path[length];
625 
626 			/* Only consider mount locations with max depth of 1 below the
627 			 * base path or the base path itself. */
628 			if (*rest == '\0')
629 				return TRUE;
630 			else if (*rest == '/')
631 			{
632 				const char* token = strstr(&rest[1], "/");
633 
634 				if (!token || (token[1] == '\0'))
635 					return TRUE;
636 			}
637 		}
638 	}
639 
640 	return FALSE;
641 }
642 
643 #define MAX_USB_DEVICES 100
644 
645 typedef struct _hotplug_dev
646 {
647 	char* path;
648 	BOOL to_add;
649 } hotplug_dev;
650 
handle_mountpoint(hotplug_dev * dev_array,size_t * size,const char * mountpoint)651 static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* mountpoint)
652 {
653 	if (!mountpoint)
654 		return;
655 	/* copy hotpluged device mount point to the dev_array */
656 	if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
657 	{
658 		dev_array[*size].path = _strdup(mountpoint);
659 		dev_array[*size + 1].to_add = TRUE;
660 		(*size)++;
661 	}
662 }
663 
664 #ifdef __sun
665 #include <sys/mnttab.h>
handle_platform_mounts_sun(hotplug_dev * dev_array,size_t * size)666 static UINT handle_platform_mounts_sun(hotplug_dev* dev_array, size_t* size)
667 {
668 	FILE* f;
669 	struct mnttab ent;
670 	f = fopen("/etc/mnttab", "r");
671 	if (f == NULL)
672 	{
673 		WLog_ERR(TAG, "fopen failed!");
674 		return ERROR_OPEN_FAILED;
675 	}
676 	while (getmntent(f, &ent) == 0)
677 	{
678 		handle_mountpoint(dev_array, size, ent.mnt_mountp);
679 	}
680 	fclose(f);
681 	return ERROR_SUCCESS;
682 }
683 #endif
684 
685 #if defined(__FreeBSD__) || defined(__OpenBSD__)
686 #include <sys/mount.h>
handle_platform_mounts_bsd(hotplug_dev * dev_array,size_t * size)687 static UINT handle_platform_mounts_bsd(hotplug_dev* dev_array, size_t* size)
688 {
689 	int mntsize;
690 	size_t idx;
691 	struct statfs* mntbuf = NULL;
692 
693 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
694 	if (!mntsize)
695 	{
696 		/* TODO: handle 'errno' */
697 		WLog_ERR(TAG, "getmntinfo failed!");
698 		return ERROR_OPEN_FAILED;
699 	}
700 	for (idx = 0; idx < (size_t)mntsize; idx++)
701 	{
702 		handle_mountpoint(dev_array, size, mntbuf[idx].f_mntonname);
703 	}
704 	free(mntbuf);
705 	return ERROR_SUCCESS;
706 }
707 #endif
708 
709 #if defined(__LINUX__) || defined(__linux__)
710 #include <mntent.h>
handle_platform_mounts_linux(hotplug_dev * dev_array,size_t * size)711 static UINT handle_platform_mounts_linux(hotplug_dev* dev_array, size_t* size)
712 {
713 	FILE* f;
714 	struct mntent* ent;
715 	f = fopen("/proc/mounts", "r");
716 	if (f == NULL)
717 	{
718 		WLog_ERR(TAG, "fopen failed!");
719 		return ERROR_OPEN_FAILED;
720 	}
721 	while ((ent = getmntent(f)) != NULL)
722 	{
723 		handle_mountpoint(dev_array, size, ent->mnt_dir);
724 	}
725 	fclose(f);
726 	return ERROR_SUCCESS;
727 }
728 #endif
729 
handle_platform_mounts(hotplug_dev * dev_array,size_t * size)730 static UINT handle_platform_mounts(hotplug_dev* dev_array, size_t* size)
731 {
732 #ifdef __sun
733 	return handle_platform_mounts_sun(dev_array, size);
734 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
735 	return handle_platform_mounts_bsd(dev_array, size);
736 #elif defined(__LINUX__) || defined(__linux__)
737 	return handle_platform_mounts_linux(dev_array, size);
738 #endif
739 	return ERROR_CALL_NOT_IMPLEMENTED;
740 }
741 
device_already_plugged(rdpdrPlugin * rdpdr,const hotplug_dev * device)742 static BOOL device_already_plugged(rdpdrPlugin* rdpdr, const hotplug_dev* device)
743 {
744 	BOOL rc = FALSE;
745 	int count, x;
746 	ULONG_PTR* keys = NULL;
747 	WCHAR* path = NULL;
748 	int status;
749 
750 	if (!rdpdr || !device)
751 		return TRUE;
752 	if (!device->to_add)
753 		return TRUE;
754 
755 	status = ConvertToUnicode(CP_UTF8, 0, device->path, -1, &path, 0);
756 	if (status <= 0)
757 		return TRUE;
758 
759 	ListDictionary_Lock(rdpdr->devman->devices);
760 	count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
761 	for (x = 0; x < count; x++)
762 	{
763 		DEVICE_DRIVE_EXT* device_ext =
764 		    (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[x]);
765 
766 		if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path)
767 			continue;
768 		if (_wcscmp(device_ext->path, path) == 0)
769 		{
770 			rc = TRUE;
771 			break;
772 		}
773 	}
774 	free(keys);
775 	free(path);
776 	ListDictionary_Unlock(rdpdr->devman->devices);
777 	return rc;
778 }
779 
780 /**
781  * Function description
782  *
783  * @return 0 on success, otherwise a Win32 error code
784  */
handle_hotplug(rdpdrPlugin * rdpdr)785 static UINT handle_hotplug(rdpdrPlugin* rdpdr)
786 {
787 	hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
788 	size_t i;
789 	size_t size = 0;
790 	int count, j;
791 	ULONG_PTR* keys = NULL;
792 	UINT32 ids[1];
793 	UINT error = ERROR_SUCCESS;
794 
795 	error = handle_platform_mounts(dev_array, &size);
796 
797 	/* delete removed devices */
798 	count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
799 
800 	for (j = 0; j < count; j++)
801 	{
802 		char* path = NULL;
803 		BOOL dev_found = FALSE;
804 		DEVICE_DRIVE_EXT* device_ext =
805 		    (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[j]);
806 
807 		if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) ||
808 		    !device_ext->path || !device_ext->automount)
809 			continue;
810 
811 		ConvertFromUnicode(CP_UTF8, 0, device_ext->path, -1, &path, 0, NULL, NULL);
812 
813 		if (!path)
814 			continue;
815 
816 		/* not plugable device */
817 		if (isAutomountLocation(path))
818 		{
819 			for (i = 0; i < size; i++)
820 			{
821 				if (strstr(path, dev_array[i].path) != NULL)
822 				{
823 					dev_found = TRUE;
824 					dev_array[i].to_add = FALSE;
825 					break;
826 				}
827 			}
828 		}
829 
830 		free(path);
831 
832 		if (!dev_found)
833 		{
834 			devman_unregister_device(rdpdr->devman, (void*)keys[j]);
835 			ids[0] = keys[j];
836 
837 			if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids)))
838 			{
839 				WLog_ERR(TAG,
840 				         "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!",
841 				         error);
842 				goto cleanup;
843 			}
844 		}
845 	}
846 
847 	/* add new devices */
848 	for (i = 0; i < size; i++)
849 	{
850 		if (!device_already_plugged(rdpdr, &dev_array[i]))
851 		{
852 			RDPDR_DRIVE drive = { 0 };
853 			char* name;
854 
855 			drive.Type = RDPDR_DTYP_FILESYSTEM;
856 			drive.Path = dev_array[i].path;
857 			drive.automount = TRUE;
858 			name = strrchr(drive.Path, '/') + 1;
859 			drive.Name = name;
860 
861 			if (!drive.Name)
862 			{
863 				WLog_ERR(TAG, "_strdup failed!");
864 				error = CHANNEL_RC_NO_MEMORY;
865 				goto cleanup;
866 			}
867 
868 			if ((error = devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive,
869 			                                        rdpdr->rdpcontext)))
870 			{
871 				WLog_ERR(TAG, "devman_load_device_service failed!");
872 				goto cleanup;
873 			}
874 		}
875 	}
876 
877 cleanup:
878 	free(keys);
879 
880 	for (i = 0; i < size; i++)
881 		free(dev_array[i].path);
882 
883 	return error;
884 }
885 
first_hotplug(rdpdrPlugin * rdpdr)886 static void first_hotplug(rdpdrPlugin* rdpdr)
887 {
888 	UINT error;
889 
890 	if ((error = handle_hotplug(rdpdr)))
891 	{
892 		WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error);
893 	}
894 }
895 
drive_hotplug_thread_func(LPVOID arg)896 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
897 {
898 	rdpdrPlugin* rdpdr;
899 	int mfd;
900 	fd_set rfds;
901 	struct timeval tv;
902 	int rv;
903 	UINT error = 0;
904 	DWORD status;
905 	rdpdr = (rdpdrPlugin*)arg;
906 	mfd = open("/proc/mounts", O_RDONLY, 0);
907 
908 	if (mfd < 0)
909 	{
910 		WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts.");
911 		error = ERROR_INTERNAL_ERROR;
912 		goto out;
913 	}
914 
915 	FD_ZERO(&rfds);
916 	FD_SET(mfd, &rfds);
917 	tv.tv_sec = 1;
918 	tv.tv_usec = 0;
919 
920 	while ((rv = select(mfd + 1, NULL, NULL, &rfds, &tv)) >= 0)
921 	{
922 		status = WaitForSingleObject(rdpdr->stopEvent, 0);
923 
924 		if (status == WAIT_FAILED)
925 		{
926 			error = GetLastError();
927 			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
928 			goto out;
929 		}
930 
931 		if (status == WAIT_OBJECT_0)
932 			break;
933 
934 		if (FD_ISSET(mfd, &rfds))
935 		{
936 			/* file /proc/mounts changed, handle this */
937 			if ((error = handle_hotplug(rdpdr)))
938 			{
939 				WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error);
940 				goto out;
941 			}
942 			else
943 				rdpdr_send_device_list_announce_request(rdpdr, TRUE);
944 		}
945 
946 		FD_ZERO(&rfds);
947 		FD_SET(mfd, &rfds);
948 		tv.tv_sec = 1;
949 		tv.tv_usec = 0;
950 	}
951 
952 out:
953 
954 	if (error && rdpdr->rdpcontext)
955 		setChannelError(rdpdr->rdpcontext, error, "drive_hotplug_thread_func reported an error");
956 
957 	ExitThread(error);
958 	return error;
959 }
960 
961 #endif
962 
963 #if !defined(_WIN32) && !defined(__IOS__)
964 /**
965  * Function description
966  *
967  * @return 0 on success, otherwise a Win32 error code
968  */
drive_hotplug_thread_terminate(rdpdrPlugin * rdpdr)969 static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
970 {
971 	UINT error;
972 
973 	if (rdpdr->hotplugThread)
974 	{
975 		SetEvent(rdpdr->stopEvent);
976 #ifdef __MACOSX__
977 		CFRunLoopStop(rdpdr->runLoop);
978 #endif
979 
980 		if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED)
981 		{
982 			error = GetLastError();
983 			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
984 			return error;
985 		}
986 
987 		CloseHandle(rdpdr->hotplugThread);
988 		CloseHandle(rdpdr->stopEvent);
989 		rdpdr->stopEvent = NULL;
990 		rdpdr->hotplugThread = NULL;
991 	}
992 
993 	return CHANNEL_RC_OK;
994 }
995 
996 #endif
997 
998 /**
999  * Function description
1000  *
1001  * @return 0 on success, otherwise a Win32 error code
1002  */
rdpdr_process_connect(rdpdrPlugin * rdpdr)1003 static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr)
1004 {
1005 	UINT32 index;
1006 	rdpSettings* settings;
1007 	UINT error = CHANNEL_RC_OK;
1008 	rdpdr->devman = devman_new(rdpdr);
1009 
1010 	if (!rdpdr->devman)
1011 	{
1012 		WLog_ERR(TAG, "devman_new failed!");
1013 		return CHANNEL_RC_NO_MEMORY;
1014 	}
1015 
1016 	settings = (rdpSettings*)rdpdr->channelEntryPoints.pExtendedData;
1017 
1018 	if (settings->ClientHostname)
1019 		strncpy(rdpdr->computerName, settings->ClientHostname, sizeof(rdpdr->computerName) - 1);
1020 	else
1021 		strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
1022 
1023 	for (index = 0; index < settings->DeviceCount; index++)
1024 	{
1025 		const RDPDR_DEVICE* device = settings->DeviceArray[index];
1026 
1027 		if (device->Type == RDPDR_DTYP_FILESYSTEM)
1028 		{
1029 			const char DynamicDrives[] = "DynamicDrives";
1030 			const RDPDR_DRIVE* drive = (const RDPDR_DRIVE*)device;
1031 			BOOL hotplugAll = strncmp(drive->Path, "*", 2) == 0;
1032 			BOOL hotplugLater = strncmp(drive->Path, DynamicDrives, sizeof(DynamicDrives)) == 0;
1033 			if (drive->Path && (hotplugAll || hotplugLater))
1034 			{
1035 				if (hotplugAll)
1036 					first_hotplug(rdpdr);
1037 #ifndef _WIN32
1038 
1039 				if (!(rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
1040 				{
1041 					WLog_ERR(TAG, "CreateEvent failed!");
1042 					return ERROR_INTERNAL_ERROR;
1043 				}
1044 
1045 #endif
1046 
1047 				if (!(rdpdr->hotplugThread =
1048 				          CreateThread(NULL, 0, drive_hotplug_thread_func, rdpdr, 0, NULL)))
1049 				{
1050 					WLog_ERR(TAG, "CreateThread failed!");
1051 #ifndef _WIN32
1052 					CloseHandle(rdpdr->stopEvent);
1053 					rdpdr->stopEvent = NULL;
1054 #endif
1055 					return ERROR_INTERNAL_ERROR;
1056 				}
1057 
1058 				continue;
1059 			}
1060 		}
1061 
1062 		if ((error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext)))
1063 		{
1064 			WLog_ERR(TAG, "devman_load_device_service failed with error %" PRIu32 "!", error);
1065 			return error;
1066 		}
1067 	}
1068 
1069 	return error;
1070 }
1071 
rdpdr_process_server_announce_request(rdpdrPlugin * rdpdr,wStream * s)1072 static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s)
1073 {
1074 	if (Stream_GetRemainingLength(s) < 8)
1075 		return ERROR_INVALID_DATA;
1076 
1077 	Stream_Read_UINT16(s, rdpdr->versionMajor);
1078 	Stream_Read_UINT16(s, rdpdr->versionMinor);
1079 	Stream_Read_UINT32(s, rdpdr->clientID);
1080 	rdpdr->sequenceId++;
1081 	return CHANNEL_RC_OK;
1082 }
1083 
1084 /**
1085  * Function description
1086  *
1087  * @return 0 on success, otherwise a Win32 error code
1088  */
rdpdr_send_client_announce_reply(rdpdrPlugin * rdpdr)1089 static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
1090 {
1091 	wStream* s;
1092 	s = Stream_New(NULL, 12);
1093 
1094 	if (!s)
1095 	{
1096 		WLog_ERR(TAG, "Stream_New failed!");
1097 		return CHANNEL_RC_NO_MEMORY;
1098 	}
1099 
1100 	Stream_Write_UINT16(s, RDPDR_CTYP_CORE);             /* Component (2 bytes) */
1101 	Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
1102 	Stream_Write_UINT16(s, rdpdr->versionMajor);
1103 	Stream_Write_UINT16(s, rdpdr->versionMinor);
1104 	Stream_Write_UINT32(s, (UINT32)rdpdr->clientID);
1105 	return rdpdr_send(rdpdr, s);
1106 }
1107 
1108 /**
1109  * Function description
1110  *
1111  * @return 0 on success, otherwise a Win32 error code
1112  */
rdpdr_send_client_name_request(rdpdrPlugin * rdpdr)1113 static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
1114 {
1115 	wStream* s;
1116 	WCHAR* computerNameW = NULL;
1117 	size_t computerNameLenW;
1118 
1119 	if (!rdpdr->computerName[0])
1120 		gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1);
1121 
1122 	computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2;
1123 	s = Stream_New(NULL, 16 + computerNameLenW + 2);
1124 
1125 	if (!s)
1126 	{
1127 		free(computerNameW);
1128 		WLog_ERR(TAG, "Stream_New failed!");
1129 		return CHANNEL_RC_NO_MEMORY;
1130 	}
1131 
1132 	Stream_Write_UINT16(s, RDPDR_CTYP_CORE);        /* Component (2 bytes) */
1133 	Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */
1134 	Stream_Write_UINT32(s, 1);                      /* unicodeFlag, 0 for ASCII and 1 for Unicode */
1135 	Stream_Write_UINT32(s, 0);                      /* codePage, must be set to zero */
1136 	Stream_Write_UINT32(s, computerNameLenW + 2);   /* computerNameLen, including null terminator */
1137 	Stream_Write(s, computerNameW, computerNameLenW);
1138 	Stream_Write_UINT16(s, 0); /* null terminator */
1139 	free(computerNameW);
1140 	return rdpdr_send(rdpdr, s);
1141 }
1142 
rdpdr_process_server_clientid_confirm(rdpdrPlugin * rdpdr,wStream * s)1143 static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s)
1144 {
1145 	UINT16 versionMajor;
1146 	UINT16 versionMinor;
1147 	UINT32 clientID;
1148 
1149 	if (Stream_GetRemainingLength(s) < 8)
1150 		return ERROR_INVALID_DATA;
1151 
1152 	Stream_Read_UINT16(s, versionMajor);
1153 	Stream_Read_UINT16(s, versionMinor);
1154 	Stream_Read_UINT32(s, clientID);
1155 
1156 	if (versionMajor != rdpdr->versionMajor || versionMinor != rdpdr->versionMinor)
1157 	{
1158 		rdpdr->versionMajor = versionMajor;
1159 		rdpdr->versionMinor = versionMinor;
1160 	}
1161 
1162 	if (clientID != rdpdr->clientID)
1163 		rdpdr->clientID = clientID;
1164 
1165 	return CHANNEL_RC_OK;
1166 }
1167 
1168 /**
1169  * Function description
1170  *
1171  * @return 0 on success, otherwise a Win32 error code
1172  */
rdpdr_send_device_list_announce_request(rdpdrPlugin * rdpdr,BOOL userLoggedOn)1173 static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn)
1174 {
1175 	int i;
1176 	BYTE c;
1177 	size_t pos;
1178 	int index;
1179 	wStream* s;
1180 	UINT32 count;
1181 	size_t data_len;
1182 	size_t count_pos;
1183 	DEVICE* device;
1184 	int keyCount;
1185 	ULONG_PTR* pKeys = NULL;
1186 	s = Stream_New(NULL, 256);
1187 
1188 	if (!s)
1189 	{
1190 		WLog_ERR(TAG, "Stream_New failed!");
1191 		return CHANNEL_RC_NO_MEMORY;
1192 	}
1193 
1194 	Stream_Write_UINT16(s, RDPDR_CTYP_CORE);                /* Component (2 bytes) */
1195 	Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
1196 	count_pos = Stream_GetPosition(s);
1197 	count = 0;
1198 	Stream_Seek_UINT32(s); /* deviceCount */
1199 	pKeys = NULL;
1200 	keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
1201 
1202 	for (index = 0; index < keyCount; index++)
1203 	{
1204 		device = (DEVICE*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)pKeys[index]);
1205 
1206 		/**
1207 		 * 1. versionMinor 0x0005 doesn't send PAKID_CORE_USER_LOGGEDON
1208 		 *    so all devices should be sent regardless of user_loggedon
1209 		 * 2. smartcard devices should be always sent
1210 		 * 3. other devices are sent only after user_loggedon
1211 		 */
1212 
1213 		if ((rdpdr->versionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) ||
1214 		    userLoggedOn)
1215 		{
1216 			data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
1217 
1218 			if (!Stream_EnsureRemainingCapacity(s, 20 + data_len))
1219 			{
1220 				free(pKeys);
1221 				Stream_Free(s, TRUE);
1222 				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
1223 				return ERROR_INVALID_DATA;
1224 			}
1225 
1226 			Stream_Write_UINT32(s, device->type); /* deviceType */
1227 			Stream_Write_UINT32(s, device->id);   /* deviceID */
1228 			strncpy((char*)Stream_Pointer(s), device->name, 8);
1229 
1230 			for (i = 0; i < 8; i++)
1231 			{
1232 				Stream_Peek_UINT8(s, c);
1233 
1234 				if (c > 0x7F)
1235 					Stream_Write_UINT8(s, '_');
1236 				else
1237 					Stream_Seek_UINT8(s);
1238 			}
1239 
1240 			Stream_Write_UINT32(s, data_len);
1241 
1242 			if (data_len > 0)
1243 				Stream_Write(s, Stream_Buffer(device->data), data_len);
1244 
1245 			count++;
1246 			WLog_INFO(TAG, "registered device #%" PRIu32 ": %s (type=%" PRIu32 " id=%" PRIu32 ")",
1247 			          count, device->name, device->type, device->id);
1248 		}
1249 	}
1250 
1251 	free(pKeys);
1252 	pos = Stream_GetPosition(s);
1253 	Stream_SetPosition(s, count_pos);
1254 	Stream_Write_UINT32(s, count);
1255 	Stream_SetPosition(s, pos);
1256 	Stream_SealLength(s);
1257 	return rdpdr_send(rdpdr, s);
1258 }
1259 
dummy_irp_response(rdpdrPlugin * rdpdr,wStream * s)1260 static UINT dummy_irp_response(rdpdrPlugin* rdpdr, wStream* s)
1261 {
1262 
1263 	UINT32 DeviceId;
1264 	UINT32 FileId;
1265 	UINT32 CompletionId;
1266 
1267 	wStream* output = Stream_New(NULL, 256); // RDPDR_DEVICE_IO_RESPONSE_LENGTH
1268 	if (!output)
1269 	{
1270 		WLog_ERR(TAG, "Stream_New failed!");
1271 		return CHANNEL_RC_NO_MEMORY;
1272 	}
1273 
1274 	Stream_SetPosition(s, 4); /* see "rdpdr_process_receive" */
1275 
1276 	Stream_Read_UINT32(s, DeviceId);     /* DeviceId (4 bytes) */
1277 	Stream_Read_UINT32(s, FileId);       /* FileId (4 bytes) */
1278 	Stream_Read_UINT32(s, CompletionId); /* CompletionId (4 bytes) */
1279 
1280 	Stream_Write_UINT16(output, RDPDR_CTYP_CORE);                /* Component (2 bytes) */
1281 	Stream_Write_UINT16(output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
1282 	Stream_Write_UINT32(output, DeviceId);                       /* DeviceId (4 bytes) */
1283 	Stream_Write_UINT32(output, CompletionId);                   /* CompletionId (4 bytes) */
1284 	Stream_Write_UINT32(output, STATUS_UNSUCCESSFUL);            /* IoStatus (4 bytes) */
1285 
1286 	Stream_Zero(output, 256 - RDPDR_DEVICE_IO_RESPONSE_LENGTH);
1287 	// or usage
1288 	// Stream_Write_UINT32(output, 0); /* Length */
1289 	// Stream_Write_UINT8(output, 0);  /* Padding */
1290 
1291 	return rdpdr_send(rdpdr, output);
1292 }
1293 
1294 /**
1295  * Function description
1296  *
1297  * @return 0 on success, otherwise a Win32 error code
1298  */
rdpdr_process_irp(rdpdrPlugin * rdpdr,wStream * s)1299 static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
1300 {
1301 	IRP* irp;
1302 	UINT error = CHANNEL_RC_OK;
1303 	irp = irp_new(rdpdr->devman, s, &error);
1304 
1305 	if (!irp)
1306 	{
1307 		WLog_ERR(TAG, "irp_new failed with %" PRIu32 "!", error);
1308 
1309 		if (error == CHANNEL_RC_OK)
1310 		{
1311 			return dummy_irp_response(rdpdr, s);
1312 		}
1313 
1314 		return error;
1315 	}
1316 
1317 	IFCALLRET(irp->device->IRPRequest, error, irp->device, irp);
1318 
1319 	if (error)
1320 		WLog_ERR(TAG, "device->IRPRequest failed with error %" PRIu32 "", error);
1321 
1322 	return error;
1323 }
1324 
rdpdr_process_component(rdpdrPlugin * rdpdr,UINT16 component,UINT16 packetId,wStream * s)1325 static UINT rdpdr_process_component(rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
1326                                     wStream* s)
1327 {
1328 	UINT32 type;
1329 	DEVICE* device;
1330 
1331 	switch (component)
1332 	{
1333 		case RDPDR_CTYP_PRN:
1334 			type = RDPDR_DTYP_PRINT;
1335 			break;
1336 
1337 		default:
1338 			return ERROR_INVALID_DATA;
1339 	}
1340 
1341 	device = devman_get_device_by_type(rdpdr->devman, type);
1342 
1343 	if (!device)
1344 		return ERROR_INVALID_PARAMETER;
1345 
1346 	return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
1347 	                    packetId, s);
1348 }
1349 
1350 /**
1351  * Function description
1352  *
1353  * @return 0 on success, otherwise a Win32 error code
1354  */
rdpdr_process_init(rdpdrPlugin * rdpdr)1355 static UINT rdpdr_process_init(rdpdrPlugin* rdpdr)
1356 {
1357 	int index;
1358 	int keyCount;
1359 	DEVICE* device;
1360 	ULONG_PTR* pKeys = NULL;
1361 	UINT error = CHANNEL_RC_OK;
1362 	pKeys = NULL;
1363 	keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
1364 
1365 	for (index = 0; index < keyCount; index++)
1366 	{
1367 		device = (DEVICE*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)pKeys[index]);
1368 		IFCALLRET(device->Init, error, device);
1369 
1370 		if (error != CHANNEL_RC_OK)
1371 		{
1372 			WLog_ERR(TAG, "Init failed!");
1373 			free(pKeys);
1374 			return error;
1375 		}
1376 	}
1377 
1378 	free(pKeys);
1379 	return CHANNEL_RC_OK;
1380 }
1381 
1382 /**
1383  * Function description
1384  *
1385  * @return 0 on success, otherwise a Win32 error code
1386  */
rdpdr_process_receive(rdpdrPlugin * rdpdr,wStream * s)1387 static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
1388 {
1389 	UINT16 component;
1390 	UINT16 packetId;
1391 	UINT32 deviceId;
1392 	UINT32 status;
1393 	UINT error = ERROR_INVALID_DATA;
1394 
1395 	if (!rdpdr || !s)
1396 		return CHANNEL_RC_NULL_DATA;
1397 
1398 	if (Stream_GetRemainingLength(s) >= 4)
1399 	{
1400 		Stream_Read_UINT16(s, component); /* Component (2 bytes) */
1401 		Stream_Read_UINT16(s, packetId);  /* PacketId (2 bytes) */
1402 
1403 		if (component == RDPDR_CTYP_CORE)
1404 		{
1405 			switch (packetId)
1406 			{
1407 				case PAKID_CORE_SERVER_ANNOUNCE:
1408 					if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
1409 					{
1410 					}
1411 					else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
1412 					{
1413 						WLog_ERR(TAG,
1414 						         "rdpdr_send_client_announce_reply failed with error %" PRIu32 "",
1415 						         error);
1416 					}
1417 					else if ((error = rdpdr_send_client_name_request(rdpdr)))
1418 					{
1419 						WLog_ERR(TAG,
1420 						         "rdpdr_send_client_name_request failed with error %" PRIu32 "",
1421 						         error);
1422 					}
1423 					else if ((error = rdpdr_process_init(rdpdr)))
1424 					{
1425 						WLog_ERR(TAG, "rdpdr_process_init failed with error %" PRIu32 "", error);
1426 					}
1427 
1428 					break;
1429 
1430 				case PAKID_CORE_SERVER_CAPABILITY:
1431 					if ((error = rdpdr_process_capability_request(rdpdr, s)))
1432 					{
1433 					}
1434 					else if ((error = rdpdr_send_capability_response(rdpdr)))
1435 					{
1436 						WLog_ERR(TAG,
1437 						         "rdpdr_send_capability_response failed with error %" PRIu32 "",
1438 						         error);
1439 					}
1440 
1441 					break;
1442 
1443 				case PAKID_CORE_CLIENTID_CONFIRM:
1444 					if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
1445 					{
1446 					}
1447 					else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
1448 					{
1449 						WLog_ERR(
1450 						    TAG,
1451 						    "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
1452 						    error);
1453 					}
1454 
1455 					break;
1456 
1457 				case PAKID_CORE_USER_LOGGEDON:
1458 					if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
1459 					{
1460 						WLog_ERR(
1461 						    TAG,
1462 						    "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
1463 						    error);
1464 					}
1465 
1466 					break;
1467 
1468 				case PAKID_CORE_DEVICE_REPLY:
1469 
1470 					/* connect to a specific resource */
1471 					if (Stream_GetRemainingLength(s) >= 8)
1472 					{
1473 						Stream_Read_UINT32(s, deviceId);
1474 						Stream_Read_UINT32(s, status);
1475 						error = CHANNEL_RC_OK;
1476 					}
1477 
1478 					break;
1479 
1480 				case PAKID_CORE_DEVICE_IOREQUEST:
1481 					if ((error = rdpdr_process_irp(rdpdr, s)))
1482 					{
1483 						WLog_ERR(TAG, "rdpdr_process_irp failed with error %" PRIu32 "", error);
1484 						return error;
1485 					}
1486 					else
1487 						s = NULL;
1488 
1489 					break;
1490 
1491 				default:
1492 					WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16 "", packetId);
1493 					error = ERROR_INVALID_DATA;
1494 					break;
1495 			}
1496 		}
1497 		else
1498 		{
1499 			error = rdpdr_process_component(rdpdr, component, packetId, s);
1500 
1501 			if (error != CHANNEL_RC_OK)
1502 			{
1503 				WLog_ERR(TAG,
1504 				         "Unknown message: Component: 0x%04" PRIX16 " PacketId: 0x%04" PRIX16 "",
1505 				         component, packetId);
1506 			}
1507 		}
1508 	}
1509 
1510 	Stream_Free(s, TRUE);
1511 	return error;
1512 }
1513 
1514 /**
1515  * Function description
1516  *
1517  * @return 0 on success, otherwise a Win32 error code
1518  */
rdpdr_send(rdpdrPlugin * rdpdr,wStream * s)1519 UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s)
1520 {
1521 	UINT status;
1522 	rdpdrPlugin* plugin = (rdpdrPlugin*)rdpdr;
1523 
1524 	if (!rdpdr || !s)
1525 	{
1526 		Stream_Free(s, TRUE);
1527 		return CHANNEL_RC_NULL_DATA;
1528 	}
1529 
1530 	if (!plugin)
1531 	{
1532 		Stream_Free(s, TRUE);
1533 		status = CHANNEL_RC_BAD_INIT_HANDLE;
1534 	}
1535 	else
1536 	{
1537 		status = plugin->channelEntryPoints.pVirtualChannelWriteEx(
1538 		    plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s),
1539 		    s);
1540 	}
1541 
1542 	if (status != CHANNEL_RC_OK)
1543 	{
1544 		Stream_Free(s, TRUE);
1545 		WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
1546 		         WTSErrorToString(status), status);
1547 	}
1548 
1549 	return status;
1550 }
1551 
1552 /**
1553  * Function description
1554  *
1555  * @return 0 on success, otherwise a Win32 error code
1556  */
rdpdr_virtual_channel_event_data_received(rdpdrPlugin * rdpdr,void * pData,UINT32 dataLength,UINT32 totalLength,UINT32 dataFlags)1557 static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* pData,
1558                                                       UINT32 dataLength, UINT32 totalLength,
1559                                                       UINT32 dataFlags)
1560 {
1561 	wStream* data_in;
1562 
1563 	if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
1564 	{
1565 		/*
1566 		 * According to MS-RDPBCGR 2.2.6.1, "All virtual channel traffic MUST be suspended.
1567 		 * This flag is only valid in server-to-client virtual channel traffic. It MUST be
1568 		 * ignored in client-to-server data." Thus it would be best practice to cease data
1569 		 * transmission. However, simply returning here avoids a crash.
1570 		 */
1571 		return CHANNEL_RC_OK;
1572 	}
1573 
1574 	if (dataFlags & CHANNEL_FLAG_FIRST)
1575 	{
1576 		if (rdpdr->data_in != NULL)
1577 			Stream_Free(rdpdr->data_in, TRUE);
1578 
1579 		rdpdr->data_in = Stream_New(NULL, totalLength);
1580 
1581 		if (!rdpdr->data_in)
1582 		{
1583 			WLog_ERR(TAG, "Stream_New failed!");
1584 			return CHANNEL_RC_NO_MEMORY;
1585 		}
1586 	}
1587 
1588 	data_in = rdpdr->data_in;
1589 
1590 	if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
1591 	{
1592 		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
1593 		return ERROR_INVALID_DATA;
1594 	}
1595 
1596 	Stream_Write(data_in, pData, dataLength);
1597 
1598 	if (dataFlags & CHANNEL_FLAG_LAST)
1599 	{
1600 		if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
1601 		{
1602 			WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received: read error");
1603 			return ERROR_INTERNAL_ERROR;
1604 		}
1605 
1606 		rdpdr->data_in = NULL;
1607 		Stream_SealLength(data_in);
1608 		Stream_SetPosition(data_in, 0);
1609 
1610 		if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (void*)data_in, NULL))
1611 		{
1612 			WLog_ERR(TAG, "MessageQueue_Post failed!");
1613 			return ERROR_INTERNAL_ERROR;
1614 		}
1615 	}
1616 
1617 	return CHANNEL_RC_OK;
1618 }
1619 
rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam,DWORD openHandle,UINT event,LPVOID pData,UINT32 dataLength,UINT32 totalLength,UINT32 dataFlags)1620 static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
1621                                                           UINT event, LPVOID pData,
1622                                                           UINT32 dataLength, UINT32 totalLength,
1623                                                           UINT32 dataFlags)
1624 {
1625 	UINT error = CHANNEL_RC_OK;
1626 	rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam;
1627 
1628 	switch (event)
1629 	{
1630 		case CHANNEL_EVENT_DATA_RECEIVED:
1631 			if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle))
1632 			{
1633 				WLog_ERR(TAG, "error no match");
1634 				return;
1635 			}
1636 			if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength,
1637 			                                                       totalLength, dataFlags)))
1638 				WLog_ERR(TAG,
1639 				         "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32 "!",
1640 				         error);
1641 
1642 			break;
1643 
1644 		case CHANNEL_EVENT_WRITE_CANCELLED:
1645 		case CHANNEL_EVENT_WRITE_COMPLETE:
1646 		{
1647 			wStream* s = (wStream*)pData;
1648 			Stream_Free(s, TRUE);
1649 		}
1650 		break;
1651 
1652 		case CHANNEL_EVENT_USER:
1653 			break;
1654 	}
1655 
1656 	if (error && rdpdr && rdpdr->rdpcontext)
1657 		setChannelError(rdpdr->rdpcontext, error,
1658 		                "rdpdr_virtual_channel_open_event_ex reported an error");
1659 
1660 	return;
1661 }
1662 
rdpdr_virtual_channel_client_thread(LPVOID arg)1663 static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
1664 {
1665 	wStream* data;
1666 	wMessage message;
1667 	rdpdrPlugin* rdpdr = (rdpdrPlugin*)arg;
1668 	UINT error;
1669 
1670 	if (!rdpdr)
1671 	{
1672 		ExitThread((DWORD)CHANNEL_RC_NULL_DATA);
1673 		return CHANNEL_RC_NULL_DATA;
1674 	}
1675 
1676 	if ((error = rdpdr_process_connect(rdpdr)))
1677 	{
1678 		WLog_ERR(TAG, "rdpdr_process_connect failed with error %" PRIu32 "!", error);
1679 
1680 		if (rdpdr->rdpcontext)
1681 			setChannelError(rdpdr->rdpcontext, error,
1682 			                "rdpdr_virtual_channel_client_thread reported an error");
1683 
1684 		ExitThread(error);
1685 		return error;
1686 	}
1687 
1688 	while (1)
1689 	{
1690 		if (!MessageQueue_Wait(rdpdr->queue))
1691 			break;
1692 
1693 		if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
1694 		{
1695 			if (message.id == WMQ_QUIT)
1696 				break;
1697 
1698 			if (message.id == 0)
1699 			{
1700 				data = (wStream*)message.wParam;
1701 
1702 				if ((error = rdpdr_process_receive(rdpdr, data)))
1703 				{
1704 					WLog_ERR(TAG, "rdpdr_process_receive failed with error %" PRIu32 "!", error);
1705 
1706 					if (rdpdr->rdpcontext)
1707 						setChannelError(rdpdr->rdpcontext, error,
1708 						                "rdpdr_virtual_channel_client_thread reported an error");
1709 
1710 					ExitThread((DWORD)error);
1711 					return error;
1712 				}
1713 			}
1714 		}
1715 	}
1716 
1717 	ExitThread(0);
1718 	return 0;
1719 }
1720 
queue_free(void * obj)1721 static void queue_free(void* obj)
1722 {
1723 	wStream* s = obj;
1724 	Stream_Free(s, TRUE);
1725 }
1726 
1727 /**
1728  * Function description
1729  *
1730  * @return 0 on success, otherwise a Win32 error code
1731  */
rdpdr_virtual_channel_event_connected(rdpdrPlugin * rdpdr,LPVOID pData,UINT32 dataLength)1732 static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pData,
1733                                                   UINT32 dataLength)
1734 {
1735 	UINT32 status;
1736 	status = rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, &rdpdr->OpenHandle,
1737 	                                                         rdpdr->channelDef.name,
1738 	                                                         rdpdr_virtual_channel_open_event_ex);
1739 
1740 	if (status != CHANNEL_RC_OK)
1741 	{
1742 		WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]",
1743 		         WTSErrorToString(status), status);
1744 		return status;
1745 	}
1746 
1747 	rdpdr->queue = MessageQueue_New(NULL);
1748 
1749 	if (!rdpdr->queue)
1750 	{
1751 		WLog_ERR(TAG, "MessageQueue_New failed!");
1752 		return CHANNEL_RC_NO_MEMORY;
1753 	}
1754 
1755 	rdpdr->queue->object.fnObjectFree = queue_free;
1756 
1757 	if (!(rdpdr->thread =
1758 	          CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread, (void*)rdpdr, 0, NULL)))
1759 	{
1760 		WLog_ERR(TAG, "CreateThread failed!");
1761 		return ERROR_INTERNAL_ERROR;
1762 	}
1763 
1764 	return CHANNEL_RC_OK;
1765 }
1766 
1767 /**
1768  * Function description
1769  *
1770  * @return 0 on success, otherwise a Win32 error code
1771  */
rdpdr_virtual_channel_event_disconnected(rdpdrPlugin * rdpdr)1772 static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr)
1773 {
1774 	UINT error;
1775 
1776 	if (rdpdr->OpenHandle == 0)
1777 		return CHANNEL_RC_OK;
1778 
1779 	if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
1780 	    (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
1781 	{
1782 		error = GetLastError();
1783 		WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1784 		return error;
1785 	}
1786 
1787 	MessageQueue_Free(rdpdr->queue);
1788 	CloseHandle(rdpdr->thread);
1789 	rdpdr->queue = NULL;
1790 	rdpdr->thread = NULL;
1791 
1792 	if ((error = drive_hotplug_thread_terminate(rdpdr)))
1793 	{
1794 		WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %" PRIu32 "!", error);
1795 		return error;
1796 	}
1797 
1798 	error = rdpdr->channelEntryPoints.pVirtualChannelCloseEx(rdpdr->InitHandle, rdpdr->OpenHandle);
1799 
1800 	if (CHANNEL_RC_OK != error)
1801 	{
1802 		WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
1803 		         WTSErrorToString(error), error);
1804 	}
1805 
1806 	rdpdr->OpenHandle = 0;
1807 
1808 	if (rdpdr->data_in)
1809 	{
1810 		Stream_Free(rdpdr->data_in, TRUE);
1811 		rdpdr->data_in = NULL;
1812 	}
1813 
1814 	if (rdpdr->devman)
1815 	{
1816 		devman_free(rdpdr->devman);
1817 		rdpdr->devman = NULL;
1818 	}
1819 
1820 	return error;
1821 }
1822 
rdpdr_virtual_channel_event_terminated(rdpdrPlugin * rdpdr)1823 static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
1824 {
1825 	rdpdr->InitHandle = 0;
1826 	free(rdpdr);
1827 }
1828 
rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam,LPVOID pInitHandle,UINT event,LPVOID pData,UINT dataLength)1829 static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1830                                                           UINT event, LPVOID pData, UINT dataLength)
1831 {
1832 	UINT error = CHANNEL_RC_OK;
1833 	rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam;
1834 
1835 	if (!rdpdr || (rdpdr->InitHandle != pInitHandle))
1836 	{
1837 		WLog_ERR(TAG, "error no match");
1838 		return;
1839 	}
1840 
1841 	switch (event)
1842 	{
1843 		case CHANNEL_EVENT_INITIALIZED:
1844 			break;
1845 
1846 		case CHANNEL_EVENT_CONNECTED:
1847 			if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength)))
1848 				WLog_ERR(TAG,
1849 				         "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 "!",
1850 				         error);
1851 
1852 			break;
1853 
1854 		case CHANNEL_EVENT_DISCONNECTED:
1855 			if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr)))
1856 				WLog_ERR(TAG,
1857 				         "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
1858 				         error);
1859 
1860 			break;
1861 
1862 		case CHANNEL_EVENT_TERMINATED:
1863 			rdpdr_virtual_channel_event_terminated(rdpdr);
1864 			break;
1865 
1866 		case CHANNEL_EVENT_ATTACHED:
1867 		case CHANNEL_EVENT_DETACHED:
1868 		default:
1869 			WLog_ERR(TAG, "unknown event %" PRIu32 "!", event);
1870 			break;
1871 	}
1872 
1873 	if (error && rdpdr->rdpcontext)
1874 		setChannelError(rdpdr->rdpcontext, error,
1875 		                "rdpdr_virtual_channel_init_event_ex reported an error");
1876 }
1877 
1878 /* rdpdr is always built-in */
1879 #define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx
1880 
VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,PVOID pInitHandle)1881 BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
1882 {
1883 	UINT rc;
1884 	rdpdrPlugin* rdpdr;
1885 	CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
1886 	rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin));
1887 
1888 	if (!rdpdr)
1889 	{
1890 		WLog_ERR(TAG, "calloc failed!");
1891 		return FALSE;
1892 	}
1893 
1894 	rdpdr->channelDef.options =
1895 	    CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
1896 	sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name), "rdpdr");
1897 	rdpdr->sequenceId = 0;
1898 	pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1899 
1900 	if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1901 	    (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1902 	{
1903 		rdpdr->rdpcontext = pEntryPointsEx->context;
1904 	}
1905 
1906 	CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
1907 	rdpdr->InitHandle = pInitHandle;
1908 	rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx(
1909 	    rdpdr, NULL, pInitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1910 	    rdpdr_virtual_channel_init_event_ex);
1911 
1912 	if (CHANNEL_RC_OK != rc)
1913 	{
1914 		WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1915 		         rc);
1916 		free(rdpdr);
1917 		return FALSE;
1918 	}
1919 
1920 	return TRUE;
1921 }
1922