Coverage Report

Created: 2026-10-15 06:31

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
1.02k
#define TAG FREERDP_TAG("utils.smartcard.ops")
46
47
static LONG smartcard_call_to_operation_handle(SMARTCARD_OPERATION* operation)
48
2.49k
{
49
2.49k
  WINPR_ASSERT(operation);
50
51
2.49k
  operation->hContext =
52
2.49k
      smartcard_scard_context_native_from_redir(&(operation->call.handles.hContext));
53
2.49k
  operation->hCard = smartcard_scard_handle_native_from_redir(&(operation->call.handles.hCard));
54
55
2.49k
  return SCARD_S_SUCCESS;
56
2.49k
}
57
58
static LONG smartcard_EstablishContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
59
15
{
60
15
  LONG status = 0;
61
62
15
  WINPR_ASSERT(s);
63
15
  WINPR_ASSERT(operation);
64
65
15
  status = smartcard_unpack_establish_context_call(s, &operation->call.establishContext);
66
15
  if (status != SCARD_S_SUCCESS)
67
1
  {
68
1
    return scard_log_status_error(TAG, "smartcard_unpack_establish_context_call", status);
69
1
  }
70
71
14
  return SCARD_S_SUCCESS;
72
15
}
73
74
static LONG smartcard_ReleaseContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
75
33
{
76
33
  LONG status = 0;
77
78
33
  WINPR_ASSERT(s);
79
33
  WINPR_ASSERT(operation);
80
81
33
  status = smartcard_unpack_context_call(s, &operation->call.context, "ReleaseContext");
82
33
  if (status != SCARD_S_SUCCESS)
83
30
    scard_log_status_error(TAG, "smartcard_unpack_context_call", status);
84
85
33
  return status;
86
33
}
87
88
static LONG smartcard_IsValidContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
89
40
{
90
40
  LONG status = 0;
91
92
40
  WINPR_ASSERT(s);
93
40
  WINPR_ASSERT(operation);
94
95
40
  status = smartcard_unpack_context_call(s, &operation->call.context, "IsValidContext");
96
97
40
  return status;
98
40
}
99
100
static LONG smartcard_ListReaderGroupsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
101
8
{
102
8
  LONG status = 0;
103
104
8
  WINPR_ASSERT(s);
105
8
  WINPR_ASSERT(operation);
106
107
8
  status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, FALSE);
108
109
8
  return status;
110
8
}
111
112
static LONG smartcard_ListReaderGroupsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
113
19
{
114
19
  LONG status = 0;
115
116
19
  WINPR_ASSERT(s);
117
19
  WINPR_ASSERT(operation);
118
119
19
  status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, TRUE);
120
121
19
  return status;
122
19
}
123
124
static LONG smartcard_ListReadersA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
125
80
{
126
80
  LONG status = 0;
127
128
80
  WINPR_ASSERT(s);
129
80
  WINPR_ASSERT(operation);
130
131
80
  status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, FALSE);
132
133
80
  return status;
134
80
}
135
136
static LONG smartcard_ListReadersW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
137
47
{
138
47
  LONG status = 0;
139
140
47
  WINPR_ASSERT(s);
141
47
  WINPR_ASSERT(operation);
142
143
47
  status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, TRUE);
144
145
47
  return status;
146
47
}
147
148
static LONG smartcard_ContextAndTwoStringA_decode_request(wStream* s,
149
                                                          SMARTCARD_OPERATION* operation)
150
24
{
151
24
  LONG status = 0;
152
153
24
  WINPR_ASSERT(s);
154
24
  WINPR_ASSERT(operation);
155
156
24
  status =
157
24
      smartcard_unpack_context_and_two_strings_a_call(s, &operation->call.contextAndTwoStringA);
158
159
24
  return status;
160
24
}
161
162
static LONG smartcard_ContextAndTwoStringW_decode_request(wStream* s,
163
                                                          SMARTCARD_OPERATION* operation)
164
24
{
165
24
  LONG status = 0;
166
167
24
  WINPR_ASSERT(s);
168
24
  WINPR_ASSERT(operation);
169
170
24
  status =
171
24
      smartcard_unpack_context_and_two_strings_w_call(s, &operation->call.contextAndTwoStringW);
172
173
24
  return status;
174
24
}
175
176
static LONG smartcard_ContextAndStringA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
177
33
{
178
33
  LONG status = 0;
179
180
33
  WINPR_ASSERT(s);
181
33
  WINPR_ASSERT(operation);
182
183
33
  status = smartcard_unpack_context_and_string_a_call(s, &operation->call.contextAndStringA);
184
185
33
  return status;
186
33
}
187
188
static LONG smartcard_ContextAndStringW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
189
44
{
190
44
  LONG status = 0;
191
192
44
  WINPR_ASSERT(s);
193
44
  WINPR_ASSERT(operation);
194
195
44
  status = smartcard_unpack_context_and_string_w_call(s, &operation->call.contextAndStringW);
196
197
44
  return status;
198
44
}
199
200
static LONG smartcard_LocateCardsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
201
98
{
202
98
  LONG status = 0;
203
204
98
  WINPR_ASSERT(s);
205
98
  WINPR_ASSERT(operation);
206
207
98
  status = smartcard_unpack_locate_cards_a_call(s, &operation->call.locateCardsA);
208
209
98
  return status;
210
98
}
211
212
static LONG smartcard_LocateCardsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
213
93
{
214
93
  LONG status = 0;
215
216
93
  WINPR_ASSERT(s);
217
93
  WINPR_ASSERT(operation);
218
219
93
  status = smartcard_unpack_locate_cards_w_call(s, &operation->call.locateCardsW);
220
221
93
  return status;
222
93
}
223
224
static LONG smartcard_GetStatusChangeA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
225
211
{
226
211
  WINPR_ASSERT(s);
227
211
  WINPR_ASSERT(operation);
228
229
211
  return smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA);
230
211
}
231
232
static LONG smartcard_GetStatusChangeW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
233
225
{
234
225
  WINPR_ASSERT(s);
235
225
  WINPR_ASSERT(operation);
236
237
225
  return smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW);
238
225
}
239
240
static LONG smartcard_Cancel_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
241
35
{
242
35
  LONG status = 0;
243
244
35
  WINPR_ASSERT(s);
245
35
  WINPR_ASSERT(operation);
246
247
35
  status = smartcard_unpack_context_call(s, &operation->call.context, "Cancel");
248
249
35
  return status;
250
35
}
251
252
static LONG smartcard_ConnectA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
253
19
{
254
19
  LONG status = 0;
255
256
19
  WINPR_ASSERT(s);
257
19
  WINPR_ASSERT(operation);
258
259
19
  status = smartcard_unpack_connect_a_call(s, &operation->call.connectA);
260
261
19
  return status;
262
19
}
263
264
static LONG smartcard_ConnectW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
265
18
{
266
18
  LONG status = 0;
267
268
18
  WINPR_ASSERT(s);
269
18
  WINPR_ASSERT(operation);
270
271
18
  status = smartcard_unpack_connect_w_call(s, &operation->call.connectW);
272
273
18
  return status;
274
18
}
275
276
static LONG smartcard_Reconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
277
24
{
278
24
  LONG status = 0;
279
280
24
  WINPR_ASSERT(s);
281
24
  WINPR_ASSERT(operation);
282
283
24
  status = smartcard_unpack_reconnect_call(s, &operation->call.reconnect);
284
285
24
  return status;
286
24
}
287
288
static LONG smartcard_Disconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
289
22
{
290
22
  LONG status = 0;
291
292
22
  WINPR_ASSERT(s);
293
22
  WINPR_ASSERT(operation);
294
295
22
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
296
22
                                                       "Disconnect");
297
298
22
  return status;
299
22
}
300
301
static LONG smartcard_BeginTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
302
13
{
303
13
  LONG status = 0;
304
305
13
  WINPR_ASSERT(s);
306
13
  WINPR_ASSERT(operation);
307
308
13
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
309
13
                                                       "BeginTransaction");
310
311
13
  return status;
312
13
}
313
314
static LONG smartcard_EndTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
315
8
{
316
8
  LONG status = 0;
317
318
8
  WINPR_ASSERT(s);
319
8
  WINPR_ASSERT(operation);
320
321
8
  status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
322
8
                                                       "EndTransaction");
323
324
8
  return status;
325
8
}
326
327
static LONG smartcard_State_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
328
25
{
329
25
  LONG status = 0;
330
331
25
  WINPR_ASSERT(s);
332
25
  WINPR_ASSERT(operation);
333
334
25
  status = smartcard_unpack_state_call(s, &operation->call.state);
335
336
25
  return status;
337
25
}
338
339
static LONG smartcard_StatusA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
340
28
{
341
28
  LONG status = 0;
342
343
28
  WINPR_ASSERT(s);
344
28
  WINPR_ASSERT(operation);
345
346
28
  status = smartcard_unpack_status_call(s, &operation->call.status, FALSE);
347
348
28
  return status;
349
28
}
350
351
static LONG smartcard_StatusW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
352
14
{
353
14
  LONG status = 0;
354
355
14
  WINPR_ASSERT(s);
356
14
  WINPR_ASSERT(operation);
357
358
14
  status = smartcard_unpack_status_call(s, &operation->call.status, TRUE);
359
360
14
  return status;
361
14
}
362
363
static LONG smartcard_Transmit_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
364
293
{
365
293
  LONG status = 0;
366
367
293
  WINPR_ASSERT(s);
368
293
  WINPR_ASSERT(operation);
369
370
293
  status = smartcard_unpack_transmit_call(s, &operation->call.transmit);
371
372
293
  return status;
373
293
}
374
375
static LONG smartcard_Control_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
376
78
{
377
78
  LONG status = 0;
378
379
78
  WINPR_ASSERT(s);
380
78
  WINPR_ASSERT(operation);
381
382
78
  status = smartcard_unpack_control_call(s, &operation->call.control);
383
384
78
  return status;
385
78
}
386
387
static LONG smartcard_GetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
388
37
{
389
37
  LONG status = 0;
390
391
37
  WINPR_ASSERT(s);
392
37
  WINPR_ASSERT(operation);
393
394
37
  status = smartcard_unpack_get_attrib_call(s, &operation->call.getAttrib);
395
396
37
  return status;
397
37
}
398
399
static LONG smartcard_SetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
400
92
{
401
92
  LONG status = 0;
402
403
92
  WINPR_ASSERT(s);
404
92
  WINPR_ASSERT(operation);
405
406
92
  status = smartcard_unpack_set_attrib_call(s, &operation->call.setAttrib);
407
408
92
  return status;
409
92
}
410
411
static LONG smartcard_AccessStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
412
33
{
413
33
  WINPR_ASSERT(s);
414
33
  WINPR_ASSERT(operation);
415
416
33
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
417
19
    return SCARD_F_INTERNAL_ERROR;
418
419
14
  Stream_Read_INT32(s, operation->call.lng.LongValue); /* Unused (4 bytes) */
420
421
14
  return SCARD_S_SUCCESS;
422
33
}
423
424
static LONG smartcard_LocateCardsByATRA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
425
108
{
426
108
  LONG status = 0;
427
428
108
  WINPR_ASSERT(s);
429
108
  WINPR_ASSERT(operation);
430
431
108
  status = smartcard_unpack_locate_cards_by_atr_a_call(s, &operation->call.locateCardsByATRA);
432
433
108
  return status;
434
108
}
435
436
static LONG smartcard_LocateCardsByATRW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
437
161
{
438
161
  LONG status = 0;
439
440
161
  WINPR_ASSERT(s);
441
161
  WINPR_ASSERT(operation);
442
443
161
  status = smartcard_unpack_locate_cards_by_atr_w_call(s, &operation->call.locateCardsByATRW);
444
445
161
  return status;
446
161
}
447
448
static LONG smartcard_ReadCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
449
45
{
450
45
  LONG status = 0;
451
452
45
  WINPR_ASSERT(s);
453
45
  WINPR_ASSERT(operation);
454
455
45
  status = smartcard_unpack_read_cache_a_call(s, &operation->call.readCacheA);
456
457
45
  return status;
458
45
}
459
460
static LONG smartcard_ReadCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
461
41
{
462
41
  LONG status = 0;
463
464
41
  WINPR_ASSERT(s);
465
41
  WINPR_ASSERT(operation);
466
467
41
  status = smartcard_unpack_read_cache_w_call(s, &operation->call.readCacheW);
468
469
41
  return status;
470
41
}
471
472
static LONG smartcard_WriteCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
473
84
{
474
84
  LONG status = 0;
475
476
84
  WINPR_ASSERT(s);
477
84
  WINPR_ASSERT(operation);
478
479
84
  status = smartcard_unpack_write_cache_a_call(s, &operation->call.writeCacheA);
480
481
84
  return status;
482
84
}
483
484
static LONG smartcard_WriteCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
485
70
{
486
70
  LONG status = 0;
487
488
70
  WINPR_ASSERT(s);
489
70
  WINPR_ASSERT(operation);
490
491
70
  status = smartcard_unpack_write_cache_w_call(s, &operation->call.writeCacheW);
492
493
70
  return status;
494
70
}
495
496
static LONG smartcard_GetTransmitCount_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
497
159
{
498
159
  LONG status = 0;
499
500
159
  WINPR_ASSERT(s);
501
159
  WINPR_ASSERT(operation);
502
503
159
  status = smartcard_unpack_get_transmit_count_call(s, &operation->call.getTransmitCount);
504
505
159
  return status;
506
159
}
507
508
static LONG smartcard_ReleaseStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
509
41
{
510
41
  WINPR_UNUSED(s);
511
41
  WINPR_UNUSED(operation);
512
41
  WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
513
41
                 "SCARD_IOCTL_RELEASETARTEDEVENT is not supported");
514
41
  return SCARD_E_UNSUPPORTED_FEATURE;
515
41
}
516
517
static LONG smartcard_GetReaderIcon_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
518
10
{
519
10
  LONG status = 0;
520
521
10
  WINPR_ASSERT(s);
522
10
  WINPR_ASSERT(operation);
523
524
10
  status = smartcard_unpack_get_reader_icon_call(s, &operation->call.getReaderIcon);
525
526
10
  return status;
527
10
}
528
529
static LONG smartcard_GetDeviceTypeId_decode_request(wStream* s, SMARTCARD_OPERATION* operation)
530
2
{
531
2
  LONG status = 0;
532
533
2
  WINPR_ASSERT(s);
534
2
  WINPR_ASSERT(operation);
535
536
2
  status = smartcard_unpack_get_device_type_id_call(s, &operation->call.getDeviceTypeId);
537
538
2
  return status;
539
2
}
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
3.02k
{
550
3.02k
  LONG status = 0;
551
3.02k
  UINT32 offset = 0;
552
553
3.02k
  WINPR_ASSERT(s);
554
3.02k
  WINPR_ASSERT(operation);
555
556
  /* Device Control Request */
557
558
3.02k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH))
559
11
    return SCARD_F_INTERNAL_ERROR;
560
561
3.00k
  const UINT32 outputBufferLength = Stream_Get_UINT32(s); /* OutputBufferLength (4 bytes) */
562
3.00k
  const UINT32 inputBufferLength = Stream_Get_UINT32(s);  /* InputBufferLength (4 bytes) */
563
3.00k
  const UINT32 ioControlCode = Stream_Get_UINT32(s);      /* IoControlCode (4 bytes) */
564
3.00k
  Stream_Seek(s, 20);                                     /* Padding (20 bytes) */
565
3.00k
  operation->ioControlCode = ioControlCode;
566
3.00k
  operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE);
567
3.00k
  operation->outputBufferLength = outputBufferLength;
568
569
3.00k
  if (Stream_Length(s) != (Stream_GetPosition(s) + inputBufferLength))
570
246
  {
571
246
    WLog_WARN(TAG, "InputBufferLength mismatch: Actual: %" PRIuz " Expected: %" PRIuz "",
572
246
              Stream_Length(s), Stream_GetPosition(s) + inputBufferLength);
573
246
    return SCARD_F_INTERNAL_ERROR;
574
246
  }
575
576
2.76k
  WLog_DBG(TAG, "%s (0x%08" PRIX32 ") FileId: %" PRIu32 " CompletionId: %" PRIu32 "",
577
2.76k
           scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, FileId, CompletionId);
578
579
2.76k
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
580
2.73k
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
581
2.68k
  {
582
2.68k
    status = smartcard_unpack_common_type_header(s);
583
2.68k
    if (status != SCARD_S_SUCCESS)
584
189
      return status;
585
586
2.50k
    status = smartcard_unpack_private_type_header(s);
587
2.50k
    if (status != SCARD_S_SUCCESS)
588
79
      return status;
589
2.50k
  }
590
591
  /* Decode */
592
2.49k
  switch (ioControlCode)
593
2.49k
  {
594
15
    case SCARD_IOCTL_ESTABLISHCONTEXT:
595
15
      status = smartcard_EstablishContext_decode_request(s, operation);
596
15
      break;
597
598
33
    case SCARD_IOCTL_RELEASECONTEXT:
599
33
      status = smartcard_ReleaseContext_decode_request(s, operation);
600
33
      break;
601
602
40
    case SCARD_IOCTL_ISVALIDCONTEXT:
603
40
      status = smartcard_IsValidContext_decode_request(s, operation);
604
40
      break;
605
606
8
    case SCARD_IOCTL_LISTREADERGROUPSA:
607
8
      status = smartcard_ListReaderGroupsA_decode_request(s, operation);
608
8
      break;
609
610
19
    case SCARD_IOCTL_LISTREADERGROUPSW:
611
19
      status = smartcard_ListReaderGroupsW_decode_request(s, operation);
612
19
      break;
613
614
80
    case SCARD_IOCTL_LISTREADERSA:
615
80
      status = smartcard_ListReadersA_decode_request(s, operation);
616
80
      break;
617
618
47
    case SCARD_IOCTL_LISTREADERSW:
619
47
      status = smartcard_ListReadersW_decode_request(s, operation);
620
47
      break;
621
622
3
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
623
3
      status = smartcard_ContextAndStringA_decode_request(s, operation);
624
3
      break;
625
626
5
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
627
5
      status = smartcard_ContextAndStringW_decode_request(s, operation);
628
5
      break;
629
630
18
    case SCARD_IOCTL_FORGETREADERGROUPA:
631
18
      status = smartcard_ContextAndStringA_decode_request(s, operation);
632
18
      break;
633
634
33
    case SCARD_IOCTL_FORGETREADERGROUPW:
635
33
      status = smartcard_ContextAndStringW_decode_request(s, operation);
636
33
      break;
637
638
7
    case SCARD_IOCTL_INTRODUCEREADERA:
639
7
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
640
7
      break;
641
642
7
    case SCARD_IOCTL_INTRODUCEREADERW:
643
7
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
644
7
      break;
645
646
12
    case SCARD_IOCTL_FORGETREADERA:
647
12
      status = smartcard_ContextAndStringA_decode_request(s, operation);
648
12
      break;
649
650
6
    case SCARD_IOCTL_FORGETREADERW:
651
6
      status = smartcard_ContextAndStringW_decode_request(s, operation);
652
6
      break;
653
654
9
    case SCARD_IOCTL_ADDREADERTOGROUPA:
655
9
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
656
9
      break;
657
658
9
    case SCARD_IOCTL_ADDREADERTOGROUPW:
659
9
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
660
9
      break;
661
662
8
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
663
8
      status = smartcard_ContextAndTwoStringA_decode_request(s, operation);
664
8
      break;
665
666
8
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
667
8
      status = smartcard_ContextAndTwoStringW_decode_request(s, operation);
668
8
      break;
669
670
98
    case SCARD_IOCTL_LOCATECARDSA:
671
98
      status = smartcard_LocateCardsA_decode_request(s, operation);
672
98
      break;
673
674
93
    case SCARD_IOCTL_LOCATECARDSW:
675
93
      status = smartcard_LocateCardsW_decode_request(s, operation);
676
93
      break;
677
678
211
    case SCARD_IOCTL_GETSTATUSCHANGEA:
679
211
      status = smartcard_GetStatusChangeA_decode_request(s, operation);
680
211
      break;
681
682
225
    case SCARD_IOCTL_GETSTATUSCHANGEW:
683
225
      status = smartcard_GetStatusChangeW_decode_request(s, operation);
684
225
      break;
685
686
35
    case SCARD_IOCTL_CANCEL:
687
35
      status = smartcard_Cancel_decode_request(s, operation);
688
35
      break;
689
690
19
    case SCARD_IOCTL_CONNECTA:
691
19
      status = smartcard_ConnectA_decode_request(s, operation);
692
19
      break;
693
694
18
    case SCARD_IOCTL_CONNECTW:
695
18
      status = smartcard_ConnectW_decode_request(s, operation);
696
18
      break;
697
698
24
    case SCARD_IOCTL_RECONNECT:
699
24
      status = smartcard_Reconnect_decode_request(s, operation);
700
24
      break;
701
702
22
    case SCARD_IOCTL_DISCONNECT:
703
22
      status = smartcard_Disconnect_decode_request(s, operation);
704
22
      break;
705
706
13
    case SCARD_IOCTL_BEGINTRANSACTION:
707
13
      status = smartcard_BeginTransaction_decode_request(s, operation);
708
13
      break;
709
710
8
    case SCARD_IOCTL_ENDTRANSACTION:
711
8
      status = smartcard_EndTransaction_decode_request(s, operation);
712
8
      break;
713
714
25
    case SCARD_IOCTL_STATE:
715
25
      status = smartcard_State_decode_request(s, operation);
716
25
      break;
717
718
28
    case SCARD_IOCTL_STATUSA:
719
28
      status = smartcard_StatusA_decode_request(s, operation);
720
28
      break;
721
722
14
    case SCARD_IOCTL_STATUSW:
723
14
      status = smartcard_StatusW_decode_request(s, operation);
724
14
      break;
725
726
293
    case SCARD_IOCTL_TRANSMIT:
727
293
      status = smartcard_Transmit_decode_request(s, operation);
728
293
      break;
729
730
78
    case SCARD_IOCTL_CONTROL:
731
78
      status = smartcard_Control_decode_request(s, operation);
732
78
      break;
733
734
37
    case SCARD_IOCTL_GETATTRIB:
735
37
      status = smartcard_GetAttrib_decode_request(s, operation);
736
37
      break;
737
738
92
    case SCARD_IOCTL_SETATTRIB:
739
92
      status = smartcard_SetAttrib_decode_request(s, operation);
740
92
      break;
741
742
33
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
743
33
      status = smartcard_AccessStartedEvent_decode_request(s, operation);
744
33
      break;
745
746
108
    case SCARD_IOCTL_LOCATECARDSBYATRA:
747
108
      status = smartcard_LocateCardsByATRA_decode_request(s, operation);
748
108
      break;
749
750
161
    case SCARD_IOCTL_LOCATECARDSBYATRW:
751
161
      status = smartcard_LocateCardsByATRW_decode_request(s, operation);
752
161
      break;
753
754
45
    case SCARD_IOCTL_READCACHEA:
755
45
      status = smartcard_ReadCacheA_decode_request(s, operation);
756
45
      break;
757
758
41
    case SCARD_IOCTL_READCACHEW:
759
41
      status = smartcard_ReadCacheW_decode_request(s, operation);
760
41
      break;
761
762
84
    case SCARD_IOCTL_WRITECACHEA:
763
84
      status = smartcard_WriteCacheA_decode_request(s, operation);
764
84
      break;
765
766
70
    case SCARD_IOCTL_WRITECACHEW:
767
70
      status = smartcard_WriteCacheW_decode_request(s, operation);
768
70
      break;
769
770
159
    case SCARD_IOCTL_GETTRANSMITCOUNT:
771
159
      status = smartcard_GetTransmitCount_decode_request(s, operation);
772
159
      break;
773
774
41
    case SCARD_IOCTL_RELEASETARTEDEVENT:
775
41
      status = smartcard_ReleaseStartedEvent_decode_request(s, operation);
776
41
      break;
777
778
10
    case SCARD_IOCTL_GETREADERICON:
779
10
      status = smartcard_GetReaderIcon_decode_request(s, operation);
780
10
      break;
781
782
2
    case SCARD_IOCTL_GETDEVICETYPEID:
783
2
      status = smartcard_GetDeviceTypeId_decode_request(s, operation);
784
2
      break;
785
786
41
    default:
787
41
      status = SCARD_F_INTERNAL_ERROR;
788
41
      break;
789
2.49k
  }
790
791
2.49k
  smartcard_call_to_operation_handle(operation);
792
793
2.49k
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
794
2.46k
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
795
2.42k
  {
796
2.42k
    offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH);
797
2.42k
    if (smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8) < 0)
798
710
      return STATUS_INVALID_PARAMETER;
799
2.42k
  }
800
801
1.78k
  if (Stream_GetPosition(s) < Stream_Length(s))
802
996
  {
803
996
    size_t difference = 0;
804
996
    difference = Stream_Length(s) - Stream_GetPosition(s);
805
996
    WLog_WARN(TAG,
806
996
              "IRP was not fully parsed %s (%s [0x%08" PRIX32 "]): Actual: %" PRIuz
807
996
              ", Expected: %" PRIuz ", Difference: %" PRIuz "",
808
996
              scard_get_ioctl_string(ioControlCode, TRUE),
809
996
              scard_get_ioctl_string(ioControlCode, FALSE), ioControlCode,
810
996
              Stream_GetPosition(s), Stream_Length(s), difference);
811
996
    winpr_HexDump(TAG, WLOG_WARN, Stream_ConstPointer(s), difference);
812
996
  }
813
814
1.78k
  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
1.78k
  return status;
826
2.49k
}
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
430
{
1499
474
  for (UINT32 x = 0; x < cReaders; x++)
1500
44
  {
1501
44
    SCARD_READERSTATEA* state = &rgReaderStates[x];
1502
44
    free(state->szReader);
1503
44
  }
1504
1505
430
  free(rgReaderStates);
1506
430
}
1507
1508
static void free_reader_states_w(LPSCARD_READERSTATEW rgReaderStates, UINT32 cReaders)
1509
493
{
1510
543
  for (UINT32 x = 0; x < cReaders; x++)
1511
50
  {
1512
50
    SCARD_READERSTATEW* state = &rgReaderStates[x];
1513
50
    free(state->szReader);
1514
50
  }
1515
1516
493
  free(rgReaderStates);
1517
493
}
1518
1519
void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated)
1520
3.02k
{
1521
3.02k
  if (!op)
1522
0
    return;
1523
1524
  /* Free resources in the call union */
1525
3.02k
  switch (op->ioControlCode)
1526
3.02k
  {
1527
38
    case SCARD_IOCTL_CANCEL:
1528
75
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1529
117
    case SCARD_IOCTL_RELEASETARTEDEVENT:
1530
127
    case SCARD_IOCTL_LISTREADERGROUPSA:
1531
148
    case SCARD_IOCTL_LISTREADERGROUPSW:
1532
178
    case SCARD_IOCTL_RECONNECT:
1533
202
    case SCARD_IOCTL_DISCONNECT:
1534
219
    case SCARD_IOCTL_BEGINTRANSACTION:
1535
229
    case SCARD_IOCTL_ENDTRANSACTION:
1536
256
    case SCARD_IOCTL_STATE:
1537
286
    case SCARD_IOCTL_STATUSA:
1538
302
    case SCARD_IOCTL_STATUSW:
1539
325
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1540
362
    case SCARD_IOCTL_RELEASECONTEXT:
1541
405
    case SCARD_IOCTL_ISVALIDCONTEXT:
1542
444
    case SCARD_IOCTL_GETATTRIB:
1543
608
    case SCARD_IOCTL_GETTRANSMITCOUNT:
1544
608
      break;
1545
100
    case SCARD_IOCTL_LOCATECARDSA:
1546
100
    {
1547
100
      LocateCardsA_Call* call = &op->call.locateCardsA;
1548
100
      free(call->mszCards);
1549
1550
100
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1551
100
    }
1552
100
    break;
1553
100
    case SCARD_IOCTL_LOCATECARDSW:
1554
100
    {
1555
100
      LocateCardsW_Call* call = &op->call.locateCardsW;
1556
100
      free(call->mszCards);
1557
1558
100
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1559
100
    }
1560
100
    break;
1561
112
    case SCARD_IOCTL_LOCATECARDSBYATRA:
1562
112
    {
1563
112
      LocateCardsByATRA_Call* call = &op->call.locateCardsByATRA;
1564
112
      free(call->rgAtrMasks);
1565
112
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1566
112
    }
1567
112
    break;
1568
163
    case SCARD_IOCTL_LOCATECARDSBYATRW:
1569
163
    {
1570
163
      LocateCardsByATRW_Call* call = &op->call.locateCardsByATRW;
1571
163
      free(call->rgAtrMasks);
1572
163
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1573
163
    }
1574
163
    break;
1575
14
    case SCARD_IOCTL_FORGETREADERA:
1576
22
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1577
42
    case SCARD_IOCTL_FORGETREADERGROUPA:
1578
42
    {
1579
42
      ContextAndStringA_Call* call = &op->call.contextAndStringA;
1580
42
      free(call->sz);
1581
42
    }
1582
42
    break;
1583
10
    case SCARD_IOCTL_FORGETREADERW:
1584
17
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1585
52
    case SCARD_IOCTL_FORGETREADERGROUPW:
1586
52
    {
1587
52
      ContextAndStringW_Call* call = &op->call.contextAndStringW;
1588
52
      free(call->sz);
1589
52
    }
1590
52
    break;
1591
11
    case SCARD_IOCTL_INTRODUCEREADERA:
1592
22
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1593
33
    case SCARD_IOCTL_ADDREADERTOGROUPA:
1594
33
    {
1595
33
      ContextAndTwoStringA_Call* call = &op->call.contextAndTwoStringA;
1596
33
      free(call->sz1);
1597
33
      free(call->sz2);
1598
33
    }
1599
33
    break;
1600
10
    case SCARD_IOCTL_INTRODUCEREADERW:
1601
25
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1602
36
    case SCARD_IOCTL_ADDREADERTOGROUPW:
1603
36
    {
1604
36
      ContextAndTwoStringW_Call* call = &op->call.contextAndTwoStringW;
1605
36
      free(call->sz1);
1606
36
      free(call->sz2);
1607
36
    }
1608
36
    break;
1609
83
    case SCARD_IOCTL_LISTREADERSA:
1610
132
    case SCARD_IOCTL_LISTREADERSW:
1611
132
    {
1612
132
      ListReaders_Call* call = &op->call.listReaders;
1613
132
      free(call->mszGroups);
1614
132
    }
1615
132
    break;
1616
218
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1617
218
    {
1618
218
      GetStatusChangeA_Call* call = &op->call.getStatusChangeA;
1619
218
      free_reader_states_a(call->rgReaderStates, call->cReaders);
1620
218
    }
1621
218
    break;
1622
230
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1623
230
    {
1624
230
      GetStatusChangeW_Call* call = &op->call.getStatusChangeW;
1625
230
      free_reader_states_w(call->rgReaderStates, call->cReaders);
1626
230
    }
1627
230
    break;
1628
12
    case SCARD_IOCTL_GETREADERICON:
1629
12
    {
1630
12
      GetReaderIcon_Call* call = &op->call.getReaderIcon;
1631
12
      free(call->szReaderName);
1632
12
    }
1633
12
    break;
1634
5
    case SCARD_IOCTL_GETDEVICETYPEID:
1635
5
    {
1636
5
      GetDeviceTypeId_Call* call = &op->call.getDeviceTypeId;
1637
5
      free(call->szReaderName);
1638
5
    }
1639
5
    break;
1640
22
    case SCARD_IOCTL_CONNECTA:
1641
22
    {
1642
22
      ConnectA_Call* call = &op->call.connectA;
1643
22
      free(call->szReader);
1644
22
    }
1645
22
    break;
1646
21
    case SCARD_IOCTL_CONNECTW:
1647
21
    {
1648
21
      ConnectW_Call* call = &op->call.connectW;
1649
21
      free(call->szReader);
1650
21
    }
1651
21
    break;
1652
96
    case SCARD_IOCTL_SETATTRIB:
1653
96
      free(op->call.setAttrib.pbAttr);
1654
96
      break;
1655
296
    case SCARD_IOCTL_TRANSMIT:
1656
296
    {
1657
296
      Transmit_Call* call = &op->call.transmit;
1658
296
      free(call->pbSendBuffer);
1659
296
      free(call->pioSendPci);
1660
296
      free(call->pioRecvPci);
1661
296
    }
1662
296
    break;
1663
84
    case SCARD_IOCTL_CONTROL:
1664
84
    {
1665
84
      Control_Call* call = &op->call.control;
1666
84
      free(call->pvInBuffer);
1667
84
    }
1668
84
    break;
1669
47
    case SCARD_IOCTL_READCACHEA:
1670
47
    {
1671
47
      ReadCacheA_Call* call = &op->call.readCacheA;
1672
47
      free(call->szLookupName);
1673
47
      free(call->Common.CardIdentifier);
1674
47
    }
1675
47
    break;
1676
45
    case SCARD_IOCTL_READCACHEW:
1677
45
    {
1678
45
      ReadCacheW_Call* call = &op->call.readCacheW;
1679
45
      free(call->szLookupName);
1680
45
      free(call->Common.CardIdentifier);
1681
45
    }
1682
45
    break;
1683
89
    case SCARD_IOCTL_WRITECACHEA:
1684
89
    {
1685
89
      WriteCacheA_Call* call = &op->call.writeCacheA;
1686
89
      free(call->szLookupName);
1687
89
      free(call->Common.CardIdentifier);
1688
89
      free(call->Common.pbData);
1689
89
    }
1690
89
    break;
1691
72
    case SCARD_IOCTL_WRITECACHEW:
1692
72
    {
1693
72
      WriteCacheW_Call* call = &op->call.writeCacheW;
1694
72
      free(call->szLookupName);
1695
72
      free(call->Common.CardIdentifier);
1696
72
      free(call->Common.pbData);
1697
72
    }
1698
72
    break;
1699
405
    default:
1700
405
      break;
1701
3.02k
  }
1702
1703
  /* Free resources in the ret union */
1704
3.02k
  switch (op->ioControlCode)
1705
3.02k
  {
1706
83
    case SCARD_IOCTL_LISTREADERSA:
1707
132
    case SCARD_IOCTL_LISTREADERSW:
1708
142
    case SCARD_IOCTL_LISTREADERGROUPSA:
1709
163
    case SCARD_IOCTL_LISTREADERGROUPSW:
1710
163
    {
1711
163
      ListReaders_Return* ret = &op->ret.listReaders;
1712
163
      free(ret->msz);
1713
163
    }
1714
163
    break;
1715
30
    case SCARD_IOCTL_STATUSA:
1716
46
    case SCARD_IOCTL_STATUSW:
1717
46
    {
1718
46
      Status_Return* ret = &op->ret.status;
1719
46
      free(ret->mszReaderNames);
1720
46
    }
1721
46
    break;
1722
218
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1723
448
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1724
448
    {
1725
448
      GetStatusChange_Return* ret = &op->ret.getStatusChange;
1726
448
      free(ret->rgReaderStates);
1727
448
    }
1728
448
    break;
1729
296
    case SCARD_IOCTL_TRANSMIT:
1730
296
    {
1731
296
      Transmit_Return* ret = &op->ret.transmit;
1732
296
      free(ret->pbRecvBuffer);
1733
296
      free(ret->pioRecvPci);
1734
296
    }
1735
296
    break;
1736
84
    case SCARD_IOCTL_CONTROL:
1737
84
    {
1738
84
      Control_Return* call = &op->ret.control;
1739
84
      free(call->pvOutBuffer);
1740
84
    }
1741
84
    break;
1742
39
    case SCARD_IOCTL_GETATTRIB:
1743
39
    {
1744
39
      GetAttrib_Return* ret = &op->ret.getAttrib;
1745
39
      free(ret->pbAttr);
1746
39
    }
1747
39
    break;
1748
1.94k
    default:
1749
1.94k
      break;
1750
3.02k
  }
1751
1752
3.02k
  {
1753
3.02k
    SMARTCARD_OPERATION empty = WINPR_C_ARRAY_INIT;
1754
3.02k
    *op = empty;
1755
3.02k
  }
1756
1757
3.02k
  if (allocated)
1758
0
    free(op);
1759
3.02k
}