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