FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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_SetPosition(out, 0);
265 if (!Stream_EnsureRemainingCapacity(out, 16))
266 return FALSE;
267 Stream_Write_UINT16(out, RDPDR_CTYP_CORE); /* Component (2 bytes) */
268 Stream_Write_UINT16(out, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
269 Stream_Write_UINT32(out, DeviceId); /* DeviceId (4 bytes) */
270 Stream_Write_UINT32(out, CompletionId); /* CompletionId (4 bytes) */
271 Stream_Write_INT32(out, ioStatus); /* IoStatus (4 bytes) */
272
273 return TRUE;
274}
275
276static void rdpdr_dump_packet(wLog* log, DWORD lvl, wStream* s, const char* custom, BOOL send)
277{
278 if (!WLog_IsLevelActive(log, lvl))
279 return;
280
281 const size_t gpos = Stream_GetPosition(s);
282 const size_t pos = send ? Stream_GetPosition(s) : Stream_Length(s);
283
284 UINT16 component = 0;
285 UINT16 packetid = 0;
286
287 Stream_SetPosition(s, 0);
288
289 if (pos >= 2)
290 Stream_Read_UINT16(s, component);
291 if (pos >= 4)
292 Stream_Read_UINT16(s, packetid);
293
294 switch (packetid)
295 {
296 case PAKID_CORE_SERVER_ANNOUNCE:
297 case PAKID_CORE_CLIENTID_CONFIRM:
298 {
299 UINT16 versionMajor = 0;
300 UINT16 versionMinor = 0;
301 UINT32 clientID = 0;
302
303 if (pos >= 6)
304 Stream_Read_UINT16(s, versionMajor);
305 if (pos >= 8)
306 Stream_Read_UINT16(s, versionMinor);
307 if (pos >= 12)
308 Stream_Read_UINT32(s, clientID);
309 WLog_Print(log, lvl,
310 "%s [%s | %s] [version:%" PRIu16 ".%" PRIu16 "][id:0x%08" PRIx32
311 "] -> %" PRIuz,
312 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
313 versionMajor, versionMinor, clientID, pos);
314 }
315 break;
316 case PAKID_CORE_CLIENT_NAME:
317 {
318 char name[256] = { 0 };
319 UINT32 unicodeFlag = 0;
320 UINT32 codePage = 0;
321 UINT32 computerNameLen = 0;
322 if (pos >= 8)
323 Stream_Read_UINT32(s, unicodeFlag);
324 if (pos >= 12)
325 Stream_Read_UINT32(s, codePage);
326 if (pos >= 16)
327 Stream_Read_UINT32(s, computerNameLen);
328 if (pos >= 16 + computerNameLen)
329 {
330 if (unicodeFlag == 0)
331 Stream_Read(s, name, MIN(sizeof(name), computerNameLen));
332 else
333 (void)ConvertWCharNToUtf8(Stream_ConstPointer(s),
334 computerNameLen / sizeof(WCHAR), name, sizeof(name));
335 }
336 WLog_Print(log, lvl,
337 "%s [%s | %s] [ucs:%" PRIu32 "|cp:%" PRIu32 "][len:0x%08" PRIx32
338 "] '%s' -> %" PRIuz,
339 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
340 unicodeFlag, codePage, computerNameLen, name, pos);
341 }
342 break;
343
344 case PAKID_CORE_DEVICE_IOREQUEST:
345 {
346 UINT32 CompletionId = 0;
347 UINT32 deviceID = 0;
348 UINT32 FileId = 0;
349 UINT32 MajorFunction = 0;
350 UINT32 MinorFunction = 0;
351
352 if (pos >= 8)
353 Stream_Read_UINT32(s, deviceID);
354 if (pos >= 12)
355 Stream_Read_UINT32(s, FileId);
356 if (pos >= 16)
357 Stream_Read_UINT32(s, CompletionId);
358 if (pos >= 20)
359 Stream_Read_UINT32(s, MajorFunction);
360 if (pos >= 24)
361 Stream_Read_UINT32(s, MinorFunction);
362 WLog_Print(log, lvl,
363 "%s [%s | %s] [0x%08" PRIx32 "] FileId=0x%08" PRIx32
364 ", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
365 ", MinorFunction=0x%08" PRIx32 " -> %" PRIuz,
366 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
367 deviceID, FileId, CompletionId, MajorFunction, MinorFunction, pos);
368 }
369 break;
370 case PAKID_CORE_DEVICE_IOCOMPLETION:
371 {
372 UINT32 completionID = 0;
373 UINT32 ioStatus = 0;
374 UINT32 deviceID = 0;
375 if (pos >= 8)
376 Stream_Read_UINT32(s, deviceID);
377 if (pos >= 12)
378 Stream_Read_UINT32(s, completionID);
379 if (pos >= 16)
380 Stream_Read_UINT32(s, ioStatus);
381
382 WLog_Print(log, lvl,
383 "%s [%s | %s] [0x%08" PRIx32 "] completionID=0x%08" PRIx32
384 ", ioStatus=0x%08" PRIx32 " -> %" PRIuz,
385 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
386 deviceID, completionID, ioStatus, pos);
387 }
388 break;
389 case PAKID_CORE_DEVICE_REPLY:
390 {
391 UINT32 deviceID = 0;
392 UINT32 status = 0;
393
394 if (pos >= 8)
395 Stream_Read_UINT32(s, deviceID);
396 if (pos >= 12)
397 Stream_Read_UINT32(s, status);
398 WLog_Print(log, lvl,
399 "%s [%s | %s] [id:0x%08" PRIx32 ",status=0x%08" PRIx32 "] -> %" PRIuz,
400 custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
401 deviceID, status, pos);
402 }
403 break;
404 case PAKID_CORE_CLIENT_CAPABILITY:
405 case PAKID_CORE_SERVER_CAPABILITY:
406 {
407 UINT16 numCapabilities = 0;
408 if (pos >= 6)
409 Stream_Read_UINT16(s, numCapabilities);
410 if (pos >= 8)
411 Stream_Seek_UINT16(s); /* padding */
412 WLog_Print(log, lvl, "%s [%s | %s] [caps:%" PRIu16 "] -> %" PRIuz, custom,
413 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
414 numCapabilities, pos);
415 for (UINT16 x = 0; x < numCapabilities; x++)
416 {
417 RDPDR_CAPABILITY_HEADER header = { 0 };
418 const UINT error = rdpdr_read_capset_header(log, s, &header);
419 if (error == CHANNEL_RC_OK)
420 Stream_Seek(s, header.CapabilityLength);
421 }
422 }
423 break;
424 case PAKID_CORE_DEVICELIST_ANNOUNCE:
425 {
426 size_t offset = 8;
427 UINT32 count = 0;
428
429 if (pos >= offset)
430 Stream_Read_UINT32(s, count);
431
432 WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
433 rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
434 pos);
435
436 for (UINT32 x = 0; x < count; x++)
437 {
438 RdpdrDevice device = { 0 };
439
440 offset += 20;
441 if (pos >= offset)
442 {
443 Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */
444 Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */
445 Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */
446 Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
447 device.DeviceData = Stream_Pointer(s);
448 }
449 offset += device.DeviceDataLength;
450
451 WLog_Print(log, lvl,
452 "%s [announce][%" PRIu32 "] %s [0x%08" PRIx32
453 "] '%s' [DeviceDataLength=%" PRIu32 "]",
454 custom, x, freerdp_rdpdr_dtyp_string(device.DeviceType), device.DeviceId,
455 device.PreferredDosName, device.DeviceDataLength);
456 }
457 }
458 break;
459 case PAKID_CORE_DEVICELIST_REMOVE:
460 {
461 size_t offset = 8;
462 UINT32 count = 0;
463
464 if (pos >= offset)
465 Stream_Read_UINT32(s, count);
466
467 WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
468 rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
469 pos);
470
471 for (UINT32 x = 0; x < count; x++)
472 {
473 UINT32 id = 0;
474
475 offset += 4;
476 if (pos >= offset)
477 Stream_Read_UINT32(s, id);
478
479 WLog_Print(log, lvl, "%s [remove][%" PRIu32 "] id=%" PRIu32, custom, x, id);
480 }
481 }
482 break;
483 case PAKID_CORE_USER_LOGGEDON:
484 WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
485 rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
486 break;
487 default:
488 {
489 WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
490 rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
491 }
492 break;
493 }
494
495 // winpr_HexLogDump(log, lvl, Stream_Buffer(s), pos);
496 Stream_SetPosition(s, gpos);
497}
498
499void rdpdr_dump_received_packet(wLog* log, DWORD lvl, wStream* s, const char* custom)
500{
501 rdpdr_dump_packet(log, lvl, s, custom, FALSE);
502}
503
504void rdpdr_dump_send_packet(wLog* log, DWORD lvl, wStream* s, const char* custom)
505{
506 rdpdr_dump_packet(log, lvl, s, custom, TRUE);
507}
508
509const char* rdpdr_irp_string(UINT32 major)
510{
511 switch (major)
512 {
513 case IRP_MJ_CREATE:
514 return "IRP_MJ_CREATE";
515 case IRP_MJ_CLOSE:
516 return "IRP_MJ_CLOSE";
517 case IRP_MJ_READ:
518 return "IRP_MJ_READ";
519 case IRP_MJ_WRITE:
520 return "IRP_MJ_WRITE";
521 case IRP_MJ_DEVICE_CONTROL:
522 return "IRP_MJ_DEVICE_CONTROL";
523 case IRP_MJ_QUERY_VOLUME_INFORMATION:
524 return "IRP_MJ_QUERY_VOLUME_INFORMATION";
525 case IRP_MJ_SET_VOLUME_INFORMATION:
526 return "IRP_MJ_SET_VOLUME_INFORMATION";
527 case IRP_MJ_QUERY_INFORMATION:
528 return "IRP_MJ_QUERY_INFORMATION";
529 case IRP_MJ_SET_INFORMATION:
530 return "IRP_MJ_SET_INFORMATION";
531 case IRP_MJ_DIRECTORY_CONTROL:
532 return "IRP_MJ_DIRECTORY_CONTROL";
533 case IRP_MJ_LOCK_CONTROL:
534 return "IRP_MJ_LOCK_CONTROL";
535 default:
536 return "IRP_UNKNOWN";
537 }
538}
539
540const char* rdpdr_cap_type_string(UINT16 capability)
541{
542 switch (capability)
543 {
544 case CAP_GENERAL_TYPE:
545 return "CAP_GENERAL_TYPE";
546 case CAP_PRINTER_TYPE:
547 return "CAP_PRINTER_TYPE";
548 case CAP_PORT_TYPE:
549 return "CAP_PORT_TYPE";
550 case CAP_DRIVE_TYPE:
551 return "CAP_DRIVE_TYPE";
552 case CAP_SMARTCARD_TYPE:
553 return "CAP_SMARTCARD_TYPE";
554 default:
555 return "CAP_UNKNOWN";
556 }
557}
558
559UINT rdpdr_read_capset_header(wLog* log, wStream* s, RDPDR_CAPABILITY_HEADER* header)
560{
561 WINPR_ASSERT(header);
562 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
563 return ERROR_INVALID_DATA;
564
565 Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
566 Stream_Read_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
567 Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */
568
569 WLog_Print(log, WLOG_TRACE,
570 "capability %s [0x%04" PRIx16 "] got version %" PRIu32 ", length %" PRIu16,
571 rdpdr_cap_type_string(header->CapabilityType), header->CapabilityType,
572 header->Version, header->CapabilityLength);
573 if (header->CapabilityLength < 8)
574 {
575 WLog_Print(log, WLOG_ERROR, "capability %s got short length %" PRIu32,
576 rdpdr_cap_type_string(header->CapabilityType), header->CapabilityLength);
577 return ERROR_INVALID_DATA;
578 }
579 header->CapabilityLength -= 8;
580 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, header->CapabilityLength))
581 return ERROR_INVALID_DATA;
582 return CHANNEL_RC_OK;
583}
584
585UINT rdpdr_write_capset_header(wLog* log, wStream* s, const RDPDR_CAPABILITY_HEADER* header)
586{
587 WINPR_ASSERT(header);
588 WINPR_ASSERT(header->CapabilityLength >= 8);
589
590 if (!Stream_EnsureRemainingCapacity(s, header->CapabilityLength))
591 {
592 WLog_Print(log, WLOG_ERROR, "not enough data in stream!");
593 return ERROR_INVALID_DATA;
594 }
595
596 WLog_Print(log, WLOG_TRACE, "writing capability %s version %" PRIu32 ", length %" PRIu16,
597 rdpdr_cap_type_string(header->CapabilityType), header->Version,
598 header->CapabilityLength);
599 Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
600 Stream_Write_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
601 Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */
602 return CHANNEL_RC_OK;
603}
FREERDP_API const char * freerdp_rdpdr_dtyp_string(UINT32 type)
Returns a string representation of RDPDR_DTYP_*.