Coverage Report

Created: 2026-09-04 06:58

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