FreeRDP
Loading...
Searching...
No Matches
rdpdr_utils.c
1
21#include <winpr/wlog.h>
22#include <winpr/print.h>
23#include <winpr/smartcard.h>
24
25#include <freerdp/utils/rdpdr_utils.h>
26#include <freerdp/channels/scard.h>
27#include <freerdp/channels/rdpdr.h>
28
29#include <freerdp/log.h>
30
31LONG scard_log_status_error(const char* tag, const char* what, LONG status)
32{
33 wLog* log = WLog_Get(tag);
34 return scard_log_status_error_wlog(log, what, status);
35}
36
37LONG scard_log_status_error_wlog(wLog* log, const char* what, LONG status)
38{
39 if (status != SCARD_S_SUCCESS)
40 {
41 DWORD level = WLOG_ERROR;
42 switch (status)
43 {
44 case SCARD_E_TIMEOUT:
45 level = WLOG_DEBUG;
46 break;
47 case SCARD_E_NO_READERS_AVAILABLE:
48 level = WLOG_INFO;
49 break;
50 default:
51 break;
52 }
53 WLog_Print(log, level, "%s failed with error %s [%" PRId32 "]", what,
54 SCardGetErrorString(status), status);
55 }
56 return status;
57}
58
59const char* scard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName)
60{
61 switch (ioControlCode)
62 {
63 case SCARD_IOCTL_ESTABLISHCONTEXT:
64 return funcName ? "SCardEstablishContext" : "SCARD_IOCTL_ESTABLISHCONTEXT";
65
66 case SCARD_IOCTL_RELEASECONTEXT:
67 return funcName ? "SCardReleaseContext" : "SCARD_IOCTL_RELEASECONTEXT";
68
69 case SCARD_IOCTL_ISVALIDCONTEXT:
70 return funcName ? "SCardIsValidContext" : "SCARD_IOCTL_ISVALIDCONTEXT";
71
72 case SCARD_IOCTL_LISTREADERGROUPSA:
73 return funcName ? "SCardListReaderGroupsA" : "SCARD_IOCTL_LISTREADERGROUPSA";
74
75 case SCARD_IOCTL_LISTREADERGROUPSW:
76 return funcName ? "SCardListReaderGroupsW" : "SCARD_IOCTL_LISTREADERGROUPSW";
77
78 case SCARD_IOCTL_LISTREADERSA:
79 return funcName ? "SCardListReadersA" : "SCARD_IOCTL_LISTREADERSA";
80
81 case SCARD_IOCTL_LISTREADERSW:
82 return funcName ? "SCardListReadersW" : "SCARD_IOCTL_LISTREADERSW";
83
84 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
85 return funcName ? "SCardIntroduceReaderGroupA" : "SCARD_IOCTL_INTRODUCEREADERGROUPA";
86
87 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
88 return funcName ? "SCardIntroduceReaderGroupW" : "SCARD_IOCTL_INTRODUCEREADERGROUPW";
89
90 case SCARD_IOCTL_FORGETREADERGROUPA:
91 return funcName ? "SCardForgetReaderGroupA" : "SCARD_IOCTL_FORGETREADERGROUPA";
92
93 case SCARD_IOCTL_FORGETREADERGROUPW:
94 return funcName ? "SCardForgetReaderGroupW" : "SCARD_IOCTL_FORGETREADERGROUPW";
95
96 case SCARD_IOCTL_INTRODUCEREADERA:
97 return funcName ? "SCardIntroduceReaderA" : "SCARD_IOCTL_INTRODUCEREADERA";
98
99 case SCARD_IOCTL_INTRODUCEREADERW:
100 return funcName ? "SCardIntroduceReaderW" : "SCARD_IOCTL_INTRODUCEREADERW";
101
102 case SCARD_IOCTL_FORGETREADERA:
103 return funcName ? "SCardForgetReaderA" : "SCARD_IOCTL_FORGETREADERA";
104
105 case SCARD_IOCTL_FORGETREADERW:
106 return funcName ? "SCardForgetReaderW" : "SCARD_IOCTL_FORGETREADERW";
107
108 case SCARD_IOCTL_ADDREADERTOGROUPA:
109 return funcName ? "SCardAddReaderToGroupA" : "SCARD_IOCTL_ADDREADERTOGROUPA";
110
111 case SCARD_IOCTL_ADDREADERTOGROUPW:
112 return funcName ? "SCardAddReaderToGroupW" : "SCARD_IOCTL_ADDREADERTOGROUPW";
113
114 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
115 return funcName ? "SCardRemoveReaderFromGroupA" : "SCARD_IOCTL_REMOVEREADERFROMGROUPA";
116
117 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
118 return funcName ? "SCardRemoveReaderFromGroupW" : "SCARD_IOCTL_REMOVEREADERFROMGROUPW";
119
120 case SCARD_IOCTL_LOCATECARDSA:
121 return funcName ? "SCardLocateCardsA" : "SCARD_IOCTL_LOCATECARDSA";
122
123 case SCARD_IOCTL_LOCATECARDSW:
124 return funcName ? "SCardLocateCardsW" : "SCARD_IOCTL_LOCATECARDSW";
125
126 case SCARD_IOCTL_GETSTATUSCHANGEA:
127 return funcName ? "SCardGetStatusChangeA" : "SCARD_IOCTL_GETSTATUSCHANGEA";
128
129 case SCARD_IOCTL_GETSTATUSCHANGEW:
130 return funcName ? "SCardGetStatusChangeW" : "SCARD_IOCTL_GETSTATUSCHANGEW";
131
132 case SCARD_IOCTL_CANCEL:
133 return funcName ? "SCardCancel" : "SCARD_IOCTL_CANCEL";
134
135 case SCARD_IOCTL_CONNECTA:
136 return funcName ? "SCardConnectA" : "SCARD_IOCTL_CONNECTA";
137
138 case SCARD_IOCTL_CONNECTW:
139 return funcName ? "SCardConnectW" : "SCARD_IOCTL_CONNECTW";
140
141 case SCARD_IOCTL_RECONNECT:
142 return funcName ? "SCardReconnect" : "SCARD_IOCTL_RECONNECT";
143
144 case SCARD_IOCTL_DISCONNECT:
145 return funcName ? "SCardDisconnect" : "SCARD_IOCTL_DISCONNECT";
146
147 case SCARD_IOCTL_BEGINTRANSACTION:
148 return funcName ? "SCardBeginTransaction" : "SCARD_IOCTL_BEGINTRANSACTION";
149
150 case SCARD_IOCTL_ENDTRANSACTION:
151 return funcName ? "SCardEndTransaction" : "SCARD_IOCTL_ENDTRANSACTION";
152
153 case SCARD_IOCTL_STATE:
154 return funcName ? "SCardState" : "SCARD_IOCTL_STATE";
155
156 case SCARD_IOCTL_STATUSA:
157 return funcName ? "SCardStatusA" : "SCARD_IOCTL_STATUSA";
158
159 case SCARD_IOCTL_STATUSW:
160 return funcName ? "SCardStatusW" : "SCARD_IOCTL_STATUSW";
161
162 case SCARD_IOCTL_TRANSMIT:
163 return funcName ? "SCardTransmit" : "SCARD_IOCTL_TRANSMIT";
164
165 case SCARD_IOCTL_CONTROL:
166 return funcName ? "SCardControl" : "SCARD_IOCTL_CONTROL";
167
168 case SCARD_IOCTL_GETATTRIB:
169 return funcName ? "SCardGetAttrib" : "SCARD_IOCTL_GETATTRIB";
170
171 case SCARD_IOCTL_SETATTRIB:
172 return funcName ? "SCardSetAttrib" : "SCARD_IOCTL_SETATTRIB";
173
174 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
175 return funcName ? "SCardAccessStartedEvent" : "SCARD_IOCTL_ACCESSSTARTEDEVENT";
176
177 case SCARD_IOCTL_LOCATECARDSBYATRA:
178 return funcName ? "SCardLocateCardsByATRA" : "SCARD_IOCTL_LOCATECARDSBYATRA";
179
180 case SCARD_IOCTL_LOCATECARDSBYATRW:
181 return funcName ? "SCardLocateCardsByATRB" : "SCARD_IOCTL_LOCATECARDSBYATRW";
182
183 case SCARD_IOCTL_READCACHEA:
184 return funcName ? "SCardReadCacheA" : "SCARD_IOCTL_READCACHEA";
185
186 case SCARD_IOCTL_READCACHEW:
187 return funcName ? "SCardReadCacheW" : "SCARD_IOCTL_READCACHEW";
188
189 case SCARD_IOCTL_WRITECACHEA:
190 return funcName ? "SCardWriteCacheA" : "SCARD_IOCTL_WRITECACHEA";
191
192 case SCARD_IOCTL_WRITECACHEW:
193 return funcName ? "SCardWriteCacheW" : "SCARD_IOCTL_WRITECACHEW";
194
195 case SCARD_IOCTL_GETTRANSMITCOUNT:
196 return funcName ? "SCardGetTransmitCount" : "SCARD_IOCTL_GETTRANSMITCOUNT";
197
198 case SCARD_IOCTL_RELEASETARTEDEVENT:
199 return funcName ? "SCardReleaseStartedEvent" : "SCARD_IOCTL_RELEASETARTEDEVENT";
200
201 case SCARD_IOCTL_GETREADERICON:
202 return funcName ? "SCardGetReaderIcon" : "SCARD_IOCTL_GETREADERICON";
203
204 case SCARD_IOCTL_GETDEVICETYPEID:
205 return funcName ? "SCardGetDeviceTypeId" : "SCARD_IOCTL_GETDEVICETYPEID";
206
207 default:
208 return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN";
209 }
210}
211
212const char* rdpdr_component_string(UINT16 component)
213{
214 switch (component)
215 {
216 case RDPDR_CTYP_PRN:
217 return "RDPDR_CTYP_PRN";
218 case RDPDR_CTYP_CORE:
219 return "RDPDR_CTYP_CORE";
220 default:
221 return "UNKNOWN";
222 }
223}
224
225const char* rdpdr_packetid_string(UINT16 packetid)
226{
227 switch (packetid)
228 {
229 case PAKID_CORE_SERVER_ANNOUNCE:
230 return "PAKID_CORE_SERVER_ANNOUNCE";
231 case PAKID_CORE_CLIENTID_CONFIRM:
232 return "PAKID_CORE_CLIENTID_CONFIRM";
233 case PAKID_CORE_CLIENT_NAME:
234 return "PAKID_CORE_CLIENT_NAME";
235 case PAKID_CORE_DEVICELIST_ANNOUNCE:
236 return "PAKID_CORE_DEVICELIST_ANNOUNCE";
237 case PAKID_CORE_DEVICE_REPLY:
238 return "PAKID_CORE_DEVICE_REPLY";
239 case PAKID_CORE_DEVICE_IOREQUEST:
240 return "PAKID_CORE_DEVICE_IOREQUEST";
241 case PAKID_CORE_DEVICE_IOCOMPLETION:
242 return "PAKID_CORE_DEVICE_IOCOMPLETION";
243 case PAKID_CORE_SERVER_CAPABILITY:
244 return "PAKID_CORE_SERVER_CAPABILITY";
245 case PAKID_CORE_CLIENT_CAPABILITY:
246 return "PAKID_CORE_CLIENT_CAPABILITY";
247 case PAKID_CORE_DEVICELIST_REMOVE:
248 return "PAKID_CORE_DEVICELIST_REMOVE";
249 case PAKID_CORE_USER_LOGGEDON:
250 return "PAKID_CORE_USER_LOGGEDON";
251 case PAKID_PRN_CACHE_DATA:
252 return "PAKID_PRN_CACHE_DATA";
253 case PAKID_PRN_USING_XPS:
254 return "PAKID_PRN_USING_XPS";
255 default:
256 return "UNKNOWN";
257 }
258}
259
260BOOL rdpdr_write_iocompletion_header(wStream* out, UINT32 DeviceId, UINT32 CompletionId,
261 NTSTATUS ioStatus)
262{
263 WINPR_ASSERT(out);
264 Stream_ResetPosition(out);
265 if (!Stream_EnsureRemainingCapacity(out, 16))
266 return FALSE;
267
268 Stream_Write_UINT16(out, RDPDR_CTYP_CORE); /* Component (2 bytes) */
269 Stream_Write_UINT16(out, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
270 Stream_Write_UINT32(out, DeviceId); /* DeviceId (4 bytes) */
271 Stream_Write_UINT32(out, CompletionId); /* CompletionId (4 bytes) */
272 Stream_Write_INT32(out, ioStatus); /* IoStatus (4 bytes) */
273
274 return TRUE;
275}
276
277static void rdpdr_dump_packet(wLog* log, DWORD lvl, wStream* s, const char* custom, BOOL send)
278{
279 if (!WLog_IsLevelActive(log, lvl))
280 return;
281
282 const size_t gpos = Stream_GetPosition(s);
283 const size_t pos = send ? Stream_GetPosition(s) : Stream_Length(s);
284
285 UINT16 component = 0;
286 UINT16 packetid = 0;
287
288 Stream_ResetPosition(s);
289
290 if (pos >= 2)
291 Stream_Read_UINT16(s, component);
292 if (pos >= 4)
293 Stream_Read_UINT16(s, packetid);
294
295 switch (packetid)
296 {
297 case PAKID_CORE_SERVER_ANNOUNCE:
298 case PAKID_CORE_CLIENTID_CONFIRM:
299 {
300 UINT16 versionMajor = 0;
301 UINT16 versionMinor = 0;
302 UINT32 clientID = 0;
303
304 if (pos >= 6)
305 Stream_Read_UINT16(s, versionMajor);
306 if (pos >= 8)
307 Stream_Read_UINT16(s, versionMinor);
308 if (pos >= 12)
309 Stream_Read_UINT32(s, clientID);
310 WLog_Print(log, lvl,
311 "%s [%s | %s] [version:%" PRIu16 ".%" PRIu16 "][id:0x%08" PRIx32
312 "] -> %" PRIuz,
313 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
314 versionMajor, versionMinor, clientID, pos);
315 }
316 break;
317 case PAKID_CORE_CLIENT_NAME:
318 {
319 char name[256] = WINPR_C_ARRAY_INIT;
320 UINT32 unicodeFlag = 0;
321 UINT32 codePage = 0;
322 UINT32 computerNameLen = 0;
323 if (pos >= 8)
324 Stream_Read_UINT32(s, unicodeFlag);
325 if (pos >= 12)
326 Stream_Read_UINT32(s, codePage);
327 if (pos >= 16)
328 Stream_Read_UINT32(s, computerNameLen);
329 if (pos >= 16 + computerNameLen)
330 {
331 if (unicodeFlag == 0)
332 Stream_Read(s, name, MIN(sizeof(name), computerNameLen));
333 else
334 (void)ConvertWCharNToUtf8(Stream_ConstPointer(s),
335 computerNameLen / sizeof(WCHAR), name, sizeof(name));
336 }
337 WLog_Print(log, lvl,
338 "%s [%s | %s] [ucs:%" PRIu32 "|cp:%" PRIu32 "][len:0x%08" PRIx32
339 "] '%s' -> %" PRIuz,
340 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
341 unicodeFlag, codePage, computerNameLen, name, pos);
342 }
343 break;
344
345 case PAKID_CORE_DEVICE_IOREQUEST:
346 {
347 UINT32 CompletionId = 0;
348 UINT32 deviceID = 0;
349 UINT32 FileId = 0;
350 UINT32 MajorFunction = 0;
351 UINT32 MinorFunction = 0;
352
353 if (pos >= 8)
354 Stream_Read_UINT32(s, deviceID);
355 if (pos >= 12)
356 Stream_Read_UINT32(s, FileId);
357 if (pos >= 16)
358 Stream_Read_UINT32(s, CompletionId);
359 if (pos >= 20)
360 Stream_Read_UINT32(s, MajorFunction);
361 if (pos >= 24)
362 Stream_Read_UINT32(s, MinorFunction);
363 WLog_Print(log, lvl,
364 "%s [%s | %s] [0x%08" PRIx32 "] FileId=0x%08" PRIx32
365 ", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
366 ", MinorFunction=0x%08" PRIx32 " -> %" PRIuz,
367 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
368 deviceID, FileId, CompletionId, MajorFunction, MinorFunction, pos);
369 }
370 break;
371 case PAKID_CORE_DEVICE_IOCOMPLETION:
372 {
373 UINT32 completionID = 0;
374 UINT32 ioStatus = 0;
375 UINT32 deviceID = 0;
376 if (pos >= 8)
377 Stream_Read_UINT32(s, deviceID);
378 if (pos >= 12)
379 Stream_Read_UINT32(s, completionID);
380 if (pos >= 16)
381 Stream_Read_UINT32(s, ioStatus);
382
383 WLog_Print(log, lvl,
384 "%s [%s | %s] [0x%08" PRIx32 "] completionID=0x%08" PRIx32
385 ", ioStatus=0x%08" PRIx32 " -> %" PRIuz,
386 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
387 deviceID, completionID, ioStatus, pos);
388 }
389 break;
390 case PAKID_CORE_DEVICE_REPLY:
391 {
392 UINT32 deviceID = 0;
393 UINT32 status = 0;
394
395 if (pos >= 8)
396 Stream_Read_UINT32(s, deviceID);
397 if (pos >= 12)
398 Stream_Read_UINT32(s, status);
399 WLog_Print(log, lvl,
400 "%s [%s | %s] [id:0x%08" PRIx32 ",status=0x%08" PRIx32 "] -> %" PRIuz,
401 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
402 deviceID, status, pos);
403 }
404 break;
405 case PAKID_CORE_CLIENT_CAPABILITY:
406 case PAKID_CORE_SERVER_CAPABILITY:
407 {
408 UINT16 numCapabilities = 0;
409 if (pos >= 6)
410 Stream_Read_UINT16(s, numCapabilities);
411 if (pos >= 8)
412 Stream_Seek_UINT16(s); /* padding */
413 WLog_Print(log, lvl, "%s [%s | %s] [caps:%" PRIu16 "] -> %" PRIuz, custom,
414 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
415 numCapabilities, pos);
416 for (UINT16 x = 0; x < numCapabilities; x++)
417 {
418 RDPDR_CAPABILITY_HEADER header = WINPR_C_ARRAY_INIT;
419 const UINT error = rdpdr_read_capset_header(log, s, &header);
420 if (error == CHANNEL_RC_OK)
421 Stream_Seek(s, header.CapabilityLength);
422 }
423 }
424 break;
425 case PAKID_CORE_DEVICELIST_ANNOUNCE:
426 {
427 size_t offset = 8;
428 UINT32 count = 0;
429
430 if (pos >= offset)
431 Stream_Read_UINT32(s, count);
432
433 WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
434 rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
435 pos);
436
437 for (UINT32 x = 0; x < count; x++)
438 {
439 RdpdrDevice device = WINPR_C_ARRAY_INIT;
440
441 offset += 20;
442 if (pos >= offset)
443 {
444 Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */
445 Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */
446 Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */
447 Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
448 device.DeviceData = Stream_Pointer(s);
449 }
450 offset += device.DeviceDataLength;
451
452 WLog_Print(log, lvl,
453 "%s [announce][%" PRIu32 "] %s [0x%08" PRIx32
454 "] '%s' [DeviceDataLength=%" PRIu32 "]",
455 custom, x, freerdp_rdpdr_dtyp_string(device.DeviceType), device.DeviceId,
456 device.PreferredDosName, device.DeviceDataLength);
457 }
458 }
459 break;
460 case PAKID_CORE_DEVICELIST_REMOVE:
461 {
462 size_t offset = 8;
463 UINT32 count = 0;
464
465 if (pos >= offset)
466 Stream_Read_UINT32(s, count);
467
468 WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
469 rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
470 pos);
471
472 for (UINT32 x = 0; x < count; x++)
473 {
474 UINT32 id = 0;
475
476 offset += 4;
477 if (pos >= offset)
478 Stream_Read_UINT32(s, id);
479
480 WLog_Print(log, lvl, "%s [remove][%" PRIu32 "] id=%" PRIu32, custom, x, id);
481 }
482 }
483 break;
484 case PAKID_CORE_USER_LOGGEDON:
485 WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
486 rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
487 break;
488 default:
489 {
490 WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
491 rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
492 }
493 break;
494 }
495
496 // winpr_HexLogDump(log, lvl, Stream_Buffer(s), pos);
497 if (!Stream_SetPosition(s, gpos))
498 WLog_Print(log, WLOG_ERROR, "Stream_SetPosition(%" PRIuz ") failed", gpos);
499}
500
501void rdpdr_dump_received_packet(wLog* log, DWORD lvl, wStream* out, const char* custom)
502{
503 rdpdr_dump_packet(log, lvl, out, custom, FALSE);
504}
505
506void rdpdr_dump_send_packet(wLog* log, DWORD lvl, wStream* out, const char* custom)
507{
508 rdpdr_dump_packet(log, lvl, out, custom, TRUE);
509}
510
511const char* rdpdr_irp_string(UINT32 major)
512{
513 switch (major)
514 {
515 case IRP_MJ_CREATE:
516 return "IRP_MJ_CREATE";
517 case IRP_MJ_CLOSE:
518 return "IRP_MJ_CLOSE";
519 case IRP_MJ_READ:
520 return "IRP_MJ_READ";
521 case IRP_MJ_WRITE:
522 return "IRP_MJ_WRITE";
523 case IRP_MJ_DEVICE_CONTROL:
524 return "IRP_MJ_DEVICE_CONTROL";
525 case IRP_MJ_QUERY_VOLUME_INFORMATION:
526 return "IRP_MJ_QUERY_VOLUME_INFORMATION";
527 case IRP_MJ_SET_VOLUME_INFORMATION:
528 return "IRP_MJ_SET_VOLUME_INFORMATION";
529 case IRP_MJ_QUERY_INFORMATION:
530 return "IRP_MJ_QUERY_INFORMATION";
531 case IRP_MJ_SET_INFORMATION:
532 return "IRP_MJ_SET_INFORMATION";
533 case IRP_MJ_DIRECTORY_CONTROL:
534 return "IRP_MJ_DIRECTORY_CONTROL";
535 case IRP_MJ_LOCK_CONTROL:
536 return "IRP_MJ_LOCK_CONTROL";
537 default:
538 return "IRP_UNKNOWN";
539 }
540}
541
542const char* rdpdr_cap_type_string(UINT16 capability)
543{
544 switch (capability)
545 {
546 case CAP_GENERAL_TYPE:
547 return "CAP_GENERAL_TYPE";
548 case CAP_PRINTER_TYPE:
549 return "CAP_PRINTER_TYPE";
550 case CAP_PORT_TYPE:
551 return "CAP_PORT_TYPE";
552 case CAP_DRIVE_TYPE:
553 return "CAP_DRIVE_TYPE";
554 case CAP_SMARTCARD_TYPE:
555 return "CAP_SMARTCARD_TYPE";
556 default:
557 return "CAP_UNKNOWN";
558 }
559}
560
561UINT rdpdr_read_capset_header(wLog* log, wStream* s, RDPDR_CAPABILITY_HEADER* header)
562{
563 WINPR_ASSERT(header);
564 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
565 return ERROR_INVALID_DATA;
566
567 Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
568 Stream_Read_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
569 Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */
570
571 WLog_Print(log, WLOG_TRACE,
572 "capability %s [0x%04" PRIx16 "] got version %" PRIu32 ", length %" PRIu16,
573 rdpdr_cap_type_string(header->CapabilityType), header->CapabilityType,
574 header->Version, header->CapabilityLength);
575 if (header->CapabilityLength < 8)
576 {
577 WLog_Print(log, WLOG_ERROR, "capability %s got short length %" PRIu32,
578 rdpdr_cap_type_string(header->CapabilityType), header->CapabilityLength);
579 return ERROR_INVALID_DATA;
580 }
581 header->CapabilityLength -= 8;
582 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, header->CapabilityLength))
583 return ERROR_INVALID_DATA;
584 return CHANNEL_RC_OK;
585}
586
587UINT rdpdr_write_capset_header(wLog* log, wStream* s, const RDPDR_CAPABILITY_HEADER* header)
588{
589 WINPR_ASSERT(header);
590 WINPR_ASSERT(header->CapabilityLength >= 8);
591
592 if (!Stream_EnsureRemainingCapacity(s, header->CapabilityLength))
593 {
594 WLog_Print(log, WLOG_ERROR, "not enough data in stream!");
595 return ERROR_INVALID_DATA;
596 }
597
598 WLog_Print(log, WLOG_TRACE, "writing capability %s version %" PRIu32 ", length %" PRIu16,
599 rdpdr_cap_type_string(header->CapabilityType), header->Version,
600 header->CapabilityLength);
601 Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
602 Stream_Write_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
603 Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */
604 return CHANNEL_RC_OK;
605}
606
607const char* rdpdr_irp_val2str(UINT32 ioCode1)
608{
609 switch (ioCode1)
610 {
611 case RDPDR_IRP_MJ_CREATE:
612 return "MJ_CREATE";
613 case RDPDR_IRP_MJ_CLEANUP:
614 return "MJ_CLEANUP";
615 case RDPDR_IRP_MJ_CLOSE:
616 return "MJ_CLOSE";
617 case RDPDR_IRP_MJ_READ:
618 return "MJ_READ";
619 case RDPDR_IRP_MJ_WRITE:
620 return "MJ_WRITE";
621 case RDPDR_IRP_MJ_FLUSH_BUFFERS:
622 return "MJ_FLUSH_BUFFERS";
623 case RDPDR_IRP_MJ_SHUTDOWN:
624 return "MJ_SHUTDOWN";
625 case RDPDR_IRP_MJ_DEVICE_CONTROL:
626 return "MJ_DEVICE_CONTROL";
627 case RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION:
628 return "MJ_QUERY_VOLUME_INFORMATION";
629 case RDPDR_IRP_MJ_SET_VOLUME_INFORMATION:
630 return "MJ_SET_VOLUME_INFORMATION";
631 case RDPDR_IRP_MJ_QUERY_INFORMATION:
632 return "MJ_QUERY_INFORMATION";
633 case RDPDR_IRP_MJ_SET_INFORMATION:
634 return "MJ_SET_INFORMATION";
635 case RDPDR_IRP_MJ_DIRECTORY_CONTROL:
636 return "MJ_DIRECTORY_CONTROL";
637 case RDPDR_IRP_MJ_LOCK_CONTROL:
638 return "MJ_LOCK_CONTROL";
639 case RDPDR_IRP_MJ_QUERY_SECURITY:
640 return "MJ_QUERY_SECURITY";
641 case RDPDR_IRP_MJ_SET_SECURITY:
642 return "MJ_SET_SECURITY";
643 default:
644 return "IRP_MJ_UNKNOWN";
645 }
646}
647
648const char* rdpdr_irp_mask2str(UINT32 ioCode1Mask, char* buffer, size_t len)
649{
650 if (len < 1)
651 return nullptr;
652
653 if (!winpr_str_append("{", buffer, len, nullptr))
654 return nullptr;
655
656 for (size_t x = 0; x < 32; x++)
657 {
658 const UINT32 mask = (1u << x);
659 if (ioCode1Mask & mask)
660 {
661 if (!winpr_str_append(rdpdr_irp_val2str(mask), &buffer[1], len - 1, "|"))
662 return nullptr;
663 }
664 }
665
666 char number[16] = WINPR_C_ARRAY_INIT;
667 (void)_snprintf(number, sizeof(number), "}[0x%08" PRIx32 "]", ioCode1Mask);
668 if (!winpr_str_append(number, buffer, len, nullptr))
669 return nullptr;
670 return buffer;
671}
672
673const char* rdpdr_device_type_string(UINT32 type)
674{
675 switch (type)
676 {
677 case RDPDR_DTYP_SERIAL:
678 return "serial";
679 case RDPDR_DTYP_PRINT:
680 return "printer";
681 case RDPDR_DTYP_FILESYSTEM:
682 return "drive";
683 case RDPDR_DTYP_SMARTCARD:
684 return "smartcard";
685 case RDPDR_DTYP_PARALLEL:
686 return "parallel";
687 default:
688 return "UNKNOWN";
689 }
690}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_rdpdr_dtyp_string(UINT32 type)
Returns a string representation of RDPDR_DTYP_*.