Coverage Report

Created: 2026-10-15 06:26

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