Coverage Report

Created: 2025-08-26 06:37

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