Coverage Report

Created: 2025-07-01 06:46

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