FreeRDP
Loading...
Searching...
No Matches
server/rdpdr_main.c
1
24#include <freerdp/config.h>
25#include <freerdp/freerdp.h>
26#include <freerdp/utils/rdpdr_utils.h>
27
28#include <winpr/crt.h>
29#include <winpr/assert.h>
30#include <winpr/nt.h>
31#include <winpr/print.h>
32#include <winpr/stream.h>
33
34#include <freerdp/channels/log.h>
35#include <freerdp/channels/scard.h>
36#include <freerdp/utils/smartcard_operations.h>
37#include "rdpdr_main.h"
38#include <freerdp/utils/channel_pdu_tracker.h>
39
40#define RDPDR_ADD_PRINTER_EVENT 0x00000001
41#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002
42#define RDPDR_DELETE_PRINTER_EVENT 0x00000003
43#define RDPDR_RENAME_PRINTER_EVENT 0x00000004
44
45#define RDPDR_HEADER_LENGTH 4
46#define RDPDR_CAPABILITY_HEADER_LENGTH 8
47
48/* [MS-RDPESC] 3.2.5.1: the output buffer length SHOULD be set to 2048 */
49#define SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH 2048
50
51struct s_rdpdr_server_private
52{
53 HANDLE Thread;
54 HANDLE StopEvent;
55 void* ChannelHandle;
56
57 UINT32 ClientId;
58 UINT16 VersionMajor;
59 UINT16 VersionMinor;
60 char* ClientComputerName;
61
62 BOOL UserLoggedOnPdu;
63
64 wListDictionary* IrpList;
65 UINT32 NextCompletionId;
66
67 wHashTable* devicelist;
68 wLog* log;
69 UINT32 SpecialDeviceTypeCap;
70 UINT32 IoCode1;
71 UINT32 ExtendedPDU;
72 BOOL haveSmartcardDevice;
73 UINT32 smartcardDeviceId;
74};
75
76static const char* fileInformation2str(uint8_t val)
77{
78 switch (val)
79 {
80 case FILE_SUPERSEDED:
81 return "FILE_DOES_NOT_EXIST";
82 case FILE_OPENED:
83 return "FILE_EXISTS";
84 case FILE_CREATED:
85 return "FILE_OVERWRITTEN";
86 case FILE_OVERWRITTEN:
87 return "FILE_CREATED";
88 case FILE_EXISTS:
89 return "FILE_OPENED";
90 case FILE_DOES_NOT_EXIST:
91 return "FILE_SUPERSEDED";
92 default:
93 return "FILE_UNKNOWN";
94 }
95}
96
97static const char* DR_DRIVE_LOCK_REQ2str(uint32_t op)
98{
99 switch (op)
100 {
101 case RDP_LOWIO_OP_SHAREDLOCK:
102 return "RDP_LOWIO_OP_UNLOCK_MULTIPLE";
103 case RDP_LOWIO_OP_EXCLUSIVELOCK:
104 return "RDP_LOWIO_OP_UNLOCK";
105 case RDP_LOWIO_OP_UNLOCK:
106 return "RDP_LOWIO_OP_EXCLUSIVELOCK";
107 case RDP_LOWIO_OP_UNLOCK_MULTIPLE:
108 return "RDP_LOWIO_OP_SHAREDLOCK";
109 default:
110 return "RDP_LOWIO_OP_UNKNOWN";
111 }
112}
113
114static void rdpdr_device_free(RdpdrDevice* device)
115{
116 if (!device)
117 return;
118 free(device->DeviceData);
119 free(device);
120}
121
122static void rdpdr_device_free_h(void* obj)
123{
124 RdpdrDevice* other = obj;
125 rdpdr_device_free(other);
126}
127
128static UINT32 rdpdr_deviceid_hash(const void* id)
129{
130 WINPR_ASSERT(id);
131 return *((const UINT32*)id);
132}
133
134static BOOL rdpdr_device_equal(const void* v1, const void* v2)
135{
136 const UINT32* p1 = (const UINT32*)v1;
137 const UINT32* p2 = (const UINT32*)v2;
138 if (!p1 && !p2)
139 return TRUE;
140 if (!p1 || !p2)
141 return FALSE;
142 return *p1 == *p2;
143}
144
145static RdpdrDevice* rdpdr_device_new(void)
146{
147 return calloc(1, sizeof(RdpdrDevice));
148}
149
150static void* rdpdr_device_clone(const void* val)
151{
152 const RdpdrDevice* other = val;
153
154 if (!other)
155 return nullptr;
156
157 RdpdrDevice* tmp = rdpdr_device_new();
158 if (!tmp)
159 goto fail;
160
161 *tmp = *other;
162 if (other->DeviceData)
163 {
164 tmp->DeviceData = malloc(other->DeviceDataLength);
165 if (!tmp->DeviceData)
166 goto fail;
167 memcpy(tmp->DeviceData, other->DeviceData, other->DeviceDataLength);
168 }
169 return tmp;
170
171fail:
172 rdpdr_device_free(tmp);
173 return nullptr;
174}
175
176static void* rdpdr_device_key_clone(const void* pvval)
177{
178 const UINT32* val = pvval;
179 if (!val)
180 return nullptr;
181
182 UINT32* ptr = calloc(1, sizeof(UINT32));
183 if (!ptr)
184 return nullptr;
185 *ptr = *val;
186 return ptr;
187}
188
189static void rdpdr_device_key_free(void* obj)
190{
191 free(obj);
192}
193
194static RdpdrDevice* rdpdr_get_device_by_id(RdpdrServerPrivate* priv, UINT32 DeviceId)
195{
196 WINPR_ASSERT(priv);
197 return HashTable_GetItemValue(priv->devicelist, &DeviceId);
198}
199
200static BOOL rdpdr_remove_device_by_id(RdpdrServerPrivate* priv, UINT32 DeviceId)
201{
202 WINPR_ASSERT(priv);
203
204 const RdpdrDevice* device = rdpdr_get_device_by_id(priv, DeviceId);
205 if (!device)
206 {
207 WLog_Print(priv->log, WLOG_WARN, "[del] Device Id: 0x%08" PRIX32 ": no such device",
208 DeviceId);
209 return FALSE;
210 }
211 WLog_Print(priv->log, WLOG_DEBUG,
212 "[del] Device Name: %s Id: 0x%08" PRIX32 " DataLength: %" PRIu32 "",
213 device->PreferredDosName, device->DeviceId, device->DeviceDataLength);
214 return HashTable_Remove(priv->devicelist, &DeviceId);
215}
216
217static BOOL rdpdr_add_device(RdpdrServerPrivate* priv, const RdpdrDevice* device)
218{
219 WINPR_ASSERT(priv);
220 WINPR_ASSERT(device);
221
222 WLog_Print(priv->log, WLOG_DEBUG,
223 "[add] Device Name: %s Id: 0x%08" PRIX32 " DataLength: %" PRIu32 "",
224 device->PreferredDosName, device->DeviceId, device->DeviceDataLength);
225
226 return HashTable_Insert(priv->devicelist, &device->DeviceId, device);
227}
228
229static UINT32 g_ClientId = 0;
230
231static const WCHAR* rdpdr_read_ustring(wLog* log, wStream* s, size_t bytelen)
232{
233 const size_t charlen = bytelen / sizeof(WCHAR);
234 const WCHAR* str = Stream_ConstPointer(s);
235 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bytelen))
236 return nullptr;
237 if (_wcsnlen(str, charlen) == charlen)
238 {
239 WLog_Print(log, WLOG_WARN, "[rdpdr] unicode string not '\\0' terminated");
240 return nullptr;
241 }
242 Stream_Seek(s, bytelen);
243 return str;
244}
245
246static RDPDR_IRP* rdpdr_server_irp_new(void)
247{
248 RDPDR_IRP* irp = (RDPDR_IRP*)calloc(1, sizeof(RDPDR_IRP));
249 return irp;
250}
251
252static void rdpdr_server_irp_free(RDPDR_IRP* irp)
253{
254 free(irp);
255}
256
257static void rdpdr_server_list_free(void* ptr)
258{
259 RDPDR_IRP* irp = ptr;
260 rdpdr_server_irp_free(irp);
261}
262static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp)
263{
264 WINPR_ASSERT(context);
265 WINPR_ASSERT(context->priv);
266
267 RdpdrServerPrivate* priv = context->priv;
268 const uintptr_t key = irp->CompletionId + 1ull;
269 return ListDictionary_Add(priv->IrpList, (void*)key, irp);
270}
271
272static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 completionId)
273{
274 WINPR_ASSERT(context);
275 WINPR_ASSERT(context->priv);
276
277 RdpdrServerPrivate* priv = context->priv;
278 const uintptr_t key = completionId + 1ull;
279 RDPDR_IRP* irp = (RDPDR_IRP*)ListDictionary_Take(priv->IrpList, (void*)key);
280 return irp;
281}
282
283static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s)
284{
285 WINPR_ASSERT(context);
286 WINPR_ASSERT(context->priv);
287 WINPR_ASSERT(s);
288
289 RdpdrServerPrivate* priv = context->priv;
290 Stream_SealLength(s);
291 const size_t length = Stream_Length(s);
292 WINPR_ASSERT(length <= UINT32_MAX);
293 Stream_ResetPosition(s);
294
295 if (length >= RDPDR_HEADER_LENGTH)
296 {
297 const RDPDR_HEADER header = {
298 .Component = Stream_Get_UINT16(s),
299 .PacketId = Stream_Get_UINT16(s),
300 };
301
302 WLog_Print(priv->log, WLOG_DEBUG,
303 "sending message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]",
304 rdpdr_component_string(header.Component), header.Component,
305 rdpdr_packetid_string(header.PacketId), header.PacketId);
306 }
307 winpr_HexLogDump(priv->log, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s));
308 ULONG written = 0;
309 BOOL status = WTSVirtualChannelWrite(priv->ChannelHandle, Stream_BufferAs(s, char),
310 (ULONG)length, &written);
311 Stream_Release(s);
312 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
313}
314
320static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context)
321{
322 WINPR_ASSERT(context);
323 WINPR_ASSERT(context->priv);
324
325 UINT error = IFCALLRESULT(CHANNEL_RC_OK, context->SendServerAnnounce, context);
326 if (error != CHANNEL_RC_OK)
327 return error;
328
329 RdpdrServerPrivate* priv = context->priv;
330 wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8);
331 if (!s)
332 {
333 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
334 return CHANNEL_RC_NO_MEMORY;
335 }
336
337 const RDPDR_HEADER header = {
338 .Component = RDPDR_CTYP_CORE,
339 .PacketId = PAKID_CORE_SERVER_ANNOUNCE,
340 };
341 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
342 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
343 Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */
344 Stream_Write_UINT16(s, priv->VersionMinor); /* VersionMinor (2 bytes) */
345 Stream_Write_UINT32(s, priv->ClientId); /* ClientId (4 bytes) */
346 return rdpdr_seal_send_free_request(context, s);
347}
348
354static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, wStream* s,
355 const RDPDR_HEADER* header)
356{
357 WINPR_ASSERT(context);
358 WINPR_ASSERT(context->priv);
359 WINPR_ASSERT(header);
360
361 RdpdrServerPrivate* priv = context->priv;
362
363 WINPR_UNUSED(header);
364
365 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8))
366 return ERROR_INVALID_DATA;
367
368 const UINT16 VersionMajor = Stream_Get_UINT16(s); /* VersionMajor (2 bytes) */
369 const UINT16 VersionMinor = Stream_Get_UINT16(s); /* VersionMinor (2 bytes) */
370 const UINT32 ClientId = Stream_Get_UINT32(s); /* ClientId (4 bytes) */
371 WLog_Print(priv->log, WLOG_DEBUG,
372 "Client Announce Response: VersionMajor: 0x%08" PRIX16 " VersionMinor: 0x%04" PRIX16
373 " ClientId: 0x%08" PRIX32 "",
374 VersionMajor, VersionMinor, ClientId);
375 priv->ClientId = ClientId;
376
377 return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveAnnounceResponse, context, VersionMajor,
378 VersionMinor, ClientId);
379}
380
386static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context, wStream* s,
387 const RDPDR_HEADER* header)
388{
389 WINPR_ASSERT(context);
390 WINPR_ASSERT(context->priv);
391 WINPR_ASSERT(s);
392 WINPR_ASSERT(header);
393 WINPR_UNUSED(header);
394
395 RdpdrServerPrivate* priv = context->priv;
396
397 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12))
398 return ERROR_INVALID_DATA;
399
400 UINT32 UnicodeFlag = Stream_Get_UINT32(s); /* UnicodeFlag (4 bytes) */
401 const UINT32 CodePage = Stream_Get_UINT32(s); /* CodePage (4 bytes) */
402 const UINT32 ComputerNameLen = Stream_Get_UINT32(s); /* ComputerNameLen (4 bytes) */
403 /* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored.
404 */
405 UnicodeFlag = UnicodeFlag & 0x00000001;
406
407 if (CodePage != 0)
408 WLog_Print(priv->log, WLOG_WARN,
409 "[MS-RDPEFS] 2.2.2.4 Client Name Request (DR_CORE_CLIENT_NAME_REQ)::CodePage "
410 "must be 0, but is 0x%08" PRIx32,
411 CodePage);
412
418 if (UnicodeFlag)
419 {
420 if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2)
421 {
422 WLog_Print(priv->log, WLOG_ERROR, "invalid unicode computer name length: %" PRIu32 "",
423 ComputerNameLen);
424 return ERROR_INVALID_DATA;
425 }
426 }
427 else
428 {
429 if (ComputerNameLen > 256 || ComputerNameLen < 1)
430 {
431 WLog_Print(priv->log, WLOG_ERROR, "invalid ascii computer name length: %" PRIu32 "",
432 ComputerNameLen);
433 return ERROR_INVALID_DATA;
434 }
435 }
436
437 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, ComputerNameLen))
438 return ERROR_INVALID_DATA;
439
440 /* ComputerName must be null terminated, check if it really is */
441 const char* computerName = Stream_ConstPointer(s);
442 if (computerName[ComputerNameLen - 1] || (UnicodeFlag && computerName[ComputerNameLen - 2]))
443 {
444 WLog_Print(priv->log, WLOG_ERROR, "computer name must be null terminated");
445 return ERROR_INVALID_DATA;
446 }
447
448 if (priv->ClientComputerName)
449 {
450 free(priv->ClientComputerName);
451 priv->ClientComputerName = nullptr;
452 }
453
454 if (UnicodeFlag)
455 {
456 priv->ClientComputerName =
457 Stream_Read_UTF16_String_As_UTF8(s, ComputerNameLen / sizeof(WCHAR), nullptr);
458 if (!priv->ClientComputerName)
459 {
460 WLog_Print(priv->log, WLOG_ERROR, "failed to convert client computer name");
461 return ERROR_INVALID_DATA;
462 }
463 }
464 else
465 {
466 const char* name = Stream_ConstPointer(s);
467 priv->ClientComputerName = _strdup(name);
468 Stream_Seek(s, ComputerNameLen);
469
470 if (!priv->ClientComputerName)
471 {
472 WLog_Print(priv->log, WLOG_ERROR, "failed to duplicate client computer name");
473 return CHANNEL_RC_NO_MEMORY;
474 }
475 }
476
477 WLog_Print(priv->log, WLOG_DEBUG, "ClientComputerName: %s", priv->ClientComputerName);
478 return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveClientNameRequest, context, ComputerNameLen,
479 priv->ClientComputerName);
480}
481
482static UINT rdpdr_server_write_capability_set_header_cb(RdpdrServerContext* context, wStream* s,
483 const RDPDR_CAPABILITY_HEADER* header)
484{
485 WINPR_ASSERT(context);
486 WINPR_ASSERT(context->priv);
487
488 RdpdrServerPrivate* priv = context->priv;
489 UINT error = rdpdr_write_capset_header(priv->log, s, header);
490 if (error != CHANNEL_RC_OK)
491 return error;
492
493 return IFCALLRESULT(CHANNEL_RC_OK, context->SendCaps, context, header, 0, nullptr);
494}
495
501static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context, wStream* s,
502 const RDPDR_CAPABILITY_HEADER* header)
503{
504 WINPR_ASSERT(context);
505 WINPR_ASSERT(context->priv);
506 WINPR_ASSERT(header);
507
508 RdpdrServerPrivate* priv = context->priv;
509
510 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
511 return ERROR_INVALID_DATA;
512
513 const UINT32 OsType = Stream_Get_UINT32(s); /* osType (4 bytes),
514 ignored on receipt */
515 const UINT32 OsVersion = Stream_Get_UINT32(s); /* osVersion (4 bytes),
516 unused and must be set to zero */
517 const UINT32 VersionMajor = Stream_Get_UINT16(s); /* protocolMajorVersion (2 bytes) */
518 const UINT32 VersionMinor = Stream_Get_UINT16(s); /* protocolMinorVersion (2 bytes) */
519 const UINT32 IoCode1 = Stream_Get_UINT32(s); /* ioCode1 (4 bytes) */
520 const UINT32 IoCode2 = Stream_Get_UINT32(s); /* ioCode2 (4 bytes),
521 must be set to zero, reserved for future use */
522 const UINT32 ExtendedPdu = Stream_Get_UINT32(s); /* extendedPdu (4 bytes) */
523 const UINT32 ExtraFlags1 = Stream_Get_UINT32(s); /* extraFlags1 (4 bytes) */
524 const UINT32 ExtraFlags2 = Stream_Get_UINT32(s); /* extraFlags2 (4 bytes),
525 must be set to zero, reserved for future use */
526
527 {
528 char buffer[1024] = WINPR_C_ARRAY_INIT;
529 WLog_Print(priv->log, WLOG_TRACE,
530 "OsType=%" PRIu32 ", OsVersion=%" PRIu32 ", VersionMajor=%" PRIu32
531 ", VersionMinor=%" PRIu32 ", IoCode1=%s, IoCode2=%" PRIu32
532 ", ExtendedPdu=%" PRIu32 ", ExtraFlags1=%" PRIu32 ", ExtraFlags2=%" PRIu32,
533 OsType, OsVersion, VersionMajor, VersionMinor,
534 rdpdr_irp_mask2str(IoCode1, buffer, sizeof(buffer)), IoCode2, ExtendedPdu,
535 ExtraFlags1, ExtraFlags2);
536 }
537
538 if (VersionMajor != RDPDR_MAJOR_RDP_VERSION)
539 {
540 WLog_Print(priv->log, WLOG_ERROR, "unsupported RDPDR version %" PRIu16 ".%" PRIu16,
541 VersionMajor, VersionMinor);
542 return ERROR_INVALID_DATA;
543 }
544
545 switch (VersionMinor)
546 {
547 case RDPDR_MINOR_RDP_VERSION_13:
548 case RDPDR_MINOR_RDP_VERSION_6_X:
549 case RDPDR_MINOR_RDP_VERSION_5_2:
550 case RDPDR_MINOR_RDP_VERSION_5_1:
551 case RDPDR_MINOR_RDP_VERSION_5_0:
552 break;
553 default:
554 WLog_Print(priv->log, WLOG_WARN, "unsupported RDPDR minor version %" PRIu16 ".%" PRIu16,
555 VersionMajor, VersionMinor);
556 break;
557 }
558
559 UINT32 SpecialTypeDeviceCap = 0;
560 if (header->Version == GENERAL_CAPABILITY_VERSION_02)
561 {
562 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
563 return ERROR_INVALID_DATA;
564
565 SpecialTypeDeviceCap = Stream_Get_UINT32(s); /* SpecialTypeDeviceCap (4 bytes) */
566 }
567 priv->SpecialDeviceTypeCap = SpecialTypeDeviceCap;
568
569 const UINT32 mask =
570 RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
571 RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
572 RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
573 RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
574 RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL;
575
576 if ((IoCode1 & mask) == 0)
577 {
578 char buffer[1024] = WINPR_C_ARRAY_INIT;
579 WLog_Print(priv->log, WLOG_ERROR, "Missing IRP mask values %s",
580 rdpdr_irp_mask2str(IoCode1 & mask, buffer, sizeof(buffer)));
581 return ERROR_INVALID_DATA;
582 }
583 priv->IoCode1 = IoCode1;
584
585 if (IoCode2 != 0)
586 {
587 WLog_Print(priv->log, WLOG_WARN,
588 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ioCode2 is "
589 "reserved for future use, expected value 0 got %" PRIu32,
590 IoCode2);
591 }
592
593 if ((ExtendedPdu & RDPDR_CLIENT_DISPLAY_NAME_PDU) == 0)
594 {
595 WLog_Print(priv->log, WLOG_WARN,
596 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) extendedPDU "
597 "should always set RDPDR_CLIENT_DISPLAY_NAME_PDU[0x00000002]");
598 }
599
600 priv->ExtendedPDU = ExtendedPdu;
601 priv->UserLoggedOnPdu = (ExtendedPdu & RDPDR_USER_LOGGEDON_PDU) != 0;
602
603 if (ExtraFlags2 != 0)
604 {
605 WLog_Print(priv->log, WLOG_WARN,
606 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ExtraFlags2 is "
607 "reserved for future use, expected value 0 got %" PRIu32,
608 ExtraFlags2);
609 }
610
611 return CHANNEL_RC_OK;
612}
613
619static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* context, wStream* s)
620{
621 WINPR_ASSERT(context);
622 WINPR_ASSERT(context->priv);
623
624 const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
625 GENERAL_CAPABILITY_VERSION_02 };
626
627 UINT32 ioCode1 = 0;
628 ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */
629 ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */
630 ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */
631 ioCode1 |= RDPDR_IRP_MJ_READ; /* always set */
632 ioCode1 |= RDPDR_IRP_MJ_WRITE; /* always set */
633 ioCode1 |= RDPDR_IRP_MJ_FLUSH_BUFFERS; /* always set */
634 ioCode1 |= RDPDR_IRP_MJ_SHUTDOWN; /* always set */
635 ioCode1 |= RDPDR_IRP_MJ_DEVICE_CONTROL; /* always set */
636 ioCode1 |= RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION; /* always set */
637 ioCode1 |= RDPDR_IRP_MJ_SET_VOLUME_INFORMATION; /* always set */
638 ioCode1 |= RDPDR_IRP_MJ_QUERY_INFORMATION; /* always set */
639 ioCode1 |= RDPDR_IRP_MJ_SET_INFORMATION; /* always set */
640 ioCode1 |= RDPDR_IRP_MJ_DIRECTORY_CONTROL; /* always set */
641 ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */
642 ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */
643 ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */
644
645 UINT32 extendedPdu = 0;
646 extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */
647 extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */
648
649 RdpdrServerPrivate* priv = context->priv;
650 if (priv->UserLoggedOnPdu)
651 extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */
652
653 UINT32 extraFlags1 = 0;
654 extraFlags1 |= ENABLE_ASYNCIO; /* optional */
655 UINT32 SpecialTypeDeviceCap = 0;
656
657 UINT error = rdpdr_write_capset_header(priv->log, s, &header);
658 if (error != CHANNEL_RC_OK)
659 return error;
660
661 const BYTE* data = Stream_ConstPointer(s);
662 const size_t start = Stream_GetPosition(s);
663 Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */
664 Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */
665 Stream_Write_UINT16(s, priv->VersionMajor); /* protocolMajorVersion (2 bytes) */
666 Stream_Write_UINT16(s, priv->VersionMinor); /* protocolMinorVersion (2 bytes) */
667 Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */
668 Stream_Write_UINT32(s, 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */
669 Stream_Write_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */
670 Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
671 Stream_Write_UINT32(
672 s, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
673 Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
674 const size_t end = Stream_GetPosition(s);
675 return IFCALLRESULT(CHANNEL_RC_OK, context->SendCaps, context, &header, end - start, data);
676}
677
683static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, wStream* s,
684 const RDPDR_CAPABILITY_HEADER* header)
685{
686 WINPR_ASSERT(context);
687 WINPR_ASSERT(context->priv);
688 WINPR_ASSERT(s);
689 WINPR_ASSERT(header);
690 WINPR_UNUSED(context);
691 WINPR_UNUSED(header);
692 WINPR_UNUSED(s);
693
694 return CHANNEL_RC_OK;
695}
696
702static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s)
703{
704 WINPR_UNUSED(context);
705 WINPR_ASSERT(context);
706 WINPR_ASSERT(context->priv);
707
708 const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
709 PRINT_CAPABILITY_VERSION_01 };
710
711 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
712}
713
719static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wStream* s,
720 const RDPDR_CAPABILITY_HEADER* header)
721{
722 WINPR_UNUSED(context);
723 WINPR_UNUSED(s);
724 WINPR_UNUSED(header);
725 WINPR_ASSERT(context);
726 WINPR_ASSERT(context->priv);
727
728 return CHANNEL_RC_OK;
729}
730
736static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s)
737{
738 WINPR_UNUSED(context);
739 WINPR_ASSERT(context);
740 WINPR_ASSERT(context->priv);
741
742 const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
743 PORT_CAPABILITY_VERSION_01 };
744
745 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
746}
747
753static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, wStream* s,
754 const RDPDR_CAPABILITY_HEADER* header)
755{
756 WINPR_ASSERT(context);
757 WINPR_ASSERT(context->priv);
758 WINPR_UNUSED(context);
759 WINPR_UNUSED(header);
760 WINPR_UNUSED(s);
761
762 return CHANNEL_RC_OK;
763}
764
770static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s)
771{
772 WINPR_ASSERT(context);
773 WINPR_ASSERT(context->priv);
774 WINPR_UNUSED(context);
775
776 const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
777 DRIVE_CAPABILITY_VERSION_02 };
778
779 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
780}
781
787static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* context, wStream* s,
788 const RDPDR_CAPABILITY_HEADER* header)
789{
790 WINPR_ASSERT(context);
791 WINPR_ASSERT(context->priv);
792 WINPR_UNUSED(context);
793 WINPR_UNUSED(header);
794 WINPR_UNUSED(s);
795
796 return CHANNEL_RC_OK;
797}
798
804static UINT rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s)
805{
806 WINPR_ASSERT(context);
807 WINPR_ASSERT(context->priv);
808 WINPR_UNUSED(context);
809
810 const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
811 SMARTCARD_CAPABILITY_VERSION_01 };
812
813 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
814}
815
821static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* context)
822{
823 WINPR_ASSERT(context);
824 WINPR_ASSERT(context->priv);
825
826 UINT16 numCapabilities = 1;
827 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
828 numCapabilities++;
829
830 if (((context->supported & RDPDR_DTYP_PARALLEL) != 0) ||
831 ((context->supported & RDPDR_DTYP_SERIAL) != 0))
832 numCapabilities++;
833
834 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
835 numCapabilities++;
836
837 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
838 numCapabilities++;
839
840 RdpdrServerPrivate* priv = context->priv;
841 wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 512);
842 if (!s)
843 {
844 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
845 return CHANNEL_RC_NO_MEMORY;
846 }
847
848 const RDPDR_HEADER header = {
849 .Component = RDPDR_CTYP_CORE,
850 .PacketId = PAKID_CORE_SERVER_CAPABILITY,
851 };
852 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
853 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
854 Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
855 Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
856
857 UINT error = 0;
858 if ((error = rdpdr_server_write_general_capability_set(context, s)))
859 {
860 WLog_Print(priv->log, WLOG_ERROR,
861 "rdpdr_server_write_general_capability_set failed with error %" PRIu32 "!",
862 error);
863 goto out;
864 }
865
866 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
867 {
868 if ((error = rdpdr_server_write_drive_capability_set(context, s)))
869 {
870 WLog_Print(priv->log, WLOG_ERROR,
871 "rdpdr_server_write_drive_capability_set failed with error %" PRIu32 "!",
872 error);
873 goto out;
874 }
875 }
876
877 if (((context->supported & RDPDR_DTYP_PARALLEL) != 0) ||
878 ((context->supported & RDPDR_DTYP_SERIAL) != 0))
879 {
880 if ((error = rdpdr_server_write_port_capability_set(context, s)))
881 {
882 WLog_Print(priv->log, WLOG_ERROR,
883 "rdpdr_server_write_port_capability_set failed with error %" PRIu32 "!",
884 error);
885 goto out;
886 }
887 }
888
889 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
890 {
891 if ((error = rdpdr_server_write_printer_capability_set(context, s)))
892 {
893 WLog_Print(priv->log, WLOG_ERROR,
894 "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!",
895 error);
896 goto out;
897 }
898 }
899
900 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
901 {
902 if ((error = rdpdr_server_write_smartcard_capability_set(context, s)))
903 {
904 WLog_Print(priv->log, WLOG_ERROR,
905 "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!",
906 error);
907 goto out;
908 }
909 }
910
911 return rdpdr_seal_send_free_request(context, s);
912out:
913 Stream_Release(s);
914 return error;
915}
916
917static UINT16 rdpdr_cap_type_to_dtyp(UINT16 capabilityType)
918{
919 switch (capabilityType)
920 {
921 case CAP_PRINTER_TYPE:
922 return RDPDR_DTYP_PRINT;
923 case CAP_PORT_TYPE:
924 return RDPDR_DTYP_SERIAL | RDPDR_DTYP_PARALLEL;
925 case CAP_DRIVE_TYPE:
926 return RDPDR_DTYP_FILESYSTEM;
927 case CAP_SMARTCARD_TYPE:
928 return RDPDR_DTYP_SMARTCARD;
929 case CAP_GENERAL_TYPE:
930 default:
931 return 0;
932 }
933}
934
940static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* context, wStream* s,
941 const RDPDR_HEADER* header)
942{
943 WINPR_ASSERT(context);
944 WINPR_ASSERT(context->priv);
945
946 RdpdrServerPrivate* priv = context->priv;
947
948 WINPR_UNUSED(header);
949
950 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
951 return ERROR_INVALID_DATA;
952
953 const UINT16 numCapabilities = Stream_Get_UINT16(s); /* numCapabilities (2 bytes) */
954 Stream_Seek_UINT16(s); /* Padding (2 bytes) */
955
956 UINT16 caps = 0;
957 for (UINT16 i = 0; i < numCapabilities; i++)
958 {
959 RDPDR_CAPABILITY_HEADER capabilityHeader = WINPR_C_ARRAY_INIT;
960 const size_t start = Stream_GetPosition(s);
961
962 UINT status = 0;
963 if ((status = rdpdr_read_capset_header(priv->log, s, &capabilityHeader)))
964 {
965 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
966 return status;
967 }
968
969 status = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveCaps, context, &capabilityHeader,
970 Stream_GetRemainingLength(s), Stream_ConstPointer(s));
971 if (status != CHANNEL_RC_OK)
972 return status;
973
974 switch (capabilityHeader.CapabilityType)
975 {
976 case CAP_GENERAL_TYPE:
977 if ((status =
978 rdpdr_server_read_general_capability_set(context, s, &capabilityHeader)))
979 {
980 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
981 return status;
982 }
983
984 break;
985
986 case CAP_PRINTER_TYPE:
987 if ((status =
988 rdpdr_server_read_printer_capability_set(context, s, &capabilityHeader)))
989 {
990 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
991 return status;
992 }
993
994 break;
995
996 case CAP_PORT_TYPE:
997 if ((status = rdpdr_server_read_port_capability_set(context, s, &capabilityHeader)))
998 {
999 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
1000 return status;
1001 }
1002
1003 break;
1004
1005 case CAP_DRIVE_TYPE:
1006 if ((status =
1007 rdpdr_server_read_drive_capability_set(context, s, &capabilityHeader)))
1008 {
1009 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
1010 return status;
1011 }
1012
1013 break;
1014
1015 case CAP_SMARTCARD_TYPE:
1016 if ((status =
1017 rdpdr_server_read_smartcard_capability_set(context, s, &capabilityHeader)))
1018 {
1019 WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
1020 return status;
1021 }
1022
1023 break;
1024
1025 default:
1026 WLog_Print(priv->log, WLOG_WARN, "Unknown capabilityType %" PRIu16 "",
1027 capabilityHeader.CapabilityType);
1028 Stream_Seek(s, capabilityHeader.CapabilityLength);
1029 return ERROR_INVALID_DATA;
1030 }
1031
1032 const UINT16 client_dtyp = rdpdr_cap_type_to_dtyp(capabilityHeader.CapabilityType);
1033 if ((client_dtyp != 0) && ((client_dtyp & context->supported) == 0))
1034 {
1035 WLog_Print(priv->log, WLOG_WARN, "client sent capability %s we did not announce!",
1036 rdpdr_cap_type_string(capabilityHeader.CapabilityType));
1037 }
1038 caps |= client_dtyp;
1039
1040 const size_t end = Stream_GetPosition(s);
1041 const size_t diff = end - start;
1042 if (diff != capabilityHeader.CapabilityLength + RDPDR_CAPABILITY_HEADER_LENGTH)
1043 {
1044 WLog_Print(priv->log, WLOG_WARN,
1045 "{capability %s[0x%04" PRIx16 "]} processed %" PRIuz
1046 " bytes, but expected to be %" PRIu16,
1047 rdpdr_cap_type_string(capabilityHeader.CapabilityType),
1048 capabilityHeader.CapabilityType, diff, capabilityHeader.CapabilityLength);
1049 }
1050 }
1051
1052 /* Only deactivate what the client did not respond with */
1053 context->supported &= caps;
1054
1055 return CHANNEL_RC_OK;
1056}
1057
1063static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
1064{
1065 WINPR_ASSERT(context);
1066 WINPR_ASSERT(context->priv);
1067
1068 RdpdrServerPrivate* priv = context->priv;
1069 wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8);
1070 if (!s)
1071 {
1072 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
1073 return CHANNEL_RC_NO_MEMORY;
1074 }
1075
1076 const RDPDR_HEADER header = {
1077 .Component = RDPDR_CTYP_CORE,
1078 .PacketId = PAKID_CORE_CLIENTID_CONFIRM,
1079 };
1080 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
1081 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
1082 Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */
1083 Stream_Write_UINT16(s, priv->VersionMinor); /* VersionMinor (2 bytes) */
1084 Stream_Write_UINT32(s, priv->ClientId); /* ClientId (4 bytes) */
1085 return rdpdr_seal_send_free_request(context, s);
1086}
1087
1093static UINT rdpdr_server_send_device_reply(RdpdrServerContext* context, UINT32 deviceId,
1094 UINT32 resultCode)
1095{
1096 WINPR_ASSERT(context);
1097 WINPR_ASSERT(context->priv);
1098
1099 RdpdrServerPrivate* priv = context->priv;
1100 wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8);
1101 if (!s)
1102 {
1103 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
1104 return CHANNEL_RC_NO_MEMORY;
1105 }
1106
1107 const RDPDR_HEADER header = {
1108 .Component = RDPDR_CTYP_CORE,
1109 .PacketId = PAKID_CORE_DEVICE_REPLY,
1110 };
1111 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
1112 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
1113 Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */
1114 Stream_Write_UINT32(s, resultCode); /* ResultCode (4 bytes) */
1115 return rdpdr_seal_send_free_request(context, s);
1116}
1117
1123static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* context,
1124 wStream* s,
1125 const RDPDR_HEADER* header)
1126{
1127 WINPR_ASSERT(context);
1128 WINPR_ASSERT(context->priv);
1129
1130 RdpdrServerPrivate* priv = context->priv;
1131
1132 WINPR_UNUSED(header);
1133
1134 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
1135 return ERROR_INVALID_DATA;
1136
1137 const UINT32 DeviceCount = Stream_Get_UINT32(s); /* DeviceCount (4 bytes) */
1138 WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount);
1139
1140 for (UINT32 i = 0; i < DeviceCount; i++)
1141 {
1142 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20))
1143 return ERROR_INVALID_DATA;
1144
1145 RdpdrDevice device = WINPR_C_ARRAY_INIT;
1146 device.DeviceType = Stream_Get_UINT32(s); /* DeviceType (4 bytes) */
1147 device.DeviceId = Stream_Get_UINT32(s); /* DeviceId (4 bytes) */
1148 Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */
1149 device.DeviceDataLength = Stream_Get_UINT32(s); /* DeviceDataLength (4 bytes) */
1150 device.DeviceData = Stream_PointerAs(s, BYTE);
1151
1152 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, device.DeviceDataLength))
1153 return ERROR_INVALID_DATA;
1154
1155 if (!rdpdr_add_device(context->priv, &device))
1156 return ERROR_INTERNAL_ERROR;
1157
1158 UINT error = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceAnnounce, context, &device);
1159 if (error != CHANNEL_RC_OK)
1160 return error;
1161
1162 error = ERROR_NOT_SUPPORTED;
1163 switch (device.DeviceType)
1164 {
1165 case RDPDR_DTYP_FILESYSTEM:
1166 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
1167 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnDriveCreate, context, &device);
1168 break;
1169
1170 case RDPDR_DTYP_PRINT:
1171 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
1172 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnPrinterCreate, context, &device);
1173 break;
1174
1175 case RDPDR_DTYP_SERIAL:
1176 if (device.DeviceDataLength != 0)
1177 {
1178 WLog_Print(priv->log, WLOG_WARN,
1179 "[rdpdr] RDPDR_DTYP_SERIAL::DeviceDataLength != 0 [%" PRIu32 "]",
1180 device.DeviceDataLength);
1181 error = ERROR_INVALID_DATA;
1182 }
1183 else if ((context->supported & RDPDR_DTYP_SERIAL) != 0)
1184 error =
1185 IFCALLRESULT(CHANNEL_RC_OK, context->OnSerialPortCreate, context, &device);
1186 break;
1187
1188 case RDPDR_DTYP_PARALLEL:
1189 if (device.DeviceDataLength != 0)
1190 {
1191 WLog_Print(priv->log, WLOG_WARN,
1192 "[rdpdr] RDPDR_DTYP_PARALLEL::DeviceDataLength != 0 [%" PRIu32 "]",
1193 device.DeviceDataLength);
1194 error = ERROR_INVALID_DATA;
1195 }
1196 else if ((context->supported & RDPDR_DTYP_PARALLEL) != 0)
1197 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnParallelPortCreate, context,
1198 &device);
1199 break;
1200
1201 case RDPDR_DTYP_SMARTCARD:
1202 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
1203 {
1204 priv->smartcardDeviceId = device.DeviceId;
1205 priv->haveSmartcardDevice = TRUE;
1206 error =
1207 IFCALLRESULT(STATUS_SUCCESS, context->OnSmartcardCreate, context, &device);
1208 }
1209 break;
1210
1211 default:
1212 WLog_Print(priv->log, WLOG_WARN,
1213 "[MS-RDPEFS] 2.2.2.9 Client Device List Announce Request "
1214 "(DR_CORE_DEVICELIST_ANNOUNCE_REQ) unknown device type %04" PRIx16
1215 " at position %" PRIu32,
1216 device.DeviceType, i);
1217 error = ERROR_INVALID_DATA;
1218 break;
1219 }
1220
1221 Stream_Seek(s, device.DeviceDataLength);
1222
1223 error = rdpdr_server_send_device_reply(context, device.DeviceId, error);
1224 if (error != CHANNEL_RC_OK)
1225 return error;
1226 }
1227
1228 return CHANNEL_RC_OK;
1229}
1230
1236static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* context, wStream* s,
1237 const RDPDR_HEADER* header)
1238{
1239 WINPR_ASSERT(context);
1240 WINPR_ASSERT(context->priv);
1241
1242 RdpdrServerPrivate* priv = context->priv;
1243
1244 WINPR_UNUSED(header);
1245
1246 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
1247 return ERROR_INVALID_DATA;
1248
1249 const UINT32 DeviceCount = Stream_Get_UINT32(s); /* DeviceCount (4 bytes) */
1250 WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount);
1251
1252 for (UINT32 i = 0; i < DeviceCount; i++)
1253 {
1254 UINT error = 0;
1255 const RdpdrDevice* device = nullptr;
1256
1257 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
1258 return ERROR_INVALID_DATA;
1259
1260 const UINT32 DeviceId = Stream_Get_UINT32(s); /* DeviceId (4 bytes) */
1261 device = rdpdr_get_device_by_id(context->priv, DeviceId);
1262 WLog_Print(priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i, DeviceId);
1263 UINT32 DeviceType = 0;
1264 if (device)
1265 DeviceType = device->DeviceType;
1266
1267 error =
1268 IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceRemove, context, DeviceId, device);
1269 if (error != CHANNEL_RC_OK)
1270 return error;
1271
1272 switch (DeviceType)
1273 {
1274 case RDPDR_DTYP_FILESYSTEM:
1275 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
1276 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnDriveDelete, context, DeviceId);
1277 break;
1278
1279 case RDPDR_DTYP_PRINT:
1280 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
1281 error =
1282 IFCALLRESULT(CHANNEL_RC_OK, context->OnPrinterDelete, context, DeviceId);
1283 break;
1284
1285 case RDPDR_DTYP_SERIAL:
1286 if ((context->supported & RDPDR_DTYP_SERIAL) != 0)
1287 error =
1288 IFCALLRESULT(CHANNEL_RC_OK, context->OnSerialPortDelete, context, DeviceId);
1289 break;
1290
1291 case RDPDR_DTYP_PARALLEL:
1292 if ((context->supported & RDPDR_DTYP_PARALLEL) != 0)
1293 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnParallelPortDelete, context,
1294 DeviceId);
1295 break;
1296
1297 case RDPDR_DTYP_SMARTCARD:
1298 if (priv->haveSmartcardDevice)
1299 {
1300 priv->haveSmartcardDevice = FALSE;
1301 priv->smartcardDeviceId = 0;
1302 }
1303 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
1304 error =
1305 IFCALLRESULT(CHANNEL_RC_OK, context->OnSmartcardDelete, context, DeviceId);
1306 break;
1307
1308 default:
1309 break;
1310 }
1311
1312 if (error != CHANNEL_RC_OK)
1313 return error;
1314
1315 if (!rdpdr_remove_device_by_id(context->priv, DeviceId))
1316 return ERROR_INVALID_DATA;
1317 }
1318
1319 return CHANNEL_RC_OK;
1320}
1321
1322static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, wStream* s,
1323 WINPR_ATTR_UNUSED UINT32 DeviceId,
1324 WINPR_ATTR_UNUSED UINT32 FileId,
1325 WINPR_ATTR_UNUSED UINT32 CompletionId)
1326{
1327 WINPR_ASSERT(context);
1328
1329 RdpdrServerPrivate* priv = context->priv;
1330 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1331 return ERROR_INVALID_DATA;
1332
1333 WINPR_ATTR_UNUSED const UINT32 DesiredAccess = Stream_Get_UINT32(s);
1334 WINPR_ATTR_UNUSED const UINT32 AllocationSize = Stream_Get_UINT32(s);
1335 WINPR_ATTR_UNUSED const UINT32 FileAttributes = Stream_Get_UINT32(s);
1336 WINPR_ATTR_UNUSED const UINT32 SharedAccess = Stream_Get_UINT32(s);
1337 WINPR_ATTR_UNUSED const UINT32 CreateDisposition = Stream_Get_UINT32(s);
1338 WINPR_ATTR_UNUSED const UINT32 CreateOptions = Stream_Get_UINT32(s);
1339 const UINT32 PathLength = Stream_Get_UINT32(s);
1340
1341 const WCHAR* path = rdpdr_read_ustring(priv->log, s, PathLength);
1342 if (!path && (PathLength > 0))
1343 return ERROR_INVALID_DATA;
1344
1345 WLog_Print(priv->log, WLOG_WARN,
1346 "[MS-RDPEFS] 2.2.1.4.1 Device Create Request (DR_CREATE_REQ) not implemented");
1347 WLog_Print(priv->log, WLOG_WARN, "TODO");
1348
1349 return CHANNEL_RC_OK;
1350}
1351
1352static UINT rdpdr_server_receive_io_close_request(RdpdrServerContext* context, wStream* s,
1353 WINPR_ATTR_UNUSED UINT32 DeviceId,
1354 WINPR_ATTR_UNUSED UINT32 FileId,
1355 WINPR_ATTR_UNUSED UINT32 CompletionId)
1356{
1357 WINPR_ASSERT(context);
1358 WINPR_ASSERT(context->priv);
1359
1360 RdpdrServerPrivate* priv = context->priv;
1361
1362 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1363 return ERROR_INVALID_DATA;
1364
1365 Stream_Seek(s, 32); /* Padding */
1366
1367 WLog_Print(priv->log, WLOG_WARN,
1368 "[MS-RDPEFS] 2.2.1.4.2 Device Close Request (DR_CLOSE_REQ) not implemented");
1369 WLog_Print(priv->log, WLOG_WARN, "TODO");
1370
1371 return CHANNEL_RC_OK;
1372}
1373
1374static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wStream* s,
1375 WINPR_ATTR_UNUSED UINT32 DeviceId,
1376 WINPR_ATTR_UNUSED UINT32 FileId,
1377 WINPR_ATTR_UNUSED UINT32 CompletionId)
1378{
1379 WINPR_ASSERT(context);
1380 WINPR_ASSERT(context->priv);
1381
1382 RdpdrServerPrivate* priv = context->priv;
1383 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1384 return ERROR_INVALID_DATA;
1385
1386 const UINT32 Length = Stream_Get_UINT32(s);
1387 const UINT64 Offset = Stream_Get_UINT64(s);
1388 Stream_Seek(s, 20); /* Padding */
1389
1390 WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset,
1391 Length);
1392
1393 WLog_Print(priv->log, WLOG_WARN,
1394 "[MS-RDPEFS] 2.2.1.4.3 Device Read Request (DR_READ_REQ) not implemented");
1395 WLog_Print(priv->log, WLOG_WARN, "TODO");
1396
1397 return CHANNEL_RC_OK;
1398}
1399
1400static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, wStream* s,
1401 WINPR_ATTR_UNUSED UINT32 DeviceId,
1402 WINPR_ATTR_UNUSED UINT32 FileId,
1403 WINPR_ATTR_UNUSED UINT32 CompletionId)
1404{
1405 WINPR_ASSERT(context);
1406 WINPR_ASSERT(context->priv);
1407
1408 RdpdrServerPrivate* priv = context->priv;
1409
1410 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1411 return ERROR_INVALID_DATA;
1412
1413 const UINT32 Length = Stream_Get_UINT32(s);
1414 const UINT64 Offset = Stream_Get_UINT64(s);
1415 Stream_Seek(s, 20); /* Padding */
1416
1417 WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset,
1418 Length);
1419
1420 const BYTE* data = Stream_ConstPointer(s);
1421 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length))
1422 return ERROR_INVALID_DATA;
1423 Stream_Seek(s, Length);
1424
1425 WLog_Print(priv->log, WLOG_WARN,
1426 "[MS-RDPEFS] 2.2.1.4.4 Device Write Request (DR_WRITE_REQ) not implemented");
1427 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)data);
1428
1429 return CHANNEL_RC_OK;
1430}
1431
1432static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* context, wStream* s,
1433 WINPR_ATTR_UNUSED UINT32 DeviceId,
1434 WINPR_ATTR_UNUSED UINT32 FileId,
1435 WINPR_ATTR_UNUSED UINT32 CompletionId)
1436{
1437 WINPR_ASSERT(context);
1438 WINPR_ASSERT(context->priv);
1439
1440 RdpdrServerPrivate* priv = context->priv;
1441
1442 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1443 return ERROR_INVALID_DATA;
1444
1445 WINPR_ATTR_UNUSED const UINT32 OutputBufferLength = Stream_Get_UINT32(s);
1446 WINPR_ATTR_UNUSED const UINT32 InputBufferLength = Stream_Get_UINT32(s);
1447 WINPR_ATTR_UNUSED const UINT32 IoControlCode = Stream_Get_UINT32(s);
1448 Stream_Seek(s, 20); /* Padding */
1449
1450 const BYTE* InputBuffer = Stream_ConstPointer(s);
1451 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, InputBufferLength))
1452 return ERROR_INVALID_DATA;
1453 Stream_Seek(s, InputBufferLength);
1454
1455 WLog_Print(priv->log, WLOG_WARN,
1456 "[MS-RDPEFS] 2.2.1.4.5 Device Control Request (DR_CONTROL_REQ) not implemented");
1457 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32,
1458 (const void*)InputBuffer, InputBufferLength, OutputBufferLength);
1459
1460 return CHANNEL_RC_OK;
1461}
1462
1463static UINT rdpdr_server_receive_io_query_volume_information_request(
1464 RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId,
1465 WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId)
1466{
1467 WINPR_ASSERT(context);
1468
1469 RdpdrServerPrivate* priv = context->priv;
1470 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1471 return ERROR_INVALID_DATA;
1472
1473 const UINT32 FsInformationClass = Stream_Get_UINT32(s);
1474 const UINT32 Length = Stream_Get_UINT32(s);
1475 Stream_Seek(s, 24); /* Padding */
1476
1477 WLog_Print(priv->log, WLOG_DEBUG,
1478 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1479 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1480
1481 const BYTE* QueryVolumeBuffer = Stream_ConstPointer(s);
1482 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length))
1483 return ERROR_INVALID_DATA;
1484 Stream_Seek(s, Length);
1485
1486 WLog_Print(priv->log, WLOG_WARN,
1487 "[MS-RDPEFS] 2.2.3.3.6 Server Drive Query Volume Information Request "
1488 "(DR_DRIVE_QUERY_VOLUME_INFORMATION_REQ) not implemented");
1489 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryVolumeBuffer);
1490
1491 return CHANNEL_RC_OK;
1492}
1493
1494static UINT rdpdr_server_receive_io_set_volume_information_request(
1495 RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId,
1496 WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId)
1497{
1498 WINPR_ASSERT(context);
1499 WINPR_ASSERT(context->priv);
1500
1501 RdpdrServerPrivate* priv = context->priv;
1502
1503 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1504 return ERROR_INVALID_DATA;
1505
1506 const UINT32 FsInformationClass = Stream_Get_UINT32(s);
1507 const UINT32 Length = Stream_Get_UINT32(s);
1508 Stream_Seek(s, 24); /* Padding */
1509
1510 WLog_Print(priv->log, WLOG_DEBUG,
1511 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1512 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1513
1514 const BYTE* SetVolumeBuffer = Stream_ConstPointer(s);
1515 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length))
1516 return ERROR_INVALID_DATA;
1517 Stream_Seek(s, Length);
1518
1519 WLog_Print(priv->log, WLOG_WARN,
1520 "[MS-RDPEFS] 2.2.3.3.7 Server Drive Set Volume Information Request "
1521 "(DR_DRIVE_SET_VOLUME_INFORMATION_REQ) not implemented");
1522 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetVolumeBuffer);
1523
1524 return CHANNEL_RC_OK;
1525}
1526
1527static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext* context,
1528 wStream* s,
1529 WINPR_ATTR_UNUSED UINT32 DeviceId,
1530 WINPR_ATTR_UNUSED UINT32 FileId,
1531 WINPR_ATTR_UNUSED UINT32 CompletionId)
1532{
1533 WINPR_ASSERT(context);
1534 WINPR_ASSERT(context->priv);
1535
1536 RdpdrServerPrivate* priv = context->priv;
1537
1538 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1539 return ERROR_INVALID_DATA;
1540
1541 const UINT32 FsInformationClass = Stream_Get_UINT32(s);
1542 const UINT32 Length = Stream_Get_UINT32(s);
1543 Stream_Seek(s, 24); /* Padding */
1544
1545 WLog_Print(priv->log, WLOG_DEBUG,
1546 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1547 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1548
1549 const BYTE* QueryBuffer = Stream_ConstPointer(s);
1550 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length))
1551 return ERROR_INVALID_DATA;
1552 Stream_Seek(s, Length);
1553
1554 WLog_Print(priv->log, WLOG_WARN,
1555 "[MS-RDPEFS] 2.2.3.3.8 Server Drive Query Information Request "
1556 "(DR_DRIVE_QUERY_INFORMATION_REQ) not implemented");
1557 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryBuffer);
1558
1559 return CHANNEL_RC_OK;
1560}
1561
1562static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* context, wStream* s,
1563 WINPR_ATTR_UNUSED UINT32 DeviceId,
1564 WINPR_ATTR_UNUSED UINT32 FileId,
1565 WINPR_ATTR_UNUSED UINT32 CompletionId)
1566{
1567 WINPR_ASSERT(context);
1568 WINPR_ASSERT(context->priv);
1569
1570 RdpdrServerPrivate* priv = context->priv;
1571
1572 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1573 return ERROR_INVALID_DATA;
1574
1575 const UINT32 FsInformationClass = Stream_Get_UINT32(s);
1576 const UINT32 Length = Stream_Get_UINT32(s);
1577 Stream_Seek(s, 24); /* Padding */
1578
1579 WLog_Print(priv->log, WLOG_DEBUG,
1580 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1581 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1582
1583 const BYTE* SetBuffer = Stream_ConstPointer(s);
1584 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length))
1585 return ERROR_INVALID_DATA;
1586 Stream_Seek(s, Length);
1587
1588 WLog_Print(priv->log, WLOG_WARN,
1589 "[MS-RDPEFS] 2.2.3.3.9 Server Drive Set Information Request "
1590 "(DR_DRIVE_SET_INFORMATION_REQ) not implemented");
1591 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetBuffer);
1592
1593 return CHANNEL_RC_OK;
1594}
1595
1596static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* context, wStream* s,
1597 WINPR_ATTR_UNUSED UINT32 DeviceId,
1598 WINPR_ATTR_UNUSED UINT32 FileId,
1599 WINPR_ATTR_UNUSED UINT32 CompletionId)
1600{
1601 WINPR_ASSERT(context);
1602 WINPR_ASSERT(context->priv);
1603
1604 RdpdrServerPrivate* priv = context->priv;
1605
1606 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1607 return ERROR_INVALID_DATA;
1608
1609 const UINT32 FsInformationClass = Stream_Get_UINT32(s);
1610 const BYTE InitialQuery = Stream_Get_UINT8(s);
1611 const UINT32 PathLength = Stream_Get_UINT32(s);
1612 Stream_Seek(s, 23); /* Padding */
1613
1614 const WCHAR* wPath = rdpdr_read_ustring(priv->log, s, PathLength);
1615 if (!wPath && (PathLength > 0))
1616 return ERROR_INVALID_DATA;
1617
1618 char* Path = ConvertWCharNToUtf8Alloc(wPath, PathLength / sizeof(WCHAR), nullptr);
1619 WLog_Print(priv->log, WLOG_DEBUG,
1620 "Got FSInformationClass %s [0x%08" PRIx32 "], InitialQuery [%" PRIu8
1621 "] Path[%" PRIu32 "] %s",
1622 FSInformationClass2Tag(FsInformationClass), FsInformationClass, InitialQuery,
1623 PathLength, Path);
1624 free(Path);
1625
1626 WLog_Print(priv->log, WLOG_WARN,
1627 "[MS-RDPEFS] 2.2.3.3.10 Server Drive Query Directory Request "
1628 "(DR_DRIVE_QUERY_DIRECTORY_REQ) not implemented");
1629 WLog_Print(priv->log, WLOG_WARN, "TODO");
1630
1631 return CHANNEL_RC_OK;
1632}
1633
1634static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* context,
1635 wStream* s,
1636 WINPR_ATTR_UNUSED UINT32 DeviceId,
1637 WINPR_ATTR_UNUSED UINT32 FileId,
1638 WINPR_ATTR_UNUSED UINT32 CompletionId)
1639{
1640 WINPR_ASSERT(context);
1641 WINPR_ASSERT(context->priv);
1642
1643 RdpdrServerPrivate* priv = context->priv;
1644
1645 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1646 return ERROR_INVALID_DATA;
1647
1648 WINPR_ATTR_UNUSED const BYTE WatchTree = Stream_Get_UINT8(s);
1649 WINPR_ATTR_UNUSED const UINT32 CompletionFilter = Stream_Get_UINT32(s);
1650 Stream_Seek(s, 27); /* Padding */
1651
1652 WLog_Print(priv->log, WLOG_WARN,
1653 "[MS-RDPEFS] 2.2.3.3.11 Server Drive NotifyChange Directory Request "
1654 "(DR_DRIVE_NOTIFY_CHANGE_DIRECTORY_REQ) not implemented");
1655 WLog_Print(priv->log, WLOG_WARN, "TODO");
1656
1657 return CHANNEL_RC_OK;
1658}
1659
1660static UINT rdpdr_server_receive_io_directory_control_request(RdpdrServerContext* context,
1661 wStream* s, UINT32 DeviceId,
1662 UINT32 FileId, UINT32 CompletionId,
1663 UINT32 MinorFunction)
1664{
1665 WINPR_ASSERT(context);
1666 WINPR_ASSERT(context->priv);
1667
1668 RdpdrServerPrivate* priv = context->priv;
1669 switch (MinorFunction)
1670 {
1671 case IRP_MN_QUERY_DIRECTORY:
1672 return rdpdr_server_receive_io_query_directory_request(context, s, DeviceId, FileId,
1673 CompletionId);
1674 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
1675 return rdpdr_server_receive_io_change_directory_request(context, s, DeviceId, FileId,
1676 CompletionId);
1677 default:
1678 WLog_Print(priv->log, WLOG_WARN,
1679 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) "
1680 "MajorFunction=%s, MinorFunction=%08" PRIx32 " is not supported",
1681 rdpdr_irp_string(IRP_MJ_DIRECTORY_CONTROL), MinorFunction);
1682 return ERROR_INVALID_DATA;
1683 }
1684}
1685
1686static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* context, wStream* s,
1687 WINPR_ATTR_UNUSED UINT32 DeviceId,
1688 WINPR_ATTR_UNUSED UINT32 FileId,
1689 WINPR_ATTR_UNUSED UINT32 CompletionId)
1690{
1691 WINPR_ASSERT(context);
1692 WINPR_ASSERT(context->priv);
1693
1694 RdpdrServerPrivate* priv = context->priv;
1695
1696 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32))
1697 return ERROR_INVALID_DATA;
1698
1699 const uint32_t Operation = Stream_Get_UINT32(s);
1700 uint32_t Lock = Stream_Get_UINT32(s);
1701 const uint32_t NumLocks = Stream_Get_UINT32(s);
1702 Stream_Seek(s, 20); /* Padding */
1703
1704 WLog_Print(priv->log, WLOG_DEBUG,
1705 "IRP_MJ_LOCK_CONTROL, Operation=%s, Lock=0x%08" PRIx32 ", NumLocks=%" PRIu32,
1706 DR_DRIVE_LOCK_REQ2str(Operation), Lock, NumLocks);
1707
1708 Lock &= 0x01; /* Only bit 0 is of importance */
1709
1710 for (UINT32 x = 0; x < NumLocks; x++)
1711 {
1712 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 16))
1713 return ERROR_INVALID_DATA;
1714
1715 const UINT64 Length = Stream_Get_UINT64(s);
1716 const UINT64 Offset = Stream_Get_UINT64(s);
1717
1718 WLog_Print(priv->log, WLOG_DEBUG, "Locking at Offset=0x%08" PRIx64 " [Length %" PRIu64 "]",
1719 Offset, Length);
1720 }
1721
1722 WLog_Print(priv->log, WLOG_WARN,
1723 "[MS-RDPEFS] 2.2.3.3.12 Server Drive Lock Control Request (DR_DRIVE_LOCK_REQ) "
1724 "[Lock=0x%08" PRIx32 "]"
1725 "not implemented",
1726 Lock);
1727 WLog_Print(priv->log, WLOG_WARN, "TODO");
1728
1729 return CHANNEL_RC_OK;
1730}
1731
1732static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, wStream* s,
1733 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
1734{
1735 WINPR_ASSERT(context);
1736 WINPR_ASSERT(context->priv);
1737 WINPR_ASSERT(header);
1738
1739 RdpdrServerPrivate* priv = context->priv;
1740
1741 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20))
1742 return ERROR_INVALID_DATA;
1743
1744 const UINT32 DeviceId = Stream_Get_UINT32(s);
1745 const UINT32 FileId = Stream_Get_UINT32(s);
1746 const UINT32 CompletionId = Stream_Get_UINT32(s);
1747 const UINT32 MajorFunction = Stream_Get_UINT32(s);
1748 const UINT32 MinorFunction = Stream_Get_UINT32(s);
1749 if ((MinorFunction != 0) && (MajorFunction != IRP_MJ_DIRECTORY_CONTROL))
1750 WLog_Print(priv->log, WLOG_WARN,
1751 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) MajorFunction=%s, "
1752 "MinorFunction=0x%08" PRIx32 " != 0",
1753 rdpdr_irp_string(MajorFunction), MinorFunction);
1754
1755 switch (MajorFunction)
1756 {
1757 case IRP_MJ_CREATE:
1758 return rdpdr_server_receive_io_create_request(context, s, DeviceId, FileId,
1759 CompletionId);
1760 case IRP_MJ_CLOSE:
1761 return rdpdr_server_receive_io_close_request(context, s, DeviceId, FileId,
1762 CompletionId);
1763 case IRP_MJ_READ:
1764 return rdpdr_server_receive_io_read_request(context, s, DeviceId, FileId, CompletionId);
1765 case IRP_MJ_WRITE:
1766 return rdpdr_server_receive_io_write_request(context, s, DeviceId, FileId,
1767 CompletionId);
1768 case IRP_MJ_DEVICE_CONTROL:
1769 return rdpdr_server_receive_io_device_control_request(context, s, DeviceId, FileId,
1770 CompletionId);
1771 case IRP_MJ_QUERY_VOLUME_INFORMATION:
1772 return rdpdr_server_receive_io_query_volume_information_request(context, s, DeviceId,
1773 FileId, CompletionId);
1774 case IRP_MJ_QUERY_INFORMATION:
1775 return rdpdr_server_receive_io_query_information_request(context, s, DeviceId, FileId,
1776 CompletionId);
1777 case IRP_MJ_SET_INFORMATION:
1778 return rdpdr_server_receive_io_set_information_request(context, s, DeviceId, FileId,
1779 CompletionId);
1780 case IRP_MJ_DIRECTORY_CONTROL:
1781 return rdpdr_server_receive_io_directory_control_request(context, s, DeviceId, FileId,
1782 CompletionId, MinorFunction);
1783 case IRP_MJ_LOCK_CONTROL:
1784 return rdpdr_server_receive_io_lock_control_request(context, s, DeviceId, FileId,
1785 CompletionId);
1786 case IRP_MJ_SET_VOLUME_INFORMATION:
1787 return rdpdr_server_receive_io_set_volume_information_request(context, s, DeviceId,
1788 FileId, CompletionId);
1789
1790 default:
1791 WLog_Print(
1792 priv->log, WLOG_WARN,
1793 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) not implemented");
1794 WLog_Print(priv->log, WLOG_WARN,
1795 "got DeviceId=0x%08" PRIx32 ", FileId=0x%08" PRIx32
1796 ", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
1797 ", MinorFunction=0x%08" PRIx32,
1798 DeviceId, FileId, CompletionId, MajorFunction, MinorFunction);
1799 return ERROR_INVALID_DATA;
1800 }
1801}
1802
1808static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* context, wStream* s,
1809 const RDPDR_HEADER* header)
1810{
1811 WINPR_ASSERT(context);
1812 WINPR_ASSERT(context->priv);
1813 WINPR_ASSERT(s);
1814 WINPR_ASSERT(header);
1815
1816 RdpdrServerPrivate* priv = context->priv;
1817
1818 WINPR_UNUSED(header);
1819
1820 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12))
1821 return ERROR_INVALID_DATA;
1822
1823 const UINT32 deviceId = Stream_Get_UINT32(s);
1824 const UINT32 completionId = Stream_Get_UINT32(s);
1825 const UINT32 ioStatus = Stream_Get_UINT32(s);
1826 WLog_Print(priv->log, WLOG_DEBUG,
1827 "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", deviceId,
1828 completionId, ioStatus);
1829 RDPDR_IRP* irp = rdpdr_server_dequeue_irp(context, completionId);
1830
1831 if (!irp)
1832 {
1833 WLog_Print(priv->log, WLOG_ERROR, "IRP not found for completionId=0x%" PRIx32 "",
1834 completionId);
1835 return CHANNEL_RC_OK;
1836 }
1837
1838 /* Invoke the callback. */
1839 UINT error = CHANNEL_RC_OK;
1840 if (irp->Callback)
1841 {
1842 error = (*irp->Callback)(context, s, irp, deviceId, completionId, ioStatus);
1843 }
1844
1845 return error;
1846}
1847
1853static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
1854{
1855 WINPR_ASSERT(context);
1856 WINPR_ASSERT(context->priv);
1857
1858 RdpdrServerPrivate* priv = context->priv;
1859 wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH);
1860 if (!s)
1861 {
1862 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
1863 return CHANNEL_RC_NO_MEMORY;
1864 }
1865
1866 const RDPDR_HEADER header = {
1867 .Component = RDPDR_CTYP_CORE,
1868 .PacketId = PAKID_CORE_USER_LOGGEDON,
1869 };
1870 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
1871 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
1872 return rdpdr_seal_send_free_request(context, s);
1873}
1874
1875static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* context, wStream* s)
1876{
1877 WINPR_ASSERT(context);
1878 WINPR_ASSERT(context->priv);
1879
1880 RdpdrServerPrivate* priv = context->priv;
1881
1882 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 24))
1883 return ERROR_INVALID_DATA;
1884
1885 char PortDosName[9] = WINPR_C_ARRAY_INIT;
1886 Stream_Read(s, PortDosName, 8);
1887 const UINT32 PnPNameLen = Stream_Get_UINT32(s);
1888 const UINT32 DriverNameLen = Stream_Get_UINT32(s);
1889 const UINT32 PrinterNameLen = Stream_Get_UINT32(s);
1890 const UINT32 CachedFieldsLen = Stream_Get_UINT32(s);
1891
1892 const WCHAR* PnPName = rdpdr_read_ustring(priv->log, s, PnPNameLen);
1893 if (!PnPName && (PnPNameLen > 0))
1894 return ERROR_INVALID_DATA;
1895 const WCHAR* DriverName = rdpdr_read_ustring(priv->log, s, DriverNameLen);
1896 if (!DriverName && (DriverNameLen > 0))
1897 return ERROR_INVALID_DATA;
1898 const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen);
1899 if (!PrinterName && (PrinterNameLen > 0))
1900 return ERROR_INVALID_DATA;
1901
1902 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, CachedFieldsLen))
1903 return ERROR_INVALID_DATA;
1904 Stream_Seek(s, CachedFieldsLen);
1905
1906 WLog_Print(priv->log, WLOG_WARN,
1907 "[MS-RDPEPC] 2.2.2.3 Add Printer Cachedata (DR_PRN_ADD_CACHEDATA) not implemented");
1908 WLog_Print(priv->log, WLOG_WARN, "TODO");
1909 return CHANNEL_RC_OK;
1910}
1911
1912static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* context, wStream* s)
1913{
1914 WINPR_ASSERT(context);
1915
1916 RdpdrServerPrivate* priv = context->priv;
1917
1918 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8))
1919 return ERROR_INVALID_DATA;
1920
1921 const UINT32 PrinterNameLen = Stream_Get_UINT32(s);
1922 const UINT32 CachedFieldsLen = Stream_Get_UINT32(s);
1923
1924 const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen);
1925 if (!PrinterName && (PrinterNameLen > 0))
1926 return ERROR_INVALID_DATA;
1927
1928 const BYTE* config = Stream_ConstPointer(s);
1929 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, CachedFieldsLen))
1930 return ERROR_INVALID_DATA;
1931 Stream_Seek(s, CachedFieldsLen);
1932
1933 WLog_Print(
1934 priv->log, WLOG_WARN,
1935 "[MS-RDPEPC] 2.2.2.4 Update Printer Cachedata (DR_PRN_UPDATE_CACHEDATA) not implemented");
1936 WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)config);
1937 return CHANNEL_RC_OK;
1938}
1939
1940static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* context, wStream* s)
1941{
1942 WINPR_ASSERT(context);
1943 WINPR_ASSERT(context->priv);
1944
1945 RdpdrServerPrivate* priv = context->priv;
1946
1947 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
1948 return ERROR_INVALID_DATA;
1949
1950 const UINT32 PrinterNameLen = Stream_Get_UINT32(s);
1951
1952 const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen);
1953 if (!PrinterName && (PrinterNameLen > 0))
1954 return ERROR_INVALID_DATA;
1955
1956 WLog_Print(
1957 priv->log, WLOG_WARN,
1958 "[MS-RDPEPC] 2.2.2.5 Delete Printer Cachedata (DR_PRN_DELETE_CACHEDATA) not implemented");
1959 WLog_Print(priv->log, WLOG_WARN, "TODO");
1960 return CHANNEL_RC_OK;
1961}
1962
1963static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* context, wStream* s)
1964{
1965 WINPR_ASSERT(context);
1966 WINPR_ASSERT(context->priv);
1967
1968 RdpdrServerPrivate* priv = context->priv;
1969
1970 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8))
1971 return ERROR_INVALID_DATA;
1972
1973 const UINT32 OldPrinterNameLen = Stream_Get_UINT32(s);
1974 const UINT32 NewPrinterNameLen = Stream_Get_UINT32(s);
1975
1976 const WCHAR* OldPrinterName = rdpdr_read_ustring(priv->log, s, OldPrinterNameLen);
1977 if (!OldPrinterName && (OldPrinterNameLen > 0))
1978 return ERROR_INVALID_DATA;
1979 const WCHAR* NewPrinterName = rdpdr_read_ustring(priv->log, s, NewPrinterNameLen);
1980 if (!NewPrinterName && (NewPrinterNameLen > 0))
1981 return ERROR_INVALID_DATA;
1982
1983 WLog_Print(
1984 priv->log, WLOG_WARN,
1985 "[MS-RDPEPC] 2.2.2.6 Rename Printer Cachedata (DR_PRN_RENAME_CACHEDATA) not implemented");
1986 WLog_Print(priv->log, WLOG_WARN, "TODO");
1987 return CHANNEL_RC_OK;
1988}
1989
1990static UINT
1991rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream* s,
1992 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
1993{
1994 WINPR_ASSERT(context);
1995 WINPR_ASSERT(context->priv);
1996 WINPR_ASSERT(header);
1997
1998 RdpdrServerPrivate* priv = context->priv;
1999 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
2000 return ERROR_INVALID_DATA;
2001
2002 const UINT32 EventId = Stream_Get_UINT32(s);
2003 switch (EventId)
2004 {
2005 case RDPDR_ADD_PRINTER_EVENT:
2006 return rdpdr_server_receive_prn_cache_add_printer(context, s);
2007 case RDPDR_UPDATE_PRINTER_EVENT:
2008 return rdpdr_server_receive_prn_cache_update_printer(context, s);
2009 case RDPDR_DELETE_PRINTER_EVENT:
2010 return rdpdr_server_receive_prn_cache_delete_printer(context, s);
2011 case RDPDR_RENAME_PRINTER_EVENT:
2012 return rdpdr_server_receive_prn_cache_rename_cachedata(context, s);
2013 default:
2014 WLog_Print(priv->log, WLOG_WARN,
2015 "[MS-RDPEPC] PAKID_PRN_CACHE_DATA unknown EventId=0x%08" PRIx32, EventId);
2016 return ERROR_INVALID_DATA;
2017 }
2018}
2019
2020static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* context, wStream* s,
2021 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
2022{
2023 WINPR_ASSERT(context);
2024 WINPR_ASSERT(context->priv);
2025 WINPR_ASSERT(header);
2026
2027 RdpdrServerPrivate* priv = context->priv;
2028
2029 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8))
2030 return ERROR_INVALID_DATA;
2031
2032 const UINT32 PrinterId = Stream_Get_UINT32(s);
2033 const UINT32 Flags = Stream_Get_UINT32(s);
2034
2035 WLog_Print(
2036 priv->log, WLOG_WARN,
2037 "[MS-RDPEPC] 2.2.2.2 Server Printer Set XPS Mode (DR_PRN_USING_XPS) not implemented");
2038 WLog_Print(priv->log, WLOG_WARN, "PrinterId=0x%08" PRIx32 ", Flags=0x%08" PRIx32, PrinterId,
2039 Flags);
2040 return CHANNEL_RC_OK;
2041}
2042
2048static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s,
2049 const RDPDR_HEADER* header)
2050{
2051 UINT error = ERROR_INVALID_DATA;
2052 WINPR_ASSERT(context);
2053 WINPR_ASSERT(context->priv);
2054 WINPR_ASSERT(s);
2055 WINPR_ASSERT(header);
2056
2057 RdpdrServerPrivate* priv = context->priv;
2058 WLog_Print(priv->log, WLOG_DEBUG,
2059 "receiving message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]",
2060 rdpdr_component_string(header->Component), header->Component,
2061 rdpdr_packetid_string(header->PacketId), header->PacketId);
2062
2063 if (header->Component == RDPDR_CTYP_CORE)
2064 {
2065 switch (header->PacketId)
2066 {
2067 case PAKID_CORE_SERVER_ANNOUNCE:
2068 WLog_Print(priv->log, WLOG_ERROR,
2069 "[MS-RDPEFS] 2.2.2.2 Server Announce Request "
2070 "(DR_CORE_SERVER_ANNOUNCE_REQ) must not be sent by a client!");
2071 break;
2072
2073 case PAKID_CORE_CLIENTID_CONFIRM:
2074 error = rdpdr_server_receive_announce_response(context, s, header);
2075 break;
2076
2077 case PAKID_CORE_CLIENT_NAME:
2078 error = rdpdr_server_receive_client_name_request(context, s, header);
2079 if (error == CHANNEL_RC_OK)
2080 error = rdpdr_server_send_core_capability_request(context);
2081 if (error == CHANNEL_RC_OK)
2082 error = rdpdr_server_send_client_id_confirm(context);
2083 break;
2084
2085 case PAKID_CORE_USER_LOGGEDON:
2086 WLog_Print(priv->log, WLOG_ERROR,
2087 "[MS-RDPEFS] 2.2.2.5 Server User Logged On (DR_CORE_USER_LOGGEDON) "
2088 "must not be sent by a client!");
2089 break;
2090
2091 case PAKID_CORE_SERVER_CAPABILITY:
2092 WLog_Print(priv->log, WLOG_ERROR,
2093 "[MS-RDPEFS] 2.2.2.7 Server Core Capability Request "
2094 "(DR_CORE_CAPABILITY_REQ) must not be sent by a client!");
2095 break;
2096
2097 case PAKID_CORE_CLIENT_CAPABILITY:
2098 error = rdpdr_server_receive_core_capability_response(context, s, header);
2099 if (error == CHANNEL_RC_OK)
2100 {
2101 if (priv->UserLoggedOnPdu)
2102 error = rdpdr_server_send_user_logged_on(context);
2103 }
2104
2105 break;
2106
2107 case PAKID_CORE_DEVICELIST_ANNOUNCE:
2108 error = rdpdr_server_receive_device_list_announce_request(context, s, header);
2109 break;
2110
2111 case PAKID_CORE_DEVICELIST_REMOVE:
2112 error = rdpdr_server_receive_device_list_remove_request(context, s, header);
2113 break;
2114
2115 case PAKID_CORE_DEVICE_REPLY:
2116 WLog_Print(priv->log, WLOG_ERROR,
2117 "[MS-RDPEFS] 2.2.2.1 Server Device Announce Response "
2118 "(DR_CORE_DEVICE_ANNOUNCE_RSP) must not be sent by a client!");
2119 break;
2120
2121 case PAKID_CORE_DEVICE_IOREQUEST:
2122 error = rdpdr_server_receive_device_io_request(context, s, header);
2123 break;
2124
2125 case PAKID_CORE_DEVICE_IOCOMPLETION:
2126 error = rdpdr_server_receive_device_io_completion(context, s, header);
2127 break;
2128
2129 default:
2130 WLog_Print(priv->log, WLOG_WARN,
2131 "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
2132 rdpdr_component_string(header->Component), header->Component,
2133 rdpdr_packetid_string(header->PacketId));
2134 break;
2135 }
2136 }
2137 else if (header->Component == RDPDR_CTYP_PRN)
2138 {
2139 switch (header->PacketId)
2140 {
2141 case PAKID_PRN_CACHE_DATA:
2142 error = rdpdr_server_receive_prn_cache_data_request(context, s, header);
2143 break;
2144
2145 case PAKID_PRN_USING_XPS:
2146 error = rdpdr_server_receive_prn_using_xps_request(context, s, header);
2147 break;
2148
2149 default:
2150 WLog_Print(priv->log, WLOG_WARN,
2151 "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
2152 rdpdr_component_string(header->Component), header->Component,
2153 rdpdr_packetid_string(header->PacketId));
2154 break;
2155 }
2156 }
2157 else
2158 {
2159 WLog_Print(priv->log, WLOG_WARN,
2160 "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
2161 rdpdr_component_string(header->Component), header->Component,
2162 rdpdr_packetid_string(header->PacketId));
2163 }
2164
2165 return IFCALLRESULT(error, context->ReceivePDU, context, header, error);
2166}
2167
2168static DWORD WINAPI rdpdr_server_thread(LPVOID arg)
2169{
2170 RdpdrServerContext* context = (RdpdrServerContext*)arg;
2171
2172 WINPR_ASSERT(context);
2173 WINPR_ASSERT(context->priv);
2174
2175 UINT error = 0;
2176 wStream* s = nullptr;
2177 RdpdrServerPrivate* priv = context->priv;
2178 ChannelPduTracker* tracker = ChannelPduTracker_new(priv->ChannelHandle);
2179 if (!tracker)
2180 goto out;
2181
2182 void* buffer = nullptr;
2183 HANDLE ChannelEvent = nullptr;
2184 DWORD BytesReturned = 0;
2185 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
2186 &BytesReturned))
2187 {
2188 WLog_Print(priv->log, WLOG_ERROR, "error retrieving WTSVirtualEventHandle");
2189 goto out;
2190 }
2191
2192 if (BytesReturned != sizeof(HANDLE))
2193 {
2194 WLog_Print(priv->log, WLOG_ERROR, "invalid size for WTSVirtualEventHandle");
2195 WTSFreeMemory(buffer);
2196 goto out;
2197 }
2198
2199 ChannelEvent = *(HANDLE*)buffer;
2200 WTSFreeMemory(buffer);
2201
2202 if ((error = rdpdr_server_send_announce_request(context)))
2203 {
2204 WLog_Print(priv->log, WLOG_ERROR,
2205 "rdpdr_server_send_announce_request failed with error %" PRIu32 "!", error);
2206 goto out;
2207 }
2208
2209 HANDLE events[2] = { priv->StopEvent, ChannelEvent };
2210
2211 while (1)
2212 {
2213 DWORD status = WaitForMultipleObjects(2, events, FALSE, INFINITE);
2214
2215 switch (status)
2216 {
2217 case WAIT_OBJECT_0:
2218 /* StopEvent */
2219 goto out;
2220 case WAIT_OBJECT_0 + 1:
2221 {
2222 BOOL ok = FALSE;
2223 s = ChannelPduTracker_poll(tracker, &ok);
2224 if (!s && ok)
2225 continue;
2226 if (!s)
2227 break;
2228
2229 if (Stream_GetRemainingLength(s) < RDPDR_HEADER_LENGTH)
2230 {
2231 error = ERROR_INTERNAL_ERROR;
2232 goto out;
2233 }
2234
2235 const RDPDR_HEADER header = {
2236 .Component = Stream_Get_UINT16(s), /* Component (2 bytes) */
2237 .PacketId = Stream_Get_UINT16(s), /* PacketId (2 bytes) */
2238 };
2239
2240 if ((error = rdpdr_server_receive_pdu(context, s, &header)))
2241 {
2242 WLog_Print(priv->log, WLOG_ERROR,
2243 "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error);
2244 goto out;
2245 }
2246 Stream_Release(s);
2247 s = nullptr;
2248 break;
2249 }
2250 case WAIT_FAILED:
2251 default:
2252 error = GetLastError();
2253 WLog_Print(priv->log, WLOG_ERROR,
2254 "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
2255 goto out;
2256 }
2257 }
2258
2259out:
2260 ChannelPduTracker_free(tracker);
2261
2262 if (s)
2263 Stream_Release(s);
2264
2265 if (error && context->rdpcontext)
2266 setChannelError(context->rdpcontext, error, "rdpdr_server_thread reported an error");
2267
2268 ExitThread(error);
2269 return error;
2270}
2271
2277static UINT rdpdr_server_start(RdpdrServerContext* context)
2278{
2279 WINPR_ASSERT(context);
2280 WINPR_ASSERT(context->priv);
2281
2282 PULONG pSessionId = nullptr;
2283 DWORD BytesReturned = 0;
2284
2285 if (!WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
2286 (LPSTR*)&pSessionId, &BytesReturned))
2287 return CHANNEL_RC_BAD_CHANNEL;
2288
2289 DWORD SessionId = (DWORD)*pSessionId;
2290 WTSFreeMemory(pSessionId);
2291
2292 RdpdrServerPrivate* priv = context->priv;
2293 priv->ChannelHandle =
2294 WTSVirtualChannelOpenEx(SessionId, RDPDR_SVC_CHANNEL_NAME, CHANNEL_OPTION_SHOW_PROTOCOL);
2295
2296 if (!priv->ChannelHandle)
2297 {
2298 WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelOpen failed!");
2299 return CHANNEL_RC_BAD_CHANNEL;
2300 }
2301
2302 if (!(priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
2303 {
2304 WLog_Print(priv->log, WLOG_ERROR, "CreateEvent failed!");
2305 return ERROR_INTERNAL_ERROR;
2306 }
2307
2308 if (!(priv->Thread = CreateThread(nullptr, 0, rdpdr_server_thread, (void*)context, 0, nullptr)))
2309 {
2310 WLog_Print(priv->log, WLOG_ERROR, "CreateThread failed!");
2311 (void)CloseHandle(priv->StopEvent);
2312 priv->StopEvent = nullptr;
2313 return ERROR_INTERNAL_ERROR;
2314 }
2315
2316 return CHANNEL_RC_OK;
2317}
2318
2324static UINT rdpdr_server_stop(RdpdrServerContext* context)
2325{
2326 WINPR_ASSERT(context);
2327 WINPR_ASSERT(context->priv);
2328
2329 RdpdrServerPrivate* priv = context->priv;
2330 if (priv->StopEvent)
2331 {
2332 (void)SetEvent(priv->StopEvent);
2333
2334 if (WaitForSingleObject(priv->Thread, INFINITE) == WAIT_FAILED)
2335 {
2336 UINT error = GetLastError();
2337 WLog_Print(priv->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!",
2338 error);
2339 return error;
2340 }
2341
2342 (void)CloseHandle(priv->Thread);
2343 priv->Thread = nullptr;
2344 (void)CloseHandle(priv->StopEvent);
2345 priv->StopEvent = nullptr;
2346 }
2347
2348 if (priv->ChannelHandle)
2349 {
2350 (void)WTSVirtualChannelClose(priv->ChannelHandle);
2351 priv->ChannelHandle = nullptr;
2352 }
2353 return CHANNEL_RC_OK;
2354}
2355
2356static void rdpdr_server_write_device_iorequest(wStream* s, UINT32 deviceId, UINT32 fileId,
2357 UINT32 completionId, UINT32 majorFunction,
2358 UINT32 minorFunction)
2359{
2360 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
2361 Stream_Write_UINT16(s, PAKID_CORE_DEVICE_IOREQUEST); /* PacketId (2 bytes) */
2362 Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */
2363 Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */
2364 Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */
2365 Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */
2366 Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */
2367}
2368
2374static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s,
2376{
2377 WINPR_ASSERT(fdi);
2378 ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION));
2379
2380 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 64))
2381 return ERROR_INVALID_DATA;
2382
2383 fdi->NextEntryOffset = Stream_Get_UINT32(s); /* NextEntryOffset (4 bytes) */
2384 fdi->FileIndex = Stream_Get_UINT32(s); /* FileIndex (4 bytes) */
2385 fdi->CreationTime.QuadPart = Stream_Get_INT64(s); /* CreationTime (8 bytes) */
2386 fdi->LastAccessTime.QuadPart = Stream_Get_INT64(s); /* LastAccessTime (8 bytes) */
2387 fdi->LastWriteTime.QuadPart = Stream_Get_INT64(s); /* LastWriteTime (8 bytes) */
2388 fdi->ChangeTime.QuadPart = Stream_Get_INT64(s); /* ChangeTime (8 bytes) */
2389 fdi->EndOfFile.QuadPart = Stream_Get_INT64(s); /* EndOfFile (8 bytes) */
2390 fdi->AllocationSize.QuadPart = Stream_Get_INT64(s); /* AllocationSize (8 bytes) */
2391 fdi->FileAttributes = Stream_Get_UINT32(s); /* FileAttributes (4 bytes) */
2392 const UINT32 fileNameLength = Stream_Get_UINT32(s); /* FileNameLength (4 bytes) */
2393
2394 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, fileNameLength))
2395 return ERROR_INVALID_DATA;
2396
2397 if (fileNameLength / sizeof(WCHAR) > ARRAYSIZE(fdi->FileName))
2398 return ERROR_INVALID_DATA;
2399
2400#if defined(__MINGW32__) || defined(WITH_WCHAR_FILE_DIRECTORY_INFORMATION)
2401 if (Stream_Read_UTF16_String(s, fdi->FileName, fileNameLength / sizeof(WCHAR)))
2402 return ERROR_INVALID_DATA;
2403#else
2404 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, fileNameLength / sizeof(WCHAR), fdi->FileName,
2405 ARRAYSIZE(fdi->FileName)) < 0)
2406 return ERROR_INVALID_DATA;
2407#endif
2408 return CHANNEL_RC_OK;
2409}
2410
2411static UINT prepare_irp(RdpdrServerContext* context, UINT32 deviceId, RDPDR_IRP_Callback callback,
2412 void* callbackData, RDPDR_IRP** outIrp)
2413{
2414 WINPR_ASSERT(context);
2415 WINPR_ASSERT(context->priv);
2416 WINPR_ASSERT(callbackData);
2417 WINPR_ASSERT(outIrp);
2418
2419 RdpdrServerPrivate* priv = context->priv;
2420
2421 RDPDR_IRP* irp = rdpdr_server_irp_new();
2422 if (!irp)
2423 {
2424 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
2425 return CHANNEL_RC_NO_MEMORY;
2426 }
2427
2428 irp->CompletionId = priv->NextCompletionId++;
2429 irp->Callback = callback;
2430 irp->CallbackData = callbackData;
2431 irp->DeviceId = deviceId;
2432
2433 if (!rdpdr_server_enqueue_irp(context, irp))
2434 {
2435 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2436 rdpdr_server_irp_free(irp);
2437 return ERROR_INTERNAL_ERROR;
2438 }
2439
2440 *outIrp = irp;
2441 return CHANNEL_RC_OK;
2442}
2443
2444static UINT prepare_smartcard_irp(RdpdrServerContext* context, UINT32 ioControlCode,
2445 RDPDR_IRP_Callback callback, void* callbackData,
2446 RDPDR_IRP** outIrp)
2447{
2448 WINPR_ASSERT(context);
2449 WINPR_ASSERT(context->priv);
2450 WINPR_ASSERT(callbackData);
2451
2452 const char* cmd = scard_get_ioctl_string(ioControlCode, FALSE);
2453
2454 RdpdrServerPrivate* priv = context->priv;
2455 if (!priv->haveSmartcardDevice)
2456 {
2457 WLog_Print(priv->log, WLOG_ERROR, "%s - no smartcard device registered", cmd);
2458 return ERROR_BAD_DEVICE;
2459 }
2460
2461 RDPDR_IRP* irp = nullptr;
2462 UINT error = prepare_irp(context, priv->smartcardDeviceId, callback, callbackData, &irp);
2463 if (error != CHANNEL_RC_OK)
2464 return error;
2465
2466 irp->IoControlCode = ioControlCode;
2467 *outIrp = irp;
2468 return CHANNEL_RC_OK;
2469}
2470
2476static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, UINT32 deviceId,
2477 UINT32 completionId, const char* path,
2478 UINT32 desiredAccess, UINT32 createOptions,
2479 UINT32 createDisposition)
2480{
2481 WINPR_ASSERT(context);
2482 WINPR_ASSERT(context->priv);
2483
2484 RdpdrServerPrivate* priv = context->priv;
2485
2486 WLog_Print(priv->log, WLOG_DEBUG,
2487 "RdpdrServerSendDeviceCreateRequest: deviceId=%" PRIu32
2488 ", path=%s, desiredAccess=0x%" PRIx32 " createOptions=0x%" PRIx32
2489 " createDisposition=0x%" PRIx32 "",
2490 deviceId, path, desiredAccess, createOptions, createDisposition);
2491 /* Compute the required Unicode size. */
2492 size_t pathStrLength = 0;
2493 size_t pathLength = 0;
2494 if (path)
2495 {
2496 pathStrLength = strlen(path);
2497 const SSIZE_T wlen = ConvertUtf8ToWChar(path, nullptr, 0);
2498 if (wlen < 0)
2499 return ERROR_INTERNAL_ERROR;
2500 pathLength = (WINPR_ASSERTING_INT_CAST(size_t, wlen) + 1) * sizeof(WCHAR);
2501 }
2502 wStream* s = Stream_New(nullptr, 256U + pathLength);
2503
2504 if (!s)
2505 {
2506 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2507 return CHANNEL_RC_NO_MEMORY;
2508 }
2509
2510 rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, 0);
2511 Stream_Write_UINT32(s, desiredAccess); /* DesiredAccess (4 bytes) */
2512 Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */
2513 Stream_Write_UINT32(s, 0);
2514 Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */
2515 Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */
2516 Stream_Write_UINT32(s, createDisposition); /* CreateDisposition (4 bytes) */
2517 Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */
2518 WINPR_ASSERT(pathLength <= UINT32_MAX);
2519 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2520 /* Convert the path to Unicode. */
2521 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, pathStrLength,
2522 TRUE) < 0)
2523 {
2524 Stream_Release(s);
2525 return ERROR_INTERNAL_ERROR;
2526 }
2527 return rdpdr_seal_send_free_request(context, s);
2528}
2529
2535static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, UINT32 deviceId,
2536 UINT32 fileId, UINT32 completionId)
2537{
2538 WINPR_ASSERT(context);
2539 WINPR_ASSERT(context->priv);
2540
2541 RdpdrServerPrivate* priv = context->priv;
2542
2543 WLog_Print(priv->log, WLOG_DEBUG,
2544 "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "",
2545 deviceId, fileId);
2546 wStream* s = Stream_New(nullptr, 128);
2547
2548 if (!s)
2549 {
2550 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2551 return CHANNEL_RC_NO_MEMORY;
2552 }
2553
2554 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_CLOSE, 0);
2555 Stream_Zero(s, 32); /* Padding (32 bytes) */
2556 return rdpdr_seal_send_free_request(context, s);
2557}
2558
2564static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, UINT32 deviceId,
2565 UINT32 fileId, UINT32 completionId, UINT32 length,
2566 UINT32 offset)
2567{
2568 WINPR_ASSERT(context);
2569 WINPR_ASSERT(context->priv);
2570
2571 RdpdrServerPrivate* priv = context->priv;
2572
2573 WLog_Print(priv->log, WLOG_DEBUG,
2574 "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2575 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2576 deviceId, fileId, length, offset);
2577 wStream* s = Stream_New(nullptr, 128);
2578
2579 if (!s)
2580 {
2581 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2582 return CHANNEL_RC_NO_MEMORY;
2583 }
2584
2585 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_READ, 0);
2586 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2587 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2588 Stream_Write_UINT32(s, 0);
2589 Stream_Zero(s, 20); /* Padding (20 bytes) */
2590 return rdpdr_seal_send_free_request(context, s);
2591}
2592
2598static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, UINT32 deviceId,
2599 UINT32 fileId, UINT32 completionId,
2600 const char* data, UINT32 length, UINT32 offset)
2601{
2602 WINPR_ASSERT(context);
2603 WINPR_ASSERT(context->priv);
2604
2605 RdpdrServerPrivate* priv = context->priv;
2606
2607 WLog_Print(priv->log, WLOG_DEBUG,
2608 "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2609 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2610 deviceId, fileId, length, offset);
2611 wStream* s = Stream_New(nullptr, 64 + length);
2612
2613 if (!s)
2614 {
2615 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2616 return CHANNEL_RC_NO_MEMORY;
2617 }
2618
2619 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_WRITE, 0);
2620 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2621 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2622 Stream_Write_UINT32(s, 0);
2623 Stream_Zero(s, 20); /* Padding (20 bytes) */
2624 Stream_Write(s, data, length); /* WriteData (variable) */
2625 return rdpdr_seal_send_free_request(context, s);
2626}
2627
2633static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* context,
2634 UINT32 deviceId, UINT32 fileId,
2635 UINT32 completionId, const char* path)
2636{
2637 WINPR_ASSERT(context);
2638 WINPR_ASSERT(context->priv);
2639
2640 RdpdrServerPrivate* priv = context->priv;
2641
2642 WLog_Print(priv->log, WLOG_DEBUG,
2643 "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2644 ", path=%s",
2645 deviceId, fileId, path);
2646 /* Compute the required Unicode size. */
2647 size_t pathStrLength = 0;
2648 size_t pathLength = 0;
2649 if (path)
2650 {
2651 pathStrLength = strlen(path);
2652 const SSIZE_T wlen = ConvertUtf8ToWChar(path, nullptr, 0);
2653 if (wlen < 0)
2654 return ERROR_INTERNAL_ERROR;
2655 pathLength = (WINPR_ASSERTING_INT_CAST(size_t, wlen) + 1) * sizeof(WCHAR);
2656 }
2657 wStream* s = Stream_New(nullptr, 64 + pathLength);
2658
2659 if (!s)
2660 {
2661 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2662 return CHANNEL_RC_NO_MEMORY;
2663 }
2664
2665 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_DIRECTORY_CONTROL,
2666 IRP_MN_QUERY_DIRECTORY);
2667 Stream_Write_UINT32(s, FileDirectoryInformation); /* FsInformationClass (4 bytes) */
2668 Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */
2669 WINPR_ASSERT(pathLength <= UINT32_MAX);
2670 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2671 Stream_Zero(s, 23); /* Padding (23 bytes) */
2672
2673 /* Convert the path to Unicode. */
2674 if (pathLength > 0)
2675 {
2676 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, pathStrLength,
2677 TRUE) < 0)
2678 {
2679 Stream_Release(s);
2680 return ERROR_INTERNAL_ERROR;
2681 }
2682 }
2683
2684 return rdpdr_seal_send_free_request(context, s);
2685}
2686
2692static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* context,
2693 UINT32 deviceId, UINT32 fileId,
2694 UINT32 completionId, const char* path)
2695{
2696 WINPR_ASSERT(context);
2697 WINPR_ASSERT(context->priv);
2698
2699 RdpdrServerPrivate* priv = context->priv;
2700
2701 WLog_Print(priv->log, WLOG_DEBUG,
2702 "RdpdrServerSendDeviceFileNameRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2703 ", path=%s",
2704 deviceId, fileId, path);
2705 /* Compute the required Unicode size. */
2706 size_t pathStrLength = 0;
2707 size_t pathLength = 0;
2708 if (path)
2709 {
2710 pathStrLength = strlen(path);
2711 const SSIZE_T wlen = ConvertUtf8ToWChar(path, nullptr, 0);
2712 if (wlen < 0)
2713 return ERROR_INTERNAL_ERROR;
2714 pathLength = (WINPR_ASSERTING_INT_CAST(size_t, wlen) + 1) * sizeof(WCHAR);
2715 }
2716
2717 wStream* s = Stream_New(nullptr, 64 + pathLength);
2718
2719 if (!s)
2720 {
2721 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2722 return CHANNEL_RC_NO_MEMORY;
2723 }
2724
2725 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_SET_INFORMATION,
2726 0);
2727 Stream_Write_UINT32(s, FileRenameInformation); /* FsInformationClass (4 bytes) */
2728 WINPR_ASSERT(pathLength <= UINT32_MAX - 6U);
2729 Stream_Write_UINT32(s, (UINT32)pathLength + 6U); /* Length (4 bytes) */
2730 Stream_Zero(s, 24); /* Padding (24 bytes) */
2731 /* RDP_FILE_RENAME_INFORMATION */
2732 Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */
2733 Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */
2734 Stream_Write_UINT32(s, (UINT32)pathLength); /* FileNameLength (4 bytes) */
2735
2736 /* Convert the path to Unicode. */
2737 if (pathLength > 0)
2738 {
2739 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, pathStrLength,
2740 TRUE) < 0)
2741 {
2742 Stream_Release(s);
2743 return ERROR_INTERNAL_ERROR;
2744 }
2745 }
2746
2747 return rdpdr_seal_send_free_request(context, s);
2748}
2749
2750static UINT rdpdr_server_send_device_control_request(RdpdrServerContext* context, UINT32 deviceId,
2751 UINT32 completionId, UINT32 ioControlCode,
2752 UINT32 outputBufferLength,
2753 const void* inputBuffer,
2754 size_t inputBufferLength)
2755{
2756 WINPR_ASSERT(context);
2757 WINPR_ASSERT(context->priv);
2758 WINPR_ASSERT(inputBuffer || (inputBufferLength == 0));
2759
2760 if (inputBufferLength > UINT32_MAX)
2761 {
2762 WLog_Print(context->priv->log, WLOG_ERROR,
2763 "inputBufferLength %" PRIuz " exceeds UINT32_MAX", inputBufferLength);
2764 return ERROR_INVALID_PARAMETER;
2765 }
2766
2767 RdpdrServerPrivate* priv = context->priv;
2768
2769 WLog_Print(priv->log, WLOG_DEBUG,
2770 "RdpdrServerSendDeviceControlRequest: deviceId=%" PRIu32 ","
2771 " ioControlCode=0x%" PRIx32 ", inputBufferLength=%" PRIuz,
2772 deviceId, ioControlCode, inputBufferLength);
2773
2774 if (inputBufferLength > 0)
2775 winpr_HexLogDump(priv->log, WLOG_DEBUG, inputBuffer, inputBufferLength);
2776
2777 wStream* s =
2778 Stream_New(nullptr, RDPDR_HEADER_LENGTH + RDPDR_DEVICE_IO_REQUEST_LENGTH +
2779 RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength);
2780 if (!s)
2781 {
2782 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
2783 return CHANNEL_RC_NO_MEMORY;
2784 }
2785
2786 UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength);
2787 rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_DEVICE_CONTROL, 0);
2788 Stream_Write_UINT32(s, outputBufferLength); /* OutputBufferLength (4 bytes) */
2789 Stream_Write_UINT32(s, inputLength); /* InputBufferLength (4 bytes) */
2790 Stream_Write_UINT32(s, ioControlCode); /* IoControlCode (4 bytes) */
2791 Stream_Zero(s, 20); /* Padding (20 bytes) */
2792
2793 if (inputBufferLength > 0)
2794 Stream_Write(s, inputBuffer, inputBufferLength);
2795
2796 return rdpdr_seal_send_free_request(context, s);
2797}
2798
2799static void rdpdr_server_convert_slashes(char* path, int size)
2800{
2801 WINPR_ASSERT(path || (size <= 0));
2802
2803 for (int i = 0; (i < size) && (path[i] != '\0'); i++)
2804 {
2805 if (path[i] == '/')
2806 path[i] = '\\';
2807 }
2808}
2809
2810/*************************************************
2811 * Drive Create Directory
2812 ************************************************/
2813
2819static UINT rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* context, wStream* s,
2820 RDPDR_IRP* irp, UINT32 deviceId,
2821 UINT32 completionId, UINT32 ioStatus)
2822{
2823 WINPR_ASSERT(context);
2824 WINPR_ASSERT(context->priv);
2825 WINPR_ASSERT(s);
2826 WINPR_ASSERT(irp);
2827 WINPR_UNUSED(s);
2828
2829 RdpdrServerPrivate* priv = context->priv;
2830 WLog_Print(priv->log, WLOG_DEBUG,
2831 "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%" PRIu32
2832 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2833 deviceId, completionId, ioStatus);
2834 /* Invoke the create directory completion routine. */
2835 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2836 /* Destroy the IRP. */
2837 rdpdr_server_irp_free(irp);
2838 return CHANNEL_RC_OK;
2839}
2840
2846static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* context, wStream* s,
2847 RDPDR_IRP* irp, UINT32 deviceId,
2848 UINT32 completionId, UINT32 ioStatus)
2849{
2850 WINPR_ASSERT(context);
2851 WINPR_ASSERT(context->priv);
2852 WINPR_ASSERT(s);
2853 WINPR_ASSERT(irp);
2854
2855 RdpdrServerPrivate* priv = context->priv;
2856 WLog_Print(priv->log, WLOG_DEBUG,
2857 "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%" PRIu32
2858 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2859 deviceId, completionId, ioStatus);
2860
2861 if (ioStatus != STATUS_SUCCESS)
2862 {
2863 /* Invoke the create directory completion routine. */
2864 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2865 /* Destroy the IRP. */
2866 rdpdr_server_irp_free(irp);
2867 return CHANNEL_RC_OK;
2868 }
2869
2870 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
2871 return ERROR_INVALID_DATA;
2872
2873 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2874 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2875 WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2876 fileInformation2str(information));
2877
2878 /* Setup the IRP. */
2879 irp->CompletionId = priv->NextCompletionId++;
2880 irp->Callback = rdpdr_server_drive_create_directory_callback2;
2881 irp->DeviceId = deviceId;
2882 irp->FileId = fileId;
2883
2884 if (!rdpdr_server_enqueue_irp(context, irp))
2885 {
2886 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2887 rdpdr_server_irp_free(irp);
2888 return ERROR_INTERNAL_ERROR;
2889 }
2890
2891 /* Send a request to close the file */
2892 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
2893}
2894
2900static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData,
2901 UINT32 deviceId, const char* path)
2902{
2903 WINPR_ASSERT(context);
2904 WINPR_ASSERT(context->priv);
2905 WINPR_ASSERT(callbackData);
2906 WINPR_ASSERT(path);
2907
2908 RDPDR_IRP* irp = nullptr;
2909 UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_create_directory_callback1,
2910 callbackData, &irp);
2911 if (ret != CHANNEL_RC_OK)
2912 return ret;
2913
2914 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
2915 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
2916
2917 /* Send a request to open the file. */
2918 return rdpdr_server_send_device_create_request(
2919 context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
2920 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE);
2921}
2922
2923/*************************************************
2924 * Drive Delete Directory
2925 ************************************************/
2926
2932static UINT rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* context, wStream* s,
2933 RDPDR_IRP* irp, UINT32 deviceId,
2934 UINT32 completionId, UINT32 ioStatus)
2935{
2936 WINPR_UNUSED(s);
2937 WINPR_ASSERT(context);
2938 WINPR_ASSERT(context->priv);
2939 WINPR_ASSERT(irp);
2940
2941 RdpdrServerPrivate* priv = context->priv;
2942 WLog_Print(priv->log, WLOG_DEBUG,
2943 "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%" PRIu32
2944 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2945 deviceId, completionId, ioStatus);
2946 /* Invoke the delete directory completion routine. */
2947 context->OnDriveDeleteDirectoryComplete(context, irp->CallbackData, ioStatus);
2948 /* Destroy the IRP. */
2949 rdpdr_server_irp_free(irp);
2950 return CHANNEL_RC_OK;
2951}
2952
2958static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* context, wStream* s,
2959 RDPDR_IRP* irp, UINT32 deviceId,
2960 UINT32 completionId, UINT32 ioStatus)
2961{
2962 WINPR_ASSERT(context);
2963 WINPR_ASSERT(context->priv);
2964 WINPR_ASSERT(irp);
2965
2966 RdpdrServerPrivate* priv = context->priv;
2967 WLog_Print(priv->log, WLOG_DEBUG,
2968 "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%" PRIu32
2969 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2970 deviceId, completionId, ioStatus);
2971
2972 if (ioStatus != STATUS_SUCCESS)
2973 {
2974 /* Invoke the delete directory completion routine. */
2975 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
2976 /* Destroy the IRP. */
2977 rdpdr_server_irp_free(irp);
2978 return CHANNEL_RC_OK;
2979 }
2980
2981 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
2982 return ERROR_INVALID_DATA;
2983
2984 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2985 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2986 WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2987 fileInformation2str(information));
2988
2989 /* Setup the IRP. */
2990 irp->CompletionId = priv->NextCompletionId++;
2991 irp->Callback = rdpdr_server_drive_delete_directory_callback2;
2992 irp->DeviceId = deviceId;
2993 irp->FileId = fileId;
2994
2995 if (!rdpdr_server_enqueue_irp(context, irp))
2996 {
2997 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2998 rdpdr_server_irp_free(irp);
2999 return ERROR_INTERNAL_ERROR;
3000 }
3001
3002 /* Send a request to close the file */
3003 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
3004}
3005
3011static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData,
3012 UINT32 deviceId, const char* path)
3013{
3014 WINPR_ASSERT(context);
3015 WINPR_ASSERT(context->priv);
3016
3017 RDPDR_IRP* irp = nullptr;
3018 UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_delete_directory_callback1,
3019 callbackData, &irp);
3020 if (ret != CHANNEL_RC_OK)
3021 return ret;
3022
3023 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3024 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3025
3026 /* Send a request to open the file. */
3027 return rdpdr_server_send_device_create_request(
3028 context, irp->DeviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE,
3029 FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3030}
3031
3032/*************************************************
3033 * Drive Query Directory
3034 ************************************************/
3035
3041static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* context, wStream* s,
3042 RDPDR_IRP* irp, UINT32 deviceId,
3043 UINT32 completionId, UINT32 ioStatus)
3044{
3045 WINPR_ASSERT(context);
3046 WINPR_ASSERT(context->priv);
3047 WINPR_ASSERT(irp);
3048
3049 RdpdrServerPrivate* priv = context->priv;
3050 WLog_Print(priv->log, WLOG_DEBUG,
3051 "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%" PRIu32
3052 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
3053 deviceId, completionId, ioStatus);
3054
3055 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
3056 return ERROR_INVALID_DATA;
3057
3058 const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */
3059
3060 FILE_DIRECTORY_INFORMATION fdi = WINPR_C_ARRAY_INIT;
3061 if (length > 0)
3062 {
3063 UINT error = rdpdr_server_read_file_directory_information(priv->log, s, &fdi);
3064 if (error)
3065 {
3066 WLog_Print(priv->log, WLOG_ERROR,
3067 "rdpdr_server_read_file_directory_information failed with error %" PRIu32
3068 "!",
3069 error);
3070 return error;
3071 }
3072 }
3073 else
3074 {
3075 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 1))
3076 return ERROR_INVALID_DATA;
3077
3078 Stream_Seek(s, 1); /* Padding (1 byte) */
3079 }
3080
3081 if (ioStatus == STATUS_SUCCESS)
3082 {
3083 /* Invoke the query directory completion routine. */
3084 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus,
3085 length > 0 ? &fdi : nullptr);
3086 /* Setup the IRP. */
3087 irp->CompletionId = priv->NextCompletionId++;
3088 irp->Callback = rdpdr_server_drive_query_directory_callback2;
3089
3090 if (!rdpdr_server_enqueue_irp(context, irp))
3091 {
3092 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3093 rdpdr_server_irp_free(irp);
3094 return ERROR_INTERNAL_ERROR;
3095 }
3096
3097 /* Send a request to query the directory. */
3098 return rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, irp->FileId,
3099 irp->CompletionId, nullptr);
3100 }
3101 else
3102 {
3103 /* Invoke the query directory completion routine. */
3104 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, nullptr);
3105 /* Destroy the IRP. */
3106 rdpdr_server_irp_free(irp);
3107 }
3108
3109 return CHANNEL_RC_OK;
3110}
3111
3117static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* context, wStream* s,
3118 RDPDR_IRP* irp, UINT32 deviceId,
3119 UINT32 completionId, UINT32 ioStatus)
3120{
3121 WINPR_ASSERT(context);
3122 WINPR_ASSERT(context->priv);
3123 WINPR_ASSERT(irp);
3124
3125 RdpdrServerPrivate* priv = context->priv;
3126 WLog_Print(priv->log, WLOG_DEBUG,
3127 "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%" PRIu32
3128 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
3129 deviceId, completionId, ioStatus);
3130
3131 if (ioStatus != STATUS_SUCCESS)
3132 {
3133 /* Invoke the query directory completion routine. */
3134 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, nullptr);
3135 /* Destroy the IRP. */
3136 rdpdr_server_irp_free(irp);
3137 return CHANNEL_RC_OK;
3138 }
3139
3140 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
3141 return ERROR_INVALID_DATA;
3142
3143 const uint32_t fileId = Stream_Get_UINT32(s);
3144 /* Setup the IRP. */
3145 irp->CompletionId = priv->NextCompletionId++;
3146 irp->Callback = rdpdr_server_drive_query_directory_callback2;
3147 irp->DeviceId = deviceId;
3148 irp->FileId = fileId;
3149 winpr_str_append("\\*.*", irp->PathName, ARRAYSIZE(irp->PathName), nullptr);
3150
3151 if (!rdpdr_server_enqueue_irp(context, irp))
3152 {
3153 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3154 rdpdr_server_irp_free(irp);
3155 return ERROR_INTERNAL_ERROR;
3156 }
3157
3158 /* Send a request to query the directory. */
3159 return rdpdr_server_send_device_query_directory_request(context, deviceId, fileId,
3160 irp->CompletionId, irp->PathName);
3161}
3162
3168static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData,
3169 UINT32 deviceId, const char* path)
3170{
3171 WINPR_ASSERT(context);
3172 WINPR_ASSERT(context->priv);
3173
3174 RDPDR_IRP* irp = nullptr;
3175 UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_query_directory_callback1,
3176 callbackData, &irp);
3177 if (ret != CHANNEL_RC_OK)
3178 return ret;
3179
3180 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3181 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3182
3183 /* Send a request to open the directory. */
3184 return rdpdr_server_send_device_create_request(
3185 context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3186 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3187}
3188
3189/*************************************************
3190 * Drive Open File
3191 ************************************************/
3192
3198static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, wStream* s,
3199 RDPDR_IRP* irp, UINT32 deviceId,
3200 UINT32 completionId, UINT32 ioStatus)
3201{
3202 WINPR_ASSERT(context);
3203 WINPR_ASSERT(context->priv);
3204 WINPR_ASSERT(irp);
3205
3206 RdpdrServerPrivate* priv = context->priv;
3207 WLog_Print(priv->log, WLOG_DEBUG,
3208 "RdpdrServerDriveOpenFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3209 ", ioStatus=0x%" PRIx32 "",
3210 deviceId, completionId, ioStatus);
3211
3212 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3213 return ERROR_INVALID_DATA;
3214
3215 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3216 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3217 WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3218 fileInformation2str(information));
3219
3220 /* Invoke the open file completion routine. */
3221 context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, fileId);
3222 /* Destroy the IRP. */
3223 rdpdr_server_irp_free(irp);
3224 return CHANNEL_RC_OK;
3225}
3226
3232static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* callbackData,
3233 UINT32 deviceId, const char* path, UINT32 desiredAccess,
3234 UINT32 createDisposition)
3235{
3236 WINPR_ASSERT(context);
3237 WINPR_ASSERT(context->priv);
3238
3239 RDPDR_IRP* irp = nullptr;
3240 UINT ret =
3241 prepare_irp(context, deviceId, rdpdr_server_drive_open_file_callback, callbackData, &irp);
3242 if (ret != CHANNEL_RC_OK)
3243 return ret;
3244
3245 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3246 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3247
3248 /* Send a request to open the file. */
3249 return rdpdr_server_send_device_create_request(context, irp->DeviceId, irp->CompletionId,
3250 irp->PathName, desiredAccess | SYNCHRONIZE,
3251 FILE_SYNCHRONOUS_IO_NONALERT, createDisposition);
3252}
3253
3254/*************************************************
3255 * Drive Read File
3256 ************************************************/
3257
3263static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, wStream* s,
3264 RDPDR_IRP* irp, UINT32 deviceId,
3265 UINT32 completionId, UINT32 ioStatus)
3266{
3267 WINPR_ASSERT(context);
3268 WINPR_ASSERT(context->priv);
3269 WINPR_ASSERT(irp);
3270
3271 RdpdrServerPrivate* priv = context->priv;
3272 WLog_Print(priv->log, WLOG_DEBUG,
3273 "RdpdrServerDriveReadFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3274 ", ioStatus=0x%" PRIx32 "",
3275 deviceId, completionId, ioStatus);
3276
3277 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4))
3278 return ERROR_INVALID_DATA;
3279
3280 const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */
3281 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length))
3282 return ERROR_INVALID_DATA;
3283
3284 char* buffer = nullptr;
3285 if (length > 0)
3286 {
3287 buffer = Stream_PointerAs(s, char);
3288 Stream_Seek(s, length);
3289 }
3290
3291 /* Invoke the read file completion routine. */
3292 context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, length);
3293 /* Destroy the IRP. */
3294 rdpdr_server_irp_free(irp);
3295 return CHANNEL_RC_OK;
3296}
3297
3303static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* callbackData,
3304 UINT32 deviceId, UINT32 fileId, UINT32 length,
3305 UINT32 offset)
3306{
3307 WINPR_ASSERT(context);
3308 WINPR_ASSERT(context->priv);
3309
3310 RDPDR_IRP* irp = nullptr;
3311 UINT ret =
3312 prepare_irp(context, deviceId, rdpdr_server_drive_read_file_callback, callbackData, &irp);
3313 if (ret != CHANNEL_RC_OK)
3314 return ret;
3315
3316 irp->FileId = fileId;
3317
3318 /* Send a request to open the directory. */
3319 return rdpdr_server_send_device_read_request(context, irp->DeviceId, irp->FileId,
3320 irp->CompletionId, length, offset);
3321}
3322
3323/*************************************************
3324 * Drive Write File
3325 ************************************************/
3326
3332static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, wStream* s,
3333 RDPDR_IRP* irp, UINT32 deviceId,
3334 UINT32 completionId, UINT32 ioStatus)
3335{
3336 WINPR_ASSERT(context);
3337 WINPR_ASSERT(context->priv);
3338 WINPR_ASSERT(irp);
3339
3340 RdpdrServerPrivate* priv = context->priv;
3341 WLog_Print(priv->log, WLOG_DEBUG,
3342 "RdpdrServerDriveWriteFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3343 ", ioStatus=0x%" PRIx32 "",
3344 deviceId, completionId, ioStatus);
3345
3346 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3347 return ERROR_INVALID_DATA;
3348
3349 const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */
3350 Stream_Seek(s, 1); /* Padding (1 byte) */
3351
3352 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length))
3353 return ERROR_INVALID_DATA;
3354
3355 /* Invoke the write file completion routine. */
3356 context->OnDriveWriteFileComplete(context, irp->CallbackData, ioStatus, length);
3357 /* Destroy the IRP. */
3358 rdpdr_server_irp_free(irp);
3359 return CHANNEL_RC_OK;
3360}
3361
3367static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* callbackData,
3368 UINT32 deviceId, UINT32 fileId, const char* buffer,
3369 UINT32 length, UINT32 offset)
3370{
3371 WINPR_ASSERT(context);
3372 WINPR_ASSERT(context->priv);
3373
3374 RDPDR_IRP* irp = nullptr;
3375 UINT ret =
3376 prepare_irp(context, deviceId, rdpdr_server_drive_write_file_callback, callbackData, &irp);
3377 if (ret != CHANNEL_RC_OK)
3378 return ret;
3379
3380 irp->FileId = fileId;
3381
3382 /* Send a request to open the directory. */
3383 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3384 return rdpdr_server_send_device_write_request(context, irp->DeviceId, irp->FileId,
3385 irp->CompletionId, buffer, length, offset);
3386 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3387}
3388
3389/*************************************************
3390 * Drive Close File
3391 ************************************************/
3392
3398static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, wStream* s,
3399 RDPDR_IRP* irp, UINT32 deviceId,
3400 UINT32 completionId, UINT32 ioStatus)
3401{
3402 WINPR_UNUSED(s);
3403 WINPR_ASSERT(context);
3404 WINPR_ASSERT(context->priv);
3405 WINPR_ASSERT(irp);
3406
3407 RdpdrServerPrivate* priv = context->priv;
3408
3409 WLog_Print(priv->log, WLOG_DEBUG,
3410 "RdpdrServerDriveCloseFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3411 ", ioStatus=0x%" PRIx32 "",
3412 deviceId, completionId, ioStatus);
3413
3414 // padding 5 bytes
3415 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3416 return ERROR_INVALID_DATA;
3417
3418 Stream_Seek(s, 5);
3419
3420 /* Invoke the close file completion routine. */
3421 context->OnDriveCloseFileComplete(context, irp->CallbackData, ioStatus);
3422 /* Destroy the IRP. */
3423 rdpdr_server_irp_free(irp);
3424 return CHANNEL_RC_OK;
3425}
3426
3432static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData,
3433 UINT32 deviceId, UINT32 fileId)
3434{
3435 WINPR_ASSERT(context);
3436 WINPR_ASSERT(context->priv);
3437
3438 RDPDR_IRP* irp = nullptr;
3439 UINT ret =
3440 prepare_irp(context, deviceId, rdpdr_server_drive_close_file_callback, callbackData, &irp);
3441 if (ret != CHANNEL_RC_OK)
3442 return ret;
3443
3444 irp->FileId = fileId;
3445
3446 /* Send a request to open the directory. */
3447 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3448 return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId,
3449 irp->CompletionId);
3450 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3451}
3452
3453/*************************************************
3454 * Drive Delete File
3455 ************************************************/
3456
3462static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context, wStream* s,
3463 RDPDR_IRP* irp, UINT32 deviceId,
3464 UINT32 completionId, UINT32 ioStatus)
3465{
3466 WINPR_UNUSED(s);
3467 WINPR_ASSERT(context);
3468 WINPR_ASSERT(context->priv);
3469 WINPR_ASSERT(irp);
3470
3471 RdpdrServerPrivate* priv = context->priv;
3472 WLog_Print(priv->log, WLOG_DEBUG,
3473 "RdpdrServerDriveDeleteFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3474 ", ioStatus=0x%" PRIx32 "",
3475 deviceId, completionId, ioStatus);
3476 /* Invoke the delete file completion routine. */
3477 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3478 /* Destroy the IRP. */
3479 rdpdr_server_irp_free(irp);
3480 return CHANNEL_RC_OK;
3481}
3482
3488static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context, wStream* s,
3489 RDPDR_IRP* irp, UINT32 deviceId,
3490 UINT32 completionId, UINT32 ioStatus)
3491{
3492 WINPR_ASSERT(context);
3493 WINPR_ASSERT(context->priv);
3494 WINPR_ASSERT(irp);
3495
3496 RdpdrServerPrivate* priv = context->priv;
3497 WLog_Print(priv->log, WLOG_DEBUG,
3498 "RdpdrServerDriveDeleteFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3499 ", ioStatus=0x%" PRIx32 "",
3500 deviceId, completionId, ioStatus);
3501
3502 if (ioStatus != STATUS_SUCCESS)
3503 {
3504 /* Invoke the close file completion routine. */
3505 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3506 /* Destroy the IRP. */
3507 rdpdr_server_irp_free(irp);
3508 return CHANNEL_RC_OK;
3509 }
3510
3511 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3512 return ERROR_INVALID_DATA;
3513
3514 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3515 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3516
3517 WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3518 fileInformation2str(information));
3519 /* Setup the IRP. */
3520 irp->CompletionId = priv->NextCompletionId++;
3521 irp->Callback = rdpdr_server_drive_delete_file_callback2;
3522 irp->DeviceId = deviceId;
3523 irp->FileId = fileId;
3524
3525 if (!rdpdr_server_enqueue_irp(context, irp))
3526 {
3527 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3528 rdpdr_server_irp_free(irp);
3529 return ERROR_INTERNAL_ERROR;
3530 }
3531
3532 /* Send a request to close the file */
3533 return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId,
3534 irp->CompletionId);
3535}
3536
3542static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData,
3543 UINT32 deviceId, const char* path)
3544{
3545 WINPR_ASSERT(context);
3546 WINPR_ASSERT(context->priv);
3547
3548 RDPDR_IRP* irp = nullptr;
3549 UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_delete_file_callback1,
3550 callbackData, &irp);
3551 if (ret != CHANNEL_RC_OK)
3552 return ret;
3553
3554 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3555 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3556
3557 /* Send a request to open the file. */
3558 return rdpdr_server_send_device_create_request(
3559 context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3560 FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3561}
3562
3563/*************************************************
3564 * Drive Rename File
3565 ************************************************/
3566
3572static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context, wStream* s,
3573 RDPDR_IRP* irp, UINT32 deviceId,
3574 UINT32 completionId, UINT32 ioStatus)
3575{
3576 WINPR_UNUSED(context);
3577 WINPR_UNUSED(s);
3578 WINPR_ASSERT(context);
3579 WINPR_ASSERT(context->priv);
3580 WINPR_ASSERT(irp);
3581
3582 RdpdrServerPrivate* priv = context->priv;
3583 WLog_Print(priv->log, WLOG_DEBUG,
3584 "RdpdrServerDriveRenameFileCallback3: deviceId=%" PRIu32 ", completionId=%" PRIu32
3585 ", ioStatus=0x%" PRIx32 "",
3586 deviceId, completionId, ioStatus);
3587 /* Destroy the IRP. */
3588 rdpdr_server_irp_free(irp);
3589 return CHANNEL_RC_OK;
3590}
3591
3597static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context, wStream* s,
3598 RDPDR_IRP* irp, UINT32 deviceId,
3599 UINT32 completionId, UINT32 ioStatus)
3600{
3601 WINPR_ASSERT(context);
3602 WINPR_ASSERT(context->priv);
3603 WINPR_ASSERT(irp);
3604
3605 RdpdrServerPrivate* priv = context->priv;
3606 WLog_Print(priv->log, WLOG_DEBUG,
3607 "RdpdrServerDriveRenameFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3608 ", ioStatus=0x%" PRIx32 "",
3609 deviceId, completionId, ioStatus);
3610
3611 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3612 return ERROR_INVALID_DATA;
3613
3614 WINPR_ATTR_UNUSED const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */
3615 Stream_Seek(s, 1); /* Padding (1 byte) */
3616
3617 /* Invoke the rename file completion routine. */
3618 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3619 /* Setup the IRP. */
3620 irp->CompletionId = priv->NextCompletionId++;
3621 irp->Callback = rdpdr_server_drive_rename_file_callback3;
3622 irp->DeviceId = deviceId;
3623
3624 if (!rdpdr_server_enqueue_irp(context, irp))
3625 {
3626 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3627 rdpdr_server_irp_free(irp);
3628 return ERROR_INTERNAL_ERROR;
3629 }
3630
3631 /* Send a request to close the file */
3632 return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId,
3633 irp->CompletionId);
3634}
3635
3641static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context, wStream* s,
3642 RDPDR_IRP* irp, UINT32 deviceId,
3643 UINT32 completionId, UINT32 ioStatus)
3644{
3645 WINPR_ASSERT(context);
3646 WINPR_ASSERT(context->priv);
3647 WINPR_ASSERT(irp);
3648
3649 RdpdrServerPrivate* priv = context->priv;
3650 WLog_Print(priv->log, WLOG_DEBUG,
3651 "RdpdrServerDriveRenameFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3652 ", ioStatus=0x%" PRIx32 "",
3653 deviceId, completionId, ioStatus);
3654
3655 if (ioStatus != STATUS_SUCCESS)
3656 {
3657 /* Invoke the rename file completion routine. */
3658 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3659 /* Destroy the IRP. */
3660 rdpdr_server_irp_free(irp);
3661 return CHANNEL_RC_OK;
3662 }
3663
3664 if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5))
3665 return ERROR_INVALID_DATA;
3666
3667 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3668 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3669 WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3670 fileInformation2str(information));
3671
3672 /* Setup the IRP. */
3673 irp->CompletionId = priv->NextCompletionId++;
3674 irp->Callback = rdpdr_server_drive_rename_file_callback2;
3675 irp->DeviceId = deviceId;
3676 irp->FileId = fileId;
3677
3678 if (!rdpdr_server_enqueue_irp(context, irp))
3679 {
3680 WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3681 rdpdr_server_irp_free(irp);
3682 return ERROR_INTERNAL_ERROR;
3683 }
3684
3685 /* Send a request to rename the file */
3686 return rdpdr_server_send_device_file_rename_request(context, irp->DeviceId, irp->FileId,
3687 irp->CompletionId, irp->ExtraBuffer);
3688}
3689
3695static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* callbackData,
3696 UINT32 deviceId, const char* oldPath,
3697 const char* newPath)
3698{
3699 WINPR_ASSERT(context);
3700 WINPR_ASSERT(context->priv);
3701
3702 RDPDR_IRP* irp = nullptr;
3703 UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_rename_file_callback1,
3704 callbackData, &irp);
3705 if (ret != CHANNEL_RC_OK)
3706 return ret;
3707
3708 strncpy(irp->PathName, oldPath, sizeof(irp->PathName) - 1);
3709 strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer) - 1);
3710 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3711 rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer));
3712
3713 /* Send a request to open the file. */
3714 return rdpdr_server_send_device_create_request(context, irp->DeviceId, irp->CompletionId,
3715 irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3716 FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3717}
3718
3719static void rdpdr_server_private_free(RdpdrServerPrivate* ctx)
3720{
3721 if (!ctx)
3722 return;
3723 ListDictionary_Free(ctx->IrpList);
3724 HashTable_Free(ctx->devicelist);
3725 free(ctx->ClientComputerName);
3726 free(ctx);
3727}
3728
3729#define TAG CHANNELS_TAG("rdpdr.server")
3730static RdpdrServerPrivate* rdpdr_server_private_new(void)
3731{
3732 RdpdrServerPrivate* priv = (RdpdrServerPrivate*)calloc(1, sizeof(RdpdrServerPrivate));
3733
3734 if (!priv)
3735 goto fail;
3736
3737 priv->log = WLog_Get(TAG);
3738 priv->VersionMajor = RDPDR_VERSION_MAJOR;
3739 priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
3740 priv->ClientId = g_ClientId++;
3741 priv->UserLoggedOnPdu = TRUE;
3742 priv->NextCompletionId = 1;
3743 priv->haveSmartcardDevice = FALSE;
3744 priv->smartcardDeviceId = 0;
3745 priv->IrpList = ListDictionary_New(TRUE);
3746
3747 if (!priv->IrpList)
3748 goto fail;
3749
3750 ListDictionary_ValueObject(priv->IrpList)->fnObjectFree = rdpdr_server_list_free;
3751
3752 priv->devicelist = HashTable_New(FALSE);
3753 if (!priv->devicelist)
3754 goto fail;
3755
3756 if (!HashTable_SetHashFunction(priv->devicelist, rdpdr_deviceid_hash))
3757 goto fail;
3758
3759 {
3760 wObject* obj = HashTable_ValueObject(priv->devicelist);
3761 WINPR_ASSERT(obj);
3762 obj->fnObjectFree = rdpdr_device_free_h;
3763 obj->fnObjectNew = rdpdr_device_clone;
3764 }
3765
3766 {
3767 wObject* obj = HashTable_KeyObject(priv->devicelist);
3768 obj->fnObjectEquals = rdpdr_device_equal;
3769 obj->fnObjectFree = rdpdr_device_key_free;
3770 obj->fnObjectNew = rdpdr_device_key_clone;
3771 }
3772
3773 return priv;
3774fail:
3775 rdpdr_server_private_free(priv);
3776 return nullptr;
3777}
3778
3779static UINT rdpdr_server_smartcard_establish_context_callback(RdpdrServerContext* context,
3780 wStream* s, RDPDR_IRP* irp,
3781 UINT32 deviceId, UINT32 completionId,
3782 UINT32 ioStatus)
3783{
3784 WINPR_ASSERT(context);
3785 WINPR_ASSERT(context->priv);
3786 WINPR_ASSERT(s);
3787 WINPR_ASSERT(irp);
3788
3789 UINT result = CHANNEL_RC_OK;
3790 RdpdrServerPrivate* priv = context->priv;
3791 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
3792
3793 WLog_Print(priv->log, WLOG_DEBUG,
3794 "RdpdrServerSmartcardEstablishContextCallback: deviceId=%" PRIu32
3795 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
3796 deviceId, completionId, ioStatus);
3797
3798 if (ioStatus != STATUS_SUCCESS)
3799 {
3800 if (context->OnSmartcardEstablishContextComplete)
3801 context->OnSmartcardEstablishContextComplete(context, irp->CallbackData, ioStatus,
3802 SCARD_F_INTERNAL_ERROR, nullptr);
3803 goto out;
3804 }
3805
3806 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
3807 if (rc != SCARD_S_SUCCESS)
3808 {
3809 result = ERROR_INVALID_DATA;
3810 goto out;
3811 }
3812
3813 if (context->OnSmartcardEstablishContextComplete)
3814 context->OnSmartcardEstablishContextComplete(context, irp->CallbackData, ioStatus,
3815 op.returnCode, &op.ret.establishContext);
3816
3817out:
3818 smartcard_operation_free(&op, FALSE);
3819 rdpdr_server_irp_free(irp);
3820 return result;
3821}
3822
3823static UINT rdpdr_server_smartcard_establish_context(RdpdrServerContext* context,
3824 void* callbackData, UINT32 dwScope,
3825 UINT32* completionId)
3826{
3827 WINPR_ASSERT(context);
3828 WINPR_ASSERT(context->priv);
3829 WINPR_ASSERT(completionId);
3830
3831 RdpdrServerPrivate* priv = context->priv;
3832 RDPDR_IRP* irp = nullptr;
3833
3834 switch (dwScope)
3835 {
3836 case SCARD_SCOPE_USER:
3837 case SCARD_SCOPE_TERMINAL:
3838 case SCARD_SCOPE_SYSTEM:
3839 break;
3840 default:
3841 WLog_Print(priv->log, WLOG_ERROR, "invalid dwScope=0x%08" PRIx32, dwScope);
3842 return ERROR_INVALID_PARAMETER;
3843 }
3844
3845 UINT result = prepare_smartcard_irp(context, SCARD_IOCTL_ESTABLISHCONTEXT,
3846 rdpdr_server_smartcard_establish_context_callback,
3847 callbackData, &irp);
3848 if (result != CHANNEL_RC_OK)
3849 return result;
3850
3851 WINPR_ASSERT(irp);
3852 *completionId = irp->CompletionId;
3853
3854 const SMARTCARD_OPERATION op = {
3855 .ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT,
3856 .call.establishContext.dwScope = dwScope,
3857 };
3858
3859 wStream* s = Stream_New(nullptr, 64);
3860 if (!s)
3861 {
3862 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
3863 result = CHANNEL_RC_NO_MEMORY;
3864 goto out;
3865 }
3866
3867 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
3868 if (rc != SCARD_S_SUCCESS)
3869 {
3870 result = ERROR_INTERNAL_ERROR;
3871 goto out;
3872 }
3873
3874 result = rdpdr_server_send_device_control_request(
3875 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
3876 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
3877
3878out:
3879 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3880 if (result != CHANNEL_RC_OK)
3881 rdpdr_server_discard_request(context, irp->CompletionId);
3882 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3883 if (s)
3884 Stream_Release(s);
3885 return result;
3886}
3887
3888/* ReleaseContext */
3889static UINT rdpdr_server_smartcard_release_context_callback(RdpdrServerContext* context, wStream* s,
3890 RDPDR_IRP* irp, UINT32 deviceId,
3891 UINT32 completionId, UINT32 ioStatus)
3892{
3893 WINPR_ASSERT(context);
3894 WINPR_ASSERT(context->priv);
3895 WINPR_ASSERT(s);
3896 WINPR_ASSERT(irp);
3897
3898 UINT result = CHANNEL_RC_OK;
3899 RdpdrServerPrivate* priv = context->priv;
3900 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
3901
3902 WLog_Print(priv->log, WLOG_DEBUG,
3903 "SmartcardReleaseContextCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3904 ", ioStatus=0x%" PRIx32,
3905 deviceId, completionId, ioStatus);
3906
3907 if (ioStatus != STATUS_SUCCESS)
3908 {
3909 if (context->OnSmartcardReleaseContextComplete)
3910 context->OnSmartcardReleaseContextComplete(context, irp->CallbackData, ioStatus,
3911 SCARD_F_INTERNAL_ERROR);
3912 goto out;
3913 }
3914
3915 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
3916 if (rc != SCARD_S_SUCCESS)
3917 {
3918 result = ERROR_INVALID_DATA;
3919 goto out;
3920 }
3921
3922 if (context->OnSmartcardReleaseContextComplete)
3923 context->OnSmartcardReleaseContextComplete(context, irp->CallbackData, ioStatus,
3924 op.returnCode);
3925
3926out:
3927 smartcard_operation_free(&op, FALSE);
3928 rdpdr_server_irp_free(irp);
3929 return result;
3930}
3931
3932static UINT rdpdr_server_smartcard_release_context(RdpdrServerContext* context, void* callbackData,
3933 const REDIR_SCARDCONTEXT* hContext,
3934 UINT32* completionId)
3935{
3936 WINPR_ASSERT(context);
3937 WINPR_ASSERT(context->priv);
3938 WINPR_ASSERT(hContext);
3939 WINPR_ASSERT(completionId);
3940
3941 RdpdrServerPrivate* priv = context->priv;
3942 RDPDR_IRP* irp = nullptr;
3943
3944 UINT result =
3945 prepare_smartcard_irp(context, SCARD_IOCTL_RELEASECONTEXT,
3946 rdpdr_server_smartcard_release_context_callback, callbackData, &irp);
3947 if (result != CHANNEL_RC_OK)
3948 return result;
3949 WINPR_ASSERT(irp);
3950 *completionId = irp->CompletionId;
3951
3952 const SMARTCARD_OPERATION op = {
3953 .ioControlCode = SCARD_IOCTL_RELEASECONTEXT,
3954 .call.context.handles.hContext = *hContext,
3955 };
3956
3957 wStream* s = Stream_New(nullptr, 64);
3958 if (!s)
3959 {
3960 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
3961 result = CHANNEL_RC_NO_MEMORY;
3962 goto out;
3963 }
3964
3965 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
3966 if (rc != SCARD_S_SUCCESS)
3967 {
3968 result = ERROR_INTERNAL_ERROR;
3969 goto out;
3970 }
3971
3972 result = rdpdr_server_send_device_control_request(
3973 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
3974 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
3975
3976out:
3977 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3978 if (result != CHANNEL_RC_OK)
3979 rdpdr_server_discard_request(context, irp->CompletionId);
3980 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
3981 if (s)
3982 Stream_Release(s);
3983 return result;
3984}
3985
3986/* IsValidContext */
3987static UINT rdpdr_server_smartcard_is_valid_context_callback(RdpdrServerContext* context,
3988 wStream* s, RDPDR_IRP* irp,
3989 UINT32 deviceId, UINT32 completionId,
3990 UINT32 ioStatus)
3991{
3992 WINPR_ASSERT(context);
3993 WINPR_ASSERT(context->priv);
3994 WINPR_ASSERT(s);
3995 WINPR_ASSERT(irp);
3996
3997 UINT result = CHANNEL_RC_OK;
3998 RdpdrServerPrivate* priv = context->priv;
3999 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4000
4001 WLog_Print(priv->log, WLOG_DEBUG,
4002 "SmartcardIsValidContextCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4003 ", ioStatus=0x%" PRIx32,
4004 deviceId, completionId, ioStatus);
4005
4006 if (ioStatus != STATUS_SUCCESS)
4007 {
4008 if (context->OnSmartcardIsValidContextComplete)
4009 context->OnSmartcardIsValidContextComplete(context, irp->CallbackData, ioStatus,
4010 SCARD_F_INTERNAL_ERROR);
4011 goto out;
4012 }
4013
4014 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4015 if (rc != SCARD_S_SUCCESS)
4016 {
4017 result = ERROR_INVALID_DATA;
4018 goto out;
4019 }
4020
4021 if (context->OnSmartcardIsValidContextComplete)
4022 context->OnSmartcardIsValidContextComplete(context, irp->CallbackData, ioStatus,
4023 op.returnCode);
4024
4025out:
4026 smartcard_operation_free(&op, FALSE);
4027 rdpdr_server_irp_free(irp);
4028 return result;
4029}
4030
4031static UINT rdpdr_server_smartcard_is_valid_context(RdpdrServerContext* context, void* callbackData,
4032 const REDIR_SCARDCONTEXT* hContext,
4033 UINT32* completionId)
4034{
4035 WINPR_ASSERT(context);
4036 WINPR_ASSERT(context->priv);
4037 WINPR_ASSERT(hContext);
4038 WINPR_ASSERT(completionId);
4039
4040 RdpdrServerPrivate* priv = context->priv;
4041 RDPDR_IRP* irp = nullptr;
4042
4043 UINT result =
4044 prepare_smartcard_irp(context, SCARD_IOCTL_ISVALIDCONTEXT,
4045 rdpdr_server_smartcard_is_valid_context_callback, callbackData, &irp);
4046 if (result != CHANNEL_RC_OK)
4047 return result;
4048
4049 WINPR_ASSERT(irp);
4050 *completionId = irp->CompletionId;
4051
4052 const SMARTCARD_OPERATION op = {
4053 .ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT,
4054 .call.context.handles.hContext = *hContext,
4055 };
4056
4057 wStream* s = Stream_New(nullptr, 64);
4058 if (!s)
4059 {
4060 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4061 result = CHANNEL_RC_NO_MEMORY;
4062 goto out;
4063 }
4064
4065 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4066 if (rc != SCARD_S_SUCCESS)
4067 {
4068 result = ERROR_INTERNAL_ERROR;
4069 goto out;
4070 }
4071
4072 result = rdpdr_server_send_device_control_request(
4073 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4074 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4075
4076out:
4077 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4078 if (result != CHANNEL_RC_OK)
4079 rdpdr_server_discard_request(context, irp->CompletionId);
4080 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4081 if (s)
4082 Stream_Release(s);
4083 return result;
4084}
4085
4086/* ListReaderGroups */
4087static UINT rdpdr_server_smartcard_list_reader_groups_callback(RdpdrServerContext* context,
4088 wStream* s, RDPDR_IRP* irp,
4089 UINT32 deviceId, UINT32 completionId,
4090 UINT32 ioStatus)
4091{
4092 WINPR_ASSERT(context);
4093 WINPR_ASSERT(context->priv);
4094 WINPR_ASSERT(s);
4095 WINPR_ASSERT(irp);
4096
4097 UINT result = CHANNEL_RC_OK;
4098 RdpdrServerPrivate* priv = context->priv;
4099 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4100
4101 WLog_Print(priv->log, WLOG_DEBUG,
4102 "SmartcardListReaderGroupsCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4103 ", ioStatus=0x%" PRIx32,
4104 deviceId, completionId, ioStatus);
4105
4106 if (ioStatus != STATUS_SUCCESS)
4107 {
4108 if (context->OnSmartcardListReaderGroupsComplete)
4109 context->OnSmartcardListReaderGroupsComplete(context, irp->CallbackData, ioStatus,
4110 SCARD_F_INTERNAL_ERROR, nullptr);
4111 goto out;
4112 }
4113
4114 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4115 if (rc != SCARD_S_SUCCESS)
4116 {
4117 result = ERROR_INVALID_DATA;
4118 goto out;
4119 }
4120
4121 if (context->OnSmartcardListReaderGroupsComplete)
4122 context->OnSmartcardListReaderGroupsComplete(context, irp->CallbackData, ioStatus,
4123 op.returnCode, &op.ret.listReaders);
4124
4125out:
4126 smartcard_operation_free(&op, FALSE);
4127 rdpdr_server_irp_free(irp);
4128 return result;
4129}
4130
4131static UINT rdpdr_server_smartcard_list_reader_groups(RdpdrServerContext* context,
4132 void* callbackData, UINT32 ioControlCode,
4133 const ListReaderGroups_Call* call,
4134 UINT32* completionId)
4135{
4136 WINPR_ASSERT(context);
4137 WINPR_ASSERT(context->priv);
4138 WINPR_ASSERT(call);
4139 WINPR_ASSERT(completionId);
4140
4141 RdpdrServerPrivate* priv = context->priv;
4142 RDPDR_IRP* irp = nullptr;
4143
4144 UINT result = prepare_smartcard_irp(context, ioControlCode,
4145 rdpdr_server_smartcard_list_reader_groups_callback,
4146 callbackData, &irp);
4147 if (result != CHANNEL_RC_OK)
4148 return result;
4149
4150 WINPR_ASSERT(irp);
4151 *completionId = irp->CompletionId;
4152
4153 const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode,
4154 .call.listReaderGroups = {
4155 .handles.hContext = call->handles.hContext,
4156 .fmszGroupsIsNULL = call->fmszGroupsIsNULL,
4157 .cchGroups = call->cchGroups,
4158 } };
4159
4160 wStream* s = Stream_New(nullptr, 32);
4161 if (!s)
4162 {
4163 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4164 result = CHANNEL_RC_NO_MEMORY;
4165 goto out;
4166 }
4167
4168 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4169 if (rc != SCARD_S_SUCCESS)
4170 {
4171 result = ERROR_INTERNAL_ERROR;
4172 goto out;
4173 }
4174
4175 result = rdpdr_server_send_device_control_request(
4176 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4177 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4178
4179out:
4180 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4181 if (result != CHANNEL_RC_OK)
4182 rdpdr_server_discard_request(context, irp->CompletionId);
4183 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4184 if (s)
4185 Stream_Release(s);
4186 return result;
4187}
4188
4189static UINT rdpdr_server_smartcard_list_reader_groupsA(RdpdrServerContext* context,
4190 void* callbackData,
4191 const ListReaderGroups_Call* call,
4192 UINT32* completionId)
4193{
4194 return rdpdr_server_smartcard_list_reader_groups(
4195 context, callbackData, SCARD_IOCTL_LISTREADERGROUPSA, call, completionId);
4196}
4197
4198static UINT rdpdr_server_smartcard_list_reader_groupsW(RdpdrServerContext* context,
4199 void* callbackData,
4200 const ListReaderGroups_Call* call,
4201 UINT32* completionId)
4202{
4203 return rdpdr_server_smartcard_list_reader_groups(
4204 context, callbackData, SCARD_IOCTL_LISTREADERGROUPSW, call, completionId);
4205}
4206
4207/* ListReaders */
4208static UINT rdpdr_server_smartcard_list_readers_callback(RdpdrServerContext* context, wStream* s,
4209 RDPDR_IRP* irp, UINT32 deviceId,
4210 UINT32 completionId, UINT32 ioStatus)
4211{
4212 WINPR_ASSERT(context);
4213 WINPR_ASSERT(context->priv);
4214 WINPR_ASSERT(s);
4215 WINPR_ASSERT(irp);
4216
4217 UINT result = CHANNEL_RC_OK;
4218 RdpdrServerPrivate* priv = context->priv;
4219 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4220
4221 WLog_Print(priv->log, WLOG_DEBUG,
4222 "SmartcardListReadersCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4223 ", ioStatus=0x%" PRIx32,
4224 deviceId, completionId, ioStatus);
4225
4226 if (ioStatus != STATUS_SUCCESS)
4227 {
4228 if (context->OnSmartcardListReadersComplete)
4229 context->OnSmartcardListReadersComplete(context, irp->CallbackData, ioStatus,
4230 SCARD_F_INTERNAL_ERROR, nullptr);
4231 goto out;
4232 }
4233
4234 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4235 if (rc != SCARD_S_SUCCESS)
4236 {
4237 result = ERROR_INVALID_DATA;
4238 goto out;
4239 }
4240
4241 if (context->OnSmartcardListReadersComplete)
4242 context->OnSmartcardListReadersComplete(context, irp->CallbackData, ioStatus, op.returnCode,
4243 &op.ret.listReaders);
4244
4245out:
4246 smartcard_operation_free(&op, FALSE);
4247 rdpdr_server_irp_free(irp);
4248 return result;
4249}
4250
4251static UINT rdpdr_server_smartcard_list_readers(RdpdrServerContext* context, void* callbackData,
4252 UINT32 ioControlCode, const ListReaders_Call* call,
4253 UINT32* completionId)
4254{
4255 WINPR_ASSERT(context);
4256 WINPR_ASSERT(context->priv);
4257 WINPR_ASSERT(call);
4258 WINPR_ASSERT(completionId);
4259
4260 RdpdrServerPrivate* priv = context->priv;
4261 RDPDR_IRP* irp = nullptr;
4262
4263 UINT result = prepare_smartcard_irp(
4264 context, ioControlCode, rdpdr_server_smartcard_list_readers_callback, callbackData, &irp);
4265 if (result != CHANNEL_RC_OK)
4266 return result;
4267
4268 WINPR_ASSERT(irp);
4269 *completionId = irp->CompletionId;
4270
4271 const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode,
4272 .call.listReaders = {
4273 .handles.hContext = call->handles.hContext,
4274 .cBytes = call->cBytes,
4275 .mszGroups = call->mszGroups,
4276 .fmszReadersIsNULL = call->fmszReadersIsNULL,
4277 .cchReaders = call->cchReaders,
4278 } };
4279
4280 wStream* s = Stream_New(nullptr, 256);
4281 if (!s)
4282 {
4283 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4284 result = CHANNEL_RC_NO_MEMORY;
4285 goto out;
4286 }
4287
4288 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4289 if (rc != SCARD_S_SUCCESS)
4290 {
4291 result = ERROR_INTERNAL_ERROR;
4292 goto out;
4293 }
4294
4295 result = rdpdr_server_send_device_control_request(
4296 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4297 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4298
4299out:
4300 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4301 if (result != CHANNEL_RC_OK)
4302 rdpdr_server_discard_request(context, irp->CompletionId);
4303 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4304 if (s)
4305 Stream_Release(s);
4306 return result;
4307}
4308
4309static UINT rdpdr_server_smartcard_list_readersA(RdpdrServerContext* context, void* callbackData,
4310 const ListReaders_Call* call, UINT32* completionId)
4311{
4312 return rdpdr_server_smartcard_list_readers(context, callbackData, SCARD_IOCTL_LISTREADERSA,
4313 call, completionId);
4314}
4315
4316static UINT rdpdr_server_smartcard_list_readersW(RdpdrServerContext* context, void* callbackData,
4317 const ListReaders_Call* call, UINT32* completionId)
4318{
4319 return rdpdr_server_smartcard_list_readers(context, callbackData, SCARD_IOCTL_LISTREADERSW,
4320 call, completionId);
4321}
4322
4323/* GetStatusChange */
4324static UINT rdpdr_server_smartcard_get_status_change_callback(RdpdrServerContext* context,
4325 wStream* s, RDPDR_IRP* irp,
4326 UINT32 deviceId, UINT32 completionId,
4327 UINT32 ioStatus)
4328{
4329 WINPR_ASSERT(context);
4330 WINPR_ASSERT(context->priv);
4331 WINPR_ASSERT(s);
4332 WINPR_ASSERT(irp);
4333
4334 UINT result = CHANNEL_RC_OK;
4335 RdpdrServerPrivate* priv = context->priv;
4336 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4337
4338 WLog_Print(priv->log, WLOG_DEBUG,
4339 "SmartcardGetStatusChangeCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4340 ", ioStatus=0x%" PRIx32,
4341 deviceId, completionId, ioStatus);
4342
4343 if (ioStatus != STATUS_SUCCESS)
4344 {
4345 if (context->OnSmartcardGetStatusChangeComplete)
4346 context->OnSmartcardGetStatusChangeComplete(context, irp->CallbackData, ioStatus,
4347 SCARD_F_INTERNAL_ERROR, nullptr);
4348 goto out;
4349 }
4350
4351 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4352 if (rc != SCARD_S_SUCCESS)
4353 {
4354 result = ERROR_INVALID_DATA;
4355 goto out;
4356 }
4357
4358 if (context->OnSmartcardGetStatusChangeComplete)
4359 context->OnSmartcardGetStatusChangeComplete(context, irp->CallbackData, ioStatus,
4360 op.returnCode, &op.ret.getStatusChange);
4361
4362out:
4363 smartcard_operation_free(&op, FALSE);
4364 rdpdr_server_irp_free(irp);
4365 return result;
4366}
4367
4368static UINT rdpdr_server_smartcard_get_status_change(RdpdrServerContext* context,
4369 void* callbackData, UINT32 ioControlCode,
4370 const void* call, DWORD cReaders,
4371 UINT32* completionId)
4372{
4373 WINPR_ASSERT(context);
4374 WINPR_ASSERT(context->priv);
4375 WINPR_ASSERT(call);
4376 WINPR_ASSERT(completionId);
4377
4378 RdpdrServerPrivate* priv = context->priv;
4379 RDPDR_IRP* irp = nullptr;
4380
4381 UINT result = prepare_smartcard_irp(context, ioControlCode,
4382 rdpdr_server_smartcard_get_status_change_callback,
4383 callbackData, &irp);
4384 if (result != CHANNEL_RC_OK)
4385 return result;
4386
4387 WINPR_ASSERT(irp);
4388 *completionId = irp->CompletionId;
4389
4390 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4391 op.ioControlCode = ioControlCode;
4392
4393 switch (ioControlCode)
4394 {
4395 case SCARD_IOCTL_GETSTATUSCHANGEA:
4396 op.call.getStatusChangeA = *(const GetStatusChangeA_Call*)call;
4397 break;
4398 case SCARD_IOCTL_GETSTATUSCHANGEW:
4399 op.call.getStatusChangeW = *(const GetStatusChangeW_Call*)call;
4400 break;
4401 default:
4402 WINPR_ASSERT(FALSE);
4403 return ERROR_INVALID_PARAMETER;
4404 }
4405
4406 wStream* s = Stream_New(nullptr, 256 + cReaders * 256);
4407 if (!s)
4408 {
4409 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4410 result = CHANNEL_RC_NO_MEMORY;
4411 goto out;
4412 }
4413
4414 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4415 if (rc != SCARD_S_SUCCESS)
4416 {
4417 result = ERROR_INTERNAL_ERROR;
4418 goto out;
4419 }
4420
4421 result = rdpdr_server_send_device_control_request(
4422 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4423 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4424
4425out:
4426 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4427 if (result != CHANNEL_RC_OK)
4428 rdpdr_server_discard_request(context, irp->CompletionId);
4429 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4430 if (s)
4431 Stream_Release(s);
4432 return result;
4433}
4434
4435static UINT rdpdr_server_smartcard_get_status_changeA(RdpdrServerContext* context,
4436 void* callbackData,
4437 const GetStatusChangeA_Call* call,
4438 UINT32* completionId)
4439{
4440 return rdpdr_server_smartcard_get_status_change(
4441 context, callbackData, SCARD_IOCTL_GETSTATUSCHANGEA, call, call->cReaders, completionId);
4442}
4443
4444static UINT rdpdr_server_smartcard_get_status_changeW(RdpdrServerContext* context,
4445 void* callbackData,
4446 const GetStatusChangeW_Call* call,
4447 UINT32* completionId)
4448{
4449 return rdpdr_server_smartcard_get_status_change(
4450 context, callbackData, SCARD_IOCTL_GETSTATUSCHANGEW, call, call->cReaders, completionId);
4451}
4452
4453/* Cancel */
4454static UINT rdpdr_server_smartcard_cancel_callback(RdpdrServerContext* context, wStream* s,
4455 RDPDR_IRP* irp, UINT32 deviceId,
4456 UINT32 completionId, UINT32 ioStatus)
4457{
4458 WINPR_ASSERT(context);
4459 WINPR_ASSERT(context->priv);
4460 WINPR_ASSERT(s);
4461 WINPR_ASSERT(irp);
4462
4463 UINT result = CHANNEL_RC_OK;
4464 RdpdrServerPrivate* priv = context->priv;
4465 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4466
4467 WLog_Print(priv->log, WLOG_DEBUG,
4468 "SmartcardCancelCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4469 ", ioStatus=0x%" PRIx32,
4470 deviceId, completionId, ioStatus);
4471
4472 if (ioStatus != STATUS_SUCCESS)
4473 {
4474 if (context->OnSmartcardCancelComplete)
4475 context->OnSmartcardCancelComplete(context, irp->CallbackData, ioStatus,
4476 SCARD_F_INTERNAL_ERROR);
4477 goto out;
4478 }
4479
4480 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4481 if (rc != SCARD_S_SUCCESS)
4482 {
4483 result = ERROR_INVALID_DATA;
4484 goto out;
4485 }
4486
4487 if (context->OnSmartcardCancelComplete)
4488 context->OnSmartcardCancelComplete(context, irp->CallbackData, ioStatus, op.returnCode);
4489
4490out:
4491 smartcard_operation_free(&op, FALSE);
4492 rdpdr_server_irp_free(irp);
4493 return result;
4494}
4495
4496static UINT rdpdr_server_smartcard_cancel(RdpdrServerContext* context, void* callbackData,
4497 const REDIR_SCARDCONTEXT* hContext, UINT32* completionId)
4498{
4499 WINPR_ASSERT(context);
4500 WINPR_ASSERT(context->priv);
4501 WINPR_ASSERT(hContext);
4502 WINPR_ASSERT(completionId);
4503
4504 RdpdrServerPrivate* priv = context->priv;
4505 RDPDR_IRP* irp = nullptr;
4506
4507 UINT result = prepare_smartcard_irp(context, SCARD_IOCTL_CANCEL,
4508 rdpdr_server_smartcard_cancel_callback, callbackData, &irp);
4509 if (result != CHANNEL_RC_OK)
4510 return result;
4511
4512 WINPR_ASSERT(irp);
4513 *completionId = irp->CompletionId;
4514
4515 const SMARTCARD_OPERATION op = {
4516 .ioControlCode = SCARD_IOCTL_CANCEL,
4517 .call.context.handles.hContext = *hContext,
4518 };
4519
4520 wStream* s = Stream_New(nullptr, 64);
4521 if (!s)
4522 {
4523 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4524 result = CHANNEL_RC_NO_MEMORY;
4525 goto out;
4526 }
4527
4528 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4529 if (rc != SCARD_S_SUCCESS)
4530 {
4531 result = ERROR_INTERNAL_ERROR;
4532 goto out;
4533 }
4534
4535 result = rdpdr_server_send_device_control_request(
4536 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4537 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4538
4539out:
4540 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4541 if (result != CHANNEL_RC_OK)
4542 rdpdr_server_discard_request(context, irp->CompletionId);
4543 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4544 if (s)
4545 Stream_Release(s);
4546 return result;
4547}
4548
4549/* Connect */
4550static UINT rdpdr_server_smartcard_connect_callback(RdpdrServerContext* context, wStream* s,
4551 RDPDR_IRP* irp, UINT32 deviceId,
4552 UINT32 completionId, UINT32 ioStatus)
4553{
4554 WINPR_ASSERT(context);
4555 WINPR_ASSERT(context->priv);
4556 WINPR_ASSERT(s);
4557 WINPR_ASSERT(irp);
4558
4559 UINT result = CHANNEL_RC_OK;
4560 RdpdrServerPrivate* priv = context->priv;
4561 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4562
4563 WLog_Print(priv->log, WLOG_DEBUG,
4564 "SmartcardConnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4565 ", ioStatus=0x%" PRIx32,
4566 deviceId, completionId, ioStatus);
4567
4568 if (ioStatus != STATUS_SUCCESS)
4569 {
4570 if (context->OnSmartcardConnectComplete)
4571 context->OnSmartcardConnectComplete(context, irp->CallbackData, ioStatus,
4572 SCARD_F_INTERNAL_ERROR, nullptr);
4573 goto out;
4574 }
4575
4576 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4577 if (rc != SCARD_S_SUCCESS)
4578 {
4579 result = ERROR_INVALID_DATA;
4580 goto out;
4581 }
4582
4583 if (context->OnSmartcardConnectComplete)
4584 context->OnSmartcardConnectComplete(context, irp->CallbackData, ioStatus, op.returnCode,
4585 &op.ret.connect);
4586
4587out:
4588 smartcard_operation_free(&op, FALSE);
4589 rdpdr_server_irp_free(irp);
4590 return result;
4591}
4592
4593static UINT rdpdr_server_smartcard_connect(RdpdrServerContext* context, void* callbackData,
4594 UINT32 ioControlCode, const void* call,
4595 UINT32* completionId)
4596{
4597 WINPR_ASSERT(context);
4598 WINPR_ASSERT(context->priv);
4599 WINPR_ASSERT(call);
4600 WINPR_ASSERT(completionId);
4601
4602 RdpdrServerPrivate* priv = context->priv;
4603 RDPDR_IRP* irp = nullptr;
4604
4605 UINT result = prepare_smartcard_irp(
4606 context, ioControlCode, rdpdr_server_smartcard_connect_callback, callbackData, &irp);
4607 if (result != CHANNEL_RC_OK)
4608 return result;
4609
4610 WINPR_ASSERT(irp);
4611 *completionId = irp->CompletionId;
4612
4613 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4614 op.ioControlCode = ioControlCode;
4615
4616 switch (ioControlCode)
4617 {
4618 case SCARD_IOCTL_CONNECTA:
4619 op.call.connectA = *(const ConnectA_Call*)call;
4620 break;
4621 case SCARD_IOCTL_CONNECTW:
4622 op.call.connectW = *(const ConnectW_Call*)call;
4623 break;
4624 default:
4625 WINPR_ASSERT(FALSE);
4626 return ERROR_INVALID_PARAMETER;
4627 }
4628
4629 wStream* s = Stream_New(nullptr, 512);
4630 if (!s)
4631 {
4632 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4633 result = CHANNEL_RC_NO_MEMORY;
4634 goto out;
4635 }
4636
4637 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4638 if (rc != SCARD_S_SUCCESS)
4639 {
4640 result = ERROR_INTERNAL_ERROR;
4641 goto out;
4642 }
4643
4644 result = rdpdr_server_send_device_control_request(
4645 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4646 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4647
4648out:
4649 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4650 if (result != CHANNEL_RC_OK)
4651 rdpdr_server_discard_request(context, irp->CompletionId);
4652 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4653 if (s)
4654 Stream_Release(s);
4655 return result;
4656}
4657
4658static UINT rdpdr_server_smartcard_connectA(RdpdrServerContext* context, void* callbackData,
4659 const ConnectA_Call* call, UINT32* completionId)
4660{
4661 return rdpdr_server_smartcard_connect(context, callbackData, SCARD_IOCTL_CONNECTA, call,
4662 completionId);
4663}
4664
4665static UINT rdpdr_server_smartcard_connectW(RdpdrServerContext* context, void* callbackData,
4666 const ConnectW_Call* call, UINT32* completionId)
4667{
4668 return rdpdr_server_smartcard_connect(context, callbackData, SCARD_IOCTL_CONNECTW, call,
4669 completionId);
4670}
4671
4672/* Reconnect */
4673static UINT rdpdr_server_smartcard_reconnect_callback(RdpdrServerContext* context, wStream* s,
4674 RDPDR_IRP* irp, UINT32 deviceId,
4675 UINT32 completionId, UINT32 ioStatus)
4676{
4677 WINPR_ASSERT(context);
4678 WINPR_ASSERT(context->priv);
4679 WINPR_ASSERT(s);
4680 WINPR_ASSERT(irp);
4681
4682 UINT result = CHANNEL_RC_OK;
4683 RdpdrServerPrivate* priv = context->priv;
4684 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4685
4686 WLog_Print(priv->log, WLOG_DEBUG,
4687 "SmartcardReconnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4688 ", ioStatus=0x%" PRIx32,
4689 deviceId, completionId, ioStatus);
4690
4691 if (ioStatus != STATUS_SUCCESS)
4692 {
4693 if (context->OnSmartcardReconnectComplete)
4694 context->OnSmartcardReconnectComplete(context, irp->CallbackData, ioStatus,
4695 SCARD_F_INTERNAL_ERROR, nullptr);
4696 goto out;
4697 }
4698
4699 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4700 if (rc != SCARD_S_SUCCESS)
4701 {
4702 result = ERROR_INVALID_DATA;
4703 goto out;
4704 }
4705
4706 if (context->OnSmartcardReconnectComplete)
4707 context->OnSmartcardReconnectComplete(context, irp->CallbackData, ioStatus, op.returnCode,
4708 &op.ret.reconnect);
4709
4710out:
4711 smartcard_operation_free(&op, FALSE);
4712 rdpdr_server_irp_free(irp);
4713 return result;
4714}
4715
4716static UINT rdpdr_server_smartcard_reconnect(RdpdrServerContext* context, void* callbackData,
4717 const Reconnect_Call* call, UINT32* completionId)
4718{
4719 WINPR_ASSERT(context);
4720 WINPR_ASSERT(context->priv);
4721 WINPR_ASSERT(call);
4722 WINPR_ASSERT(completionId);
4723
4724 RdpdrServerPrivate* priv = context->priv;
4725 RDPDR_IRP* irp = nullptr;
4726
4727 UINT result =
4728 prepare_smartcard_irp(context, SCARD_IOCTL_RECONNECT,
4729 rdpdr_server_smartcard_reconnect_callback, callbackData, &irp);
4730 if (result != CHANNEL_RC_OK)
4731 return result;
4732
4733 WINPR_ASSERT(irp);
4734 *completionId = irp->CompletionId;
4735
4736 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_RECONNECT,
4737 .call.reconnect = {
4738 .handles.hContext = call->handles.hContext,
4739 .handles.hCard = call->handles.hCard,
4740 .dwShareMode = call->dwShareMode,
4741 .dwPreferredProtocols = call->dwPreferredProtocols,
4742 .dwInitialization = call->dwInitialization,
4743 } };
4744
4745 wStream* s = Stream_New(nullptr, 128);
4746 if (!s)
4747 {
4748 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4749 result = CHANNEL_RC_NO_MEMORY;
4750 goto out;
4751 }
4752
4753 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4754 if (rc != SCARD_S_SUCCESS)
4755 {
4756 result = ERROR_INTERNAL_ERROR;
4757 goto out;
4758 }
4759
4760 result = rdpdr_server_send_device_control_request(
4761 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4762 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4763
4764out:
4765 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4766 if (result != CHANNEL_RC_OK)
4767 rdpdr_server_discard_request(context, irp->CompletionId);
4768 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4769 if (s)
4770 Stream_Release(s);
4771 return result;
4772}
4773
4774/* Disconnect */
4775static UINT rdpdr_server_smartcard_disconnect_callback(RdpdrServerContext* context, wStream* s,
4776 RDPDR_IRP* irp, UINT32 deviceId,
4777 UINT32 completionId, UINT32 ioStatus)
4778{
4779 WINPR_ASSERT(context);
4780 WINPR_ASSERT(context->priv);
4781 WINPR_ASSERT(s);
4782 WINPR_ASSERT(irp);
4783
4784 UINT result = CHANNEL_RC_OK;
4785 RdpdrServerPrivate* priv = context->priv;
4786 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4787
4788 WLog_Print(priv->log, WLOG_DEBUG,
4789 "SmartcardDisconnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4790 ", ioStatus=0x%" PRIx32,
4791 deviceId, completionId, ioStatus);
4792
4793 if (ioStatus != STATUS_SUCCESS)
4794 {
4795 if (context->OnSmartcardDisconnectComplete)
4796 context->OnSmartcardDisconnectComplete(context, irp->CallbackData, ioStatus,
4797 SCARD_F_INTERNAL_ERROR);
4798 goto out;
4799 }
4800
4801 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4802 if (rc != SCARD_S_SUCCESS)
4803 {
4804 result = ERROR_INVALID_DATA;
4805 goto out;
4806 }
4807
4808 if (context->OnSmartcardDisconnectComplete)
4809 context->OnSmartcardDisconnectComplete(context, irp->CallbackData, ioStatus, op.returnCode);
4810
4811out:
4812 smartcard_operation_free(&op, FALSE);
4813 rdpdr_server_irp_free(irp);
4814 return result;
4815}
4816
4817static UINT rdpdr_server_smartcard_disconnect(RdpdrServerContext* context, void* callbackData,
4818 const HCardAndDisposition_Call* call,
4819 UINT32* completionId)
4820{
4821 WINPR_ASSERT(context);
4822 WINPR_ASSERT(context->priv);
4823 WINPR_ASSERT(call);
4824 WINPR_ASSERT(completionId);
4825
4826 RdpdrServerPrivate* priv = context->priv;
4827 RDPDR_IRP* irp = nullptr;
4828
4829 UINT result =
4830 prepare_smartcard_irp(context, SCARD_IOCTL_DISCONNECT,
4831 rdpdr_server_smartcard_disconnect_callback, callbackData, &irp);
4832 if (result != CHANNEL_RC_OK)
4833 return result;
4834
4835 WINPR_ASSERT(irp);
4836 *completionId = irp->CompletionId;
4837
4838 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_DISCONNECT,
4839 .call.hCardAndDisposition = {
4840 .handles.hContext = call->handles.hContext,
4841 .handles.hCard = call->handles.hCard,
4842 .dwDisposition = call->dwDisposition,
4843 } };
4844
4845 wStream* s = Stream_New(nullptr, 128);
4846 if (!s)
4847 {
4848 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4849 result = CHANNEL_RC_NO_MEMORY;
4850 goto out;
4851 }
4852
4853 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4854 if (rc != SCARD_S_SUCCESS)
4855 {
4856 result = ERROR_INTERNAL_ERROR;
4857 goto out;
4858 }
4859
4860 result = rdpdr_server_send_device_control_request(
4861 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4862 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4863
4864out:
4865 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4866 if (result != CHANNEL_RC_OK)
4867 rdpdr_server_discard_request(context, irp->CompletionId);
4868 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4869 if (s)
4870 Stream_Release(s);
4871 return result;
4872}
4873
4874/* BeginTransaction */
4875static UINT rdpdr_server_smartcard_begin_transaction_callback(RdpdrServerContext* context,
4876 wStream* s, RDPDR_IRP* irp,
4877 UINT32 deviceId, UINT32 completionId,
4878 UINT32 ioStatus)
4879{
4880 WINPR_ASSERT(context);
4881 WINPR_ASSERT(context->priv);
4882 WINPR_ASSERT(s);
4883 WINPR_ASSERT(irp);
4884
4885 UINT result = CHANNEL_RC_OK;
4886 RdpdrServerPrivate* priv = context->priv;
4887 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4888
4889 WLog_Print(priv->log, WLOG_DEBUG,
4890 "SmartcardBeginTransactionCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4891 ", ioStatus=0x%" PRIx32,
4892 deviceId, completionId, ioStatus);
4893
4894 if (ioStatus != STATUS_SUCCESS)
4895 {
4896 if (context->OnSmartcardBeginTransactionComplete)
4897 context->OnSmartcardBeginTransactionComplete(context, irp->CallbackData, ioStatus,
4898 SCARD_F_INTERNAL_ERROR);
4899 goto out;
4900 }
4901
4902 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
4903 if (rc != SCARD_S_SUCCESS)
4904 {
4905 result = ERROR_INVALID_DATA;
4906 goto out;
4907 }
4908
4909 if (context->OnSmartcardBeginTransactionComplete)
4910 context->OnSmartcardBeginTransactionComplete(context, irp->CallbackData, ioStatus,
4911 op.returnCode);
4912
4913out:
4914 smartcard_operation_free(&op, FALSE);
4915 rdpdr_server_irp_free(irp);
4916 return result;
4917}
4918
4919static UINT rdpdr_server_smartcard_begin_transaction(RdpdrServerContext* context,
4920 void* callbackData,
4921 const HCardAndDisposition_Call* call,
4922 UINT32* completionId)
4923{
4924 WINPR_ASSERT(context);
4925 WINPR_ASSERT(context->priv);
4926 WINPR_ASSERT(call);
4927 WINPR_ASSERT(completionId);
4928
4929 RdpdrServerPrivate* priv = context->priv;
4930 RDPDR_IRP* irp = nullptr;
4931
4932 UINT result = prepare_smartcard_irp(context, SCARD_IOCTL_BEGINTRANSACTION,
4933 rdpdr_server_smartcard_begin_transaction_callback,
4934 callbackData, &irp);
4935 if (result != CHANNEL_RC_OK)
4936 return result;
4937
4938 WINPR_ASSERT(irp);
4939 *completionId = irp->CompletionId;
4940
4941 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_BEGINTRANSACTION,
4942 .call.hCardAndDisposition = {
4943 .handles.hContext = call->handles.hContext,
4944 .handles.hCard = call->handles.hCard,
4945 .dwDisposition = SCARD_LEAVE_CARD,
4946 } };
4947
4948 wStream* s = Stream_New(nullptr, 128);
4949 if (!s)
4950 {
4951 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
4952 result = CHANNEL_RC_NO_MEMORY;
4953 goto out;
4954 }
4955
4956 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
4957 if (rc != SCARD_S_SUCCESS)
4958 {
4959 result = ERROR_INTERNAL_ERROR;
4960 goto out;
4961 }
4962
4963 result = rdpdr_server_send_device_control_request(
4964 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
4965 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
4966
4967out:
4968 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4969 if (result != CHANNEL_RC_OK)
4970 rdpdr_server_discard_request(context, irp->CompletionId);
4971 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
4972 if (s)
4973 Stream_Release(s);
4974 return result;
4975}
4976
4977/* EndTransaction */
4978static UINT rdpdr_server_smartcard_end_transaction_callback(RdpdrServerContext* context, wStream* s,
4979 RDPDR_IRP* irp, UINT32 deviceId,
4980 UINT32 completionId, UINT32 ioStatus)
4981{
4982 WINPR_ASSERT(context);
4983 WINPR_ASSERT(context->priv);
4984 WINPR_ASSERT(s);
4985 WINPR_ASSERT(irp);
4986
4987 UINT result = CHANNEL_RC_OK;
4988 RdpdrServerPrivate* priv = context->priv;
4989 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
4990
4991 WLog_Print(priv->log, WLOG_DEBUG,
4992 "SmartcardEndTransactionCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
4993 ", ioStatus=0x%" PRIx32,
4994 deviceId, completionId, ioStatus);
4995
4996 if (ioStatus != STATUS_SUCCESS)
4997 {
4998 if (context->OnSmartcardEndTransactionComplete)
4999 context->OnSmartcardEndTransactionComplete(context, irp->CallbackData, ioStatus,
5000 SCARD_F_INTERNAL_ERROR);
5001 goto out;
5002 }
5003
5004 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5005 if (rc != SCARD_S_SUCCESS)
5006 {
5007 result = ERROR_INVALID_DATA;
5008 goto out;
5009 }
5010
5011 if (context->OnSmartcardEndTransactionComplete)
5012 context->OnSmartcardEndTransactionComplete(context, irp->CallbackData, ioStatus,
5013 op.returnCode);
5014
5015out:
5016 smartcard_operation_free(&op, FALSE);
5017 rdpdr_server_irp_free(irp);
5018 return result;
5019}
5020
5021static UINT rdpdr_server_smartcard_end_transaction(RdpdrServerContext* context, void* callbackData,
5022 const HCardAndDisposition_Call* call,
5023 UINT32* completionId)
5024{
5025 WINPR_ASSERT(context);
5026 WINPR_ASSERT(context->priv);
5027 WINPR_ASSERT(call);
5028 WINPR_ASSERT(completionId);
5029
5030 RdpdrServerPrivate* priv = context->priv;
5031 RDPDR_IRP* irp = nullptr;
5032
5033 UINT result =
5034 prepare_smartcard_irp(context, SCARD_IOCTL_ENDTRANSACTION,
5035 rdpdr_server_smartcard_end_transaction_callback, callbackData, &irp);
5036 if (result != CHANNEL_RC_OK)
5037 return result;
5038
5039 WINPR_ASSERT(irp);
5040 *completionId = irp->CompletionId;
5041
5042 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_ENDTRANSACTION,
5043 .call.hCardAndDisposition = {
5044 .handles.hContext = call->handles.hContext,
5045 .handles.hCard = call->handles.hCard,
5046 .dwDisposition = call->dwDisposition,
5047 } };
5048
5049 wStream* s = Stream_New(nullptr, 128);
5050 if (!s)
5051 {
5052 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5053 result = CHANNEL_RC_NO_MEMORY;
5054 goto out;
5055 }
5056
5057 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
5058 if (rc != SCARD_S_SUCCESS)
5059 {
5060 result = ERROR_INTERNAL_ERROR;
5061 goto out;
5062 }
5063
5064 result = rdpdr_server_send_device_control_request(
5065 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5066 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5067
5068out:
5069 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5070 if (result != CHANNEL_RC_OK)
5071 rdpdr_server_discard_request(context, irp->CompletionId);
5072 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5073 if (s)
5074 Stream_Release(s);
5075 return result;
5076}
5077
5078/* Status */
5079static UINT rdpdr_server_smartcard_status_callback(RdpdrServerContext* context, wStream* s,
5080 RDPDR_IRP* irp, UINT32 deviceId,
5081 UINT32 completionId, UINT32 ioStatus)
5082{
5083 WINPR_ASSERT(context);
5084 WINPR_ASSERT(context->priv);
5085 WINPR_ASSERT(s);
5086 WINPR_ASSERT(irp);
5087
5088 UINT result = CHANNEL_RC_OK;
5089 RdpdrServerPrivate* priv = context->priv;
5090 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
5091
5092 WLog_Print(priv->log, WLOG_DEBUG,
5093 "SmartcardStatusCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
5094 ", ioStatus=0x%" PRIx32,
5095 deviceId, completionId, ioStatus);
5096
5097 if (ioStatus != STATUS_SUCCESS)
5098 {
5099 if (context->OnSmartcardStatusComplete)
5100 context->OnSmartcardStatusComplete(context, irp->CallbackData, ioStatus,
5101 SCARD_F_INTERNAL_ERROR, nullptr);
5102 goto out;
5103 }
5104
5105 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5106 if (rc != SCARD_S_SUCCESS)
5107 {
5108 result = ERROR_INVALID_DATA;
5109 goto out;
5110 }
5111
5112 if (context->OnSmartcardStatusComplete)
5113 context->OnSmartcardStatusComplete(context, irp->CallbackData, ioStatus, op.returnCode,
5114 &op.ret.status);
5115
5116out:
5117 smartcard_operation_free(&op, FALSE);
5118 rdpdr_server_irp_free(irp);
5119 return result;
5120}
5121
5122static UINT rdpdr_server_smartcard_status(RdpdrServerContext* context, void* callbackData,
5123 UINT32 ioControlCode, const Status_Call* call,
5124 UINT32* completionId)
5125{
5126 WINPR_ASSERT(context);
5127 WINPR_ASSERT(context->priv);
5128 WINPR_ASSERT(call);
5129 WINPR_ASSERT(completionId);
5130
5131 RdpdrServerPrivate* priv = context->priv;
5132 RDPDR_IRP* irp = nullptr;
5133
5134 UINT result = prepare_smartcard_irp(context, ioControlCode,
5135 rdpdr_server_smartcard_status_callback, callbackData, &irp);
5136 if (result != CHANNEL_RC_OK)
5137 return result;
5138
5139 WINPR_ASSERT(irp);
5140 *completionId = irp->CompletionId;
5141
5142 const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode,
5143 .call.status = {
5144 .handles.hContext = call->handles.hContext,
5145 .handles.hCard = call->handles.hCard,
5146 .fmszReaderNamesIsNULL = call->fmszReaderNamesIsNULL,
5147 .cchReaderLen = call->cchReaderLen,
5148 .cbAtrLen = call->cbAtrLen,
5149 } };
5150
5151 wStream* s = Stream_New(nullptr, 128);
5152 if (!s)
5153 {
5154 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5155 result = CHANNEL_RC_NO_MEMORY;
5156 goto out;
5157 }
5158
5159 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
5160 if (rc != SCARD_S_SUCCESS)
5161 {
5162 result = ERROR_INTERNAL_ERROR;
5163 goto out;
5164 }
5165
5166 result = rdpdr_server_send_device_control_request(
5167 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5168 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5169
5170out:
5171 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5172 if (result != CHANNEL_RC_OK)
5173 rdpdr_server_discard_request(context, irp->CompletionId);
5174 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5175 if (s)
5176 Stream_Release(s);
5177 return result;
5178}
5179
5180static UINT rdpdr_server_smartcard_statusA(RdpdrServerContext* context, void* callbackData,
5181 const Status_Call* call, UINT32* completionId)
5182{
5183 return rdpdr_server_smartcard_status(context, callbackData, SCARD_IOCTL_STATUSA, call,
5184 completionId);
5185}
5186
5187static UINT rdpdr_server_smartcard_statusW(RdpdrServerContext* context, void* callbackData,
5188 const Status_Call* call, UINT32* completionId)
5189{
5190 return rdpdr_server_smartcard_status(context, callbackData, SCARD_IOCTL_STATUSW, call,
5191 completionId);
5192}
5193
5194/* Transmit */
5195static UINT rdpdr_server_smartcard_transmit_callback(RdpdrServerContext* context, wStream* s,
5196 RDPDR_IRP* irp, UINT32 deviceId,
5197 UINT32 completionId, UINT32 ioStatus)
5198{
5199 WINPR_ASSERT(context);
5200 WINPR_ASSERT(context->priv);
5201 WINPR_ASSERT(s);
5202 WINPR_ASSERT(irp);
5203
5204 UINT result = CHANNEL_RC_OK;
5205 RdpdrServerPrivate* priv = context->priv;
5206 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
5207
5208 WLog_Print(priv->log, WLOG_DEBUG,
5209 "SmartcardTransmitCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
5210 ", ioStatus=0x%" PRIx32,
5211 deviceId, completionId, ioStatus);
5212
5213 if (ioStatus != STATUS_SUCCESS)
5214 {
5215 if (context->OnSmartcardTransmitComplete)
5216 context->OnSmartcardTransmitComplete(context, irp->CallbackData, ioStatus,
5217 SCARD_F_INTERNAL_ERROR, nullptr);
5218 goto out;
5219 }
5220
5221 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5222 if (rc != SCARD_S_SUCCESS)
5223 {
5224 result = ERROR_INVALID_DATA;
5225 goto out;
5226 }
5227
5228 if (context->OnSmartcardTransmitComplete)
5229 context->OnSmartcardTransmitComplete(context, irp->CallbackData, ioStatus, op.returnCode,
5230 &op.ret.transmit);
5231
5232out:
5233 smartcard_operation_free(&op, FALSE);
5234 rdpdr_server_irp_free(irp);
5235 return result;
5236}
5237
5238static UINT rdpdr_server_smartcard_transmit(RdpdrServerContext* context, void* callbackData,
5239 const Transmit_Call* call, UINT32* completionId)
5240{
5241 WINPR_ASSERT(context);
5242 WINPR_ASSERT(context->priv);
5243 WINPR_ASSERT(call);
5244 WINPR_ASSERT(completionId);
5245
5246 RdpdrServerPrivate* priv = context->priv;
5247 RDPDR_IRP* irp = nullptr;
5248
5249 UINT result =
5250 prepare_smartcard_irp(context, SCARD_IOCTL_TRANSMIT,
5251 rdpdr_server_smartcard_transmit_callback, callbackData, &irp);
5252 if (result != CHANNEL_RC_OK)
5253 return result;
5254
5255 WINPR_ASSERT(irp);
5256 *completionId = irp->CompletionId;
5257
5258 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_TRANSMIT,
5259 .call.transmit = *call };
5260
5261 wStream* s = Stream_New(nullptr, 512 + call->cbSendLength);
5262 if (!s)
5263 {
5264 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5265 result = CHANNEL_RC_NO_MEMORY;
5266 goto out;
5267 }
5268
5269 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
5270 if (rc != SCARD_S_SUCCESS)
5271 {
5272 result = ERROR_INTERNAL_ERROR;
5273 goto out;
5274 }
5275
5276 result = rdpdr_server_send_device_control_request(
5277 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5278 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5279
5280out:
5281 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5282 if (result != CHANNEL_RC_OK)
5283 rdpdr_server_discard_request(context, irp->CompletionId);
5284 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5285 if (s)
5286 Stream_Release(s);
5287 return result;
5288}
5289
5290/* Control */
5291static UINT rdpdr_server_smartcard_control_callback(RdpdrServerContext* context, wStream* s,
5292 RDPDR_IRP* irp, UINT32 deviceId,
5293 UINT32 completionId, UINT32 ioStatus)
5294{
5295 WINPR_ASSERT(context);
5296 WINPR_ASSERT(context->priv);
5297 WINPR_ASSERT(s);
5298 WINPR_ASSERT(irp);
5299
5300 UINT result = CHANNEL_RC_OK;
5301 RdpdrServerPrivate* priv = context->priv;
5302 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
5303
5304 WLog_Print(priv->log, WLOG_DEBUG,
5305 "SmartcardControlCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
5306 ", ioStatus=0x%" PRIx32,
5307 deviceId, completionId, ioStatus);
5308
5309 if (ioStatus != STATUS_SUCCESS)
5310 {
5311 if (context->OnSmartcardControlComplete)
5312 context->OnSmartcardControlComplete(context, irp->CallbackData, ioStatus,
5313 SCARD_F_INTERNAL_ERROR, nullptr);
5314 goto out;
5315 }
5316
5317 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5318 if (rc != SCARD_S_SUCCESS)
5319 {
5320 result = ERROR_INVALID_DATA;
5321 goto out;
5322 }
5323
5324 if (context->OnSmartcardControlComplete)
5325 context->OnSmartcardControlComplete(context, irp->CallbackData, ioStatus, op.returnCode,
5326 &op.ret.control);
5327
5328out:
5329 smartcard_operation_free(&op, FALSE);
5330 rdpdr_server_irp_free(irp);
5331 return result;
5332}
5333
5334static UINT rdpdr_server_smartcard_control(RdpdrServerContext* context, void* callbackData,
5335 const Control_Call* call, UINT32* completionId)
5336{
5337 WINPR_ASSERT(context);
5338 WINPR_ASSERT(context->priv);
5339 WINPR_ASSERT(call);
5340 WINPR_ASSERT(completionId);
5341
5342 RdpdrServerPrivate* priv = context->priv;
5343 RDPDR_IRP* irp = nullptr;
5344
5345 UINT result = prepare_smartcard_irp(
5346 context, SCARD_IOCTL_CONTROL, rdpdr_server_smartcard_control_callback, callbackData, &irp);
5347 if (result != CHANNEL_RC_OK)
5348 return result;
5349
5350 WINPR_ASSERT(irp);
5351 *completionId = irp->CompletionId;
5352
5353 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_CONTROL,
5354 .call.control = {
5355 .handles.hContext = call->handles.hContext,
5356 .handles.hCard = call->handles.hCard,
5357 .dwControlCode = call->dwControlCode,
5358 .cbInBufferSize = call->cbInBufferSize,
5359 .pvInBuffer = call->pvInBuffer,
5360 .fpvOutBufferIsNULL = call->fpvOutBufferIsNULL,
5361 .cbOutBufferSize = call->cbOutBufferSize,
5362 } };
5363
5364 wStream* s = Stream_New(nullptr, 512 + call->cbOutBufferSize);
5365 if (!s)
5366 {
5367 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5368 result = CHANNEL_RC_NO_MEMORY;
5369 goto out;
5370 }
5371
5372 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
5373 if (rc != SCARD_S_SUCCESS)
5374 {
5375 result = ERROR_INTERNAL_ERROR;
5376 goto out;
5377 }
5378
5379 result = rdpdr_server_send_device_control_request(
5380 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5381 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5382
5383out:
5384 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5385 if (result != CHANNEL_RC_OK)
5386 rdpdr_server_discard_request(context, irp->CompletionId);
5387 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5388 if (s)
5389 Stream_Release(s);
5390 return result;
5391}
5392
5393/* getAttrib */
5394static UINT rdpdr_server_smartcard_get_attrib_callback(RdpdrServerContext* context, wStream* s,
5395 RDPDR_IRP* irp, UINT32 deviceId,
5396 UINT32 completionId, UINT32 ioStatus)
5397{
5398 WINPR_ASSERT(context);
5399 WINPR_ASSERT(context->priv);
5400 WINPR_ASSERT(s);
5401 WINPR_ASSERT(irp);
5402
5403 UINT result = CHANNEL_RC_OK;
5404 RdpdrServerPrivate* priv = context->priv;
5405 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
5406
5407 WLog_Print(priv->log, WLOG_DEBUG,
5408 "SmartcardGetAttribCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
5409 ", ioStatus=0x%" PRIx32,
5410 deviceId, completionId, ioStatus);
5411
5412 if (ioStatus != STATUS_SUCCESS)
5413 {
5414 if (context->OnSmartcardGetAttribComplete)
5415 context->OnSmartcardGetAttribComplete(context, irp->CallbackData, ioStatus,
5416 SCARD_F_INTERNAL_ERROR, nullptr);
5417 goto out;
5418 }
5419
5420 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5421 if (rc != SCARD_S_SUCCESS)
5422 {
5423 result = ERROR_INVALID_DATA;
5424 goto out;
5425 }
5426
5427 if (context->OnSmartcardGetAttribComplete)
5428 context->OnSmartcardGetAttribComplete(context, irp->CallbackData, ioStatus, op.returnCode,
5429 &op.ret.getAttrib);
5430
5431out:
5432 smartcard_operation_free(&op, FALSE);
5433 rdpdr_server_irp_free(irp);
5434 return result;
5435}
5436
5437static UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* callbackData,
5438 const GetAttrib_Call* call, UINT32* completionId)
5439{
5440 WINPR_ASSERT(context);
5441 WINPR_ASSERT(context->priv);
5442 WINPR_ASSERT(call);
5443 WINPR_ASSERT(completionId);
5444
5445 RdpdrServerPrivate* priv = context->priv;
5446
5447 RDPDR_IRP* irp = nullptr;
5448 const UINT ret =
5449 prepare_smartcard_irp(context, SCARD_IOCTL_GETATTRIB,
5450 rdpdr_server_smartcard_get_attrib_callback, callbackData, &irp);
5451 if (ret != CHANNEL_RC_OK)
5452 return ret;
5453
5454 WINPR_ASSERT(irp);
5455 *completionId = irp->CompletionId;
5456
5457 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_GETATTRIB,
5458 .call.getAttrib = *call };
5459
5460 UINT error = CHANNEL_RC_NO_MEMORY;
5461 wStream* s = Stream_New(nullptr, 64);
5462 if (!s)
5463 {
5464 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5465 goto out;
5466 }
5467
5468 LONG status = smartcard_irp_device_control_encode_request(s, &op);
5469 if (status != SCARD_S_SUCCESS)
5470 {
5471 error = ERROR_INTERNAL_ERROR;
5472 goto out;
5473 }
5474
5475 error = rdpdr_server_send_device_control_request(
5476 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5477 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5478
5479out:
5480 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5481 if (error != CHANNEL_RC_OK && irp)
5482 rdpdr_server_discard_request(context, irp->CompletionId);
5483 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5484 if (s)
5485 Stream_Release(s);
5486 return error;
5487}
5488
5489/* SetAttrib */
5490static UINT rdpdr_server_smartcard_set_attrib_callback(RdpdrServerContext* context, wStream* s,
5491 RDPDR_IRP* irp, UINT32 deviceId,
5492 UINT32 completionId, UINT32 ioStatus)
5493{
5494 WINPR_ASSERT(context);
5495 WINPR_ASSERT(context->priv);
5496 WINPR_ASSERT(s);
5497 WINPR_ASSERT(irp);
5498
5499 UINT result = CHANNEL_RC_OK;
5500 RdpdrServerPrivate* priv = context->priv;
5501 SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT;
5502
5503 WLog_Print(priv->log, WLOG_DEBUG,
5504 "SmartcardSetAttribCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
5505 ", ioStatus=0x%" PRIx32,
5506 deviceId, completionId, ioStatus);
5507
5508 if (ioStatus != STATUS_SUCCESS)
5509 {
5510 if (context->OnSmartcardSetAttribComplete)
5511 context->OnSmartcardSetAttribComplete(context, irp->CallbackData, ioStatus,
5512 SCARD_F_INTERNAL_ERROR);
5513 goto out;
5514 }
5515
5516 const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op);
5517 if (rc != SCARD_S_SUCCESS)
5518 {
5519 result = ERROR_INVALID_DATA;
5520 goto out;
5521 }
5522
5523 if (context->OnSmartcardSetAttribComplete)
5524 context->OnSmartcardSetAttribComplete(context, irp->CallbackData, ioStatus, op.returnCode);
5525
5526out:
5527 smartcard_operation_free(&op, FALSE);
5528 rdpdr_server_irp_free(irp);
5529 return result;
5530}
5531
5532static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* callbackData,
5533 const SetAttrib_Call* call, UINT32* completionId)
5534{
5535 WINPR_ASSERT(context);
5536 WINPR_ASSERT(context->priv);
5537 WINPR_ASSERT(call);
5538 WINPR_ASSERT(completionId);
5539
5540 RdpdrServerPrivate* priv = context->priv;
5541 RDPDR_IRP* irp = nullptr;
5542
5543 UINT result =
5544 prepare_smartcard_irp(context, SCARD_IOCTL_SETATTRIB,
5545 rdpdr_server_smartcard_set_attrib_callback, callbackData, &irp);
5546 if (result != CHANNEL_RC_OK)
5547 return result;
5548
5549 WINPR_ASSERT(irp);
5550 *completionId = irp->CompletionId;
5551
5552 const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_SETATTRIB,
5553 .call.setAttrib = {
5554 .handles.hContext = call->handles.hContext,
5555 .handles.hCard = call->handles.hCard,
5556 .dwAttrId = call->dwAttrId,
5557 .cbAttrLen = call->cbAttrLen,
5558 .pbAttr = call->pbAttr,
5559 } };
5560
5561 wStream* s = Stream_New(nullptr, 64 + call->cbAttrLen);
5562 if (!s)
5563 {
5564 WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!");
5565 result = CHANNEL_RC_NO_MEMORY;
5566 goto out;
5567 }
5568
5569 const LONG rc = smartcard_irp_device_control_encode_request(s, &op);
5570 if (rc != SCARD_S_SUCCESS)
5571 {
5572 result = ERROR_INTERNAL_ERROR;
5573 goto out;
5574 }
5575
5576 result = rdpdr_server_send_device_control_request(
5577 context, irp->DeviceId, irp->CompletionId, irp->IoControlCode,
5578 SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s));
5579
5580out:
5581 // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5582 if (result != CHANNEL_RC_OK)
5583 rdpdr_server_discard_request(context, irp->CompletionId);
5584 // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there
5585 if (s)
5586 Stream_Release(s);
5587 return result;
5588}
5589
5590RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
5591{
5592 RdpdrServerContext* context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext));
5593
5594 if (!context)
5595 goto fail;
5596
5597 context->vcm = vcm;
5598 context->Start = rdpdr_server_start;
5599 context->Stop = rdpdr_server_stop;
5600 context->DriveCreateDirectory = rdpdr_server_drive_create_directory;
5601 context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory;
5602 context->DriveQueryDirectory = rdpdr_server_drive_query_directory;
5603 context->DriveOpenFile = rdpdr_server_drive_open_file;
5604 context->DriveReadFile = rdpdr_server_drive_read_file;
5605 context->DriveWriteFile = rdpdr_server_drive_write_file;
5606 context->DriveCloseFile = rdpdr_server_drive_close_file;
5607 context->DriveDeleteFile = rdpdr_server_drive_delete_file;
5608 context->DriveRenameFile = rdpdr_server_drive_rename_file;
5609 context->SmartcardEstablishContext = rdpdr_server_smartcard_establish_context;
5610 context->SmartcardReleaseContext = rdpdr_server_smartcard_release_context;
5611 context->SmartcardIsValidContext = rdpdr_server_smartcard_is_valid_context;
5612 context->SmartcardListReaderGroupsA = rdpdr_server_smartcard_list_reader_groupsA;
5613 context->SmartcardListReaderGroupsW = rdpdr_server_smartcard_list_reader_groupsW;
5614 context->SmartcardListReadersA = rdpdr_server_smartcard_list_readersA;
5615 context->SmartcardListReadersW = rdpdr_server_smartcard_list_readersW;
5616 context->SmartcardGetStatusChangeA = rdpdr_server_smartcard_get_status_changeA;
5617 context->SmartcardGetStatusChangeW = rdpdr_server_smartcard_get_status_changeW;
5618 context->SmartcardCancel = rdpdr_server_smartcard_cancel;
5619 context->SmartcardConnectA = rdpdr_server_smartcard_connectA;
5620 context->SmartcardConnectW = rdpdr_server_smartcard_connectW;
5621 context->SmartcardReconnect = rdpdr_server_smartcard_reconnect;
5622 context->SmartcardDisconnect = rdpdr_server_smartcard_disconnect;
5623 context->SmartcardBeginTransaction = rdpdr_server_smartcard_begin_transaction;
5624 context->SmartcardEndTransaction = rdpdr_server_smartcard_end_transaction;
5625 context->SmartcardStatusA = rdpdr_server_smartcard_statusA;
5626 context->SmartcardStatusW = rdpdr_server_smartcard_statusW;
5627 context->SmartcardTransmit = rdpdr_server_smartcard_transmit;
5628 context->SmartcardControl = rdpdr_server_smartcard_control;
5629 context->SmartcardGetAttrib = rdpdr_server_smartcard_get_attrib;
5630 context->SmartcardSetAttrib = rdpdr_server_smartcard_set_attrib;
5631 context->priv = rdpdr_server_private_new();
5632 if (!context->priv)
5633 goto fail;
5634
5635 /* By default announce everything, the server application can deactivate that later on */
5636 context->supported = UINT16_MAX;
5637
5638 return context;
5639fail:
5640 WINPR_PRAGMA_DIAG_PUSH
5641 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
5642 rdpdr_server_context_free(context);
5643 WINPR_PRAGMA_DIAG_POP
5644 return nullptr;
5645}
5646
5647void rdpdr_server_context_free(RdpdrServerContext* context)
5648{
5649 if (!context)
5650 return;
5651
5652 rdpdr_server_private_free(context->priv);
5653 free(context);
5654}
5655
5656void rdpdr_server_discard_request(RdpdrServerContext* context, UINT32 completionId)
5657{
5658 WINPR_ASSERT(context);
5659
5660 RdpdrServerPrivate* priv = context->priv;
5661 const uintptr_t key = completionId + 1ull;
5662 ListDictionary_Remove(priv->IrpList, (void*)key);
5663}
UINT16 PacketId
UINT16 Component
union SMARTCARD_OPERATION::@33 ret
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:61
WINPR_ATTR_NODISCARD OBJECT_NEW_FN fnObjectNew
Definition collections.h:54