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* 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:
 
  128static const char* support_str(BOOL val)
 
  135static 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";
 
  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));
 
  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));
 
  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);
 
  207static 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  WINPR_ASSERT(
rdpdr->context.RdpdrRegisterDevice);
 
  222  rc = 
rdpdr->context.RdpdrRegisterDevice(&
rdpdr->context, drive.device, &drive.device->Id);
 
  223  if (rc != CHANNEL_RC_OK)
 
  227  freerdp_device_free(drive.device);
 
  228  return rc == CHANNEL_RC_OK;
 
  236static UINT rdpdr_send_device_list_remove_request(
rdpdrPlugin* 
rdpdr, UINT32 count,
 
  242  WINPR_ASSERT(ids || (count == 0));
 
  245    return CHANNEL_RC_OK;
 
  247  if (!rdpdr_check_extended_pdu_flag(
rdpdr, RDPDR_DEVICE_REMOVE_PDUS))
 
  248    return CHANNEL_RC_OK;
 
  250  s = StreamPool_Take(
rdpdr->pool, count * 
sizeof(UINT32) + 8);
 
  254    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
  255    return CHANNEL_RC_NO_MEMORY;
 
  258  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
 
  259  Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
 
  260  Stream_Write_UINT32(s, count);
 
  262  for (UINT32 i = 0; i < count; i++)
 
  263    Stream_Write_UINT32(s, ids[i]);
 
  265  Stream_SealLength(s);
 
  266  return rdpdr_send(
rdpdr, s);
 
  269#if defined(_UWP) || defined(__IOS__) 
  271static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
 
  272                           WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
 
  274  return ERROR_CALL_NOT_IMPLEMENTED;
 
  281static DWORD WINAPI drive_hotplug_thread_func(WINPR_ATTR_UNUSED LPVOID arg)
 
  283  return CHANNEL_RC_OK;
 
  286static UINT drive_hotplug_thread_terminate(WINPR_ATTR_UNUSED 
rdpdrPlugin* 
rdpdr)
 
  288  return CHANNEL_RC_OK;
 
  293static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
 
  294                           WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
 
  296  return CHANNEL_RC_OK;
 
  299static BOOL check_path(
const char* path)
 
  301  UINT type = GetDriveTypeA(path);
 
  303  if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
 
  304        type == DRIVE_REMOTE))
 
  307  return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
 
  312  DWORD unitmask = GetLogicalDrives();
 
  314  for (
size_t i = 0; i < 26; i++)
 
  318      char drive_path[] = { 
'c', 
':', 
'\\', 
'\0' };
 
  319      char drive_name[] = { 
'c', 
'\0' };
 
  320      drive_path[0] = 
'A' + (char)i;
 
  321      drive_name[0] = 
'A' + (char)i;
 
  323      if (check_path(drive_path))
 
  325        rdpdr_load_drive(
rdpdr, drive_name, drive_path, TRUE);
 
  329    unitmask = unitmask >> 1;
 
  333static LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 
  336  PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
 
  342    case WM_DEVICECHANGE:
 
  345        case DBT_DEVICEARRIVAL:
 
  346          if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
 
  348            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
 
  349            DWORD unitmask = lpdbv->dbcv_unitmask;
 
  351            for (
int i = 0; i < 26; i++)
 
  355                char drive_path[] = { 
'c', 
':', 
'/', 
'\0' };
 
  356                char drive_name[] = { 
'c', 
'\0' };
 
  357                drive_path[0] = 
'A' + (char)i;
 
  358                drive_name[0] = 
'A' + (char)i;
 
  360                if (check_path(drive_path))
 
  362                  rdpdr_load_drive(
rdpdr, drive_name, drive_path, TRUE);
 
  366              unitmask = unitmask >> 1;
 
  372        case DBT_DEVICEREMOVECOMPLETE:
 
  373          if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
 
  375            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
 
  376            DWORD unitmask = lpdbv->dbcv_unitmask;
 
  377            char drive_name_upper, drive_name_lower;
 
  378            ULONG_PTR* keys = NULL;
 
  379            DEVICE_DRIVE_EXT* device_ext;
 
  381            for (
int i = 0; i < 26; i++)
 
  385                drive_name_upper = 
'A' + i;
 
  386                drive_name_lower = 
'a' + i;
 
  388                    ListDictionary_GetKeys(
rdpdr->devman->devices, &keys);
 
  390                for (
size_t j = 0; j < count; j++)
 
  392                  device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
 
  393                      rdpdr->devman->devices, (
void*)keys[j]);
 
  395                  if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
 
  398                  if (device_ext->path[0] == drive_name_upper ||
 
  399                      device_ext->path[0] == drive_name_lower)
 
  401                    if (device_ext->automount)
 
  403                      const uint32_t ids[] = { keys[j] };
 
  404                      WINPR_ASSERT(
rdpdr->context.RdpdrUnregisterDevice);
 
  405                      error = 
rdpdr->context.RdpdrUnregisterDevice(
 
  406                          &
rdpdr->context, ARRAYSIZE(ids), ids);
 
  411                            rdpdr->log, WLOG_ERROR,
 
  412                            "rdpdr_send_device_list_remove_request failed " 
  413                            "with error %" PRIu32 
"!",
 
  425              unitmask = unitmask >> 1;
 
  438      return DefWindowProc(hWnd, Msg, wParam, lParam);
 
  441  return DefWindowProc(hWnd, Msg, wParam, lParam);
 
  444static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
 
  451  DEV_BROADCAST_HANDLE NotificationFilter;
 
  452  HDEVNOTIFY hDevNotify;
 
  455  wnd_cls.cbSize = 
sizeof(WNDCLASSEX);
 
  456  wnd_cls.style = CS_HREDRAW | CS_VREDRAW;
 
  457  wnd_cls.lpfnWndProc = hotplug_proc;
 
  458  wnd_cls.cbClsExtra = 0;
 
  459  wnd_cls.cbWndExtra = 0;
 
  460  wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 
  461  wnd_cls.hCursor = NULL;
 
  462  wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 
  463  wnd_cls.lpszMenuName = NULL;
 
  464  wnd_cls.lpszClassName = L
"DRIVE_HOTPLUG";
 
  465  wnd_cls.hInstance = NULL;
 
  466  wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
  467  RegisterClassEx(&wnd_cls);
 
  469  hwnd = CreateWindowEx(0, L
"DRIVE_HOTPLUG", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
 
  470  SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)
rdpdr);
 
  471  rdpdr->hotplug_wnd = hwnd;
 
  473  NotificationFilter.dbch_size = 
sizeof(DEV_BROADCAST_HANDLE);
 
  474  NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
 
  475  hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
 
  478  while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
 
  486      TranslateMessage(&msg);
 
  487      DispatchMessage(&msg);
 
  491  UnregisterDeviceNotification(hDevNotify);
 
  492  return CHANNEL_RC_OK;
 
  502  UINT error = CHANNEL_RC_OK;
 
  504  if (
rdpdr->hotplug_wnd && !PostMessage(
rdpdr->hotplug_wnd, WM_QUIT, 0, 0))
 
  506    error = GetLastError();
 
  507    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"PostMessage failed with error %" PRIu32 
"", error);
 
  513#elif defined(__MACOSX__) 
  515#define MAX_USB_DEVICES 100 
  528static UINT handle_hotplug(WINPR_ATTR_UNUSED RdpdrClientContext* context,
 
  529                           WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
 
  531  WINPR_ASSERT(context);
 
  534  struct dirent* pDirent = NULL;
 
  535  char fullpath[PATH_MAX] = { 0 };
 
  536  char* szdir = (
char*)
"/Volumes";
 
  537  struct stat buf = { 0 };
 
  538  hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
 
  540  DEVICE_DRIVE_EXT* device_ext = NULL;
 
  541  ULONG_PTR* keys = NULL;
 
  543  UINT error = ERROR_INTERNAL_ERROR;
 
  546  DIR* pDir = opendir(szdir);
 
  550    printf(
"Cannot open directory\n");
 
  551    return ERROR_OPEN_FAILED;
 
  554  while ((pDirent = readdir(pDir)) != NULL)
 
  556    if (pDirent->d_name[0] != 
'.')
 
  558      (void)sprintf_s(fullpath, ARRAYSIZE(fullpath), 
"%s/%s", szdir, pDirent->d_name);
 
  559      if (stat(fullpath, &buf) != 0)
 
  562      if (S_ISDIR(buf.st_mode))
 
  564        dev_array[size].path = _strdup(fullpath);
 
  566        if (!dev_array[size].path)
 
  569          error = CHANNEL_RC_NO_MEMORY;
 
  573        dev_array[size++].to_add = TRUE;
 
  580  count = ListDictionary_GetKeys(
rdpdr->devman->devices, &keys);
 
  582  for (
size_t j = 0; j < count; j++)
 
  585    BOOL dev_found = FALSE;
 
  587        (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
rdpdr->devman->devices, (
void*)keys[j]);
 
  589    if (!device_ext || !device_ext->automount)
 
  592    if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM)
 
  595    if (device_ext->path == NULL)
 
  598    path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
 
  603    if (strstr(path, 
"/Volumes/") == NULL)
 
  609    for (
size_t i = 0; i < size; i++)
 
  611      if (strstr(path, dev_array[i].path) != NULL)
 
  614        dev_array[i].to_add = FALSE;
 
  623      const uint32_t ids[] = { keys[j] };
 
  624      WINPR_ASSERT(
rdpdr->context.RdpdrUnregisterDevice);
 
  625      error = 
rdpdr->context.RdpdrUnregisterDevice(&
rdpdr->context, ARRAYSIZE(ids), ids);
 
  628        WLog_Print(
rdpdr->log, WLOG_ERROR,
 
  629                   "rdpdr_send_device_list_remove_request failed with error %" PRIu32 
"!",
 
  637  for (
size_t i = 0; i < size; i++)
 
  639    const hotplug_dev* dev = &dev_array[i];
 
  642      const char* path = dev->path;
 
  643      const char* name = strrchr(path, 
'/') + 1;
 
  644      error = rdpdr_load_drive(
rdpdr, name, path, TRUE);
 
  653  for (
size_t i = 0; i < size; i++)
 
  654    free(dev_array[i].path);
 
  659static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef,
 
  660                                           void* clientCallBackInfo, 
size_t numEvents,
 
  662                                           const FSEventStreamEventFlags eventFlags[],
 
  663                                           const FSEventStreamEventId eventIds[])
 
  667  char** paths = (
char**)eventPaths;
 
  670  for (
size_t i = 0; i < numEvents; i++)
 
  672    if (strcmp(paths[i], 
"/Volumes/") == 0)
 
  674      UINT error = ERROR_CALL_NOT_IMPLEMENTED;
 
  675      if (
rdpdr->context.RdpdrHotplugDevice)
 
  676        error = 
rdpdr->context.RdpdrHotplugDevice(&
rdpdr->context,
 
  677                                                  RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
 
  680        case ERROR_DISK_CHANGE:
 
  683        case ERROR_CALL_NOT_IMPLEMENTED:
 
  686          WLog_Print(
rdpdr->log, WLOG_ERROR,
 
  687                     "handle_hotplug failed with error %" PRIu32 
"!", error);
 
  697  UINT error = ERROR_CALL_NOT_IMPLEMENTED;
 
  698  if (
rdpdr->context.RdpdrHotplugDevice)
 
  699    error = 
rdpdr->context.RdpdrHotplugDevice(&
rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
 
  703    case ERROR_DISK_CHANGE:
 
  705    case ERROR_CALL_NOT_IMPLEMENTED:
 
  708      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"handle_hotplug failed with error %" PRIu32 
"!",
 
  714static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
 
  718  WINPR_ASSERT(
rdpdr->stopEvent);
 
  720  CFStringRef path = CFSTR(
"/Volumes/");
 
  721  CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (
const void**)&path, 1, NULL);
 
  722  FSEventStreamContext ctx = {
 
  723    .copyDescription = NULL, .info = arg, .release = NULL, .retain = NULL, .version = 0
 
  725  FSEventStreamRef fsev =
 
  726      FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch,
 
  727                          kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
 
  729  dispatch_queue_t queue = dispatch_queue_create(TAG, NULL);
 
  730  FSEventStreamSetDispatchQueue(fsev, queue);
 
  731  FSEventStreamStart(fsev);
 
  732  WLog_Print(
rdpdr->log, WLOG_DEBUG, 
"Started hotplug watcher");
 
  733  HANDLE handles[] = { 
rdpdr->stopEvent, freerdp_abort_event(
rdpdr->rdpcontext) };
 
  734  WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
 
  735  WLog_Print(
rdpdr->log, WLOG_DEBUG, 
"Stopped hotplug watcher");
 
  736  FSEventStreamStop(fsev);
 
  737  FSEventStreamRelease(fsev);
 
  738  dispatch_release(queue);
 
  740  ExitThread(CHANNEL_RC_OK);
 
  741  return CHANNEL_RC_OK;
 
  746static const char* automountLocations[] = { 
"/run/user/%lu/gvfs", 
"/run/media/%s", 
"/media/%s",
 
  749static BOOL isAutomountLocation(
const char* path)
 
  751  const size_t nrLocations = 
sizeof(automountLocations) / 
sizeof(automountLocations[0]);
 
  752  char buffer[MAX_PATH] = { 0 };
 
  753  uid_t uid = getuid();
 
  754  char uname[MAX_PATH] = { 0 };
 
  755  ULONG size = 
sizeof(uname) - 1;
 
  757  if (!GetUserNameExA(NameSamCompatible, uname, &size))
 
  763  for (
size_t x = 0; x < nrLocations; x++)
 
  765    const char* location = automountLocations[x];
 
  768    WINPR_PRAGMA_DIAG_PUSH
 
  769    WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
 
  770    if (strstr(location, 
"%lu"))
 
  771      (
void)snprintf(buffer, 
sizeof(buffer), location, (
unsigned long)uid);
 
  772    else if (strstr(location, 
"%s"))
 
  773      (void)snprintf(buffer, 
sizeof(buffer), location, uname);
 
  775      (
void)snprintf(buffer, 
sizeof(buffer), 
"%s", location);
 
  776    WINPR_PRAGMA_DIAG_POP
 
  778    length = strnlen(buffer, 
sizeof(buffer));
 
  780    if (strncmp(buffer, path, length) == 0)
 
  782      const char* rest = &path[length];
 
  788      else if (*rest == 
'/')
 
  790        const char* token = strstr(&rest[1], 
"/");
 
  792        if (!token || (token[1] == 
'\0'))
 
  801#define MAX_USB_DEVICES 100 
  809static void handle_mountpoint(hotplug_dev* dev_array, 
size_t* size, 
const char* mountpoint)
 
  814  if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
 
  816    dev_array[*size].path = _strdup(mountpoint);
 
  817    dev_array[*size].to_add = TRUE;
 
  823#include <sys/mnttab.h> 
  824static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array, 
size_t* size)
 
  828  f = winpr_fopen(
"/etc/mnttab", 
"r");
 
  831    WLog_Print(log, WLOG_ERROR, 
"fopen failed!");
 
  832    return ERROR_OPEN_FAILED;
 
  834  while (getmntent(f, &ent) == 0)
 
  836    handle_mountpoint(dev_array, size, ent.mnt_mountp);
 
  839  return ERROR_SUCCESS;
 
  843#if defined(__FreeBSD__) || defined(__OpenBSD__) 
  844#include <sys/mount.h> 
  845static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array, 
size_t* size)
 
  848  struct statfs* mntbuf = NULL;
 
  850  mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
 
  854    WLog_Print(log, WLOG_ERROR, 
"getmntinfo failed!");
 
  855    return ERROR_OPEN_FAILED;
 
  857  for (
size_t idx = 0; idx < (size_t)mntsize; idx++)
 
  859    handle_mountpoint(dev_array, size, mntbuf[idx].f_mntonname);
 
  862  return ERROR_SUCCESS;
 
  866#if defined(__LINUX__) || defined(__linux__) 
  868static struct mntent* getmntent_x(FILE* f, 
struct mntent* buffer, 
char* pathbuffer,
 
  869                                  size_t pathbuffersize)
 
  871#if defined(FREERDP_HAVE_GETMNTENT_R) 
  872  WINPR_ASSERT(pathbuffersize <= INT32_MAX);
 
  873  return getmntent_r(f, buffer, pathbuffer, (
int)pathbuffersize);
 
  877  (void)pathbuffersize;
 
  882static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array, 
size_t* size)
 
  885  struct mntent mnt = { 0 };
 
  886  char pathbuffer[PATH_MAX] = { 0 };
 
  887  struct mntent* ent = NULL;
 
  888  f = winpr_fopen(
"/proc/mounts", 
"r");
 
  891    WLog_Print(log, WLOG_ERROR, 
"fopen failed!");
 
  892    return ERROR_OPEN_FAILED;
 
  894  while ((ent = getmntent_x(f, &mnt, pathbuffer, 
sizeof(pathbuffer))) != NULL)
 
  896    handle_mountpoint(dev_array, size, ent->mnt_dir);
 
  899  return ERROR_SUCCESS;
 
  903static UINT handle_platform_mounts(wLog* log, hotplug_dev* dev_array, 
size_t* size)
 
  906  return handle_platform_mounts_sun(log, dev_array, size);
 
  907#elif defined(__FreeBSD__) || defined(__OpenBSD__) 
  908  return handle_platform_mounts_bsd(log, dev_array, size);
 
  909#elif defined(__LINUX__) || defined(__linux__) 
  910  return handle_platform_mounts_linux(log, dev_array, size);
 
  912  return ERROR_CALL_NOT_IMPLEMENTED;
 
  915static BOOL device_not_plugged(ULONG_PTR key, 
void* element, 
void* data)
 
  917  const WCHAR* path = (
const WCHAR*)data;
 
  918  DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
 
  923  if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path)
 
  925  if (_wcscmp(device_ext->path, path) != 0)
 
  930static BOOL device_already_plugged(
rdpdrPlugin* 
rdpdr, 
const hotplug_dev* device)
 
  935  if (!
rdpdr || !device)
 
  940  WINPR_ASSERT(
rdpdr->devman);
 
  941  WINPR_ASSERT(device->path);
 
  943  path = ConvertUtf8ToWCharAlloc(device->path, NULL);
 
  947  rc = device_foreach(
rdpdr, TRUE, device_not_plugged, path);
 
  952struct hotplug_delete_arg
 
  954  hotplug_dev* dev_array;
 
  955  size_t dev_array_size;
 
  959static BOOL hotplug_delete_foreach(ULONG_PTR key, 
void* element, 
void* data)
 
  962  BOOL dev_found = FALSE;
 
  963  struct hotplug_delete_arg* arg = (
struct hotplug_delete_arg*)data;
 
  964  DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)element;
 
  967  WINPR_ASSERT(arg->rdpdr);
 
  968  WINPR_ASSERT(arg->dev_array || (arg->dev_array_size == 0));
 
  969  WINPR_ASSERT(key <= UINT32_MAX);
 
  971  if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || !device_ext->path ||
 
  972      !device_ext->automount)
 
  975  WINPR_ASSERT(device_ext->path);
 
  976  path = ConvertWCharToUtf8Alloc(device_ext->path, NULL);
 
  981  if (isAutomountLocation(path))
 
  983    for (
size_t i = 0; i < arg->dev_array_size; i++)
 
  985      hotplug_dev* cur = &arg->dev_array[i];
 
  986      if (cur->path && strstr(path, cur->path) != NULL)
 
  999    const UINT32 ids[1] = { (UINT32)key };
 
 1000    WINPR_ASSERT(arg->rdpdr->context.RdpdrUnregisterDevice);
 
 1002        arg->rdpdr->context.RdpdrUnregisterDevice(&arg->rdpdr->context, ARRAYSIZE(ids), ids);
 
 1006      WLog_Print(arg->rdpdr->log, WLOG_ERROR,
 
 1007                 "rdpdr_send_device_list_remove_request failed with error %" PRIu32 
"!",
 
 1016static UINT handle_hotplug(RdpdrClientContext* context,
 
 1017                           WINPR_ATTR_UNUSED RdpdrHotplugEventType type)
 
 1019  WINPR_ASSERT(context);
 
 1022  hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 };
 
 1024  UINT error = ERROR_SUCCESS;
 
 1025  struct hotplug_delete_arg arg = { dev_array, ARRAYSIZE(dev_array), 
rdpdr };
 
 1027  WINPR_ASSERT(
rdpdr);
 
 1028  WINPR_ASSERT(
rdpdr->devman);
 
 1030  error = handle_platform_mounts(
rdpdr->log, dev_array, &size);
 
 1033   device_foreach(
rdpdr, FALSE, hotplug_delete_foreach, &arg);
 
 1036  for (
size_t i = 0; i < size; i++)
 
 1038    hotplug_dev* cur = &dev_array[i];
 
 1039    if (!device_already_plugged(
rdpdr, cur))
 
 1041      const char* path = cur->path;
 
 1042      const char* name = strrchr(path, 
'/') + 1;
 
 1044      rdpdr_load_drive(
rdpdr, name, path, TRUE);
 
 1045      error = ERROR_DISK_CHANGE;
 
 1049  for (
size_t i = 0; i < size; i++)
 
 1050    free(dev_array[i].path);
 
 1057  UINT error = ERROR_CALL_NOT_IMPLEMENTED;
 
 1059  WINPR_ASSERT(
rdpdr);
 
 1060  if (
rdpdr->context.RdpdrHotplugDevice)
 
 1061    error = 
rdpdr->context.RdpdrHotplugDevice(&
rdpdr->context, RDPDR_HOTPLUG_FIRST_CHECK);
 
 1065    case ERROR_DISK_CHANGE:
 
 1067    case ERROR_OPEN_FAILED:
 
 1068    case ERROR_CALL_NOT_IMPLEMENTED:
 
 1071      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"handle_hotplug failed with error %" PRIu32 
"!",
 
 1077static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
 
 1081  WINPR_ASSERT(
rdpdr);
 
 1082  WINPR_ASSERT(
rdpdr->stopEvent);
 
 1084  while (WaitForSingleObject(
rdpdr->stopEvent, 1000) == WAIT_TIMEOUT)
 
 1086    UINT error = ERROR_CALL_NOT_IMPLEMENTED;
 
 1087    if (
rdpdr->context.RdpdrHotplugDevice)
 
 1089          rdpdr->context.RdpdrHotplugDevice(&
rdpdr->context, RDPDR_HOTPLUG_CHECK_FOR_CHANGES);
 
 1092      case ERROR_DISK_CHANGE:
 
 1095      case ERROR_OPEN_FAILED:
 
 1096      case ERROR_CALL_NOT_IMPLEMENTED:
 
 1099        WLog_Print(
rdpdr->log, WLOG_ERROR, 
"handle_hotplug failed with error %" PRIu32 
"!",
 
 1107  const UINT error = GetLastError();
 
 1108  if (error && 
rdpdr->rdpcontext)
 
 1109    setChannelError(
rdpdr->rdpcontext, error, 
"reported an error");
 
 1118#if !defined(_WIN32) && !defined(__IOS__) 
 1128  WINPR_ASSERT(
rdpdr);
 
 1130  if (
rdpdr->hotplugThread)
 
 1133    if (
rdpdr->stopEvent)
 
 1134      (void)SetEvent(
rdpdr->stopEvent);
 
 1137    if (WaitForSingleObject(
rdpdr->hotplugThread, INFINITE) == WAIT_FAILED)
 
 1139      error = GetLastError();
 
 1140      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"WaitForSingleObject failed with error %" PRIu32 
"!",
 
 1145    (void)CloseHandle(
rdpdr->hotplugThread);
 
 1146    rdpdr->hotplugThread = NULL;
 
 1149  return CHANNEL_RC_OK;
 
 1156  WINPR_ASSERT(
rdpdr);
 
 1157  WINPR_ASSERT(
rdpdr->rdpcontext);
 
 1159  rdpSettings* settings = 
rdpdr->rdpcontext->settings;
 
 1160  WINPR_ASSERT(settings);
 
 1166        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_DeviceArray, index);
 
 1167    WINPR_ASSERT(device);
 
 1169    if (device->Type == RDPDR_DTYP_FILESYSTEM)
 
 1171      const char DynamicDrives[] = 
"DynamicDrives";
 
 1176      const char wildcard[] = 
"*";
 
 1177      BOOL hotplugAll = strncmp(drive->Path, wildcard, 
sizeof(wildcard)) == 0;
 
 1178      BOOL hotplugLater = strncmp(drive->Path, DynamicDrives, 
sizeof(DynamicDrives)) == 0;
 
 1180      if (hotplugAll || hotplugLater)
 
 1184          WLog_Print(
rdpdr->log, WLOG_WARN,
 
 1185                     "Drive hotplug is not supported in synchronous mode!");
 
 1190          first_hotplug(
rdpdr);
 
 1195        if (!
rdpdr->hotplugThread)
 
 1197          rdpdr->hotplugThread =
 
 1198              CreateThread(NULL, 0, drive_hotplug_thread_func, 
rdpdr, 0, NULL);
 
 1199          if (!
rdpdr->hotplugThread)
 
 1201            WLog_Print(
rdpdr->log, WLOG_ERROR, 
"CreateThread failed!");
 
 1202            return ERROR_INTERNAL_ERROR;
 
 1210    const UINT error = devman_load_device_service(
rdpdr->devman, device, 
rdpdr->rdpcontext);
 
 1213      WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1214                 "devman_load_device_service failed with error %" PRIu32 
"!", error);
 
 1218  return CHANNEL_RC_OK;
 
 1228  WINPR_ASSERT(
rdpdr);
 
 1234    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"devman_new failed!");
 
 1235    return CHANNEL_RC_NO_MEMORY;
 
 1238  WINPR_ASSERT(
rdpdr->rdpcontext);
 
 1240  rdpSettings* settings = 
rdpdr->rdpcontext->settings;
 
 1241  WINPR_ASSERT(settings);
 
 1250    DWORD size = ARRAYSIZE(
rdpdr->computerName);
 
 1251    if (!GetComputerNameExA(ComputerNameNetBIOS, 
rdpdr->computerName, &size))
 
 1252      return ERROR_INTERNAL_ERROR;
 
 1255    strncpy(
rdpdr->computerName, name, strnlen(name, 
sizeof(
rdpdr->computerName)));
 
 1257  return rdpdr_add_devices(
rdpdr);
 
 1262  WINPR_ASSERT(
rdpdr);
 
 1265  if (!Stream_CheckAndLogRequiredLengthWLog(
rdpdr->log, s, 8))
 
 1266    return ERROR_INVALID_DATA;
 
 1268  Stream_Read_UINT16(s, 
rdpdr->serverVersionMajor);
 
 1269  Stream_Read_UINT16(s, 
rdpdr->serverVersionMinor);
 
 1270  Stream_Read_UINT32(s, 
rdpdr->clientID);
 
 1271  rdpdr->sequenceId++;
 
 1273  rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, 
rdpdr->serverVersionMajor);
 
 1274  rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, 
rdpdr->serverVersionMinor);
 
 1275  WLog_Print(
rdpdr->log, WLOG_DEBUG,
 
 1276             "[rdpdr] server announces version %" PRIu32 
".%" PRIu32 
", client uses %" PRIu32
 
 1278             rdpdr->serverVersionMajor, 
rdpdr->serverVersionMinor, 
rdpdr->clientVersionMajor,
 
 1279             rdpdr->clientVersionMinor);
 
 1280  return CHANNEL_RC_OK;
 
 1292  WINPR_ASSERT(
rdpdr);
 
 1293  WINPR_ASSERT(
rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE);
 
 1294  rdpdr_state_advance(
rdpdr, RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
 
 1296  s = StreamPool_Take(
rdpdr->pool, 12);
 
 1300    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
 1301    return CHANNEL_RC_NO_MEMORY;
 
 1304  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);             
 
 1305  Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); 
 
 1306  Stream_Write_UINT16(s, 
rdpdr->clientVersionMajor);
 
 1307  Stream_Write_UINT16(s, 
rdpdr->clientVersionMinor);
 
 1308  Stream_Write_UINT32(s, 
rdpdr->clientID);
 
 1309  return rdpdr_send(
rdpdr, s);
 
 1320  WCHAR* computerNameW = NULL;
 
 1321  size_t computerNameLenW = 0;
 
 1323  WINPR_ASSERT(
rdpdr);
 
 1324  WINPR_ASSERT(
rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY);
 
 1325  rdpdr_state_advance(
rdpdr, RDPDR_CHANNEL_STATE_NAME_REQUEST);
 
 1327  const size_t len = strnlen(
rdpdr->computerName, 
sizeof(
rdpdr->computerName));
 
 1329    return ERROR_INTERNAL_ERROR;
 
 1331  WINPR_ASSERT(
rdpdr->computerName);
 
 1332  computerNameW = ConvertUtf8NToWCharAlloc(
rdpdr->computerName, len, &computerNameLenW);
 
 1333  computerNameLenW *= 
sizeof(WCHAR);
 
 1335  if (computerNameLenW > 0)
 
 1336    computerNameLenW += 
sizeof(WCHAR); 
 
 1338  s = StreamPool_Take(
rdpdr->pool, 16U + computerNameLenW);
 
 1342    free(computerNameW);
 
 1343    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
 1344    return CHANNEL_RC_NO_MEMORY;
 
 1347  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);        
 
 1348  Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); 
 
 1349  Stream_Write_UINT32(s, 1);                      
 
 1350  Stream_Write_UINT32(s, 0);                      
 
 1351  Stream_Write_UINT32(s,
 
 1352                      (UINT32)computerNameLenW); 
 
 1353  Stream_Write(s, computerNameW, computerNameLenW);
 
 1354  free(computerNameW);
 
 1355  return rdpdr_send(
rdpdr, s);
 
 1360  UINT16 versionMajor = 0;
 
 1361  UINT16 versionMinor = 0;
 
 1362  UINT32 clientID = 0;
 
 1364  WINPR_ASSERT(
rdpdr);
 
 1367  if (!Stream_CheckAndLogRequiredLengthWLog(
rdpdr->log, s, 8))
 
 1368    return ERROR_INVALID_DATA;
 
 1370  Stream_Read_UINT16(s, versionMajor);
 
 1371  Stream_Read_UINT16(s, versionMinor);
 
 1372  Stream_Read_UINT32(s, clientID);
 
 1374  if (versionMajor != 
rdpdr->clientVersionMajor || versionMinor != 
rdpdr->clientVersionMinor)
 
 1376    WLog_Print(
rdpdr->log, WLOG_WARN,
 
 1377               "[rdpdr] server announced version %" PRIu32 
".%" PRIu32 
", client uses %" PRIu32
 
 1378               ".%" PRIu32 
" but clientid confirm requests version %" PRIu32 
".%" PRIu32,
 
 1379               rdpdr->serverVersionMajor, 
rdpdr->serverVersionMinor, 
rdpdr->clientVersionMajor,
 
 1380               rdpdr->clientVersionMinor, versionMajor, versionMinor);
 
 1381    rdpdr->clientVersionMajor = versionMajor;
 
 1382    rdpdr->clientVersionMinor = versionMinor;
 
 1385  if (clientID != 
rdpdr->clientID)
 
 1386    rdpdr->clientID = clientID;
 
 1388  return CHANNEL_RC_OK;
 
 1391struct device_announce_arg
 
 1399static BOOL device_announce(ULONG_PTR key, 
void* element, 
void* data)
 
 1401  struct device_announce_arg* arg = data;
 
 1403  DEVICE* device = (DEVICE*)element;
 
 1408  WINPR_ASSERT(device);
 
 1409  WINPR_ASSERT(arg->rdpdr);
 
 1410  WINPR_ASSERT(arg->s);
 
 1421  if ((
rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) ||
 
 1422      (device->type == RDPDR_DTYP_SMARTCARD) || arg->userLoggedOn)
 
 1424    size_t data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
 
 1426    if (!Stream_EnsureRemainingCapacity(arg->s, 20 + data_len))
 
 1428      Stream_Release(arg->s);
 
 1429      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_EnsureRemainingCapacity failed!");
 
 1433    Stream_Write_UINT32(arg->s, device->type); 
 
 1434    Stream_Write_UINT32(arg->s, device->id);   
 
 1435    strncpy(Stream_Pointer(arg->s), device->name, 8);
 
 1437    for (
size_t i = 0; i < 8; i++)
 
 1440      Stream_Peek_UINT8(arg->s, c);
 
 1443        Stream_Write_UINT8(arg->s, 
'_');
 
 1445        Stream_Seek_UINT8(arg->s);
 
 1448    WINPR_ASSERT(data_len <= UINT32_MAX);
 
 1449    Stream_Write_UINT32(arg->s, (UINT32)data_len);
 
 1452      Stream_Write(arg->s, Stream_Buffer(device->data), data_len);
 
 1455    WLog_Print(
rdpdr->log, WLOG_INFO,
 
 1456               "registered [%9s] device #%" PRIu32 
": %5s (type=%2" PRIu32 
" id=%2" PRIu32 
")",
 
 1457               rdpdr_device_type_string(device->type), arg->count, device->name, device->type,
 
 1463static UINT rdpdr_send_device_list_announce_request(
rdpdrPlugin* 
rdpdr, BOOL userLoggedOn)
 
 1467  size_t count_pos = 0;
 
 1468  struct device_announce_arg arg = { 0 };
 
 1470  WINPR_ASSERT(
rdpdr);
 
 1471  WINPR_ASSERT(
rdpdr->devman);
 
 1475    rdpdr->userLoggedOn = TRUE;
 
 1478  s = StreamPool_Take(
rdpdr->pool, 256);
 
 1482    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
 1483    return CHANNEL_RC_NO_MEMORY;
 
 1486  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);                
 
 1487  Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); 
 
 1488  count_pos = Stream_GetPosition(s);
 
 1489  Stream_Seek_UINT32(s); 
 
 1492  arg.userLoggedOn = userLoggedOn;
 
 1494  if (!device_foreach(
rdpdr, TRUE, device_announce, &arg))
 
 1495    return ERROR_INVALID_DATA;
 
 1500    return CHANNEL_RC_OK;
 
 1502  pos = Stream_GetPosition(s);
 
 1503  Stream_SetPosition(s, count_pos);
 
 1504  Stream_Write_UINT32(s, arg.count);
 
 1505  Stream_SetPosition(s, pos);
 
 1506  Stream_SealLength(s);
 
 1507  return rdpdr_send(
rdpdr, s);
 
 1512  WINPR_ASSERT(
rdpdr);
 
 1513  if (
rdpdr->state != RDPDR_CHANNEL_STATE_READY)
 
 1515    WLog_Print(
rdpdr->log, WLOG_DEBUG,
 
 1516               "hotplug event received, but channel [RDPDR] is not ready (state %s), ignoring.",
 
 1517               rdpdr_state_str(
rdpdr->state));
 
 1518    return CHANNEL_RC_OK;
 
 1520  return rdpdr_send_device_list_announce_request(
rdpdr, 
rdpdr->userLoggedOn);
 
 1525  WINPR_ASSERT(
rdpdr);
 
 1531    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
 1532    return CHANNEL_RC_NO_MEMORY;
 
 1535  Stream_SetPosition(s, 4); 
 
 1537  const uint32_t DeviceId = Stream_Get_UINT32(s);     
 
 1538  const uint32_t FileId = Stream_Get_UINT32(s);       
 
 1539  const uint32_t CompletionId = Stream_Get_UINT32(s); 
 
 1541  WLog_Print(
rdpdr->log, WLOG_WARN,
 
 1542             "Dummy response {DeviceId=%" PRIu32 
", FileId=%" PRIu32 
", CompletionId=%" PRIu32
 
 1544             DeviceId, FileId, CompletionId);
 
 1545  if (!rdpdr_write_iocompletion_header(output, DeviceId, CompletionId, STATUS_UNSUCCESSFUL))
 
 1546    return CHANNEL_RC_NO_MEMORY;
 
 1548  return rdpdr_send(
rdpdr, output);
 
 1559  UINT error = CHANNEL_RC_OK;
 
 1561  WINPR_ASSERT(
rdpdr);
 
 1568    if ((error == CHANNEL_RC_OK) ||
 
 1569        (error == ERROR_DEV_NOT_EXIST && 
rdpdr->ignoreInvalidDevices))
 
 1571      return dummy_irp_response(
rdpdr, s);
 
 1574    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"irp_new failed with %" PRIu32 
"!", error);
 
 1578  if (irp->device->IRPRequest)
 
 1579    IFCALLRET(irp->device->IRPRequest, error, irp->device, irp);
 
 1583  if (error != CHANNEL_RC_OK)
 
 1585    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"device->IRPRequest failed with error %" PRIu32 
"",
 
 1593static UINT rdpdr_process_component(
rdpdrPlugin* 
rdpdr, UINT16 component, UINT16 packetId,
 
 1597  DEVICE* device = NULL;
 
 1599  WINPR_ASSERT(
rdpdr);
 
 1604    case RDPDR_CTYP_PRN:
 
 1605      type = RDPDR_DTYP_PRINT;
 
 1609      return ERROR_INVALID_DATA;
 
 1612  device = devman_get_device_by_type(
rdpdr->devman, type);
 
 1615    return ERROR_DEV_NOT_EXIST;
 
 1617  return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
 
 1626static BOOL device_init(ULONG_PTR key, 
void* element, 
void* data)
 
 1629  UINT error = CHANNEL_RC_OK;
 
 1630  DEVICE* device = element;
 
 1635  IFCALLRET(device->Init, error, device);
 
 1637  if (error != CHANNEL_RC_OK)
 
 1639    WLog_Print(log, WLOG_ERROR, 
"Device init failed with %s", WTSErrorToString(error));
 
 1647  WINPR_ASSERT(
rdpdr);
 
 1648  WINPR_ASSERT(
rdpdr->devman);
 
 1650  rdpdr->userLoggedOn = FALSE; 
 
 1651  if (!device_foreach(
rdpdr, TRUE, device_init, 
rdpdr->log))
 
 1652    return ERROR_INTERNAL_ERROR;
 
 1653  return CHANNEL_RC_OK;
 
 1656static BOOL state_match(
enum RDPDR_CHANNEL_STATE state, 
size_t count, va_list ap)
 
 1658  for (
size_t x = 0; x < count; x++)
 
 1660    enum RDPDR_CHANNEL_STATE cur = va_arg(ap, 
enum RDPDR_CHANNEL_STATE);
 
 1667static const char* state_str(
size_t count, va_list ap, 
char* buffer, 
size_t size)
 
 1669  for (
size_t x = 0; x < count; x++)
 
 1671    enum RDPDR_CHANNEL_STATE cur = va_arg(ap, 
enum RDPDR_CHANNEL_STATE);
 
 1672    const char* curstr = rdpdr_state_str(cur);
 
 1673    winpr_str_append(curstr, buffer, size, 
"|");
 
 1678static BOOL rdpdr_state_check(
rdpdrPlugin* 
rdpdr, UINT16 packetid, 
enum RDPDR_CHANNEL_STATE next,
 
 1682  WINPR_ASSERT(
rdpdr);
 
 1684  va_start(ap, count);
 
 1685  BOOL rc = state_match(
rdpdr->state, count, ap);
 
 1690    const char* strstate = rdpdr_state_str(
rdpdr->state);
 
 1691    char buffer[256] = { 0 };
 
 1693    va_start(ap, count);
 
 1694    state_str(count, ap, buffer, 
sizeof(buffer));
 
 1697    WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1698               "channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.",
 
 1699               rdpdr_packetid_string(packetid), buffer, strstate);
 
 1701    rdpdr_state_advance(
rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
 
 1704  return rdpdr_state_advance(
rdpdr, next);
 
 1709  WINPR_ASSERT(
rdpdr);
 
 1713    case PAKID_CORE_SERVER_ANNOUNCE:
 
 1718      rdpdr_state_advance(
rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
 
 1719      return rdpdr_state_check(
rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1,
 
 1720                               RDPDR_CHANNEL_STATE_INITIAL);
 
 1721    case PAKID_CORE_SERVER_CAPABILITY:
 
 1722      return rdpdr_state_check(
 
 1723          rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6,
 
 1724          RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_SERVER_CAPS,
 
 1725          RDPDR_CHANNEL_STATE_READY, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
 
 1726          RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_USER_LOGGEDON);
 
 1727    case PAKID_CORE_CLIENTID_CONFIRM:
 
 1728      return rdpdr_state_check(
rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 5,
 
 1729                               RDPDR_CHANNEL_STATE_NAME_REQUEST,
 
 1730                               RDPDR_CHANNEL_STATE_SERVER_CAPS,
 
 1731                               RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY,
 
 1732                               RDPDR_CHANNEL_STATE_USER_LOGGEDON);
 
 1733    case PAKID_CORE_USER_LOGGEDON:
 
 1734      if (!rdpdr_check_extended_pdu_flag(
rdpdr, RDPDR_USER_LOGGEDON_PDU))
 
 1737      return rdpdr_state_check(
 
 1738          rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4,
 
 1739          RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
 
 1740          RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY);
 
 1743      enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY;
 
 1744      return rdpdr_state_check(
rdpdr, packetid, state, 1, state);
 
 1751  if (
rdpdr->haveClientId && 
rdpdr->haveServerCaps)
 
 1753    const UINT error = rdpdr_send_device_list_announce_request(
rdpdr, FALSE);
 
 1756      WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1757                 "rdpdr_send_device_list_announce_request failed with error %" PRIu32 
"",
 
 1761    if (!rdpdr_state_advance(
rdpdr, RDPDR_CHANNEL_STATE_READY))
 
 1774  UINT16 component = 0;
 
 1775  UINT16 packetId = 0;
 
 1776  UINT32 deviceId = 0;
 
 1778  UINT error = ERROR_INVALID_DATA;
 
 1781    return CHANNEL_RC_NULL_DATA;
 
 1783  rdpdr_dump_received_packet(
rdpdr->log, WLOG_TRACE, s, 
"[rdpdr-channel] receive");
 
 1784  if (Stream_GetRemainingLength(s) >= 4)
 
 1786    Stream_Read_UINT16(s, component); 
 
 1787    Stream_Read_UINT16(s, packetId);  
 
 1789    if (component == RDPDR_CTYP_CORE)
 
 1791      if (!rdpdr_check_channel_state(
rdpdr, packetId))
 
 1792        return CHANNEL_RC_OK;
 
 1796        case PAKID_CORE_SERVER_ANNOUNCE:
 
 1797          rdpdr->haveClientId = FALSE;
 
 1798          rdpdr->haveServerCaps = FALSE;
 
 1799          if ((error = rdpdr_process_server_announce_request(
rdpdr, s)))
 
 1802          else if ((error = rdpdr_send_client_announce_reply(
rdpdr)))
 
 1804            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1805                       "rdpdr_send_client_announce_reply failed with error %" PRIu32 
"",
 
 1808          else if ((error = rdpdr_send_client_name_request(
rdpdr)))
 
 1810            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1811                       "rdpdr_send_client_name_request failed with error %" PRIu32 
"",
 
 1814          else if ((error = rdpdr_process_init(
rdpdr)))
 
 1816            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1817                       "rdpdr_process_init failed with error %" PRIu32 
"", error);
 
 1822        case PAKID_CORE_SERVER_CAPABILITY:
 
 1823          if ((error = rdpdr_process_capability_request(
rdpdr, s)))
 
 1826          else if ((error = rdpdr_send_capability_response(
rdpdr)))
 
 1828            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1829                       "rdpdr_send_capability_response failed with error %" PRIu32 
"",
 
 1834            rdpdr->haveServerCaps = TRUE;
 
 1835            if (!tryAdvance(
rdpdr))
 
 1836              error = ERROR_INTERNAL_ERROR;
 
 1841        case PAKID_CORE_CLIENTID_CONFIRM:
 
 1842          if ((error = rdpdr_process_server_clientid_confirm(
rdpdr, s)))
 
 1847            rdpdr->haveClientId = TRUE;
 
 1848            if (!tryAdvance(
rdpdr))
 
 1849              error = ERROR_INTERNAL_ERROR;
 
 1853        case PAKID_CORE_USER_LOGGEDON:
 
 1854          if (!
rdpdr->haveServerCaps)
 
 1856            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1857                       "Wrong state %s for %s. [serverCaps=%d, clientId=%d]",
 
 1858                       rdpdr_state_str(
rdpdr->state), rdpdr_packetid_string(packetId),
 
 1860            error = ERROR_INTERNAL_ERROR;
 
 1862          else if ((error = rdpdr_send_device_list_announce_request(
rdpdr, TRUE)))
 
 1865                rdpdr->log, WLOG_ERROR,
 
 1866                "rdpdr_send_device_list_announce_request failed with error %" PRIu32 
"",
 
 1869          else if (!tryAdvance(
rdpdr))
 
 1871            error = ERROR_INTERNAL_ERROR;
 
 1876        case PAKID_CORE_DEVICE_REPLY:
 
 1879          if (Stream_GetRemainingLength(s) >= 8)
 
 1881            Stream_Read_UINT32(s, deviceId);
 
 1882            Stream_Read_UINT32(s, status);
 
 1885              devman_unregister_device(
rdpdr->devman, (
void*)((
size_t)deviceId));
 
 1886            error = CHANNEL_RC_OK;
 
 1891        case PAKID_CORE_DEVICE_IOREQUEST:
 
 1892          if ((error = rdpdr_process_irp(
rdpdr, s)))
 
 1894            WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1895                       "rdpdr_process_irp failed with error %" PRIu32 
"", error);
 
 1904          WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 1905                     "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16 
"", packetId);
 
 1906          error = ERROR_INVALID_DATA;
 
 1912      error = rdpdr_process_component(
rdpdr, component, packetId, s);
 
 1914      if (error != CHANNEL_RC_OK)
 
 1916        DWORD level = WLOG_ERROR;
 
 1917        if (
rdpdr->ignoreInvalidDevices)
 
 1919          if (error == ERROR_DEV_NOT_EXIST)
 
 1922            error = CHANNEL_RC_OK;
 
 1925        WLog_Print(
rdpdr->log, level,
 
 1926                   "Unknown message: Component: %s [0x%04" PRIX16
 
 1927                   "] PacketId: %s [0x%04" PRIX16 
"]",
 
 1928                   rdpdr_component_string(component), component,
 
 1929                   rdpdr_packetid_string(packetId), packetId);
 
 1949    return CHANNEL_RC_NULL_DATA;
 
 1955    return CHANNEL_RC_BAD_INIT_HANDLE;
 
 1958  const size_t pos = Stream_GetPosition(s);
 
 1959  UINT status = ERROR_INTERNAL_ERROR;
 
 1960  if (pos <= UINT32_MAX)
 
 1962    rdpdr_dump_send_packet(
rdpdr->log, WLOG_TRACE, s, 
"[rdpdr-channel] send");
 
 1963    status = plugin->channelEntryPoints.pVirtualChannelWriteEx(
 
 1964        plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)pos, s);
 
 1967  if (status != CHANNEL_RC_OK)
 
 1970    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"pVirtualChannelWriteEx failed with %s [%08" PRIX32 
"]",
 
 1971               WTSErrorToString(status), status);
 
 1982static UINT rdpdr_virtual_channel_event_data_received(
rdpdrPlugin* 
rdpdr, 
void* pData,
 
 1983                                                      UINT32 dataLength, UINT32 totalLength,
 
 1988  WINPR_ASSERT(
rdpdr);
 
 1989  WINPR_ASSERT(pData || (dataLength == 0));
 
 1991  if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
 
 1999    return CHANNEL_RC_OK;
 
 2002  if (dataFlags & CHANNEL_FLAG_FIRST)
 
 2004    if (
rdpdr->data_in != NULL)
 
 2005      Stream_Release(
rdpdr->data_in);
 
 2007    rdpdr->data_in = StreamPool_Take(
rdpdr->pool, totalLength);
 
 2009    if (!
rdpdr->data_in)
 
 2011      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_New failed!");
 
 2012      return CHANNEL_RC_NO_MEMORY;
 
 2016  data_in = 
rdpdr->data_in;
 
 2018  if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
 
 2020    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"Stream_EnsureRemainingCapacity failed!");
 
 2021    return ERROR_INVALID_DATA;
 
 2024  Stream_Write(data_in, pData, dataLength);
 
 2026  if (dataFlags & CHANNEL_FLAG_LAST)
 
 2028    const size_t pos = Stream_GetPosition(data_in);
 
 2029    const size_t cap = Stream_Capacity(data_in);
 
 2032      WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2033                 "rdpdr_virtual_channel_event_data_received: read error");
 
 2034      return ERROR_INTERNAL_ERROR;
 
 2037    Stream_SealLength(data_in);
 
 2038    Stream_SetPosition(data_in, 0);
 
 2042      if (!MessageQueue_Post(
rdpdr->queue, NULL, 0, (
void*)data_in, NULL))
 
 2044        WLog_Print(
rdpdr->log, WLOG_ERROR, 
"MessageQueue_Post failed!");
 
 2045        return ERROR_INTERNAL_ERROR;
 
 2047      rdpdr->data_in = NULL;
 
 2051      UINT error = rdpdr_process_receive(
rdpdr, data_in);
 
 2052      Stream_Release(data_in);
 
 2053      rdpdr->data_in = NULL;
 
 2059  return CHANNEL_RC_OK;
 
 2062static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
 
 2063                                                          UINT event, LPVOID pData,
 
 2064                                                          UINT32 dataLength, UINT32 totalLength,
 
 2067  UINT error = CHANNEL_RC_OK;
 
 2070  WINPR_ASSERT(
rdpdr);
 
 2073    case CHANNEL_EVENT_DATA_RECEIVED:
 
 2074      if (!
rdpdr || !pData || (
rdpdr->OpenHandle != openHandle))
 
 2076        WLog_Print(
rdpdr->log, WLOG_ERROR, 
"error no match");
 
 2079      if ((error = rdpdr_virtual_channel_event_data_received(
rdpdr, pData, dataLength,
 
 2080                                                             totalLength, dataFlags)))
 
 2081        WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2082                   "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32
 
 2088    case CHANNEL_EVENT_WRITE_CANCELLED:
 
 2089    case CHANNEL_EVENT_WRITE_COMPLETE:
 
 2096    case CHANNEL_EVENT_USER:
 
 2103    setChannelError(
rdpdr->rdpcontext, error,
 
 2104                    "rdpdr_virtual_channel_open_event_ex reported an error");
 
 2107static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
 
 2114    ExitThread((DWORD)CHANNEL_RC_NULL_DATA);
 
 2115    return CHANNEL_RC_NULL_DATA;
 
 2118  if ((error = rdpdr_process_connect(
rdpdr)))
 
 2120    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"rdpdr_process_connect failed with error %" PRIu32 
"!",
 
 2123    if (
rdpdr->rdpcontext)
 
 2124      setChannelError(
rdpdr->rdpcontext, error,
 
 2125                      "rdpdr_virtual_channel_client_thread reported an error");
 
 2133    wMessage message = { 0 };
 
 2134    WINPR_ASSERT(
rdpdr);
 
 2136    if (!MessageQueue_Wait(
rdpdr->queue))
 
 2139    if (MessageQueue_Peek(
rdpdr->queue, &message, TRUE))
 
 2141      if (message.id == WMQ_QUIT)
 
 2144      if (message.id == 0)
 
 2148        error = rdpdr_process_receive(
rdpdr, data);
 
 2150        Stream_Release(data);
 
 2153          WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2154                     "rdpdr_process_receive failed with error %" PRIu32 
"!", error);
 
 2156          if (
rdpdr->rdpcontext)
 
 2157            setChannelError(
rdpdr->rdpcontext, error,
 
 2158                            "rdpdr_virtual_channel_client_thread reported an error");
 
 2167  if ((error = drive_hotplug_thread_terminate(
rdpdr)))
 
 2168    WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2169               "drive_hotplug_thread_terminate failed with error %" PRIu32 
"!", error);
 
 2175static void queue_free(
void* obj)
 
 2178  wMessage* msg = (wMessage*)obj;
 
 2180  if (!msg || (msg->id != 0))
 
 2193static UINT rdpdr_virtual_channel_event_connected(
rdpdrPlugin* 
rdpdr, LPVOID pData,
 
 2198  WINPR_ASSERT(
rdpdr);
 
 2199  WINPR_UNUSED(pData);
 
 2200  WINPR_UNUSED(dataLength);
 
 2204    rdpdr->queue = MessageQueue_New(NULL);
 
 2208      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"MessageQueue_New failed!");
 
 2209      return CHANNEL_RC_NO_MEMORY;
 
 2212    obj = MessageQueue_Object(
rdpdr->queue);
 
 2213    obj->fnObjectFree = queue_free;
 
 2215    if (!(
rdpdr->thread = CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread,
 
 2216                                       (
void*)
rdpdr, 0, NULL)))
 
 2218      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"CreateThread failed!");
 
 2219      return ERROR_INTERNAL_ERROR;
 
 2224    UINT error = rdpdr_process_connect(
rdpdr);
 
 2227      WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2228                 "rdpdr_process_connect failed with error %" PRIu32 
"!", error);
 
 2233  return rdpdr->channelEntryPoints.pVirtualChannelOpenEx(
rdpdr->InitHandle, &
rdpdr->OpenHandle,
 
 2234                                                         rdpdr->channelDef.name,
 
 2235                                                         rdpdr_virtual_channel_open_event_ex);
 
 2247  WINPR_ASSERT(
rdpdr);
 
 2249  if (
rdpdr->OpenHandle == 0)
 
 2250    return CHANNEL_RC_OK;
 
 2254    if (MessageQueue_PostQuit(
rdpdr->queue, 0) &&
 
 2255        (WaitForSingleObject(
rdpdr->thread, INFINITE) == WAIT_FAILED))
 
 2257      error = GetLastError();
 
 2258      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"WaitForSingleObject failed with error %" PRIu32 
"!",
 
 2265    (void)CloseHandle(
rdpdr->thread);
 
 2266  MessageQueue_Free(
rdpdr->queue);
 
 2267  rdpdr->queue = NULL;
 
 2268  rdpdr->thread = NULL;
 
 2270  WINPR_ASSERT(
rdpdr->channelEntryPoints.pVirtualChannelCloseEx);
 
 2271  error = 
rdpdr->channelEntryPoints.pVirtualChannelCloseEx(
rdpdr->InitHandle, 
rdpdr->OpenHandle);
 
 2273  if (CHANNEL_RC_OK != error)
 
 2275    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"pVirtualChannelCloseEx failed with %s [%08" PRIX32 
"]",
 
 2276               WTSErrorToString(error), error);
 
 2279  rdpdr->OpenHandle = 0;
 
 2283    Stream_Release(
rdpdr->data_in);
 
 2284    rdpdr->data_in = NULL;
 
 2289    devman_free(
rdpdr->devman);
 
 2290    rdpdr->devman = NULL;
 
 2298  WINPR_ASSERT(
rdpdr);
 
 2300  if (
rdpdr->stopEvent)
 
 2302    (void)CloseHandle(
rdpdr->stopEvent);
 
 2303    rdpdr->stopEvent = NULL;
 
 2306  rdpdr->InitHandle = 0;
 
 2307  StreamPool_Free(
rdpdr->pool);
 
 2311static UINT rdpdr_register_device(RdpdrClientContext* context, 
const RDPDR_DEVICE* device,
 
 2314  WINPR_ASSERT(context);
 
 2315  WINPR_ASSERT(device);
 
 2319  WINPR_ASSERT(
rdpdr);
 
 2323    return ERROR_INVALID_DATA;
 
 2324  UINT rc = devman_load_device_service(
rdpdr->devman, copy, 
rdpdr->rdpcontext);
 
 2326  freerdp_device_free(copy);
 
 2327  if (rc == CHANNEL_RC_OK)
 
 2328    rc = rdpdr_try_send_device_list_announce_request(
rdpdr);
 
 2332static UINT rdpdr_unregister_device(RdpdrClientContext* context, 
size_t count, 
const uint32_t ids[])
 
 2334  WINPR_ASSERT(context);
 
 2337  WINPR_ASSERT(
rdpdr);
 
 2339  for (
size_t x = 0; x < count; x++)
 
 2341    const uintptr_t 
id = ids[x];
 
 2342    devman_unregister_device(
rdpdr->devman, (
void*)
id);
 
 2344  return rdpdr_send_device_list_remove_request(
rdpdr, WINPR_ASSERTING_INT_CAST(uint32_t, count),
 
 2349                                                    WINPR_ATTR_UNUSED LPVOID pData,
 
 2350                                                    WINPR_ATTR_UNUSED UINT32 dataLength)
 
 2352  WINPR_ASSERT(
rdpdr);
 
 2354  WINPR_ASSERT(!
rdpdr->stopEvent);
 
 2355  rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
 2356  WINPR_ASSERT(
rdpdr->stopEvent);
 
 2360  rdpdr->context.RdpdrHotplugDevice = handle_hotplug;
 
 2361  rdpdr->context.RdpdrRegisterDevice = rdpdr_register_device;
 
 2362  rdpdr->context.RdpdrUnregisterDevice = rdpdr_unregister_device;
 
 2363  return CHANNEL_RC_OK;
 
 2366static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
 
 2367                                                          UINT event, LPVOID pData, UINT dataLength)
 
 2369  UINT error = CHANNEL_RC_OK;
 
 2372  if (!
rdpdr || (
rdpdr->InitHandle != pInitHandle))
 
 2374    WLog_ERR(TAG, 
"error no match");
 
 2378  WINPR_ASSERT(pData || (dataLength == 0));
 
 2382    case CHANNEL_EVENT_INITIALIZED:
 
 2383      error = rdpdr_virtual_channel_event_initialized(
rdpdr, pData, dataLength);
 
 2386    case CHANNEL_EVENT_CONNECTED:
 
 2387      if ((error = rdpdr_virtual_channel_event_connected(
rdpdr, pData, dataLength)))
 
 2388        WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2389                   "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 
"!",
 
 2394    case CHANNEL_EVENT_DISCONNECTED:
 
 2395      if ((error = rdpdr_virtual_channel_event_disconnected(
rdpdr)))
 
 2396        WLog_Print(
rdpdr->log, WLOG_ERROR,
 
 2397                   "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32
 
 2403    case CHANNEL_EVENT_TERMINATED:
 
 2404      rdpdr_virtual_channel_event_terminated(
rdpdr);
 
 2408    case CHANNEL_EVENT_ATTACHED:
 
 2409    case CHANNEL_EVENT_DETACHED:
 
 2411      WLog_Print(
rdpdr->log, WLOG_ERROR, 
"unknown event %" PRIu32 
"!", event);
 
 2416    setChannelError(
rdpdr->rdpcontext, error,
 
 2417                    "rdpdr_virtual_channel_init_event_ex reported an error");
 
 2421#define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx 
 2423FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
 
 2430  WINPR_ASSERT(pEntryPoints);
 
 2431  WINPR_ASSERT(pInitHandle);
 
 2437    WLog_ERR(TAG, 
"calloc failed!");
 
 2440  rdpdr->log = WLog_Get(TAG);
 
 2442  rdpdr->clientExtendedPDU =
 
 2443      RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU;
 
 2444  rdpdr->clientIOCode1 =
 
 2445      RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
 
 2446      RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
 
 2447      RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
 
 2448      RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
 
 2449      RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL |
 
 2450      RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY;
 
 2452  rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO;
 
 2454  rdpdr->pool = StreamPool_New(TRUE, 1024);
 
 2461  rdpdr->channelDef.options =
 
 2462      CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
 
 2463  (void)sprintf_s(
rdpdr->channelDef.name, ARRAYSIZE(
rdpdr->channelDef.name),
 
 2464                  RDPDR_SVC_CHANNEL_NAME);
 
 2465  rdpdr->sequenceId = 0;
 
 2469      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
 
 2471    rdpdr->rdpcontext = pEntryPointsEx->context;
 
 2473                                   FreeRDP_SynchronousStaticChannels))
 
 2474      rdpdr->async = TRUE;
 
 2478  rdpdr->InitHandle = pInitHandle;
 
 2479  rc = 
rdpdr->channelEntryPoints.pVirtualChannelInitEx(
 
 2480      rdpdr, &
rdpdr->context, pInitHandle, &
rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
 
 2481      rdpdr_virtual_channel_init_event_ex);
 
 2483  if (CHANNEL_RC_OK != rc)
 
 2485    WLog_Print(
rdpdr->log, WLOG_ERROR, 
"pVirtualChannelInitEx failed with %s [%08" PRIX32 
"]",
 
 2486               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.