Coverage Report

Created: 2026-03-04 06:17

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