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 NULL;
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 NULL;
166}
167
168static void* rdpdr_device_key_clone(const void* pvval)
169{
170 const UINT32* val = pvval;
171 if (!val)
172 return NULL;
173
174 UINT32* ptr = calloc(1, sizeof(UINT32));
175 if (!ptr)
176 return NULL;
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 NULL;
229 if (_wcsnlen(str, charlen) == charlen)
230 {
231 WLog_Print(log, WLOG_WARN, "[rdpdr] unicode string not '\\0' terminated");
232 return NULL;
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 = NULL;
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_SetPosition(s, 0);
281
282 if (length >= RDPDR_HEADER_LENGTH)
283 {
284 RDPDR_HEADER header = { 0 };
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 = NULL;
309 RDPDR_HEADER header = { 0 };
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(NULL, 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 = NULL;
443 }
444
445 if (UnicodeFlag)
446 {
447 context->priv->ClientComputerName =
448 Stream_Read_UTF16_String_As_UTF8(s, ComputerNameLen / sizeof(WCHAR), NULL);
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, NULL);
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] = { 0 };
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] = { 0 };
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) ? TRUE : FALSE;
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 = NULL;
812 RDPDR_HEADER header = { 0 };
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(NULL, 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 = { 0 };
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)(1 << 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 = NULL;
1049 RDPDR_HEADER header = { 0 };
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(NULL, 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 = { 0 };
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 = NULL;
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 = NULL;
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), NULL);
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 = NULL;
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 = NULL;
1833 RDPDR_HEADER header = { 0 };
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(NULL, 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] = { 0 };
1856 UINT32 PnPNameLen = 0;
1857 UINT32 DriverNameLen = 0;
1858 UINT32 PrinterNameLen = 0;
1859 UINT32 CachedFieldsLen = 0;
1860 const WCHAR* PnPName = NULL;
1861 const WCHAR* DriverName = NULL;
1862 const WCHAR* PrinterName = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
1955 const WCHAR* NewPrinterName = NULL;
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 = NULL;
2164 HANDLE events[8] = { 0 };
2165 HANDLE ChannelEvent = NULL;
2166 DWORD BytesReturned = 0;
2167 UINT error = 0;
2168 RdpdrServerContext* context = (RdpdrServerContext*)arg;
2169 wStream* s = Stream_New(NULL, 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, NULL, 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_SetPosition(s, 0);
2253 Stream_SetLength(s, BytesReturned);
2254
2255 while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH)
2256 {
2257 RDPDR_HEADER header = { 0 };
2258
2259 Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
2260 Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
2261
2262 if ((error = rdpdr_server_receive_pdu(context, s, &header)))
2263 {
2264 WLog_Print(context->priv->log, WLOG_ERROR,
2265 "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error);
2266 goto out_stream;
2267 }
2268 }
2269 }
2270 }
2271
2272out_stream:
2273 Stream_Free(s, TRUE);
2274out:
2275
2276 if (error && context->rdpcontext)
2277 setChannelError(context->rdpcontext, error, "rdpdr_server_thread reported an error");
2278
2279 ExitThread(error);
2280 return error;
2281}
2282
2288static UINT rdpdr_server_start(RdpdrServerContext* context)
2289{
2290 WINPR_ASSERT(context);
2291 WINPR_ASSERT(context->priv);
2292 context->priv->ChannelHandle =
2293 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPDR_SVC_CHANNEL_NAME);
2294
2295 if (!context->priv->ChannelHandle)
2296 {
2297 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpen failed!");
2298 return CHANNEL_RC_BAD_CHANNEL;
2299 }
2300
2301 if (!(context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
2302 {
2303 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
2304 return ERROR_INTERNAL_ERROR;
2305 }
2306
2307 if (!(context->priv->Thread =
2308 CreateThread(NULL, 0, rdpdr_server_thread, (void*)context, 0, NULL)))
2309 {
2310 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
2311 (void)CloseHandle(context->priv->StopEvent);
2312 context->priv->StopEvent = NULL;
2313 return ERROR_INTERNAL_ERROR;
2314 }
2315
2316 return CHANNEL_RC_OK;
2317}
2318
2324static UINT rdpdr_server_stop(RdpdrServerContext* context)
2325{
2326 UINT error = 0;
2327 WINPR_ASSERT(context);
2328 WINPR_ASSERT(context->priv);
2329
2330 if (context->priv->StopEvent)
2331 {
2332 (void)SetEvent(context->priv->StopEvent);
2333
2334 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
2335 {
2336 error = GetLastError();
2337 WLog_Print(context->priv->log, WLOG_ERROR,
2338 "WaitForSingleObject failed with error %" PRIu32 "!", error);
2339 return error;
2340 }
2341
2342 (void)CloseHandle(context->priv->Thread);
2343 context->priv->Thread = NULL;
2344 (void)CloseHandle(context->priv->StopEvent);
2345 context->priv->StopEvent = NULL;
2346 }
2347
2348 if (context->priv->ChannelHandle)
2349 {
2350 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
2351 context->priv->ChannelHandle = NULL;
2352 }
2353 return CHANNEL_RC_OK;
2354}
2355
2356static void rdpdr_server_write_device_iorequest(wStream* s, UINT32 deviceId, UINT32 fileId,
2357 UINT32 completionId, UINT32 majorFunction,
2358 UINT32 minorFunction)
2359{
2360 Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
2361 Stream_Write_UINT16(s, PAKID_CORE_DEVICE_IOREQUEST); /* PacketId (2 bytes) */
2362 Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */
2363 Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */
2364 Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */
2365 Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */
2366 Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */
2367}
2368
2374static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s,
2376{
2377 UINT32 fileNameLength = 0;
2378 WINPR_ASSERT(fdi);
2379 ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION));
2380
2381 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 64))
2382 return ERROR_INVALID_DATA;
2383
2384 Stream_Read_UINT32(s, fdi->NextEntryOffset); /* NextEntryOffset (4 bytes) */
2385 Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */
2386 Stream_Read_INT64(s, fdi->CreationTime.QuadPart); /* CreationTime (8 bytes) */
2387 Stream_Read_INT64(s, fdi->LastAccessTime.QuadPart); /* LastAccessTime (8 bytes) */
2388 Stream_Read_INT64(s, fdi->LastWriteTime.QuadPart); /* LastWriteTime (8 bytes) */
2389 Stream_Read_INT64(s, fdi->ChangeTime.QuadPart); /* ChangeTime (8 bytes) */
2390 Stream_Read_INT64(s, fdi->EndOfFile.QuadPart); /* EndOfFile (8 bytes) */
2391 Stream_Read_INT64(s, fdi->AllocationSize.QuadPart); /* AllocationSize (8 bytes) */
2392 Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */
2393 Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */
2394
2395 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, fileNameLength))
2396 return ERROR_INVALID_DATA;
2397
2398 if (fileNameLength / sizeof(WCHAR) > ARRAYSIZE(fdi->FileName))
2399 return ERROR_INVALID_DATA;
2400
2401#if defined(__MINGW32__) || defined(WITH_WCHAR_FILE_DIRECTORY_INFORMATION)
2402 if (Stream_Read_UTF16_String(s, fdi->FileName, fileNameLength / sizeof(WCHAR)))
2403 return ERROR_INVALID_DATA;
2404#else
2405 if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, fileNameLength / sizeof(WCHAR), fdi->FileName,
2406 ARRAYSIZE(fdi->FileName)) < 0)
2407 return ERROR_INVALID_DATA;
2408#endif
2409 return CHANNEL_RC_OK;
2410}
2411
2417static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, UINT32 deviceId,
2418 UINT32 completionId, const char* path,
2419 UINT32 desiredAccess, UINT32 createOptions,
2420 UINT32 createDisposition)
2421{
2422 size_t pathLength = 0;
2423 wStream* s = NULL;
2424 WINPR_ASSERT(context);
2425 WINPR_ASSERT(context->priv);
2426
2427 WLog_Print(context->priv->log, WLOG_DEBUG,
2428 "RdpdrServerSendDeviceCreateRequest: deviceId=%" PRIu32
2429 ", path=%s, desiredAccess=0x%" PRIx32 " createOptions=0x%" PRIx32
2430 " createDisposition=0x%" PRIx32 "",
2431 deviceId, path, desiredAccess, createOptions, createDisposition);
2432 /* Compute the required Unicode size. */
2433 pathLength = (strlen(path) + 1U) * sizeof(WCHAR);
2434 s = Stream_New(NULL, 256U + pathLength);
2435
2436 if (!s)
2437 {
2438 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2439 return CHANNEL_RC_NO_MEMORY;
2440 }
2441
2442 rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, 0);
2443 Stream_Write_UINT32(s, desiredAccess); /* DesiredAccess (4 bytes) */
2444 Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */
2445 Stream_Write_UINT32(s, 0);
2446 Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */
2447 Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */
2448 Stream_Write_UINT32(s, createDisposition); /* CreateDisposition (4 bytes) */
2449 Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */
2450 WINPR_ASSERT(pathLength <= UINT32_MAX);
2451 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2452 /* Convert the path to Unicode. */
2453 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2454 pathLength / sizeof(WCHAR), TRUE) < 0)
2455 {
2456 Stream_Free(s, TRUE);
2457 return ERROR_INTERNAL_ERROR;
2458 }
2459 return rdpdr_seal_send_free_request(context, s);
2460}
2461
2467static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, UINT32 deviceId,
2468 UINT32 fileId, UINT32 completionId)
2469{
2470 wStream* s = NULL;
2471 WINPR_ASSERT(context);
2472 WINPR_ASSERT(context->priv);
2473
2474 WLog_Print(context->priv->log, WLOG_DEBUG,
2475 "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "",
2476 deviceId, fileId);
2477 s = Stream_New(NULL, 128);
2478
2479 if (!s)
2480 {
2481 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2482 return CHANNEL_RC_NO_MEMORY;
2483 }
2484
2485 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_CLOSE, 0);
2486 Stream_Zero(s, 32); /* Padding (32 bytes) */
2487 return rdpdr_seal_send_free_request(context, s);
2488}
2489
2495static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, UINT32 deviceId,
2496 UINT32 fileId, UINT32 completionId, UINT32 length,
2497 UINT32 offset)
2498{
2499 wStream* s = NULL;
2500 WINPR_ASSERT(context);
2501 WINPR_ASSERT(context->priv);
2502
2503 WLog_Print(context->priv->log, WLOG_DEBUG,
2504 "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2505 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2506 deviceId, fileId, length, offset);
2507 s = Stream_New(NULL, 128);
2508
2509 if (!s)
2510 {
2511 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2512 return CHANNEL_RC_NO_MEMORY;
2513 }
2514
2515 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_READ, 0);
2516 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2517 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2518 Stream_Write_UINT32(s, 0);
2519 Stream_Zero(s, 20); /* Padding (20 bytes) */
2520 return rdpdr_seal_send_free_request(context, s);
2521}
2522
2528static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, UINT32 deviceId,
2529 UINT32 fileId, UINT32 completionId,
2530 const char* data, UINT32 length, UINT32 offset)
2531{
2532 wStream* s = NULL;
2533 WINPR_ASSERT(context);
2534 WINPR_ASSERT(context->priv);
2535
2536 WLog_Print(context->priv->log, WLOG_DEBUG,
2537 "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2538 ", length=%" PRIu32 ", offset=%" PRIu32 "",
2539 deviceId, fileId, length, offset);
2540 s = Stream_New(NULL, 64 + length);
2541
2542 if (!s)
2543 {
2544 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2545 return CHANNEL_RC_NO_MEMORY;
2546 }
2547
2548 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_WRITE, 0);
2549 Stream_Write_UINT32(s, length); /* Length (4 bytes) */
2550 Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */
2551 Stream_Write_UINT32(s, 0);
2552 Stream_Zero(s, 20); /* Padding (20 bytes) */
2553 Stream_Write(s, data, length); /* WriteData (variable) */
2554 return rdpdr_seal_send_free_request(context, s);
2555}
2556
2562static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* context,
2563 UINT32 deviceId, UINT32 fileId,
2564 UINT32 completionId, const char* path)
2565{
2566 size_t pathLength = 0;
2567 wStream* s = NULL;
2568 WINPR_ASSERT(context);
2569 WINPR_ASSERT(context->priv);
2570
2571 WLog_Print(context->priv->log, WLOG_DEBUG,
2572 "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2573 ", path=%s",
2574 deviceId, fileId, path);
2575 /* Compute the required Unicode size. */
2576 pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
2577 s = Stream_New(NULL, 64 + pathLength);
2578
2579 if (!s)
2580 {
2581 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2582 return CHANNEL_RC_NO_MEMORY;
2583 }
2584
2585 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_DIRECTORY_CONTROL,
2586 IRP_MN_QUERY_DIRECTORY);
2587 Stream_Write_UINT32(s, FileDirectoryInformation); /* FsInformationClass (4 bytes) */
2588 Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */
2589 WINPR_ASSERT(pathLength <= UINT32_MAX);
2590 Stream_Write_UINT32(s, (UINT32)pathLength); /* PathLength (4 bytes) */
2591 Stream_Zero(s, 23); /* Padding (23 bytes) */
2592
2593 /* Convert the path to Unicode. */
2594 if (pathLength > 0)
2595 {
2596 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2597 pathLength / sizeof(WCHAR), TRUE) < 0)
2598 {
2599 Stream_Free(s, TRUE);
2600 return ERROR_INTERNAL_ERROR;
2601 }
2602 }
2603
2604 return rdpdr_seal_send_free_request(context, s);
2605}
2606
2612static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* context,
2613 UINT32 deviceId, UINT32 fileId,
2614 UINT32 completionId, const char* path)
2615{
2616 size_t pathLength = 0;
2617 wStream* s = NULL;
2618 WINPR_ASSERT(context);
2619 WINPR_ASSERT(context->priv);
2620
2621 WLog_Print(context->priv->log, WLOG_DEBUG,
2622 "RdpdrServerSendDeviceFileNameRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32
2623 ", path=%s",
2624 deviceId, fileId, path);
2625 /* Compute the required Unicode size. */
2626 pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0;
2627 s = Stream_New(NULL, 64 + pathLength);
2628
2629 if (!s)
2630 {
2631 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
2632 return CHANNEL_RC_NO_MEMORY;
2633 }
2634
2635 rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_SET_INFORMATION,
2636 0);
2637 Stream_Write_UINT32(s, FileRenameInformation); /* FsInformationClass (4 bytes) */
2638 WINPR_ASSERT(pathLength <= UINT32_MAX - 6U);
2639 Stream_Write_UINT32(s, (UINT32)pathLength + 6U); /* Length (4 bytes) */
2640 Stream_Zero(s, 24); /* Padding (24 bytes) */
2641 /* RDP_FILE_RENAME_INFORMATION */
2642 Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */
2643 Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */
2644 Stream_Write_UINT32(s, (UINT32)pathLength); /* FileNameLength (4 bytes) */
2645
2646 /* Convert the path to Unicode. */
2647 if (pathLength > 0)
2648 {
2649 if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path,
2650 pathLength / sizeof(WCHAR), TRUE) < 0)
2651 {
2652 Stream_Free(s, TRUE);
2653 return ERROR_INTERNAL_ERROR;
2654 }
2655 }
2656
2657 return rdpdr_seal_send_free_request(context, s);
2658}
2659
2660static void rdpdr_server_convert_slashes(char* path, int size)
2661{
2662 WINPR_ASSERT(path || (size <= 0));
2663
2664 for (int i = 0; (i < size) && (path[i] != '\0'); i++)
2665 {
2666 if (path[i] == '/')
2667 path[i] = '\\';
2668 }
2669}
2670
2671/*************************************************
2672 * Drive Create Directory
2673 ************************************************/
2674
2680static UINT rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* context, wStream* s,
2681 RDPDR_IRP* irp, UINT32 deviceId,
2682 UINT32 completionId, UINT32 ioStatus)
2683{
2684 WINPR_ASSERT(context);
2685 WINPR_ASSERT(context->priv);
2686 WINPR_ASSERT(s);
2687 WINPR_ASSERT(irp);
2688 WINPR_UNUSED(s);
2689
2690 WLog_Print(context->priv->log, WLOG_DEBUG,
2691 "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%" PRIu32
2692 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2693 deviceId, completionId, ioStatus);
2694 /* Invoke the create directory completion routine. */
2695 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2696 /* Destroy the IRP. */
2697 rdpdr_server_irp_free(irp);
2698 return CHANNEL_RC_OK;
2699}
2700
2706static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* context, wStream* s,
2707 RDPDR_IRP* irp, UINT32 deviceId,
2708 UINT32 completionId, UINT32 ioStatus)
2709{
2710 WINPR_ASSERT(context);
2711 WINPR_ASSERT(context->priv);
2712 WINPR_ASSERT(s);
2713 WINPR_ASSERT(irp);
2714 WLog_Print(context->priv->log, WLOG_DEBUG,
2715 "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%" PRIu32
2716 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2717 deviceId, completionId, ioStatus);
2718
2719 if (ioStatus != STATUS_SUCCESS)
2720 {
2721 /* Invoke the create directory completion routine. */
2722 context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus);
2723 /* Destroy the IRP. */
2724 rdpdr_server_irp_free(irp);
2725 return CHANNEL_RC_OK;
2726 }
2727
2728 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
2729 return ERROR_INVALID_DATA;
2730
2731 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2732 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2733 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2734 fileInformation2str(information));
2735
2736 /* Setup the IRP. */
2737 irp->CompletionId = context->priv->NextCompletionId++;
2738 irp->Callback = rdpdr_server_drive_create_directory_callback2;
2739 irp->DeviceId = deviceId;
2740 irp->FileId = fileId;
2741
2742 if (!rdpdr_server_enqueue_irp(context, irp))
2743 {
2744 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2745 rdpdr_server_irp_free(irp);
2746 return ERROR_INTERNAL_ERROR;
2747 }
2748
2749 /* Send a request to close the file */
2750 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
2751}
2752
2758static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData,
2759 UINT32 deviceId, const char* path)
2760{
2761 RDPDR_IRP* irp = NULL;
2762 WINPR_ASSERT(context);
2763 WINPR_ASSERT(context->priv);
2764 WINPR_ASSERT(callbackData);
2765 WINPR_ASSERT(path);
2766 irp = rdpdr_server_irp_new();
2767
2768 if (!irp)
2769 {
2770 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
2771 return CHANNEL_RC_NO_MEMORY;
2772 }
2773
2774 irp->CompletionId = context->priv->NextCompletionId++;
2775 irp->Callback = rdpdr_server_drive_create_directory_callback1;
2776 irp->CallbackData = callbackData;
2777 irp->DeviceId = deviceId;
2778 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
2779 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
2780
2781 if (!rdpdr_server_enqueue_irp(context, irp))
2782 {
2783 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2784 rdpdr_server_irp_free(irp);
2785 return ERROR_INTERNAL_ERROR;
2786 }
2787
2788 /* Send a request to open the file. */
2789 return rdpdr_server_send_device_create_request(
2790 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
2791 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE);
2792}
2793
2794/*************************************************
2795 * Drive Delete Directory
2796 ************************************************/
2797
2803static UINT rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* context, wStream* s,
2804 RDPDR_IRP* irp, UINT32 deviceId,
2805 UINT32 completionId, UINT32 ioStatus)
2806{
2807 WINPR_UNUSED(s);
2808 WINPR_ASSERT(context);
2809 WINPR_ASSERT(context->priv);
2810 WINPR_ASSERT(irp);
2811
2812 WLog_Print(context->priv->log, WLOG_DEBUG,
2813 "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%" PRIu32
2814 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2815 deviceId, completionId, ioStatus);
2816 /* Invoke the delete directory completion routine. */
2817 context->OnDriveDeleteDirectoryComplete(context, irp->CallbackData, ioStatus);
2818 /* Destroy the IRP. */
2819 rdpdr_server_irp_free(irp);
2820 return CHANNEL_RC_OK;
2821}
2822
2828static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* context, wStream* s,
2829 RDPDR_IRP* irp, UINT32 deviceId,
2830 UINT32 completionId, UINT32 ioStatus)
2831{
2832 WINPR_ASSERT(context);
2833 WINPR_ASSERT(context->priv);
2834 WINPR_ASSERT(irp);
2835 WLog_Print(context->priv->log, WLOG_DEBUG,
2836 "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%" PRIu32
2837 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2838 deviceId, completionId, ioStatus);
2839
2840 if (ioStatus != STATUS_SUCCESS)
2841 {
2842 /* Invoke the delete directory completion routine. */
2843 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
2844 /* Destroy the IRP. */
2845 rdpdr_server_irp_free(irp);
2846 return CHANNEL_RC_OK;
2847 }
2848
2849 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
2850 return ERROR_INVALID_DATA;
2851
2852 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
2853 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
2854 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
2855 fileInformation2str(information));
2856
2857 /* Setup the IRP. */
2858 irp->CompletionId = context->priv->NextCompletionId++;
2859 irp->Callback = rdpdr_server_drive_delete_directory_callback2;
2860 irp->DeviceId = deviceId;
2861 irp->FileId = fileId;
2862
2863 if (!rdpdr_server_enqueue_irp(context, irp))
2864 {
2865 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2866 rdpdr_server_irp_free(irp);
2867 return ERROR_INTERNAL_ERROR;
2868 }
2869
2870 /* Send a request to close the file */
2871 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
2872}
2873
2879static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData,
2880 UINT32 deviceId, const char* path)
2881{
2882 RDPDR_IRP* irp = rdpdr_server_irp_new();
2883 WINPR_ASSERT(context);
2884 WINPR_ASSERT(context->priv);
2885 WINPR_ASSERT(irp);
2886
2887 if (!irp)
2888 {
2889 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
2890 return CHANNEL_RC_NO_MEMORY;
2891 }
2892
2893 irp->CompletionId = context->priv->NextCompletionId++;
2894 irp->Callback = rdpdr_server_drive_delete_directory_callback1;
2895 irp->CallbackData = callbackData;
2896 irp->DeviceId = deviceId;
2897 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
2898 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
2899
2900 if (!rdpdr_server_enqueue_irp(context, irp))
2901 {
2902 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2903 rdpdr_server_irp_free(irp);
2904 return ERROR_INTERNAL_ERROR;
2905 }
2906
2907 /* Send a request to open the file. */
2908 return rdpdr_server_send_device_create_request(
2909 context, deviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE,
2910 FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
2911}
2912
2913/*************************************************
2914 * Drive Query Directory
2915 ************************************************/
2916
2922static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* context, wStream* s,
2923 RDPDR_IRP* irp, UINT32 deviceId,
2924 UINT32 completionId, UINT32 ioStatus)
2925{
2926 UINT error = 0;
2927 UINT32 length = 0;
2928 FILE_DIRECTORY_INFORMATION fdi = { 0 };
2929
2930 WINPR_ASSERT(context);
2931 WINPR_ASSERT(context->priv);
2932 WINPR_ASSERT(irp);
2933 WLog_Print(context->priv->log, WLOG_DEBUG,
2934 "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%" PRIu32
2935 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
2936 deviceId, completionId, ioStatus);
2937
2938 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
2939 return ERROR_INVALID_DATA;
2940
2941 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
2942
2943 if (length > 0)
2944 {
2945 if ((error = rdpdr_server_read_file_directory_information(context->priv->log, s, &fdi)))
2946 {
2947 WLog_Print(context->priv->log, WLOG_ERROR,
2948 "rdpdr_server_read_file_directory_information failed with error %" PRIu32
2949 "!",
2950 error);
2951 return error;
2952 }
2953 }
2954 else
2955 {
2956 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 1))
2957 return ERROR_INVALID_DATA;
2958
2959 Stream_Seek(s, 1); /* Padding (1 byte) */
2960 }
2961
2962 if (ioStatus == STATUS_SUCCESS)
2963 {
2964 /* Invoke the query directory completion routine. */
2965 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus,
2966 length > 0 ? &fdi : NULL);
2967 /* Setup the IRP. */
2968 irp->CompletionId = context->priv->NextCompletionId++;
2969 irp->Callback = rdpdr_server_drive_query_directory_callback2;
2970
2971 if (!rdpdr_server_enqueue_irp(context, irp))
2972 {
2973 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
2974 rdpdr_server_irp_free(irp);
2975 return ERROR_INTERNAL_ERROR;
2976 }
2977
2978 /* Send a request to query the directory. */
2979 return rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, irp->FileId,
2980 irp->CompletionId, NULL);
2981 }
2982 else
2983 {
2984 /* Invoke the query directory completion routine. */
2985 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL);
2986 /* Destroy the IRP. */
2987 rdpdr_server_irp_free(irp);
2988 }
2989
2990 return CHANNEL_RC_OK;
2991}
2992
2998static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* context, wStream* s,
2999 RDPDR_IRP* irp, UINT32 deviceId,
3000 UINT32 completionId, UINT32 ioStatus)
3001{
3002 WINPR_ASSERT(context);
3003 WINPR_ASSERT(context->priv);
3004 WINPR_ASSERT(irp);
3005 WLog_Print(context->priv->log, WLOG_DEBUG,
3006 "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%" PRIu32
3007 ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "",
3008 deviceId, completionId, ioStatus);
3009
3010 if (ioStatus != STATUS_SUCCESS)
3011 {
3012 /* Invoke the query directory completion routine. */
3013 context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL);
3014 /* Destroy the IRP. */
3015 rdpdr_server_irp_free(irp);
3016 return CHANNEL_RC_OK;
3017 }
3018
3019 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
3020 return ERROR_INVALID_DATA;
3021
3022 const uint32_t fileId = Stream_Get_UINT32(s);
3023 /* Setup the IRP. */
3024 irp->CompletionId = context->priv->NextCompletionId++;
3025 irp->Callback = rdpdr_server_drive_query_directory_callback2;
3026 irp->DeviceId = deviceId;
3027 irp->FileId = fileId;
3028 winpr_str_append("\\*.*", irp->PathName, ARRAYSIZE(irp->PathName), NULL);
3029
3030 if (!rdpdr_server_enqueue_irp(context, irp))
3031 {
3032 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3033 rdpdr_server_irp_free(irp);
3034 return ERROR_INTERNAL_ERROR;
3035 }
3036
3037 /* Send a request to query the directory. */
3038 return rdpdr_server_send_device_query_directory_request(context, deviceId, fileId,
3039 irp->CompletionId, irp->PathName);
3040}
3041
3047static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData,
3048 UINT32 deviceId, const char* path)
3049{
3050 RDPDR_IRP* irp = rdpdr_server_irp_new();
3051 WINPR_ASSERT(context);
3052 WINPR_ASSERT(context->priv);
3053 WINPR_ASSERT(irp);
3054
3055 if (!irp)
3056 {
3057 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3058 return CHANNEL_RC_NO_MEMORY;
3059 }
3060
3061 irp->CompletionId = context->priv->NextCompletionId++;
3062 irp->Callback = rdpdr_server_drive_query_directory_callback1;
3063 irp->CallbackData = callbackData;
3064 irp->DeviceId = deviceId;
3065 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3066 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3067
3068 if (!rdpdr_server_enqueue_irp(context, irp))
3069 {
3070 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3071 rdpdr_server_irp_free(irp);
3072 return ERROR_INTERNAL_ERROR;
3073 }
3074
3075 /* Send a request to open the directory. */
3076 return rdpdr_server_send_device_create_request(
3077 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3078 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3079}
3080
3081/*************************************************
3082 * Drive Open File
3083 ************************************************/
3084
3090static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, wStream* s,
3091 RDPDR_IRP* irp, UINT32 deviceId,
3092 UINT32 completionId, UINT32 ioStatus)
3093{
3094 WINPR_ASSERT(context);
3095 WINPR_ASSERT(context->priv);
3096 WINPR_ASSERT(irp);
3097 WLog_Print(context->priv->log, WLOG_DEBUG,
3098 "RdpdrServerDriveOpenFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3099 ", ioStatus=0x%" PRIx32 "",
3100 deviceId, completionId, ioStatus);
3101
3102 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3103 return ERROR_INVALID_DATA;
3104
3105 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3106 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3107 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3108 fileInformation2str(information));
3109
3110 /* Invoke the open file completion routine. */
3111 context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, fileId);
3112 /* Destroy the IRP. */
3113 rdpdr_server_irp_free(irp);
3114 return CHANNEL_RC_OK;
3115}
3116
3122static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* callbackData,
3123 UINT32 deviceId, const char* path, UINT32 desiredAccess,
3124 UINT32 createDisposition)
3125{
3126 RDPDR_IRP* irp = rdpdr_server_irp_new();
3127 WINPR_ASSERT(context);
3128 WINPR_ASSERT(context->priv);
3129 WINPR_ASSERT(irp);
3130
3131 if (!irp)
3132 {
3133 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3134 return CHANNEL_RC_NO_MEMORY;
3135 }
3136
3137 irp->CompletionId = context->priv->NextCompletionId++;
3138 irp->Callback = rdpdr_server_drive_open_file_callback;
3139 irp->CallbackData = callbackData;
3140 irp->DeviceId = deviceId;
3141 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3142 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3143
3144 if (!rdpdr_server_enqueue_irp(context, irp))
3145 {
3146 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3147 rdpdr_server_irp_free(irp);
3148 return ERROR_INTERNAL_ERROR;
3149 }
3150
3151 /* Send a request to open the file. */
3152 return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId,
3153 irp->PathName, desiredAccess | SYNCHRONIZE,
3154 FILE_SYNCHRONOUS_IO_NONALERT, createDisposition);
3155}
3156
3157/*************************************************
3158 * Drive Read File
3159 ************************************************/
3160
3166static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, wStream* s,
3167 RDPDR_IRP* irp, UINT32 deviceId,
3168 UINT32 completionId, UINT32 ioStatus)
3169{
3170 UINT32 length = 0;
3171 char* buffer = NULL;
3172 WINPR_ASSERT(context);
3173 WINPR_ASSERT(context->priv);
3174 WINPR_ASSERT(irp);
3175 WLog_Print(context->priv->log, WLOG_DEBUG,
3176 "RdpdrServerDriveReadFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3177 ", ioStatus=0x%" PRIx32 "",
3178 deviceId, completionId, ioStatus);
3179
3180 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
3181 return ERROR_INVALID_DATA;
3182
3183 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3184
3185 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length))
3186 return ERROR_INVALID_DATA;
3187
3188 if (length > 0)
3189 {
3190 buffer = Stream_Pointer(s);
3191 Stream_Seek(s, length);
3192 }
3193
3194 /* Invoke the read file completion routine. */
3195 context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, length);
3196 /* Destroy the IRP. */
3197 rdpdr_server_irp_free(irp);
3198 return CHANNEL_RC_OK;
3199}
3200
3206static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* callbackData,
3207 UINT32 deviceId, UINT32 fileId, UINT32 length,
3208 UINT32 offset)
3209{
3210 RDPDR_IRP* irp = rdpdr_server_irp_new();
3211 WINPR_ASSERT(context);
3212 WINPR_ASSERT(context->priv);
3213 WINPR_ASSERT(irp);
3214
3215 if (!irp)
3216 {
3217 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3218 return CHANNEL_RC_NO_MEMORY;
3219 }
3220
3221 irp->CompletionId = context->priv->NextCompletionId++;
3222 irp->Callback = rdpdr_server_drive_read_file_callback;
3223 irp->CallbackData = callbackData;
3224 irp->DeviceId = deviceId;
3225 irp->FileId = fileId;
3226
3227 if (!rdpdr_server_enqueue_irp(context, irp))
3228 {
3229 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3230 rdpdr_server_irp_free(irp);
3231 return ERROR_INTERNAL_ERROR;
3232 }
3233
3234 /* Send a request to open the directory. */
3235 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3236 return rdpdr_server_send_device_read_request(context, deviceId, fileId, irp->CompletionId,
3237 length, offset);
3238}
3239
3240/*************************************************
3241 * Drive Write File
3242 ************************************************/
3243
3249static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, wStream* s,
3250 RDPDR_IRP* irp, UINT32 deviceId,
3251 UINT32 completionId, UINT32 ioStatus)
3252{
3253 UINT32 length = 0;
3254 WINPR_ASSERT(context);
3255 WINPR_ASSERT(context->priv);
3256 WINPR_ASSERT(irp);
3257 WLog_Print(context->priv->log, WLOG_DEBUG,
3258 "RdpdrServerDriveWriteFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3259 ", ioStatus=0x%" PRIx32 "",
3260 deviceId, completionId, ioStatus);
3261
3262 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3263 return ERROR_INVALID_DATA;
3264
3265 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3266 Stream_Seek(s, 1); /* Padding (1 byte) */
3267
3268 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length))
3269 return ERROR_INVALID_DATA;
3270
3271 /* Invoke the write file completion routine. */
3272 context->OnDriveWriteFileComplete(context, irp->CallbackData, ioStatus, length);
3273 /* Destroy the IRP. */
3274 rdpdr_server_irp_free(irp);
3275 return CHANNEL_RC_OK;
3276}
3277
3283static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* callbackData,
3284 UINT32 deviceId, UINT32 fileId, const char* buffer,
3285 UINT32 length, UINT32 offset)
3286{
3287 RDPDR_IRP* irp = rdpdr_server_irp_new();
3288 WINPR_ASSERT(context);
3289 WINPR_ASSERT(context->priv);
3290 WINPR_ASSERT(irp);
3291
3292 if (!irp)
3293 {
3294 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3295 return CHANNEL_RC_NO_MEMORY;
3296 }
3297
3298 irp->CompletionId = context->priv->NextCompletionId++;
3299 irp->Callback = rdpdr_server_drive_write_file_callback;
3300 irp->CallbackData = callbackData;
3301 irp->DeviceId = deviceId;
3302 irp->FileId = fileId;
3303
3304 if (!rdpdr_server_enqueue_irp(context, irp))
3305 {
3306 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3307 rdpdr_server_irp_free(irp);
3308 return ERROR_INTERNAL_ERROR;
3309 }
3310
3311 /* Send a request to open the directory. */
3312 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3313 return rdpdr_server_send_device_write_request(context, deviceId, fileId, irp->CompletionId,
3314 buffer, length, offset);
3315}
3316
3317/*************************************************
3318 * Drive Close File
3319 ************************************************/
3320
3326static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, wStream* s,
3327 RDPDR_IRP* irp, UINT32 deviceId,
3328 UINT32 completionId, UINT32 ioStatus)
3329{
3330 WINPR_UNUSED(s);
3331 WINPR_ASSERT(context);
3332 WINPR_ASSERT(context->priv);
3333 WINPR_ASSERT(irp);
3334
3335 WLog_Print(context->priv->log, WLOG_DEBUG,
3336 "RdpdrServerDriveCloseFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32
3337 ", ioStatus=0x%" PRIx32 "",
3338 deviceId, completionId, ioStatus);
3339
3340 // padding 5 bytes
3341 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3342 return ERROR_INVALID_DATA;
3343
3344 Stream_Seek(s, 5);
3345
3346 /* Invoke the close file completion routine. */
3347 context->OnDriveCloseFileComplete(context, irp->CallbackData, ioStatus);
3348 /* Destroy the IRP. */
3349 rdpdr_server_irp_free(irp);
3350 return CHANNEL_RC_OK;
3351}
3352
3358static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData,
3359 UINT32 deviceId, UINT32 fileId)
3360{
3361 RDPDR_IRP* irp = rdpdr_server_irp_new();
3362 WINPR_ASSERT(context);
3363 WINPR_ASSERT(context->priv);
3364 WINPR_ASSERT(irp);
3365
3366 if (!irp)
3367 {
3368 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3369 return CHANNEL_RC_NO_MEMORY;
3370 }
3371
3372 irp->CompletionId = context->priv->NextCompletionId++;
3373 irp->Callback = rdpdr_server_drive_close_file_callback;
3374 irp->CallbackData = callbackData;
3375 irp->DeviceId = deviceId;
3376 irp->FileId = fileId;
3377
3378 if (!rdpdr_server_enqueue_irp(context, irp))
3379 {
3380 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3381 rdpdr_server_irp_free(irp);
3382 return ERROR_INTERNAL_ERROR;
3383 }
3384
3385 /* Send a request to open the directory. */
3386 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3387 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
3388}
3389
3390/*************************************************
3391 * Drive Delete File
3392 ************************************************/
3393
3399static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context, wStream* s,
3400 RDPDR_IRP* irp, UINT32 deviceId,
3401 UINT32 completionId, UINT32 ioStatus)
3402{
3403 WINPR_UNUSED(s);
3404 WINPR_ASSERT(context);
3405 WINPR_ASSERT(context->priv);
3406 WINPR_ASSERT(irp);
3407
3408 WLog_Print(context->priv->log, WLOG_DEBUG,
3409 "RdpdrServerDriveDeleteFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3410 ", ioStatus=0x%" PRIx32 "",
3411 deviceId, completionId, ioStatus);
3412 /* Invoke the delete file completion routine. */
3413 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3414 /* Destroy the IRP. */
3415 rdpdr_server_irp_free(irp);
3416 return CHANNEL_RC_OK;
3417}
3418
3424static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context, wStream* s,
3425 RDPDR_IRP* irp, UINT32 deviceId,
3426 UINT32 completionId, UINT32 ioStatus)
3427{
3428 WINPR_ASSERT(context);
3429 WINPR_ASSERT(context->priv);
3430 WINPR_ASSERT(irp);
3431 WLog_Print(context->priv->log, WLOG_DEBUG,
3432 "RdpdrServerDriveDeleteFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3433 ", ioStatus=0x%" PRIx32 "",
3434 deviceId, completionId, ioStatus);
3435
3436 if (ioStatus != STATUS_SUCCESS)
3437 {
3438 /* Invoke the close file completion routine. */
3439 context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus);
3440 /* Destroy the IRP. */
3441 rdpdr_server_irp_free(irp);
3442 return CHANNEL_RC_OK;
3443 }
3444
3445 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3446 return ERROR_INVALID_DATA;
3447
3448 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3449 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3450
3451 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3452 fileInformation2str(information));
3453 /* Setup the IRP. */
3454 irp->CompletionId = context->priv->NextCompletionId++;
3455 irp->Callback = rdpdr_server_drive_delete_file_callback2;
3456 irp->DeviceId = deviceId;
3457 irp->FileId = fileId;
3458
3459 if (!rdpdr_server_enqueue_irp(context, irp))
3460 {
3461 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3462 rdpdr_server_irp_free(irp);
3463 return ERROR_INTERNAL_ERROR;
3464 }
3465
3466 /* Send a request to close the file */
3467 return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId);
3468}
3469
3475static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData,
3476 UINT32 deviceId, const char* path)
3477{
3478 RDPDR_IRP* irp = rdpdr_server_irp_new();
3479 WINPR_ASSERT(context);
3480 WINPR_ASSERT(context->priv);
3481 WINPR_ASSERT(irp);
3482
3483 if (!irp)
3484 {
3485 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3486 return CHANNEL_RC_NO_MEMORY;
3487 }
3488
3489 irp->CompletionId = context->priv->NextCompletionId++;
3490 irp->Callback = rdpdr_server_drive_delete_file_callback1;
3491 irp->CallbackData = callbackData;
3492 irp->DeviceId = deviceId;
3493 strncpy(irp->PathName, path, sizeof(irp->PathName) - 1);
3494 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3495
3496 if (!rdpdr_server_enqueue_irp(context, irp))
3497 {
3498 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3499 rdpdr_server_irp_free(irp);
3500 return ERROR_INTERNAL_ERROR;
3501 }
3502
3503 /* Send a request to open the file. */
3504 return rdpdr_server_send_device_create_request(
3505 context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3506 FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3507}
3508
3509/*************************************************
3510 * Drive Rename File
3511 ************************************************/
3512
3518static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context, wStream* s,
3519 RDPDR_IRP* irp, UINT32 deviceId,
3520 UINT32 completionId, UINT32 ioStatus)
3521{
3522 WINPR_UNUSED(context);
3523 WINPR_UNUSED(s);
3524 WINPR_ASSERT(context);
3525 WINPR_ASSERT(context->priv);
3526 WINPR_ASSERT(irp);
3527
3528 WLog_Print(context->priv->log, WLOG_DEBUG,
3529 "RdpdrServerDriveRenameFileCallback3: deviceId=%" PRIu32 ", completionId=%" PRIu32
3530 ", ioStatus=0x%" PRIx32 "",
3531 deviceId, completionId, ioStatus);
3532 /* Destroy the IRP. */
3533 rdpdr_server_irp_free(irp);
3534 return CHANNEL_RC_OK;
3535}
3536
3542static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context, wStream* s,
3543 RDPDR_IRP* irp, UINT32 deviceId,
3544 UINT32 completionId, UINT32 ioStatus)
3545{
3546 UINT32 length = 0;
3547 WINPR_ASSERT(context);
3548 WINPR_ASSERT(context->priv);
3549 WINPR_ASSERT(irp);
3550 WLog_Print(context->priv->log, WLOG_DEBUG,
3551 "RdpdrServerDriveRenameFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32
3552 ", ioStatus=0x%" PRIx32 "",
3553 deviceId, completionId, ioStatus);
3554
3555 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3556 return ERROR_INVALID_DATA;
3557
3558 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3559 Stream_Seek(s, 1); /* Padding (1 byte) */
3560 /* Invoke the rename file completion routine. */
3561 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3562 /* Setup the IRP. */
3563 irp->CompletionId = context->priv->NextCompletionId++;
3564 irp->Callback = rdpdr_server_drive_rename_file_callback3;
3565 irp->DeviceId = deviceId;
3566
3567 if (!rdpdr_server_enqueue_irp(context, irp))
3568 {
3569 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3570 rdpdr_server_irp_free(irp);
3571 return ERROR_INTERNAL_ERROR;
3572 }
3573
3574 /* Send a request to close the file */
3575 return rdpdr_server_send_device_close_request(context, deviceId, irp->FileId,
3576 irp->CompletionId);
3577}
3578
3584static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context, wStream* s,
3585 RDPDR_IRP* irp, UINT32 deviceId,
3586 UINT32 completionId, UINT32 ioStatus)
3587{
3588 WINPR_ASSERT(context);
3589 WINPR_ASSERT(context->priv);
3590 WINPR_ASSERT(irp);
3591 WLog_Print(context->priv->log, WLOG_DEBUG,
3592 "RdpdrServerDriveRenameFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32
3593 ", ioStatus=0x%" PRIx32 "",
3594 deviceId, completionId, ioStatus);
3595
3596 if (ioStatus != STATUS_SUCCESS)
3597 {
3598 /* Invoke the rename file completion routine. */
3599 context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus);
3600 /* Destroy the IRP. */
3601 rdpdr_server_irp_free(irp);
3602 return CHANNEL_RC_OK;
3603 }
3604
3605 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5))
3606 return ERROR_INVALID_DATA;
3607
3608 const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */
3609 const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */
3610 WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId,
3611 fileInformation2str(information));
3612
3613 /* Setup the IRP. */
3614 irp->CompletionId = context->priv->NextCompletionId++;
3615 irp->Callback = rdpdr_server_drive_rename_file_callback2;
3616 irp->DeviceId = deviceId;
3617 irp->FileId = fileId;
3618
3619 if (!rdpdr_server_enqueue_irp(context, irp))
3620 {
3621 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3622 rdpdr_server_irp_free(irp);
3623 return ERROR_INTERNAL_ERROR;
3624 }
3625
3626 /* Send a request to rename the file */
3627 return rdpdr_server_send_device_file_rename_request(context, deviceId, fileId,
3628 irp->CompletionId, irp->ExtraBuffer);
3629}
3630
3636static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* callbackData,
3637 UINT32 deviceId, const char* oldPath,
3638 const char* newPath)
3639{
3640 WINPR_ASSERT(context);
3641 WINPR_ASSERT(context->priv);
3642 RDPDR_IRP* irp = rdpdr_server_irp_new();
3643
3644 if (!irp)
3645 {
3646 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!");
3647 return CHANNEL_RC_NO_MEMORY;
3648 }
3649
3650 irp->CompletionId = context->priv->NextCompletionId++;
3651 irp->Callback = rdpdr_server_drive_rename_file_callback1;
3652 irp->CallbackData = callbackData;
3653 irp->DeviceId = deviceId;
3654 strncpy(irp->PathName, oldPath, sizeof(irp->PathName) - 1);
3655 strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer) - 1);
3656 rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName));
3657 rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer));
3658
3659 if (!rdpdr_server_enqueue_irp(context, irp))
3660 {
3661 WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!");
3662 rdpdr_server_irp_free(irp);
3663 return ERROR_INTERNAL_ERROR;
3664 }
3665
3666 /* Send a request to open the file. */
3667 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp
3668 return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId,
3669 irp->PathName, FILE_READ_DATA | SYNCHRONIZE,
3670 FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN);
3671}
3672
3673static void rdpdr_server_private_free(RdpdrServerPrivate* ctx)
3674{
3675 if (!ctx)
3676 return;
3677 ListDictionary_Free(ctx->IrpList);
3678 HashTable_Free(ctx->devicelist);
3679 free(ctx->ClientComputerName);
3680 free(ctx);
3681}
3682
3683#define TAG CHANNELS_TAG("rdpdr.server")
3684static RdpdrServerPrivate* rdpdr_server_private_new(void)
3685{
3686 RdpdrServerPrivate* priv = (RdpdrServerPrivate*)calloc(1, sizeof(RdpdrServerPrivate));
3687
3688 if (!priv)
3689 goto fail;
3690
3691 priv->log = WLog_Get(TAG);
3692 priv->VersionMajor = RDPDR_VERSION_MAJOR;
3693 priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
3694 priv->ClientId = g_ClientId++;
3695 priv->UserLoggedOnPdu = TRUE;
3696 priv->NextCompletionId = 1;
3697 priv->IrpList = ListDictionary_New(TRUE);
3698
3699 if (!priv->IrpList)
3700 goto fail;
3701
3702 priv->devicelist = HashTable_New(FALSE);
3703 if (!priv->devicelist)
3704 goto fail;
3705
3706 HashTable_SetHashFunction(priv->devicelist, rdpdr_deviceid_hash);
3707
3708 {
3709 wObject* obj = HashTable_ValueObject(priv->devicelist);
3710 WINPR_ASSERT(obj);
3711 obj->fnObjectFree = rdpdr_device_free_h;
3712 obj->fnObjectNew = rdpdr_device_clone;
3713 }
3714
3715 {
3716 wObject* obj = HashTable_KeyObject(priv->devicelist);
3717 obj->fnObjectEquals = rdpdr_device_equal;
3718 obj->fnObjectFree = rdpdr_device_key_free;
3719 obj->fnObjectNew = rdpdr_device_key_clone;
3720 }
3721
3722 return priv;
3723fail:
3724 rdpdr_server_private_free(priv);
3725 return NULL;
3726}
3727
3728RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
3729{
3730 RdpdrServerContext* context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext));
3731
3732 if (!context)
3733 goto fail;
3734
3735 context->vcm = vcm;
3736 context->Start = rdpdr_server_start;
3737 context->Stop = rdpdr_server_stop;
3738 context->DriveCreateDirectory = rdpdr_server_drive_create_directory;
3739 context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory;
3740 context->DriveQueryDirectory = rdpdr_server_drive_query_directory;
3741 context->DriveOpenFile = rdpdr_server_drive_open_file;
3742 context->DriveReadFile = rdpdr_server_drive_read_file;
3743 context->DriveWriteFile = rdpdr_server_drive_write_file;
3744 context->DriveCloseFile = rdpdr_server_drive_close_file;
3745 context->DriveDeleteFile = rdpdr_server_drive_delete_file;
3746 context->DriveRenameFile = rdpdr_server_drive_rename_file;
3747 context->priv = rdpdr_server_private_new();
3748 if (!context->priv)
3749 goto fail;
3750
3751 /* By default announce everything, the server application can deactivate that later on */
3752 context->supported = UINT16_MAX;
3753
3754 return context;
3755fail:
3756 WINPR_PRAGMA_DIAG_PUSH
3757 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
3758 rdpdr_server_context_free(context);
3759 WINPR_PRAGMA_DIAG_POP
3760 return NULL;
3761}
3762
3763void rdpdr_server_context_free(RdpdrServerContext* context)
3764{
3765 if (!context)
3766 return;
3767
3768 rdpdr_server_private_free(context->priv);
3769 free(context);
3770}
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:58
OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:59
OBJECT_NEW_FN fnObjectNew
Definition collections.h:53