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