Coverage Report

Created: 2026-10-28 06:54

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