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