25#include <freerdp/config.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>
57#include <CoreFoundation/CoreFoundation.h>
65#include "rdpdr_capabilities.h"
70#include "rdpdr_main.h"
72#define TAG CHANNELS_TAG("rdpdr.client")
82static 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";
109static const char* support_str(BOOL val)
116static const char* rdpdr_caps_pdu_str(UINT32 flag)
120 case RDPDR_DEVICE_REMOVE_PDUS:
121 return "RDPDR_USER_LOGGEDON_PDU";
122 case RDPDR_CLIENT_DISPLAY_NAME_PDU:
123 return "RDPDR_CLIENT_DISPLAY_NAME_PDU";
124 case RDPDR_USER_LOGGEDON_PDU:
125 return "RDPDR_USER_LOGGEDON_PDU";
127 return "RDPDR_UNKNONW";
131static BOOL rdpdr_check_extended_pdu_flag(
rdpdrPlugin* rdpdr, UINT32 flag)
135 const BOOL client = (rdpdr->clientExtendedPDU & flag) != 0;
136 const BOOL server = (rdpdr->serverExtendedPDU & flag) != 0;
138 if (!client || !server)
140 WLog_Print(rdpdr->log, WLOG_WARN,
"Checking ExtendedPDU::%s, client %s, server %s",
141 rdpdr_caps_pdu_str(flag), support_str(client), support_str(server));
147BOOL rdpdr_state_advance(
rdpdrPlugin* rdpdr,
enum RDPDR_CHANNEL_STATE next)
151 if (next != rdpdr->state)
152 WLog_Print(rdpdr->log, WLOG_DEBUG,
"[RDPDR] transition from %s to %s",
153 rdpdr_state_str(rdpdr->state), rdpdr_state_str(next));
158static BOOL device_foreach(
rdpdrPlugin* rdpdr, BOOL abortOnFail,
159 BOOL (*fkt)(ULONG_PTR key,
void* element,
void* data),
void* data)
162 ULONG_PTR* keys =
nullptr;
164 ListDictionary_Lock(rdpdr->devman->devices);
165 const size_t count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
166 for (
size_t x = 0; x < count; x++)
168 void* element = ListDictionary_GetItemValue(rdpdr->devman->devices, (
void*)keys[x]);
169 if (!fkt(keys[x], element, data))
177 ListDictionary_Unlock(rdpdr->devman->devices);
186static UINT rdpdr_try_send_device_list_announce_request(
rdpdrPlugin* rdpdr);
188static BOOL rdpdr_load_drive(
rdpdrPlugin* rdpdr,
const char* name,
const char* path, BOOL automount)
190 UINT rc = ERROR_INTERNAL_ERROR;
196 const char* args[] = { name, path, automount ? nullptr : name };
198 drive.device = freerdp_device_new(RDPDR_DTYP_FILESYSTEM, ARRAYSIZE(args), args);
202 WINPR_ASSERT(rdpdr->context.RdpdrRegisterDevice);
203 rc = rdpdr->context.RdpdrRegisterDevice(&rdpdr->context, drive.device, &drive.device->Id);
204 if (rc != CHANNEL_RC_OK)
208 freerdp_device_free(drive.device);
209 return rc == CHANNEL_RC_OK;
217static UINT rdpdr_send_device_list_remove_request(
rdpdrPlugin* rdpdr, UINT32 count,
223 WINPR_ASSERT(ids || (count == 0));
226 return CHANNEL_RC_OK;
228 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_DEVICE_REMOVE_PDUS))
229 return CHANNEL_RC_OK;
231 s = StreamPool_Take(rdpdr->pool, count *
sizeof(UINT32) + 8);
235 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
236 return CHANNEL_RC_NO_MEMORY;
239 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
240 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
241 Stream_Write_UINT32(s, count);
243 for (UINT32 i = 0; i < count; i++)
244 Stream_Write_UINT32(s, ids[i]);
246 Stream_SealLength(s);
247 return rdpdr_send(rdpdr, s);
250#if defined(_UWP) || defined(__IOS__)
252static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
253 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
255 return ERROR_CALL_NOT_IMPLEMENTED;
258static void first_hotplug(WINPR_ATTR_UNUSED
rdpdrPlugin* rdpdr)
262static DWORD WINAPI drive_hotplug_thread_func(WINPR_ATTR_UNUSED LPVOID arg)
264 return CHANNEL_RC_OK;
267static UINT drive_hotplug_thread_terminate(WINPR_ATTR_UNUSED
rdpdrPlugin* rdpdr)
269 return CHANNEL_RC_OK;
274static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
275 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
277 return CHANNEL_RC_OK;
280static BOOL check_path(
const char* path)
282 UINT type = GetDriveTypeA(path);
284 if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
285 type == DRIVE_REMOTE))
288 return GetVolumeInformationA(path,
nullptr, 0,
nullptr,
nullptr,
nullptr,
nullptr, 0);
293 DWORD unitmask = GetLogicalDrives();
295 for (
size_t i = 0; i < 26; i++)
299 char drive_path[] = {
'c',
':',
'\\',
'\0' };
300 char drive_name[] = {
'c',
'\0' };
301 drive_path[0] =
'A' + (char)i;
302 drive_name[0] =
'A' + (char)i;
304 if (check_path(drive_path))
306 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
310 unitmask = unitmask >> 1;
314static LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
317 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
319 rdpdr = (
rdpdrPlugin*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
323 case WM_DEVICECHANGE:
326 case DBT_DEVICEARRIVAL:
327 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
329 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
330 DWORD unitmask = lpdbv->dbcv_unitmask;
332 for (
int i = 0; i < 26; i++)
336 char drive_path[] = {
'c',
':',
'/',
'\0' };
337 char drive_name[] = {
'c',
'\0' };
338 drive_path[0] =
'A' + (char)i;
339 drive_name[0] =
'A' + (char)i;
341 if (check_path(drive_path))
343 rdpdr_load_drive(rdpdr, drive_name, drive_path, TRUE);
347 unitmask = unitmask >> 1;
353 case DBT_DEVICEREMOVECOMPLETE:
354 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
356 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
357 DWORD unitmask = lpdbv->dbcv_unitmask;
358 char drive_name_upper, drive_name_lower;
359 ULONG_PTR* keys =
nullptr;
360 DEVICE_DRIVE_EXT* device_ext;
362 for (
int i = 0; i < 26; i++)
366 drive_name_upper =
'A' + i;
367 drive_name_lower =
'a' + i;
369 ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
371 for (
size_t j = 0; j < count; j++)
373 device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
374 rdpdr->devman->devices, (
void*)keys[j]);
376 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
379 if (device_ext->path[0] == drive_name_upper ||
380 device_ext->path[0] == drive_name_lower)
382 if (device_ext->automount)
384 const uint32_t ids[] = { (uint32_t)keys[j] };
385 WINPR_ASSERT(rdpdr->context.RdpdrUnregisterDevice);
386 error = rdpdr->context.RdpdrUnregisterDevice(
387 &rdpdr->context, ARRAYSIZE(ids), ids);
392 rdpdr->log, WLOG_ERROR,
393 "rdpdr_send_device_list_remove_request failed "
394 "with error %" PRIu32
"!",
406 unitmask = unitmask >> 1;
419 return DefWindowProc(hWnd, Msg, wParam, lParam);
422 return DefWindowProc(hWnd, Msg, wParam, lParam);
425static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
432 DEV_BROADCAST_HANDLE NotificationFilter;
433 HDEVNOTIFY hDevNotify;
436 wnd_cls.cbSize =
sizeof(WNDCLASSEX);
437 wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
438 wnd_cls.lpfnWndProc = hotplug_proc;
439 wnd_cls.cbClsExtra = 0;
440 wnd_cls.cbWndExtra = 0;
441 wnd_cls.hIcon = LoadIcon(
nullptr, IDI_APPLICATION);
442 wnd_cls.hCursor =
nullptr;
443 wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
444 wnd_cls.lpszMenuName =
nullptr;
445 wnd_cls.lpszClassName = L
"DRIVE_HOTPLUG";
446 wnd_cls.hInstance =
nullptr;
447 wnd_cls.hIconSm = LoadIcon(
nullptr, IDI_APPLICATION);
448 RegisterClassEx(&wnd_cls);
450 hwnd = CreateWindowEx(0, L
"DRIVE_HOTPLUG",
nullptr, 0, 0, 0, 0, 0,
nullptr,
nullptr,
nullptr,
452 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr);
453 rdpdr->hotplug_wnd = hwnd;
455 NotificationFilter.dbch_size =
sizeof(DEV_BROADCAST_HANDLE);
456 NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
457 hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
460 while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
468 TranslateMessage(&msg);
469 DispatchMessage(&msg);
473 UnregisterDeviceNotification(hDevNotify);
474 return CHANNEL_RC_OK;
482static UINT drive_hotplug_thread_terminate(
rdpdrPlugin* rdpdr)
484 UINT error = CHANNEL_RC_OK;
486 if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0))
488 error = GetLastError();
489 WLog_Print(rdpdr->log, WLOG_ERROR,
"PostMessage failed with error %" PRIu32
"", error);
495#elif defined(__MACOSX__)
497#define MAX_USB_DEVICES 100
510static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
511 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
513 WINPR_ASSERT(context);
516 struct dirent* pDirent =
nullptr;
517 char fullpath[PATH_MAX] = WINPR_C_ARRAY_INIT;
518 char* szdir = (
char*)
"/Volumes";
519 struct stat buf = WINPR_C_ARRAY_INIT;
520 hotplug_dev dev_array[MAX_USB_DEVICES] = WINPR_C_ARRAY_INIT;
522 DEVICE_DRIVE_EXT* device_ext =
nullptr;
523 ULONG_PTR* keys =
nullptr;
525 UINT error = ERROR_INTERNAL_ERROR;
527 DIR* pDir = opendir(szdir);
531 printf(
"Cannot open directory\n");
532 return ERROR_OPEN_FAILED;
535 while ((pDirent = readdir(pDir)) !=
nullptr)
537 if (pDirent->d_name[0] !=
'.')
539 (void)sprintf_s(fullpath, ARRAYSIZE(fullpath),
"%s/%s", szdir, pDirent->d_name);
540 if (stat(fullpath, &buf) != 0)
543 if (S_ISDIR(buf.st_mode))
545 dev_array[size].path = _strdup(fullpath);
547 if (!dev_array[size].path)
550 error = CHANNEL_RC_NO_MEMORY;
554 dev_array[size++].to_add = TRUE;
561 count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
563 for (
size_t j = 0; j < count; j++)
565 char* path =
nullptr;
566 BOOL dev_found = FALSE;
568 (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (
void*)keys[j]);
570 if (!device_ext || !device_ext->automount)
573 if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
576 if (device_ext->path ==
nullptr)
579 path = ConvertWCharToUtf8Alloc(device_ext->path,
nullptr);
584 if (strstr(path,
"/Volumes/") ==
nullptr)
590 for (
size_t i = 0; i < size; i++)
592 if (strstr(path, dev_array[i].path) !=
nullptr)
595 dev_array[i].to_add = FALSE;
604 const uint32_t ids[] = { (uint32_t)keys[j] };
605 WINPR_ASSERT(rdpdr->context.RdpdrUnregisterDevice);
606 error = rdpdr->context.RdpdrUnregisterDevice(&rdpdr->context, ARRAYSIZE(ids), ids);
609 WLog_Print(rdpdr->log, WLOG_ERROR,
610 "rdpdr_send_device_list_remove_request failed with error %" PRIu32
"!",
618 for (
size_t i = 0; i < size; i++)
620 const hotplug_dev* dev = &dev_array[i];
623 const char* path = dev->path;
624 const char* name = strrchr(path,
'/') + 1;
625 error = rdpdr_load_drive(rdpdr, name, path, TRUE);
634 for (
size_t i = 0; i < size; i++)
635 free(dev_array[i].path);
640static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,
641 void* clientCallBackInfo,
size_t numEvents,
643 const FSEventStreamEventFlags eventFlags[],
644 const FSEventStreamEventId eventIds[])
648 char** paths = (
char**)eventPaths;
651 for (
size_t i = 0; i < numEvents; i++)
653 if (strcmp(paths[i],
"/Volumes/") == 0)
655 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
656 if (rdpdr->context.RdpdrHotplugDevice)
657 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context,
658 RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
661 case ERROR_DISK_CHANGE:
664 case ERROR_CALL_NOT_IMPLEMENTED:
667 WLog_Print(rdpdr->log, WLOG_ERROR,
668 "handle_hotplug failed with error %" PRIu32
"!", error);
678 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
679 if (rdpdr->context.RdpdrHotplugDevice)
680 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
684 case ERROR_DISK_CHANGE:
686 case ERROR_CALL_NOT_IMPLEMENTED:
689 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
695static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
699 WINPR_ASSERT(rdpdr->stopEvent);
701 CFStringRef path = CFSTR(
"/Volumes/");
702 CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (
const void**)&path, 1,
nullptr);
703 FSEventStreamContext ctx = {
704 .copyDescription =
nullptr, .info = arg, .release =
nullptr, .retain =
nullptr, .version = 0
706 FSEventStreamRef fsev =
707 FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch,
708 kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
710 dispatch_queue_t queue = dispatch_queue_create(TAG,
nullptr);
711 FSEventStreamSetDispatchQueue(fsev, queue);
712 FSEventStreamStart(fsev);
713 WLog_Print(rdpdr->log, WLOG_DEBUG,
"Started hotplug watcher");
714 HANDLE handles[] = { rdpdr->stopEvent, freerdp_abort_event(rdpdr->rdpcontext) };
715 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
716 WLog_Print(rdpdr->log, WLOG_DEBUG,
"Stopped hotplug watcher");
717 FSEventStreamStop(fsev);
718 FSEventStreamRelease(fsev);
719 dispatch_release(queue);
721 UINT error = CHANNEL_RC_OK;
722 if (status > WAIT_OBJECT_0 + ARRAYSIZE(handles))
723 error = ERROR_INTERNAL_ERROR;
730static const char* automountLocations[] = {
"/run/user/%lu/gvfs",
"/run/media/%s",
"/media/%s",
733static BOOL isAutomountLocation(
const char* path)
735 const size_t nrLocations =
sizeof(automountLocations) /
sizeof(automountLocations[0]);
736 char buffer[MAX_PATH] = WINPR_C_ARRAY_INIT;
737 uid_t uid = getuid();
738 char uname[MAX_PATH] = WINPR_C_ARRAY_INIT;
739 ULONG size =
sizeof(uname) - 1;
741 if (!GetUserNameExA(NameSamCompatible, uname, &size))
747 for (
size_t x = 0; x < nrLocations; x++)
749 const char* location = automountLocations[x];
752 WINPR_PRAGMA_DIAG_PUSH
753 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
754 if (strstr(location,
"%lu"))
755 (
void)snprintf(buffer,
sizeof(buffer), location, (
unsigned long)uid);
756 else if (strstr(location,
"%s"))
757 (void)snprintf(buffer,
sizeof(buffer), location, uname);
759 (
void)snprintf(buffer,
sizeof(buffer),
"%s", location);
760 WINPR_PRAGMA_DIAG_POP
762 length = strnlen(buffer,
sizeof(buffer));
764 if (strncmp(buffer, path, length) == 0)
766 const char* rest = &path[length];
772 else if (*rest ==
'/')
774 const char* token = strstr(&rest[1],
"/");
776 if (!token || (token[1] ==
'\0'))
785#define MAX_USB_DEVICES 100
793static void handle_mountpoint(hotplug_dev* dev_array,
size_t* size,
const char* mountpoint)
798 if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
800 dev_array[*size].path = _strdup(mountpoint);
801 dev_array[*size].to_add = TRUE;
807#include <sys/mnttab.h>
808static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array,
size_t* size)
812 f = winpr_fopen(
"/etc/mnttab",
"r");
815 WLog_Print(log, WLOG_ERROR,
"fopen failed!");
816 return ERROR_OPEN_FAILED;
818 while (getmntent(f, &ent) == 0)
820 handle_mountpoint(dev_array, size, ent.mnt_mountp);
823 return ERROR_SUCCESS;
827#if defined(__FreeBSD__) || defined(__OpenBSD__)
828#include <sys/mount.h>
829static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array,
size_t* size)
832 struct statfs* mntbuf =
nullptr;
834 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
838 WLog_Print(log, WLOG_ERROR,
"getmntinfo failed!");
839 return ERROR_OPEN_FAILED;
841 for (
size_t idx = 0; idx < (size_t)mntsize; idx++)
843 handle_mountpoint(dev_array, size, mntbuf[idx].f_mntonname);
845 return ERROR_SUCCESS;
849#if defined(__LINUX__) || defined(__linux__)
851static struct mntent* getmntent_x(FILE* f,
struct mntent* buffer,
char* pathbuffer,
852 size_t pathbuffersize)
854#if defined(FREERDP_HAVE_GETMNTENT_R)
855 WINPR_ASSERT(pathbuffersize <= INT32_MAX);
856 return getmntent_r(f, buffer, pathbuffer, (
int)pathbuffersize);
860 (void)pathbuffersize;
865static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array,
size_t* size)
868 struct mntent mnt = WINPR_C_ARRAY_INIT;
869 char pathbuffer[PATH_MAX] = WINPR_C_ARRAY_INIT;
870 struct mntent* ent =
nullptr;
871 f = winpr_fopen(
"/proc/mounts",
"r");
874 WLog_Print(log, WLOG_ERROR,
"fopen failed!");
875 return ERROR_OPEN_FAILED;
877 while ((ent = getmntent_x(f, &mnt, pathbuffer,
sizeof(pathbuffer))) !=
nullptr)
879 handle_mountpoint(dev_array, size, ent->mnt_dir);
882 return ERROR_SUCCESS;
886static UINT handle_platform_mounts(wLog* log, hotplug_dev* dev_array,
size_t* size)
889 return handle_platform_mounts_sun(log, dev_array, size);
890#elif defined(__FreeBSD__) || defined(__OpenBSD__)
891 return handle_platform_mounts_bsd(log, dev_array, size);
892#elif defined(__LINUX__) || defined(__linux__)
893 return handle_platform_mounts_linux(log, dev_array, size);
895 return ERROR_CALL_NOT_IMPLEMENTED;
898static BOOL device_not_plugged(ULONG_PTR key,
void* element,
void* data)
900 const WCHAR* path = (
const WCHAR*)data;
901 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
906 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path)
908 if (_wcscmp(device_ext->path, path) != 0)
913static BOOL device_already_plugged(
rdpdrPlugin* rdpdr,
const hotplug_dev* device)
916 WCHAR* path =
nullptr;
918 if (!rdpdr || !device)
923 WINPR_ASSERT(rdpdr->devman);
924 WINPR_ASSERT(device->path);
926 path = ConvertUtf8ToWCharAlloc(device->path,
nullptr);
930 rc = device_foreach(rdpdr, TRUE, device_not_plugged, path);
935struct hotplug_delete_arg
937 hotplug_dev* dev_array;
938 size_t dev_array_size;
942static BOOL hotplug_delete_foreach(ULONG_PTR key,
void* element,
void* data)
944 char* path =
nullptr;
945 BOOL dev_found = FALSE;
946 struct hotplug_delete_arg* arg = (
struct hotplug_delete_arg*)data;
947 DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
950 WINPR_ASSERT(arg->rdpdr);
951 WINPR_ASSERT(arg->dev_array || (arg->dev_array_size == 0));
952 WINPR_ASSERT(key <= UINT32_MAX);
954 if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path ||
955 !device_ext->automount)
958 WINPR_ASSERT(device_ext->path);
959 path = ConvertWCharToUtf8Alloc(device_ext->path,
nullptr);
964 if (isAutomountLocation(path))
966 for (
size_t i = 0; i < arg->dev_array_size; i++)
968 hotplug_dev* cur = &arg->dev_array[i];
969 if (cur->path && strstr(path, cur->path) !=
nullptr)
982 const UINT32 ids[1] = { (UINT32)key };
983 WINPR_ASSERT(arg->rdpdr->context.RdpdrUnregisterDevice);
985 arg->rdpdr->context.RdpdrUnregisterDevice(&arg->rdpdr->context, ARRAYSIZE(ids), ids);
989 WLog_Print(arg->rdpdr->log, WLOG_ERROR,
990 "rdpdr_send_device_list_remove_request failed with error %" PRIu32
"!",
999static UINT handle_hotplug(RdpdrClientContext* context,
1000 WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
1002 WINPR_ASSERT(context);
1005 hotplug_dev dev_array[MAX_USB_DEVICES] = WINPR_C_ARRAY_INIT;
1007 UINT error = ERROR_SUCCESS;
1008 struct hotplug_delete_arg arg = { dev_array, ARRAYSIZE(dev_array), rdpdr };
1010 WINPR_ASSERT(rdpdr);
1011 WINPR_ASSERT(rdpdr->devman);
1013 error = handle_platform_mounts(rdpdr->log, dev_array, &size);
1016 device_foreach(rdpdr, FALSE, hotplug_delete_foreach, &arg);
1019 for (
size_t i = 0; i < size; i++)
1021 hotplug_dev* cur = &dev_array[i];
1022 if (!device_already_plugged(rdpdr, cur))
1024 const char* path = cur->path;
1025 const char* name = strrchr(path,
'/') + 1;
1027 rdpdr_load_drive(rdpdr, name, path, TRUE);
1028 error = ERROR_DISK_CHANGE;
1032 for (
size_t i = 0; i < size; i++)
1033 free(dev_array[i].path);
1040 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
1042 WINPR_ASSERT(rdpdr);
1043 if (rdpdr->context.RdpdrHotplugDevice)
1044 error = rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
1048 case ERROR_DISK_CHANGE:
1050 case ERROR_OPEN_FAILED:
1051 case ERROR_CALL_NOT_IMPLEMENTED:
1054 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
1060static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
1064 WINPR_ASSERT(rdpdr);
1065 WINPR_ASSERT(rdpdr->stopEvent);
1067 while (WaitForSingleObject(rdpdr->stopEvent, 1000) == WAIT_TIMEOUT)
1069 UINT error = ERROR_CALL_NOT_IMPLEMENTED;
1070 if (rdpdr->context.RdpdrHotplugDevice)
1072 rdpdr->context.RdpdrHotplugDevice(&rdpdr->context, RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
1075 case ERROR_DISK_CHANGE:
1078 case ERROR_OPEN_FAILED:
1079 case ERROR_CALL_NOT_IMPLEMENTED:
1082 WLog_Print(rdpdr->log, WLOG_ERROR,
"handle_hotplug failed with error %" PRIu32
"!",
1090 const UINT error = GetLastError();
1091 if (error && rdpdr->rdpcontext)
1092 setChannelError(rdpdr->rdpcontext, error,
"reported an error");
1101#if !defined(_WIN32) && !defined(__IOS__)
1107static UINT drive_hotplug_thread_terminate(
rdpdrPlugin* rdpdr)
1111 WINPR_ASSERT(rdpdr);
1113 if (rdpdr->hotplugThread)
1116 if (rdpdr->stopEvent)
1117 (void)SetEvent(rdpdr->stopEvent);
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 =
nullptr;
1132 return CHANNEL_RC_OK;
1139 WINPR_ASSERT(rdpdr);
1140 WINPR_ASSERT(rdpdr->rdpcontext);
1142 rdpSettings* settings = rdpdr->rdpcontext->settings;
1143 WINPR_ASSERT(settings);
1149 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_DeviceArray, index);
1150 WINPR_ASSERT(device);
1152 if (device->Type == RDPDR_DTYP_FILESYSTEM)
1154 const char DynamicDrives[] =
"DynamicDrives";
1159 const char wildcard[] =
"*";
1160 BOOL hotplugAll = strncmp(drive->Path, wildcard,
sizeof(wildcard)) == 0;
1161 BOOL hotplugLater = strncmp(drive->Path, DynamicDrives,
sizeof(DynamicDrives)) == 0;
1163 if (hotplugAll || hotplugLater)
1167 WLog_Print(rdpdr->log, WLOG_WARN,
1168 "Drive hotplug is not supported in synchronous mode!");
1173 first_hotplug(rdpdr);
1178 if (!rdpdr->hotplugThread)
1180 rdpdr->hotplugThread =
1181 CreateThread(
nullptr, 0, drive_hotplug_thread_func, rdpdr, 0,
nullptr);
1182 if (!rdpdr->hotplugThread)
1184 WLog_Print(rdpdr->log, WLOG_ERROR,
"CreateThread failed!");
1185 return ERROR_INTERNAL_ERROR;
1193 const UINT error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext);
1196 WLog_Print(rdpdr->log, WLOG_ERROR,
1197 "devman_load_device_service failed with error %" PRIu32
"!", error);
1201 return CHANNEL_RC_OK;
1209static UINT rdpdr_process_connect(
rdpdrPlugin* rdpdr)
1211 WINPR_ASSERT(rdpdr);
1213 rdpdr->devman = devman_new(rdpdr);
1217 WLog_Print(rdpdr->log, WLOG_ERROR,
"devman_new failed!");
1218 return CHANNEL_RC_NO_MEMORY;
1221 WINPR_ASSERT(rdpdr->rdpcontext);
1223 rdpSettings* settings = rdpdr->rdpcontext->settings;
1224 WINPR_ASSERT(settings);
1233 DWORD size = ARRAYSIZE(rdpdr->computerName);
1234 if (!GetComputerNameExA(ComputerNameNetBIOS, rdpdr->computerName, &size))
1235 return ERROR_INTERNAL_ERROR;
1238 strncpy(rdpdr->computerName, name, strnlen(name,
sizeof(rdpdr->computerName)));
1240 return rdpdr_add_devices(rdpdr);
1244static UINT32 generate(
rdpdrPlugin* rdpdr, UINT32 received)
1246 UINT32 clientID = received;
1253 if ((rdpdr->serverVersionMajor == RDPDR_VERSION_MAJOR) &&
1254 (rdpdr->serverVersionMinor < RDPDR_VERSION_MINOR_RDP6X))
1256 while ((clientID == 0) || (clientID == UINT32_MAX) || (clientID == received) || (rc < 0))
1258 rc = winpr_RAND(&clientID,
sizeof(clientID));
1267 WINPR_ASSERT(rdpdr);
1270 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1271 return ERROR_INVALID_DATA;
1273 Stream_Read_UINT16(s, rdpdr->serverVersionMajor);
1274 Stream_Read_UINT16(s, rdpdr->serverVersionMinor);
1276 const UINT32 clientID = Stream_Get_UINT32(s);
1277 rdpdr->clientID = generate(rdpdr, clientID);
1279 rdpdr->sequenceId++;
1281 rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, rdpdr->serverVersionMajor);
1282 rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, rdpdr->serverVersionMinor);
1283 WLog_Print(rdpdr->log, WLOG_DEBUG,
1284 "[rdpdr] server announces version %" PRIu32
".%" PRIu32
", client uses %" PRIu32
1286 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1287 rdpdr->clientVersionMinor);
1288 return CHANNEL_RC_OK;
1296static UINT rdpdr_send_client_announce_reply(
rdpdrPlugin* rdpdr)
1298 WINPR_ASSERT(rdpdr);
1299 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE);
1300 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY))
1301 return ERROR_INVALID_STATE;
1303 wStream* s = StreamPool_Take(rdpdr->pool, 12);
1307 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1308 return CHANNEL_RC_NO_MEMORY;
1311 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1312 Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM);
1313 Stream_Write_UINT16(s, rdpdr->clientVersionMajor);
1314 Stream_Write_UINT16(s, rdpdr->clientVersionMinor);
1315 Stream_Write_UINT32(s, rdpdr->clientID);
1316 return rdpdr_send(rdpdr, s);
1324static UINT rdpdr_send_client_name_request(
rdpdrPlugin* rdpdr)
1327 WCHAR* computerNameW =
nullptr;
1328 size_t computerNameLenW = 0;
1330 WINPR_ASSERT(rdpdr);
1331 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
1332 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_NAME_REQUEST))
1333 return ERROR_INVALID_STATE;
1335 const size_t len = strnlen(rdpdr->computerName,
sizeof(rdpdr->computerName));
1337 return ERROR_INTERNAL_ERROR;
1339 WINPR_ASSERT(rdpdr->computerName);
1340 computerNameW = ConvertUtf8NToWCharAlloc(rdpdr->computerName, len, &computerNameLenW);
1341 computerNameLenW *=
sizeof(WCHAR);
1343 if (computerNameLenW > 0)
1344 computerNameLenW +=
sizeof(WCHAR);
1346 s = StreamPool_Take(rdpdr->pool, 16U + computerNameLenW);
1350 free(computerNameW);
1351 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1352 return CHANNEL_RC_NO_MEMORY;
1355 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1356 Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME);
1357 Stream_Write_UINT32(s, 1);
1358 Stream_Write_UINT32(s, 0);
1359 Stream_Write_UINT32(s,
1360 (UINT32)computerNameLenW);
1361 Stream_Write(s, computerNameW, computerNameLenW);
1362 free(computerNameW);
1363 return rdpdr_send(rdpdr, s);
1368 UINT16 versionMajor = 0;
1369 UINT16 versionMinor = 0;
1370 UINT32 clientID = 0;
1372 WINPR_ASSERT(rdpdr);
1375 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1376 return ERROR_INVALID_DATA;
1378 Stream_Read_UINT16(s, versionMajor);
1379 Stream_Read_UINT16(s, versionMinor);
1380 Stream_Read_UINT32(s, clientID);
1382 if (versionMajor != rdpdr->clientVersionMajor || versionMinor != rdpdr->clientVersionMinor)
1384 WLog_Print(rdpdr->log, WLOG_WARN,
1385 "[rdpdr] server announced version %" PRIu32
".%" PRIu32
", client uses %" PRIu32
1386 ".%" PRIu32
" but clientid confirm requests version %" PRIu32
".%" PRIu32,
1387 rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
1388 rdpdr->clientVersionMinor, versionMajor, versionMinor);
1389 rdpdr->clientVersionMajor = versionMajor;
1390 rdpdr->clientVersionMinor = versionMinor;
1393 if (clientID != rdpdr->clientID)
1394 rdpdr->clientID = clientID;
1396 return CHANNEL_RC_OK;
1399struct device_announce_arg
1407static BOOL device_announce(ULONG_PTR key,
void* element,
void* data)
1409 struct device_announce_arg* arg = data;
1411 DEVICE* device = (DEVICE*)element;
1416 WINPR_ASSERT(device);
1417 WINPR_ASSERT(arg->rdpdr);
1418 WINPR_ASSERT(arg->s);
1429 if ((rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) ||
1430 (device->type == RDPDR_DTYP_SMARTCARD) || arg->userLoggedOn)
1432 size_t data_len = (device->data ==
nullptr ? 0 : Stream_GetPosition(device->data));
1434 if (!Stream_EnsureRemainingCapacity(arg->s, 20 + data_len))
1436 Stream_Release(arg->s);
1437 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
1441 Stream_Write_UINT32(arg->s, device->type);
1442 Stream_Write_UINT32(arg->s, device->id);
1443 strncpy(Stream_Pointer(arg->s), device->name, 8);
1445 for (
size_t i = 0; i < 8; i++)
1448 Stream_Peek_UINT8(arg->s, c);
1451 Stream_Write_UINT8(arg->s,
'_');
1453 Stream_Seek_UINT8(arg->s);
1456 WINPR_ASSERT(data_len <= UINT32_MAX);
1457 Stream_Write_UINT32(arg->s, (UINT32)data_len);
1460 Stream_Write(arg->s, Stream_Buffer(device->data), data_len);
1463 WLog_Print(rdpdr->log, WLOG_INFO,
1464 "registered [%9s] device #%" PRIu32
": %5s (type=%2" PRIu32
" id=%2" PRIu32
")",
1465 rdpdr_device_type_string(device->type), arg->count, device->name, device->type,
1471static UINT rdpdr_send_device_list_announce_request(
rdpdrPlugin* rdpdr, BOOL userLoggedOn)
1475 size_t count_pos = 0;
1476 struct device_announce_arg arg = WINPR_C_ARRAY_INIT;
1478 WINPR_ASSERT(rdpdr);
1479 WINPR_ASSERT(rdpdr->devman);
1483 rdpdr->userLoggedOn = TRUE;
1486 s = StreamPool_Take(rdpdr->pool, 256);
1490 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1491 return CHANNEL_RC_NO_MEMORY;
1494 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
1495 Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE);
1496 count_pos = Stream_GetPosition(s);
1497 Stream_Seek_UINT32(s);
1500 arg.userLoggedOn = userLoggedOn || rdpdr->userLoggedOn;
1502 if (!device_foreach(rdpdr, TRUE, device_announce, &arg))
1503 return ERROR_INVALID_DATA;
1508 return CHANNEL_RC_OK;
1510 pos = Stream_GetPosition(s);
1511 if (!Stream_SetPosition(s, count_pos))
1514 return ERROR_INVALID_DATA;
1516 Stream_Write_UINT32(s, arg.count);
1517 if (!Stream_SetPosition(s, pos))
1520 return ERROR_INVALID_DATA;
1522 Stream_SealLength(s);
1523 return rdpdr_send(rdpdr, s);
1526UINT rdpdr_try_send_device_list_announce_request(
rdpdrPlugin* rdpdr)
1528 WINPR_ASSERT(rdpdr);
1529 if (rdpdr->state != RDPDR_CHANNEL_STATE_READY)
1531 WLog_Print(rdpdr->log, WLOG_DEBUG,
1532 "hotplug event received, but channel [RDPDR] is not ready (state %s), ignoring.",
1533 rdpdr_state_str(rdpdr->state));
1534 return CHANNEL_RC_OK;
1536 return rdpdr_send_device_list_announce_request(rdpdr, rdpdr->userLoggedOn);
1541 WINPR_ASSERT(rdpdr);
1544 wStream* output = StreamPool_Take(rdpdr->pool, 256);
1547 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
1548 return CHANNEL_RC_NO_MEMORY;
1551 if (!Stream_SetPosition(s, 4))
1553 Stream_Release(output);
1554 return ERROR_INVALID_DATA;
1557 const uint32_t DeviceId = Stream_Get_UINT32(s);
1558 const uint32_t FileId = Stream_Get_UINT32(s);
1559 const uint32_t CompletionId = Stream_Get_UINT32(s);
1561 WLog_Print(rdpdr->log, WLOG_WARN,
1562 "Dummy response {DeviceId=%" PRIu32
", FileId=%" PRIu32
", CompletionId=%" PRIu32
1564 DeviceId, FileId, CompletionId);
1565 if (!rdpdr_write_iocompletion_header(output, DeviceId, CompletionId, STATUS_UNSUCCESSFUL))
1566 return CHANNEL_RC_NO_MEMORY;
1568 return rdpdr_send(rdpdr, output);
1578 UINT error = CHANNEL_RC_OK;
1580 WINPR_ASSERT(rdpdr);
1583 IRP* irp = irp_new(rdpdr->devman, rdpdr->pool, s, rdpdr->log, &error);
1587 if ((error == CHANNEL_RC_OK) ||
1588 (error == ERROR_DEV_NOT_EXIST && rdpdr->ignoreInvalidDevices))
1590 return dummy_irp_response(rdpdr, s);
1593 WLog_Print(rdpdr->log, WLOG_ERROR,
"irp_new failed with %" PRIu32
"!", error);
1597 if (irp->device->IRPRequest)
1598 error = irp->device->IRPRequest(irp->device, irp);
1600 error = irp->Discard(irp);
1602 if (error != CHANNEL_RC_OK)
1604 WLog_Print(rdpdr->log, WLOG_ERROR,
"device->IRPRequest failed with error %" PRIu32
"",
1611static UINT rdpdr_process_component(
rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
1615 DEVICE* device =
nullptr;
1617 WINPR_ASSERT(rdpdr);
1622 case RDPDR_CTYP_PRN:
1623 type = RDPDR_DTYP_PRINT;
1627 return ERROR_INVALID_DATA;
1630 device = devman_get_device_by_type(rdpdr->devman, type);
1633 return ERROR_DEV_NOT_EXIST;
1635 return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
1644static BOOL device_init(ULONG_PTR key,
void* element,
void* data)
1647 UINT error = CHANNEL_RC_OK;
1648 DEVICE* device = element;
1653 IFCALLRET(device->Init, error, device);
1655 if (error != CHANNEL_RC_OK)
1657 WLog_Print(log, WLOG_ERROR,
"Device init failed with %s", WTSErrorToString(error));
1665 WINPR_ASSERT(rdpdr);
1666 WINPR_ASSERT(rdpdr->devman);
1668 rdpdr->userLoggedOn = FALSE;
1675 rdpdr->clearing = TRUE;
1676 BOOL rc = device_foreach(rdpdr, TRUE, device_init, rdpdr->log);
1677 rdpdr->clearing = FALSE;
1679 return ERROR_INTERNAL_ERROR;
1680 return CHANNEL_RC_OK;
1683static BOOL state_match(
enum RDPDR_CHANNEL_STATE state,
size_t count, va_list ap)
1685 for (
size_t x = 0; x < count; x++)
1687 enum RDPDR_CHANNEL_STATE cur = va_arg(ap,
enum RDPDR_CHANNEL_STATE);
1694static const char* state_str(
size_t count, va_list ap,
char* buffer,
size_t size)
1696 for (
size_t x = 0; x < count; x++)
1698 enum RDPDR_CHANNEL_STATE cur = va_arg(ap,
enum RDPDR_CHANNEL_STATE);
1699 const char* curstr = rdpdr_state_str(cur);
1700 winpr_str_append(curstr, buffer, size,
"|");
1705static BOOL rdpdr_state_check(
rdpdrPlugin* rdpdr, UINT16 packetid,
enum RDPDR_CHANNEL_STATE next,
1708 va_list ap = WINPR_C_ARRAY_INIT;
1709 WINPR_ASSERT(rdpdr);
1711 va_start(ap, count);
1712 BOOL rc = state_match(rdpdr->state, count, ap);
1717 const char* strstate = rdpdr_state_str(rdpdr->state);
1718 char buffer[256] = WINPR_C_ARRAY_INIT;
1720 va_start(ap, count);
1721 state_str(count, ap, buffer,
sizeof(buffer));
1724 WLog_Print(rdpdr->log, WLOG_ERROR,
1725 "channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.",
1726 rdpdr_packetid_string(packetid), buffer, strstate);
1728 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL))
1732 return rdpdr_state_advance(rdpdr, next);
1735static BOOL rdpdr_check_channel_state(
rdpdrPlugin* rdpdr, UINT16 packetid)
1737 WINPR_ASSERT(rdpdr);
1741 case PAKID_CORE_SERVER_ANNOUNCE:
1746 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL))
1748 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1,
1749 RDPDR_CHANNEL_STATE_INITIAL);
1750 case PAKID_CORE_SERVER_CAPABILITY:
1751 return rdpdr_state_check(
1752 rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6,
1753 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_SERVER_CAPS,
1754 RDPDR_CHANNEL_STATE_READY, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1755 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1756 case PAKID_CORE_CLIENTID_CONFIRM:
1757 return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 5,
1758 RDPDR_CHANNEL_STATE_NAME_REQUEST,
1759 RDPDR_CHANNEL_STATE_SERVER_CAPS,
1760 RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY,
1761 RDPDR_CHANNEL_STATE_USER_LOGGEDON);
1762 case PAKID_CORE_USER_LOGGEDON:
1763 if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU))
1766 return rdpdr_state_check(
1767 rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4,
1768 RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
1769 RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY);
1772 enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY;
1773 return rdpdr_state_check(rdpdr, packetid, state, 1, state);
1778static BOOL tryAdvance(
rdpdrPlugin* rdpdr, BOOL announce)
1780 if (rdpdr->haveClientId && rdpdr->haveServerCaps)
1784 const UINT error = rdpdr_send_device_list_announce_request(rdpdr, FALSE);
1787 WLog_Print(rdpdr->log, WLOG_ERROR,
1788 "rdpdr_send_device_list_announce_request failed with error %" PRIu32
"",
1793 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
1806 UINT16 component = 0;
1807 UINT16 packetId = 0;
1808 UINT32 deviceId = 0;
1810 UINT error = ERROR_INVALID_DATA;
1813 return CHANNEL_RC_NULL_DATA;
1815 rdpdr_dump_received_packet(rdpdr->log, WLOG_TRACE, s,
"[rdpdr-channel] receive");
1816 if (Stream_GetRemainingLength(s) >= 4)
1818 Stream_Read_UINT16(s, component);
1819 Stream_Read_UINT16(s, packetId);
1821 if (component == RDPDR_CTYP_CORE)
1823 if (!rdpdr_check_channel_state(rdpdr, packetId))
1824 return CHANNEL_RC_OK;
1828 case PAKID_CORE_SERVER_ANNOUNCE:
1829 rdpdr->haveClientId = FALSE;
1830 rdpdr->haveServerCaps = FALSE;
1831 if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
1834 else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
1836 WLog_Print(rdpdr->log, WLOG_ERROR,
1837 "rdpdr_send_client_announce_reply failed with error %" PRIu32
"",
1840 else if ((error = rdpdr_send_client_name_request(rdpdr)))
1842 WLog_Print(rdpdr->log, WLOG_ERROR,
1843 "rdpdr_send_client_name_request failed with error %" PRIu32
"",
1846 else if ((error = rdpdr_process_init(rdpdr)))
1848 WLog_Print(rdpdr->log, WLOG_ERROR,
1849 "rdpdr_process_init failed with error %" PRIu32
"", error);
1854 case PAKID_CORE_SERVER_CAPABILITY:
1855 if ((error = rdpdr_process_capability_request(rdpdr, s)))
1858 else if ((error = rdpdr_send_capability_response(rdpdr)))
1860 WLog_Print(rdpdr->log, WLOG_ERROR,
1861 "rdpdr_send_capability_response failed with error %" PRIu32
"",
1866 rdpdr->haveServerCaps = TRUE;
1867 if (!tryAdvance(rdpdr, TRUE))
1868 error = ERROR_INTERNAL_ERROR;
1873 case PAKID_CORE_CLIENTID_CONFIRM:
1874 if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
1879 rdpdr->haveClientId = TRUE;
1880 if (!tryAdvance(rdpdr, TRUE))
1881 error = ERROR_INTERNAL_ERROR;
1885 case PAKID_CORE_USER_LOGGEDON:
1886 if (!rdpdr->haveServerCaps)
1892 WLog_Print(rdpdr->log, WLOG_WARN,
1893 "%s in state %s, ignoring. [serverCaps=%d, clientId=%d]",
1894 rdpdr_packetid_string(packetId), rdpdr_state_str(rdpdr->state),
1895 rdpdr->haveServerCaps, rdpdr->haveClientId);
1896 error = CHANNEL_RC_OK;
1898 else if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
1901 rdpdr->log, WLOG_ERROR,
1902 "rdpdr_send_device_list_announce_request failed with error %" PRIu32
"",
1905 else if (!tryAdvance(rdpdr, FALSE))
1907 error = ERROR_INTERNAL_ERROR;
1912 case PAKID_CORE_DEVICE_REPLY:
1915 if (Stream_GetRemainingLength(s) >= 8)
1917 Stream_Read_UINT32(s, deviceId);
1918 Stream_Read_UINT32(s, status);
1921 devman_unregister_device(rdpdr->devman, (
void*)((
size_t)deviceId));
1922 error = CHANNEL_RC_OK;
1927 case PAKID_CORE_DEVICE_IOREQUEST:
1928 if ((error = rdpdr_process_irp(rdpdr, s)))
1930 WLog_Print(rdpdr->log, WLOG_ERROR,
1931 "rdpdr_process_irp failed with error %" PRIu32
"", error);
1940 WLog_Print(rdpdr->log, WLOG_ERROR,
1941 "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16
"", packetId);
1942 error = ERROR_INVALID_DATA;
1948 error = rdpdr_process_component(rdpdr, component, packetId, s);
1950 if (error != CHANNEL_RC_OK)
1952 DWORD level = WLOG_ERROR;
1953 if (rdpdr->ignoreInvalidDevices)
1955 if (error == ERROR_DEV_NOT_EXIST)
1958 error = CHANNEL_RC_OK;
1961 WLog_Print(rdpdr->log, level,
1962 "Unknown message: Component: %s [0x%04" PRIX16
1963 "] PacketId: %s [0x%04" PRIX16
"]",
1964 rdpdr_component_string(component), component,
1965 rdpdr_packetid_string(packetId), packetId);
1982 if (rdpdr->clearing)
1984 WLog_ERR(TAG,
"trying to send message while reinitializing channel, aborting");
1985 return ERROR_INTERNAL_ERROR;
1990 return CHANNEL_RC_NULL_DATA;
1996 return CHANNEL_RC_BAD_INIT_HANDLE;
1999 const size_t pos = Stream_GetPosition(s);
2000 UINT status = ERROR_INTERNAL_ERROR;
2001 if (pos <= UINT32_MAX)
2003 rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s,
"[rdpdr-channel] send");
2004 status = plugin->channelEntryPoints.pVirtualChannelWriteEx(
2005 plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)pos, s);
2008 if (status != CHANNEL_RC_OK)
2011 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
2012 WTSErrorToString(status), status);
2023static UINT rdpdr_virtual_channel_event_data_received(
rdpdrPlugin* rdpdr,
void* pData,
2024 UINT32 dataLength, UINT32 totalLength,
2027 WINPR_ASSERT(rdpdr);
2028 WINPR_ASSERT(pData || (dataLength == 0));
2030 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
2038 return CHANNEL_RC_OK;
2041 if (dataFlags & CHANNEL_FLAG_FIRST)
2043 if (rdpdr->data_in !=
nullptr)
2044 Stream_Release(rdpdr->data_in);
2046 rdpdr->data_in = StreamPool_Take(rdpdr->pool, totalLength);
2048 if (!rdpdr->data_in)
2050 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_New failed!");
2051 return CHANNEL_RC_NO_MEMORY;
2055 if (!rdpdr->data_in)
2057 WLog_Print(rdpdr->log, WLOG_ERROR,
2058 "Invalid state, no CHANNEL_FLAG_FIRST received, aborting.");
2059 return ERROR_INVALID_DATA;
2062 wStream* data_in = rdpdr->data_in;
2063 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
2065 WLog_Print(rdpdr->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
2066 return ERROR_INVALID_DATA;
2069 Stream_Write(data_in, pData, dataLength);
2071 if (dataFlags & CHANNEL_FLAG_LAST)
2073 const size_t pos = Stream_GetPosition(data_in);
2074 const size_t cap = Stream_Capacity(data_in);
2077 WLog_Print(rdpdr->log, WLOG_ERROR,
2078 "rdpdr_virtual_channel_event_data_received: read error");
2079 return ERROR_INTERNAL_ERROR;
2082 Stream_SealLength(data_in);
2083 Stream_ResetPosition(data_in);
2087 if (!MessageQueue_Post(rdpdr->queue,
nullptr, 0, (
void*)data_in,
nullptr))
2089 WLog_Print(rdpdr->log, WLOG_ERROR,
"MessageQueue_Post failed!");
2090 return ERROR_INTERNAL_ERROR;
2092 rdpdr->data_in =
nullptr;
2096 UINT error = rdpdr_process_receive(rdpdr, data_in);
2097 Stream_Release(data_in);
2098 rdpdr->data_in =
nullptr;
2104 return CHANNEL_RC_OK;
2107static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
2108 UINT event, LPVOID pData,
2109 UINT32 dataLength, UINT32 totalLength,
2112 UINT error = CHANNEL_RC_OK;
2115 WINPR_ASSERT(rdpdr);
2118 case CHANNEL_EVENT_DATA_RECEIVED:
2119 if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle))
2121 WLog_Print(rdpdr->log, WLOG_ERROR,
"error no match");
2124 if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength,
2125 totalLength, dataFlags)))
2126 WLog_Print(rdpdr->log, WLOG_ERROR,
2127 "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32
2133 case CHANNEL_EVENT_WRITE_CANCELLED:
2134 case CHANNEL_EVENT_WRITE_COMPLETE:
2141 case CHANNEL_EVENT_USER:
2147 if (error && rdpdr && rdpdr->rdpcontext)
2148 setChannelError(rdpdr->rdpcontext, error,
2149 "rdpdr_virtual_channel_open_event_ex reported an error");
2152static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
2159 ExitThread((DWORD)CHANNEL_RC_NULL_DATA);
2160 return CHANNEL_RC_NULL_DATA;
2163 if ((error = rdpdr_process_connect(rdpdr)))
2165 WLog_Print(rdpdr->log, WLOG_ERROR,
"rdpdr_process_connect failed with error %" PRIu32
"!",
2168 if (rdpdr->rdpcontext)
2169 setChannelError(rdpdr->rdpcontext, error,
2170 "rdpdr_virtual_channel_client_thread reported an error");
2178 wMessage message = WINPR_C_ARRAY_INIT;
2179 WINPR_ASSERT(rdpdr);
2181 if (!MessageQueue_Wait(rdpdr->queue))
2184 if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
2186 if (message.id == WMQ_QUIT)
2189 if (message.id == 0)
2193 error = rdpdr_process_receive(rdpdr, data);
2195 Stream_Release(data);
2198 WLog_Print(rdpdr->log, WLOG_ERROR,
2199 "rdpdr_process_receive failed with error %" PRIu32
"!", error);
2201 if (rdpdr->rdpcontext)
2202 setChannelError(rdpdr->rdpcontext, error,
2203 "rdpdr_virtual_channel_client_thread reported an error");
2212 if ((error = drive_hotplug_thread_terminate(rdpdr)))
2213 WLog_Print(rdpdr->log, WLOG_ERROR,
2214 "drive_hotplug_thread_terminate failed with error %" PRIu32
"!", error);
2220static void queue_free(
void* obj)
2223 wMessage* msg = (wMessage*)obj;
2225 if (!msg || (msg->id != 0))
2238static UINT rdpdr_virtual_channel_event_connected(
rdpdrPlugin* rdpdr, LPVOID pData,
2243 WINPR_ASSERT(rdpdr);
2244 WINPR_UNUSED(pData);
2245 WINPR_UNUSED(dataLength);
2249 rdpdr->queue = MessageQueue_New(
nullptr);
2253 WLog_Print(rdpdr->log, WLOG_ERROR,
"MessageQueue_New failed!");
2254 return CHANNEL_RC_NO_MEMORY;
2257 obj = MessageQueue_Object(rdpdr->queue);
2260 if (!(rdpdr->thread = CreateThread(
nullptr, 0, rdpdr_virtual_channel_client_thread,
2261 (
void*)rdpdr, 0,
nullptr)))
2263 WLog_Print(rdpdr->log, WLOG_ERROR,
"CreateThread failed!");
2264 return ERROR_INTERNAL_ERROR;
2269 UINT error = rdpdr_process_connect(rdpdr);
2272 WLog_Print(rdpdr->log, WLOG_ERROR,
2273 "rdpdr_process_connect failed with error %" PRIu32
"!", error);
2278 return rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, &rdpdr->OpenHandle,
2279 rdpdr->channelDef.name,
2280 rdpdr_virtual_channel_open_event_ex);
2288static UINT rdpdr_virtual_channel_event_disconnected(
rdpdrPlugin* rdpdr)
2292 WINPR_ASSERT(rdpdr);
2294 if (rdpdr->OpenHandle == 0)
2295 return CHANNEL_RC_OK;
2297 if (rdpdr->queue && rdpdr->thread)
2299 if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
2300 (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
2302 error = GetLastError();
2303 WLog_Print(rdpdr->log, WLOG_ERROR,
"WaitForSingleObject failed with error %" PRIu32
"!",
2310 (void)CloseHandle(rdpdr->thread);
2311 MessageQueue_Free(rdpdr->queue);
2312 rdpdr->queue =
nullptr;
2313 rdpdr->thread =
nullptr;
2315 WINPR_ASSERT(rdpdr->channelEntryPoints.pVirtualChannelCloseEx);
2316 error = rdpdr->channelEntryPoints.pVirtualChannelCloseEx(rdpdr->InitHandle, rdpdr->OpenHandle);
2318 if (CHANNEL_RC_OK != error)
2320 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelCloseEx failed with %s [%08" PRIX32
"]",
2321 WTSErrorToString(error), error);
2324 rdpdr->OpenHandle = 0;
2328 Stream_Release(rdpdr->data_in);
2329 rdpdr->data_in =
nullptr;
2334 devman_free(rdpdr->devman);
2335 rdpdr->devman =
nullptr;
2341static void rdpdr_virtual_channel_event_terminated(
rdpdrPlugin* rdpdr)
2343 WINPR_ASSERT(rdpdr);
2345 if (rdpdr->stopEvent)
2347 (void)CloseHandle(rdpdr->stopEvent);
2348 rdpdr->stopEvent =
nullptr;
2351 rdpdr->InitHandle =
nullptr;
2352 StreamPool_Free(rdpdr->pool);
2356static UINT rdpdr_register_device(RdpdrClientContext* context,
const RDPDR_DEVICE* device,
2359 WINPR_ASSERT(context);
2360 WINPR_ASSERT(device);
2364 WINPR_ASSERT(rdpdr);
2368 return ERROR_INVALID_DATA;
2369 UINT rc = devman_load_device_service(rdpdr->devman, copy, rdpdr->rdpcontext);
2371 freerdp_device_free(copy);
2372 if (rc == CHANNEL_RC_OK)
2373 rc = rdpdr_try_send_device_list_announce_request(rdpdr);
2377static UINT rdpdr_unregister_device(RdpdrClientContext* context,
size_t count,
const uint32_t ids[])
2379 WINPR_ASSERT(context);
2382 WINPR_ASSERT(rdpdr);
2384 for (
size_t x = 0; x < count; x++)
2386 const uintptr_t
id = ids[x];
2387 devman_unregister_device(rdpdr->devman, (
void*)
id);
2389 return rdpdr_send_device_list_remove_request(rdpdr, WINPR_ASSERTING_INT_CAST(uint32_t, count),
2393static UINT rdpdr_virtual_channel_event_initialized(
rdpdrPlugin* rdpdr,
2394 WINPR_ATTR_UNUSED LPVOID pData,
2395 WINPR_ATTR_UNUSED UINT32 dataLength)
2397 WINPR_ASSERT(rdpdr);
2399 WINPR_ASSERT(!rdpdr->stopEvent);
2400 rdpdr->stopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
2401 if (!rdpdr->stopEvent)
2402 return ERROR_INTERNAL_ERROR;
2405 rdpdr->context.handle = rdpdr;
2406 rdpdr->context.RdpdrHotplugDevice = handle_hotplug;
2407 rdpdr->context.RdpdrRegisterDevice = rdpdr_register_device;
2408 rdpdr->context.RdpdrUnregisterDevice = rdpdr_unregister_device;
2409 return CHANNEL_RC_OK;
2412static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
2413 UINT event, LPVOID pData, UINT dataLength)
2415 UINT error = CHANNEL_RC_OK;
2418 if (!rdpdr || (rdpdr->InitHandle != pInitHandle))
2420 WLog_ERR(TAG,
"error no match");
2424 WINPR_ASSERT(pData || (dataLength == 0));
2428 case CHANNEL_EVENT_INITIALIZED:
2429 error = rdpdr_virtual_channel_event_initialized(rdpdr, pData, dataLength);
2432 case CHANNEL_EVENT_CONNECTED:
2433 if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength)))
2434 WLog_Print(rdpdr->log, WLOG_ERROR,
2435 "rdpdr_virtual_channel_event_connected failed with error %" PRIu32
"!",
2440 case CHANNEL_EVENT_DISCONNECTED:
2441 if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr)))
2442 WLog_Print(rdpdr->log, WLOG_ERROR,
2443 "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32
2449 case CHANNEL_EVENT_TERMINATED:
2450 rdpdr_virtual_channel_event_terminated(rdpdr);
2454 case CHANNEL_EVENT_ATTACHED:
2455 case CHANNEL_EVENT_DETACHED:
2457 WLog_Print(rdpdr->log, WLOG_ERROR,
"unknown event %" PRIu32
"!", event);
2461 if (error && rdpdr && rdpdr->rdpcontext)
2462 setChannelError(rdpdr->rdpcontext, error,
2463 "rdpdr_virtual_channel_init_event_ex reported an error");
2467#define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx
2469FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
2472 WINPR_ASSERT(pEntryPoints);
2473 WINPR_ASSERT(pInitHandle);
2479 WLog_ERR(TAG,
"calloc failed!");
2482 rdpdr->log = WLog_Get(TAG);
2484 rdpdr->clientExtendedPDU =
2485 RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU;
2486 rdpdr->clientIOCode1 =
2487 RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
2488 RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
2489 RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
2490 RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
2491 RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL |
2492 RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY;
2494 rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO;
2496 rdpdr->pool = StreamPool_New(TRUE, 1024);
2503 rdpdr->channelDef.options =
2504 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
2505 (void)sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name),
2506 RDPDR_SVC_CHANNEL_NAME);
2507 rdpdr->sequenceId = 0;
2512 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
2514 rdpdr->rdpcontext = pEntryPointsEx->context;
2516 FreeRDP_SynchronousStaticChannels))
2517 rdpdr->async = TRUE;
2521 rdpdr->InitHandle = pInitHandle;
2522 const UINT rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx(
2523 rdpdr, &rdpdr->context, pInitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
2524 rdpdr_virtual_channel_init_event_ex);
2526 if (CHANNEL_RC_OK != rc)
2528 WLog_Print(rdpdr->log, WLOG_ERROR,
"pVirtualChannelInitEx failed with %s [%08" PRIX32
"]",
2529 WTSErrorToString(rc), rc);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree