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