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