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 "rdpdr_main.h"
36
37#define RDPDR_ADD_PRINTER_EVENT 0x00000001
38#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002
39#define RDPDR_DELETE_PRINTER_EVENT 0x00000003
40#define RDPDR_RENAME_PRINTER_EVENT 0x00000004
41
42#define RDPDR_HEADER_LENGTH 4
43#define RDPDR_CAPABILITY_HEADER_LENGTH 8
44
45struct s_rdpdr_server_private
46{
47 HANDLE Thread;
48 HANDLE StopEvent;
49 void* ChannelHandle;
50
51 UINT32 ClientId;
52 UINT16 VersionMajor;
53 UINT16 VersionMinor;
54 char* ClientComputerName;
55
56 BOOL UserLoggedOnPdu;
57
58 wListDictionary* IrpList;
59 UINT32 NextCompletionId;
60
61 wHashTable* devicelist;
62 wLog* log;
63 UINT32 SpecialDeviceTypeCap;
64 UINT32 IoCode1;
65 UINT32 ExtendedPDU;
66};
67
68static const char* fileInformation2str(uint8_t val)
69{
70 switch (val)
71 {
72 case FILE_SUPERSEDED:
73 return "FILE_DOES_NOT_EXIST";
74 case FILE_OPENED:
75 return "FILE_EXISTS";
76 case FILE_CREATED:
77 return "FILE_OVERWRITTEN";
78 case FILE_OVERWRITTEN:
79 return "FILE_CREATED";
80 case FILE_EXISTS:
81 return "FILE_OPENED";
82 case FILE_DOES_NOT_EXIST:
83 return "FILE_SUPERSEDED";
84 default:
85 return "FILE_UNKNOWN";
86 }
87}
88
89static const char* DR_DRIVE_LOCK_REQ2str(uint32_t op)
90{
91 switch (op)
92 {
93 case RDP_LOWIO_OP_SHAREDLOCK:
94 return "RDP_LOWIO_OP_UNLOCK_MULTIPLE";
95 case RDP_LOWIO_OP_EXCLUSIVELOCK:
96 return "RDP_LOWIO_OP_UNLOCK";
97 case RDP_LOWIO_OP_UNLOCK:
98 return "RDP_LOWIO_OP_EXCLUSIVELOCK";
99 case RDP_LOWIO_OP_UNLOCK_MULTIPLE:
100 return "RDP_LOWIO_OP_SHAREDLOCK";
101 default:
102 return "RDP_LOWIO_OP_UNKNOWN";
103 }
104}
105
106static void rdpdr_device_free(RdpdrDevice* device)
107{
108 if (!device)
109 return;
110 free(device->DeviceData);
111 free(device);
112}
113
114static void rdpdr_device_free_h(void* obj)
115{
116 RdpdrDevice* other = obj;
117 rdpdr_device_free(other);
118}
119
120static UINT32 rdpdr_deviceid_hash(const void* id)
121{
122 WINPR_ASSERT(id);
123 return *((const UINT32*)id);
124}
125
126static BOOL rdpdr_device_equal(const void* v1, const void* v2)
127{
128 const UINT32* p1 = (const UINT32*)v1;
129 const UINT32* p2 = (const UINT32*)v2;
130 if (!p1 && !p2)
131 return TRUE;
132 if (!p1 || !p2)
133 return FALSE;
134 return *p1 == *p2;
135}
136
137static RdpdrDevice* rdpdr_device_new(void)
138{
139 return calloc(1, sizeof(RdpdrDevice));
140}
141
142static void* rdpdr_device_clone(const void* val)
143{
144 const RdpdrDevice* other = val;
145
146 if (!other)
147 return nullptr;
148
149 RdpdrDevice* tmp = rdpdr_device_new();
150 if (!tmp)
151 goto fail;
152
153 *tmp = *other;
154 if (other->DeviceData)
155 {
156 tmp->DeviceData = malloc(other->DeviceDataLength);
157 if (!tmp->DeviceData)
158 goto fail;
159 memcpy(tmp->DeviceData, other->DeviceData, other->DeviceDataLength);
160 }
161 return tmp;
162
163fail:
164 rdpdr_device_free(tmp);
165 return nullptr;
166}
167
168static void* rdpdr_device_key_clone(const void* pvval)
169{
170 const UINT32* val = pvval;
171 if (!val)
172 return nullptr;
173
174 UINT32* ptr = calloc(1, sizeof(UINT32));
175 if (!ptr)
176 return nullptr;
177 *ptr = *val;
178 return ptr;
179}
180
181static void rdpdr_device_key_free(void* obj)
182{
183 free(obj);
184}
185
186static RdpdrDevice* rdpdr_get_device_by_id(RdpdrServerPrivate* priv, UINT32 DeviceId)
187{
188 WINPR_ASSERT(priv);
189 return HashTable_GetItemValue(priv->devicelist, &DeviceId);
190}
191
192static BOOL rdpdr_remove_device_by_id(RdpdrServerPrivate* priv, UINT32 DeviceId)
193{
194 const RdpdrDevice* device = rdpdr_get_device_by_id(priv, DeviceId);
195 WINPR_ASSERT(priv);
196
197 if (!device)
198 {
199 WLog_Print(priv->log, WLOG_WARN, "[del] Device Id: 0x%08" PRIX32 ": no such device",
200 DeviceId);
201 return FALSE;
202 }
203 WLog_Print(priv->log, WLOG_DEBUG,
204 "[del] Device Name: %s Id: 0x%08" PRIX32 " DataLength: %" PRIu32 "",
205 device->PreferredDosName, device->DeviceId, device->DeviceDataLength);
206 return HashTable_Remove(priv->devicelist, &DeviceId);
207}
208
209static BOOL rdpdr_add_device(RdpdrServerPrivate* priv, const RdpdrDevice* device)
210{
211 WINPR_ASSERT(priv);
212 WINPR_ASSERT(device);
213
214 WLog_Print(priv->log, WLOG_DEBUG,
215 "[add] Device Name: %s Id: 0x%08" PRIX32 " DataLength: %" PRIu32 "",
216 device->PreferredDosName, device->DeviceId, device->DeviceDataLength);
217
218 return HashTable_Insert(priv->devicelist, &device->DeviceId, device);
219}
220
221static UINT32 g_ClientId = 0;
222
223static const WCHAR* rdpdr_read_ustring(wLog* log, wStream* s, size_t bytelen)
224{
225 const size_t charlen = (bytelen + 1) / sizeof(WCHAR);
226 const WCHAR* str = Stream_ConstPointer(s);
227 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bytelen))
228 return nullptr;
229 if (_wcsnlen(str, charlen) == charlen)
230 {
231 WLog_Print(log, WLOG_WARN, "[rdpdr] unicode string not '\\0' terminated");
232 return nullptr;
233 }
234 Stream_Seek(s, bytelen);
235 return str;
236}
237
238static RDPDR_IRP* rdpdr_server_irp_new(void)
239{
240 RDPDR_IRP* irp = (RDPDR_IRP*)calloc(1, sizeof(RDPDR_IRP));
241 return irp;
242}
243
244static void rdpdr_server_irp_free(RDPDR_IRP* irp)
245{
246 free(irp);
247}
248
249static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp)
250{
251 WINPR_ASSERT(context);
252 WINPR_ASSERT(context->priv);
253 const uintptr_t key = irp->CompletionId + 1ull;
254 return ListDictionary_Add(context->priv->IrpList, (void*)key, irp);
255}
256
257static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 completionId)
258{
259 RDPDR_IRP* irp = nullptr;
260 WINPR_ASSERT(context);
261 WINPR_ASSERT(context->priv);
262
263 const uintptr_t key = completionId + 1ull;
264 irp = (RDPDR_IRP*)ListDictionary_Take(context->priv->IrpList, (void*)key);
265 return irp;
266}
267
268static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s)
269{
270 BOOL status = 0;
271 ULONG written = 0;
272
273 WINPR_ASSERT(context);
274 WINPR_ASSERT(context->priv);
275 WINPR_ASSERT(s);
276
277 Stream_SealLength(s);
278 const size_t length = Stream_Length(s);
279 WINPR_ASSERT(length <= UINT32_MAX);
280 Stream_ResetPosition(s);
281
282 if (length >= RDPDR_HEADER_LENGTH)
283 {
284 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
285 Stream_Read_UINT16(s, header.Component);
286 Stream_Read_UINT16(s, header.PacketId);
287
288 WLog_Print(context->priv->log, WLOG_DEBUG,
289 "sending message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]",
290 rdpdr_component_string(header.Component), header.Component,
291 rdpdr_packetid_string(header.PacketId), header.PacketId);
292 }
293 winpr_HexLogDump(context->priv->log, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s));
294 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
295 (ULONG)length, &written);
296 Stream_Free(s, TRUE);
297 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
298}
299
305static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context)
306{
307 UINT error = 0;
308 wStream* s = nullptr;
309 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
310
311 WINPR_ASSERT(context);
312 WINPR_ASSERT(context->priv);
313
314 header.Component = RDPDR_CTYP_CORE;
315 header.PacketId = PAKID_CORE_SERVER_ANNOUNCE;
316
317 error = IFCALLRESULT(CHANNEL_RC_OK, context->SendServerAnnounce, context);
318 if (error != CHANNEL_RC_OK)
319 return error;
320
321 s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8);
322
323 if (!s)
324 {
325 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
326 return CHANNEL_RC_NO_MEMORY;
327 }
328
329 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
330 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
331 Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */
332 Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
333 Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
334 return rdpdr_seal_send_free_request(context, s);
335}
336
342static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, wStream* s,
343 const RDPDR_HEADER* header)
344{
345 UINT32 ClientId = 0;
346 UINT16 VersionMajor = 0;
347 UINT16 VersionMinor = 0;
348 WINPR_ASSERT(context);
349 WINPR_ASSERT(context->priv);
350 WINPR_ASSERT(header);
351
352 WINPR_UNUSED(header);
353
354 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
355 return ERROR_INVALID_DATA;
356
357 Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */
358 Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */
359 Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */
360 WLog_Print(context->priv->log, WLOG_DEBUG,
361 "Client Announce Response: VersionMajor: 0x%08" PRIX16 " VersionMinor: 0x%04" PRIX16
362 " ClientId: 0x%08" PRIX32 "",
363 VersionMajor, VersionMinor, ClientId);
364 context->priv->ClientId = ClientId;
365
366 return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveAnnounceResponse, context, VersionMajor,
367 VersionMinor, ClientId);
368}
369
375static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context, wStream* s,
376 const RDPDR_HEADER* header)
377{
378 UINT32 UnicodeFlag = 0;
379 UINT32 CodePage = 0;
380 UINT32 ComputerNameLen = 0;
381
382 WINPR_ASSERT(context);
383 WINPR_ASSERT(context->priv);
384 WINPR_ASSERT(s);
385 WINPR_ASSERT(header);
386 WINPR_UNUSED(header);
387
388 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
389 return ERROR_INVALID_DATA;
390
391 Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
392 Stream_Read_UINT32(s, CodePage); /* CodePage (4 bytes), MUST be set to zero */
393 Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
394 /* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored.
395 */
396 UnicodeFlag = UnicodeFlag & 0x00000001;
397
398 if (CodePage != 0)
399 WLog_Print(context->priv->log, WLOG_WARN,
400 "[MS-RDPEFS] 2.2.2.4 Client Name Request (DR_CORE_CLIENT_NAME_REQ)::CodePage "
401 "must be 0, but is 0x%08" PRIx32,
402 CodePage);
403
409 if (UnicodeFlag)
410 {
411 if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2)
412 {
413 WLog_Print(context->priv->log, WLOG_ERROR,
414 "invalid unicode computer name length: %" PRIu32 "", ComputerNameLen);
415 return ERROR_INVALID_DATA;
416 }
417 }
418 else
419 {
420 if (ComputerNameLen > 256 || ComputerNameLen < 1)
421 {
422 WLog_Print(context->priv->log, WLOG_ERROR,
423 "invalid ascii computer name length: %" PRIu32 "", ComputerNameLen);
424 return ERROR_INVALID_DATA;
425 }
426 }
427
428 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, ComputerNameLen))
429 return ERROR_INVALID_DATA;
430
431 /* ComputerName must be null terminated, check if it really is */
432 const char* computerName = Stream_ConstPointer(s);
433 if (computerName[ComputerNameLen - 1] || (UnicodeFlag && computerName[ComputerNameLen - 2]))
434 {
435 WLog_Print(context->priv->log, WLOG_ERROR, "computer name must be null terminated");
436 return ERROR_INVALID_DATA;
437 }
438
439 if (context->priv->ClientComputerName)
440 {
441 free(context->priv->ClientComputerName);
442 context->priv->ClientComputerName = nullptr;
443 }
444
445 if (UnicodeFlag)
446 {
447 context->priv->ClientComputerName =
448 Stream_Read_UTF16_String_As_UTF8(s, ComputerNameLen / sizeof(WCHAR), nullptr);
449 if (!context->priv->ClientComputerName)
450 {
451 WLog_Print(context->priv->log, WLOG_ERROR, "failed to convert client computer name");
452 return ERROR_INVALID_DATA;
453 }
454 }
455 else
456 {
457 const char* name = Stream_ConstPointer(s);
458 context->priv->ClientComputerName = _strdup(name);
459 Stream_Seek(s, ComputerNameLen);
460
461 if (!context->priv->ClientComputerName)
462 {
463 WLog_Print(context->priv->log, WLOG_ERROR, "failed to duplicate client computer name");
464 return CHANNEL_RC_NO_MEMORY;
465 }
466 }
467
468 WLog_Print(context->priv->log, WLOG_DEBUG, "ClientComputerName: %s",
469 context->priv->ClientComputerName);
470 return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveClientNameRequest, context, ComputerNameLen,
471 context->priv->ClientComputerName);
472}
473
474static UINT rdpdr_server_write_capability_set_header_cb(RdpdrServerContext* context, wStream* s,
475 const RDPDR_CAPABILITY_HEADER* header)
476{
477 WINPR_ASSERT(context);
478 WINPR_ASSERT(context->priv);
479 UINT error = rdpdr_write_capset_header(context->priv->log, s, header);
480 if (error != CHANNEL_RC_OK)
481 return error;
482
483 return IFCALLRESULT(CHANNEL_RC_OK, context->SendCaps, context, header, 0, nullptr);
484}
485
491static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context, wStream* s,
492 const RDPDR_CAPABILITY_HEADER* header)
493{
494 WINPR_ASSERT(context);
495 WINPR_ASSERT(context->priv);
496 WINPR_ASSERT(header);
497
498 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
499 return ERROR_INVALID_DATA;
500
501 const UINT32 OsType = Stream_Get_UINT32(s); /* osType (4 bytes), ignored on receipt */
502 const UINT32 OsVersion =
503 Stream_Get_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */
504 const UINT32 VersionMajor = Stream_Get_UINT16(s); /* protocolMajorVersion (2 bytes) */
505 const UINT32 VersionMinor = Stream_Get_UINT16(s); /* protocolMinorVersion (2 bytes) */
506 const UINT32 IoCode1 = Stream_Get_UINT32(s); /* ioCode1 (4 bytes) */
507 const UINT32 IoCode2 =
508 Stream_Get_UINT32(s); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */
509 const UINT32 ExtendedPdu = Stream_Get_UINT32(s); /* extendedPdu (4 bytes) */
510 const UINT32 ExtraFlags1 = Stream_Get_UINT32(s); /* extraFlags1 (4 bytes) */
511 const UINT32 ExtraFlags2 = Stream_Get_UINT32(
512 s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
513
514 {
515 char buffer[1024] = WINPR_C_ARRAY_INIT;
516 WLog_Print(context->priv->log, WLOG_TRACE,
517 "OsType=%" PRIu32 ", OsVersion=%" PRIu32 ", VersionMajor=%" PRIu32
518 ", VersionMinor=%" PRIu32 ", IoCode1=%s, IoCode2=%" PRIu32
519 ", ExtendedPdu=%" PRIu32 ", ExtraFlags1=%" PRIu32 ", ExtraFlags2=%" PRIu32,
520 OsType, OsVersion, VersionMajor, VersionMinor,
521 rdpdr_irp_mask2str(IoCode1, buffer, sizeof(buffer)), IoCode2, ExtendedPdu,
522 ExtraFlags1, ExtraFlags2);
523 }
524
525 if (VersionMajor != RDPDR_MAJOR_RDP_VERSION)
526 {
527 WLog_Print(context->priv->log, WLOG_ERROR, "unsupported RDPDR version %" PRIu16 ".%" PRIu16,
528 VersionMajor, VersionMinor);
529 return ERROR_INVALID_DATA;
530 }
531
532 switch (VersionMinor)
533 {
534 case RDPDR_MINOR_RDP_VERSION_13:
535 case RDPDR_MINOR_RDP_VERSION_6_X:
536 case RDPDR_MINOR_RDP_VERSION_5_2:
537 case RDPDR_MINOR_RDP_VERSION_5_1:
538 case RDPDR_MINOR_RDP_VERSION_5_0:
539 break;
540 default:
541 WLog_Print(context->priv->log, WLOG_WARN,
542 "unsupported RDPDR minor version %" PRIu16 ".%" PRIu16, VersionMajor,
543 VersionMinor);
544 break;
545 }
546
547 UINT32 SpecialTypeDeviceCap = 0;
548 if (header->Version == GENERAL_CAPABILITY_VERSION_02)
549 {
550 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
551 return ERROR_INVALID_DATA;
552
553 SpecialTypeDeviceCap = Stream_Get_UINT32(s); /* SpecialTypeDeviceCap (4 bytes) */
554 }
555 context->priv->SpecialDeviceTypeCap = SpecialTypeDeviceCap;
556
557 const UINT32 mask =
558 RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
559 RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
560 RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
561 RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
562 RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL;
563
564 if ((IoCode1 & mask) == 0)
565 {
566 char buffer[1024] = WINPR_C_ARRAY_INIT;
567 WLog_Print(context->priv->log, WLOG_ERROR, "Missing IRP mask values %s",
568 rdpdr_irp_mask2str(IoCode1 & mask, buffer, sizeof(buffer)));
569 return ERROR_INVALID_DATA;
570 }
571 context->priv->IoCode1 = IoCode1;
572
573 if (IoCode2 != 0)
574 {
575 WLog_Print(context->priv->log, WLOG_WARN,
576 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ioCode2 is "
577 "reserved for future use, expected value 0 got %" PRIu32,
578 IoCode2);
579 }
580
581 if ((ExtendedPdu & RDPDR_CLIENT_DISPLAY_NAME_PDU) == 0)
582 {
583 WLog_Print(context->priv->log, WLOG_WARN,
584 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) extendedPDU "
585 "should always set RDPDR_CLIENT_DISPLAY_NAME_PDU[0x00000002]");
586 }
587
588 context->priv->ExtendedPDU = ExtendedPdu;
589 context->priv->UserLoggedOnPdu = (ExtendedPdu & RDPDR_USER_LOGGEDON_PDU) != 0;
590
591 if (ExtraFlags2 != 0)
592 {
593 WLog_Print(context->priv->log, WLOG_WARN,
594 "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ExtraFlags2 is "
595 "reserved for future use, expected value 0 got %" PRIu32,
596 ExtraFlags2);
597 }
598
599 return CHANNEL_RC_OK;
600}
601
607static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* context, wStream* s)
608{
609 UINT32 ioCode1 = 0;
610 UINT32 extendedPdu = 0;
611 UINT32 extraFlags1 = 0;
612 UINT32 SpecialTypeDeviceCap = 0;
613 const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
614 GENERAL_CAPABILITY_VERSION_02 };
615
616 WINPR_ASSERT(context);
617 WINPR_ASSERT(context->priv);
618
619 ioCode1 = 0;
620 ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */
621 ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */
622 ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */
623 ioCode1 |= RDPDR_IRP_MJ_READ; /* always set */
624 ioCode1 |= RDPDR_IRP_MJ_WRITE; /* always set */
625 ioCode1 |= RDPDR_IRP_MJ_FLUSH_BUFFERS; /* always set */
626 ioCode1 |= RDPDR_IRP_MJ_SHUTDOWN; /* always set */
627 ioCode1 |= RDPDR_IRP_MJ_DEVICE_CONTROL; /* always set */
628 ioCode1 |= RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION; /* always set */
629 ioCode1 |= RDPDR_IRP_MJ_SET_VOLUME_INFORMATION; /* always set */
630 ioCode1 |= RDPDR_IRP_MJ_QUERY_INFORMATION; /* always set */
631 ioCode1 |= RDPDR_IRP_MJ_SET_INFORMATION; /* always set */
632 ioCode1 |= RDPDR_IRP_MJ_DIRECTORY_CONTROL; /* always set */
633 ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */
634 ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */
635 ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */
636 extendedPdu = 0;
637 extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */
638 extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */
639
640 if (context->priv->UserLoggedOnPdu)
641 extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */
642
643 extraFlags1 = 0;
644 extraFlags1 |= ENABLE_ASYNCIO; /* optional */
645 SpecialTypeDeviceCap = 0;
646
647 UINT error = rdpdr_write_capset_header(context->priv->log, s, &header);
648 if (error != CHANNEL_RC_OK)
649 return error;
650
651 const BYTE* data = Stream_ConstPointer(s);
652 const size_t start = Stream_GetPosition(s);
653 Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */
654 Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */
655 Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */
656 Stream_Write_UINT16(s, context->priv->VersionMinor); /* protocolMinorVersion (2 bytes) */
657 Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */
658 Stream_Write_UINT32(s, 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */
659 Stream_Write_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */
660 Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
661 Stream_Write_UINT32(
662 s, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
663 Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
664 const size_t end = Stream_GetPosition(s);
665 return IFCALLRESULT(CHANNEL_RC_OK, context->SendCaps, context, &header, end - start, data);
666}
667
673static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, wStream* s,
674 const RDPDR_CAPABILITY_HEADER* header)
675{
676 WINPR_ASSERT(context);
677 WINPR_ASSERT(context->priv);
678 WINPR_ASSERT(s);
679 WINPR_ASSERT(header);
680 WINPR_UNUSED(context);
681 WINPR_UNUSED(header);
682 WINPR_UNUSED(s);
683
684 return CHANNEL_RC_OK;
685}
686
692static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s)
693{
694 const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
695 PRINT_CAPABILITY_VERSION_01 };
696 WINPR_UNUSED(context);
697 WINPR_ASSERT(context);
698 WINPR_ASSERT(context->priv);
699
700 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
701}
702
708static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wStream* s,
709 const RDPDR_CAPABILITY_HEADER* header)
710{
711 WINPR_UNUSED(context);
712 WINPR_UNUSED(s);
713 WINPR_UNUSED(header);
714 WINPR_ASSERT(context);
715 WINPR_ASSERT(context->priv);
716
717 return CHANNEL_RC_OK;
718}
719
725static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s)
726{
727 const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
728 PORT_CAPABILITY_VERSION_01 };
729 WINPR_UNUSED(context);
730 WINPR_ASSERT(context);
731 WINPR_ASSERT(context->priv);
732
733 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
734}
735
741static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, wStream* s,
742 const RDPDR_CAPABILITY_HEADER* header)
743{
744 WINPR_ASSERT(context);
745 WINPR_ASSERT(context->priv);
746 WINPR_UNUSED(context);
747 WINPR_UNUSED(header);
748 WINPR_UNUSED(s);
749
750 return CHANNEL_RC_OK;
751}
752
758static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s)
759{
760 const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
761 DRIVE_CAPABILITY_VERSION_02 };
762
763 WINPR_ASSERT(context);
764 WINPR_ASSERT(context->priv);
765 WINPR_UNUSED(context);
766
767 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
768}
769
775static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* context, wStream* s,
776 const RDPDR_CAPABILITY_HEADER* header)
777{
778 WINPR_ASSERT(context);
779 WINPR_ASSERT(context->priv);
780 WINPR_UNUSED(context);
781 WINPR_UNUSED(header);
782 WINPR_UNUSED(s);
783
784 return CHANNEL_RC_OK;
785}
786
792static UINT rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s)
793{
794 const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
795 SMARTCARD_CAPABILITY_VERSION_01 };
796 WINPR_ASSERT(context);
797 WINPR_ASSERT(context->priv);
798
799 WINPR_UNUSED(context);
800
801 return rdpdr_server_write_capability_set_header_cb(context, s, &header);
802}
803
809static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* context)
810{
811 wStream* s = nullptr;
812 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
813 UINT16 numCapabilities = 0;
814 UINT error = 0;
815 WINPR_ASSERT(context);
816 WINPR_ASSERT(context->priv);
817
818 header.Component = RDPDR_CTYP_CORE;
819 header.PacketId = PAKID_CORE_SERVER_CAPABILITY;
820 numCapabilities = 1;
821
822 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
823 numCapabilities++;
824
825 if (((context->supported & RDPDR_DTYP_PARALLEL) != 0) ||
826 ((context->supported & RDPDR_DTYP_SERIAL) != 0))
827 numCapabilities++;
828
829 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
830 numCapabilities++;
831
832 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
833 numCapabilities++;
834
835 s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 512);
836
837 if (!s)
838 {
839 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
840 return CHANNEL_RC_NO_MEMORY;
841 }
842
843 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
844 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
845 Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
846 Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
847
848 if ((error = rdpdr_server_write_general_capability_set(context, s)))
849 {
850 WLog_Print(context->priv->log, WLOG_ERROR,
851 "rdpdr_server_write_general_capability_set failed with error %" PRIu32 "!",
852 error);
853 goto out;
854 }
855
856 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
857 {
858 if ((error = rdpdr_server_write_drive_capability_set(context, s)))
859 {
860 WLog_Print(context->priv->log, WLOG_ERROR,
861 "rdpdr_server_write_drive_capability_set failed with error %" PRIu32 "!",
862 error);
863 goto out;
864 }
865 }
866
867 if (((context->supported & RDPDR_DTYP_PARALLEL) != 0) ||
868 ((context->supported & RDPDR_DTYP_SERIAL) != 0))
869 {
870 if ((error = rdpdr_server_write_port_capability_set(context, s)))
871 {
872 WLog_Print(context->priv->log, WLOG_ERROR,
873 "rdpdr_server_write_port_capability_set failed with error %" PRIu32 "!",
874 error);
875 goto out;
876 }
877 }
878
879 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
880 {
881 if ((error = rdpdr_server_write_printer_capability_set(context, s)))
882 {
883 WLog_Print(context->priv->log, WLOG_ERROR,
884 "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!",
885 error);
886 goto out;
887 }
888 }
889
890 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
891 {
892 if ((error = rdpdr_server_write_smartcard_capability_set(context, s)))
893 {
894 WLog_Print(context->priv->log, WLOG_ERROR,
895 "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!",
896 error);
897 goto out;
898 }
899 }
900
901 return rdpdr_seal_send_free_request(context, s);
902out:
903 Stream_Free(s, TRUE);
904 return error;
905}
906
912static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* context, wStream* s,
913 const RDPDR_HEADER* header)
914{
915 UINT status = 0;
916 UINT16 numCapabilities = 0;
917
918 WINPR_ASSERT(context);
919 WINPR_ASSERT(context->priv);
920
921 WINPR_UNUSED(header);
922
923 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
924 return ERROR_INVALID_DATA;
925
926 Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
927 Stream_Seek_UINT16(s); /* Padding (2 bytes) */
928
929 UINT16 caps = 0;
930 for (UINT16 i = 0; i < numCapabilities; i++)
931 {
932 RDPDR_CAPABILITY_HEADER capabilityHeader = WINPR_C_ARRAY_INIT;
933 const size_t start = Stream_GetPosition(s);
934
935 if ((status = rdpdr_read_capset_header(context->priv->log, s, &capabilityHeader)))
936 {
937 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status);
938 return status;
939 }
940
941 status = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveCaps, context, &capabilityHeader,
942 Stream_GetRemainingLength(s), Stream_ConstPointer(s));
943 if (status != CHANNEL_RC_OK)
944 return status;
945
946 caps |= capabilityHeader.CapabilityType;
947 switch (capabilityHeader.CapabilityType)
948 {
949 case CAP_GENERAL_TYPE:
950 if ((status =
951 rdpdr_server_read_general_capability_set(context, s, &capabilityHeader)))
952 {
953 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!",
954 status);
955 return status;
956 }
957
958 break;
959
960 case CAP_PRINTER_TYPE:
961 if ((status =
962 rdpdr_server_read_printer_capability_set(context, s, &capabilityHeader)))
963 {
964 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!",
965 status);
966 return status;
967 }
968
969 break;
970
971 case CAP_PORT_TYPE:
972 if ((status = rdpdr_server_read_port_capability_set(context, s, &capabilityHeader)))
973 {
974 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!",
975 status);
976 return status;
977 }
978
979 break;
980
981 case CAP_DRIVE_TYPE:
982 if ((status =
983 rdpdr_server_read_drive_capability_set(context, s, &capabilityHeader)))
984 {
985 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!",
986 status);
987 return status;
988 }
989
990 break;
991
992 case CAP_SMARTCARD_TYPE:
993 if ((status =
994 rdpdr_server_read_smartcard_capability_set(context, s, &capabilityHeader)))
995 {
996 WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!",
997 status);
998 return status;
999 }
1000
1001 break;
1002
1003 default:
1004 WLog_Print(context->priv->log, WLOG_WARN, "Unknown capabilityType %" PRIu16 "",
1005 capabilityHeader.CapabilityType);
1006 Stream_Seek(s, capabilityHeader.CapabilityLength);
1007 return ERROR_INVALID_DATA;
1008 }
1009
1010 for (UINT16 x = 0; x < 16; x++)
1011 {
1012 const UINT16 mask = (UINT16)(1u << x);
1013 if (((caps & mask) != 0) && ((context->supported & mask) == 0))
1014 {
1015 WLog_Print(context->priv->log, WLOG_WARN,
1016 "client sent capability %s we did not announce!",
1018 }
1019
1020 /* we assume the server supports the capability. so only deactivate what the client did
1021 * not respond with */
1022 if ((caps & mask) == 0)
1023 context->supported &= ~mask;
1024 }
1025
1026 const size_t end = Stream_GetPosition(s);
1027 const size_t diff = end - start;
1028 if (diff != capabilityHeader.CapabilityLength + RDPDR_CAPABILITY_HEADER_LENGTH)
1029 {
1030 WLog_Print(context->priv->log, WLOG_WARN,
1031 "{capability %s[0x%04" PRIx16 "]} processed %" PRIuz
1032 " bytes, but expected to be %" PRIu16,
1033 rdpdr_cap_type_string(capabilityHeader.CapabilityType),
1034 capabilityHeader.CapabilityType, diff, capabilityHeader.CapabilityLength);
1035 }
1036 }
1037
1038 return CHANNEL_RC_OK;
1039}
1040
1046static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
1047{
1048 wStream* s = nullptr;
1049 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
1050
1051 WINPR_ASSERT(context);
1052 WINPR_ASSERT(context->priv);
1053
1054 header.Component = RDPDR_CTYP_CORE;
1055 header.PacketId = PAKID_CORE_CLIENTID_CONFIRM;
1056 s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8);
1057
1058 if (!s)
1059 {
1060 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1061 return CHANNEL_RC_NO_MEMORY;
1062 }
1063
1064 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
1065 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
1066 Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */
1067 Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
1068 Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
1069 return rdpdr_seal_send_free_request(context, s);
1070}
1071
1077static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* context,
1078 wStream* s,
1079 const RDPDR_HEADER* header)
1080{
1081 UINT32 DeviceCount = 0;
1082
1083 WINPR_ASSERT(context);
1084 WINPR_ASSERT(context->priv);
1085
1086 WINPR_UNUSED(header);
1087
1088 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1089 return ERROR_INVALID_DATA;
1090
1091 Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */
1092 WLog_Print(context->priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount);
1093
1094 for (UINT32 i = 0; i < DeviceCount; i++)
1095 {
1096 UINT error = 0;
1097 RdpdrDevice device = WINPR_C_ARRAY_INIT;
1098
1099 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20))
1100 return ERROR_INVALID_DATA;
1101
1102 Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */
1103 Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */
1104 Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */
1105 Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
1106 device.DeviceData = Stream_Pointer(s);
1107
1108 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, device.DeviceDataLength))
1109 return ERROR_INVALID_DATA;
1110
1111 if (!rdpdr_add_device(context->priv, &device))
1112 return ERROR_INTERNAL_ERROR;
1113
1114 error = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceAnnounce, context, &device);
1115 if (error != CHANNEL_RC_OK)
1116 return error;
1117
1118 switch (device.DeviceType)
1119 {
1120 case RDPDR_DTYP_FILESYSTEM:
1121 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
1122 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnDriveCreate, context, &device);
1123 break;
1124
1125 case RDPDR_DTYP_PRINT:
1126 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
1127 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnPrinterCreate, context, &device);
1128 break;
1129
1130 case RDPDR_DTYP_SERIAL:
1131 if (device.DeviceDataLength != 0)
1132 {
1133 WLog_Print(context->priv->log, WLOG_WARN,
1134 "[rdpdr] RDPDR_DTYP_SERIAL::DeviceDataLength != 0 [%" PRIu32 "]",
1135 device.DeviceDataLength);
1136 error = ERROR_INVALID_DATA;
1137 }
1138 else if ((context->supported & RDPDR_DTYP_SERIAL) != 0)
1139 error =
1140 IFCALLRESULT(CHANNEL_RC_OK, context->OnSerialPortCreate, context, &device);
1141 break;
1142
1143 case RDPDR_DTYP_PARALLEL:
1144 if (device.DeviceDataLength != 0)
1145 {
1146 WLog_Print(context->priv->log, WLOG_WARN,
1147 "[rdpdr] RDPDR_DTYP_PARALLEL::DeviceDataLength != 0 [%" PRIu32 "]",
1148 device.DeviceDataLength);
1149 error = ERROR_INVALID_DATA;
1150 }
1151 else if ((context->supported & RDPDR_DTYP_PARALLEL) != 0)
1152 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnParallelPortCreate, context,
1153 &device);
1154 break;
1155
1156 case RDPDR_DTYP_SMARTCARD:
1157 if (device.DeviceDataLength != 0)
1158 {
1159 WLog_Print(context->priv->log, WLOG_WARN,
1160 "[rdpdr] RDPDR_DTYP_SMARTCARD::DeviceDataLength != 0 [%" PRIu32 "]",
1161 device.DeviceDataLength);
1162 error = ERROR_INVALID_DATA;
1163 }
1164 else if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
1165 error =
1166 IFCALLRESULT(CHANNEL_RC_OK, context->OnSmartcardCreate, context, &device);
1167 break;
1168
1169 default:
1170 WLog_Print(context->priv->log, WLOG_WARN,
1171 "[MS-RDPEFS] 2.2.2.9 Client Device List Announce Request "
1172 "(DR_CORE_DEVICELIST_ANNOUNCE_REQ) unknown device type %04" PRIx16
1173 " at position %" PRIu32,
1174 device.DeviceType, i);
1175 error = ERROR_INVALID_DATA;
1176 break;
1177 }
1178
1179 if (error != CHANNEL_RC_OK)
1180 return error;
1181
1182 Stream_Seek(s, device.DeviceDataLength);
1183 }
1184
1185 return CHANNEL_RC_OK;
1186}
1187
1193static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* context, wStream* s,
1194 const RDPDR_HEADER* header)
1195{
1196 UINT32 DeviceCount = 0;
1197 UINT32 DeviceType = 0;
1198 UINT32 DeviceId = 0;
1199 WINPR_ASSERT(context);
1200 WINPR_ASSERT(context->priv);
1201
1202 WINPR_UNUSED(header);
1203
1204 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1205 return ERROR_INVALID_DATA;
1206
1207 Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */
1208 WLog_Print(context->priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount);
1209
1210 for (UINT32 i = 0; i < DeviceCount; i++)
1211 {
1212 UINT error = 0;
1213 const RdpdrDevice* device = nullptr;
1214
1215 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1216 return ERROR_INVALID_DATA;
1217
1218 Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
1219 device = rdpdr_get_device_by_id(context->priv, DeviceId);
1220 WLog_Print(context->priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i,
1221 DeviceId);
1222 DeviceType = 0;
1223 if (device)
1224 DeviceType = device->DeviceType;
1225
1226 error =
1227 IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceRemove, context, DeviceId, device);
1228 if (error != CHANNEL_RC_OK)
1229 return error;
1230
1231 switch (DeviceType)
1232 {
1233 case RDPDR_DTYP_FILESYSTEM:
1234 if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0)
1235 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnDriveDelete, context, DeviceId);
1236 break;
1237
1238 case RDPDR_DTYP_PRINT:
1239 if ((context->supported & RDPDR_DTYP_PRINT) != 0)
1240 error =
1241 IFCALLRESULT(CHANNEL_RC_OK, context->OnPrinterDelete, context, DeviceId);
1242 break;
1243
1244 case RDPDR_DTYP_SERIAL:
1245 if ((context->supported & RDPDR_DTYP_SERIAL) != 0)
1246 error =
1247 IFCALLRESULT(CHANNEL_RC_OK, context->OnSerialPortDelete, context, DeviceId);
1248 break;
1249
1250 case RDPDR_DTYP_PARALLEL:
1251 if ((context->supported & RDPDR_DTYP_PARALLEL) != 0)
1252 error = IFCALLRESULT(CHANNEL_RC_OK, context->OnParallelPortDelete, context,
1253 DeviceId);
1254 break;
1255
1256 case RDPDR_DTYP_SMARTCARD:
1257 if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0)
1258 error =
1259 IFCALLRESULT(CHANNEL_RC_OK, context->OnSmartcardDelete, context, DeviceId);
1260 break;
1261
1262 default:
1263 break;
1264 }
1265
1266 if (error != CHANNEL_RC_OK)
1267 return error;
1268
1269 if (!rdpdr_remove_device_by_id(context->priv, DeviceId))
1270 return ERROR_INVALID_DATA;
1271 }
1272
1273 return CHANNEL_RC_OK;
1274}
1275
1276static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, wStream* s,
1277 WINPR_ATTR_UNUSED UINT32 DeviceId,
1278 WINPR_ATTR_UNUSED UINT32 FileId,
1279 WINPR_ATTR_UNUSED UINT32 CompletionId)
1280{
1281 const WCHAR* path = nullptr;
1282 UINT32 DesiredAccess = 0;
1283 UINT32 AllocationSize = 0;
1284 UINT32 FileAttributes = 0;
1285 UINT32 SharedAccess = 0;
1286 UINT32 CreateDisposition = 0;
1287 UINT32 CreateOptions = 0;
1288 UINT32 PathLength = 0;
1289
1290 WINPR_ASSERT(context);
1291 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1292 return ERROR_INVALID_DATA;
1293
1294 Stream_Read_UINT32(s, DesiredAccess);
1295 Stream_Read_UINT32(s, AllocationSize);
1296 Stream_Read_UINT32(s, FileAttributes);
1297 Stream_Read_UINT32(s, SharedAccess);
1298 Stream_Read_UINT32(s, CreateDisposition);
1299 Stream_Read_UINT32(s, CreateOptions);
1300 Stream_Read_UINT32(s, PathLength);
1301
1302 path = rdpdr_read_ustring(context->priv->log, s, PathLength);
1303 if (!path && (PathLength > 0))
1304 return ERROR_INVALID_DATA;
1305
1306 WLog_Print(context->priv->log, WLOG_WARN,
1307 "[MS-RDPEFS] 2.2.1.4.1 Device Create Request (DR_CREATE_REQ) not implemented");
1308 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1309
1310 return CHANNEL_RC_OK;
1311}
1312
1313static UINT rdpdr_server_receive_io_close_request(RdpdrServerContext* context, wStream* s,
1314 WINPR_ATTR_UNUSED UINT32 DeviceId,
1315 WINPR_ATTR_UNUSED UINT32 FileId,
1316 WINPR_ATTR_UNUSED UINT32 CompletionId)
1317{
1318 WINPR_ASSERT(context);
1319 WINPR_ASSERT(context->priv);
1320
1321 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1322 return ERROR_INVALID_DATA;
1323
1324 Stream_Seek(s, 32); /* Padding */
1325
1326 WLog_Print(context->priv->log, WLOG_WARN,
1327 "[MS-RDPEFS] 2.2.1.4.2 Device Close Request (DR_CLOSE_REQ) not implemented");
1328 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1329
1330 return CHANNEL_RC_OK;
1331}
1332
1333static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wStream* s,
1334 WINPR_ATTR_UNUSED UINT32 DeviceId,
1335 WINPR_ATTR_UNUSED UINT32 FileId,
1336 WINPR_ATTR_UNUSED UINT32 CompletionId)
1337{
1338 UINT32 Length = 0;
1339 UINT64 Offset = 0;
1340
1341 WINPR_ASSERT(context);
1342 WINPR_ASSERT(context->priv);
1343 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1344 return ERROR_INVALID_DATA;
1345
1346 Stream_Read_UINT32(s, Length);
1347 Stream_Read_UINT64(s, Offset);
1348 Stream_Seek(s, 20); /* Padding */
1349
1350 WLog_Print(context->priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32,
1351 Offset, Length);
1352
1353 WLog_Print(context->priv->log, WLOG_WARN,
1354 "[MS-RDPEFS] 2.2.1.4.3 Device Read Request (DR_READ_REQ) not implemented");
1355 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1356
1357 return CHANNEL_RC_OK;
1358}
1359
1360static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, wStream* s,
1361 WINPR_ATTR_UNUSED UINT32 DeviceId,
1362 WINPR_ATTR_UNUSED UINT32 FileId,
1363 WINPR_ATTR_UNUSED UINT32 CompletionId)
1364{
1365 UINT32 Length = 0;
1366 UINT64 Offset = 0;
1367
1368 WINPR_ASSERT(context);
1369 WINPR_ASSERT(context->priv);
1370
1371 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1372 return ERROR_INVALID_DATA;
1373
1374 Stream_Read_UINT32(s, Length);
1375 Stream_Read_UINT64(s, Offset);
1376 Stream_Seek(s, 20); /* Padding */
1377
1378 WLog_Print(context->priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32,
1379 Offset, Length);
1380
1381 const BYTE* data = Stream_ConstPointer(s);
1382 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length))
1383 return ERROR_INVALID_DATA;
1384 Stream_Seek(s, Length);
1385
1386 WLog_Print(context->priv->log, WLOG_WARN,
1387 "[MS-RDPEFS] 2.2.1.4.4 Device Write Request (DR_WRITE_REQ) not implemented");
1388 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)data);
1389
1390 return CHANNEL_RC_OK;
1391}
1392
1393static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* context, wStream* s,
1394 WINPR_ATTR_UNUSED UINT32 DeviceId,
1395 WINPR_ATTR_UNUSED UINT32 FileId,
1396 WINPR_ATTR_UNUSED UINT32 CompletionId)
1397{
1398 UINT32 OutputBufferLength = 0;
1399 UINT32 InputBufferLength = 0;
1400 UINT32 IoControlCode = 0;
1401
1402 WINPR_ASSERT(context);
1403 WINPR_ASSERT(context->priv);
1404
1405 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1406 return ERROR_INVALID_DATA;
1407
1408 Stream_Read_UINT32(s, OutputBufferLength);
1409 Stream_Read_UINT32(s, InputBufferLength);
1410 Stream_Read_UINT32(s, IoControlCode);
1411 Stream_Seek(s, 20); /* Padding */
1412
1413 const BYTE* InputBuffer = Stream_ConstPointer(s);
1414 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, InputBufferLength))
1415 return ERROR_INVALID_DATA;
1416 Stream_Seek(s, InputBufferLength);
1417
1418 WLog_Print(context->priv->log, WLOG_WARN,
1419 "[MS-RDPEFS] 2.2.1.4.5 Device Control Request (DR_CONTROL_REQ) not implemented");
1420 WLog_Print(context->priv->log, WLOG_WARN,
1421 "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32,
1422 (const void*)InputBuffer, InputBufferLength, OutputBufferLength);
1423
1424 return CHANNEL_RC_OK;
1425}
1426
1427static UINT rdpdr_server_receive_io_query_volume_information_request(
1428 RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId,
1429 WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId)
1430{
1431 UINT32 FsInformationClass = 0;
1432 UINT32 Length = 0;
1433
1434 WINPR_ASSERT(context);
1435 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1436 return ERROR_INVALID_DATA;
1437
1438 Stream_Read_UINT32(s, FsInformationClass);
1439 Stream_Read_UINT32(s, Length);
1440 Stream_Seek(s, 24); /* Padding */
1441
1442 WLog_Print(context->priv->log, WLOG_DEBUG,
1443 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1444 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1445
1446 const BYTE* QueryVolumeBuffer = Stream_ConstPointer(s);
1447 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length))
1448 return ERROR_INVALID_DATA;
1449 Stream_Seek(s, Length);
1450
1451 WLog_Print(context->priv->log, WLOG_WARN,
1452 "[MS-RDPEFS] 2.2.3.3.6 Server Drive Query Volume Information Request "
1453 "(DR_DRIVE_QUERY_VOLUME_INFORMATION_REQ) not implemented");
1454 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryVolumeBuffer);
1455
1456 return CHANNEL_RC_OK;
1457}
1458
1459static UINT rdpdr_server_receive_io_set_volume_information_request(
1460 RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId,
1461 WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId)
1462{
1463 UINT32 FsInformationClass = 0;
1464 UINT32 Length = 0;
1465
1466 WINPR_ASSERT(context);
1467 WINPR_ASSERT(context->priv);
1468
1469 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1470 return ERROR_INVALID_DATA;
1471
1472 Stream_Read_UINT32(s, FsInformationClass);
1473 Stream_Read_UINT32(s, Length);
1474 Stream_Seek(s, 24); /* Padding */
1475
1476 WLog_Print(context->priv->log, WLOG_DEBUG,
1477 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1478 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1479
1480 const BYTE* SetVolumeBuffer = Stream_ConstPointer(s);
1481 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length))
1482 return ERROR_INVALID_DATA;
1483 Stream_Seek(s, Length);
1484
1485 WLog_Print(context->priv->log, WLOG_WARN,
1486 "[MS-RDPEFS] 2.2.3.3.7 Server Drive Set Volume Information Request "
1487 "(DR_DRIVE_SET_VOLUME_INFORMATION_REQ) not implemented");
1488 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetVolumeBuffer);
1489
1490 return CHANNEL_RC_OK;
1491}
1492
1493static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext* context,
1494 wStream* s,
1495 WINPR_ATTR_UNUSED UINT32 DeviceId,
1496 WINPR_ATTR_UNUSED UINT32 FileId,
1497 WINPR_ATTR_UNUSED UINT32 CompletionId)
1498{
1499 UINT32 FsInformationClass = 0;
1500 UINT32 Length = 0;
1501
1502 WINPR_ASSERT(context);
1503 WINPR_ASSERT(context->priv);
1504
1505 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1506 return ERROR_INVALID_DATA;
1507
1508 Stream_Read_UINT32(s, FsInformationClass);
1509 Stream_Read_UINT32(s, Length);
1510 Stream_Seek(s, 24); /* Padding */
1511
1512 WLog_Print(context->priv->log, WLOG_DEBUG,
1513 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1514 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1515
1516 const BYTE* QueryBuffer = Stream_ConstPointer(s);
1517 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length))
1518 return ERROR_INVALID_DATA;
1519 Stream_Seek(s, Length);
1520
1521 WLog_Print(context->priv->log, WLOG_WARN,
1522 "[MS-RDPEFS] 2.2.3.3.8 Server Drive Query Information Request "
1523 "(DR_DRIVE_QUERY_INFORMATION_REQ) not implemented");
1524 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryBuffer);
1525
1526 return CHANNEL_RC_OK;
1527}
1528
1529static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* context, wStream* s,
1530 WINPR_ATTR_UNUSED UINT32 DeviceId,
1531 WINPR_ATTR_UNUSED UINT32 FileId,
1532 WINPR_ATTR_UNUSED UINT32 CompletionId)
1533{
1534 UINT32 FsInformationClass = 0;
1535 UINT32 Length = 0;
1536
1537 WINPR_ASSERT(context);
1538 WINPR_ASSERT(context->priv);
1539
1540 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1541 return ERROR_INVALID_DATA;
1542
1543 Stream_Read_UINT32(s, FsInformationClass);
1544 Stream_Read_UINT32(s, Length);
1545 Stream_Seek(s, 24); /* Padding */
1546
1547 WLog_Print(context->priv->log, WLOG_DEBUG,
1548 "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32,
1549 FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length);
1550
1551 const BYTE* SetBuffer = Stream_ConstPointer(s);
1552 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length))
1553 return ERROR_INVALID_DATA;
1554 Stream_Seek(s, Length);
1555
1556 WLog_Print(context->priv->log, WLOG_WARN,
1557 "[MS-RDPEFS] 2.2.3.3.9 Server Drive Set Information Request "
1558 "(DR_DRIVE_SET_INFORMATION_REQ) not implemented");
1559 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetBuffer);
1560
1561 return CHANNEL_RC_OK;
1562}
1563
1564static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* context, wStream* s,
1565 WINPR_ATTR_UNUSED UINT32 DeviceId,
1566 WINPR_ATTR_UNUSED UINT32 FileId,
1567 WINPR_ATTR_UNUSED UINT32 CompletionId)
1568{
1569 BYTE InitialQuery = 0;
1570 UINT32 FsInformationClass = 0;
1571 UINT32 PathLength = 0;
1572
1573 WINPR_ASSERT(context);
1574 WINPR_ASSERT(context->priv);
1575
1576 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1577 return ERROR_INVALID_DATA;
1578
1579 Stream_Read_UINT32(s, FsInformationClass);
1580 Stream_Read_UINT8(s, InitialQuery);
1581 Stream_Read_UINT32(s, PathLength);
1582 Stream_Seek(s, 23); /* Padding */
1583
1584 const WCHAR* wPath = rdpdr_read_ustring(context->priv->log, s, PathLength);
1585 if (!wPath && (PathLength > 0))
1586 return ERROR_INVALID_DATA;
1587
1588 char* Path = ConvertWCharNToUtf8Alloc(wPath, PathLength / sizeof(WCHAR), nullptr);
1589 WLog_Print(context->priv->log, WLOG_DEBUG,
1590 "Got FSInformationClass %s [0x%08" PRIx32 "], InitialQuery [%" PRIu8
1591 "] Path[%" PRIu32 "] %s",
1592 FSInformationClass2Tag(FsInformationClass), FsInformationClass, InitialQuery,
1593 PathLength, Path);
1594 free(Path);
1595
1596 WLog_Print(context->priv->log, WLOG_WARN,
1597 "[MS-RDPEFS] 2.2.3.3.10 Server Drive Query Directory Request "
1598 "(DR_DRIVE_QUERY_DIRECTORY_REQ) not implemented");
1599 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1600
1601 return CHANNEL_RC_OK;
1602}
1603
1604static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* context,
1605 wStream* s,
1606 WINPR_ATTR_UNUSED UINT32 DeviceId,
1607 WINPR_ATTR_UNUSED UINT32 FileId,
1608 WINPR_ATTR_UNUSED UINT32 CompletionId)
1609{
1610 BYTE WatchTree = 0;
1611 UINT32 CompletionFilter = 0;
1612
1613 WINPR_ASSERT(context);
1614 WINPR_ASSERT(context->priv);
1615
1616 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1617 return ERROR_INVALID_DATA;
1618
1619 Stream_Read_UINT8(s, WatchTree);
1620 Stream_Read_UINT32(s, CompletionFilter);
1621 Stream_Seek(s, 27); /* Padding */
1622
1623 WLog_Print(context->priv->log, WLOG_WARN,
1624 "[MS-RDPEFS] 2.2.3.3.11 Server Drive NotifyChange Directory Request "
1625 "(DR_DRIVE_NOTIFY_CHANGE_DIRECTORY_REQ) not implemented");
1626 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1627
1628 return CHANNEL_RC_OK;
1629}
1630
1631static UINT rdpdr_server_receive_io_directory_control_request(RdpdrServerContext* context,
1632 wStream* s, UINT32 DeviceId,
1633 UINT32 FileId, UINT32 CompletionId,
1634 UINT32 MinorFunction)
1635{
1636 WINPR_ASSERT(context);
1637 WINPR_ASSERT(context->priv);
1638
1639 switch (MinorFunction)
1640 {
1641 case IRP_MN_QUERY_DIRECTORY:
1642 return rdpdr_server_receive_io_query_directory_request(context, s, DeviceId, FileId,
1643 CompletionId);
1644 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
1645 return rdpdr_server_receive_io_change_directory_request(context, s, DeviceId, FileId,
1646 CompletionId);
1647 default:
1648 WLog_Print(context->priv->log, WLOG_WARN,
1649 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) "
1650 "MajorFunction=%s, MinorFunction=%08" PRIx32 " is not supported",
1651 rdpdr_irp_string(IRP_MJ_DIRECTORY_CONTROL), MinorFunction);
1652 return ERROR_INVALID_DATA;
1653 }
1654}
1655
1656static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* context, wStream* s,
1657 WINPR_ATTR_UNUSED UINT32 DeviceId,
1658 WINPR_ATTR_UNUSED UINT32 FileId,
1659 WINPR_ATTR_UNUSED UINT32 CompletionId)
1660{
1661 WINPR_ASSERT(context);
1662 WINPR_ASSERT(context->priv);
1663
1664 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32))
1665 return ERROR_INVALID_DATA;
1666
1667 const uint32_t Operation = Stream_Get_UINT32(s);
1668 uint32_t Lock = Stream_Get_UINT32(s);
1669 const uint32_t NumLocks = Stream_Get_UINT32(s);
1670 Stream_Seek(s, 20); /* Padding */
1671
1672 WLog_Print(context->priv->log, WLOG_DEBUG,
1673 "IRP_MJ_LOCK_CONTROL, Operation=%s, Lock=0x%08" PRIx32 ", NumLocks=%" PRIu32,
1674 DR_DRIVE_LOCK_REQ2str(Operation), Lock, NumLocks);
1675
1676 Lock &= 0x01; /* Only bit 0 is of importance */
1677
1678 for (UINT32 x = 0; x < NumLocks; x++)
1679 {
1680 UINT64 Length = 0;
1681 UINT64 Offset = 0;
1682
1683 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 16))
1684 return ERROR_INVALID_DATA;
1685
1686 Stream_Read_UINT64(s, Length);
1687 Stream_Read_UINT64(s, Offset);
1688
1689 WLog_Print(context->priv->log, WLOG_DEBUG,
1690 "Locking at Offset=0x%08" PRIx64 " [Length %" PRIu64 "]", Offset, Length);
1691 }
1692
1693 WLog_Print(context->priv->log, WLOG_WARN,
1694 "[MS-RDPEFS] 2.2.3.3.12 Server Drive Lock Control Request (DR_DRIVE_LOCK_REQ) "
1695 "[Lock=0x%08" PRIx32 "]"
1696 "not implemented",
1697 Lock);
1698 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1699
1700 return CHANNEL_RC_OK;
1701}
1702
1703static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, wStream* s,
1704 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
1705{
1706 UINT32 DeviceId = 0;
1707 UINT32 FileId = 0;
1708 UINT32 CompletionId = 0;
1709 UINT32 MajorFunction = 0;
1710 UINT32 MinorFunction = 0;
1711
1712 WINPR_ASSERT(context);
1713 WINPR_ASSERT(context->priv);
1714 WINPR_ASSERT(header);
1715
1716 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20))
1717 return ERROR_INVALID_DATA;
1718
1719 Stream_Read_UINT32(s, DeviceId);
1720 Stream_Read_UINT32(s, FileId);
1721 Stream_Read_UINT32(s, CompletionId);
1722 Stream_Read_UINT32(s, MajorFunction);
1723 Stream_Read_UINT32(s, MinorFunction);
1724 if ((MinorFunction != 0) && (MajorFunction != IRP_MJ_DIRECTORY_CONTROL))
1725 WLog_Print(context->priv->log, WLOG_WARN,
1726 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) MajorFunction=%s, "
1727 "MinorFunction=0x%08" PRIx32 " != 0",
1728 rdpdr_irp_string(MajorFunction), MinorFunction);
1729
1730 switch (MajorFunction)
1731 {
1732 case IRP_MJ_CREATE:
1733 return rdpdr_server_receive_io_create_request(context, s, DeviceId, FileId,
1734 CompletionId);
1735 case IRP_MJ_CLOSE:
1736 return rdpdr_server_receive_io_close_request(context, s, DeviceId, FileId,
1737 CompletionId);
1738 case IRP_MJ_READ:
1739 return rdpdr_server_receive_io_read_request(context, s, DeviceId, FileId, CompletionId);
1740 case IRP_MJ_WRITE:
1741 return rdpdr_server_receive_io_write_request(context, s, DeviceId, FileId,
1742 CompletionId);
1743 case IRP_MJ_DEVICE_CONTROL:
1744 return rdpdr_server_receive_io_device_control_request(context, s, DeviceId, FileId,
1745 CompletionId);
1746 case IRP_MJ_QUERY_VOLUME_INFORMATION:
1747 return rdpdr_server_receive_io_query_volume_information_request(context, s, DeviceId,
1748 FileId, CompletionId);
1749 case IRP_MJ_QUERY_INFORMATION:
1750 return rdpdr_server_receive_io_query_information_request(context, s, DeviceId, FileId,
1751 CompletionId);
1752 case IRP_MJ_SET_INFORMATION:
1753 return rdpdr_server_receive_io_set_information_request(context, s, DeviceId, FileId,
1754 CompletionId);
1755 case IRP_MJ_DIRECTORY_CONTROL:
1756 return rdpdr_server_receive_io_directory_control_request(context, s, DeviceId, FileId,
1757 CompletionId, MinorFunction);
1758 case IRP_MJ_LOCK_CONTROL:
1759 return rdpdr_server_receive_io_lock_control_request(context, s, DeviceId, FileId,
1760 CompletionId);
1761 case IRP_MJ_SET_VOLUME_INFORMATION:
1762 return rdpdr_server_receive_io_set_volume_information_request(context, s, DeviceId,
1763 FileId, CompletionId);
1764
1765 default:
1766 WLog_Print(
1767 context->priv->log, WLOG_WARN,
1768 "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) not implemented");
1769 WLog_Print(context->priv->log, WLOG_WARN,
1770 "got DeviceId=0x%08" PRIx32 ", FileId=0x%08" PRIx32
1771 ", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
1772 ", MinorFunction=0x%08" PRIx32,
1773 DeviceId, FileId, CompletionId, MajorFunction, MinorFunction);
1774 return ERROR_INVALID_DATA;
1775 }
1776}
1777
1783static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* context, wStream* s,
1784 const RDPDR_HEADER* header)
1785{
1786 UINT32 deviceId = 0;
1787 UINT32 completionId = 0;
1788 UINT32 ioStatus = 0;
1789 RDPDR_IRP* irp = nullptr;
1790 UINT error = CHANNEL_RC_OK;
1791 WINPR_ASSERT(context);
1792 WINPR_ASSERT(context->priv);
1793 WINPR_ASSERT(s);
1794 WINPR_ASSERT(header);
1795
1796 WINPR_UNUSED(header);
1797
1798 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1799 return ERROR_INVALID_DATA;
1800
1801 Stream_Read_UINT32(s, deviceId);
1802 Stream_Read_UINT32(s, completionId);
1803 Stream_Read_UINT32(s, ioStatus);
1804 WLog_Print(context->priv->log, WLOG_DEBUG,
1805 "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", deviceId,
1806 completionId, ioStatus);
1807 irp = rdpdr_server_dequeue_irp(context, completionId);
1808
1809 if (!irp)
1810 {
1811 WLog_Print(context->priv->log, WLOG_ERROR, "IRP not found for completionId=0x%" PRIx32 "",
1812 completionId);
1813 return CHANNEL_RC_OK;
1814 }
1815
1816 /* Invoke the callback. */
1817 if (irp->Callback)
1818 {
1819 error = (*irp->Callback)(context, s, irp, deviceId, completionId, ioStatus);
1820 }
1821
1822 return error;
1823}
1824
1830static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
1831{
1832 wStream* s = nullptr;
1833 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
1834
1835 WINPR_ASSERT(context);
1836 WINPR_ASSERT(context->priv);
1837
1838 header.Component = RDPDR_CTYP_CORE;
1839 header.PacketId = PAKID_CORE_USER_LOGGEDON;
1840 s = Stream_New(nullptr, RDPDR_HEADER_LENGTH);
1841
1842 if (!s)
1843 {
1844 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1845 return CHANNEL_RC_NO_MEMORY;
1846 }
1847
1848 Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
1849 Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
1850 return rdpdr_seal_send_free_request(context, s);
1851}
1852
1853static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* context, wStream* s)
1854{
1855 char PortDosName[9] = WINPR_C_ARRAY_INIT;
1856 UINT32 PnPNameLen = 0;
1857 UINT32 DriverNameLen = 0;
1858 UINT32 PrinterNameLen = 0;
1859 UINT32 CachedFieldsLen = 0;
1860 const WCHAR* PnPName = nullptr;
1861 const WCHAR* DriverName = nullptr;
1862 const WCHAR* PrinterName = nullptr;
1863
1864 WINPR_ASSERT(context);
1865 WINPR_ASSERT(context->priv);
1866
1867 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 24))
1868 return ERROR_INVALID_DATA;
1869
1870 Stream_Read(s, PortDosName, 8);
1871 Stream_Read_UINT32(s, PnPNameLen);
1872 Stream_Read_UINT32(s, DriverNameLen);
1873 Stream_Read_UINT32(s, PrinterNameLen);
1874 Stream_Read_UINT32(s, CachedFieldsLen);
1875
1876 PnPName = rdpdr_read_ustring(context->priv->log, s, PnPNameLen);
1877 if (!PnPName && (PnPNameLen > 0))
1878 return ERROR_INVALID_DATA;
1879 DriverName = rdpdr_read_ustring(context->priv->log, s, DriverNameLen);
1880 if (!DriverName && (DriverNameLen > 0))
1881 return ERROR_INVALID_DATA;
1882 PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen);
1883 if (!PrinterName && (PrinterNameLen > 0))
1884 return ERROR_INVALID_DATA;
1885
1886 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, CachedFieldsLen))
1887 return ERROR_INVALID_DATA;
1888 Stream_Seek(s, CachedFieldsLen);
1889
1890 WLog_Print(context->priv->log, WLOG_WARN,
1891 "[MS-RDPEPC] 2.2.2.3 Add Printer Cachedata (DR_PRN_ADD_CACHEDATA) not implemented");
1892 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1893 return CHANNEL_RC_OK;
1894}
1895
1896static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* context, wStream* s)
1897{
1898 UINT32 PrinterNameLen = 0;
1899 UINT32 CachedFieldsLen = 0;
1900 const WCHAR* PrinterName = nullptr;
1901
1902 WINPR_ASSERT(context);
1903
1904 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1905 return ERROR_INVALID_DATA;
1906
1907 Stream_Read_UINT32(s, PrinterNameLen);
1908 Stream_Read_UINT32(s, CachedFieldsLen);
1909
1910 PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen);
1911 if (!PrinterName && (PrinterNameLen > 0))
1912 return ERROR_INVALID_DATA;
1913
1914 const BYTE* config = Stream_ConstPointer(s);
1915 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, CachedFieldsLen))
1916 return ERROR_INVALID_DATA;
1917 Stream_Seek(s, CachedFieldsLen);
1918
1919 WLog_Print(
1920 context->priv->log, WLOG_WARN,
1921 "[MS-RDPEPC] 2.2.2.4 Update Printer Cachedata (DR_PRN_UPDATE_CACHEDATA) not implemented");
1922 WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)config);
1923 return CHANNEL_RC_OK;
1924}
1925
1926static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* context, wStream* s)
1927{
1928 UINT32 PrinterNameLen = 0;
1929 const WCHAR* PrinterName = nullptr;
1930
1931 WINPR_ASSERT(context);
1932 WINPR_ASSERT(context->priv);
1933
1934 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1935 return ERROR_INVALID_DATA;
1936
1937 Stream_Read_UINT32(s, PrinterNameLen);
1938
1939 PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen);
1940 if (!PrinterName && (PrinterNameLen > 0))
1941 return ERROR_INVALID_DATA;
1942
1943 WLog_Print(
1944 context->priv->log, WLOG_WARN,
1945 "[MS-RDPEPC] 2.2.2.5 Delete Printer Cachedata (DR_PRN_DELETE_CACHEDATA) not implemented");
1946 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1947 return CHANNEL_RC_OK;
1948}
1949
1950static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* context, wStream* s)
1951{
1952 UINT32 OldPrinterNameLen = 0;
1953 UINT32 NewPrinterNameLen = 0;
1954 const WCHAR* OldPrinterName = nullptr;
1955 const WCHAR* NewPrinterName = nullptr;
1956
1957 WINPR_ASSERT(context);
1958 WINPR_ASSERT(context->priv);
1959
1960 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1961 return ERROR_INVALID_DATA;
1962
1963 Stream_Read_UINT32(s, OldPrinterNameLen);
1964 Stream_Read_UINT32(s, NewPrinterNameLen);
1965
1966 OldPrinterName = rdpdr_read_ustring(context->priv->log, s, OldPrinterNameLen);
1967 if (!OldPrinterName && (OldPrinterNameLen > 0))
1968 return ERROR_INVALID_DATA;
1969 NewPrinterName = rdpdr_read_ustring(context->priv->log, s, NewPrinterNameLen);
1970 if (!NewPrinterName && (NewPrinterNameLen > 0))
1971 return ERROR_INVALID_DATA;
1972
1973 WLog_Print(
1974 context->priv->log, WLOG_WARN,
1975 "[MS-RDPEPC] 2.2.2.6 Rename Printer Cachedata (DR_PRN_RENAME_CACHEDATA) not implemented");
1976 WLog_Print(context->priv->log, WLOG_WARN, "TODO");
1977 return CHANNEL_RC_OK;
1978}
1979
1980static UINT
1981rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream* s,
1982 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
1983{
1984 UINT32 EventId = 0;
1985
1986 WINPR_ASSERT(context);
1987 WINPR_ASSERT(context->priv);
1988 WINPR_ASSERT(header);
1989
1990 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1991 return ERROR_INVALID_DATA;
1992
1993 Stream_Read_UINT32(s, EventId);
1994 switch (EventId)
1995 {
1996 case RDPDR_ADD_PRINTER_EVENT:
1997 return rdpdr_server_receive_prn_cache_add_printer(context, s);
1998 case RDPDR_UPDATE_PRINTER_EVENT:
1999 return rdpdr_server_receive_prn_cache_update_printer(context, s);
2000 case RDPDR_DELETE_PRINTER_EVENT:
2001 return rdpdr_server_receive_prn_cache_delete_printer(context, s);
2002 case RDPDR_RENAME_PRINTER_EVENT:
2003 return rdpdr_server_receive_prn_cache_rename_cachedata(context, s);
2004 default:
2005 WLog_Print(context->priv->log, WLOG_WARN,
2006 "[MS-RDPEPC] PAKID_PRN_CACHE_DATA unknown EventId=0x%08" PRIx32, EventId);
2007 return ERROR_INVALID_DATA;
2008 }
2009}
2010
2011static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* context, wStream* s,
2012 WINPR_ATTR_UNUSED const RDPDR_HEADER* header)
2013{
2014 UINT32 PrinterId = 0;
2015 UINT32 Flags = 0;
2016
2017 WINPR_ASSERT(context);
2018 WINPR_ASSERT(context->priv);
2019 WINPR_ASSERT(header);
2020
2021 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
2022 return ERROR_INVALID_DATA;
2023
2024 Stream_Read_UINT32(s, PrinterId);
2025 Stream_Read_UINT32(s, Flags);
2026
2027 WLog_Print(
2028 context->priv->log, WLOG_WARN,
2029 "[MS-RDPEPC] 2.2.2.2 Server Printer Set XPS Mode (DR_PRN_USING_XPS) not implemented");
2030 WLog_Print(context->priv->log, WLOG_WARN, "PrinterId=0x%08" PRIx32 ", Flags=0x%08" PRIx32,
2031 PrinterId, Flags);
2032 return CHANNEL_RC_OK;
2033}
2034
2040static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s,
2041 const RDPDR_HEADER* header)
2042{
2043 UINT error = ERROR_INVALID_DATA;
2044 WINPR_ASSERT(context);
2045 WINPR_ASSERT(context->priv);
2046 WINPR_ASSERT(s);
2047 WINPR_ASSERT(header);
2048
2049 WLog_Print(context->priv->log, WLOG_DEBUG,
2050 "receiving message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]",
2051 rdpdr_component_string(header->Component), header->Component,
2052 rdpdr_packetid_string(header->PacketId), header->PacketId);
2053
2054 if (header->Component == RDPDR_CTYP_CORE)
2055 {
2056 switch (header->PacketId)
2057 {
2058 case PAKID_CORE_SERVER_ANNOUNCE:
2059 WLog_Print(context->priv->log, WLOG_ERROR,
2060 "[MS-RDPEFS] 2.2.2.2 Server Announce Request "
2061 "(DR_CORE_SERVER_ANNOUNCE_REQ) must not be sent by a client!");
2062 break;
2063
2064 case PAKID_CORE_CLIENTID_CONFIRM:
2065 error = rdpdr_server_receive_announce_response(context, s, header);
2066 break;
2067
2068 case PAKID_CORE_CLIENT_NAME:
2069 error = rdpdr_server_receive_client_name_request(context, s, header);
2070 if (error == CHANNEL_RC_OK)
2071 error = rdpdr_server_send_core_capability_request(context);
2072 if (error == CHANNEL_RC_OK)
2073 error = rdpdr_server_send_client_id_confirm(context);
2074 break;
2075
2076 case PAKID_CORE_USER_LOGGEDON:
2077 WLog_Print(context->priv->log, WLOG_ERROR,
2078 "[MS-RDPEFS] 2.2.2.5 Server User Logged On (DR_CORE_USER_LOGGEDON) "
2079 "must not be sent by a client!");
2080 break;
2081
2082 case PAKID_CORE_SERVER_CAPABILITY:
2083 WLog_Print(context->priv->log, WLOG_ERROR,
2084 "[MS-RDPEFS] 2.2.2.7 Server Core Capability Request "
2085 "(DR_CORE_CAPABILITY_REQ) must not be sent by a client!");
2086 break;
2087
2088 case PAKID_CORE_CLIENT_CAPABILITY:
2089 error = rdpdr_server_receive_core_capability_response(context, s, header);
2090 if (error == CHANNEL_RC_OK)
2091 {
2092 if (context->priv->UserLoggedOnPdu)
2093 error = rdpdr_server_send_user_logged_on(context);
2094 }
2095
2096 break;
2097
2098 case PAKID_CORE_DEVICELIST_ANNOUNCE:
2099 error = rdpdr_server_receive_device_list_announce_request(context, s, header);
2100 break;
2101
2102 case PAKID_CORE_DEVICELIST_REMOVE:
2103 error = rdpdr_server_receive_device_list_remove_request(context, s, header);
2104 break;
2105
2106 case PAKID_CORE_DEVICE_REPLY:
2107 WLog_Print(context->priv->log, WLOG_ERROR,
2108 "[MS-RDPEFS] 2.2.2.1 Server Device Announce Response "
2109 "(DR_CORE_DEVICE_ANNOUNCE_RSP) must not be sent by a client!");
2110 break;
2111
2112 case PAKID_CORE_DEVICE_IOREQUEST:
2113 error = rdpdr_server_receive_device_io_request(context, s, header);
2114 break;
2115
2116 case PAKID_CORE_DEVICE_IOCOMPLETION:
2117 error = rdpdr_server_receive_device_io_completion(context, s, header);
2118 break;
2119
2120 default:
2121 WLog_Print(context->priv->log, WLOG_WARN,
2122 "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
2123 rdpdr_component_string(header->Component), header->Component,
2124 rdpdr_packetid_string(header->PacketId));
2125 break;
2126 }
2127 }
2128 else if (header->Component == RDPDR_CTYP_PRN)
2129 {
2130 switch (header->PacketId)
2131 {
2132 case PAKID_PRN_CACHE_DATA:
2133 error = rdpdr_server_receive_prn_cache_data_request(context, s, header);
2134 break;
2135
2136 case PAKID_PRN_USING_XPS:
2137 error = rdpdr_server_receive_prn_using_xps_request(context, s, header);
2138 break;
2139
2140 default:
2141 WLog_Print(context->priv->log, WLOG_WARN,
2142 "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
2143 rdpdr_component_string(header->Component), header->Component,
2144 rdpdr_packetid_string(header->PacketId));
2145 break;
2146 }
2147 }
2148 else
2149 {
2150 WLog_Print(context->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 }
2155
2156 return IFCALLRESULT(error, context->ReceivePDU, context, header, error);
2157}
2158
2159static DWORD WINAPI rdpdr_server_thread(LPVOID arg)
2160{
2161 DWORD status = 0;
2162 DWORD nCount = 0;
2163 void* buffer = nullptr;
2164 HANDLE events[8] = WINPR_C_ARRAY_INIT;
2165 HANDLE ChannelEvent = nullptr;
2166 DWORD BytesReturned = 0;
2167 UINT error = 0;
2168 RdpdrServerContext* context = (RdpdrServerContext*)arg;
2169 wStream* s = Stream_New(nullptr, 4096);
2170
2171 WINPR_ASSERT(context);
2172 WINPR_ASSERT(context->priv);
2173
2174 if (!s)
2175 {
2176 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2177 error = CHANNEL_RC_NO_MEMORY;
2178 goto out;
2179 }
2180
2181 if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
2182 &BytesReturned) == TRUE)
2183 {
2184 if (BytesReturned == sizeof(HANDLE))
2185 ChannelEvent = *(HANDLE*)buffer;
2186
2187 WTSFreeMemory(buffer);
2188 }
2189
2190 nCount = 0;
2191 events[nCount++] = ChannelEvent;
2192 events[nCount++] = context->priv->StopEvent;
2193
2194 if ((error = rdpdr_server_send_announce_request(context)))
2195 {
2196 WLog_Print(context->priv->log, WLOG_ERROR,
2197 "rdpdr_server_send_announce_request failed with error %" PRIu32 "!", error);
2198 goto out_stream;
2199 }
2200
2201 while (1)
2202 {
2203 size_t capacity = 0;
2204 BytesReturned = 0;
2205 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
2206
2207 if (status == WAIT_FAILED)
2208 {
2209 error = GetLastError();
2210 WLog_Print(context->priv->log, WLOG_ERROR,
2211 "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
2212 goto out_stream;
2213 }
2214
2215 status = WaitForSingleObject(context->priv->StopEvent, 0);
2216
2217 if (status == WAIT_FAILED)
2218 {
2219 error = GetLastError();
2220 WLog_Print(context->priv->log, WLOG_ERROR,
2221 "WaitForSingleObject failed with error %" PRIu32 "!", error);
2222 goto out_stream;
2223 }
2224
2225 if (status == WAIT_OBJECT_0)
2226 break;
2227
2228 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, nullptr, 0, &BytesReturned))
2229 {
2230 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2231 error = ERROR_INTERNAL_ERROR;
2232 break;
2233 }
2234 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
2235 {
2236 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
2237 error = ERROR_INTERNAL_ERROR;
2238 break;
2239 }
2240
2241 capacity = MIN(Stream_Capacity(s), UINT32_MAX);
2242 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char),
2243 (ULONG)capacity, &BytesReturned))
2244 {
2245 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2246 error = ERROR_INTERNAL_ERROR;
2247 break;
2248 }
2249
2250 if (BytesReturned >= RDPDR_HEADER_LENGTH)
2251 {
2252 Stream_ResetPosition(s);
2253 if (!Stream_SetLength(s, BytesReturned))
2254 {
2255 error = ERROR_INTERNAL_ERROR;
2256 goto out_stream;
2257 }
2258
2259 while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH)
2260 {
2261 RDPDR_HEADER header = WINPR_C_ARRAY_INIT;
2262
2263 Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
2264 Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
2265
2266 if ((error = rdpdr_server_receive_pdu(context, s, &header)))
2267 {
2268 WLog_Print(context->priv->log, WLOG_ERROR,
2269 "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error);
2270 goto out_stream;
2271 }
2272 }
2273 }
2274 }
2275
2276out_stream:
2277 Stream_Free(s, TRUE);
2278out:
2279
2280 if (error && context->rdpcontext)
2281 setChannelError(context->rdpcontext, error, "rdpdr_server_thread reported an error");
2282
2283 ExitThread(error);
2284 return error;
2285}
2286
2292static UINT rdpdr_server_start(RdpdrServerContext* context)
2293{
2294 WINPR_ASSERT(context);
2295 WINPR_ASSERT(context->priv);
2296 context->priv->ChannelHandle =
2297 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPDR_SVC_CHANNEL_NAME);
2298
2299 if (!context->priv->ChannelHandle)
2300 {
2301 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpen failed!");
2302 return CHANNEL_RC_BAD_CHANNEL;
2303 }
2304
2305 if (!(context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
2306 {
2307 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
2308 return ERROR_INTERNAL_ERROR;
2309 }
2310
2311 if (!(context->priv->Thread =
2312 CreateThread(nullptr, 0, rdpdr_server_thread, (void*)context, 0, nullptr)))
2313 {
2314 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
2315 (void)CloseHandle(context->priv->StopEvent);
2316 context->priv->StopEvent = nullptr;
2317 return ERROR_INTERNAL_ERROR;
2318 }
2319
2320 return CHANNEL_RC_OK;
2321}
2322
2328static UINT rdpdr_server_stop(RdpdrServerContext* context)
2329{
2330 UINT error = 0;
2331 WINPR_ASSERT(context);
2332 WINPR_ASSERT(context->priv);
2333
2334 if (context->priv->StopEvent)
2335 {
2336 (void)SetEvent(context->priv->StopEvent);
2337
2338 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
2339 {
2340 error = GetLastError();
2341 WLog_Print(context->priv->log, WLOG_ERROR,
2342 "WaitForSingleObject failed with error %" PRIu32 "!", error);
2343 return error;
2344 }
2345
2346 (void)CloseHandle(context->priv->Thread);
2347 context->priv->Thread = nullptr;
2348 (void)CloseHandle(context->priv->StopEvent);
2349 context->priv->StopEvent = nullptr;
2350 }
2351
2352 if (context->priv->ChannelHandle)
2353 {
2354 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
2355 context->priv->ChannelHandle = nullptr;
2356 }
2357 return CHANNEL_RC_OK;
2358}
2359
2360static void rdpdr_server_write_device_iorequest(wStream* s, UINT32 deviceId, UINT32 fileId,
2361 UINT32 completionId, UINT32 majorFunction,
2362 UINT32 minorFunction)
2363{
2364 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
2365 Stream_Write_UINT16(s, PAKID_CORE_DEVICE_IOREQUEST); /* PacketId (2 bytes) */
2366 Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */
2367 Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */
2368 Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */
2369 Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */
2370 Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */
2371}
2372
2378static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s,
2380{
2381 UINT32 fileNameLength = 0;
2382 WINPR_ASSERT(fdi);
2383 ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION));
2384
2385 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 64))
2386 return ERROR_INVALID_DATA;
2387
2388 Stream_Read_UINT32(s, fdi->NextEntryOffset); /* NextEntryOffset (4 bytes) */
2389 Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */
2390 Stream_Read_INT64(s, fdi->CreationTime.QuadPart); /* CreationTime (8 bytes) */
2391 Stream_Read_INT64(s, fdi->LastAccessTime.QuadPart); /* LastAccessTime (8 bytes) */
2392 Stream_Read_INT64(s, fdi->LastWriteTime.QuadPart); /* LastWriteTime (8 bytes) */
2393 Stream_Read_INT64(s, fdi->ChangeTime.QuadPart); /* ChangeTime (8 bytes) */
2394 Stream_Read_INT64(s, fdi->EndOfFile.QuadPart); /* EndOfFile (8 bytes) */
2395 Stream_Read_INT64(s, fdi->AllocationSize.QuadPart); /* AllocationSize (8 bytes) */
2396 Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */
2397 Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */
2398
2399 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, fileNameLength))
2400 return ERROR_INVALID_DATA;
2401
2402 if (fileNameLength / sizeof(WCHAR) > ARRAYSIZE(fdi->FileName))
2403 return ERROR_INVALID_DATA;
2404
2405#if defined(__MINGW32__) || defined(WITH_WCHAR_FILE_DIRECTORY_INFORMATION)
2406 if (Stream_Read_UTF16_String(s, fdi->FileName, fileNameLength / sizeof(WCHAR)))
2407 return ERROR_INVALID_DATA;
2408#else
2409 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, fileNameLength / sizeof(WCHAR), fdi->FileName,
2410 ARRAYSIZE(fdi->FileName)) < 0)
2411 return ERROR_INVALID_DATA;
2412#endif
2413 return CHANNEL_RC_OK;
2414}
2415
2421static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, UINT32 deviceId,
2422 UINT32 completionId, const char* path,
2423 UINT32 desiredAccess, UINT32 createOptions,
2424 UINT32 createDisposition)
2425{
2426 size_t pathLength = 0;
2427 wStream* s = nullptr;
2428 WINPR_ASSERT(context);
2429 WINPR_ASSERT(context->priv);
2430
2431 WLog_Print(context->priv->log, WLOG_DEBUG,
2432 "RdpdrServerSendDeviceCreateRequest: deviceId=%" PRIu32
2433 ", path=%s, desiredAccess=0x%" PRIx32 " createOptions=0x%" PRIx32
2434 " createDisposition=0x%" PRIx32 "",
2435 deviceId, path, desiredAccess, createOptions, createDisposition);
2436 /* Compute the required Unicode size. */
2437 pathLength = (strlen(path) + 1U) * sizeof(WCHAR);
2438 s = Stream_New(nullptr, 256U + pathLength);
2439
2440 if (!s)
2441 {
2442 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2443 return CHANNEL_RC_NO_MEMORY;
2444 }
2445
2446 rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, 0);
2447 Stream_Write_UINT32(s, desiredAccess); /* DesiredAccess (4 bytes) */
2448 Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */
2449 Stream_Write_UINT32(s, 0);
2450 Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */
2451 Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */
2452 Stream_Write_UINT32(s, createDisposition); /* CreateDisposition (4 bytes) */
2453 Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */
2454 WINPR_ASSERT(pathLength <= UINT32_MAX);
2455 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2456 /* Convert the path to Unicode. */
2457 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2458 pathLength / sizeof(WCHAR), TRUE) < 0)
2459 {
2460 Stream_Free(s, TRUE);
2461 return ERROR_INTERNAL_ERROR;
2462 }
2463 return rdpdr_seal_send_free_request(context, s);
2464}
2465
2471static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, UINT32 deviceId,
2472 UINT32 fileId, UINT32 completionId)
2473{
2474 wStream* s = nullptr;
2475 WINPR_ASSERT(context);
2476 WINPR_ASSERT(context->priv);
2477
2478 WLog_Print(context->priv->log, WLOG_DEBUG,
2479 "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "",
2480 deviceId, fileId);
2481 s = Stream_New(nullptr, 128);
2482
2483 if (!s)
2484 {
2485 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2486 return CHANNEL_RC_NO_MEMORY;
2487 }
2488
2489 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_CLOSE, 0);
2490 Stream_Zero(s, 32); /* Padding (32 bytes) */
2491 return rdpdr_seal_send_free_request(context, s);
2492}
2493
2499static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, UINT32 deviceId,
2500 UINT32 fileId, UINT32 completionId, UINT32 length,
2501 UINT32 offset)
2502{
2503 wStream* s = nullptr;
2504 WINPR_ASSERT(context);
2505 WINPR_ASSERT(context->priv);
2506
2507 WLog_Print(context->priv->log, WLOG_DEBUG,
2508 "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2509 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2510 deviceId, fileId, length, offset);
2511 s = Stream_New(nullptr, 128);
2512
2513 if (!s)
2514 {
2515 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2516 return CHANNEL_RC_NO_MEMORY;
2517 }
2518
2519 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_READ, 0);
2520 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2521 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2522 Stream_Write_UINT32(s, 0);
2523 Stream_Zero(s, 20); /* Padding (20 bytes) */
2524 return rdpdr_seal_send_free_request(context, s);
2525}
2526
2532static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, UINT32 deviceId,
2533 UINT32 fileId, UINT32 completionId,
2534 const char* data, UINT32 length, UINT32 offset)
2535{
2536 wStream* s = nullptr;
2537 WINPR_ASSERT(context);
2538 WINPR_ASSERT(context->priv);
2539
2540 WLog_Print(context->priv->log, WLOG_DEBUG,
2541 "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2542 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2543 deviceId, fileId, length, offset);
2544 s = Stream_New(nullptr, 64 + length);
2545
2546 if (!s)
2547 {
2548 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2549 return CHANNEL_RC_NO_MEMORY;
2550 }
2551
2552 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_WRITE, 0);
2553 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2554 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2555 Stream_Write_UINT32(s, 0);
2556 Stream_Zero(s, 20); /* Padding (20 bytes) */
2557 Stream_Write(s, data, length); /* WriteData (variable) */
2558 return rdpdr_seal_send_free_request(context, s);
2559}
2560
2566static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* context,
2567 UINT32 deviceId, UINT32 fileId,
2568 UINT32 completionId, const char* path)
2569{
2570 size_t pathLength = 0;
2571 wStream* s = nullptr;
2572 WINPR_ASSERT(context);
2573 WINPR_ASSERT(context->priv);
2574
2575 WLog_Print(context->priv->log, WLOG_DEBUG,
2576 "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2577 ", path=%s",
2578 deviceId, fileId, path);
2579 /* Compute the required Unicode size. */
2580 pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
2581 s = Stream_New(nullptr, 64 + pathLength);
2582
2583 if (!s)
2584 {
2585 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2586 return CHANNEL_RC_NO_MEMORY;
2587 }
2588
2589 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_DIRECTORY_CONTROL,
2590 IRP_MN_QUERY_DIRECTORY);
2591 Stream_Write_UINT32(s, FileDirectoryInformation); /* FsInformationClass (4 bytes) */
2592 Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */
2593 WINPR_ASSERT(pathLength <= UINT32_MAX);
2594 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2595 Stream_Zero(s, 23); /* Padding (23 bytes) */
2596
2597 /* Convert the path to Unicode. */
2598 if (pathLength > 0)
2599 {
2600 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2601 pathLength / sizeof(WCHAR), TRUE) < 0)
2602 {
2603 Stream_Free(s, TRUE);
2604 return ERROR_INTERNAL_ERROR;
2605 }
2606 }
2607
2608 return rdpdr_seal_send_free_request(context, s);
2609}
2610
2616static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* context,
2617 UINT32 deviceId, UINT32 fileId,
2618 UINT32 completionId, const char* path)
2619{
2620 size_t pathLength = 0;
2621 wStream* s = nullptr;
2622 WINPR_ASSERT(context);
2623 WINPR_ASSERT(context->priv);
2624
2625 WLog_Print(context->priv->log, WLOG_DEBUG,
2626 "RdpdrServerSendDeviceFileNameRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2627 ", path=%s",
2628 deviceId, fileId, path);
2629 /* Compute the required Unicode size. */
2630 pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
2631 s = Stream_New(nullptr, 64 + pathLength);
2632
2633 if (!s)
2634 {
2635 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2636 return CHANNEL_RC_NO_MEMORY;
2637 }
2638
2639 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_SET_INFORMATION,
2640 0);
2641 Stream_Write_UINT32(s, FileRenameInformation); /* FsInformationClass (4 bytes) */
2642 WINPR_ASSERT(pathLength <= UINT32_MAX - 6U);
2643 Stream_Write_UINT32(s, (UINT32)pathLength + 6U); /* Length (4 bytes) */
2644 Stream_Zero(s, 24); /* Padding (24 bytes) */
2645 /* RDP_FILE_RENAME_INFORMATION */
2646 Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */
2647 Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */
2648 Stream_Write_UINT32(s, (UINT32)pathLength); /* FileNameLength (4 bytes) */
2649
2650 /* Convert the path to Unicode. */
2651 if (pathLength > 0)
2652 {
2653 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2654 pathLength / sizeof(WCHAR), TRUE) < 0)
2655 {
2656 Stream_Free(s, TRUE);
2657 return ERROR_INTERNAL_ERROR;
2658 }
2659 }
2660
2661 return rdpdr_seal_send_free_request(context, s);
2662}
2663
2664static void rdpdr_server_convert_slashes(char* path, int size)
2665{
2666 WINPR_ASSERT(path || (size <= 0));
2667
2668 for (int i = 0; (i < size) && (path[i] != '\0'); i++)
2669 {
2670 if (path[i] == '/')
2671 path[i] = '\\';
2672 }
2673}
2674
2675/*************************************************
2676 * Drive Create Directory
2677 ************************************************/
2678
2684static UINT rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* context, wStream* s,
2685 RDPDR_IRP* irp, UINT32 deviceId,
2686 UINT32 completionId, UINT32 ioStatus)
2687{
2688 WINPR_ASSERT(context);
2689 WINPR_ASSERT(context->priv);
2690 WINPR_ASSERT(s);
2691 WINPR_ASSERT(irp);
2692 WINPR_UNUSED(s);
2693
2694 WLog_Print(context->priv->log, WLOG_DEBUG,
2695 "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%" PRIu32
2696 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2697 deviceId, completionId, ioStatus);
2698 /* Invoke the create directory completion routine. */
2699 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2700 /* Destroy the IRP. */
2701 rdpdr_server_irp_free(irp);
2702 return CHANNEL_RC_OK;
2703}
2704
2710static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* context, wStream* s,
2711 RDPDR_IRP* irp, UINT32 deviceId,
2712 UINT32 completionId, UINT32 ioStatus)
2713{
2714 WINPR_ASSERT(context);
2715 WINPR_ASSERT(context->priv);
2716 WINPR_ASSERT(s);
2717 WINPR_ASSERT(irp);
2718 WLog_Print(context->priv->log, WLOG_DEBUG,
2719 "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%" PRIu32
2720 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2721 deviceId, completionId, ioStatus);
2722
2723 if (ioStatus != STATUS_SUCCESS)
2724 {
2725 /* Invoke the create directory completion routine. */
2726 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2727 /* Destroy the IRP. */
2728 rdpdr_server_irp_free(irp);
2729 return CHANNEL_RC_OK;
2730 }
2731
2732 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
2733 return ERROR_INVALID_DATA;
2734
2735 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2736 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2737 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2738 fileInformation2str(information));
2739
2740 /* Setup the IRP. */
2741 irp->CompletionId = context->priv->NextCompletionId++;
2742 irp->Callback = rdpdr_server_drive_create_directory_callback2;
2743 irp->DeviceId = deviceId;
2744 irp->FileId = fileId;
2745
2746 if (!rdpdr_server_enqueue_irp(context, irp))
2747 {
2748 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2749 rdpdr_server_irp_free(irp);
2750 return ERROR_INTERNAL_ERROR;
2751 }
2752
2753 /* Send a request to close the file */
2754 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
2755}
2756
2762static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData,
2763 UINT32 deviceId, const char* path)
2764{
2765 RDPDR_IRP* irp = nullptr;
2766 WINPR_ASSERT(context);
2767 WINPR_ASSERT(context->priv);
2768 WINPR_ASSERT(callbackData);
2769 WINPR_ASSERT(path);
2770 irp = rdpdr_server_irp_new();
2771
2772 if (!irp)
2773 {
2774 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
2775 return CHANNEL_RC_NO_MEMORY;
2776 }
2777
2778 irp->CompletionId = context->priv->NextCompletionId++;
2779 irp->Callback = rdpdr_server_drive_create_directory_callback1;
2780 irp->CallbackData = callbackData;
2781 irp->DeviceId = deviceId;
2782 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
2783 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
2784
2785 if (!rdpdr_server_enqueue_irp(context, irp))
2786 {
2787 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2788 rdpdr_server_irp_free(irp);
2789 return ERROR_INTERNAL_ERROR;
2790 }
2791
2792 /* Send a request to open the file. */
2793 return rdpdr_server_send_device_create_request(
2794 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
2795 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE);
2796}
2797
2798/*************************************************
2799 * Drive Delete Directory
2800 ************************************************/
2801
2807static UINT rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* context, wStream* s,
2808 RDPDR_IRP* irp, UINT32 deviceId,
2809 UINT32 completionId, UINT32 ioStatus)
2810{
2811 WINPR_UNUSED(s);
2812 WINPR_ASSERT(context);
2813 WINPR_ASSERT(context->priv);
2814 WINPR_ASSERT(irp);
2815
2816 WLog_Print(context->priv->log, WLOG_DEBUG,
2817 "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%" PRIu32
2818 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2819 deviceId, completionId, ioStatus);
2820 /* Invoke the delete directory completion routine. */
2821 context->OnDriveDeleteDirectoryComplete(context, irp->CallbackData, ioStatus);
2822 /* Destroy the IRP. */
2823 rdpdr_server_irp_free(irp);
2824 return CHANNEL_RC_OK;
2825}
2826
2832static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* context, wStream* s,
2833 RDPDR_IRP* irp, UINT32 deviceId,
2834 UINT32 completionId, UINT32 ioStatus)
2835{
2836 WINPR_ASSERT(context);
2837 WINPR_ASSERT(context->priv);
2838 WINPR_ASSERT(irp);
2839 WLog_Print(context->priv->log, WLOG_DEBUG,
2840 "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%" PRIu32
2841 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2842 deviceId, completionId, ioStatus);
2843
2844 if (ioStatus != STATUS_SUCCESS)
2845 {
2846 /* Invoke the delete directory completion routine. */
2847 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
2848 /* Destroy the IRP. */
2849 rdpdr_server_irp_free(irp);
2850 return CHANNEL_RC_OK;
2851 }
2852
2853 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
2854 return ERROR_INVALID_DATA;
2855
2856 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2857 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2858 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2859 fileInformation2str(information));
2860
2861 /* Setup the IRP. */
2862 irp->CompletionId = context->priv->NextCompletionId++;
2863 irp->Callback = rdpdr_server_drive_delete_directory_callback2;
2864 irp->DeviceId = deviceId;
2865 irp->FileId = fileId;
2866
2867 if (!rdpdr_server_enqueue_irp(context, irp))
2868 {
2869 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2870 rdpdr_server_irp_free(irp);
2871 return ERROR_INTERNAL_ERROR;
2872 }
2873
2874 /* Send a request to close the file */
2875 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
2876}
2877
2883static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData,
2884 UINT32 deviceId, const char* path)
2885{
2886 RDPDR_IRP* irp = rdpdr_server_irp_new();
2887 WINPR_ASSERT(context);
2888 WINPR_ASSERT(context->priv);
2889 WINPR_ASSERT(irp);
2890
2891 if (!irp)
2892 {
2893 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
2894 return CHANNEL_RC_NO_MEMORY;
2895 }
2896
2897 irp->CompletionId = context->priv->NextCompletionId++;
2898 irp->Callback = rdpdr_server_drive_delete_directory_callback1;
2899 irp->CallbackData = callbackData;
2900 irp->DeviceId = deviceId;
2901 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
2902 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
2903
2904 if (!rdpdr_server_enqueue_irp(context, irp))
2905 {
2906 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2907 rdpdr_server_irp_free(irp);
2908 return ERROR_INTERNAL_ERROR;
2909 }
2910
2911 /* Send a request to open the file. */
2912 return rdpdr_server_send_device_create_request(
2913 context, deviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE,
2914 FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
2915}
2916
2917/*************************************************
2918 * Drive Query Directory
2919 ************************************************/
2920
2926static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* context, wStream* s,
2927 RDPDR_IRP* irp, UINT32 deviceId,
2928 UINT32 completionId, UINT32 ioStatus)
2929{
2930 UINT error = 0;
2931 UINT32 length = 0;
2932 FILE_DIRECTORY_INFORMATION fdi = WINPR_C_ARRAY_INIT;
2933
2934 WINPR_ASSERT(context);
2935 WINPR_ASSERT(context->priv);
2936 WINPR_ASSERT(irp);
2937 WLog_Print(context->priv->log, WLOG_DEBUG,
2938 "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%" PRIu32
2939 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2940 deviceId, completionId, ioStatus);
2941
2942 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
2943 return ERROR_INVALID_DATA;
2944
2945 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
2946
2947 if (length > 0)
2948 {
2949 if ((error = rdpdr_server_read_file_directory_information(context->priv->log, s, &fdi)))
2950 {
2951 WLog_Print(context->priv->log, WLOG_ERROR,
2952 "rdpdr_server_read_file_directory_information failed with error %" PRIu32
2953 "!",
2954 error);
2955 return error;
2956 }
2957 }
2958 else
2959 {
2960 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 1))
2961 return ERROR_INVALID_DATA;
2962
2963 Stream_Seek(s, 1); /* Padding (1 byte) */
2964 }
2965
2966 if (ioStatus == STATUS_SUCCESS)
2967 {
2968 /* Invoke the query directory completion routine. */
2969 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus,
2970 length > 0 ? &fdi : nullptr);
2971 /* Setup the IRP. */
2972 irp->CompletionId = context->priv->NextCompletionId++;
2973 irp->Callback = rdpdr_server_drive_query_directory_callback2;
2974
2975 if (!rdpdr_server_enqueue_irp(context, irp))
2976 {
2977 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2978 rdpdr_server_irp_free(irp);
2979 return ERROR_INTERNAL_ERROR;
2980 }
2981
2982 /* Send a request to query the directory. */
2983 return rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, irp->FileId,
2984 irp->CompletionId, nullptr);
2985 }
2986 else
2987 {
2988 /* Invoke the query directory completion routine. */
2989 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, nullptr);
2990 /* Destroy the IRP. */
2991 rdpdr_server_irp_free(irp);
2992 }
2993
2994 return CHANNEL_RC_OK;
2995}
2996
3002static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* context, wStream* s,
3003 RDPDR_IRP* irp, UINT32 deviceId,
3004 UINT32 completionId, UINT32 ioStatus)
3005{
3006 WINPR_ASSERT(context);
3007 WINPR_ASSERT(context->priv);
3008 WINPR_ASSERT(irp);
3009 WLog_Print(context->priv->log, WLOG_DEBUG,
3010 "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%" PRIu32
3011 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
3012 deviceId, completionId, ioStatus);
3013
3014 if (ioStatus != STATUS_SUCCESS)
3015 {
3016 /* Invoke the query directory completion routine. */
3017 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, nullptr);
3018 /* Destroy the IRP. */
3019 rdpdr_server_irp_free(irp);
3020 return CHANNEL_RC_OK;
3021 }
3022
3023 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
3024 return ERROR_INVALID_DATA;
3025
3026 const uint32_t fileId = Stream_Get_UINT32(s);
3027 /* Setup the IRP. */
3028 irp->CompletionId = context->priv->NextCompletionId++;
3029 irp->Callback = rdpdr_server_drive_query_directory_callback2;
3030 irp->DeviceId = deviceId;
3031 irp->FileId = fileId;
3032 winpr_str_append("\\*.*", irp->PathName, ARRAYSIZE(irp->PathName), nullptr);
3033
3034 if (!rdpdr_server_enqueue_irp(context, irp))
3035 {
3036 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3037 rdpdr_server_irp_free(irp);
3038 return ERROR_INTERNAL_ERROR;
3039 }
3040
3041 /* Send a request to query the directory. */
3042 return rdpdr_server_send_device_query_directory_request(context, deviceId, fileId,
3043 irp->CompletionId, irp->PathName);
3044}
3045
3051static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData,
3052 UINT32 deviceId, const char* path)
3053{
3054 RDPDR_IRP* irp = rdpdr_server_irp_new();
3055 WINPR_ASSERT(context);
3056 WINPR_ASSERT(context->priv);
3057 WINPR_ASSERT(irp);
3058
3059 if (!irp)
3060 {
3061 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3062 return CHANNEL_RC_NO_MEMORY;
3063 }
3064
3065 irp->CompletionId = context->priv->NextCompletionId++;
3066 irp->Callback = rdpdr_server_drive_query_directory_callback1;
3067 irp->CallbackData = callbackData;
3068 irp->DeviceId = deviceId;
3069 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3070 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3071
3072 if (!rdpdr_server_enqueue_irp(context, irp))
3073 {
3074 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3075 rdpdr_server_irp_free(irp);
3076 return ERROR_INTERNAL_ERROR;
3077 }
3078
3079 /* Send a request to open the directory. */
3080 return rdpdr_server_send_device_create_request(
3081 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3082 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3083}
3084
3085/*************************************************
3086 * Drive Open File
3087 ************************************************/
3088
3094static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, wStream* s,
3095 RDPDR_IRP* irp, UINT32 deviceId,
3096 UINT32 completionId, UINT32 ioStatus)
3097{
3098 WINPR_ASSERT(context);
3099 WINPR_ASSERT(context->priv);
3100 WINPR_ASSERT(irp);
3101 WLog_Print(context->priv->log, WLOG_DEBUG,
3102 "RdpdrServerDriveOpenFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3103 ", ioStatus=0x%" PRIx32 "",
3104 deviceId, completionId, ioStatus);
3105
3106 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3107 return ERROR_INVALID_DATA;
3108
3109 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3110 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3111 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3112 fileInformation2str(information));
3113
3114 /* Invoke the open file completion routine. */
3115 context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, fileId);
3116 /* Destroy the IRP. */
3117 rdpdr_server_irp_free(irp);
3118 return CHANNEL_RC_OK;
3119}
3120
3126static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* callbackData,
3127 UINT32 deviceId, const char* path, UINT32 desiredAccess,
3128 UINT32 createDisposition)
3129{
3130 RDPDR_IRP* irp = rdpdr_server_irp_new();
3131 WINPR_ASSERT(context);
3132 WINPR_ASSERT(context->priv);
3133 WINPR_ASSERT(irp);
3134
3135 if (!irp)
3136 {
3137 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3138 return CHANNEL_RC_NO_MEMORY;
3139 }
3140
3141 irp->CompletionId = context->priv->NextCompletionId++;
3142 irp->Callback = rdpdr_server_drive_open_file_callback;
3143 irp->CallbackData = callbackData;
3144 irp->DeviceId = deviceId;
3145 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3146 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3147
3148 if (!rdpdr_server_enqueue_irp(context, irp))
3149 {
3150 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3151 rdpdr_server_irp_free(irp);
3152 return ERROR_INTERNAL_ERROR;
3153 }
3154
3155 /* Send a request to open the file. */
3156 return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId,
3157 irp->PathName, desiredAccess | SYNCHRONIZE,
3158 FILE_SYNCHRONOUS_IO_NONALERT, createDisposition);
3159}
3160
3161/*************************************************
3162 * Drive Read File
3163 ************************************************/
3164
3170static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, wStream* s,
3171 RDPDR_IRP* irp, UINT32 deviceId,
3172 UINT32 completionId, UINT32 ioStatus)
3173{
3174 UINT32 length = 0;
3175 char* buffer = nullptr;
3176 WINPR_ASSERT(context);
3177 WINPR_ASSERT(context->priv);
3178 WINPR_ASSERT(irp);
3179 WLog_Print(context->priv->log, WLOG_DEBUG,
3180 "RdpdrServerDriveReadFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3181 ", ioStatus=0x%" PRIx32 "",
3182 deviceId, completionId, ioStatus);
3183
3184 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
3185 return ERROR_INVALID_DATA;
3186
3187 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3188
3189 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length))
3190 return ERROR_INVALID_DATA;
3191
3192 if (length > 0)
3193 {
3194 buffer = Stream_Pointer(s);
3195 Stream_Seek(s, length);
3196 }
3197
3198 /* Invoke the read file completion routine. */
3199 context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, length);
3200 /* Destroy the IRP. */
3201 rdpdr_server_irp_free(irp);
3202 return CHANNEL_RC_OK;
3203}
3204
3210static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* callbackData,
3211 UINT32 deviceId, UINT32 fileId, UINT32 length,
3212 UINT32 offset)
3213{
3214 RDPDR_IRP* irp = rdpdr_server_irp_new();
3215 WINPR_ASSERT(context);
3216 WINPR_ASSERT(context->priv);
3217 WINPR_ASSERT(irp);
3218
3219 if (!irp)
3220 {
3221 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3222 return CHANNEL_RC_NO_MEMORY;
3223 }
3224
3225 irp->CompletionId = context->priv->NextCompletionId++;
3226 irp->Callback = rdpdr_server_drive_read_file_callback;
3227 irp->CallbackData = callbackData;
3228 irp->DeviceId = deviceId;
3229 irp->FileId = fileId;
3230
3231 if (!rdpdr_server_enqueue_irp(context, irp))
3232 {
3233 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3234 rdpdr_server_irp_free(irp);
3235 return ERROR_INTERNAL_ERROR;
3236 }
3237
3238 /* Send a request to open the directory. */
3239 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3240 return rdpdr_server_send_device_read_request(context, deviceId, fileId, irp->CompletionId,
3241 length, offset);
3242}
3243
3244/*************************************************
3245 * Drive Write File
3246 ************************************************/
3247
3253static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, wStream* s,
3254 RDPDR_IRP* irp, UINT32 deviceId,
3255 UINT32 completionId, UINT32 ioStatus)
3256{
3257 UINT32 length = 0;
3258 WINPR_ASSERT(context);
3259 WINPR_ASSERT(context->priv);
3260 WINPR_ASSERT(irp);
3261 WLog_Print(context->priv->log, WLOG_DEBUG,
3262 "RdpdrServerDriveWriteFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3263 ", ioStatus=0x%" PRIx32 "",
3264 deviceId, completionId, ioStatus);
3265
3266 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3267 return ERROR_INVALID_DATA;
3268
3269 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3270 Stream_Seek(s, 1); /* Padding (1 byte) */
3271
3272 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length))
3273 return ERROR_INVALID_DATA;
3274
3275 /* Invoke the write file completion routine. */
3276 context->OnDriveWriteFileComplete(context, irp->CallbackData, ioStatus, length);
3277 /* Destroy the IRP. */
3278 rdpdr_server_irp_free(irp);
3279 return CHANNEL_RC_OK;
3280}
3281
3287static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* callbackData,
3288 UINT32 deviceId, UINT32 fileId, const char* buffer,
3289 UINT32 length, UINT32 offset)
3290{
3291 RDPDR_IRP* irp = rdpdr_server_irp_new();
3292 WINPR_ASSERT(context);
3293 WINPR_ASSERT(context->priv);
3294 WINPR_ASSERT(irp);
3295
3296 if (!irp)
3297 {
3298 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3299 return CHANNEL_RC_NO_MEMORY;
3300 }
3301
3302 irp->CompletionId = context->priv->NextCompletionId++;
3303 irp->Callback = rdpdr_server_drive_write_file_callback;
3304 irp->CallbackData = callbackData;
3305 irp->DeviceId = deviceId;
3306 irp->FileId = fileId;
3307
3308 if (!rdpdr_server_enqueue_irp(context, irp))
3309 {
3310 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3311 rdpdr_server_irp_free(irp);
3312 return ERROR_INTERNAL_ERROR;
3313 }
3314
3315 /* Send a request to open the directory. */
3316 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3317 return rdpdr_server_send_device_write_request(context, deviceId, fileId, irp->CompletionId,
3318 buffer, length, offset);
3319}
3320
3321/*************************************************
3322 * Drive Close File
3323 ************************************************/
3324
3330static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, wStream* s,
3331 RDPDR_IRP* irp, UINT32 deviceId,
3332 UINT32 completionId, UINT32 ioStatus)
3333{
3334 WINPR_UNUSED(s);
3335 WINPR_ASSERT(context);
3336 WINPR_ASSERT(context->priv);
3337 WINPR_ASSERT(irp);
3338
3339 WLog_Print(context->priv->log, WLOG_DEBUG,
3340 "RdpdrServerDriveCloseFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3341 ", ioStatus=0x%" PRIx32 "",
3342 deviceId, completionId, ioStatus);
3343
3344 // padding 5 bytes
3345 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3346 return ERROR_INVALID_DATA;
3347
3348 Stream_Seek(s, 5);
3349
3350 /* Invoke the close file completion routine. */
3351 context->OnDriveCloseFileComplete(context, irp->CallbackData, ioStatus);
3352 /* Destroy the IRP. */
3353 rdpdr_server_irp_free(irp);
3354 return CHANNEL_RC_OK;
3355}
3356
3362static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData,
3363 UINT32 deviceId, UINT32 fileId)
3364{
3365 RDPDR_IRP* irp = rdpdr_server_irp_new();
3366 WINPR_ASSERT(context);
3367 WINPR_ASSERT(context->priv);
3368 WINPR_ASSERT(irp);
3369
3370 if (!irp)
3371 {
3372 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3373 return CHANNEL_RC_NO_MEMORY;
3374 }
3375
3376 irp->CompletionId = context->priv->NextCompletionId++;
3377 irp->Callback = rdpdr_server_drive_close_file_callback;
3378 irp->CallbackData = callbackData;
3379 irp->DeviceId = deviceId;
3380 irp->FileId = fileId;
3381
3382 if (!rdpdr_server_enqueue_irp(context, irp))
3383 {
3384 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3385 rdpdr_server_irp_free(irp);
3386 return ERROR_INTERNAL_ERROR;
3387 }
3388
3389 /* Send a request to open the directory. */
3390 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3391 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
3392}
3393
3394/*************************************************
3395 * Drive Delete File
3396 ************************************************/
3397
3403static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context, wStream* s,
3404 RDPDR_IRP* irp, UINT32 deviceId,
3405 UINT32 completionId, UINT32 ioStatus)
3406{
3407 WINPR_UNUSED(s);
3408 WINPR_ASSERT(context);
3409 WINPR_ASSERT(context->priv);
3410 WINPR_ASSERT(irp);
3411
3412 WLog_Print(context->priv->log, WLOG_DEBUG,
3413 "RdpdrServerDriveDeleteFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3414 ", ioStatus=0x%" PRIx32 "",
3415 deviceId, completionId, ioStatus);
3416 /* Invoke the delete file completion routine. */
3417 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3418 /* Destroy the IRP. */
3419 rdpdr_server_irp_free(irp);
3420 return CHANNEL_RC_OK;
3421}
3422
3428static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context, wStream* s,
3429 RDPDR_IRP* irp, UINT32 deviceId,
3430 UINT32 completionId, UINT32 ioStatus)
3431{
3432 WINPR_ASSERT(context);
3433 WINPR_ASSERT(context->priv);
3434 WINPR_ASSERT(irp);
3435 WLog_Print(context->priv->log, WLOG_DEBUG,
3436 "RdpdrServerDriveDeleteFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3437 ", ioStatus=0x%" PRIx32 "",
3438 deviceId, completionId, ioStatus);
3439
3440 if (ioStatus != STATUS_SUCCESS)
3441 {
3442 /* Invoke the close file completion routine. */
3443 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3444 /* Destroy the IRP. */
3445 rdpdr_server_irp_free(irp);
3446 return CHANNEL_RC_OK;
3447 }
3448
3449 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3450 return ERROR_INVALID_DATA;
3451
3452 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3453 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3454
3455 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3456 fileInformation2str(information));
3457 /* Setup the IRP. */
3458 irp->CompletionId = context->priv->NextCompletionId++;
3459 irp->Callback = rdpdr_server_drive_delete_file_callback2;
3460 irp->DeviceId = deviceId;
3461 irp->FileId = fileId;
3462
3463 if (!rdpdr_server_enqueue_irp(context, irp))
3464 {
3465 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3466 rdpdr_server_irp_free(irp);
3467 return ERROR_INTERNAL_ERROR;
3468 }
3469
3470 /* Send a request to close the file */
3471 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
3472}
3473
3479static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData,
3480 UINT32 deviceId, const char* path)
3481{
3482 RDPDR_IRP* irp = rdpdr_server_irp_new();
3483 WINPR_ASSERT(context);
3484 WINPR_ASSERT(context->priv);
3485 WINPR_ASSERT(irp);
3486
3487 if (!irp)
3488 {
3489 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3490 return CHANNEL_RC_NO_MEMORY;
3491 }
3492
3493 irp->CompletionId = context->priv->NextCompletionId++;
3494 irp->Callback = rdpdr_server_drive_delete_file_callback1;
3495 irp->CallbackData = callbackData;
3496 irp->DeviceId = deviceId;
3497 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3498 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3499
3500 if (!rdpdr_server_enqueue_irp(context, irp))
3501 {
3502 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3503 rdpdr_server_irp_free(irp);
3504 return ERROR_INTERNAL_ERROR;
3505 }
3506
3507 /* Send a request to open the file. */
3508 return rdpdr_server_send_device_create_request(
3509 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3510 FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3511}
3512
3513/*************************************************
3514 * Drive Rename File
3515 ************************************************/
3516
3522static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context, wStream* s,
3523 RDPDR_IRP* irp, UINT32 deviceId,
3524 UINT32 completionId, UINT32 ioStatus)
3525{
3526 WINPR_UNUSED(context);
3527 WINPR_UNUSED(s);
3528 WINPR_ASSERT(context);
3529 WINPR_ASSERT(context->priv);
3530 WINPR_ASSERT(irp);
3531
3532 WLog_Print(context->priv->log, WLOG_DEBUG,
3533 "RdpdrServerDriveRenameFileCallback3: deviceId=%" PRIu32 ", completionId=%" PRIu32
3534 ", ioStatus=0x%" PRIx32 "",
3535 deviceId, completionId, ioStatus);
3536 /* Destroy the IRP. */
3537 rdpdr_server_irp_free(irp);
3538 return CHANNEL_RC_OK;
3539}
3540
3546static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context, wStream* s,
3547 RDPDR_IRP* irp, UINT32 deviceId,
3548 UINT32 completionId, UINT32 ioStatus)
3549{
3550 UINT32 length = 0;
3551 WINPR_ASSERT(context);
3552 WINPR_ASSERT(context->priv);
3553 WINPR_ASSERT(irp);
3554 WLog_Print(context->priv->log, WLOG_DEBUG,
3555 "RdpdrServerDriveRenameFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3556 ", ioStatus=0x%" PRIx32 "",
3557 deviceId, completionId, ioStatus);
3558
3559 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3560 return ERROR_INVALID_DATA;
3561
3562 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3563 Stream_Seek(s, 1); /* Padding (1 byte) */
3564 /* Invoke the rename file completion routine. */
3565 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3566 /* Setup the IRP. */
3567 irp->CompletionId = context->priv->NextCompletionId++;
3568 irp->Callback = rdpdr_server_drive_rename_file_callback3;
3569 irp->DeviceId = deviceId;
3570
3571 if (!rdpdr_server_enqueue_irp(context, irp))
3572 {
3573 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3574 rdpdr_server_irp_free(irp);
3575 return ERROR_INTERNAL_ERROR;
3576 }
3577
3578 /* Send a request to close the file */
3579 return rdpdr_server_send_device_close_request(context, deviceId, irp->FileId,
3580 irp->CompletionId);
3581}
3582
3588static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context, wStream* s,
3589 RDPDR_IRP* irp, UINT32 deviceId,
3590 UINT32 completionId, UINT32 ioStatus)
3591{
3592 WINPR_ASSERT(context);
3593 WINPR_ASSERT(context->priv);
3594 WINPR_ASSERT(irp);
3595 WLog_Print(context->priv->log, WLOG_DEBUG,
3596 "RdpdrServerDriveRenameFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3597 ", ioStatus=0x%" PRIx32 "",
3598 deviceId, completionId, ioStatus);
3599
3600 if (ioStatus != STATUS_SUCCESS)
3601 {
3602 /* Invoke the rename file completion routine. */
3603 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3604 /* Destroy the IRP. */
3605 rdpdr_server_irp_free(irp);
3606 return CHANNEL_RC_OK;
3607 }
3608
3609 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3610 return ERROR_INVALID_DATA;
3611
3612 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3613 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3614 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3615 fileInformation2str(information));
3616
3617 /* Setup the IRP. */
3618 irp->CompletionId = context->priv->NextCompletionId++;
3619 irp->Callback = rdpdr_server_drive_rename_file_callback2;
3620 irp->DeviceId = deviceId;
3621 irp->FileId = fileId;
3622
3623 if (!rdpdr_server_enqueue_irp(context, irp))
3624 {
3625 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3626 rdpdr_server_irp_free(irp);
3627 return ERROR_INTERNAL_ERROR;
3628 }
3629
3630 /* Send a request to rename the file */
3631 return rdpdr_server_send_device_file_rename_request(context, deviceId, fileId,
3632 irp->CompletionId, irp->ExtraBuffer);
3633}
3634
3640static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* callbackData,
3641 UINT32 deviceId, const char* oldPath,
3642 const char* newPath)
3643{
3644 WINPR_ASSERT(context);
3645 WINPR_ASSERT(context->priv);
3646 RDPDR_IRP* irp = rdpdr_server_irp_new();
3647
3648 if (!irp)
3649 {
3650 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3651 return CHANNEL_RC_NO_MEMORY;
3652 }
3653
3654 irp->CompletionId = context->priv->NextCompletionId++;
3655 irp->Callback = rdpdr_server_drive_rename_file_callback1;
3656 irp->CallbackData = callbackData;
3657 irp->DeviceId = deviceId;
3658 strncpy(irp->PathName, oldPath, sizeof(irp->PathName) - 1);
3659 strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer) - 1);
3660 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3661 rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer));
3662
3663 if (!rdpdr_server_enqueue_irp(context, irp))
3664 {
3665 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3666 rdpdr_server_irp_free(irp);
3667 return ERROR_INTERNAL_ERROR;
3668 }
3669
3670 /* Send a request to open the file. */
3671 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3672 return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId,
3673 irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3674 FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3675}
3676
3677static void rdpdr_server_private_free(RdpdrServerPrivate* ctx)
3678{
3679 if (!ctx)
3680 return;
3681 ListDictionary_Free(ctx->IrpList);
3682 HashTable_Free(ctx->devicelist);
3683 free(ctx->ClientComputerName);
3684 free(ctx);
3685}
3686
3687#define TAG CHANNELS_TAG("rdpdr.server")
3688static RdpdrServerPrivate* rdpdr_server_private_new(void)
3689{
3690 RdpdrServerPrivate* priv = (RdpdrServerPrivate*)calloc(1, sizeof(RdpdrServerPrivate));
3691
3692 if (!priv)
3693 goto fail;
3694
3695 priv->log = WLog_Get(TAG);
3696 priv->VersionMajor = RDPDR_VERSION_MAJOR;
3697 priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
3698 priv->ClientId = g_ClientId++;
3699 priv->UserLoggedOnPdu = TRUE;
3700 priv->NextCompletionId = 1;
3701 priv->IrpList = ListDictionary_New(TRUE);
3702
3703 if (!priv->IrpList)
3704 goto fail;
3705
3706 priv->devicelist = HashTable_New(FALSE);
3707 if (!priv->devicelist)
3708 goto fail;
3709
3710 if (!HashTable_SetHashFunction(priv->devicelist, rdpdr_deviceid_hash))
3711 goto fail;
3712
3713 {
3714 wObject* obj = HashTable_ValueObject(priv->devicelist);
3715 WINPR_ASSERT(obj);
3716 obj->fnObjectFree = rdpdr_device_free_h;
3717 obj->fnObjectNew = rdpdr_device_clone;
3718 }
3719
3720 {
3721 wObject* obj = HashTable_KeyObject(priv->devicelist);
3722 obj->fnObjectEquals = rdpdr_device_equal;
3723 obj->fnObjectFree = rdpdr_device_key_free;
3724 obj->fnObjectNew = rdpdr_device_key_clone;
3725 }
3726
3727 return priv;
3728fail:
3729 rdpdr_server_private_free(priv);
3730 return nullptr;
3731}
3732
3733RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
3734{
3735 RdpdrServerContext* context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext));
3736
3737 if (!context)
3738 goto fail;
3739
3740 context->vcm = vcm;
3741 context->Start = rdpdr_server_start;
3742 context->Stop = rdpdr_server_stop;
3743 context->DriveCreateDirectory = rdpdr_server_drive_create_directory;
3744 context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory;
3745 context->DriveQueryDirectory = rdpdr_server_drive_query_directory;
3746 context->DriveOpenFile = rdpdr_server_drive_open_file;
3747 context->DriveReadFile = rdpdr_server_drive_read_file;
3748 context->DriveWriteFile = rdpdr_server_drive_write_file;
3749 context->DriveCloseFile = rdpdr_server_drive_close_file;
3750 context->DriveDeleteFile = rdpdr_server_drive_delete_file;
3751 context->DriveRenameFile = rdpdr_server_drive_rename_file;
3752 context->priv = rdpdr_server_private_new();
3753 if (!context->priv)
3754 goto fail;
3755
3756 /* By default announce everything, the server application can deactivate that later on */
3757 context->supported = UINT16_MAX;
3758
3759 return context;
3760fail:
3761 WINPR_PRAGMA_DIAG_PUSH
3762 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
3763 rdpdr_server_context_free(context);
3764 WINPR_PRAGMA_DIAG_POP
3765 return nullptr;
3766}
3767
3768void rdpdr_server_context_free(RdpdrServerContext* context)
3769{
3770 if (!context)
3771 return;
3772
3773 rdpdr_server_private_free(context->priv);
3774 free(context);
3775}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_rdpdr_dtyp_string(UINT32 type)
Returns a string representation of RDPDR_DTYP_*.
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