Coverage Report

Created: 2026-07-16 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/utils/smartcard_operations.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Smartcard Device Service Virtual Channel
4
 *
5
 * Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
6
 * Copyright 2011 O.S. Systems Software Ltda.
7
 * Copyright 2011 Anthony Tong <atong@trustedcs.com>
8
 * Copyright 2015 Thincast Technologies GmbH
9
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
11
 * Copyright 2017 Thincast Technologies GmbH
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 *     http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25
26
#include <freerdp/config.h>
27
28
#include <winpr/assert.h>
29
30
#include <winpr/crt.h>
31
#include <winpr/print.h>
32
#include <winpr/stream.h>
33
#include <winpr/smartcard.h>
34
35
#include <freerdp/freerdp.h>
36
#include <freerdp/channels/rdpdr.h>
37
#include <freerdp/channels/scard.h>
38
39
#include <freerdp/utils/rdpdr_utils.h>
40
41
#include <freerdp/utils/smartcard_operations.h>
42
#include <freerdp/utils/smartcard_pack.h>
43
44
#include <freerdp/log.h>
45
0
#define TAG FREERDP_TAG("utils.smartcard.ops")
46
47
static LONG smartcard_call_to_operation_handle(SMARTCARD_OPERATION* operation)
48
0
{
49
0
  WINPR_ASSERT(operation);
50
51
0
  operation->hContext =
52
0
      smartcard_scard_context_native_from_redir(&(operation->call.handles.hContext));
53
0
  operation->hCard = smartcard_scard_handle_native_from_redir(&(operation->call.handles.hCard));
54
55
0
  return SCARD_S_SUCCESS;
56
0
}
57
58
static LONG smartcard_EstablishContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
59
0
{
60
0
  LONG status = 0;
61
62
0
  WINPR_ASSERT(s);
63
0
  WINPR_ASSERT(operation);
64
65
0
  status = smartcard_unpack_establish_context_call(s, &operation->call.establishContext);
66
0
  if (status != SCARD_S_SUCCESS)
67
0
  {
68
0
    return scard_log_status_error(TAG, "smartcard_unpack_establish_context_call", status);
69
0
  }
70
71
0
  return SCARD_S_SUCCESS;
72
0
}
73
74
static LONG smartcard_ReleaseContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
75
0
{
76
0
  LONG status = 0;
77
78
0
  WINPR_ASSERT(s);
79
0
  WINPR_ASSERT(operation);
80
81
0
  status = smartcard_unpack_context_call(s, &operation->call.context, "ReleaseContext");
82
0
  if (status != SCARD_S_SUCCESS)
83
0
    scard_log_status_error(TAG, "smartcard_unpack_context_call", status);
84
85
0
  return status;
86
0
}
87
88
static LONG smartcard_IsValidContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
89
0
{
90
0
  LONG status = 0;
91
92
0
  WINPR_ASSERT(s);
93
0
  WINPR_ASSERT(operation);
94
95
0
  status = smartcard_unpack_context_call(s, &operation->call.context, "IsValidContext");
96
97
0
  return status;
98
0
}
99
100
static LONG smartcard_ListReaderGroupsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
101
0
{
102
0
  LONG status = 0;
103
104
0
  WINPR_ASSERT(s);
105
0
  WINPR_ASSERT(operation);
106
107
0
  status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, FALSE);
108
109
0
  return status;
110
0
}
111
112
static LONG smartcard_ListReaderGroupsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
113
0
{
114
0
  LONG status = 0;
115
116
0
  WINPR_ASSERT(s);
117
0
  WINPR_ASSERT(operation);
118
119
0
  status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, TRUE);
120
121
0
  return status;
122
0
}
123
124
static LONG smartcard_ListReadersA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
125
0
{
126
0
  LONG status = 0;
127
128
0
  WINPR_ASSERT(s);
129
0
  WINPR_ASSERT(operation);
130
131
0
  status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, FALSE);
132
133
0
  return status;
134
0
}
135
136
static LONG smartcard_ListReadersW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
137
0
{
138
0
  LONG status = 0;
139
140
0
  WINPR_ASSERT(s);
141
0
  WINPR_ASSERT(operation);
142
143
0
  status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, TRUE);
144
145
0
  return status;
146
0
}
147
148
static LONG smartcard_ContextAndTwoStringA_decode_request(wStream* s,
149
                                                          SMARTCARD_OPERATION* operation)
150
0
{
151
0
  LONG status = 0;
152
153
0
  WINPR_ASSERT(s);
154
0
  WINPR_ASSERT(operation);
155
156
0
  status =
157
0
      smartcard_unpack_context_and_two_strings_a_call(s, &operation->call.contextAndTwoStringA);
158
159
0
  return status;
160
0
}
161
162
static LONG smartcard_ContextAndTwoStringW_decode_request(wStream* s,
163
                                                          SMARTCARD_OPERATION* operation)
164
0
{
165
0
  LONG status = 0;
166
167
0
  WINPR_ASSERT(s);
168
0
  WINPR_ASSERT(operation);
169
170
0
  status =
171
0
      smartcard_unpack_context_and_two_strings_w_call(s, &operation->call.contextAndTwoStringW);
172
173
0
  return status;
174
0
}
175
176
static LONG smartcard_ContextAndStringA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
177
0
{
178
0
  LONG status = 0;
179
180
0
  WINPR_ASSERT(s);
181
0
  WINPR_ASSERT(operation);
182
183
0
  status = smartcard_unpack_context_and_string_a_call(s, &operation->call.contextAndStringA);
184
185
0
  return status;
186
0
}
187
188
static LONG smartcard_ContextAndStringW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
189
0
{
190
0
  LONG status = 0;
191
192
0
  WINPR_ASSERT(s);
193
0
  WINPR_ASSERT(operation);
194
195
0
  status = smartcard_unpack_context_and_string_w_call(s, &operation->call.contextAndStringW);
196
197
0
  return status;
198
0
}
199
200
static LONG smartcard_LocateCardsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
201
0
{
202
0
  LONG status = 0;
203
204
0
  WINPR_ASSERT(s);
205
0
  WINPR_ASSERT(operation);
206
207
0
  status = smartcard_unpack_locate_cards_a_call(s, &operation->call.locateCardsA);
208
209
0
  return status;
210
0
}
211
212
static LONG smartcard_LocateCardsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
213
0
{
214
0
  LONG status = 0;
215
216
0
  WINPR_ASSERT(s);
217
0
  WINPR_ASSERT(operation);
218
219
0
  status = smartcard_unpack_locate_cards_w_call(s, &operation->call.locateCardsW);
220
221
0
  return status;
222
0
}
223
224
static LONG smartcard_GetStatusChangeA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
225
0
{
226
0
  WINPR_ASSERT(s);
227
0
  WINPR_ASSERT(operation);
228
229
0
  return smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA);
230
0
}
231
232
static LONG smartcard_GetStatusChangeW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
233
0
{
234
0
  WINPR_ASSERT(s);
235
0
  WINPR_ASSERT(operation);
236
237
0
  return smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW);
238
0
}
239
240
static LONG smartcard_Cancel_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
241
0
{
242
0
  LONG status = 0;
243
244
0
  WINPR_ASSERT(s);
245
0
  WINPR_ASSERT(operation);
246
247
0
  status = smartcard_unpack_context_call(s, &operation->call.context, "Cancel");
248
249
0
  return status;
250
0
}
251
252
static LONG smartcard_ConnectA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
253
0
{
254
0
  LONG status = 0;
255
256
0
  WINPR_ASSERT(s);
257
0
  WINPR_ASSERT(operation);
258
259
0
  status = smartcard_unpack_connect_a_call(s, &operation->call.connectA);
260
261
0
  return status;
262
0
}
263
264
static LONG smartcard_ConnectW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
265
0
{
266
0
  LONG status = 0;
267
268
0
  WINPR_ASSERT(s);
269
0
  WINPR_ASSERT(operation);
270
271
0
  status = smartcard_unpack_connect_w_call(s, &operation->call.connectW);
272
273
0
  return status;
274
0
}
275
276
static LONG smartcard_Reconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
277
0
{
278
0
  LONG status = 0;
279
280
0
  WINPR_ASSERT(s);
281
0
  WINPR_ASSERT(operation);
282
283
0
  status = smartcard_unpack_reconnect_call(s, &operation->call.reconnect);
284
285
0
  return status;
286
0
}
287
288
static LONG smartcard_Disconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
289
0
{
290
0
  LONG status = 0;
291
292
0
  WINPR_ASSERT(s);
293
0
  WINPR_ASSERT(operation);
294
295
0
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
296
0
                                                       "Disconnect");
297
298
0
  return status;
299
0
}
300
301
static LONG smartcard_BeginTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
302
0
{
303
0
  LONG status = 0;
304
305
0
  WINPR_ASSERT(s);
306
0
  WINPR_ASSERT(operation);
307
308
0
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
309
0
                                                       "BeginTransaction");
310
311
0
  return status;
312
0
}
313
314
static LONG smartcard_EndTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
315
0
{
316
0
  LONG status = 0;
317
318
0
  WINPR_ASSERT(s);
319
0
  WINPR_ASSERT(operation);
320
321
0
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
322
0
                                                       "EndTransaction");
323
324
0
  return status;
325
0
}
326
327
static LONG smartcard_State_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
328
0
{
329
0
  LONG status = 0;
330
331
0
  WINPR_ASSERT(s);
332
0
  WINPR_ASSERT(operation);
333
334
0
  status = smartcard_unpack_state_call(s, &operation->call.state);
335
336
0
  return status;
337
0
}
338
339
static LONG smartcard_StatusA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
340
0
{
341
0
  LONG status = 0;
342
343
0
  WINPR_ASSERT(s);
344
0
  WINPR_ASSERT(operation);
345
346
0
  status = smartcard_unpack_status_call(s, &operation->call.status, FALSE);
347
348
0
  return status;
349
0
}
350
351
static LONG smartcard_StatusW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
352
0
{
353
0
  LONG status = 0;
354
355
0
  WINPR_ASSERT(s);
356
0
  WINPR_ASSERT(operation);
357
358
0
  status = smartcard_unpack_status_call(s, &operation->call.status, TRUE);
359
360
0
  return status;
361
0
}
362
363
static LONG smartcard_Transmit_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
364
0
{
365
0
  LONG status = 0;
366
367
0
  WINPR_ASSERT(s);
368
0
  WINPR_ASSERT(operation);
369
370
0
  status = smartcard_unpack_transmit_call(s, &operation->call.transmit);
371
372
0
  return status;
373
0
}
374
375
static LONG smartcard_Control_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
376
0
{
377
0
  LONG status = 0;
378
379
0
  WINPR_ASSERT(s);
380
0
  WINPR_ASSERT(operation);
381
382
0
  status = smartcard_unpack_control_call(s, &operation->call.control);
383
384
0
  return status;
385
0
}
386
387
static LONG smartcard_GetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
388
0
{
389
0
  LONG status = 0;
390
391
0
  WINPR_ASSERT(s);
392
0
  WINPR_ASSERT(operation);
393
394
0
  status = smartcard_unpack_get_attrib_call(s, &operation->call.getAttrib);
395
396
0
  return status;
397
0
}
398
399
static LONG smartcard_SetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
400
0
{
401
0
  LONG status = 0;
402
403
0
  WINPR_ASSERT(s);
404
0
  WINPR_ASSERT(operation);
405
406
0
  status = smartcard_unpack_set_attrib_call(s, &operation->call.setAttrib);
407
408
0
  return status;
409
0
}
410
411
static LONG smartcard_AccessStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
412
0
{
413
0
  WINPR_ASSERT(s);
414
0
  WINPR_ASSERT(operation);
415
416
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
417
0
    return SCARD_F_INTERNAL_ERROR;
418
419
0
  Stream_Read_INT32(s, operation->call.lng.LongValue); /* Unused (4 bytes) */
420
421
0
  return SCARD_S_SUCCESS;
422
0
}
423
424
static LONG smartcard_LocateCardsByATRA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
425
0
{
426
0
  LONG status = 0;
427
428
0
  WINPR_ASSERT(s);
429
0
  WINPR_ASSERT(operation);
430
431
0
  status = smartcard_unpack_locate_cards_by_atr_a_call(s, &operation->call.locateCardsByATRA);
432
433
0
  return status;
434
0
}
435
436
static LONG smartcard_LocateCardsByATRW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
437
0
{
438
0
  LONG status = 0;
439
440
0
  WINPR_ASSERT(s);
441
0
  WINPR_ASSERT(operation);
442
443
0
  status = smartcard_unpack_locate_cards_by_atr_w_call(s, &operation->call.locateCardsByATRW);
444
445
0
  return status;
446
0
}
447
448
static LONG smartcard_ReadCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
449
0
{
450
0
  LONG status = 0;
451
452
0
  WINPR_ASSERT(s);
453
0
  WINPR_ASSERT(operation);
454
455
0
  status = smartcard_unpack_read_cache_a_call(s, &operation->call.readCacheA);
456
457
0
  return status;
458
0
}
459
460
static LONG smartcard_ReadCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
461
0
{
462
0
  LONG status = 0;
463
464
0
  WINPR_ASSERT(s);
465
0
  WINPR_ASSERT(operation);
466
467
0
  status = smartcard_unpack_read_cache_w_call(s, &operation->call.readCacheW);
468
469
0
  return status;
470
0
}
471
472
static LONG smartcard_WriteCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
473
0
{
474
0
  LONG status = 0;
475
476
0
  WINPR_ASSERT(s);
477
0
  WINPR_ASSERT(operation);
478
479
0
  status = smartcard_unpack_write_cache_a_call(s, &operation->call.writeCacheA);
480
481
0
  return status;
482
0
}
483
484
static LONG smartcard_WriteCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
485
0
{
486
0
  LONG status = 0;
487
488
0
  WINPR_ASSERT(s);
489
0
  WINPR_ASSERT(operation);
490
491
0
  status = smartcard_unpack_write_cache_w_call(s, &operation->call.writeCacheW);
492
493
0
  return status;
494
0
}
495
496
static LONG smartcard_GetTransmitCount_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
497
0
{
498
0
  LONG status = 0;
499
500
0
  WINPR_ASSERT(s);
501
0
  WINPR_ASSERT(operation);
502
503
0
  status = smartcard_unpack_get_transmit_count_call(s, &operation->call.getTransmitCount);
504
505
0
  return status;
506
0
}
507
508
static LONG smartcard_ReleaseStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
509
0
{
510
0
  WINPR_UNUSED(s);
511
0
  WINPR_UNUSED(operation);
512
0
  WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
513
0
                 "SCARD_IOCTL_RELEASETARTEDEVENT is not supported");
514
0
  return SCARD_E_UNSUPPORTED_FEATURE;
515
0
}
516
517
static LONG smartcard_GetReaderIcon_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
518
0
{
519
0
  LONG status = 0;
520
521
0
  WINPR_ASSERT(s);
522
0
  WINPR_ASSERT(operation);
523
524
0
  status = smartcard_unpack_get_reader_icon_call(s, &operation->call.getReaderIcon);
525
526
0
  return status;
527
0
}
528
529
static LONG smartcard_GetDeviceTypeId_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
530
0
{
531
0
  LONG status = 0;
532
533
0
  WINPR_ASSERT(s);
534
0
  WINPR_ASSERT(operation);
535
536
0
  status = smartcard_unpack_get_device_type_id_call(s, &operation->call.getDeviceTypeId);
537
538
0
  return status;
539
0
}
540
541
LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 FileId,
542
                                         SMARTCARD_OPERATION* operation)
543
0
{
544
0
  return smartcard_irp_device_control_decode_request(s, CompletionId, FileId, operation);
545
0
}
546
547
LONG smartcard_irp_device_control_decode_request(wStream* s, UINT32 CompletionId, UINT32 FileId,
548
                                                 SMARTCARD_OPERATION* operation)
549
0
{
550
0
  LONG status = 0;
551
0
  UINT32 offset = 0;
552
553
0
  WINPR_ASSERT(s);
554
0
  WINPR_ASSERT(operation);
555
556
  /* Device Control Request */
557
558
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH))
559
0
    return SCARD_F_INTERNAL_ERROR;
560
561
0
  const UINT32 outputBufferLength = Stream_Get_UINT32(s); /* OutputBufferLength (4 bytes) */
562
0
  const UINT32 inputBufferLength = Stream_Get_UINT32(s);  /* InputBufferLength (4 bytes) */
563
0
  const UINT32 ioControlCode = Stream_Get_UINT32(s);      /* IoControlCode (4 bytes) */
564
0
  Stream_Seek(s, 20);                                     /* Padding (20 bytes) */
565
0
  operation->ioControlCode = ioControlCode;
566
0
  operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE);
567
0
  operation->outputBufferLength = outputBufferLength;
568
569
0
  if (Stream_Length(s) != (Stream_GetPosition(s) + inputBufferLength))
570
0
  {
571
0
    WLog_WARN(TAG, "InputBufferLength mismatch: Actual: %" PRIuz " Expected: %" PRIuz "",
572
0
              Stream_Length(s), Stream_GetPosition(s) + inputBufferLength);
573
0
    return SCARD_F_INTERNAL_ERROR;
574
0
  }
575
576
0
  WLog_DBG(TAG, "%s (0x%08" PRIX32 ") FileId: %" PRIu32 " CompletionId: %" PRIu32 "",
577
0
           scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, FileId, CompletionId);
578
579
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
580
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
581
0
  {
582
0
    status = smartcard_unpack_common_type_header(s);
583
0
    if (status != SCARD_S_SUCCESS)
584
0
      return status;
585
586
0
    status = smartcard_unpack_private_type_header(s);
587
0
    if (status != SCARD_S_SUCCESS)
588
0
      return status;
589
0
  }
590
591
  /* Decode */
592
0
  switch (ioControlCode)
593
0
  {
594
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
595
0
      status = smartcard_EstablishContext_decode_request(s, operation);
596
0
      break;
597
598
0
    case SCARD_IOCTL_RELEASECONTEXT:
599
0
      status = smartcard_ReleaseContext_decode_request(s, operation);
600
0
      break;
601
602
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
603
0
      status = smartcard_IsValidContext_decode_request(s, operation);
604
0
      break;
605
606
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
607
0
      status = smartcard_ListReaderGroupsA_decode_request(s, operation);
608
0
      break;
609
610
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
611
0
      status = smartcard_ListReaderGroupsW_decode_request(s, operation);
612
0
      break;
613
614
0
    case SCARD_IOCTL_LISTREADERSA:
615
0
      status = smartcard_ListReadersA_decode_request(s, operation);
616
0
      break;
617
618
0
    case SCARD_IOCTL_LISTREADERSW:
619
0
      status = smartcard_ListReadersW_decode_request(s, operation);
620
0
      break;
621
622
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
623
0
      status = smartcard_ContextAndStringA_decode_request(s, operation);
624
0
      break;
625
626
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
627
0
      status = smartcard_ContextAndStringW_decode_request(s, operation);
628
0
      break;
629
630
0
    case SCARD_IOCTL_FORGETREADERGROUPA:
631
0
      status = smartcard_ContextAndStringA_decode_request(s, operation);
632
0
      break;
633
634
0
    case SCARD_IOCTL_FORGETREADERGROUPW:
635
0
      status = smartcard_ContextAndStringW_decode_request(s, operation);
636
0
      break;
637
638
0
    case SCARD_IOCTL_INTRODUCEREADERA:
639
0
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
640
0
      break;
641
642
0
    case SCARD_IOCTL_INTRODUCEREADERW:
643
0
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
644
0
      break;
645
646
0
    case SCARD_IOCTL_FORGETREADERA:
647
0
      status = smartcard_ContextAndStringA_decode_request(s, operation);
648
0
      break;
649
650
0
    case SCARD_IOCTL_FORGETREADERW:
651
0
      status = smartcard_ContextAndStringW_decode_request(s, operation);
652
0
      break;
653
654
0
    case SCARD_IOCTL_ADDREADERTOGROUPA:
655
0
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
656
0
      break;
657
658
0
    case SCARD_IOCTL_ADDREADERTOGROUPW:
659
0
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
660
0
      break;
661
662
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
663
0
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
664
0
      break;
665
666
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
667
0
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
668
0
      break;
669
670
0
    case SCARD_IOCTL_LOCATECARDSA:
671
0
      status = smartcard_LocateCardsA_decode_request(s, operation);
672
0
      break;
673
674
0
    case SCARD_IOCTL_LOCATECARDSW:
675
0
      status = smartcard_LocateCardsW_decode_request(s, operation);
676
0
      break;
677
678
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
679
0
      status = smartcard_GetStatusChangeA_decode_request(s, operation);
680
0
      break;
681
682
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
683
0
      status = smartcard_GetStatusChangeW_decode_request(s, operation);
684
0
      break;
685
686
0
    case SCARD_IOCTL_CANCEL:
687
0
      status = smartcard_Cancel_decode_request(s, operation);
688
0
      break;
689
690
0
    case SCARD_IOCTL_CONNECTA:
691
0
      status = smartcard_ConnectA_decode_request(s, operation);
692
0
      break;
693
694
0
    case SCARD_IOCTL_CONNECTW:
695
0
      status = smartcard_ConnectW_decode_request(s, operation);
696
0
      break;
697
698
0
    case SCARD_IOCTL_RECONNECT:
699
0
      status = smartcard_Reconnect_decode_request(s, operation);
700
0
      break;
701
702
0
    case SCARD_IOCTL_DISCONNECT:
703
0
      status = smartcard_Disconnect_decode_request(s, operation);
704
0
      break;
705
706
0
    case SCARD_IOCTL_BEGINTRANSACTION:
707
0
      status = smartcard_BeginTransaction_decode_request(s, operation);
708
0
      break;
709
710
0
    case SCARD_IOCTL_ENDTRANSACTION:
711
0
      status = smartcard_EndTransaction_decode_request(s, operation);
712
0
      break;
713
714
0
    case SCARD_IOCTL_STATE:
715
0
      status = smartcard_State_decode_request(s, operation);
716
0
      break;
717
718
0
    case SCARD_IOCTL_STATUSA:
719
0
      status = smartcard_StatusA_decode_request(s, operation);
720
0
      break;
721
722
0
    case SCARD_IOCTL_STATUSW:
723
0
      status = smartcard_StatusW_decode_request(s, operation);
724
0
      break;
725
726
0
    case SCARD_IOCTL_TRANSMIT:
727
0
      status = smartcard_Transmit_decode_request(s, operation);
728
0
      break;
729
730
0
    case SCARD_IOCTL_CONTROL:
731
0
      status = smartcard_Control_decode_request(s, operation);
732
0
      break;
733
734
0
    case SCARD_IOCTL_GETATTRIB:
735
0
      status = smartcard_GetAttrib_decode_request(s, operation);
736
0
      break;
737
738
0
    case SCARD_IOCTL_SETATTRIB:
739
0
      status = smartcard_SetAttrib_decode_request(s, operation);
740
0
      break;
741
742
0
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
743
0
      status = smartcard_AccessStartedEvent_decode_request(s, operation);
744
0
      break;
745
746
0
    case SCARD_IOCTL_LOCATECARDSBYATRA:
747
0
      status = smartcard_LocateCardsByATRA_decode_request(s, operation);
748
0
      break;
749
750
0
    case SCARD_IOCTL_LOCATECARDSBYATRW:
751
0
      status = smartcard_LocateCardsByATRW_decode_request(s, operation);
752
0
      break;
753
754
0
    case SCARD_IOCTL_READCACHEA:
755
0
      status = smartcard_ReadCacheA_decode_request(s, operation);
756
0
      break;
757
758
0
    case SCARD_IOCTL_READCACHEW:
759
0
      status = smartcard_ReadCacheW_decode_request(s, operation);
760
0
      break;
761
762
0
    case SCARD_IOCTL_WRITECACHEA:
763
0
      status = smartcard_WriteCacheA_decode_request(s, operation);
764
0
      break;
765
766
0
    case SCARD_IOCTL_WRITECACHEW:
767
0
      status = smartcard_WriteCacheW_decode_request(s, operation);
768
0
      break;
769
770
0
    case SCARD_IOCTL_GETTRANSMITCOUNT:
771
0
      status = smartcard_GetTransmitCount_decode_request(s, operation);
772
0
      break;
773
774
0
    case SCARD_IOCTL_RELEASETARTEDEVENT:
775
0
      status = smartcard_ReleaseStartedEvent_decode_request(s, operation);
776
0
      break;
777
778
0
    case SCARD_IOCTL_GETREADERICON:
779
0
      status = smartcard_GetReaderIcon_decode_request(s, operation);
780
0
      break;
781
782
0
    case SCARD_IOCTL_GETDEVICETYPEID:
783
0
      status = smartcard_GetDeviceTypeId_decode_request(s, operation);
784
0
      break;
785
786
0
    default:
787
0
      status = SCARD_F_INTERNAL_ERROR;
788
0
      break;
789
0
  }
790
791
0
  smartcard_call_to_operation_handle(operation);
792
793
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
794
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
795
0
  {
796
0
    offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH);
797
0
    if (smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8) < 0)
798
0
      return STATUS_INVALID_PARAMETER;
799
0
  }
800
801
0
  if (Stream_GetPosition(s) < Stream_Length(s))
802
0
  {
803
0
    size_t difference = 0;
804
0
    difference = Stream_Length(s) - Stream_GetPosition(s);
805
0
    WLog_WARN(TAG,
806
0
              "IRP was not fully parsed %s (%s [0x%08" PRIX32 "]): Actual: %" PRIuz
807
0
              ", Expected: %" PRIuz ", Difference: %" PRIuz "",
808
0
              scard_get_ioctl_string(ioControlCode, TRUE),
809
0
              scard_get_ioctl_string(ioControlCode, FALSE), ioControlCode,
810
0
              Stream_GetPosition(s), Stream_Length(s), difference);
811
0
    winpr_HexDump(TAG, WLOG_WARN, Stream_ConstPointer(s), difference);
812
0
  }
813
814
0
  if (Stream_GetPosition(s) > Stream_Length(s))
815
0
  {
816
0
    size_t difference = 0;
817
0
    difference = Stream_GetPosition(s) - Stream_Length(s);
818
0
    WLog_WARN(TAG,
819
0
              "IRP was parsed beyond its end %s (0x%08" PRIX32 "): Actual: %" PRIuz
820
0
              ", Expected: %" PRIuz ", Difference: %" PRIuz "",
821
0
              scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, Stream_GetPosition(s),
822
0
              Stream_Length(s), difference);
823
0
  }
824
825
0
  return status;
826
0
}
827
828
static LONG smartcard_EstablishContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
829
0
{
830
0
  WINPR_ASSERT(s);
831
0
  WINPR_ASSERT(operation);
832
833
0
  return smartcard_unpack_establish_context_return(s, &operation->ret.establishContext);
834
0
}
835
836
static LONG smartcard_ReleaseContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
837
0
{
838
0
  WINPR_UNUSED(s);
839
0
  WINPR_ASSERT(operation);
840
841
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
842
0
  smartcard_trace_long_return(&ret, "ReleaseContext");
843
0
  return SCARD_S_SUCCESS;
844
0
}
845
846
static LONG smartcard_IsValidContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
847
0
{
848
0
  WINPR_UNUSED(s);
849
0
  WINPR_ASSERT(operation);
850
851
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
852
0
  smartcard_trace_long_return(&ret, "IsValidContext");
853
0
  return SCARD_S_SUCCESS;
854
0
}
855
856
static LONG smartcard_ListReaderGroupsA_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
857
0
{
858
0
  WINPR_ASSERT(s);
859
0
  WINPR_ASSERT(operation);
860
861
0
  return smartcard_unpack_list_reader_groups_return(s, &operation->ret.listReaders, FALSE);
862
0
}
863
864
static LONG smartcard_ListReaderGroupsW_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
865
0
{
866
0
  WINPR_ASSERT(s);
867
0
  WINPR_ASSERT(operation);
868
869
0
  return smartcard_unpack_list_reader_groups_return(s, &operation->ret.listReaders, TRUE);
870
0
}
871
872
static LONG smartcard_ListReadersA_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
873
0
{
874
0
  WINPR_ASSERT(s);
875
0
  WINPR_ASSERT(operation);
876
877
0
  return smartcard_unpack_list_readers_return(s, &operation->ret.listReaders, FALSE);
878
0
}
879
880
static LONG smartcard_ListReadersW_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
881
0
{
882
0
  WINPR_ASSERT(s);
883
0
  WINPR_ASSERT(operation);
884
885
0
  return smartcard_unpack_list_readers_return(s, &operation->ret.listReaders, TRUE);
886
0
}
887
888
static LONG smartcard_GetStatusChangeA_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
889
0
{
890
0
  WINPR_ASSERT(s);
891
0
  WINPR_ASSERT(operation);
892
893
0
  return smartcard_unpack_get_status_change_return(s, &operation->ret.getStatusChange, FALSE);
894
0
}
895
896
static LONG smartcard_GetStatusChangeW_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
897
0
{
898
0
  WINPR_ASSERT(s);
899
0
  WINPR_ASSERT(operation);
900
901
0
  return smartcard_unpack_get_status_change_return(s, &operation->ret.getStatusChange, TRUE);
902
0
}
903
904
static LONG smartcard_Cancel_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
905
0
{
906
0
  WINPR_UNUSED(s);
907
0
  WINPR_ASSERT(operation);
908
909
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
910
0
  smartcard_trace_long_return(&ret, "Cancel");
911
0
  return SCARD_S_SUCCESS;
912
0
}
913
914
static LONG smartcard_ConnectA_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
915
0
{
916
0
  WINPR_ASSERT(s);
917
0
  WINPR_ASSERT(operation);
918
919
0
  return smartcard_unpack_connect_return(s, &operation->ret.connect);
920
0
}
921
922
static LONG smartcard_ConnectW_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
923
0
{
924
0
  WINPR_ASSERT(s);
925
0
  WINPR_ASSERT(operation);
926
927
0
  return smartcard_unpack_connect_return(s, &operation->ret.connect);
928
0
}
929
930
static LONG smartcard_Reconnect_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
931
0
{
932
0
  WINPR_ASSERT(s);
933
0
  WINPR_ASSERT(operation);
934
935
0
  return smartcard_unpack_reconnect_return(s, &operation->ret.reconnect);
936
0
}
937
938
static LONG smartcard_Disconnect_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
939
0
{
940
0
  WINPR_UNUSED(s);
941
0
  WINPR_ASSERT(operation);
942
943
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
944
0
  smartcard_trace_long_return(&ret, "Disconnect");
945
0
  return SCARD_S_SUCCESS;
946
0
}
947
948
static LONG smartcard_BeginTransaction_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
949
0
{
950
0
  WINPR_UNUSED(s);
951
0
  WINPR_ASSERT(operation);
952
953
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
954
0
  smartcard_trace_long_return(&ret, "BeginTransaction");
955
0
  return SCARD_S_SUCCESS;
956
0
}
957
958
static LONG smartcard_EndTransaction_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
959
0
{
960
0
  WINPR_UNUSED(s);
961
0
  WINPR_ASSERT(operation);
962
963
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
964
0
  smartcard_trace_long_return(&ret, "EndTransaction");
965
0
  return SCARD_S_SUCCESS;
966
0
}
967
968
static LONG smartcard_StatusA_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
969
0
{
970
0
  WINPR_ASSERT(s);
971
0
  WINPR_ASSERT(operation);
972
973
0
  return smartcard_unpack_status_return(s, &operation->ret.status, FALSE);
974
0
}
975
976
static LONG smartcard_StatusW_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
977
0
{
978
0
  WINPR_ASSERT(s);
979
0
  WINPR_ASSERT(operation);
980
981
0
  return smartcard_unpack_status_return(s, &operation->ret.status, TRUE);
982
0
}
983
984
static LONG smartcard_Transmit_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
985
0
{
986
0
  WINPR_ASSERT(s);
987
0
  WINPR_ASSERT(operation);
988
989
0
  return smartcard_unpack_transmit_return(s, &operation->ret.transmit);
990
0
}
991
992
static LONG smartcard_Control_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
993
0
{
994
0
  WINPR_ASSERT(s);
995
0
  WINPR_ASSERT(operation);
996
997
0
  return smartcard_unpack_control_return(s, &operation->ret.control);
998
0
}
999
1000
static LONG smartcard_GetAttrib_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
1001
0
{
1002
0
  WINPR_ASSERT(s);
1003
0
  WINPR_ASSERT(operation);
1004
1005
0
  return smartcard_unpack_get_attrib_return(s, &operation->ret.getAttrib);
1006
0
}
1007
1008
static LONG smartcard_SetAttrib_decode_response(wStream* s, SMARTCARD_OPERATION* operation)
1009
0
{
1010
0
  WINPR_UNUSED(s);
1011
0
  WINPR_ASSERT(operation);
1012
1013
0
  const Long_Return ret = { .ReturnCode = operation->returnCode };
1014
0
  smartcard_trace_long_return(&ret, "SetAttrib");
1015
0
  return SCARD_S_SUCCESS;
1016
0
}
1017
1018
LONG smartcard_irp_device_control_decode_response(wStream* s, UINT32 ioControlCode,
1019
                                                  SMARTCARD_OPERATION* operation)
1020
0
{
1021
0
  LONG status = SCARD_S_SUCCESS;
1022
1023
0
  WINPR_ASSERT(s);
1024
0
  WINPR_ASSERT(operation);
1025
1026
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH))
1027
0
    return SCARD_F_INTERNAL_ERROR;
1028
1029
0
  const size_t startPosition = Stream_GetPosition(s);
1030
1031
0
  const UINT32 outputBufferLength = Stream_Get_UINT32(s);
1032
0
  operation->ioControlCode = ioControlCode;
1033
0
  operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE);
1034
0
  operation->outputBufferLength = outputBufferLength;
1035
1036
0
  if (outputBufferLength == 0)
1037
0
    return SCARD_S_SUCCESS;
1038
1039
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, outputBufferLength))
1040
0
    return SCARD_F_INTERNAL_ERROR;
1041
1042
0
  status = smartcard_unpack_common_type_header(s);
1043
0
  if (status != SCARD_S_SUCCESS)
1044
0
    return status;
1045
1046
0
  status = smartcard_unpack_private_type_header(s);
1047
0
  if (status != SCARD_S_SUCCESS)
1048
0
    return status;
1049
1050
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1051
0
    return SCARD_F_INTERNAL_ERROR;
1052
1053
0
  Stream_Read_INT32(s, operation->returnCode);
1054
1055
0
  if (operation->returnCode != SCARD_S_SUCCESS)
1056
0
  {
1057
0
    WLog_DBG(TAG, "%s failed with ReturnCode %s [0x%08" PRIX32 "]",
1058
0
             scard_get_ioctl_string(ioControlCode, TRUE),
1059
0
             SCardGetErrorString(operation->returnCode), (UINT32)operation->returnCode);
1060
0
  }
1061
1062
0
  switch (ioControlCode)
1063
0
  {
1064
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1065
0
      status = smartcard_EstablishContext_decode_response(s, operation);
1066
0
      break;
1067
1068
0
    case SCARD_IOCTL_RELEASECONTEXT:
1069
0
      status = smartcard_ReleaseContext_decode_response(s, operation);
1070
0
      break;
1071
1072
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1073
0
      status = smartcard_IsValidContext_decode_response(s, operation);
1074
0
      break;
1075
1076
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1077
0
      status = smartcard_ListReaderGroupsA_decode_response(s, operation);
1078
0
      break;
1079
1080
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1081
0
      status = smartcard_ListReaderGroupsW_decode_response(s, operation);
1082
0
      break;
1083
1084
0
    case SCARD_IOCTL_LISTREADERSA:
1085
0
      status = smartcard_ListReadersA_decode_response(s, operation);
1086
0
      break;
1087
1088
0
    case SCARD_IOCTL_LISTREADERSW:
1089
0
      status = smartcard_ListReadersW_decode_response(s, operation);
1090
0
      break;
1091
1092
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1093
0
      status = smartcard_GetStatusChangeA_decode_response(s, operation);
1094
0
      break;
1095
1096
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1097
0
      status = smartcard_GetStatusChangeW_decode_response(s, operation);
1098
0
      break;
1099
1100
0
    case SCARD_IOCTL_CANCEL:
1101
0
      status = smartcard_Cancel_decode_response(s, operation);
1102
0
      break;
1103
1104
0
    case SCARD_IOCTL_CONNECTA:
1105
0
      status = smartcard_ConnectA_decode_response(s, operation);
1106
0
      break;
1107
1108
0
    case SCARD_IOCTL_CONNECTW:
1109
0
      status = smartcard_ConnectW_decode_response(s, operation);
1110
0
      break;
1111
1112
0
    case SCARD_IOCTL_RECONNECT:
1113
0
      status = smartcard_Reconnect_decode_response(s, operation);
1114
0
      break;
1115
1116
0
    case SCARD_IOCTL_DISCONNECT:
1117
0
      status = smartcard_Disconnect_decode_response(s, operation);
1118
0
      break;
1119
1120
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1121
0
      status = smartcard_BeginTransaction_decode_response(s, operation);
1122
0
      break;
1123
1124
0
    case SCARD_IOCTL_ENDTRANSACTION:
1125
0
      status = smartcard_EndTransaction_decode_response(s, operation);
1126
0
      break;
1127
1128
0
    case SCARD_IOCTL_STATUSA:
1129
0
      status = smartcard_StatusA_decode_response(s, operation);
1130
0
      break;
1131
1132
0
    case SCARD_IOCTL_STATUSW:
1133
0
      status = smartcard_StatusW_decode_response(s, operation);
1134
0
      break;
1135
1136
0
    case SCARD_IOCTL_TRANSMIT:
1137
0
      status = smartcard_Transmit_decode_response(s, operation);
1138
0
      break;
1139
1140
0
    case SCARD_IOCTL_CONTROL:
1141
0
      status = smartcard_Control_decode_response(s, operation);
1142
0
      break;
1143
1144
0
    case SCARD_IOCTL_GETATTRIB:
1145
0
      status = smartcard_GetAttrib_decode_response(s, operation);
1146
0
      break;
1147
1148
0
    case SCARD_IOCTL_SETATTRIB:
1149
0
      status = smartcard_SetAttrib_decode_response(s, operation);
1150
0
      break;
1151
1152
0
    default:
1153
0
      WLog_WARN(TAG, "unsupported response for %s (0x%08" PRIX32 ")",
1154
0
                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1155
0
      break;
1156
0
  }
1157
1158
0
  if (status != SCARD_S_SUCCESS)
1159
0
    return status;
1160
1161
0
  const size_t offset = startPosition + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH;
1162
0
  if (smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8) < 0)
1163
0
    return STATUS_INVALID_PARAMETER;
1164
1165
0
  return status;
1166
0
}
1167
1168
static LONG smartcard_EstablishContext_encode_request(wStream* s,
1169
                                                      const SMARTCARD_OPERATION* operation)
1170
0
{
1171
0
  WINPR_ASSERT(s);
1172
0
  WINPR_ASSERT(operation);
1173
1174
0
  return smartcard_pack_establish_context_call(s, &operation->call.establishContext);
1175
0
}
1176
1177
static LONG smartcard_ReleaseContext_encode_request(wStream* s,
1178
                                                    const SMARTCARD_OPERATION* operation)
1179
0
{
1180
0
  WINPR_ASSERT(s);
1181
0
  WINPR_ASSERT(operation);
1182
1183
0
  return smartcard_pack_context_call(s, &operation->call.context, "ReleaseContext");
1184
0
}
1185
1186
static LONG smartcard_IsValidContext_encode_request(wStream* s,
1187
                                                    const SMARTCARD_OPERATION* operation)
1188
0
{
1189
0
  WINPR_ASSERT(s);
1190
0
  WINPR_ASSERT(operation);
1191
1192
0
  return smartcard_pack_context_call(s, &operation->call.context, "IsValidContext");
1193
0
}
1194
1195
static LONG smartcard_ListReaderGroupsA_encode_request(wStream* s,
1196
                                                       const SMARTCARD_OPERATION* operation)
1197
0
{
1198
0
  WINPR_ASSERT(s);
1199
0
  WINPR_ASSERT(operation);
1200
1201
0
  return smartcard_pack_list_reader_groups_call(s, &operation->call.listReaderGroups, FALSE);
1202
0
}
1203
1204
static LONG smartcard_ListReaderGroupsW_encode_request(wStream* s,
1205
                                                       const SMARTCARD_OPERATION* operation)
1206
0
{
1207
0
  WINPR_ASSERT(s);
1208
0
  WINPR_ASSERT(operation);
1209
1210
0
  return smartcard_pack_list_reader_groups_call(s, &operation->call.listReaderGroups, TRUE);
1211
0
}
1212
1213
static LONG smartcard_ListReadersA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1214
0
{
1215
0
  WINPR_ASSERT(s);
1216
0
  WINPR_ASSERT(operation);
1217
1218
0
  return smartcard_pack_list_readers_call(s, &operation->call.listReaders, FALSE);
1219
0
}
1220
1221
static LONG smartcard_ListReadersW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1222
0
{
1223
0
  WINPR_ASSERT(s);
1224
0
  WINPR_ASSERT(operation);
1225
1226
0
  return smartcard_pack_list_readers_call(s, &operation->call.listReaders, TRUE);
1227
0
}
1228
1229
static LONG smartcard_GetStatusChangeA_encode_request(wStream* s,
1230
                                                      const SMARTCARD_OPERATION* operation)
1231
0
{
1232
0
  WINPR_ASSERT(s);
1233
0
  WINPR_ASSERT(operation);
1234
1235
0
  return smartcard_pack_get_status_change_a_call(s, &operation->call.getStatusChangeA);
1236
0
}
1237
1238
static LONG smartcard_GetStatusChangeW_encode_request(wStream* s,
1239
                                                      const SMARTCARD_OPERATION* operation)
1240
0
{
1241
0
  WINPR_ASSERT(s);
1242
0
  WINPR_ASSERT(operation);
1243
1244
0
  return smartcard_pack_get_status_change_w_call(s, &operation->call.getStatusChangeW);
1245
0
}
1246
1247
static LONG smartcard_Cancel_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1248
0
{
1249
0
  WINPR_ASSERT(s);
1250
0
  WINPR_ASSERT(operation);
1251
1252
0
  return smartcard_pack_context_call(s, &operation->call.context, "Cancel");
1253
0
}
1254
1255
static LONG smartcard_ConnectA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1256
0
{
1257
0
  WINPR_ASSERT(s);
1258
0
  WINPR_ASSERT(operation);
1259
1260
0
  return smartcard_pack_connect_a_call(s, &operation->call.connectA);
1261
0
}
1262
1263
static LONG smartcard_ConnectW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1264
0
{
1265
0
  WINPR_ASSERT(s);
1266
0
  WINPR_ASSERT(operation);
1267
1268
0
  return smartcard_pack_connect_w_call(s, &operation->call.connectW);
1269
0
}
1270
1271
static LONG smartcard_Reconnect_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1272
0
{
1273
0
  WINPR_ASSERT(s);
1274
0
  WINPR_ASSERT(operation);
1275
1276
0
  return smartcard_pack_reconnect_call(s, &operation->call.reconnect);
1277
0
}
1278
1279
static LONG smartcard_Disconnect_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1280
0
{
1281
0
  WINPR_ASSERT(s);
1282
0
  WINPR_ASSERT(operation);
1283
1284
0
  return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
1285
0
                                                   "Disconnect");
1286
0
}
1287
1288
static LONG smartcard_BeginTransaction_encode_request(wStream* s,
1289
                                                      const SMARTCARD_OPERATION* operation)
1290
0
{
1291
0
  WINPR_ASSERT(s);
1292
0
  WINPR_ASSERT(operation);
1293
1294
0
  return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
1295
0
                                                   "BeginTransaction");
1296
0
}
1297
1298
static LONG smartcard_EndTransaction_encode_request(wStream* s,
1299
                                                    const SMARTCARD_OPERATION* operation)
1300
0
{
1301
0
  WINPR_ASSERT(s);
1302
0
  WINPR_ASSERT(operation);
1303
1304
0
  return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
1305
0
                                                   "EndTransaction");
1306
0
}
1307
1308
static LONG smartcard_StatusA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1309
0
{
1310
0
  WINPR_ASSERT(s);
1311
0
  WINPR_ASSERT(operation);
1312
1313
0
  return smartcard_pack_status_call(s, &operation->call.status, FALSE);
1314
0
}
1315
1316
static LONG smartcard_StatusW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1317
0
{
1318
0
  WINPR_ASSERT(s);
1319
0
  WINPR_ASSERT(operation);
1320
1321
0
  return smartcard_pack_status_call(s, &operation->call.status, TRUE);
1322
0
}
1323
1324
static LONG smartcard_Transmit_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1325
0
{
1326
0
  WINPR_ASSERT(s);
1327
0
  WINPR_ASSERT(operation);
1328
1329
0
  return smartcard_pack_transmit_call(s, &operation->call.transmit);
1330
0
}
1331
1332
static LONG smartcard_Control_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1333
0
{
1334
0
  WINPR_ASSERT(s);
1335
0
  WINPR_ASSERT(operation);
1336
1337
0
  return smartcard_pack_control_call(s, &operation->call.control);
1338
0
}
1339
1340
static LONG smartcard_GetAttrib_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1341
0
{
1342
0
  WINPR_ASSERT(s);
1343
0
  WINPR_ASSERT(operation);
1344
1345
0
  return smartcard_pack_get_attrib_call(s, &operation->call.getAttrib);
1346
0
}
1347
1348
static LONG smartcard_SetAttrib_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1349
0
{
1350
0
  WINPR_ASSERT(s);
1351
0
  WINPR_ASSERT(operation);
1352
1353
0
  return smartcard_pack_set_attrib_call(s, &operation->call.setAttrib);
1354
0
}
1355
1356
LONG smartcard_irp_device_control_encode_request(wStream* s, const SMARTCARD_OPERATION* operation)
1357
0
{
1358
0
  LONG status = SCARD_S_SUCCESS;
1359
1360
0
  WINPR_ASSERT(s);
1361
0
  WINPR_ASSERT(operation);
1362
1363
0
  const UINT32 ioControlCode = operation->ioControlCode;
1364
1365
0
  const size_t headerPos = Stream_GetPosition(s);
1366
0
  Stream_Zero(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH);  /* CommonTypeHeader (8 bytes) */
1367
0
  Stream_Zero(s, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
1368
1369
0
  switch (ioControlCode)
1370
0
  {
1371
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1372
0
      status = smartcard_EstablishContext_encode_request(s, operation);
1373
0
      break;
1374
1375
0
    case SCARD_IOCTL_RELEASECONTEXT:
1376
0
      status = smartcard_ReleaseContext_encode_request(s, operation);
1377
0
      break;
1378
1379
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1380
0
      status = smartcard_IsValidContext_encode_request(s, operation);
1381
0
      break;
1382
1383
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1384
0
      status = smartcard_ListReaderGroupsA_encode_request(s, operation);
1385
0
      break;
1386
1387
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1388
0
      status = smartcard_ListReaderGroupsW_encode_request(s, operation);
1389
0
      break;
1390
1391
0
    case SCARD_IOCTL_LISTREADERSA:
1392
0
      status = smartcard_ListReadersA_encode_request(s, operation);
1393
0
      break;
1394
1395
0
    case SCARD_IOCTL_LISTREADERSW:
1396
0
      status = smartcard_ListReadersW_encode_request(s, operation);
1397
0
      break;
1398
1399
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1400
0
      status = smartcard_GetStatusChangeA_encode_request(s, operation);
1401
0
      break;
1402
1403
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1404
0
      status = smartcard_GetStatusChangeW_encode_request(s, operation);
1405
0
      break;
1406
1407
0
    case SCARD_IOCTL_CANCEL:
1408
0
      status = smartcard_Cancel_encode_request(s, operation);
1409
0
      break;
1410
1411
0
    case SCARD_IOCTL_CONNECTA:
1412
0
      status = smartcard_ConnectA_encode_request(s, operation);
1413
0
      break;
1414
1415
0
    case SCARD_IOCTL_CONNECTW:
1416
0
      status = smartcard_ConnectW_encode_request(s, operation);
1417
0
      break;
1418
1419
0
    case SCARD_IOCTL_RECONNECT:
1420
0
      status = smartcard_Reconnect_encode_request(s, operation);
1421
0
      break;
1422
1423
0
    case SCARD_IOCTL_DISCONNECT:
1424
0
      status = smartcard_Disconnect_encode_request(s, operation);
1425
0
      break;
1426
1427
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1428
0
      status = smartcard_BeginTransaction_encode_request(s, operation);
1429
0
      break;
1430
1431
0
    case SCARD_IOCTL_ENDTRANSACTION:
1432
0
      status = smartcard_EndTransaction_encode_request(s, operation);
1433
0
      break;
1434
1435
0
    case SCARD_IOCTL_STATUSA:
1436
0
      status = smartcard_StatusA_encode_request(s, operation);
1437
0
      break;
1438
1439
0
    case SCARD_IOCTL_STATUSW:
1440
0
      status = smartcard_StatusW_encode_request(s, operation);
1441
0
      break;
1442
1443
0
    case SCARD_IOCTL_TRANSMIT:
1444
0
      status = smartcard_Transmit_encode_request(s, operation);
1445
0
      break;
1446
1447
0
    case SCARD_IOCTL_CONTROL:
1448
0
      status = smartcard_Control_encode_request(s, operation);
1449
0
      break;
1450
1451
0
    case SCARD_IOCTL_GETATTRIB:
1452
0
      status = smartcard_GetAttrib_encode_request(s, operation);
1453
0
      break;
1454
1455
0
    case SCARD_IOCTL_SETATTRIB:
1456
0
      status = smartcard_SetAttrib_encode_request(s, operation);
1457
0
      break;
1458
1459
0
    default:
1460
0
      WLog_WARN(TAG, "unsupported request for %s (0x%08" PRIX32 ")",
1461
0
                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1462
0
      return SCARD_E_UNSUPPORTED_FEATURE;
1463
0
  }
1464
1465
0
  if (status != SCARD_S_SUCCESS)
1466
0
    return status;
1467
1468
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
1469
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
1470
0
  {
1471
0
    const LONG rc = smartcard_pack_write_size_align(s, Stream_GetPosition(s), 8);
1472
0
    if (rc != SCARD_S_SUCCESS)
1473
0
      return rc;
1474
0
  }
1475
1476
0
  const size_t dataEndPos = Stream_GetPosition(s);
1477
0
  const size_t payloadSize = dataEndPos - headerPos;
1478
0
  const size_t objectBufferLength =
1479
0
      payloadSize - SMARTCARD_COMMON_TYPE_HEADER_LENGTH - SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH;
1480
1481
0
  status = smartcard_pack_write_size_align(s, payloadSize, 8);
1482
0
  if (status != SCARD_S_SUCCESS)
1483
0
    return status;
1484
1485
0
  const size_t endPos = Stream_GetPosition(s);
1486
0
  if (!Stream_SetPosition(s, headerPos))
1487
0
    return SCARD_E_BAD_SEEK;
1488
0
  smartcard_pack_common_type_header(s);
1489
0
  smartcard_pack_private_type_header(s, (UINT32)objectBufferLength);
1490
0
  if (!Stream_SetPosition(s, endPos))
1491
0
    return SCARD_E_BAD_SEEK;
1492
0
  Stream_SealLength(s);
1493
1494
0
  return status;
1495
0
}
1496
1497
static void free_reader_states_a(LPSCARD_READERSTATEA rgReaderStates, UINT32 cReaders)
1498
0
{
1499
0
  for (UINT32 x = 0; x < cReaders; x++)
1500
0
  {
1501
0
    SCARD_READERSTATEA* state = &rgReaderStates[x];
1502
0
    free(state->szReader);
1503
0
  }
1504
1505
0
  free(rgReaderStates);
1506
0
}
1507
1508
static void free_reader_states_w(LPSCARD_READERSTATEW rgReaderStates, UINT32 cReaders)
1509
0
{
1510
0
  for (UINT32 x = 0; x < cReaders; x++)
1511
0
  {
1512
0
    SCARD_READERSTATEW* state = &rgReaderStates[x];
1513
0
    free(state->szReader);
1514
0
  }
1515
1516
0
  free(rgReaderStates);
1517
0
}
1518
1519
void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated)
1520
0
{
1521
0
  if (!op)
1522
0
    return;
1523
1524
  /* Free resources in the call union */
1525
0
  switch (op->ioControlCode)
1526
0
  {
1527
0
    case SCARD_IOCTL_CANCEL:
1528
0
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1529
0
    case SCARD_IOCTL_RELEASETARTEDEVENT:
1530
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1531
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1532
0
    case SCARD_IOCTL_RECONNECT:
1533
0
    case SCARD_IOCTL_DISCONNECT:
1534
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1535
0
    case SCARD_IOCTL_ENDTRANSACTION:
1536
0
    case SCARD_IOCTL_STATE:
1537
0
    case SCARD_IOCTL_STATUSA:
1538
0
    case SCARD_IOCTL_STATUSW:
1539
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1540
0
    case SCARD_IOCTL_RELEASECONTEXT:
1541
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1542
0
    case SCARD_IOCTL_GETATTRIB:
1543
0
    case SCARD_IOCTL_GETTRANSMITCOUNT:
1544
0
      break;
1545
0
    case SCARD_IOCTL_LOCATECARDSA:
1546
0
    {
1547
0
      LocateCardsA_Call* call = &op->call.locateCardsA;
1548
0
      free(call->mszCards);
1549
1550
0
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1551
0
    }
1552
0
    break;
1553
0
    case SCARD_IOCTL_LOCATECARDSW:
1554
0
    {
1555
0
      LocateCardsW_Call* call = &op->call.locateCardsW;
1556
0
      free(call->mszCards);
1557
1558
0
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1559
0
    }
1560
0
    break;
1561
0
    case SCARD_IOCTL_LOCATECARDSBYATRA:
1562
0
    {
1563
0
      LocateCardsByATRA_Call* call = &op->call.locateCardsByATRA;
1564
1565
0
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1566
0
    }
1567
0
    break;
1568
0
    case SCARD_IOCTL_LOCATECARDSBYATRW:
1569
0
    {
1570
0
      LocateCardsByATRW_Call* call = &op->call.locateCardsByATRW;
1571
0
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1572
0
    }
1573
0
    break;
1574
0
    case SCARD_IOCTL_FORGETREADERA:
1575
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1576
0
    case SCARD_IOCTL_FORGETREADERGROUPA:
1577
0
    {
1578
0
      ContextAndStringA_Call* call = &op->call.contextAndStringA;
1579
0
      free(call->sz);
1580
0
    }
1581
0
    break;
1582
0
    case SCARD_IOCTL_FORGETREADERW:
1583
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1584
0
    case SCARD_IOCTL_FORGETREADERGROUPW:
1585
0
    {
1586
0
      ContextAndStringW_Call* call = &op->call.contextAndStringW;
1587
0
      free(call->sz);
1588
0
    }
1589
0
    break;
1590
0
    case SCARD_IOCTL_INTRODUCEREADERA:
1591
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1592
0
    case SCARD_IOCTL_ADDREADERTOGROUPA:
1593
0
    {
1594
0
      ContextAndTwoStringA_Call* call = &op->call.contextAndTwoStringA;
1595
0
      free(call->sz1);
1596
0
      free(call->sz2);
1597
0
    }
1598
0
    break;
1599
0
    case SCARD_IOCTL_INTRODUCEREADERW:
1600
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1601
0
    case SCARD_IOCTL_ADDREADERTOGROUPW:
1602
0
    {
1603
0
      ContextAndTwoStringW_Call* call = &op->call.contextAndTwoStringW;
1604
0
      free(call->sz1);
1605
0
      free(call->sz2);
1606
0
    }
1607
0
    break;
1608
0
    case SCARD_IOCTL_LISTREADERSA:
1609
0
    case SCARD_IOCTL_LISTREADERSW:
1610
0
    {
1611
0
      ListReaders_Call* call = &op->call.listReaders;
1612
0
      free(call->mszGroups);
1613
0
    }
1614
0
    break;
1615
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1616
0
    {
1617
0
      GetStatusChangeA_Call* call = &op->call.getStatusChangeA;
1618
0
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1619
0
    }
1620
0
    break;
1621
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1622
0
    {
1623
0
      GetStatusChangeW_Call* call = &op->call.getStatusChangeW;
1624
0
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1625
0
    }
1626
0
    break;
1627
0
    case SCARD_IOCTL_GETREADERICON:
1628
0
    {
1629
0
      GetReaderIcon_Call* call = &op->call.getReaderIcon;
1630
0
      free(call->szReaderName);
1631
0
    }
1632
0
    break;
1633
0
    case SCARD_IOCTL_GETDEVICETYPEID:
1634
0
    {
1635
0
      GetDeviceTypeId_Call* call = &op->call.getDeviceTypeId;
1636
0
      free(call->szReaderName);
1637
0
    }
1638
0
    break;
1639
0
    case SCARD_IOCTL_CONNECTA:
1640
0
    {
1641
0
      ConnectA_Call* call = &op->call.connectA;
1642
0
      free(call->szReader);
1643
0
    }
1644
0
    break;
1645
0
    case SCARD_IOCTL_CONNECTW:
1646
0
    {
1647
0
      ConnectW_Call* call = &op->call.connectW;
1648
0
      free(call->szReader);
1649
0
    }
1650
0
    break;
1651
0
    case SCARD_IOCTL_SETATTRIB:
1652
0
      free(op->call.setAttrib.pbAttr);
1653
0
      break;
1654
0
    case SCARD_IOCTL_TRANSMIT:
1655
0
    {
1656
0
      Transmit_Call* call = &op->call.transmit;
1657
0
      free(call->pbSendBuffer);
1658
0
      free(call->pioSendPci);
1659
0
      free(call->pioRecvPci);
1660
0
    }
1661
0
    break;
1662
0
    case SCARD_IOCTL_CONTROL:
1663
0
    {
1664
0
      Control_Call* call = &op->call.control;
1665
0
      free(call->pvInBuffer);
1666
0
    }
1667
0
    break;
1668
0
    case SCARD_IOCTL_READCACHEA:
1669
0
    {
1670
0
      ReadCacheA_Call* call = &op->call.readCacheA;
1671
0
      free(call->szLookupName);
1672
0
      free(call->Common.CardIdentifier);
1673
0
    }
1674
0
    break;
1675
0
    case SCARD_IOCTL_READCACHEW:
1676
0
    {
1677
0
      ReadCacheW_Call* call = &op->call.readCacheW;
1678
0
      free(call->szLookupName);
1679
0
      free(call->Common.CardIdentifier);
1680
0
    }
1681
0
    break;
1682
0
    case SCARD_IOCTL_WRITECACHEA:
1683
0
    {
1684
0
      WriteCacheA_Call* call = &op->call.writeCacheA;
1685
0
      free(call->szLookupName);
1686
0
      free(call->Common.CardIdentifier);
1687
0
      free(call->Common.pbData);
1688
0
    }
1689
0
    break;
1690
0
    case SCARD_IOCTL_WRITECACHEW:
1691
0
    {
1692
0
      WriteCacheW_Call* call = &op->call.writeCacheW;
1693
0
      free(call->szLookupName);
1694
0
      free(call->Common.CardIdentifier);
1695
0
      free(call->Common.pbData);
1696
0
    }
1697
0
    break;
1698
0
    default:
1699
0
      break;
1700
0
  }
1701
1702
  /* Free resources in the ret union */
1703
0
  switch (op->ioControlCode)
1704
0
  {
1705
0
    case SCARD_IOCTL_LISTREADERSA:
1706
0
    case SCARD_IOCTL_LISTREADERSW:
1707
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1708
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1709
0
    {
1710
0
      ListReaders_Return* ret = &op->ret.listReaders;
1711
0
      free(ret->msz);
1712
0
    }
1713
0
    break;
1714
0
    case SCARD_IOCTL_STATUSA:
1715
0
    case SCARD_IOCTL_STATUSW:
1716
0
    {
1717
0
      Status_Return* ret = &op->ret.status;
1718
0
      free(ret->mszReaderNames);
1719
0
    }
1720
0
    break;
1721
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1722
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1723
0
    {
1724
0
      GetStatusChange_Return* ret = &op->ret.getStatusChange;
1725
0
      free(ret->rgReaderStates);
1726
0
    }
1727
0
    break;
1728
0
    case SCARD_IOCTL_TRANSMIT:
1729
0
    {
1730
0
      Transmit_Return* ret = &op->ret.transmit;
1731
0
      free(ret->pbRecvBuffer);
1732
0
      free(ret->pioRecvPci);
1733
0
    }
1734
0
    break;
1735
0
    case SCARD_IOCTL_CONTROL:
1736
0
    {
1737
0
      Control_Return* call = &op->ret.control;
1738
0
      free(call->pvOutBuffer);
1739
0
    }
1740
0
    break;
1741
0
    case SCARD_IOCTL_GETATTRIB:
1742
0
    {
1743
0
      GetAttrib_Return* ret = &op->ret.getAttrib;
1744
0
      free(ret->pbAttr);
1745
0
    }
1746
0
    break;
1747
0
    default:
1748
0
      break;
1749
0
  }
1750
1751
0
  {
1752
0
    SMARTCARD_OPERATION empty = WINPR_C_ARRAY_INIT;
1753
0
    *op = empty;
1754
0
  }
1755
1756
0
  if (allocated)
1757
0
    free(op);
1758
0
}