FreeRDP
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 
31 LONG 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 
53 const 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 
206 const 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 
219 const 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 
254 BOOL rdpdr_write_iocompletion_header(wStream* out, UINT32 DeviceId, UINT32 CompletionId,
255  UINT32 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_UINT32(out, ioStatus); /* IoStatus (4 bytes) */
266 
267  return TRUE;
268 }
269 
270 static 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 
493 void 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 
498 void 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 
503 const 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 
534 const 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 
553 UINT 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 
579 UINT 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_*.