25 #include <freerdp/config.h>
32 #include <winpr/crt.h>
33 #include <winpr/sysinfo.h>
34 #include <winpr/assert.h>
35 #include <winpr/stream.h>
37 #include <winpr/print.h>
38 #include <winpr/sspicli.h>
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>
51 #include <sys/types.h>
57 #include <CoreFoundation/CoreFoundation.h>
60 #include <sys/types.h>
65 #include "rdpdr_capabilities.h"
70 #include "rdpdr_main.h"
72 #define TAG CHANNELS_TAG("rdpdr.client")
82 static const char* rdpdr_state_str(
enum RDPDR_CHANNEL_STATE state)
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";
105 return "RDPDR_CHANNEL_STATE_UNKNOWN";
109 static const char* rdpdr_device_type_string(UINT32 type)
113 case RDPDR_DTYP_SERIAL:
115 case RDPDR_DTYP_PRINT:
117 case RDPDR_DTYP_FILESYSTEM:
119 case RDPDR_DTYP_SMARTCARD:
121 case RDPDR_DTYP_PARALLEL:
128 static const char* support_str(BOOL val)
135 static const char* rdpdr_caps_pdu_str(UINT32 flag)
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";
146 return "RDPDR_UNKNONW";
150 static BOOL rdpdr_check_extended_pdu_flag(
rdpdrPlugin* rdpdr, UINT32 flag)
154 const BOOL client = (rdpdr->clientExtendedPDU & flag) != 0;
155 const BOOL server = (rdpdr->serverExtendedPDU & flag) != 0;
157 if (!client || !server)
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));
166 BOOL rdpdr_state_advance(
rdpdrPlugin* rdpdr,
enum RDPDR_CHANNEL_STATE next)
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));
177 static BOOL device_foreach(
rdpdrPlugin* rdpdr, BOOL abortOnFail,
178 BOOL (*fkt)(ULONG_PTR key,
void* element,
void* data),
void* data)
181 ULONG_PTR* keys = NULL;
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++)
187 void* element = ListDictionary_GetItemValue(rdpdr->devman->devices, (
void*)keys[x]);
188 if (!fkt(keys[x], element, data))
196 ListDictionary_Unlock(rdpdr->devman->devices);
205 static UINT rdpdr_try_send_device_list_announce_request(
rdpdrPlugin* rdpdr);
207 static BOOL rdpdr_load_drive(
rdpdrPlugin* rdpdr,
const char* name,
const char* path, BOOL automount)
209 UINT rc = ERROR_INTERNAL_ERROR;
215 const char* args[] = { name, path, automount ? NULL : name };
217 drive.device = freerdp_device_new(RDPDR_DTYP_FILESYSTEM, ARRAYSIZE(args), args);
221 rc = devman_load_device_service(rdpdr->devman, drive.device, rdpdr->rdpcontext);
222 if (rc != CHANNEL_RC_OK)
226 freerdp_device_free(drive.device);
227 return rc == CHANNEL_RC_OK;
235 static UINT rdpdr_send_device_list_remove_request(
rdpdrPlugin* rdpdr, UINT32 count, UINT32 ids[])
240 WINPR_ASSERT(ids || (count == 0));
243 return CHANNEL_RC_OK;
245 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_DEVICE_REMOVE_PDUS))
246 return CHANNEL_RC_OK;
248 s = StreamPool_Take(rdpdr->pool, count *
sizeof(UINT32) + 8);
252 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
253 return CHANNEL_RC_NO_MEMORY;
256 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
257 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
258 Stream_Write_UINT32(s, count);
260 for (UINT32 i = 0; i < count; i++)
261 Stream_Write_UINT32(s, ids[i]);
263 Stream_SealLength(s);
264 return rdpdr_send(rdpdr, s);
267 #if defined(_UWP) || defined(__IOS__)
273 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
275 return CHANNEL_RC_OK;
278 static UINT drive_hotplug_thread_terminate(
rdpdrPlugin* rdpdr)
280 return CHANNEL_RC_OK;
283 #elif defined(_WIN32)
285 static BOOL check_path(
const char* path)
287 UINT type = GetDriveTypeA(path);
289 if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
290 type == DRIVE_REMOTE))
293 return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
298 DWORD unitmask = GetLogicalDrives();
300 for (
size_t i = 0; i < 26; i++)
304 char drive_path[] = {
'c',
':',
'\\',
'\0' };
305 char drive_name[] = {
'c',
'\0' };
306 drive_path[0] =
'A' + (char)i;
307 drive_name[0] =
'A' + (char)i;
309 if (check_path(drive_path))
311 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
315 unitmask = unitmask >> 1;
319 static LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
322 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
324 rdpdr = (
rdpdrPlugin*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
328 case WM_DEVICECHANGE:
331 case DBT_DEVICEARRIVAL:
332 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
334 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
335 DWORD unitmask = lpdbv->dbcv_unitmask;
337 for (
int i = 0; i < 26; i++)
341 char drive_path[] = {
'c',
':',
'/',
'\0' };
342 char drive_name[] = {
'c',
'\0' };
343 drive_path[0] =
'A' + (char)i;
344 drive_name[0] =
'A' + (char)i;
346 if (check_path(drive_path))
348 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
349 rdpdr_try_send_device_list_announce_request(rdpdr);
353 unitmask = unitmask >> 1;
359 case DBT_DEVICEREMOVECOMPLETE:
360 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
362 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
363 DWORD unitmask = lpdbv->dbcv_unitmask;
365 char drive_name_upper, drive_name_lower;
366 ULONG_PTR* keys = NULL;
367 DEVICE_DRIVE_EXT* device_ext;
370 for (
int i = 0; i < 26; i++)
374 drive_name_upper =
'A' + i;
375 drive_name_lower =
'a' + i;
376 count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
378 for (
int j = 0; j < count; j++)
380 device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
381 rdpdr->devman->devices, (
void*)keys[j]);
383 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
386 if (device_ext->path[0] == drive_name_upper ||
387 device_ext->path[0] == drive_name_lower)
389 if (device_ext->automount)
391 devman_unregister_device(rdpdr->devman, (
void*)keys[j]);
394 if ((error = rdpdr_send_device_list_remove_request(
399 rdpdr->log, WLOG_ERROR,
400 "rdpdr_send_device_list_remove_request failed "
401 "with error %" PRIu32
"!",
413 unitmask = unitmask >> 1;
426 return DefWindowProc(hWnd, Msg, wParam, lParam);
429 return DefWindowProc(hWnd, Msg, wParam, lParam);
432 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
439 DEV_BROADCAST_HANDLE NotificationFilter;
440 HDEVNOTIFY hDevNotify;
443 wnd_cls.cbSize =
sizeof(WNDCLASSEX);
444 wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
445 wnd_cls.lpfnWndProc = hotplug_proc;
446 wnd_cls.cbClsExtra = 0;
447 wnd_cls.cbWndExtra = 0;
448 wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
449 wnd_cls.hCursor = NULL;
450 wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
451 wnd_cls.lpszMenuName = NULL;
452 wnd_cls.lpszClassName = L
"DRIVE_HOTPLUG";
453 wnd_cls.hInstance = NULL;
454 wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
455 RegisterClassEx(&wnd_cls);
457 hwnd = CreateWindowEx(0, L
"DRIVE_HOTPLUG", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
458 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr);
459 rdpdr->hotplug_wnd = hwnd;
461 NotificationFilter.dbch_size =
sizeof(DEV_BROADCAST_HANDLE);
462 NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
463 hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
466 while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
474 TranslateMessage(&msg);
475 DispatchMessage(&msg);
479 UnregisterDeviceNotification(hDevNotify);
480 return CHANNEL_RC_OK;
488 static UINT drive_hotplug_thread_terminate(
rdpdrPlugin* rdpdr)
490 UINT error = CHANNEL_RC_OK;
492 if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0))
494 error = GetLastError();
495 WLog_Print(rdpdr->log, WLOG_ERROR,
"PostMessage failed with error %" PRIu32
"", error);
501 #elif defined(__MACOSX__)
503 #define MAX_USB_DEVICES 100
518 struct dirent* pDirent = NULL;
519 char fullpath[PATH_MAX] = { 0 };
520 char* szdir = (
char*)
"/Volumes";
521 struct stat buf = { 0 };
522 hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
524 DEVICE_DRIVE_EXT* device_ext = NULL;
525 ULONG_PTR* keys = NULL;
527 UINT error = ERROR_INTERNAL_ERROR;
530 DIR* pDir = opendir(szdir);
534 printf(
"Cannot open directory\n");
535 return ERROR_OPEN_FAILED;
538 while ((pDirent = readdir(pDir)) != NULL)
540 if (pDirent->d_name[0] !=
'.')
542 (void)sprintf_s(fullpath, ARRAYSIZE(fullpath),
"%s/%s", szdir, pDirent->d_name);
543 if (stat(fullpath, &buf) != 0)
546 if (S_ISDIR(buf.st_mode))
548 dev_array[size].path = _strdup(fullpath);
550 if (!dev_array[size].path)
553 error = CHANNEL_RC_NO_MEMORY;
557 dev_array[size++].to_add = TRUE;
564 count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
566 for (
size_t j = 0; j < count; j++)
569 BOOL dev_found = FALSE;
571 (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (
void*)keys[j]);
573 if (!device_ext || !device_ext->automount)
576 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
579 if (device_ext->path == NULL)
582 path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
587 if (strstr(path,
"/Volumes/") == NULL)
593 for (
size_t i = 0; i < size; i++)
595 if (strstr(path, dev_array[i].path) != NULL)
598 dev_array[i].to_add = FALSE;
607 devman_unregister_device(rdpdr->devman, (
void*)keys[j]);
610 if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids)))
612 WLog_Print(rdpdr->log, WLOG_ERROR,
613 "rdpdr_send_device_list_remove_request failed with error %" PRIu32
"!",
621 for (
size_t i = 0; i < size; i++)
623 const hotplug_dev* dev = &dev_array[i];
626 const char* path = dev->path;
627 const char* name = strrchr(path,
'/') + 1;
628 error = rdpdr_load_drive(rdpdr, name, path, TRUE);
637 for (
size_t i = 0; i < size; i++)
638 free(dev_array[i].path);
643 static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,
644 void* clientCallBackInfo,
size_t numEvents,
646 const FSEventStreamEventFlags eventFlags[],
647 const FSEventStreamEventId eventIds[])
651 char** paths = (
char**)eventPaths;
654 for (
size_t i = 0; i < numEvents; i++)
656 if (strcmp(paths[i],
"/Volumes/") == 0)
658 if ((error = handle_hotplug(rdpdr)))
660 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
664 rdpdr_try_send_device_list_announce_request(rdpdr);
675 if ((error = handle_hotplug(rdpdr)))
677 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!", error);
681 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
684 FSEventStreamRef fsev;
686 CFStringRef path = CFSTR(
"/Volumes/");
687 CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (
const void**)&path, 1, NULL);
688 FSEventStreamContext ctx = { 0 };
692 WINPR_ASSERT(!rdpdr->stopEvent);
693 rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
694 if (!rdpdr->stopEvent)
698 FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch,
699 kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
701 rdpdr->runLoop = CFRunLoopGetCurrent();
702 FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode);
703 FSEventStreamStart(fsev);
705 FSEventStreamStop(fsev);
706 FSEventStreamRelease(fsev);
708 if (rdpdr->stopEvent)
710 (void)CloseHandle(rdpdr->stopEvent);
711 rdpdr->stopEvent = NULL;
713 ExitThread(CHANNEL_RC_OK);
714 return CHANNEL_RC_OK;
719 static const char* automountLocations[] = {
"/run/user/%lu/gvfs",
"/run/media/%s",
"/media/%s",
722 static BOOL isAutomountLocation(
const char* path)
724 const size_t nrLocations =
sizeof(automountLocations) /
sizeof(automountLocations[0]);
725 char buffer[MAX_PATH] = { 0 };
726 uid_t uid = getuid();
727 char uname[MAX_PATH] = { 0 };
728 ULONG size =
sizeof(uname) - 1;
730 if (!GetUserNameExA(NameSamCompatible, uname, &size))
736 for (
size_t x = 0; x < nrLocations; x++)
738 const char* location = automountLocations[x];
741 WINPR_PRAGMA_DIAG_PUSH
742 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
743 if (strstr(location,
"%lu"))
744 (
void)snprintf(buffer,
sizeof(buffer), location, (
unsigned long)uid);
745 else if (strstr(location,
"%s"))
746 (void)snprintf(buffer,
sizeof(buffer), location, uname);
748 (
void)snprintf(buffer,
sizeof(buffer),
"%s", location);
749 WINPR_PRAGMA_DIAG_POP
751 length = strnlen(buffer,
sizeof(buffer));
753 if (strncmp(buffer, path, length) == 0)
755 const char* rest = &path[length];
761 else if (*rest ==
'/')
763 const char* token = strstr(&rest[1],
"/");
765 if (!token || (token[1] ==
'\0'))
774 #define MAX_USB_DEVICES 100
782 static void handle_mountpoint(hotplug_dev* dev_array,
size_t* size,
const char* mountpoint)
787 if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
789 dev_array[*size].path = _strdup(mountpoint);
790 dev_array[*size].to_add = TRUE;
796 #include <sys/mnttab.h>
797 static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array,
size_t* size)
801 f = winpr_fopen(
"/etc/mnttab",
"r");
804 WLog_Print(log, WLOG_ERROR,
"fopen failed!");
805 return ERROR_OPEN_FAILED;
807 while (getmntent(f, &ent) == 0)
809 handle_mountpoint(dev_array, size, ent.mnt_mountp);
812 return ERROR_SUCCESS;
816 #if defined(__FreeBSD__) || defined(__OpenBSD__)
817 #include <sys/mount.h>
818 static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array,
size_t* size)
821 struct statfs* mntbuf = NULL;
823 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
827 WLog_Print(log, WLOG_ERROR,
"getmntinfo failed!");
828 return ERROR_OPEN_FAILED;
830 for (
size_t idx = 0; idx < (size_t)mntsize; idx++)
832 handle_mountpoint(dev_array, size, mntbuf[idx].f_mntonname);
835 return ERROR_SUCCESS;
839 #if defined(__LINUX__) || defined(__linux__)
841 static struct mntent* getmntent_x(FILE* f,
struct mntent* buffer,
char* pathbuffer,
842 size_t pathbuffersize)
844 #if defined(FREERDP_HAVE_GETMNTENT_R)
845 WINPR_ASSERT(pathbuffersize <= INT32_MAX);
846 return getmntent_r(f, buffer, pathbuffer, (
int)pathbuffersize);
850 (void)pathbuffersize;
855 static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array,
size_t* size)
858 struct mntent mnt = { 0 };
859 char pathbuffer[PATH_MAX] = { 0 };
860 struct mntent* ent = NULL;
861 f = winpr_fopen(
"/proc/mounts",
"r");
864 WLog_Print(log, WLOG_ERROR,
"fopen failed!");
865 return ERROR_OPEN_FAILED;
867 while ((ent = getmntent_x(f, &mnt, pathbuffer,
sizeof(pathbuffer))) != NULL)
869 handle_mountpoint(dev_array, size, ent->mnt_dir);
872 return ERROR_SUCCESS;
876 static UINT handle_platform_mounts(wLog* log, hotplug_dev* dev_array,
size_t* size)
879 return handle_platform_mounts_sun(log, dev_array, size);
880 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
881 return handle_platform_mounts_bsd(log, dev_array, size);
882 #elif defined(__LINUX__) || defined(__linux__)
883 return handle_platform_mounts_linux(log, dev_array, size);
885 return ERROR_CALL_NOT_IMPLEMENTED;
888 static BOOL device_not_plugged(ULONG_PTR key,
void* element,
void* data)
890 const WCHAR* path = (
const WCHAR*)data;
891 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
896 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path)
898 if (_wcscmp(device_ext->path, path) != 0)
903 static BOOL device_already_plugged(
rdpdrPlugin* rdpdr,
const hotplug_dev* device)
908 if (!rdpdr || !device)
913 WINPR_ASSERT(rdpdr->devman);
914 WINPR_ASSERT(device->path);
916 path = ConvertUtf8ToWCharAlloc(device->path, NULL);
920 rc = device_foreach(rdpdr, TRUE, device_not_plugged, path);
925 struct hotplug_delete_arg
927 hotplug_dev* dev_array;
928 size_t dev_array_size;
932 static BOOL hotplug_delete_foreach(ULONG_PTR key,
void* element,
void* data)
935 BOOL dev_found = FALSE;
936 struct hotplug_delete_arg* arg = (
struct hotplug_delete_arg*)data;
937 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
940 WINPR_ASSERT(arg->rdpdr);
941 WINPR_ASSERT(arg->dev_array || (arg->dev_array_size == 0));
942 WINPR_ASSERT(key <= UINT32_MAX);
944 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path ||
945 !device_ext->automount)
948 WINPR_ASSERT(device_ext->path);
949 path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
954 if (isAutomountLocation(path))
956 for (
size_t i = 0; i < arg->dev_array_size; i++)
958 hotplug_dev* cur = &arg->dev_array[i];
959 if (cur->path && strstr(path, cur->path) != NULL)
973 UINT32 ids[1] = { (UINT32)key };
975 WINPR_ASSERT(arg->rdpdr->devman);
976 devman_unregister_device(arg->rdpdr->devman, (
void*)key);
977 WINPR_ASSERT(key <= UINT32_MAX);
979 error = rdpdr_send_device_list_remove_request(arg->rdpdr, 1, ids);
982 WLog_Print(arg->rdpdr->log, WLOG_ERROR,
983 "rdpdr_send_device_list_remove_request failed with error %" PRIu32
"!",
994 hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
996 UINT error = ERROR_SUCCESS;
997 struct hotplug_delete_arg arg = { dev_array, ARRAYSIZE(dev_array), rdpdr };
1000 WINPR_ASSERT(rdpdr->devman);
1002 error = handle_platform_mounts(rdpdr->log, dev_array, &size);
1005 device_foreach(rdpdr, FALSE, hotplug_delete_foreach, &arg);
1008 for (
size_t i = 0; i < size; i++)
1010 hotplug_dev* cur = &dev_array[i];
1011 if (!device_already_plugged(rdpdr, cur))
1013 const char* path = cur->path;
1014 const char* name = strrchr(path,
'/') + 1;
1016 rdpdr_load_drive(rdpdr, name, path, TRUE);
1017 error = ERROR_DISK_CHANGE;
1021 for (
size_t i = 0; i < size; i++)
1022 free(dev_array[i].path);
1031 WINPR_ASSERT(rdpdr);
1032 if ((error = handle_hotplug(rdpdr)))
1036 case ERROR_DISK_CHANGE:
1038 case ERROR_OPEN_FAILED:
1039 case ERROR_CALL_NOT_IMPLEMENTED:
1042 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
1049 static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
1055 WINPR_ASSERT(rdpdr);
1057 WINPR_ASSERT(!rdpdr->stopEvent);
1058 rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1059 if (!rdpdr->stopEvent)
1062 while (WaitForSingleObject(rdpdr->stopEvent, 1000) == WAIT_TIMEOUT)
1064 error = handle_hotplug(rdpdr);
1067 case ERROR_DISK_CHANGE:
1068 rdpdr_try_send_device_list_announce_request(rdpdr);
1071 case ERROR_OPEN_FAILED:
1072 case ERROR_CALL_NOT_IMPLEMENTED:
1075 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
1082 error = GetLastError();
1083 if (error && rdpdr->rdpcontext)
1084 setChannelError(rdpdr->rdpcontext, error,
"reported an error");
1086 if (rdpdr->stopEvent)
1088 (void)CloseHandle(rdpdr->stopEvent);
1089 rdpdr->stopEvent = NULL;
1098 #if !defined(_WIN32) && !defined(__IOS__)
1104 static UINT drive_hotplug_thread_terminate(
rdpdrPlugin* rdpdr)
1108 WINPR_ASSERT(rdpdr);
1110 if (rdpdr->hotplugThread)
1112 #if !defined(_WIN32)
1113 if (rdpdr->stopEvent)
1114 (void)SetEvent(rdpdr->stopEvent);
1117 CFRunLoopStop(rdpdr->runLoop);
1120 if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED)
1122 error = GetLastError();
1123 WLog_Print(rdpdr->log, WLOG_ERROR,
"WaitForSingleObject failed with error %" PRIu32
"!",
1128 (void)CloseHandle(rdpdr->hotplugThread);
1129 rdpdr->hotplugThread = NULL;
1132 return CHANNEL_RC_OK;
1142 static UINT rdpdr_process_connect(
rdpdrPlugin* rdpdr)
1144 UINT error = CHANNEL_RC_OK;
1146 WINPR_ASSERT(rdpdr);
1148 rdpdr->devman = devman_new(rdpdr);
1152 WLog_Print(rdpdr->log, WLOG_ERROR,
"devman_new failed!");
1153 return CHANNEL_RC_NO_MEMORY;
1156 WINPR_ASSERT(rdpdr->rdpcontext);
1158 rdpSettings* settings = rdpdr->rdpcontext->settings;
1159 WINPR_ASSERT(settings);
1168 DWORD size = ARRAYSIZE(rdpdr->computerName);
1169 if (!GetComputerNameExA(ComputerNameNetBIOS, rdpdr->computerName, &size))
1170 return ERROR_INTERNAL_ERROR;
1173 strncpy(rdpdr->computerName, name, strnlen(name,
sizeof(rdpdr->computerName)));
1179 freerdp_settings_get_pointer_array(settings, FreeRDP_DeviceArray, index);
1181 if (device->Type == RDPDR_DTYP_FILESYSTEM)
1183 const char DynamicDrives[] =
"DynamicDrives";
1188 const char wildcard[] =
"*";
1189 BOOL hotplugAll = strncmp(drive->Path, wildcard,
sizeof(wildcard)) == 0;
1190 BOOL hotplugLater = strncmp(drive->Path, DynamicDrives,
sizeof(DynamicDrives)) == 0;
1192 if (hotplugAll || hotplugLater)
1196 WLog_Print(rdpdr->log, WLOG_WARN,
1197 "Drive hotplug is not supported in synchronous mode!");
1202 first_hotplug(rdpdr);
1207 if (!rdpdr->hotplugThread)
1209 rdpdr->hotplugThread =
1210 CreateThread(NULL, 0, drive_hotplug_thread_func, rdpdr, 0, NULL);
1211 if (!rdpdr->hotplugThread)
1213 WLog_Print(rdpdr->log, WLOG_ERROR,
"CreateThread failed!");
1214 return ERROR_INTERNAL_ERROR;
1222 if ((error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext)))
1224 WLog_Print(rdpdr->log, WLOG_ERROR,
1225 "devman_load_device_service failed with error %" PRIu32
"!", error);
1235 WINPR_ASSERT(rdpdr);
1238 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1239 return ERROR_INVALID_DATA;
1241 Stream_Read_UINT16(s, rdpdr->serverVersionMajor);
1242 Stream_Read_UINT16(s, rdpdr->serverVersionMinor);
1243 Stream_Read_UINT32(s, rdpdr->clientID);
1244 rdpdr->sequenceId++;
1246 rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, rdpdr->serverVersionMajor);
1247 rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, rdpdr->serverVersionMinor);
1248 WLog_Print(rdpdr->log, WLOG_DEBUG,
1249 "[rdpdr] server announces version %" PRIu32
".%" PRIu32
", client uses %" PRIu32
1251 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1252 rdpdr->clientVersionMinor);
1253 return CHANNEL_RC_OK;
1261 static UINT rdpdr_send_client_announce_reply(
rdpdrPlugin* rdpdr)
1265 WINPR_ASSERT(rdpdr);
1266 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE);
1267 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
1269 s = StreamPool_Take(rdpdr->pool, 12);
1273 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1274 return CHANNEL_RC_NO_MEMORY;
1277 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1278 Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM);
1279 Stream_Write_UINT16(s, rdpdr->clientVersionMajor);
1280 Stream_Write_UINT16(s, rdpdr->clientVersionMinor);
1281 Stream_Write_UINT32(s, rdpdr->clientID);
1282 return rdpdr_send(rdpdr, s);
1290 static UINT rdpdr_send_client_name_request(
rdpdrPlugin* rdpdr)
1293 WCHAR* computerNameW = NULL;
1294 size_t computerNameLenW = 0;
1296 WINPR_ASSERT(rdpdr);
1297 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
1298 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_NAME_REQUEST);
1300 const size_t len = strnlen(rdpdr->computerName,
sizeof(rdpdr->computerName));
1302 return ERROR_INTERNAL_ERROR;
1304 WINPR_ASSERT(rdpdr->computerName);
1305 computerNameW = ConvertUtf8NToWCharAlloc(rdpdr->computerName, len, &computerNameLenW);
1306 computerNameLenW *=
sizeof(WCHAR);
1308 if (computerNameLenW > 0)
1309 computerNameLenW +=
sizeof(WCHAR);
1311 s = StreamPool_Take(rdpdr->pool, 16U + computerNameLenW);
1315 free(computerNameW);
1316 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1317 return CHANNEL_RC_NO_MEMORY;
1320 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1321 Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME);
1322 Stream_Write_UINT32(s, 1);
1323 Stream_Write_UINT32(s, 0);
1324 Stream_Write_UINT32(s,
1325 (UINT32)computerNameLenW);
1326 Stream_Write(s, computerNameW, computerNameLenW);
1327 free(computerNameW);
1328 return rdpdr_send(rdpdr, s);
1333 UINT16 versionMajor = 0;
1334 UINT16 versionMinor = 0;
1335 UINT32 clientID = 0;
1337 WINPR_ASSERT(rdpdr);
1340 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1341 return ERROR_INVALID_DATA;
1343 Stream_Read_UINT16(s, versionMajor);
1344 Stream_Read_UINT16(s, versionMinor);
1345 Stream_Read_UINT32(s, clientID);
1347 if (versionMajor != rdpdr->clientVersionMajor || versionMinor != rdpdr->clientVersionMinor)
1349 WLog_Print(rdpdr->log, WLOG_WARN,
1350 "[rdpdr] server announced version %" PRIu32
".%" PRIu32
", client uses %" PRIu32
1351 ".%" PRIu32
" but clientid confirm requests version %" PRIu32
".%" PRIu32,
1352 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1353 rdpdr->clientVersionMinor, versionMajor, versionMinor);
1354 rdpdr->clientVersionMajor = versionMajor;
1355 rdpdr->clientVersionMinor = versionMinor;
1358 if (clientID != rdpdr->clientID)
1359 rdpdr->clientID = clientID;
1361 return CHANNEL_RC_OK;
1364 struct device_announce_arg
1372 static BOOL device_announce(ULONG_PTR key,
void* element,
void* data)
1374 struct device_announce_arg* arg = data;
1376 DEVICE* device = (DEVICE*)element;
1381 WINPR_ASSERT(device);
1382 WINPR_ASSERT(arg->rdpdr);
1383 WINPR_ASSERT(arg->s);
1394 if ((rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) ||
1395 (device->type == RDPDR_DTYP_SMARTCARD) || arg->userLoggedOn)
1397 size_t data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
1399 if (!Stream_EnsureRemainingCapacity(arg->s, 20 + data_len))
1401 Stream_Release(arg->s);
1402 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
1406 Stream_Write_UINT32(arg->s, device->type);
1407 Stream_Write_UINT32(arg->s, device->id);
1408 strncpy(Stream_Pointer(arg->s), device->name, 8);
1410 for (
size_t i = 0; i < 8; i++)
1413 Stream_Peek_UINT8(arg->s, c);
1416 Stream_Write_UINT8(arg->s,
'_');
1418 Stream_Seek_UINT8(arg->s);
1421 WINPR_ASSERT(data_len <= UINT32_MAX);
1422 Stream_Write_UINT32(arg->s, (UINT32)data_len);
1425 Stream_Write(arg->s, Stream_Buffer(device->data), data_len);
1428 WLog_Print(rdpdr->log, WLOG_INFO,
1429 "registered [%09s] device #%" PRIu32
": %s (type=%" PRIu32
" id=%" PRIu32
")",
1430 rdpdr_device_type_string(device->type), arg->count, device->name, device->type,
1436 static UINT rdpdr_send_device_list_announce_request(
rdpdrPlugin* rdpdr, BOOL userLoggedOn)
1440 size_t count_pos = 0;
1441 struct device_announce_arg arg = { 0 };
1443 WINPR_ASSERT(rdpdr);
1444 WINPR_ASSERT(rdpdr->devman);
1448 rdpdr->userLoggedOn = TRUE;
1451 s = StreamPool_Take(rdpdr->pool, 256);
1455 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1456 return CHANNEL_RC_NO_MEMORY;
1459 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1460 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE);
1461 count_pos = Stream_GetPosition(s);
1462 Stream_Seek_UINT32(s);
1465 arg.userLoggedOn = userLoggedOn;
1467 if (!device_foreach(rdpdr, TRUE, device_announce, &arg))
1468 return ERROR_INVALID_DATA;
1473 return CHANNEL_RC_OK;
1475 pos = Stream_GetPosition(s);
1476 Stream_SetPosition(s, count_pos);
1477 Stream_Write_UINT32(s, arg.count);
1478 Stream_SetPosition(s, pos);
1479 Stream_SealLength(s);
1480 return rdpdr_send(rdpdr, s);
1483 UINT rdpdr_try_send_device_list_announce_request(
rdpdrPlugin* rdpdr)
1485 WINPR_ASSERT(rdpdr);
1486 if (rdpdr->state != RDPDR_CHANNEL_STATE_READY)
1488 WLog_Print(rdpdr->log, WLOG_DEBUG,
1489 "hotplug event received, but channel [RDPDR] is not ready (state %s), ignoring.",
1490 rdpdr_state_str(rdpdr->state));
1491 return CHANNEL_RC_OK;
1493 return rdpdr_send_device_list_announce_request(rdpdr, rdpdr->userLoggedOn);
1499 UINT32 DeviceId = 0;
1501 UINT32 CompletionId = 0;
1503 WINPR_ASSERT(rdpdr);
1506 output = StreamPool_Take(rdpdr->pool, 256);
1509 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1510 return CHANNEL_RC_NO_MEMORY;
1513 Stream_SetPosition(s, 4);
1515 Stream_Read_UINT32(s, DeviceId);
1516 Stream_Read_UINT32(s, FileId);
1517 Stream_Read_UINT32(s, CompletionId);
1519 if (!rdpdr_write_iocompletion_header(output, DeviceId, CompletionId,
1520 (UINT32)STATUS_UNSUCCESSFUL))
1521 return CHANNEL_RC_NO_MEMORY;
1523 return rdpdr_send(rdpdr, output);
1534 UINT error = CHANNEL_RC_OK;
1536 WINPR_ASSERT(rdpdr);
1539 irp = irp_new(rdpdr->devman, rdpdr->pool, s, rdpdr->log, &error);
1543 WLog_Print(rdpdr->log, WLOG_ERROR,
"irp_new failed with %" PRIu32
"!", error);
1545 if (error == CHANNEL_RC_OK || (error == ERROR_DEV_NOT_EXIST && rdpdr->ignoreInvalidDevices))
1547 return dummy_irp_response(rdpdr, s);
1553 if (irp->device->IRPRequest)
1554 IFCALLRET(irp->device->IRPRequest, error, irp->device, irp);
1558 if (error != CHANNEL_RC_OK)
1560 WLog_Print(rdpdr->log, WLOG_ERROR,
"device->IRPRequest failed with error %" PRIu32
"",
1568 static UINT rdpdr_process_component(
rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
1572 DEVICE* device = NULL;
1574 WINPR_ASSERT(rdpdr);
1579 case RDPDR_CTYP_PRN:
1580 type = RDPDR_DTYP_PRINT;
1584 return ERROR_INVALID_DATA;
1587 device = devman_get_device_by_type(rdpdr->devman, type);
1590 return ERROR_DEV_NOT_EXIST;
1592 return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
1601 static BOOL device_init(ULONG_PTR key,
void* element,
void* data)
1604 UINT error = CHANNEL_RC_OK;
1605 DEVICE* device = element;
1610 IFCALLRET(device->Init, error, device);
1612 if (error != CHANNEL_RC_OK)
1614 WLog_Print(log, WLOG_ERROR,
"Device init failed with %s", WTSErrorToString(error));
1620 static UINT rdpdr_process_init(
rdpdrPlugin* rdpdr)
1622 WINPR_ASSERT(rdpdr);
1623 WINPR_ASSERT(rdpdr->devman);
1625 rdpdr->userLoggedOn = FALSE;
1626 if (!device_foreach(rdpdr, TRUE, device_init, rdpdr->log))
1627 return ERROR_INTERNAL_ERROR;
1628 return CHANNEL_RC_OK;
1631 static BOOL state_match(
enum RDPDR_CHANNEL_STATE state,
size_t count, va_list ap)
1633 for (
size_t x = 0; x < count; x++)
1635 enum RDPDR_CHANNEL_STATE cur = va_arg(ap,
enum RDPDR_CHANNEL_STATE);
1642 static const char* state_str(
size_t count, va_list ap,
char* buffer,
size_t size)
1644 for (
size_t x = 0; x < count; x++)
1646 enum RDPDR_CHANNEL_STATE cur = va_arg(ap,
enum RDPDR_CHANNEL_STATE);
1647 const char* curstr = rdpdr_state_str(cur);
1648 winpr_str_append(curstr, buffer, size,
"|");
1653 static BOOL rdpdr_state_check(
rdpdrPlugin* rdpdr, UINT16 packetid,
enum RDPDR_CHANNEL_STATE next,
1657 WINPR_ASSERT(rdpdr);
1659 va_start(ap, count);
1660 BOOL rc = state_match(rdpdr->state, count, ap);
1665 const char* strstate = rdpdr_state_str(rdpdr->state);
1666 char buffer[256] = { 0 };
1668 va_start(ap, count);
1669 state_str(count, ap, buffer,
sizeof(buffer));
1672 WLog_Print(rdpdr->log, WLOG_ERROR,
1673 "channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.",
1674 rdpdr_packetid_string(packetid), buffer, strstate);
1676 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
1679 return rdpdr_state_advance(rdpdr, next);
1682 static BOOL rdpdr_check_channel_state(
rdpdrPlugin* rdpdr, UINT16 packetid)
1684 WINPR_ASSERT(rdpdr);
1688 case PAKID_CORE_SERVER_ANNOUNCE:
1693 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
1694 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1,
1695 RDPDR_CHANNEL_STATE_INITIAL);
1696 case PAKID_CORE_SERVER_CAPABILITY:
1697 return rdpdr_state_check(
1698 rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6,
1699 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_SERVER_CAPS,
1700 RDPDR_CHANNEL_STATE_READY, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1701 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1702 case PAKID_CORE_CLIENTID_CONFIRM:
1703 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 3,
1704 RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY,
1705 RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1706 case PAKID_CORE_USER_LOGGEDON:
1707 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU))
1710 return rdpdr_state_check(
1711 rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4,
1712 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1713 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY);
1716 enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY;
1717 return rdpdr_state_check(rdpdr, packetid, state, 1, state);
1729 UINT16 component = 0;
1730 UINT16 packetId = 0;
1731 UINT32 deviceId = 0;
1733 UINT error = ERROR_INVALID_DATA;
1736 return CHANNEL_RC_NULL_DATA;
1738 rdpdr_dump_received_packet(rdpdr->log, WLOG_TRACE, s,
"[rdpdr-channel] receive");
1739 if (Stream_GetRemainingLength(s) >= 4)
1741 Stream_Read_UINT16(s, component);
1742 Stream_Read_UINT16(s, packetId);
1744 if (component == RDPDR_CTYP_CORE)
1746 if (!rdpdr_check_channel_state(rdpdr, packetId))
1747 return CHANNEL_RC_OK;
1751 case PAKID_CORE_SERVER_ANNOUNCE:
1752 if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
1755 else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
1757 WLog_Print(rdpdr->log, WLOG_ERROR,
1758 "rdpdr_send_client_announce_reply failed with error %" PRIu32
"",
1761 else if ((error = rdpdr_send_client_name_request(rdpdr)))
1763 WLog_Print(rdpdr->log, WLOG_ERROR,
1764 "rdpdr_send_client_name_request failed with error %" PRIu32
"",
1767 else if ((error = rdpdr_process_init(rdpdr)))
1769 WLog_Print(rdpdr->log, WLOG_ERROR,
1770 "rdpdr_process_init failed with error %" PRIu32
"", error);
1775 case PAKID_CORE_SERVER_CAPABILITY:
1776 if ((error = rdpdr_process_capability_request(rdpdr, s)))
1779 else if ((error = rdpdr_send_capability_response(rdpdr)))
1781 WLog_Print(rdpdr->log, WLOG_ERROR,
1782 "rdpdr_send_capability_response failed with error %" PRIu32
"",
1788 case PAKID_CORE_CLIENTID_CONFIRM:
1789 if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
1792 else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
1795 rdpdr->log, WLOG_ERROR,
1796 "rdpdr_send_device_list_announce_request failed with error %" PRIu32
"",
1799 else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
1801 error = ERROR_INTERNAL_ERROR;
1805 case PAKID_CORE_USER_LOGGEDON:
1806 if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
1809 rdpdr->log, WLOG_ERROR,
1810 "rdpdr_send_device_list_announce_request failed with error %" PRIu32
"",
1813 else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
1815 error = ERROR_INTERNAL_ERROR;
1820 case PAKID_CORE_DEVICE_REPLY:
1823 if (Stream_GetRemainingLength(s) >= 8)
1825 Stream_Read_UINT32(s, deviceId);
1826 Stream_Read_UINT32(s, status);
1829 devman_unregister_device(rdpdr->devman, (
void*)((
size_t)deviceId));
1830 error = CHANNEL_RC_OK;
1835 case PAKID_CORE_DEVICE_IOREQUEST:
1836 if ((error = rdpdr_process_irp(rdpdr, s)))
1838 WLog_Print(rdpdr->log, WLOG_ERROR,
1839 "rdpdr_process_irp failed with error %" PRIu32
"", error);
1848 WLog_Print(rdpdr->log, WLOG_ERROR,
1849 "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16
"", packetId);
1850 error = ERROR_INVALID_DATA;
1856 error = rdpdr_process_component(rdpdr, component, packetId, s);
1858 if (error != CHANNEL_RC_OK)
1860 DWORD level = WLOG_ERROR;
1861 if (rdpdr->ignoreInvalidDevices)
1863 if (error == ERROR_DEV_NOT_EXIST)
1866 error = CHANNEL_RC_OK;
1869 WLog_Print(rdpdr->log, level,
1870 "Unknown message: Component: %s [0x%04" PRIX16
1871 "] PacketId: %s [0x%04" PRIX16
"]",
1872 rdpdr_component_string(component), component,
1873 rdpdr_packetid_string(packetId), packetId);
1893 return CHANNEL_RC_NULL_DATA;
1899 return CHANNEL_RC_BAD_INIT_HANDLE;
1902 const size_t pos = Stream_GetPosition(s);
1903 UINT status = ERROR_INTERNAL_ERROR;
1904 if (pos <= UINT32_MAX)
1906 rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s,
"[rdpdr-channel] send");
1907 status = plugin->channelEntryPoints.pVirtualChannelWriteEx(
1908 plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)pos, s);
1911 if (status != CHANNEL_RC_OK)
1914 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
1915 WTSErrorToString(status), status);
1926 static UINT rdpdr_virtual_channel_event_data_received(
rdpdrPlugin* rdpdr,
void* pData,
1927 UINT32 dataLength, UINT32 totalLength,
1932 WINPR_ASSERT(rdpdr);
1933 WINPR_ASSERT(pData || (dataLength == 0));
1935 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
1943 return CHANNEL_RC_OK;
1946 if (dataFlags & CHANNEL_FLAG_FIRST)
1948 if (rdpdr->data_in != NULL)
1949 Stream_Release(rdpdr->data_in);
1951 rdpdr->data_in = StreamPool_Take(rdpdr->pool, totalLength);
1953 if (!rdpdr->data_in)
1955 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1956 return CHANNEL_RC_NO_MEMORY;
1960 data_in = rdpdr->data_in;
1962 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
1964 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
1965 return ERROR_INVALID_DATA;
1968 Stream_Write(data_in, pData, dataLength);
1970 if (dataFlags & CHANNEL_FLAG_LAST)
1972 const size_t pos = Stream_GetPosition(data_in);
1973 const size_t cap = Stream_Capacity(data_in);
1976 WLog_Print(rdpdr->log, WLOG_ERROR,
1977 "rdpdr_virtual_channel_event_data_received: read error");
1978 return ERROR_INTERNAL_ERROR;
1981 Stream_SealLength(data_in);
1982 Stream_SetPosition(data_in, 0);
1986 if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (
void*)data_in, NULL))
1988 WLog_Print(rdpdr->log, WLOG_ERROR,
"MessageQueue_Post failed!");
1989 return ERROR_INTERNAL_ERROR;
1991 rdpdr->data_in = NULL;
1995 UINT error = rdpdr_process_receive(rdpdr, data_in);
1996 Stream_Release(data_in);
1997 rdpdr->data_in = NULL;
2003 return CHANNEL_RC_OK;
2006 static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
2007 UINT event, LPVOID pData,
2008 UINT32 dataLength, UINT32 totalLength,
2011 UINT error = CHANNEL_RC_OK;
2014 WINPR_ASSERT(rdpdr);
2017 case CHANNEL_EVENT_DATA_RECEIVED:
2018 if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle))
2020 WLog_Print(rdpdr->log, WLOG_ERROR,
"error no match");
2023 if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength,
2024 totalLength, dataFlags)))
2025 WLog_Print(rdpdr->log, WLOG_ERROR,
2026 "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32
2032 case CHANNEL_EVENT_WRITE_CANCELLED:
2033 case CHANNEL_EVENT_WRITE_COMPLETE:
2040 case CHANNEL_EVENT_USER:
2046 if (error && rdpdr && rdpdr->rdpcontext)
2047 setChannelError(rdpdr->rdpcontext, error,
2048 "rdpdr_virtual_channel_open_event_ex reported an error");
2051 static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
2058 ExitThread((DWORD)CHANNEL_RC_NULL_DATA);
2059 return CHANNEL_RC_NULL_DATA;
2062 if ((error = rdpdr_process_connect(rdpdr)))
2064 WLog_Print(rdpdr->log, WLOG_ERROR,
"rdpdr_process_connect failed with error %" PRIu32
"!",
2067 if (rdpdr->rdpcontext)
2068 setChannelError(rdpdr->rdpcontext, error,
2069 "rdpdr_virtual_channel_client_thread reported an error");
2077 wMessage message = { 0 };
2078 WINPR_ASSERT(rdpdr);
2080 if (!MessageQueue_Wait(rdpdr->queue))
2083 if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
2085 if (message.id == WMQ_QUIT)
2088 if (message.id == 0)
2092 error = rdpdr_process_receive(rdpdr, data);
2094 Stream_Release(data);
2097 WLog_Print(rdpdr->log, WLOG_ERROR,
2098 "rdpdr_process_receive failed with error %" PRIu32
"!", error);
2100 if (rdpdr->rdpcontext)
2101 setChannelError(rdpdr->rdpcontext, error,
2102 "rdpdr_virtual_channel_client_thread reported an error");
2111 if ((error = drive_hotplug_thread_terminate(rdpdr)))
2112 WLog_Print(rdpdr->log, WLOG_ERROR,
2113 "drive_hotplug_thread_terminate failed with error %" PRIu32
"!", error);
2119 static void queue_free(
void* obj)
2122 wMessage* msg = (wMessage*)obj;
2124 if (!msg || (msg->id != 0))
2137 static UINT rdpdr_virtual_channel_event_connected(
rdpdrPlugin* rdpdr, LPVOID pData,
2142 WINPR_ASSERT(rdpdr);
2143 WINPR_UNUSED(pData);
2144 WINPR_UNUSED(dataLength);
2148 rdpdr->queue = MessageQueue_New(NULL);
2152 WLog_Print(rdpdr->log, WLOG_ERROR,
"MessageQueue_New failed!");
2153 return CHANNEL_RC_NO_MEMORY;
2156 obj = MessageQueue_Object(rdpdr->queue);
2157 obj->fnObjectFree = queue_free;
2159 if (!(rdpdr->thread = CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread,
2160 (
void*)rdpdr, 0, NULL)))
2162 WLog_Print(rdpdr->log, WLOG_ERROR,
"CreateThread failed!");
2163 return ERROR_INTERNAL_ERROR;
2168 UINT error = rdpdr_process_connect(rdpdr);
2171 WLog_Print(rdpdr->log, WLOG_ERROR,
2172 "rdpdr_process_connect failed with error %" PRIu32
"!", error);
2177 return rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, &rdpdr->OpenHandle,
2178 rdpdr->channelDef.name,
2179 rdpdr_virtual_channel_open_event_ex);
2187 static UINT rdpdr_virtual_channel_event_disconnected(
rdpdrPlugin* rdpdr)
2191 WINPR_ASSERT(rdpdr);
2193 if (rdpdr->OpenHandle == 0)
2194 return CHANNEL_RC_OK;
2196 if (rdpdr->queue && rdpdr->thread)
2198 if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
2199 (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
2201 error = GetLastError();
2202 WLog_Print(rdpdr->log, WLOG_ERROR,
"WaitForSingleObject failed with error %" PRIu32
"!",
2209 (void)CloseHandle(rdpdr->thread);
2210 MessageQueue_Free(rdpdr->queue);
2211 rdpdr->queue = NULL;
2212 rdpdr->thread = NULL;
2214 WINPR_ASSERT(rdpdr->channelEntryPoints.pVirtualChannelCloseEx);
2215 error = rdpdr->channelEntryPoints.pVirtualChannelCloseEx(rdpdr->InitHandle, rdpdr->OpenHandle);
2217 if (CHANNEL_RC_OK != error)
2219 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelCloseEx failed with %s [%08" PRIX32
"]",
2220 WTSErrorToString(error), error);
2223 rdpdr->OpenHandle = 0;
2227 Stream_Release(rdpdr->data_in);
2228 rdpdr->data_in = NULL;
2233 devman_free(rdpdr->devman);
2234 rdpdr->devman = NULL;
2240 static void rdpdr_virtual_channel_event_terminated(
rdpdrPlugin* rdpdr)
2242 WINPR_ASSERT(rdpdr);
2243 rdpdr->InitHandle = 0;
2244 StreamPool_Free(rdpdr->pool);
2248 static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
2249 UINT event, LPVOID pData, UINT dataLength)
2251 UINT error = CHANNEL_RC_OK;
2254 if (!rdpdr || (rdpdr->InitHandle != pInitHandle))
2256 WLog_ERR(TAG,
"error no match");
2260 WINPR_ASSERT(pData || (dataLength == 0));
2264 case CHANNEL_EVENT_INITIALIZED:
2267 case CHANNEL_EVENT_CONNECTED:
2268 if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength)))
2269 WLog_Print(rdpdr->log, WLOG_ERROR,
2270 "rdpdr_virtual_channel_event_connected failed with error %" PRIu32
"!",
2275 case CHANNEL_EVENT_DISCONNECTED:
2276 if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr)))
2277 WLog_Print(rdpdr->log, WLOG_ERROR,
2278 "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32
2284 case CHANNEL_EVENT_TERMINATED:
2285 rdpdr_virtual_channel_event_terminated(rdpdr);
2289 case CHANNEL_EVENT_ATTACHED:
2290 case CHANNEL_EVENT_DETACHED:
2292 WLog_Print(rdpdr->log, WLOG_ERROR,
"unknown event %" PRIu32
"!", event);
2296 if (error && rdpdr && rdpdr->rdpcontext)
2297 setChannelError(rdpdr->rdpcontext, error,
2298 "rdpdr_virtual_channel_init_event_ex reported an error");
2302 #define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx
2304 FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
2311 WINPR_ASSERT(pEntryPoints);
2312 WINPR_ASSERT(pInitHandle);
2318 WLog_ERR(TAG,
"calloc failed!");
2321 rdpdr->log = WLog_Get(TAG);
2323 rdpdr->clientExtendedPDU =
2324 RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU;
2325 rdpdr->clientIOCode1 =
2326 RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
2327 RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
2328 RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
2329 RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
2330 RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL |
2331 RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY;
2333 rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO;
2335 rdpdr->pool = StreamPool_New(TRUE, 1024);
2342 rdpdr->channelDef.options =
2343 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
2344 (void)sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name),
2345 RDPDR_SVC_CHANNEL_NAME);
2346 rdpdr->sequenceId = 0;
2350 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
2352 rdpdr->rdpcontext = pEntryPointsEx->context;
2354 FreeRDP_SynchronousStaticChannels))
2355 rdpdr->async = TRUE;
2359 rdpdr->InitHandle = pInitHandle;
2360 rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx(
2361 rdpdr, NULL, pInitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
2362 rdpdr_virtual_channel_init_event_ex);
2364 if (CHANNEL_RC_OK != rc)
2366 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelInitEx failed with %s [%08" PRIX32
"]",
2367 WTSErrorToString(rc), rc);
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.
This struct contains function pointer to initialize/free objects.