channels: patch rdpdr/smartcard valgrind leaks, fix hang on disconnect
[platform/upstream/freerdp.git] / channels / rdpdr / client / rdpdr_main.c
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  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <winpr/crt.h>
30 #include <winpr/stream.h>
31
32 #include <freerdp/types.h>
33 #include <freerdp/constants.h>
34 #include <freerdp/channels/log.h>
35 #include <freerdp/channels/rdpdr.h>
36
37 #ifdef _WIN32
38 #include <windows.h>
39 #include <dbt.h>
40 #else
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #endif
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #include "rdpdr_capabilities.h"
51
52 #include "devman.h"
53 #include "irp.h"
54
55 #include "rdpdr_main.h"
56
57 typedef struct _DEVICE_DRIVE_EXT DEVICE_DRIVE_EXT;
58
59 struct _DEVICE_DRIVE_EXT
60 {
61         DEVICE device;
62         char* path;
63 };
64
65 static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn);
66
67 static void rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 count, UINT32 ids[])
68 {
69         UINT32 i;
70         wStream* s;
71
72         s = Stream_New(NULL, 256);
73
74         Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
75         Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE);
76         Stream_Write_UINT32(s, count);
77
78         for (i = 0; i < count; i++)
79                 Stream_Write_UINT32(s, ids[i]);
80
81         Stream_SealLength(s);
82
83         rdpdr_send(rdpdr, s);
84 }
85
86 #ifdef _WIN32
87
88 LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
89 {
90         rdpdrPlugin *rdpdr;
91         PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
92
93         rdpdr = (rdpdrPlugin *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
94
95         switch(Msg)
96         {
97                 case WM_DEVICECHANGE:
98                         switch (wParam)
99                         {
100                                 case DBT_DEVICEARRIVAL:
101                                         if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
102                                         {
103                                                 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
104                                                 DWORD unitmask = lpdbv->dbcv_unitmask;
105                                                 int i;
106                                                 char drive_path[4] = { 'c', ':', '/', '\0'};
107
108                                                 for (i = 0; i < 26; i++)
109                                                 {
110                                                         if (unitmask & 0x01)
111                                                         {
112                                                                 RDPDR_DRIVE* drive;
113
114                                                                 drive_path[0] = 'A' + i;
115
116                                                                 drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
117                                                                 ZeroMemory(drive, sizeof(RDPDR_DRIVE));
118
119                                                                 drive->Type = RDPDR_DTYP_FILESYSTEM;
120
121                                                                 drive->Path = _strdup(drive_path);
122                                                                 drive_path[1] = '\0';
123                                                                 drive->Name = _strdup(drive_path);
124                                                                 devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive);
125                                                                 rdpdr_send_device_list_announce_request(rdpdr, TRUE);
126                                                         }
127                                                         unitmask = unitmask >> 1;
128                                                 }
129                                         }
130                                         break;
131
132                                 case DBT_DEVICEREMOVECOMPLETE:
133                                         if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
134                                         {
135                                                 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
136                                                 DWORD unitmask = lpdbv->dbcv_unitmask;
137                                                 int i, j, count;
138                                                 char drive_name_upper, drive_name_lower;
139
140                                                 ULONG_PTR *keys;
141                                                 DEVICE_DRIVE_EXT *device_ext;
142                                                 UINT32 ids[1];
143
144                                                 for (i = 0; i < 26; i++)
145                                                 {
146                                                         if (unitmask & 0x01)
147                                                         {
148                                                                 drive_name_upper = 'A' + i;
149                                                                 drive_name_lower = 'a' + i;
150
151                                                                 count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
152
153                                                                 for (j = 0; j < count; j++)
154                                                                 {
155                                                                         device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]);
156                                                                         if (device_ext->path[0] == drive_name_upper || device_ext->path[0] == drive_name_lower)
157                                                                         {
158                                                                                 devman_unregister_device(rdpdr->devman, (void *)keys[j]);
159                                                                                 ids[0] = keys[j];
160                                                                                 rdpdr_send_device_list_remove_request(rdpdr, 1, ids);
161                                                                                 break;
162                                                                         }
163                                                                 }
164                                                         }
165                                                         unitmask = unitmask >> 1;
166                                                 }
167                                         }
168                                         break;
169
170                                 default:
171                                         break;
172                         }
173                         break;
174
175                 default:
176                         return DefWindowProc(hWnd, Msg, wParam, lParam);
177         }
178         return DefWindowProc(hWnd, Msg, wParam, lParam);
179 }
180
181 static void* drive_hotplug_thread_func(void* arg)
182 {
183         rdpdrPlugin *rdpdr;
184         WNDCLASSEX wnd_cls;
185         HWND hwnd;
186         MSG msg;
187         BOOL bRet;
188         DEV_BROADCAST_HANDLE NotificationFilter;
189         HDEVNOTIFY hDevNotify;
190
191         rdpdr = (rdpdrPlugin *)arg;
192
193         /* init windows class */
194         wnd_cls.cbSize        = sizeof(WNDCLASSEX);
195         wnd_cls.style         = CS_HREDRAW | CS_VREDRAW;
196         wnd_cls.lpfnWndProc   = hotplug_proc;
197         wnd_cls.cbClsExtra    = 0;
198         wnd_cls.cbWndExtra    = 0;
199         wnd_cls.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
200         wnd_cls.hCursor       = NULL;
201         wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
202         wnd_cls.lpszMenuName  = NULL;
203         wnd_cls.lpszClassName = L"DRIVE_HOTPLUG";
204         wnd_cls.hInstance     = NULL;
205         wnd_cls.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
206         RegisterClassEx(&wnd_cls);
207
208         /* create window */
209         hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL,
210                         0, 0, 0, 0, 0,
211                         NULL, NULL, NULL, NULL);
212         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr);
213
214         rdpdr->hotplug_wnd = hwnd;
215         /* register device interface to hwnd */
216         NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
217         NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
218         hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
219
220         /* message loop */
221         while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
222         {
223                 if (bRet == -1)
224                 {
225                         break;
226                 }
227                 else
228                 {
229                         TranslateMessage(&msg);
230                         DispatchMessage(&msg);
231                 }
232         }
233
234         UnregisterDeviceNotification(hDevNotify);
235
236         return NULL;
237 }
238
239 static void drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
240 {
241         if (rdpdr->hotplug_wnd)
242                 PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0);
243 }
244
245 #else
246
247 #define MAX_USB_DEVICES 100
248
249 typedef struct _hotplug_dev {
250         char* path;
251         BOOL  to_add;
252 } hotplug_dev;
253
254 static char* next_line(FILE* fd, size_t* len)
255 {
256         size_t newsiz;
257         int c;
258         char* newbuf;
259         char* lrbuf;
260         int lrsiz;
261
262         *len = 0;
263         lrsiz = 0;
264         lrbuf = NULL;
265         newbuf = NULL;
266
267         for (;;)
268         {
269                 c = fgetc(fd);
270                 if (ferror(fd))
271                         return NULL;
272
273                 if (c == EOF)
274                 {
275                         if (*len == 0)
276                                 return NULL;
277                         else
278                         {
279                                 lrbuf[(*len)] = '\0';
280                                 return lrbuf;
281                         }
282                 }
283                 else
284                 {
285                         if (*len == lrsiz)
286                         {
287                                 newsiz = lrsiz + 4096;
288                                 newbuf = realloc(lrbuf, newsiz);
289                                 if (newbuf == NULL)
290                                         return NULL;
291                                 lrbuf = newbuf;
292                                 lrsiz = newsiz;
293                         }
294                         lrbuf[(*len)] = c;
295
296                         if (c == '\n')
297                         {
298                                 lrbuf[(*len)] = '\0';
299                                 return lrbuf;
300                         }
301
302                         (*len)++;
303                 }
304         }
305 }
306
307 static char* get_word(char* str, unsigned int* offset)
308 {
309         char* p;
310         char* tmp;
311         char* word;
312         int wlen;
313
314         if (*offset >= strlen(str))
315                 return NULL;
316
317         p = str + *offset;
318         tmp = p;
319
320         while (*tmp != ' ' && *tmp  != '\0')
321                 tmp++;
322
323         wlen = tmp - p;
324         *offset += wlen;
325
326         /* in case there are more than one space between words */
327         while (*(str + *offset) == ' ')
328                 (*offset)++;
329
330         word = malloc(wlen + 1);
331         
332         if (word != NULL)
333         {
334                 CopyMemory(word, p, wlen);
335                 word[wlen] = '\0';
336         }
337         
338         return word;
339 }
340
341 static void handle_hotplug(rdpdrPlugin* rdpdr)
342 {
343         FILE *f;
344         size_t len;
345         char *line;
346         char *word;
347         unsigned int wlen;
348
349         hotplug_dev dev_array[MAX_USB_DEVICES];
350         int i, j;
351         int size = 0;
352
353         int count;
354         DEVICE_DRIVE_EXT *device_ext;
355         ULONG_PTR *keys;
356         UINT32 ids[1];
357
358         f = fopen("/proc/mounts", "r");
359         if (f == NULL)
360         {
361                 return;
362         }
363
364         while ((line = next_line(f, &len)))
365         {
366                 wlen = 0;
367                 while ((word = get_word(line, &wlen)))
368                 {
369                         /* copy hotpluged device mount point to the dev_array */
370                         if (strstr(word, "/mnt/") != NULL || strstr(word, "/media/") != NULL)
371                         {
372                                 dev_array[size].path = strdup(word);
373                                 dev_array[size++].to_add = TRUE;
374                         }
375                         free(word);
376                 }
377                 free(line);
378         }
379
380         fclose(f);
381
382         /* delete removed devices */
383         count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
384
385         for (j = 0; j < count; j++)
386         {
387                 BOOL dev_found = FALSE;
388
389                 device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]);
390
391                 /* not plugable device */
392                 if (strstr(device_ext->path, "/mnt/") == NULL && strstr(device_ext->path, "/media/") == NULL)
393                         continue;
394
395                 for (i = 0; i < size; i++)
396                 {
397                         if (strstr(device_ext->path, dev_array[i].path) != NULL)
398                         {
399                                 dev_found = TRUE;
400                                 dev_array[i].to_add = FALSE;
401                                 break;
402                         }
403                 }
404
405                 if (!dev_found)
406                 {
407                         devman_unregister_device(rdpdr->devman, (void *)keys[j]);
408                         ids[0] = keys[j];
409                         rdpdr_send_device_list_remove_request(rdpdr, 1, ids);
410                 }
411         }
412
413         /* add new devices */
414         for (i = 0; i < size; i++)
415         {
416                 RDPDR_DRIVE* drive;
417
418                 if (dev_array[i].to_add)
419                 {
420                         char* name;
421
422                         drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
423                         ZeroMemory(drive, sizeof(RDPDR_DRIVE));
424
425                         drive->Type = RDPDR_DTYP_FILESYSTEM;
426
427                         drive->Path = _strdup(dev_array[i].path);
428                         name = strrchr(drive->Path, '/') + 1;
429                         drive->Name = _strdup(name);
430                         devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive);
431                 }
432
433                 free(dev_array[i].path);
434                 dev_array[i].path = NULL;
435         }
436         rdpdr_send_device_list_announce_request(rdpdr, TRUE);
437 }
438
439 static void* drive_hotplug_thread_func(void* arg)
440 {
441         rdpdrPlugin* rdpdr;
442         int mfd;
443         fd_set rfds;
444         struct timeval tv;
445         int rv;
446
447         rdpdr = (rdpdrPlugin*) arg;
448
449         rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
450
451         mfd = open("/proc/mounts", O_RDONLY, 0);
452
453         if (mfd < 0)
454         {
455                 WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts.");
456                 return NULL;
457         }
458
459         FD_ZERO(&rfds);
460         FD_SET(mfd, &rfds);
461         tv.tv_sec = 1;
462         tv.tv_usec = 0;
463
464         handle_hotplug(rdpdr);
465
466         while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
467         {
468                 if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0)
469                         break;
470
471                 if (FD_ISSET(mfd, &rfds))
472                 {
473                         /* file /proc/mounts changed, handle this */
474                         handle_hotplug(rdpdr);
475                 }
476
477                 FD_ZERO(&rfds);
478                 FD_SET(mfd, &rfds);
479                 tv.tv_sec = 1;
480                 tv.tv_usec = 0;
481         }
482
483         return NULL;
484 }
485
486 static void drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
487 {
488         if (rdpdr->hotplugThread)
489         {
490                 if (rdpdr->stopEvent)
491                         SetEvent(rdpdr->stopEvent);
492
493                 WaitForSingleObject(rdpdr->hotplugThread, INFINITE);
494                 rdpdr->hotplugThread = NULL;
495         }
496 }
497
498 #endif
499
500
501 static void rdpdr_process_connect(rdpdrPlugin* rdpdr)
502 {
503         UINT32 index;
504         RDPDR_DEVICE* device;
505         rdpSettings* settings;
506
507         rdpdr->devman = devman_new(rdpdr);
508         settings = (rdpSettings*) rdpdr->channelEntryPoints.pExtendedData;
509
510         strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
511
512         for (index = 0; index < settings->DeviceCount; index++)
513         {
514                 device = settings->DeviceArray[index];
515
516                 if (device->Name && (strcmp(device->Name, "*") == 0))
517                 {
518                         rdpdr->hotplugThread = CreateThread(NULL, 0,
519                                         (LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL);
520                         continue;
521                 }
522
523                 devman_load_device_service(rdpdr->devman, device);
524         }
525 }
526
527 static void rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s)
528 {
529         Stream_Read_UINT16(s, rdpdr->versionMajor);
530         Stream_Read_UINT16(s, rdpdr->versionMinor);
531         Stream_Read_UINT32(s, rdpdr->clientID);
532
533         rdpdr->sequenceId++;
534 }
535
536 static void rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
537 {
538         wStream* s;
539
540         s = Stream_New(NULL, 12);
541
542         Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
543         Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
544
545         Stream_Write_UINT16(s, rdpdr->versionMajor);
546         Stream_Write_UINT16(s, rdpdr->versionMinor);
547         Stream_Write_UINT32(s, (UINT32) rdpdr->clientID);
548
549         rdpdr_send(rdpdr, s);
550 }
551
552 static void rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
553 {
554         wStream* s;
555         WCHAR* computerNameW = NULL;
556         size_t computerNameLenW;
557
558         if (!rdpdr->computerName[0])
559                 gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1);
560
561         computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2;
562
563         s = Stream_New(NULL, 16 + computerNameLenW + 2);
564
565         Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
566         Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */
567
568         Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
569         Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
570         Stream_Write_UINT32(s, computerNameLenW + 2); /* computerNameLen, including null terminator */
571         Stream_Write(s, computerNameW, computerNameLenW);
572         Stream_Write_UINT16(s, 0); /* null terminator */
573
574         free(computerNameW);
575
576         rdpdr_send(rdpdr, s);
577 }
578
579 static void rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s)
580 {
581         UINT16 versionMajor;
582         UINT16 versionMinor;
583         UINT32 clientID;
584
585         Stream_Read_UINT16(s, versionMajor);
586         Stream_Read_UINT16(s, versionMinor);
587         Stream_Read_UINT32(s, clientID);
588
589         if (versionMajor != rdpdr->versionMajor || versionMinor != rdpdr->versionMinor)
590         {
591                 rdpdr->versionMajor = versionMajor;
592                 rdpdr->versionMinor = versionMinor;
593         }
594
595         if (clientID != rdpdr->clientID)
596         {
597                 rdpdr->clientID = clientID;
598         }
599 }
600
601 static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn)
602 {
603         int i;
604         BYTE c;
605         int pos;
606         int index;
607         wStream* s;
608         UINT32 count;
609         int data_len;
610         int count_pos;
611         DEVICE* device;
612         int keyCount;
613         ULONG_PTR* pKeys;
614
615         s = Stream_New(NULL, 256);
616
617         Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
618         Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
619
620         count_pos = (int) Stream_GetPosition(s);
621         count = 0;
622
623         Stream_Seek_UINT32(s); /* deviceCount */
624
625         pKeys = NULL;
626         keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
627
628         for (index = 0; index < keyCount; index++)
629         {
630                 device = (DEVICE*) ListDictionary_GetItemValue(rdpdr->devman->devices, (void*) pKeys[index]);
631
632                 /**
633                  * 1. versionMinor 0x0005 doesn't send PAKID_CORE_USER_LOGGEDON
634                  *    so all devices should be sent regardless of user_loggedon
635                  * 2. smartcard devices should be always sent
636                  * 3. other devices are sent only after user_loggedon
637                  */
638
639                 if ((rdpdr->versionMinor == 0x0005) ||
640                         (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn)
641                 {
642                         data_len = (int) (device->data == NULL ? 0 : Stream_GetPosition(device->data));
643                         Stream_EnsureRemainingCapacity(s, 20 + data_len);
644
645                         Stream_Write_UINT32(s, device->type); /* deviceType */
646                         Stream_Write_UINT32(s, device->id); /* deviceID */
647                         strncpy((char*) Stream_Pointer(s), device->name, 8);
648
649                         for (i = 0; i < 8; i++)
650                         {
651                                 Stream_Peek_UINT8(s, c);
652
653                                 if (c > 0x7F)
654                                         Stream_Write_UINT8(s, '_');
655                                 else
656                                         Stream_Seek_UINT8(s);
657                         }
658
659                         Stream_Write_UINT32(s, data_len);
660
661                         if (data_len > 0)
662                                 Stream_Write(s, Stream_Buffer(device->data), data_len);
663
664                         count++;
665                         WLog_INFO(TAG, "registered device #%d: %s (type=%d id=%d)",
666                                           count, device->name, device->type, device->id);
667                 }
668         }
669
670         if (pKeys)
671                 free(pKeys);
672
673         pos = (int) Stream_GetPosition(s);
674         Stream_SetPosition(s, count_pos);
675         Stream_Write_UINT32(s, count);
676         Stream_SetPosition(s, pos);
677         Stream_SealLength(s);
678
679         rdpdr_send(rdpdr, s);
680 }
681
682 static BOOL rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
683 {
684         IRP* irp;
685
686         irp = irp_new(rdpdr->devman, s);
687
688         if (!irp)
689                 return FALSE;
690
691         IFCALL(irp->device->IRPRequest, irp->device, irp);
692
693         return TRUE;
694 }
695
696 static void rdpdr_process_init(rdpdrPlugin* rdpdr)
697 {
698         int index;
699         int keyCount;
700         DEVICE* device;
701         ULONG_PTR* pKeys;
702
703         pKeys = NULL;
704         keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
705
706         for (index = 0; index < keyCount; index++)
707         {
708                 device = (DEVICE*) ListDictionary_GetItemValue(rdpdr->devman->devices, (void*) pKeys[index]);
709
710                 IFCALL(device->Init, device);
711         }
712
713         free(pKeys);
714 }
715
716 static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
717 {
718         UINT16 component;
719         UINT16 packetId;
720         UINT32 deviceId;
721         UINT32 status;
722
723         Stream_Read_UINT16(s, component); /* Component (2 bytes) */
724         Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
725
726         if (component == RDPDR_CTYP_CORE)
727         {
728                 switch (packetId)
729                 {
730                         case PAKID_CORE_SERVER_ANNOUNCE:
731                                 rdpdr_process_server_announce_request(rdpdr, s);
732                                 rdpdr_send_client_announce_reply(rdpdr);
733                                 rdpdr_send_client_name_request(rdpdr);
734                                 rdpdr_process_init(rdpdr);
735                                 break;
736
737                         case PAKID_CORE_SERVER_CAPABILITY:
738                                 rdpdr_process_capability_request(rdpdr, s);
739                                 rdpdr_send_capability_response(rdpdr);
740                                 break;
741
742                         case PAKID_CORE_CLIENTID_CONFIRM:
743                                 rdpdr_process_server_clientid_confirm(rdpdr, s);
744                                 rdpdr_send_device_list_announce_request(rdpdr, FALSE);
745                                 break;
746
747                         case PAKID_CORE_USER_LOGGEDON:
748                                 rdpdr_send_device_list_announce_request(rdpdr, TRUE);
749                                 break;
750
751                         case PAKID_CORE_DEVICE_REPLY:
752                                 /* connect to a specific resource */
753                                 Stream_Read_UINT32(s, deviceId);
754                                 Stream_Read_UINT32(s, status);
755                                 break;
756
757                         case PAKID_CORE_DEVICE_IOREQUEST:
758                                 if (rdpdr_process_irp(rdpdr, s))
759                                         s = NULL;
760                                 break;
761
762                         default:
763                                 WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_CORE unknown PacketId: 0x%04X", packetId);
764                                 break;
765
766                 }
767         }
768         else if (component == RDPDR_CTYP_PRN)
769         {
770                 WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_PRN unknown PacketId: 0x%04X", packetId);
771         }
772         else
773         {
774                 WLog_ERR(TAG, "rdpdr_process_receive: unknown message: Component: 0x%04X PacketId: 0x%04X",
775                                 component, packetId);
776         }
777
778         Stream_Free(s, TRUE);
779 }
780
781
782 /****************************************************************************************/
783
784
785 static wListDictionary* g_InitHandles;
786 static wListDictionary* g_OpenHandles;
787
788 void rdpdr_add_init_handle_data(void* pInitHandle, void* pUserData)
789 {
790         if (!g_InitHandles)
791                 g_InitHandles = ListDictionary_New(TRUE);
792
793         ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
794 }
795
796 void* rdpdr_get_init_handle_data(void* pInitHandle)
797 {
798         void* pUserData = NULL;
799         pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
800         return pUserData;
801 }
802
803 void rdpdr_remove_init_handle_data(void* pInitHandle)
804 {
805         ListDictionary_Remove(g_InitHandles, pInitHandle);
806 }
807
808 void rdpdr_add_open_handle_data(DWORD openHandle, void* pUserData)
809 {
810         void* pOpenHandle = (void*) (size_t) openHandle;
811
812         if (!g_OpenHandles)
813                 g_OpenHandles = ListDictionary_New(TRUE);
814
815         ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
816 }
817
818 void* rdpdr_get_open_handle_data(DWORD openHandle)
819 {
820         void* pUserData = NULL;
821         void* pOpenHandle = (void*) (size_t) openHandle;
822         pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
823         return pUserData;
824 }
825
826 void rdpdr_remove_open_handle_data(DWORD openHandle)
827 {
828         void* pOpenHandle = (void*) (size_t) openHandle;
829         ListDictionary_Remove(g_OpenHandles, pOpenHandle);
830 }
831
832 int rdpdr_send(rdpdrPlugin* rdpdr, wStream* s)
833 {
834         UINT32 status = 0;
835         rdpdrPlugin* plugin = (rdpdrPlugin*) rdpdr;
836
837         if (!plugin)
838         {
839                 status = CHANNEL_RC_BAD_INIT_HANDLE;
840         }
841         else
842         {
843                 status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle,
844                         Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
845         }
846
847         if (status != CHANNEL_RC_OK)
848         {
849                 Stream_Free(s, TRUE);
850                 WLog_ERR(TAG, "rdpdr_send: VirtualChannelWrite failed %d", status);
851         }
852
853         return status;
854 }
855
856 static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
857                 void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
858 {
859         wStream* data_in;
860
861         if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
862         {
863                 /*
864                  * According to MS-RDPBCGR 2.2.6.1, "All virtual channel traffic MUST be suspended.
865                  * This flag is only valid in server-to-client virtual channel traffic. It MUST be
866                  * ignored in client-to-server data." Thus it would be best practice to cease data
867                  * transmission. However, simply returning here avoids a crash.
868                  */
869                 return;
870         }
871
872         if (dataFlags & CHANNEL_FLAG_FIRST)
873         {
874                 if (rdpdr->data_in)
875                         Stream_Free(rdpdr->data_in, TRUE);
876
877                 rdpdr->data_in = Stream_New(NULL, totalLength);
878         }
879
880         data_in = rdpdr->data_in;
881         Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
882         Stream_Write(data_in, pData, dataLength);
883
884         if (dataFlags & CHANNEL_FLAG_LAST)
885         {
886                 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
887                 {
888                         WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received: read error\n");
889                 }
890
891                 rdpdr->data_in = NULL;
892                 Stream_SealLength(data_in);
893                 Stream_SetPosition(data_in, 0);
894
895                 MessageQueue_Post(rdpdr->queue, NULL, 0, (void*) data_in, NULL);
896         }
897 }
898
899 static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT event,
900                 LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
901 {
902         rdpdrPlugin* rdpdr;
903
904         rdpdr = (rdpdrPlugin*) rdpdr_get_open_handle_data(openHandle);
905
906         if (!rdpdr)
907         {
908                 WLog_ERR(TAG, "rdpdr_virtual_channel_open_event: error no match\n");
909                 return;
910         }
911
912         switch (event)
913         {
914                 case CHANNEL_EVENT_DATA_RECEIVED:
915                         rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength, totalLength, dataFlags);
916                         break;
917
918                 case CHANNEL_EVENT_WRITE_COMPLETE:
919                         Stream_Free((wStream*) pData, TRUE);
920                         break;
921         }
922 }
923
924 static void* rdpdr_virtual_channel_client_thread(void* arg)
925 {
926         wStream* data;
927         wMessage message;
928         rdpdrPlugin* rdpdr = (rdpdrPlugin*) arg;
929
930         rdpdr_process_connect(rdpdr);
931
932         while (1)
933         {
934                 if (!MessageQueue_Wait(rdpdr->queue))
935                         break;
936
937                 if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
938                 {
939                         if (message.id == WMQ_QUIT)
940                                 break;
941
942                         if (message.id == 0)
943                         {
944                                 data = (wStream*) message.wParam;
945                                 rdpdr_process_receive(rdpdr, data);
946                         }
947                 }
948         }
949
950         ExitThread(0);
951         return NULL;
952 }
953
954 static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pData, UINT32 dataLength)
955 {
956         UINT32 status;
957
958         status = rdpdr->channelEntryPoints.pVirtualChannelOpen(rdpdr->InitHandle,
959                 &rdpdr->OpenHandle, rdpdr->channelDef.name, rdpdr_virtual_channel_open_event);
960
961         rdpdr_add_open_handle_data(rdpdr->OpenHandle, rdpdr);
962
963         if (status != CHANNEL_RC_OK)
964         {
965                 WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected: open failed: status: %d\n", status);
966                 return;
967         }
968
969         rdpdr->queue = MessageQueue_New(NULL);
970
971         rdpdr->thread = CreateThread(NULL, 0,
972                         (LPTHREAD_START_ROUTINE) rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, NULL);
973 }
974
975 static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
976 {
977         if (rdpdr->queue)
978         {
979                 MessageQueue_PostQuit(rdpdr->queue, 0);
980                 WaitForSingleObject(rdpdr->thread, INFINITE);
981
982                 MessageQueue_Free(rdpdr->queue);
983                 rdpdr->queue = NULL;
984
985                 CloseHandle(rdpdr->thread);
986                 rdpdr->thread = NULL;
987         }
988
989         drive_hotplug_thread_terminate(rdpdr);
990
991         rdpdr->channelEntryPoints.pVirtualChannelClose(rdpdr->OpenHandle);
992
993         if (rdpdr->data_in)
994         {
995                 Stream_Free(rdpdr->data_in, TRUE);
996                 rdpdr->data_in = NULL;
997         }
998
999         if (rdpdr->devman)
1000         {
1001                 devman_free(rdpdr->devman);
1002                 rdpdr->devman = NULL;
1003         }
1004
1005         rdpdr_remove_open_handle_data(rdpdr->OpenHandle);
1006         rdpdr_remove_init_handle_data(rdpdr->InitHandle);
1007
1008         free(rdpdr);
1009 }
1010
1011 static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
1012 {
1013         rdpdrPlugin* rdpdr;
1014
1015         rdpdr = (rdpdrPlugin*) rdpdr_get_init_handle_data(pInitHandle);
1016
1017         if (!rdpdr)
1018         {
1019                 WLog_ERR(TAG, "rdpdr_virtual_channel_init_event: error no match");
1020                 return;
1021         }
1022
1023         switch (event)
1024         {
1025                 case CHANNEL_EVENT_CONNECTED:
1026                         rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength);
1027                         break;
1028
1029                 case CHANNEL_EVENT_DISCONNECTED:
1030                         break;
1031
1032                 case CHANNEL_EVENT_TERMINATED:
1033                         rdpdr_virtual_channel_event_terminated(rdpdr);
1034                         break;
1035         }
1036 }
1037
1038 /* rdpdr is always built-in */
1039 #define VirtualChannelEntry     rdpdr_VirtualChannelEntry
1040
1041 BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
1042 {
1043         rdpdrPlugin* rdpdr;
1044
1045         rdpdr = (rdpdrPlugin*) calloc(1, sizeof(rdpdrPlugin));
1046
1047         if (!rdpdr)
1048                 return -1;
1049
1050         rdpdr->channelDef.options =
1051                         CHANNEL_OPTION_INITIALIZED |
1052                         CHANNEL_OPTION_ENCRYPT_RDP |
1053                         CHANNEL_OPTION_COMPRESS_RDP;
1054
1055         strcpy(rdpdr->channelDef.name, "rdpdr");
1056
1057         rdpdr->sequenceId = 0;
1058
1059         CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
1060
1061         rdpdr->channelEntryPoints.pVirtualChannelInit(&rdpdr->InitHandle,
1062                 &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpdr_virtual_channel_init_event);
1063
1064         rdpdr_add_init_handle_data(rdpdr->InitHandle, (void*) rdpdr);
1065
1066         return 1;
1067 }