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