Coverage Report

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