FreeRDP
Loading...
Searching...
No Matches
client/rdpdr_main.c
1
25#include <freerdp/config.h>
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdint.h>
31
32#include <winpr/crt.h>
33#include <winpr/sysinfo.h>
34#include <winpr/assert.h>
35#include <winpr/stream.h>
36
37#include <winpr/print.h>
38#include <winpr/sspicli.h>
39
40#include <freerdp/types.h>
41#include <freerdp/freerdp.h>
42#include <freerdp/constants.h>
43#include <freerdp/channels/log.h>
44#include <freerdp/channels/rdpdr.h>
45#include <freerdp/utils/rdpdr_utils.h>
46
47#ifdef _WIN32
48#include <windows.h>
49#include <dbt.h>
50#else
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <fcntl.h>
54#endif
55
56#ifdef __MACOSX__
57#include <CoreFoundation/CoreFoundation.h>
58#include <stdio.h>
59#include <dirent.h>
60#include <sys/types.h>
61#include <sys/stat.h>
62#include <unistd.h>
63#endif
64
65#include "rdpdr_capabilities.h"
66
67#include "devman.h"
68#include "irp.h"
69
70#include "rdpdr_main.h"
71
72#define TAG CHANNELS_TAG("rdpdr.client")
73
74/* IMPORTANT: Keep in sync with DRIVE_DEVICE */
75typedef struct
76{
77 DEVICE device;
78 WCHAR* path;
79 BOOL automount;
80} DEVICE_DRIVE_EXT;
81
82static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state)
83{
84 switch (state)
85 {
86 case RDPDR_CHANNEL_STATE_INITIAL:
87 return "RDPDR_CHANNEL_STATE_INITIAL";
88 case RDPDR_CHANNEL_STATE_ANNOUNCE:
89 return "RDPDR_CHANNEL_STATE_ANNOUNCE";
90 case RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY:
91 return "RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY";
92 case RDPDR_CHANNEL_STATE_NAME_REQUEST:
93 return "RDPDR_CHANNEL_STATE_NAME_REQUEST";
94 case RDPDR_CHANNEL_STATE_SERVER_CAPS:
95 return "RDPDR_CHANNEL_STATE_SERVER_CAPS";
96 case RDPDR_CHANNEL_STATE_CLIENT_CAPS:
97 return "RDPDR_CHANNEL_STATE_CLIENT_CAPS";
98 case RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM:
99 return "RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM";
100 case RDPDR_CHANNEL_STATE_READY:
101 return "RDPDR_CHANNEL_STATE_READY";
102 case RDPDR_CHANNEL_STATE_USER_LOGGEDON:
103 return "RDPDR_CHANNEL_STATE_USER_LOGGEDON";
104 default:
105 return "RDPDR_CHANNEL_STATE_UNKNOWN";
106 }
107}
108
109static const char* rdpdr_device_type_string(UINT32 type)
110{
111 switch (type)
112 {
113 case RDPDR_DTYP_SERIAL:
114 return "serial";
115 case RDPDR_DTYP_PRINT:
116 return "printer";
117 case RDPDR_DTYP_FILESYSTEM:
118 return "drive";
119 case RDPDR_DTYP_SMARTCARD:
120 return "smartcard";
121 case RDPDR_DTYP_PARALLEL:
122 return "parallel";
123 default:
124 return "UNKNOWN";
125 }
126}
127
128static const char* support_str(BOOL val)
129{
130 if (val)
131 return "supported";
132 return "not found";
133}
134
135static const char* rdpdr_caps_pdu_str(UINT32 flag)
136{
137 switch (flag)
138 {
139 case RDPDR_DEVICE_REMOVE_PDUS:
140 return "RDPDR_USER_LOGGEDON_PDU";
141 case RDPDR_CLIENT_DISPLAY_NAME_PDU:
142 return "RDPDR_CLIENT_DISPLAY_NAME_PDU";
143 case RDPDR_USER_LOGGEDON_PDU:
144 return "RDPDR_USER_LOGGEDON_PDU";
145 default:
146 return "RDPDR_UNKNONW";
147 }
148}
149
150static BOOL rdpdr_check_extended_pdu_flag(rdpdrPlugin* rdpdr, UINT32 flag)
151{
152 WINPR_ASSERT(rdpdr);
153
154 const BOOL client = (rdpdr->clientExtendedPDU & flag) != 0;
155 const BOOL server = (rdpdr->serverExtendedPDU & flag) != 0;
156
157 if (!client || !server)
158 {
159 WLog_Print(rdpdr->log, WLOG_WARN, "Checking ExtendedPDU::%s, client %s, server %s",
160 rdpdr_caps_pdu_str(flag), support_str(client), support_str(server));
161 return FALSE;
162 }
163 return TRUE;
164}
165
166BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next)
167{
168 WINPR_ASSERT(rdpdr);
169
170 if (next != rdpdr->state)
171 WLog_Print(rdpdr->log, WLOG_DEBUG, "[RDPDR] transition from %s to %s",
172 rdpdr_state_str(rdpdr->state), rdpdr_state_str(next));
173 rdpdr->state = next;
174 return TRUE;
175}
176
177static BOOL device_foreach(rdpdrPlugin* rdpdr, BOOL abortOnFail,
178 BOOL (*fkt)(ULONG_PTR key, void* element, void* data), void* data)
179{
180 BOOL rc = TRUE;
181 ULONG_PTR* keys = NULL;
182
183 ListDictionary_Lock(rdpdr->devman->devices);
184 const size_t count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
185 for (size_t x = 0; x < count; x++)
186 {
187 void* element = ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[x]);
188 if (!fkt(keys[x], element, data))
189 {
190 rc = FALSE;
191 if (abortOnFail)
192 break;
193 }
194 }
195 free(keys);
196 ListDictionary_Unlock(rdpdr->devman->devices);
197 return rc;
198}
199
205static UINT rdpdr_try_send_device_list_announce_request(rdpdrPlugin* rdpdr);
206
207static BOOL rdpdr_load_drive(rdpdrPlugin* rdpdr, const char* name, const char* path, BOOL automount)
208{
209 UINT rc = ERROR_INTERNAL_ERROR;
210 union
211 {
212 RDPDR_DRIVE* drive;
213 RDPDR_DEVICE* device;
214 } drive;
215 const char* args[] = { name, path, automount ? NULL : name };
216
217 drive.device = freerdp_device_new(RDPDR_DTYP_FILESYSTEM, ARRAYSIZE(args), args);
218 if (!drive.device)
219 goto fail;
220
221 WINPR_ASSERT(rdpdr->context.RdpdrRegisterDevice);
222 rc = rdpdr->context.RdpdrRegisterDevice(&rdpdr->context, drive.device, &drive.device->Id);
223 if (rc != CHANNEL_RC_OK)
224 goto fail;
225
226fail:
227 freerdp_device_free(drive.device);
228 return rc == CHANNEL_RC_OK;
229}
230
236static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 count,
237 const UINT32 ids[])
238{
239 wStream* s = NULL;
240
241 WINPR_ASSERT(rdpdr);
242 WINPR_ASSERT(ids || (count == 0));
243
244 if (count == 0)
245 return CHANNEL_RC_OK;
246
247 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_DEVICE_REMOVE_PDUS))
248 return CHANNEL_RC_OK;
249
250 s = StreamPool_Take(rdpdr->pool, count * sizeof(UINT32) + 8);
251
252 if (!s)
253 {
254 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
255 return CHANNEL_RC_NO_MEMORY;
256 }
257
258 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
259 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
260 Stream_Write_UINT32(s, count);
261
262 for (UINT32 i = 0; i < count; i++)
263 Stream_Write_UINT32(s, ids[i]);
264
265 Stream_SealLength(s);
266 return rdpdr_send(rdpdr, s);
267}
268
269#if defined(_UWP) || defined(__IOS__)
270
271static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
272 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
273{
274 return ERROR_CALL_NOT_IMPLEMENTED;
275}
276
277static void first_hotplug(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr)
278{
279}
280
281static DWORD WINAPI drive_hotplug_thread_func(WINPR_ATTR_UNUSED LPVOID arg)
282{
283 return CHANNEL_RC_OK;
284}
285
286static UINT drive_hotplug_thread_terminate(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr)
287{
288 return CHANNEL_RC_OK;
289}
290
291#elif defined(_WIN32)
292
293static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
294 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
295{
296 return CHANNEL_RC_OK;
297}
298
299static BOOL check_path(const char* path)
300{
301 UINT type = GetDriveTypeA(path);
302
303 if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
304 type == DRIVE_REMOTE))
305 return FALSE;
306
307 return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
308}
309
310static void first_hotplug(rdpdrPlugin* rdpdr)
311{
312 DWORD unitmask = GetLogicalDrives();
313
314 for (size_t i = 0; i < 26; i++)
315 {
316 if (unitmask & 0x01)
317 {
318 char drive_path[] = { 'c', ':', '\\', '\0' };
319 char drive_name[] = { 'c', '\0' };
320 drive_path[0] = 'A' + (char)i;
321 drive_name[0] = 'A' + (char)i;
322
323 if (check_path(drive_path))
324 {
325 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
326 }
327 }
328
329 unitmask = unitmask >> 1;
330 }
331}
332
333static LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
334{
336 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
337 UINT error;
338 rdpdr = (rdpdrPlugin*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
339
340 switch (Msg)
341 {
342 case WM_DEVICECHANGE:
343 switch (wParam)
344 {
345 case DBT_DEVICEARRIVAL:
346 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
347 {
348 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
349 DWORD unitmask = lpdbv->dbcv_unitmask;
350
351 for (int i = 0; i < 26; i++)
352 {
353 if (unitmask & 0x01)
354 {
355 char drive_path[] = { 'c', ':', '/', '\0' };
356 char drive_name[] = { 'c', '\0' };
357 drive_path[0] = 'A' + (char)i;
358 drive_name[0] = 'A' + (char)i;
359
360 if (check_path(drive_path))
361 {
362 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
363 }
364 }
365
366 unitmask = unitmask >> 1;
367 }
368 }
369
370 break;
371
372 case DBT_DEVICEREMOVECOMPLETE:
373 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
374 {
375 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
376 DWORD unitmask = lpdbv->dbcv_unitmask;
377 char drive_name_upper, drive_name_lower;
378 ULONG_PTR* keys = NULL;
379 DEVICE_DRIVE_EXT* device_ext;
380
381 for (int i = 0; i < 26; i++)
382 {
383 if (unitmask & 0x01)
384 {
385 drive_name_upper = 'A' + i;
386 drive_name_lower = 'a' + i;
387 const size_t count =
388 ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
389
390 for (size_t j = 0; j < count; j++)
391 {
392 device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
393 rdpdr->devman->devices, (void*)keys[j]);
394
395 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
396 continue;
397
398 if (device_ext->path[0] == drive_name_upper ||
399 device_ext->path[0] == drive_name_lower)
400 {
401 if (device_ext->automount)
402 {
403 const uint32_t ids[] = { keys[j] };
404 WINPR_ASSERT(rdpdr->context.RdpdrUnregisterDevice);
405 error = rdpdr->context.RdpdrUnregisterDevice(
406 &rdpdr->context, ARRAYSIZE(ids), ids);
407 if (error)
408 {
409 // don't end on error, just report ?
410 WLog_Print(
411 rdpdr->log, WLOG_ERROR,
412 "rdpdr_send_device_list_remove_request failed "
413 "with error %" PRIu32 "!",
414 error);
415 }
416
417 break;
418 }
419 }
420 }
421
422 free(keys);
423 }
424
425 unitmask = unitmask >> 1;
426 }
427 }
428
429 break;
430
431 default:
432 break;
433 }
434
435 break;
436
437 default:
438 return DefWindowProc(hWnd, Msg, wParam, lParam);
439 }
440
441 return DefWindowProc(hWnd, Msg, wParam, lParam);
442}
443
444static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
445{
447 WNDCLASSEX wnd_cls;
448 HWND hwnd;
449 MSG msg;
450 BOOL bRet;
451 DEV_BROADCAST_HANDLE NotificationFilter;
452 HDEVNOTIFY hDevNotify;
453 rdpdr = (rdpdrPlugin*)arg;
454 /* init windows class */
455 wnd_cls.cbSize = sizeof(WNDCLASSEX);
456 wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
457 wnd_cls.lpfnWndProc = hotplug_proc;
458 wnd_cls.cbClsExtra = 0;
459 wnd_cls.cbWndExtra = 0;
460 wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
461 wnd_cls.hCursor = NULL;
462 wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
463 wnd_cls.lpszMenuName = NULL;
464 wnd_cls.lpszClassName = L"DRIVE_HOTPLUG";
465 wnd_cls.hInstance = NULL;
466 wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
467 RegisterClassEx(&wnd_cls);
468 /* create window */
469 hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
470 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr);
471 rdpdr->hotplug_wnd = hwnd;
472 /* register device interface to hwnd */
473 NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
474 NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
475 hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
476
477 /* message loop */
478 while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
479 {
480 if (bRet == -1)
481 {
482 break;
483 }
484 else
485 {
486 TranslateMessage(&msg);
487 DispatchMessage(&msg);
488 }
489 }
490
491 UnregisterDeviceNotification(hDevNotify);
492 return CHANNEL_RC_OK;
493}
494
500static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
501{
502 UINT error = CHANNEL_RC_OK;
503
504 if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0))
505 {
506 error = GetLastError();
507 WLog_Print(rdpdr->log, WLOG_ERROR, "PostMessage failed with error %" PRIu32 "", error);
508 }
509
510 return error;
511}
512
513#elif defined(__MACOSX__)
514
515#define MAX_USB_DEVICES 100
516
517typedef struct
518{
519 char* path;
520 BOOL to_add;
521} hotplug_dev;
522
528static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
529 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
530{
531 WINPR_ASSERT(context);
532 rdpdrPlugin* rdpdr = context->handle;
533
534 struct dirent* pDirent = NULL;
535 char fullpath[PATH_MAX] = { 0 };
536 char* szdir = (char*)"/Volumes";
537 struct stat buf = { 0 };
538 hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
539 int count = 0;
540 DEVICE_DRIVE_EXT* device_ext = NULL;
541 ULONG_PTR* keys = NULL;
542 int size = 0;
543 UINT error = ERROR_INTERNAL_ERROR;
544 UINT32 ids[1];
545
546 DIR* pDir = opendir(szdir);
547
548 if (pDir == NULL)
549 {
550 printf("Cannot open directory\n");
551 return ERROR_OPEN_FAILED;
552 }
553
554 while ((pDirent = readdir(pDir)) != NULL)
555 {
556 if (pDirent->d_name[0] != '.')
557 {
558 (void)sprintf_s(fullpath, ARRAYSIZE(fullpath), "%s/%s", szdir, pDirent->d_name);
559 if (stat(fullpath, &buf) != 0)
560 continue;
561
562 if (S_ISDIR(buf.st_mode))
563 {
564 dev_array[size].path = _strdup(fullpath);
565
566 if (!dev_array[size].path)
567 {
568 closedir(pDir);
569 error = CHANNEL_RC_NO_MEMORY;
570 goto cleanup;
571 }
572
573 dev_array[size++].to_add = TRUE;
574 }
575 }
576 }
577
578 closedir(pDir);
579 /* delete removed devices */
580 count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
581
582 for (size_t j = 0; j < count; j++)
583 {
584 char* path = NULL;
585 BOOL dev_found = FALSE;
586 device_ext =
587 (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[j]);
588
589 if (!device_ext || !device_ext->automount)
590 continue;
591
592 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
593 continue;
594
595 if (device_ext->path == NULL)
596 continue;
597
598 path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
599 if (!path)
600 continue;
601
602 /* not pluggable device */
603 if (strstr(path, "/Volumes/") == NULL)
604 {
605 free(path);
606 continue;
607 }
608
609 for (size_t i = 0; i < size; i++)
610 {
611 if (strstr(path, dev_array[i].path) != NULL)
612 {
613 dev_found = TRUE;
614 dev_array[i].to_add = FALSE;
615 break;
616 }
617 }
618
619 free(path);
620
621 if (!dev_found)
622 {
623 const uint32_t ids[] = { keys[j] };
624 WINPR_ASSERT(rdpdr->context.RdpdrUnregisterDevice);
625 error = rdpdr->context.RdpdrUnregisterDevice(&rdpdr->context, ARRAYSIZE(ids), ids);
626 if (error)
627 {
628 WLog_Print(rdpdr->log, WLOG_ERROR,
629 "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!",
630 error);
631 goto cleanup;
632 }
633 }
634 }
635
636 /* add new devices */
637 for (size_t i = 0; i < size; i++)
638 {
639 const hotplug_dev* dev = &dev_array[i];
640 if (dev->to_add)
641 {
642 const char* path = dev->path;
643 const char* name = strrchr(path, '/') + 1;
644 error = rdpdr_load_drive(rdpdr, name, path, TRUE);
645 if (error)
646 goto cleanup;
647 }
648 }
649
650cleanup:
651 free(keys);
652
653 for (size_t i = 0; i < size; i++)
654 free(dev_array[i].path);
655
656 return error;
657}
658
659static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,
660 void* clientCallBackInfo, size_t numEvents,
661 void* eventPaths,
662 const FSEventStreamEventFlags eventFlags[],
663 const FSEventStreamEventId eventIds[])
664{
666 UINT error;
667 char** paths = (char**)eventPaths;
668 rdpdr = (rdpdrPlugin*)clientCallBackInfo;
669
670 for (size_t i = 0; i < numEvents; i++)
671 {
672 if (strcmp(paths[i], "/Volumes/") == 0)
673 {
674 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
675 if (rdpdr->context.RdpdrHotplugDevice)
676 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context,
677 RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
678 switch (error)
679 {
680 case ERROR_DISK_CHANGE:
681 case CHANNEL_RC_OK:
682 break;
683 case ERROR_CALL_NOT_IMPLEMENTED:
684 break;
685 default:
686 WLog_Print(rdpdr->log, WLOG_ERROR,
687 "handle_hotplug failed with error %" PRIu32 "!", error);
688 break;
689 }
690 }
691 }
692}
693
694static void first_hotplug(rdpdrPlugin* rdpdr)
695{
696 WINPR_ASSERT(rdpdr);
697 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
698 if (rdpdr->context.RdpdrHotplugDevice)
699 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
700
701 switch (error)
702 {
703 case ERROR_DISK_CHANGE:
704 case CHANNEL_RC_OK:
705 case ERROR_CALL_NOT_IMPLEMENTED:
706 break;
707 default:
708 WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!",
709 error);
710 break;
711 }
712}
713
714static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
715{
717 WINPR_ASSERT(rdpdr);
718 WINPR_ASSERT(rdpdr->stopEvent);
719
720 CFStringRef path = CFSTR("/Volumes/");
721 CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (const void**)&path, 1, NULL);
722 FSEventStreamContext ctx = {
723 .copyDescription = NULL, .info = arg, .release = NULL, .retain = NULL, .version = 0
724 };
725 FSEventStreamRef fsev =
726 FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch,
727 kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
728
729 dispatch_queue_t queue = dispatch_queue_create(TAG, NULL);
730 FSEventStreamSetDispatchQueue(fsev, queue);
731 FSEventStreamStart(fsev);
732 WLog_Print(rdpdr->log, WLOG_DEBUG, "Started hotplug watcher");
733 HANDLE handles[] = { rdpdr->stopEvent, freerdp_abort_event(rdpdr->rdpcontext) };
734 WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
735 WLog_Print(rdpdr->log, WLOG_DEBUG, "Stopped hotplug watcher");
736 FSEventStreamStop(fsev);
737 FSEventStreamRelease(fsev);
738 dispatch_release(queue);
739out:
740 ExitThread(CHANNEL_RC_OK);
741 return CHANNEL_RC_OK;
742}
743
744#else
745
746static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s",
747 "/media", "/mnt" };
748
749static BOOL isAutomountLocation(const char* path)
750{
751 const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]);
752 char buffer[MAX_PATH] = { 0 };
753 uid_t uid = getuid();
754 char uname[MAX_PATH] = { 0 };
755 ULONG size = sizeof(uname) - 1;
756
757 if (!GetUserNameExA(NameSamCompatible, uname, &size))
758 return FALSE;
759
760 if (!path)
761 return FALSE;
762
763 for (size_t x = 0; x < nrLocations; x++)
764 {
765 const char* location = automountLocations[x];
766 size_t length = 0;
767
768 WINPR_PRAGMA_DIAG_PUSH
769 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
770 if (strstr(location, "%lu"))
771 (void)snprintf(buffer, sizeof(buffer), location, (unsigned long)uid);
772 else if (strstr(location, "%s"))
773 (void)snprintf(buffer, sizeof(buffer), location, uname);
774 else
775 (void)snprintf(buffer, sizeof(buffer), "%s", location);
776 WINPR_PRAGMA_DIAG_POP
777
778 length = strnlen(buffer, sizeof(buffer));
779
780 if (strncmp(buffer, path, length) == 0)
781 {
782 const char* rest = &path[length];
783
784 /* Only consider mount locations with max depth of 1 below the
785 * base path or the base path itself. */
786 if (*rest == '\0')
787 return TRUE;
788 else if (*rest == '/')
789 {
790 const char* token = strstr(&rest[1], "/");
791
792 if (!token || (token[1] == '\0'))
793 return TRUE;
794 }
795 }
796 }
797
798 return FALSE;
799}
800
801#define MAX_USB_DEVICES 100
802
803typedef struct
804{
805 char* path;
806 BOOL to_add;
807} hotplug_dev;
808
809static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* mountpoint)
810{
811 if (!mountpoint)
812 return;
813 /* copy hotpluged device mount point to the dev_array */
814 if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
815 {
816 dev_array[*size].path = _strdup(mountpoint);
817 dev_array[*size].to_add = TRUE;
818 (*size)++;
819 }
820}
821
822#ifdef __sun
823#include <sys/mnttab.h>
824static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array, size_t* size)
825{
826 FILE* f;
827 struct mnttab ent;
828 f = winpr_fopen("/etc/mnttab", "r");
829 if (f == NULL)
830 {
831 WLog_Print(log, WLOG_ERROR, "fopen failed!");
832 return ERROR_OPEN_FAILED;
833 }
834 while (getmntent(f, &ent) == 0)
835 {
836 handle_mountpoint(dev_array, size, ent.mnt_mountp);
837 }
838 fclose(f);
839 return ERROR_SUCCESS;
840}
841#endif
842
843#if defined(__FreeBSD__) || defined(__OpenBSD__)
844#include <sys/mount.h>
845static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array, size_t* size)
846{
847 int mntsize;
848 struct statfs* mntbuf = NULL;
849
850 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
851 if (!mntsize)
852 {
853 /* TODO: handle 'errno' */
854 WLog_Print(log, WLOG_ERROR, "getmntinfo failed!");
855 return ERROR_OPEN_FAILED;
856 }
857 for (size_t idx = 0; idx < (size_t)mntsize; idx++)
858 {
859 handle_mountpoint(dev_array, size, mntbuf[idx].f_mntonname);
860 }
861 free(mntbuf);
862 return ERROR_SUCCESS;
863}
864#endif
865
866#if defined(__LINUX__) || defined(__linux__)
867#include <mntent.h>
868static struct mntent* getmntent_x(FILE* f, struct mntent* buffer, char* pathbuffer,
869 size_t pathbuffersize)
870{
871#if defined(FREERDP_HAVE_GETMNTENT_R)
872 WINPR_ASSERT(pathbuffersize <= INT32_MAX);
873 return getmntent_r(f, buffer, pathbuffer, (int)pathbuffersize);
874#else
875 (void)buffer;
876 (void)pathbuffer;
877 (void)pathbuffersize;
878 return getmntent(f);
879#endif
880}
881
882static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array, size_t* size)
883{
884 FILE* f = NULL;
885 struct mntent mnt = { 0 };
886 char pathbuffer[PATH_MAX] = { 0 };
887 struct mntent* ent = NULL;
888 f = winpr_fopen("/proc/mounts", "r");
889 if (f == NULL)
890 {
891 WLog_Print(log, WLOG_ERROR, "fopen failed!");
892 return ERROR_OPEN_FAILED;
893 }
894 while ((ent = getmntent_x(f, &mnt, pathbuffer, sizeof(pathbuffer))) != NULL)
895 {
896 handle_mountpoint(dev_array, size, ent->mnt_dir);
897 }
898 (void)fclose(f);
899 return ERROR_SUCCESS;
900}
901#endif
902
903static UINT handle_platform_mounts(wLog* log, hotplug_dev* dev_array, size_t* size)
904{
905#ifdef __sun
906 return handle_platform_mounts_sun(log, dev_array, size);
907#elif defined(__FreeBSD__) || defined(__OpenBSD__)
908 return handle_platform_mounts_bsd(log, dev_array, size);
909#elif defined(__LINUX__) || defined(__linux__)
910 return handle_platform_mounts_linux(log, dev_array, size);
911#endif
912 return ERROR_CALL_NOT_IMPLEMENTED;
913}
914
915static BOOL device_not_plugged(ULONG_PTR key, void* element, void* data)
916{
917 const WCHAR* path = (const WCHAR*)data;
918 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
919
920 WINPR_UNUSED(key);
921 WINPR_ASSERT(path);
922
923 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path)
924 return TRUE;
925 if (_wcscmp(device_ext->path, path) != 0)
926 return TRUE;
927 return FALSE;
928}
929
930static BOOL device_already_plugged(rdpdrPlugin* rdpdr, const hotplug_dev* device)
931{
932 BOOL rc = FALSE;
933 WCHAR* path = NULL;
934
935 if (!rdpdr || !device)
936 return TRUE;
937 if (!device->to_add)
938 return TRUE;
939
940 WINPR_ASSERT(rdpdr->devman);
941 WINPR_ASSERT(device->path);
942
943 path = ConvertUtf8ToWCharAlloc(device->path, NULL);
944 if (!path)
945 return TRUE;
946
947 rc = device_foreach(rdpdr, TRUE, device_not_plugged, path);
948 free(path);
949 return !rc;
950}
951
952struct hotplug_delete_arg
953{
954 hotplug_dev* dev_array;
955 size_t dev_array_size;
957};
958
959static BOOL hotplug_delete_foreach(ULONG_PTR key, void* element, void* data)
960{
961 char* path = NULL;
962 BOOL dev_found = FALSE;
963 struct hotplug_delete_arg* arg = (struct hotplug_delete_arg*)data;
964 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
965
966 WINPR_ASSERT(arg);
967 WINPR_ASSERT(arg->rdpdr);
968 WINPR_ASSERT(arg->dev_array || (arg->dev_array_size == 0));
969 WINPR_ASSERT(key <= UINT32_MAX);
970
971 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path ||
972 !device_ext->automount)
973 return TRUE;
974
975 WINPR_ASSERT(device_ext->path);
976 path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
977 if (!path)
978 return FALSE;
979
980 /* not pluggable device */
981 if (isAutomountLocation(path))
982 {
983 for (size_t i = 0; i < arg->dev_array_size; i++)
984 {
985 hotplug_dev* cur = &arg->dev_array[i];
986 if (cur->path && strstr(path, cur->path) != NULL)
987 {
988 dev_found = TRUE;
989 cur->to_add = FALSE;
990 break;
991 }
992 }
993 }
994
995 free(path);
996
997 if (!dev_found)
998 {
999 const UINT32 ids[1] = { (UINT32)key };
1000 WINPR_ASSERT(arg->rdpdr->context.RdpdrUnregisterDevice);
1001 const UINT error =
1002 arg->rdpdr->context.RdpdrUnregisterDevice(&arg->rdpdr->context, ARRAYSIZE(ids), ids);
1003
1004 if (error)
1005 {
1006 WLog_Print(arg->rdpdr->log, WLOG_ERROR,
1007 "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!",
1008 error);
1009 return FALSE;
1010 }
1011 }
1012
1013 return TRUE;
1014}
1015
1016static UINT handle_hotplug(RdpdrClientContext* context,
1017 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
1018{
1019 WINPR_ASSERT(context);
1020 rdpdrPlugin* rdpdr = context->handle;
1021
1022 hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
1023 size_t size = 0;
1024 UINT error = ERROR_SUCCESS;
1025 struct hotplug_delete_arg arg = { dev_array, ARRAYSIZE(dev_array), rdpdr };
1026
1027 WINPR_ASSERT(rdpdr);
1028 WINPR_ASSERT(rdpdr->devman);
1029
1030 error = handle_platform_mounts(rdpdr->log, dev_array, &size);
1031
1032 /* delete removed devices */
1033 /* Ignore result */ device_foreach(rdpdr, FALSE, hotplug_delete_foreach, &arg);
1034
1035 /* add new devices */
1036 for (size_t i = 0; i < size; i++)
1037 {
1038 hotplug_dev* cur = &dev_array[i];
1039 if (!device_already_plugged(rdpdr, cur))
1040 {
1041 const char* path = cur->path;
1042 const char* name = strrchr(path, '/') + 1;
1043
1044 rdpdr_load_drive(rdpdr, name, path, TRUE);
1045 error = ERROR_DISK_CHANGE;
1046 }
1047 }
1048
1049 for (size_t i = 0; i < size; i++)
1050 free(dev_array[i].path);
1051
1052 return error;
1053}
1054
1055static void first_hotplug(rdpdrPlugin* rdpdr)
1056{
1057 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
1058
1059 WINPR_ASSERT(rdpdr);
1060 if (rdpdr->context.RdpdrHotplugDevice)
1061 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
1062
1063 switch (error)
1064 {
1065 case ERROR_DISK_CHANGE:
1066 case CHANNEL_RC_OK:
1067 case ERROR_OPEN_FAILED:
1068 case ERROR_CALL_NOT_IMPLEMENTED:
1069 break;
1070 default:
1071 WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!",
1072 error);
1073 break;
1074 }
1075}
1076
1077static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
1078{
1079 rdpdrPlugin* rdpdr = (rdpdrPlugin*)arg;
1080
1081 WINPR_ASSERT(rdpdr);
1082 WINPR_ASSERT(rdpdr->stopEvent);
1083
1084 while (WaitForSingleObject(rdpdr->stopEvent, 1000) == WAIT_TIMEOUT)
1085 {
1086 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
1087 if (rdpdr->context.RdpdrHotplugDevice)
1088 error =
1089 rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
1090 switch (error)
1091 {
1092 case ERROR_DISK_CHANGE:
1093 break;
1094 case CHANNEL_RC_OK:
1095 case ERROR_OPEN_FAILED:
1096 case ERROR_CALL_NOT_IMPLEMENTED:
1097 break;
1098 default:
1099 WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!",
1100 error);
1101 goto out;
1102 }
1103 }
1104
1105out:
1106{
1107 const UINT error = GetLastError();
1108 if (error && rdpdr->rdpcontext)
1109 setChannelError(rdpdr->rdpcontext, error, "reported an error");
1110
1111 ExitThread(error);
1112 return error;
1113}
1114}
1115
1116#endif
1117
1118#if !defined(_WIN32) && !defined(__IOS__)
1124static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
1125{
1126 UINT error = 0;
1127
1128 WINPR_ASSERT(rdpdr);
1129
1130 if (rdpdr->hotplugThread)
1131 {
1132#if !defined(_WIN32)
1133 if (rdpdr->stopEvent)
1134 (void)SetEvent(rdpdr->stopEvent);
1135#endif
1136
1137 if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED)
1138 {
1139 error = GetLastError();
1140 WLog_Print(rdpdr->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!",
1141 error);
1142 return error;
1143 }
1144
1145 (void)CloseHandle(rdpdr->hotplugThread);
1146 rdpdr->hotplugThread = NULL;
1147 }
1148
1149 return CHANNEL_RC_OK;
1150}
1151
1152#endif
1153
1154static UINT rdpdr_add_devices(rdpdrPlugin* rdpdr)
1155{
1156 WINPR_ASSERT(rdpdr);
1157 WINPR_ASSERT(rdpdr->rdpcontext);
1158
1159 rdpSettings* settings = rdpdr->rdpcontext->settings;
1160 WINPR_ASSERT(settings);
1161
1162 for (UINT32 index = 0; index < freerdp_settings_get_uint32(settings, FreeRDP_DeviceCount);
1163 index++)
1164 {
1165 RDPDR_DEVICE* device =
1166 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_DeviceArray, index);
1167 WINPR_ASSERT(device);
1168
1169 if (device->Type == RDPDR_DTYP_FILESYSTEM)
1170 {
1171 const char DynamicDrives[] = "DynamicDrives";
1172 const RDPDR_DRIVE* drive = (const RDPDR_DRIVE*)device;
1173 if (!drive->Path)
1174 continue;
1175
1176 const char wildcard[] = "*";
1177 BOOL hotplugAll = strncmp(drive->Path, wildcard, sizeof(wildcard)) == 0;
1178 BOOL hotplugLater = strncmp(drive->Path, DynamicDrives, sizeof(DynamicDrives)) == 0;
1179
1180 if (hotplugAll || hotplugLater)
1181 {
1182 if (!rdpdr->async)
1183 {
1184 WLog_Print(rdpdr->log, WLOG_WARN,
1185 "Drive hotplug is not supported in synchronous mode!");
1186 continue;
1187 }
1188
1189 if (hotplugAll)
1190 first_hotplug(rdpdr);
1191
1192 /* There might be multiple hotplug related device entries.
1193 * Ensure the thread is only started once
1194 */
1195 if (!rdpdr->hotplugThread)
1196 {
1197 rdpdr->hotplugThread =
1198 CreateThread(NULL, 0, drive_hotplug_thread_func, rdpdr, 0, NULL);
1199 if (!rdpdr->hotplugThread)
1200 {
1201 WLog_Print(rdpdr->log, WLOG_ERROR, "CreateThread failed!");
1202 return ERROR_INTERNAL_ERROR;
1203 }
1204 }
1205
1206 continue;
1207 }
1208 }
1209
1210 const UINT error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext);
1211 if (error)
1212 {
1213 WLog_Print(rdpdr->log, WLOG_ERROR,
1214 "devman_load_device_service failed with error %" PRIu32 "!", error);
1215 return error;
1216 }
1217 }
1218 return CHANNEL_RC_OK;
1219}
1220
1226static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr)
1227{
1228 WINPR_ASSERT(rdpdr);
1229
1230 rdpdr->devman = devman_new(rdpdr);
1231
1232 if (!rdpdr->devman)
1233 {
1234 WLog_Print(rdpdr->log, WLOG_ERROR, "devman_new failed!");
1235 return CHANNEL_RC_NO_MEMORY;
1236 }
1237
1238 WINPR_ASSERT(rdpdr->rdpcontext);
1239
1240 rdpSettings* settings = rdpdr->rdpcontext->settings;
1241 WINPR_ASSERT(settings);
1242
1243 rdpdr->ignoreInvalidDevices = freerdp_settings_get_bool(settings, FreeRDP_IgnoreInvalidDevices);
1244
1245 const char* name = freerdp_settings_get_string(settings, FreeRDP_ClientHostname);
1246 if (!name)
1247 name = freerdp_settings_get_string(settings, FreeRDP_ComputerName);
1248 if (!name)
1249 {
1250 DWORD size = ARRAYSIZE(rdpdr->computerName);
1251 if (!GetComputerNameExA(ComputerNameNetBIOS, rdpdr->computerName, &size))
1252 return ERROR_INTERNAL_ERROR;
1253 }
1254 else
1255 strncpy(rdpdr->computerName, name, strnlen(name, sizeof(rdpdr->computerName)));
1256
1257 return rdpdr_add_devices(rdpdr);
1258}
1259
1260static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s)
1261{
1262 WINPR_ASSERT(rdpdr);
1263 WINPR_ASSERT(s);
1264
1265 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1266 return ERROR_INVALID_DATA;
1267
1268 Stream_Read_UINT16(s, rdpdr->serverVersionMajor);
1269 Stream_Read_UINT16(s, rdpdr->serverVersionMinor);
1270 Stream_Read_UINT32(s, rdpdr->clientID);
1271 rdpdr->sequenceId++;
1272
1273 rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, rdpdr->serverVersionMajor);
1274 rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, rdpdr->serverVersionMinor);
1275 WLog_Print(rdpdr->log, WLOG_DEBUG,
1276 "[rdpdr] server announces version %" PRIu32 ".%" PRIu32 ", client uses %" PRIu32
1277 ".%" PRIu32,
1278 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1279 rdpdr->clientVersionMinor);
1280 return CHANNEL_RC_OK;
1281}
1282
1288static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
1289{
1290 wStream* s = NULL;
1291
1292 WINPR_ASSERT(rdpdr);
1293 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE);
1294 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
1295
1296 s = StreamPool_Take(rdpdr->pool, 12);
1297
1298 if (!s)
1299 {
1300 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
1301 return CHANNEL_RC_NO_MEMORY;
1302 }
1303
1304 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
1305 Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
1306 Stream_Write_UINT16(s, rdpdr->clientVersionMajor);
1307 Stream_Write_UINT16(s, rdpdr->clientVersionMinor);
1308 Stream_Write_UINT32(s, rdpdr->clientID);
1309 return rdpdr_send(rdpdr, s);
1310}
1311
1317static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
1318{
1319 wStream* s = NULL;
1320 WCHAR* computerNameW = NULL;
1321 size_t computerNameLenW = 0;
1322
1323 WINPR_ASSERT(rdpdr);
1324 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
1325 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_NAME_REQUEST);
1326
1327 const size_t len = strnlen(rdpdr->computerName, sizeof(rdpdr->computerName));
1328 if (len == 0)
1329 return ERROR_INTERNAL_ERROR;
1330
1331 WINPR_ASSERT(rdpdr->computerName);
1332 computerNameW = ConvertUtf8NToWCharAlloc(rdpdr->computerName, len, &computerNameLenW);
1333 computerNameLenW *= sizeof(WCHAR);
1334
1335 if (computerNameLenW > 0)
1336 computerNameLenW += sizeof(WCHAR); // also write '\0'
1337
1338 s = StreamPool_Take(rdpdr->pool, 16U + computerNameLenW);
1339
1340 if (!s)
1341 {
1342 free(computerNameW);
1343 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
1344 return CHANNEL_RC_NO_MEMORY;
1345 }
1346
1347 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
1348 Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */
1349 Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
1350 Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
1351 Stream_Write_UINT32(s,
1352 (UINT32)computerNameLenW); /* computerNameLen, including null terminator */
1353 Stream_Write(s, computerNameW, computerNameLenW);
1354 free(computerNameW);
1355 return rdpdr_send(rdpdr, s);
1356}
1357
1358static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s)
1359{
1360 UINT16 versionMajor = 0;
1361 UINT16 versionMinor = 0;
1362 UINT32 clientID = 0;
1363
1364 WINPR_ASSERT(rdpdr);
1365 WINPR_ASSERT(s);
1366
1367 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1368 return ERROR_INVALID_DATA;
1369
1370 Stream_Read_UINT16(s, versionMajor);
1371 Stream_Read_UINT16(s, versionMinor);
1372 Stream_Read_UINT32(s, clientID);
1373
1374 if (versionMajor != rdpdr->clientVersionMajor || versionMinor != rdpdr->clientVersionMinor)
1375 {
1376 WLog_Print(rdpdr->log, WLOG_WARN,
1377 "[rdpdr] server announced version %" PRIu32 ".%" PRIu32 ", client uses %" PRIu32
1378 ".%" PRIu32 " but clientid confirm requests version %" PRIu32 ".%" PRIu32,
1379 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1380 rdpdr->clientVersionMinor, versionMajor, versionMinor);
1381 rdpdr->clientVersionMajor = versionMajor;
1382 rdpdr->clientVersionMinor = versionMinor;
1383 }
1384
1385 if (clientID != rdpdr->clientID)
1386 rdpdr->clientID = clientID;
1387
1388 return CHANNEL_RC_OK;
1389}
1390
1391struct device_announce_arg
1392{
1394 wStream* s;
1395 BOOL userLoggedOn;
1396 UINT32 count;
1397};
1398
1399static BOOL device_announce(ULONG_PTR key, void* element, void* data)
1400{
1401 struct device_announce_arg* arg = data;
1402 rdpdrPlugin* rdpdr = NULL;
1403 DEVICE* device = (DEVICE*)element;
1404
1405 WINPR_UNUSED(key);
1406
1407 WINPR_ASSERT(arg);
1408 WINPR_ASSERT(device);
1409 WINPR_ASSERT(arg->rdpdr);
1410 WINPR_ASSERT(arg->s);
1411
1412 rdpdr = arg->rdpdr;
1413
1421 if ((rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) ||
1422 (device->type == RDPDR_DTYP_SMARTCARD) || arg->userLoggedOn)
1423 {
1424 size_t data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
1425
1426 if (!Stream_EnsureRemainingCapacity(arg->s, 20 + data_len))
1427 {
1428 Stream_Release(arg->s);
1429 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
1430 return FALSE;
1431 }
1432
1433 Stream_Write_UINT32(arg->s, device->type); /* deviceType */
1434 Stream_Write_UINT32(arg->s, device->id); /* deviceID */
1435 strncpy(Stream_Pointer(arg->s), device->name, 8);
1436
1437 for (size_t i = 0; i < 8; i++)
1438 {
1439 BYTE c = 0;
1440 Stream_Peek_UINT8(arg->s, c);
1441
1442 if (c > 0x7F)
1443 Stream_Write_UINT8(arg->s, '_');
1444 else
1445 Stream_Seek_UINT8(arg->s);
1446 }
1447
1448 WINPR_ASSERT(data_len <= UINT32_MAX);
1449 Stream_Write_UINT32(arg->s, (UINT32)data_len);
1450
1451 if (data_len > 0)
1452 Stream_Write(arg->s, Stream_Buffer(device->data), data_len);
1453
1454 arg->count++;
1455 WLog_Print(rdpdr->log, WLOG_INFO,
1456 "registered [%9s] device #%" PRIu32 ": %5s (type=%2" PRIu32 " id=%2" PRIu32 ")",
1457 rdpdr_device_type_string(device->type), arg->count, device->name, device->type,
1458 device->id);
1459 }
1460 return TRUE;
1461}
1462
1463static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn)
1464{
1465 size_t pos = 0;
1466 wStream* s = NULL;
1467 size_t count_pos = 0;
1468 struct device_announce_arg arg = { 0 };
1469
1470 WINPR_ASSERT(rdpdr);
1471 WINPR_ASSERT(rdpdr->devman);
1472
1473 if (userLoggedOn)
1474 {
1475 rdpdr->userLoggedOn = TRUE;
1476 }
1477
1478 s = StreamPool_Take(rdpdr->pool, 256);
1479
1480 if (!s)
1481 {
1482 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
1483 return CHANNEL_RC_NO_MEMORY;
1484 }
1485
1486 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
1487 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
1488 count_pos = Stream_GetPosition(s);
1489 Stream_Seek_UINT32(s); /* deviceCount */
1490
1491 arg.rdpdr = rdpdr;
1492 arg.userLoggedOn = userLoggedOn;
1493 arg.s = s;
1494 if (!device_foreach(rdpdr, TRUE, device_announce, &arg))
1495 return ERROR_INVALID_DATA;
1496
1497 if (arg.count == 0)
1498 {
1499 Stream_Release(s);
1500 return CHANNEL_RC_OK;
1501 }
1502 pos = Stream_GetPosition(s);
1503 Stream_SetPosition(s, count_pos);
1504 Stream_Write_UINT32(s, arg.count);
1505 Stream_SetPosition(s, pos);
1506 Stream_SealLength(s);
1507 return rdpdr_send(rdpdr, s);
1508}
1509
1510UINT rdpdr_try_send_device_list_announce_request(rdpdrPlugin* rdpdr)
1511{
1512 WINPR_ASSERT(rdpdr);
1513 if (rdpdr->state != RDPDR_CHANNEL_STATE_READY)
1514 {
1515 WLog_Print(rdpdr->log, WLOG_DEBUG,
1516 "hotplug event received, but channel [RDPDR] is not ready (state %s), ignoring.",
1517 rdpdr_state_str(rdpdr->state));
1518 return CHANNEL_RC_OK;
1519 }
1520 return rdpdr_send_device_list_announce_request(rdpdr, rdpdr->userLoggedOn);
1521}
1522
1523static UINT dummy_irp_response(rdpdrPlugin* rdpdr, wStream* s)
1524{
1525 WINPR_ASSERT(rdpdr);
1526 WINPR_ASSERT(s);
1527
1528 wStream* output = StreamPool_Take(rdpdr->pool, 256); // RDPDR_DEVICE_IO_RESPONSE_LENGTH
1529 if (!output)
1530 {
1531 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
1532 return CHANNEL_RC_NO_MEMORY;
1533 }
1534
1535 Stream_SetPosition(s, 4); /* see "rdpdr_process_receive" */
1536
1537 const uint32_t DeviceId = Stream_Get_UINT32(s); /* DeviceId (4 bytes) */
1538 const uint32_t FileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
1539 const uint32_t CompletionId = Stream_Get_UINT32(s); /* CompletionId (4 bytes) */
1540
1541 WLog_Print(rdpdr->log, WLOG_WARN,
1542 "Dummy response {DeviceId=%" PRIu32 ", FileId=%" PRIu32 ", CompletionId=%" PRIu32
1543 "}",
1544 DeviceId, FileId, CompletionId);
1545 if (!rdpdr_write_iocompletion_header(output, DeviceId, CompletionId, STATUS_UNSUCCESSFUL))
1546 return CHANNEL_RC_NO_MEMORY;
1547
1548 return rdpdr_send(rdpdr, output);
1549}
1550
1556static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
1557{
1558 IRP* irp = NULL;
1559 UINT error = CHANNEL_RC_OK;
1560
1561 WINPR_ASSERT(rdpdr);
1562 WINPR_ASSERT(s);
1563
1564 irp = irp_new(rdpdr->devman, rdpdr->pool, s, rdpdr->log, &error);
1565
1566 if (!irp)
1567 {
1568 if ((error == CHANNEL_RC_OK) ||
1569 (error == ERROR_DEV_NOT_EXIST && rdpdr->ignoreInvalidDevices))
1570 {
1571 return dummy_irp_response(rdpdr, s);
1572 }
1573
1574 WLog_Print(rdpdr->log, WLOG_ERROR, "irp_new failed with %" PRIu32 "!", error);
1575 return error;
1576 }
1577
1578 if (irp->device->IRPRequest)
1579 IFCALLRET(irp->device->IRPRequest, error, irp->device, irp);
1580 else
1581 irp->Discard(irp);
1582
1583 if (error != CHANNEL_RC_OK)
1584 {
1585 WLog_Print(rdpdr->log, WLOG_ERROR, "device->IRPRequest failed with error %" PRIu32 "",
1586 error);
1587 irp->Discard(irp);
1588 }
1589
1590 return error;
1591}
1592
1593static UINT rdpdr_process_component(rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
1594 wStream* s)
1595{
1596 UINT32 type = 0;
1597 DEVICE* device = NULL;
1598
1599 WINPR_ASSERT(rdpdr);
1600 WINPR_ASSERT(s);
1601
1602 switch (component)
1603 {
1604 case RDPDR_CTYP_PRN:
1605 type = RDPDR_DTYP_PRINT;
1606 break;
1607
1608 default:
1609 return ERROR_INVALID_DATA;
1610 }
1611
1612 device = devman_get_device_by_type(rdpdr->devman, type);
1613
1614 if (!device)
1615 return ERROR_DEV_NOT_EXIST;
1616
1617 return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
1618 packetId, s);
1619}
1620
1626static BOOL device_init(ULONG_PTR key, void* element, void* data)
1627{
1628 wLog* log = data;
1629 UINT error = CHANNEL_RC_OK;
1630 DEVICE* device = element;
1631
1632 WINPR_UNUSED(key);
1633 WINPR_UNUSED(data);
1634
1635 IFCALLRET(device->Init, error, device);
1636
1637 if (error != CHANNEL_RC_OK)
1638 {
1639 WLog_Print(log, WLOG_ERROR, "Device init failed with %s", WTSErrorToString(error));
1640 return FALSE;
1641 }
1642 return TRUE;
1643}
1644
1645static UINT rdpdr_process_init(rdpdrPlugin* rdpdr)
1646{
1647 WINPR_ASSERT(rdpdr);
1648 WINPR_ASSERT(rdpdr->devman);
1649
1650 rdpdr->userLoggedOn = FALSE; /* reset possible received state */
1651 if (!device_foreach(rdpdr, TRUE, device_init, rdpdr->log))
1652 return ERROR_INTERNAL_ERROR;
1653 return CHANNEL_RC_OK;
1654}
1655
1656static BOOL state_match(enum RDPDR_CHANNEL_STATE state, size_t count, va_list ap)
1657{
1658 for (size_t x = 0; x < count; x++)
1659 {
1660 enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE);
1661 if (state == cur)
1662 return TRUE;
1663 }
1664 return FALSE;
1665}
1666
1667static const char* state_str(size_t count, va_list ap, char* buffer, size_t size)
1668{
1669 for (size_t x = 0; x < count; x++)
1670 {
1671 enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE);
1672 const char* curstr = rdpdr_state_str(cur);
1673 winpr_str_append(curstr, buffer, size, "|");
1674 }
1675 return buffer;
1676}
1677
1678static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, enum RDPDR_CHANNEL_STATE next,
1679 size_t count, ...)
1680{
1681 va_list ap = { 0 };
1682 WINPR_ASSERT(rdpdr);
1683
1684 va_start(ap, count);
1685 BOOL rc = state_match(rdpdr->state, count, ap);
1686 va_end(ap);
1687
1688 if (!rc)
1689 {
1690 const char* strstate = rdpdr_state_str(rdpdr->state);
1691 char buffer[256] = { 0 };
1692
1693 va_start(ap, count);
1694 state_str(count, ap, buffer, sizeof(buffer));
1695 va_end(ap);
1696
1697 WLog_Print(rdpdr->log, WLOG_ERROR,
1698 "channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.",
1699 rdpdr_packetid_string(packetid), buffer, strstate);
1700
1701 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
1702 return FALSE;
1703 }
1704 return rdpdr_state_advance(rdpdr, next);
1705}
1706
1707static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid)
1708{
1709 WINPR_ASSERT(rdpdr);
1710
1711 switch (packetid)
1712 {
1713 case PAKID_CORE_SERVER_ANNOUNCE:
1714 /* windows servers sometimes send this message.
1715 * it seems related to session login (e.g. first initialization for RDP/TLS style login,
1716 * then reinitialize the channel after login successful
1717 */
1718 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
1719 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1,
1720 RDPDR_CHANNEL_STATE_INITIAL);
1721 case PAKID_CORE_SERVER_CAPABILITY:
1722 return rdpdr_state_check(
1723 rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6,
1724 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_SERVER_CAPS,
1725 RDPDR_CHANNEL_STATE_READY, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1726 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1727 case PAKID_CORE_CLIENTID_CONFIRM:
1728 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 5,
1729 RDPDR_CHANNEL_STATE_NAME_REQUEST,
1730 RDPDR_CHANNEL_STATE_SERVER_CAPS,
1731 RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY,
1732 RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1733 case PAKID_CORE_USER_LOGGEDON:
1734 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU))
1735 return FALSE;
1736
1737 return rdpdr_state_check(
1738 rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4,
1739 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1740 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY);
1741 default:
1742 {
1743 enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY;
1744 return rdpdr_state_check(rdpdr, packetid, state, 1, state);
1745 }
1746 }
1747}
1748
1749static BOOL tryAdvance(rdpdrPlugin* rdpdr)
1750{
1751 if (rdpdr->haveClientId && rdpdr->haveServerCaps)
1752 {
1753 const UINT error = rdpdr_send_device_list_announce_request(rdpdr, FALSE);
1754 if (error)
1755 {
1756 WLog_Print(rdpdr->log, WLOG_ERROR,
1757 "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
1758 error);
1759 return FALSE;
1760 }
1761 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
1762 return FALSE;
1763 }
1764 return TRUE;
1765}
1766
1772static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
1773{
1774 UINT16 component = 0;
1775 UINT16 packetId = 0;
1776 UINT32 deviceId = 0;
1777 UINT32 status = 0;
1778 UINT error = ERROR_INVALID_DATA;
1779
1780 if (!rdpdr || !s)
1781 return CHANNEL_RC_NULL_DATA;
1782
1783 rdpdr_dump_received_packet(rdpdr->log, WLOG_TRACE, s, "[rdpdr-channel] receive");
1784 if (Stream_GetRemainingLength(s) >= 4)
1785 {
1786 Stream_Read_UINT16(s, component); /* Component (2 bytes) */
1787 Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
1788
1789 if (component == RDPDR_CTYP_CORE)
1790 {
1791 if (!rdpdr_check_channel_state(rdpdr, packetId))
1792 return CHANNEL_RC_OK;
1793
1794 switch (packetId)
1795 {
1796 case PAKID_CORE_SERVER_ANNOUNCE:
1797 rdpdr->haveClientId = FALSE;
1798 rdpdr->haveServerCaps = FALSE;
1799 if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
1800 {
1801 }
1802 else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
1803 {
1804 WLog_Print(rdpdr->log, WLOG_ERROR,
1805 "rdpdr_send_client_announce_reply failed with error %" PRIu32 "",
1806 error);
1807 }
1808 else if ((error = rdpdr_send_client_name_request(rdpdr)))
1809 {
1810 WLog_Print(rdpdr->log, WLOG_ERROR,
1811 "rdpdr_send_client_name_request failed with error %" PRIu32 "",
1812 error);
1813 }
1814 else if ((error = rdpdr_process_init(rdpdr)))
1815 {
1816 WLog_Print(rdpdr->log, WLOG_ERROR,
1817 "rdpdr_process_init failed with error %" PRIu32 "", error);
1818 }
1819
1820 break;
1821
1822 case PAKID_CORE_SERVER_CAPABILITY:
1823 if ((error = rdpdr_process_capability_request(rdpdr, s)))
1824 {
1825 }
1826 else if ((error = rdpdr_send_capability_response(rdpdr)))
1827 {
1828 WLog_Print(rdpdr->log, WLOG_ERROR,
1829 "rdpdr_send_capability_response failed with error %" PRIu32 "",
1830 error);
1831 }
1832 else
1833 {
1834 rdpdr->haveServerCaps = TRUE;
1835 if (!tryAdvance(rdpdr))
1836 error = ERROR_INTERNAL_ERROR;
1837 }
1838
1839 break;
1840
1841 case PAKID_CORE_CLIENTID_CONFIRM:
1842 if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
1843 {
1844 }
1845 else
1846 {
1847 rdpdr->haveClientId = TRUE;
1848 if (!tryAdvance(rdpdr))
1849 error = ERROR_INTERNAL_ERROR;
1850 }
1851 break;
1852
1853 case PAKID_CORE_USER_LOGGEDON:
1854 if (!rdpdr->haveServerCaps)
1855 {
1856 WLog_Print(rdpdr->log, WLOG_ERROR,
1857 "Wrong state %s for %s. [serverCaps=%d, clientId=%d]",
1858 rdpdr_state_str(rdpdr->state), rdpdr_packetid_string(packetId),
1859 rdpdr->haveServerCaps, rdpdr->haveClientId);
1860 error = ERROR_INTERNAL_ERROR;
1861 }
1862 else if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
1863 {
1864 WLog_Print(
1865 rdpdr->log, WLOG_ERROR,
1866 "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
1867 error);
1868 }
1869 else if (!tryAdvance(rdpdr))
1870 {
1871 error = ERROR_INTERNAL_ERROR;
1872 }
1873
1874 break;
1875
1876 case PAKID_CORE_DEVICE_REPLY:
1877
1878 /* connect to a specific resource */
1879 if (Stream_GetRemainingLength(s) >= 8)
1880 {
1881 Stream_Read_UINT32(s, deviceId);
1882 Stream_Read_UINT32(s, status);
1883
1884 if (status != 0)
1885 devman_unregister_device(rdpdr->devman, (void*)((size_t)deviceId));
1886 error = CHANNEL_RC_OK;
1887 }
1888
1889 break;
1890
1891 case PAKID_CORE_DEVICE_IOREQUEST:
1892 if ((error = rdpdr_process_irp(rdpdr, s)))
1893 {
1894 WLog_Print(rdpdr->log, WLOG_ERROR,
1895 "rdpdr_process_irp failed with error %" PRIu32 "", error);
1896 return error;
1897 }
1898 else
1899 s = NULL;
1900
1901 break;
1902
1903 default:
1904 WLog_Print(rdpdr->log, WLOG_ERROR,
1905 "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16 "", packetId);
1906 error = ERROR_INVALID_DATA;
1907 break;
1908 }
1909 }
1910 else
1911 {
1912 error = rdpdr_process_component(rdpdr, component, packetId, s);
1913
1914 if (error != CHANNEL_RC_OK)
1915 {
1916 DWORD level = WLOG_ERROR;
1917 if (rdpdr->ignoreInvalidDevices)
1918 {
1919 if (error == ERROR_DEV_NOT_EXIST)
1920 {
1921 level = WLOG_WARN;
1922 error = CHANNEL_RC_OK;
1923 }
1924 }
1925 WLog_Print(rdpdr->log, level,
1926 "Unknown message: Component: %s [0x%04" PRIX16
1927 "] PacketId: %s [0x%04" PRIX16 "]",
1928 rdpdr_component_string(component), component,
1929 rdpdr_packetid_string(packetId), packetId);
1930 }
1931 }
1932 }
1933
1934 return error;
1935}
1936
1942UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s)
1943{
1944 rdpdrPlugin* plugin = rdpdr;
1945
1946 if (!s)
1947 {
1948 Stream_Release(s);
1949 return CHANNEL_RC_NULL_DATA;
1950 }
1951
1952 if (!plugin)
1953 {
1954 Stream_Release(s);
1955 return CHANNEL_RC_BAD_INIT_HANDLE;
1956 }
1957
1958 const size_t pos = Stream_GetPosition(s);
1959 UINT status = ERROR_INTERNAL_ERROR;
1960 if (pos <= UINT32_MAX)
1961 {
1962 rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s, "[rdpdr-channel] send");
1963 status = plugin->channelEntryPoints.pVirtualChannelWriteEx(
1964 plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)pos, s);
1965 }
1966
1967 if (status != CHANNEL_RC_OK)
1968 {
1969 Stream_Release(s);
1970 WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
1971 WTSErrorToString(status), status);
1972 }
1973
1974 return status;
1975}
1976
1982static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* pData,
1983 UINT32 dataLength, UINT32 totalLength,
1984 UINT32 dataFlags)
1985{
1986 wStream* data_in = NULL;
1987
1988 WINPR_ASSERT(rdpdr);
1989 WINPR_ASSERT(pData || (dataLength == 0));
1990
1991 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
1992 {
1993 /*
1994 * According to MS-RDPBCGR 2.2.6.1, "All virtual channel traffic MUST be suspended.
1995 * This flag is only valid in server-to-client virtual channel traffic. It MUST be
1996 * ignored in client-to-server data." Thus it would be best practice to cease data
1997 * transmission. However, simply returning here avoids a crash.
1998 */
1999 return CHANNEL_RC_OK;
2000 }
2001
2002 if (dataFlags & CHANNEL_FLAG_FIRST)
2003 {
2004 if (rdpdr->data_in != NULL)
2005 Stream_Release(rdpdr->data_in);
2006
2007 rdpdr->data_in = StreamPool_Take(rdpdr->pool, totalLength);
2008
2009 if (!rdpdr->data_in)
2010 {
2011 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
2012 return CHANNEL_RC_NO_MEMORY;
2013 }
2014 }
2015
2016 data_in = rdpdr->data_in;
2017
2018 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
2019 {
2020 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
2021 return ERROR_INVALID_DATA;
2022 }
2023
2024 Stream_Write(data_in, pData, dataLength);
2025
2026 if (dataFlags & CHANNEL_FLAG_LAST)
2027 {
2028 const size_t pos = Stream_GetPosition(data_in);
2029 const size_t cap = Stream_Capacity(data_in);
2030 if (cap < pos)
2031 {
2032 WLog_Print(rdpdr->log, WLOG_ERROR,
2033 "rdpdr_virtual_channel_event_data_received: read error");
2034 return ERROR_INTERNAL_ERROR;
2035 }
2036
2037 Stream_SealLength(data_in);
2038 Stream_SetPosition(data_in, 0);
2039
2040 if (rdpdr->async)
2041 {
2042 if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (void*)data_in, NULL))
2043 {
2044 WLog_Print(rdpdr->log, WLOG_ERROR, "MessageQueue_Post failed!");
2045 return ERROR_INTERNAL_ERROR;
2046 }
2047 rdpdr->data_in = NULL;
2048 }
2049 else
2050 {
2051 UINT error = rdpdr_process_receive(rdpdr, data_in);
2052 Stream_Release(data_in);
2053 rdpdr->data_in = NULL;
2054 if (error)
2055 return error;
2056 }
2057 }
2058
2059 return CHANNEL_RC_OK;
2060}
2061
2062static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
2063 UINT event, LPVOID pData,
2064 UINT32 dataLength, UINT32 totalLength,
2065 UINT32 dataFlags)
2066{
2067 UINT error = CHANNEL_RC_OK;
2068 rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam;
2069
2070 WINPR_ASSERT(rdpdr);
2071 switch (event)
2072 {
2073 case CHANNEL_EVENT_DATA_RECEIVED:
2074 if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle))
2075 {
2076 WLog_Print(rdpdr->log, WLOG_ERROR, "error no match");
2077 return;
2078 }
2079 if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength,
2080 totalLength, dataFlags)))
2081 WLog_Print(rdpdr->log, WLOG_ERROR,
2082 "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32
2083 "!",
2084 error);
2085
2086 break;
2087
2088 case CHANNEL_EVENT_WRITE_CANCELLED:
2089 case CHANNEL_EVENT_WRITE_COMPLETE:
2090 {
2091 wStream* s = (wStream*)pData;
2092 Stream_Release(s);
2093 }
2094 break;
2095
2096 case CHANNEL_EVENT_USER:
2097 break;
2098 default:
2099 break;
2100 }
2101
2102 if (error && rdpdr && rdpdr->rdpcontext)
2103 setChannelError(rdpdr->rdpcontext, error,
2104 "rdpdr_virtual_channel_open_event_ex reported an error");
2105}
2106
2107static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
2108{
2109 rdpdrPlugin* rdpdr = (rdpdrPlugin*)arg;
2110 UINT error = 0;
2111
2112 if (!rdpdr)
2113 {
2114 ExitThread((DWORD)CHANNEL_RC_NULL_DATA);
2115 return CHANNEL_RC_NULL_DATA;
2116 }
2117
2118 if ((error = rdpdr_process_connect(rdpdr)))
2119 {
2120 WLog_Print(rdpdr->log, WLOG_ERROR, "rdpdr_process_connect failed with error %" PRIu32 "!",
2121 error);
2122
2123 if (rdpdr->rdpcontext)
2124 setChannelError(rdpdr->rdpcontext, error,
2125 "rdpdr_virtual_channel_client_thread reported an error");
2126
2127 ExitThread(error);
2128 return error;
2129 }
2130
2131 while (1)
2132 {
2133 wMessage message = { 0 };
2134 WINPR_ASSERT(rdpdr);
2135
2136 if (!MessageQueue_Wait(rdpdr->queue))
2137 break;
2138
2139 if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
2140 {
2141 if (message.id == WMQ_QUIT)
2142 break;
2143
2144 if (message.id == 0)
2145 {
2146 wStream* data = (wStream*)message.wParam;
2147
2148 error = rdpdr_process_receive(rdpdr, data);
2149
2150 Stream_Release(data);
2151 if (error)
2152 {
2153 WLog_Print(rdpdr->log, WLOG_ERROR,
2154 "rdpdr_process_receive failed with error %" PRIu32 "!", error);
2155
2156 if (rdpdr->rdpcontext)
2157 setChannelError(rdpdr->rdpcontext, error,
2158 "rdpdr_virtual_channel_client_thread reported an error");
2159
2160 goto fail;
2161 }
2162 }
2163 }
2164 }
2165
2166fail:
2167 if ((error = drive_hotplug_thread_terminate(rdpdr)))
2168 WLog_Print(rdpdr->log, WLOG_ERROR,
2169 "drive_hotplug_thread_terminate failed with error %" PRIu32 "!", error);
2170
2171 ExitThread(error);
2172 return error;
2173}
2174
2175static void queue_free(void* obj)
2176{
2177 wStream* s = NULL;
2178 wMessage* msg = (wMessage*)obj;
2179
2180 if (!msg || (msg->id != 0))
2181 return;
2182
2183 s = (wStream*)msg->wParam;
2184 WINPR_ASSERT(s);
2185 Stream_Release(s);
2186}
2187
2193static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pData,
2194 UINT32 dataLength)
2195{
2196 wObject* obj = NULL;
2197
2198 WINPR_ASSERT(rdpdr);
2199 WINPR_UNUSED(pData);
2200 WINPR_UNUSED(dataLength);
2201
2202 if (rdpdr->async)
2203 {
2204 rdpdr->queue = MessageQueue_New(NULL);
2205
2206 if (!rdpdr->queue)
2207 {
2208 WLog_Print(rdpdr->log, WLOG_ERROR, "MessageQueue_New failed!");
2209 return CHANNEL_RC_NO_MEMORY;
2210 }
2211
2212 obj = MessageQueue_Object(rdpdr->queue);
2213 obj->fnObjectFree = queue_free;
2214
2215 if (!(rdpdr->thread = CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread,
2216 (void*)rdpdr, 0, NULL)))
2217 {
2218 WLog_Print(rdpdr->log, WLOG_ERROR, "CreateThread failed!");
2219 return ERROR_INTERNAL_ERROR;
2220 }
2221 }
2222 else
2223 {
2224 UINT error = rdpdr_process_connect(rdpdr);
2225 if (error)
2226 {
2227 WLog_Print(rdpdr->log, WLOG_ERROR,
2228 "rdpdr_process_connect failed with error %" PRIu32 "!", error);
2229 return error;
2230 }
2231 }
2232
2233 return rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, &rdpdr->OpenHandle,
2234 rdpdr->channelDef.name,
2235 rdpdr_virtual_channel_open_event_ex);
2236}
2237
2243static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr)
2244{
2245 UINT error = 0;
2246
2247 WINPR_ASSERT(rdpdr);
2248
2249 if (rdpdr->OpenHandle == 0)
2250 return CHANNEL_RC_OK;
2251
2252 if (rdpdr->queue && rdpdr->thread)
2253 {
2254 if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
2255 (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
2256 {
2257 error = GetLastError();
2258 WLog_Print(rdpdr->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!",
2259 error);
2260 return error;
2261 }
2262 }
2263
2264 if (rdpdr->thread)
2265 (void)CloseHandle(rdpdr->thread);
2266 MessageQueue_Free(rdpdr->queue);
2267 rdpdr->queue = NULL;
2268 rdpdr->thread = NULL;
2269
2270 WINPR_ASSERT(rdpdr->channelEntryPoints.pVirtualChannelCloseEx);
2271 error = rdpdr->channelEntryPoints.pVirtualChannelCloseEx(rdpdr->InitHandle, rdpdr->OpenHandle);
2272
2273 if (CHANNEL_RC_OK != error)
2274 {
2275 WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
2276 WTSErrorToString(error), error);
2277 }
2278
2279 rdpdr->OpenHandle = 0;
2280
2281 if (rdpdr->data_in)
2282 {
2283 Stream_Release(rdpdr->data_in);
2284 rdpdr->data_in = NULL;
2285 }
2286
2287 if (rdpdr->devman)
2288 {
2289 devman_free(rdpdr->devman);
2290 rdpdr->devman = NULL;
2291 }
2292
2293 return error;
2294}
2295
2296static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
2297{
2298 WINPR_ASSERT(rdpdr);
2299#if !defined(_WIN32)
2300 if (rdpdr->stopEvent)
2301 {
2302 (void)CloseHandle(rdpdr->stopEvent);
2303 rdpdr->stopEvent = NULL;
2304 }
2305#endif
2306 rdpdr->InitHandle = 0;
2307 StreamPool_Free(rdpdr->pool);
2308 free(rdpdr);
2309}
2310
2311static UINT rdpdr_register_device(RdpdrClientContext* context, const RDPDR_DEVICE* device,
2312 uint32_t* pid)
2313{
2314 WINPR_ASSERT(context);
2315 WINPR_ASSERT(device);
2316 WINPR_ASSERT(pid);
2317
2318 rdpdrPlugin* rdpdr = context->handle;
2319 WINPR_ASSERT(rdpdr);
2320
2321 RDPDR_DEVICE* copy = freerdp_device_clone(device);
2322 if (!copy)
2323 return ERROR_INVALID_DATA;
2324 UINT rc = devman_load_device_service(rdpdr->devman, copy, rdpdr->rdpcontext);
2325 *pid = copy->Id;
2326 freerdp_device_free(copy);
2327 if (rc == CHANNEL_RC_OK)
2328 rc = rdpdr_try_send_device_list_announce_request(rdpdr);
2329 return rc;
2330}
2331
2332static UINT rdpdr_unregister_device(RdpdrClientContext* context, size_t count, const uint32_t ids[])
2333{
2334 WINPR_ASSERT(context);
2335
2336 rdpdrPlugin* rdpdr = context->handle;
2337 WINPR_ASSERT(rdpdr);
2338
2339 for (size_t x = 0; x < count; x++)
2340 {
2341 const uintptr_t id = ids[x];
2342 devman_unregister_device(rdpdr->devman, (void*)id);
2343 }
2344 return rdpdr_send_device_list_remove_request(rdpdr, WINPR_ASSERTING_INT_CAST(uint32_t, count),
2345 ids);
2346}
2347
2348static UINT rdpdr_virtual_channel_event_initialized(rdpdrPlugin* rdpdr,
2349 WINPR_ATTR_UNUSED LPVOID pData,
2350 WINPR_ATTR_UNUSED UINT32 dataLength)
2351{
2352 WINPR_ASSERT(rdpdr);
2353#if !defined(_WIN32)
2354 WINPR_ASSERT(!rdpdr->stopEvent);
2355 rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
2356 WINPR_ASSERT(rdpdr->stopEvent);
2357#endif
2358
2359 rdpdr->context.handle = rdpdr;
2360 rdpdr->context.RdpdrHotplugDevice = handle_hotplug;
2361 rdpdr->context.RdpdrRegisterDevice = rdpdr_register_device;
2362 rdpdr->context.RdpdrUnregisterDevice = rdpdr_unregister_device;
2363 return CHANNEL_RC_OK;
2364}
2365
2366static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
2367 UINT event, LPVOID pData, UINT dataLength)
2368{
2369 UINT error = CHANNEL_RC_OK;
2370 rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam;
2371
2372 if (!rdpdr || (rdpdr->InitHandle != pInitHandle))
2373 {
2374 WLog_ERR(TAG, "error no match");
2375 return;
2376 }
2377
2378 WINPR_ASSERT(pData || (dataLength == 0));
2379
2380 switch (event)
2381 {
2382 case CHANNEL_EVENT_INITIALIZED:
2383 error = rdpdr_virtual_channel_event_initialized(rdpdr, pData, dataLength);
2384 break;
2385
2386 case CHANNEL_EVENT_CONNECTED:
2387 if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength)))
2388 WLog_Print(rdpdr->log, WLOG_ERROR,
2389 "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 "!",
2390 error);
2391
2392 break;
2393
2394 case CHANNEL_EVENT_DISCONNECTED:
2395 if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr)))
2396 WLog_Print(rdpdr->log, WLOG_ERROR,
2397 "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32
2398 "!",
2399 error);
2400
2401 break;
2402
2403 case CHANNEL_EVENT_TERMINATED:
2404 rdpdr_virtual_channel_event_terminated(rdpdr);
2405 rdpdr = NULL;
2406 break;
2407
2408 case CHANNEL_EVENT_ATTACHED:
2409 case CHANNEL_EVENT_DETACHED:
2410 default:
2411 WLog_Print(rdpdr->log, WLOG_ERROR, "unknown event %" PRIu32 "!", event);
2412 break;
2413 }
2414
2415 if (error && rdpdr && rdpdr->rdpcontext)
2416 setChannelError(rdpdr->rdpcontext, error,
2417 "rdpdr_virtual_channel_init_event_ex reported an error");
2418}
2419
2420/* rdpdr is always built-in */
2421#define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx
2422
2423FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
2424 PVOID pInitHandle))
2425{
2426 UINT rc = 0;
2427 rdpdrPlugin* rdpdr = NULL;
2428 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
2429
2430 WINPR_ASSERT(pEntryPoints);
2431 WINPR_ASSERT(pInitHandle);
2432
2433 rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin));
2434
2435 if (!rdpdr)
2436 {
2437 WLog_ERR(TAG, "calloc failed!");
2438 return FALSE;
2439 }
2440 rdpdr->log = WLog_Get(TAG);
2441
2442 rdpdr->clientExtendedPDU =
2443 RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU;
2444 rdpdr->clientIOCode1 =
2445 RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
2446 RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
2447 RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
2448 RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
2449 RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL |
2450 RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY;
2451
2452 rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO;
2453
2454 rdpdr->pool = StreamPool_New(TRUE, 1024);
2455 if (!rdpdr->pool)
2456 {
2457 free(rdpdr);
2458 return FALSE;
2459 }
2460
2461 rdpdr->channelDef.options =
2462 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
2463 (void)sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name),
2464 RDPDR_SVC_CHANNEL_NAME);
2465 rdpdr->sequenceId = 0;
2466 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
2467
2468 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
2469 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
2470 {
2471 rdpdr->rdpcontext = pEntryPointsEx->context;
2472 if (!freerdp_settings_get_bool(rdpdr->rdpcontext->settings,
2473 FreeRDP_SynchronousStaticChannels))
2474 rdpdr->async = TRUE;
2475 }
2476
2477 CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
2478 rdpdr->InitHandle = pInitHandle;
2479 rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx(
2480 rdpdr, &rdpdr->context, pInitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
2481 rdpdr_virtual_channel_init_event_ex);
2482
2483 if (CHANNEL_RC_OK != rc)
2484 {
2485 WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]",
2486 WTSErrorToString(rc), rc);
2487 free(rdpdr);
2488 return FALSE;
2489 }
2490
2491 return TRUE;
2492}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
Definition svc.h:60
This struct contains function pointer to initialize/free objects.
Definition collections.h:57