Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/libfreerdp/utils/smartcard_call.c
Line
Count
Source (jump to first uncovered line)
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/library.h>
34
#include <winpr/smartcard.h>
35
36
#include <freerdp/freerdp.h>
37
#include <freerdp/channels/rdpdr.h>
38
#include <freerdp/channels/scard.h>
39
40
#include <freerdp/utils/rdpdr_utils.h>
41
#include <freerdp/utils/smartcard_pack.h>
42
#include <freerdp/utils/smartcard_call.h>
43
44
#include "smartcard_pack.h"
45
46
#include <freerdp/log.h>
47
0
#define SCARD_TAG FREERDP_TAG("utils.smartcard.call")
48
49
#if defined(WITH_SMARTCARD_EMULATE)
50
#include <freerdp/emulate/scard/smartcard_emulate.h>
51
52
#define wrap(ctx, fkt, ...)                                             \
53
0
  ctx->useEmulatedCard ? Emulate_##fkt(ctx->emulation, ##__VA_ARGS__) \
54
0
                       : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
55
0
#define wrap_ptr(ctx, fkt, ...) wrap(ctx, fkt, ##__VA_ARGS__)
56
#else
57
#define wrap(ctx, fkt, ...) \
58
  ctx->useEmulatedCard ? SCARD_F_INTERNAL_ERROR : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
59
#define wrap_ptr(ctx, fkt, ...) \
60
  ctx->useEmulatedCard ? NULL : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
61
#endif
62
63
struct s_scard_call_context
64
{
65
  BOOL useEmulatedCard;
66
  HANDLE StartedEvent;
67
  wLinkedList* names;
68
  wHashTable* rgSCardContextList;
69
#if defined(WITH_SMARTCARD_EMULATE)
70
  SmartcardEmulationContext* emulation;
71
#endif
72
  HANDLE hWinSCardLibrary;
73
  SCardApiFunctionTable WinSCardApi;
74
  const SCardApiFunctionTable* pWinSCardApi;
75
  HANDLE stopEvent;
76
  void* userdata;
77
78
  void* (*fn_new)(void*, SCARDCONTEXT);
79
  void (*fn_free)(void*);
80
  wLog* log;
81
};
82
83
struct s_scard_context_element
84
{
85
  void* context;
86
  void (*fn_free)(void*);
87
};
88
89
static void context_free(void* arg);
90
91
static LONG smartcard_EstablishContext_Call(scard_call_context* smartcard, wStream* out,
92
                                            SMARTCARD_OPERATION* operation)
93
0
{
94
0
  LONG status = 0;
95
0
  SCARDCONTEXT hContext = { 0 };
96
0
  EstablishContext_Return ret = { 0 };
97
0
  EstablishContext_Call* call = &operation->call.establishContext;
98
0
  status = ret.ReturnCode =
99
0
      wrap(smartcard, SCardEstablishContext, call->dwScope, NULL, NULL, &hContext);
100
101
0
  if (ret.ReturnCode == SCARD_S_SUCCESS)
102
0
  {
103
0
    const void* key = (void*)(size_t)hContext;
104
0
    struct s_scard_context_element* pContext =
105
0
        calloc(1, sizeof(struct s_scard_context_element));
106
0
    if (!pContext)
107
0
      return STATUS_NO_MEMORY;
108
109
0
    pContext->fn_free = smartcard->fn_free;
110
111
0
    if (smartcard->fn_new)
112
0
    {
113
0
      pContext->context = smartcard->fn_new(smartcard->userdata, hContext);
114
0
      if (!pContext->context)
115
0
      {
116
0
        free(pContext);
117
0
        return STATUS_NO_MEMORY;
118
0
      }
119
0
    }
120
121
0
    if (!HashTable_Insert(smartcard->rgSCardContextList, key, (void*)pContext))
122
0
    {
123
0
      WLog_Print(smartcard->log, WLOG_ERROR, "ListDictionary_Add failed!");
124
0
      context_free(pContext);
125
0
      return STATUS_INTERNAL_ERROR;
126
0
    }
127
0
  }
128
0
  else
129
0
  {
130
0
    return scard_log_status_error_wlog(smartcard->log, "SCardEstablishContext", status);
131
0
  }
132
133
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of pContext
134
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), hContext);
135
136
0
  status = smartcard_pack_establish_context_return(out, &ret);
137
0
  if (status != SCARD_S_SUCCESS)
138
0
  {
139
0
    return scard_log_status_error_wlog(smartcard->log,
140
0
                                       "smartcard_pack_establish_context_return", status);
141
0
  }
142
143
0
  return ret.ReturnCode;
144
0
}
145
146
static LONG smartcard_ReleaseContext_Call(scard_call_context* smartcard,
147
                                          WINPR_ATTR_UNUSED wStream* out,
148
                                          SMARTCARD_OPERATION* operation)
149
0
{
150
0
  Long_Return ret = { 0 };
151
152
0
  WINPR_ASSERT(smartcard);
153
0
  WINPR_ASSERT(out);
154
0
  WINPR_ASSERT(operation);
155
156
0
  ret.ReturnCode = wrap(smartcard, SCardReleaseContext, operation->hContext);
157
158
0
  if (ret.ReturnCode == SCARD_S_SUCCESS)
159
0
    HashTable_Remove(smartcard->rgSCardContextList, (void*)operation->hContext);
160
0
  else
161
0
  {
162
0
    return scard_log_status_error_wlog(smartcard->log, "SCardReleaseContext", ret.ReturnCode);
163
0
  }
164
165
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "ReleaseContext");
166
0
  return ret.ReturnCode;
167
0
}
168
169
static LONG smartcard_IsValidContext_Call(scard_call_context* smartcard,
170
                                          WINPR_ATTR_UNUSED wStream* out,
171
                                          SMARTCARD_OPERATION* operation)
172
0
{
173
0
  Long_Return ret = { 0 };
174
175
0
  WINPR_ASSERT(smartcard);
176
0
  WINPR_ASSERT(out);
177
0
  WINPR_ASSERT(operation);
178
179
0
  ret.ReturnCode = wrap(smartcard, SCardIsValidContext, operation->hContext);
180
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IsValidContext");
181
0
  return ret.ReturnCode;
182
0
}
183
184
static LONG smartcard_ListReaderGroupsA_Call(scard_call_context* smartcard, wStream* out,
185
                                             SMARTCARD_OPERATION* operation)
186
0
{
187
0
  LONG status = 0;
188
0
  ListReaderGroups_Return ret = { 0 };
189
0
  LPSTR mszGroups = NULL;
190
0
  DWORD cchGroups = 0;
191
192
0
  WINPR_ASSERT(smartcard);
193
0
  WINPR_ASSERT(out);
194
0
  WINPR_ASSERT(operation);
195
196
0
  cchGroups = SCARD_AUTOALLOCATE;
197
0
  ret.ReturnCode =
198
0
      wrap(smartcard, SCardListReaderGroupsA, operation->hContext, (LPSTR)&mszGroups, &cchGroups);
199
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchGroups == SCARD_AUTOALLOCATE))
200
0
    return SCARD_F_UNKNOWN_ERROR;
201
202
0
  ret.msz = (BYTE*)mszGroups;
203
0
  ret.cBytes = cchGroups;
204
205
0
  status = smartcard_pack_list_reader_groups_return(out, &ret, FALSE);
206
207
0
  if (status != SCARD_S_SUCCESS)
208
0
    return status;
209
210
0
  if (mszGroups)
211
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszGroups);
212
213
0
  return ret.ReturnCode;
214
0
}
215
216
static LONG smartcard_ListReaderGroupsW_Call(scard_call_context* smartcard, wStream* out,
217
                                             SMARTCARD_OPERATION* operation)
218
0
{
219
0
  LONG status = 0;
220
0
  ListReaderGroups_Return ret = { 0 };
221
0
  LPWSTR mszGroups = NULL;
222
0
  DWORD cchGroups = 0;
223
224
0
  WINPR_ASSERT(smartcard);
225
0
  WINPR_ASSERT(out);
226
0
  WINPR_ASSERT(operation);
227
228
0
  cchGroups = SCARD_AUTOALLOCATE;
229
0
  status = ret.ReturnCode = wrap(smartcard, SCardListReaderGroupsW, operation->hContext,
230
0
                                 (LPWSTR)&mszGroups, &cchGroups);
231
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchGroups == SCARD_AUTOALLOCATE))
232
0
    return SCARD_F_UNKNOWN_ERROR;
233
234
0
  ret.msz = (BYTE*)mszGroups;
235
236
0
  WINPR_ASSERT(cchGroups < SCARD_AUTOALLOCATE / sizeof(WCHAR));
237
0
  const size_t blen = sizeof(WCHAR) * cchGroups;
238
0
  WINPR_ASSERT(blen <= UINT32_MAX);
239
0
  ret.cBytes = (UINT32)blen;
240
241
0
  if (status != SCARD_S_SUCCESS)
242
0
    return status;
243
244
0
  status = smartcard_pack_list_reader_groups_return(out, &ret, TRUE);
245
246
0
  if (status != SCARD_S_SUCCESS)
247
0
    return status;
248
249
0
  if (mszGroups)
250
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszGroups);
251
252
0
  return ret.ReturnCode;
253
0
}
254
255
static BOOL filter_match(wLinkedList* list, LPCSTR reader, size_t readerLen)
256
0
{
257
0
  if (readerLen < 1)
258
0
    return FALSE;
259
260
0
  LinkedList_Enumerator_Reset(list);
261
262
0
  while (LinkedList_Enumerator_MoveNext(list))
263
0
  {
264
0
    const char* filter = LinkedList_Enumerator_Current(list);
265
266
0
    if (filter)
267
0
    {
268
0
      if (strstr(reader, filter) != NULL)
269
0
        return TRUE;
270
0
    }
271
0
  }
272
273
0
  return FALSE;
274
0
}
275
276
static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD cchReaders)
277
0
{
278
0
  size_t rpos = 0;
279
0
  size_t wpos = 0;
280
281
0
  if (*mszReaders == NULL || LinkedList_Count(list) < 1)
282
0
    return cchReaders;
283
284
0
  do
285
0
  {
286
0
    LPCSTR rreader = &(*mszReaders)[rpos];
287
0
    LPSTR wreader = &(*mszReaders)[wpos];
288
0
    size_t readerLen = strnlen(rreader, cchReaders - rpos);
289
290
0
    rpos += readerLen + 1;
291
292
0
    if (filter_match(list, rreader, readerLen))
293
0
    {
294
0
      if (rreader != wreader)
295
0
        memmove(wreader, rreader, readerLen + 1);
296
297
0
      wpos += readerLen + 1;
298
0
    }
299
0
  } while (rpos < cchReaders);
300
301
  /* this string must be double 0 terminated */
302
0
  if (rpos != wpos)
303
0
  {
304
0
    if (wpos >= cchReaders)
305
0
      return 0;
306
307
0
    (*mszReaders)[wpos++] = '\0';
308
0
  }
309
310
0
  return (DWORD)wpos;
311
0
}
312
313
static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWORD cchReaders)
314
0
{
315
0
  DWORD rc = 0;
316
0
  LPSTR readers = NULL;
317
318
0
  if (LinkedList_Count(list) < 1)
319
0
    return cchReaders;
320
321
0
  readers = ConvertMszWCharNToUtf8Alloc(*mszReaders, cchReaders, NULL);
322
323
0
  if (!readers)
324
0
  {
325
0
    free(readers);
326
0
    return 0;
327
0
  }
328
329
0
  free(*mszReaders);
330
0
  *mszReaders = NULL;
331
0
  rc = filter_device_by_name_a(list, &readers, cchReaders);
332
333
0
  *mszReaders = ConvertMszUtf8NToWCharAlloc(readers, rc, NULL);
334
0
  if (!*mszReaders)
335
0
    rc = 0;
336
337
0
  free(readers);
338
0
  return rc;
339
0
}
340
341
static LONG smartcard_ListReadersA_Call(scard_call_context* smartcard, wStream* out,
342
                                        SMARTCARD_OPERATION* operation)
343
0
{
344
0
  ListReaders_Return ret = { 0 };
345
0
  LPSTR mszReaders = NULL;
346
347
0
  WINPR_ASSERT(smartcard);
348
0
  WINPR_ASSERT(out);
349
0
  WINPR_ASSERT(operation);
350
351
0
  ListReaders_Call* call = &operation->call.listReaders;
352
0
  DWORD cchReaders = SCARD_AUTOALLOCATE;
353
0
  LONG status = ret.ReturnCode = wrap(smartcard, SCardListReadersA, operation->hContext,
354
0
                                      (LPCSTR)call->mszGroups, (LPSTR)&mszReaders, &cchReaders);
355
0
  if (status == SCARD_S_SUCCESS)
356
0
  {
357
0
    if (cchReaders == SCARD_AUTOALLOCATE)
358
0
      status = SCARD_F_UNKNOWN_ERROR;
359
0
  }
360
361
0
  if (status != SCARD_S_SUCCESS)
362
0
  {
363
0
    (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersA", status);
364
0
    return smartcard_pack_list_readers_return(out, &ret, FALSE);
365
0
  }
366
367
0
  cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders);
368
0
  ret.msz = (BYTE*)mszReaders;
369
0
  ret.cBytes = cchReaders;
370
371
0
  status = smartcard_pack_list_readers_return(out, &ret, FALSE);
372
0
  if (mszReaders)
373
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaders);
374
375
0
  if (status != SCARD_S_SUCCESS)
376
0
    return scard_log_status_error_wlog(smartcard->log, "smartcard_pack_list_readers_return",
377
0
                                       status);
378
379
0
  return ret.ReturnCode;
380
0
}
381
382
static LONG smartcard_ListReadersW_Call(scard_call_context* smartcard, wStream* out,
383
                                        SMARTCARD_OPERATION* operation)
384
0
{
385
0
  LONG status = 0;
386
0
  ListReaders_Return ret = { 0 };
387
0
  DWORD cchReaders = 0;
388
0
  ListReaders_Call* call = NULL;
389
0
  union
390
0
  {
391
0
    const BYTE* bp;
392
0
    const char* sz;
393
0
    const WCHAR* wz;
394
0
  } string;
395
0
  union
396
0
  {
397
0
    WCHAR** ppw;
398
0
    WCHAR* pw;
399
0
    CHAR* pc;
400
0
    BYTE* pb;
401
0
  } mszReaders;
402
403
0
  WINPR_ASSERT(smartcard);
404
0
  WINPR_ASSERT(operation);
405
406
0
  call = &operation->call.listReaders;
407
408
0
  string.bp = call->mszGroups;
409
0
  cchReaders = SCARD_AUTOALLOCATE;
410
0
  status = ret.ReturnCode = wrap(smartcard, SCardListReadersW, operation->hContext, string.wz,
411
0
                                 (LPWSTR)&mszReaders.pw, &cchReaders);
412
0
  if (status == SCARD_S_SUCCESS)
413
0
  {
414
0
    if (cchReaders == SCARD_AUTOALLOCATE)
415
0
      status = SCARD_F_UNKNOWN_ERROR;
416
0
  }
417
418
0
  if (status != SCARD_S_SUCCESS)
419
0
  {
420
0
    (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersW", status);
421
0
    return smartcard_pack_list_readers_return(out, &ret, TRUE);
422
0
  }
423
424
0
  cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders.pw, cchReaders);
425
0
  ret.msz = mszReaders.pb;
426
0
  ret.cBytes = cchReaders * sizeof(WCHAR);
427
0
  status = smartcard_pack_list_readers_return(out, &ret, TRUE);
428
429
0
  if (mszReaders.pb)
430
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaders.pb);
431
432
0
  if (status != SCARD_S_SUCCESS)
433
0
    return status;
434
435
0
  return ret.ReturnCode;
436
0
}
437
438
static LONG smartcard_IntroduceReaderGroupA_Call(scard_call_context* smartcard,
439
                                                 WINPR_ATTR_UNUSED wStream* out,
440
                                                 SMARTCARD_OPERATION* operation)
441
0
{
442
0
  Long_Return ret = { 0 };
443
0
  ContextAndStringA_Call* call = NULL;
444
445
0
  WINPR_ASSERT(smartcard);
446
0
  WINPR_ASSERT(out);
447
0
  WINPR_ASSERT(operation);
448
449
0
  call = &operation->call.contextAndStringA;
450
0
  ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupA, operation->hContext, call->sz);
451
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupA", ret.ReturnCode);
452
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupA");
453
0
  return ret.ReturnCode;
454
0
}
455
456
static LONG smartcard_IntroduceReaderGroupW_Call(scard_call_context* smartcard,
457
                                                 WINPR_ATTR_UNUSED wStream* out,
458
                                                 SMARTCARD_OPERATION* operation)
459
0
{
460
0
  Long_Return ret = { 0 };
461
0
  ContextAndStringW_Call* call = NULL;
462
463
0
  WINPR_ASSERT(smartcard);
464
0
  WINPR_ASSERT(out);
465
0
  WINPR_ASSERT(operation);
466
467
0
  call = &operation->call.contextAndStringW;
468
0
  ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupW, operation->hContext, call->sz);
469
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupW", ret.ReturnCode);
470
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupW");
471
0
  return ret.ReturnCode;
472
0
}
473
474
static LONG smartcard_IntroduceReaderA_Call(scard_call_context* smartcard,
475
                                            WINPR_ATTR_UNUSED wStream* out,
476
                                            SMARTCARD_OPERATION* operation)
477
0
{
478
0
  Long_Return ret = { 0 };
479
0
  ContextAndTwoStringA_Call* call = NULL;
480
481
0
  WINPR_ASSERT(smartcard);
482
0
  WINPR_ASSERT(out);
483
0
  WINPR_ASSERT(operation);
484
485
0
  call = &operation->call.contextAndTwoStringA;
486
0
  ret.ReturnCode =
487
0
      wrap(smartcard, SCardIntroduceReaderA, operation->hContext, call->sz1, call->sz2);
488
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderA", ret.ReturnCode);
489
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderA");
490
0
  return ret.ReturnCode;
491
0
}
492
493
static LONG smartcard_IntroduceReaderW_Call(scard_call_context* smartcard,
494
                                            WINPR_ATTR_UNUSED wStream* out,
495
                                            SMARTCARD_OPERATION* operation)
496
0
{
497
0
  Long_Return ret = { 0 };
498
0
  ContextAndTwoStringW_Call* call = NULL;
499
500
0
  WINPR_ASSERT(smartcard);
501
0
  WINPR_ASSERT(out);
502
0
  WINPR_ASSERT(operation);
503
504
0
  call = &operation->call.contextAndTwoStringW;
505
0
  ret.ReturnCode =
506
0
      wrap(smartcard, SCardIntroduceReaderW, operation->hContext, call->sz1, call->sz2);
507
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderW", ret.ReturnCode);
508
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderW");
509
0
  return ret.ReturnCode;
510
0
}
511
512
static LONG smartcard_ForgetReaderA_Call(scard_call_context* smartcard,
513
                                         WINPR_ATTR_UNUSED wStream* out,
514
                                         SMARTCARD_OPERATION* operation)
515
0
{
516
0
  Long_Return ret = { 0 };
517
0
  ContextAndStringA_Call* call = NULL;
518
519
0
  WINPR_ASSERT(smartcard);
520
0
  WINPR_ASSERT(out);
521
0
  WINPR_ASSERT(operation);
522
523
0
  call = &operation->call.contextAndStringA;
524
0
  ret.ReturnCode = wrap(smartcard, SCardForgetReaderA, operation->hContext, call->sz);
525
0
  scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderA", ret.ReturnCode);
526
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderA");
527
0
  return ret.ReturnCode;
528
0
}
529
530
static LONG smartcard_ForgetReaderW_Call(scard_call_context* smartcard,
531
                                         WINPR_ATTR_UNUSED wStream* out,
532
                                         SMARTCARD_OPERATION* operation)
533
0
{
534
0
  Long_Return ret = { 0 };
535
0
  ContextAndStringW_Call* call = NULL;
536
537
0
  WINPR_ASSERT(smartcard);
538
0
  WINPR_ASSERT(out);
539
0
  WINPR_ASSERT(operation);
540
541
0
  call = &operation->call.contextAndStringW;
542
0
  ret.ReturnCode = wrap(smartcard, SCardForgetReaderW, operation->hContext, call->sz);
543
0
  scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderW", ret.ReturnCode);
544
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderW");
545
0
  return ret.ReturnCode;
546
0
}
547
548
static LONG smartcard_AddReaderToGroupA_Call(scard_call_context* smartcard,
549
                                             WINPR_ATTR_UNUSED wStream* out,
550
                                             SMARTCARD_OPERATION* operation)
551
0
{
552
0
  Long_Return ret = { 0 };
553
0
  ContextAndTwoStringA_Call* call = NULL;
554
555
0
  WINPR_ASSERT(smartcard);
556
0
  WINPR_ASSERT(out);
557
0
  WINPR_ASSERT(operation);
558
559
0
  call = &operation->call.contextAndTwoStringA;
560
0
  ret.ReturnCode =
561
0
      wrap(smartcard, SCardAddReaderToGroupA, operation->hContext, call->sz1, call->sz2);
562
0
  scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupA", ret.ReturnCode);
563
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA");
564
0
  return ret.ReturnCode;
565
0
}
566
567
static LONG smartcard_AddReaderToGroupW_Call(scard_call_context* smartcard,
568
                                             WINPR_ATTR_UNUSED wStream* out,
569
                                             SMARTCARD_OPERATION* operation)
570
0
{
571
0
  Long_Return ret = { 0 };
572
0
  ContextAndTwoStringW_Call* call = NULL;
573
574
0
  WINPR_ASSERT(smartcard);
575
0
  WINPR_ASSERT(out);
576
0
  WINPR_ASSERT(operation);
577
578
0
  call = &operation->call.contextAndTwoStringW;
579
0
  ret.ReturnCode =
580
0
      wrap(smartcard, SCardAddReaderToGroupW, operation->hContext, call->sz1, call->sz2);
581
0
  scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupW", ret.ReturnCode);
582
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA");
583
0
  return ret.ReturnCode;
584
0
}
585
586
static LONG smartcard_RemoveReaderFromGroupA_Call(scard_call_context* smartcard,
587
                                                  WINPR_ATTR_UNUSED wStream* out,
588
                                                  SMARTCARD_OPERATION* operation)
589
0
{
590
0
  Long_Return ret = { 0 };
591
0
  ContextAndTwoStringA_Call* call = NULL;
592
593
0
  WINPR_ASSERT(smartcard);
594
0
  WINPR_ASSERT(out);
595
0
  WINPR_ASSERT(operation);
596
597
0
  call = &operation->call.contextAndTwoStringA;
598
0
  ret.ReturnCode =
599
0
      wrap(smartcard, SCardRemoveReaderFromGroupA, operation->hContext, call->sz1, call->sz2);
600
0
  scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupA", ret.ReturnCode);
601
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupA");
602
0
  return ret.ReturnCode;
603
0
}
604
605
static LONG smartcard_RemoveReaderFromGroupW_Call(scard_call_context* smartcard,
606
                                                  WINPR_ATTR_UNUSED wStream* out,
607
                                                  SMARTCARD_OPERATION* operation)
608
0
{
609
0
  Long_Return ret = { 0 };
610
0
  ContextAndTwoStringW_Call* call = NULL;
611
612
0
  WINPR_ASSERT(smartcard);
613
0
  WINPR_ASSERT(out);
614
0
  WINPR_ASSERT(operation);
615
616
0
  call = &operation->call.contextAndTwoStringW;
617
0
  ret.ReturnCode =
618
0
      wrap(smartcard, SCardRemoveReaderFromGroupW, operation->hContext, call->sz1, call->sz2);
619
0
  scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupW", ret.ReturnCode);
620
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupW");
621
0
  return ret.ReturnCode;
622
0
}
623
624
static LONG smartcard_LocateCardsA_Call(scard_call_context* smartcard, wStream* out,
625
                                        SMARTCARD_OPERATION* operation)
626
0
{
627
0
  LONG status = 0;
628
0
  LocateCards_Return ret = { 0 };
629
0
  LocateCardsA_Call* call = NULL;
630
631
0
  WINPR_ASSERT(smartcard);
632
0
  WINPR_ASSERT(operation);
633
634
0
  call = &operation->call.locateCardsA;
635
636
0
  ret.ReturnCode = wrap(smartcard, SCardLocateCardsA, operation->hContext, call->mszCards,
637
0
                        call->rgReaderStates, call->cReaders);
638
0
  scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsA", ret.ReturnCode);
639
0
  ret.cReaders = call->cReaders;
640
0
  ret.rgReaderStates = NULL;
641
642
0
  if (ret.cReaders > 0)
643
0
  {
644
0
    ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
645
646
0
    if (!ret.rgReaderStates)
647
0
      return STATUS_NO_MEMORY;
648
0
  }
649
650
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
651
0
  {
652
0
    ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
653
0
    ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
654
0
    ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
655
0
    CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
656
0
               sizeof(ret.rgReaderStates[x].rgbAtr));
657
0
  }
658
659
0
  status = smartcard_pack_locate_cards_return(out, &ret);
660
661
0
  if (status != SCARD_S_SUCCESS)
662
0
    return status;
663
664
0
  return ret.ReturnCode;
665
0
}
666
667
static LONG smartcard_LocateCardsW_Call(scard_call_context* smartcard, wStream* out,
668
                                        SMARTCARD_OPERATION* operation)
669
0
{
670
0
  LONG status = 0;
671
0
  LocateCards_Return ret = { 0 };
672
0
  LocateCardsW_Call* call = NULL;
673
674
0
  WINPR_ASSERT(smartcard);
675
0
  WINPR_ASSERT(operation);
676
677
0
  call = &operation->call.locateCardsW;
678
679
0
  ret.ReturnCode = wrap(smartcard, SCardLocateCardsW, operation->hContext, call->mszCards,
680
0
                        call->rgReaderStates, call->cReaders);
681
0
  scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsW", ret.ReturnCode);
682
0
  ret.cReaders = call->cReaders;
683
0
  ret.rgReaderStates = NULL;
684
685
0
  if (ret.cReaders > 0)
686
0
  {
687
0
    ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
688
689
0
    if (!ret.rgReaderStates)
690
0
      return STATUS_NO_MEMORY;
691
0
  }
692
693
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
694
0
  {
695
0
    ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
696
0
    ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
697
0
    ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
698
0
    CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
699
0
               sizeof(ret.rgReaderStates[x].rgbAtr));
700
0
  }
701
702
0
  status = smartcard_pack_locate_cards_return(out, &ret);
703
704
0
  if (status != SCARD_S_SUCCESS)
705
0
    return status;
706
707
0
  return ret.ReturnCode;
708
0
}
709
710
static LONG smartcard_ReadCacheA_Call(scard_call_context* smartcard, wStream* out,
711
                                      SMARTCARD_OPERATION* operation)
712
0
{
713
0
  LONG status = 0;
714
0
  BOOL autoalloc = 0;
715
0
  ReadCache_Return ret = { 0 };
716
0
  ReadCacheA_Call* call = NULL;
717
718
0
  WINPR_ASSERT(smartcard);
719
0
  WINPR_ASSERT(out);
720
0
  WINPR_ASSERT(operation);
721
722
0
  call = &operation->call.readCacheA;
723
0
  autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
724
725
0
  if (!call->Common.fPbDataIsNULL)
726
0
  {
727
0
    ret.cbDataLen = call->Common.cbDataLen;
728
0
    if (!autoalloc)
729
0
    {
730
0
      ret.pbData = malloc(ret.cbDataLen);
731
0
      if (!ret.pbData)
732
0
        return SCARD_F_INTERNAL_ERROR;
733
0
    }
734
0
  }
735
736
0
  if (autoalloc)
737
0
    ret.ReturnCode = wrap(smartcard, SCardReadCacheA, operation->hContext,
738
0
                          call->Common.CardIdentifier, call->Common.FreshnessCounter,
739
0
                          call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
740
0
  else
741
0
    ret.ReturnCode =
742
0
        wrap(smartcard, SCardReadCacheA, operation->hContext, call->Common.CardIdentifier,
743
0
             call->Common.FreshnessCounter, call->szLookupName, ret.pbData, &ret.cbDataLen);
744
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
745
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
746
0
  {
747
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheA", ret.ReturnCode);
748
0
  }
749
750
0
  status = smartcard_pack_read_cache_return(out, &ret);
751
0
  if (autoalloc)
752
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
753
0
  else
754
0
    free(ret.pbData);
755
0
  if (status != SCARD_S_SUCCESS)
756
0
    return status;
757
758
0
  return ret.ReturnCode;
759
0
}
760
761
static LONG smartcard_ReadCacheW_Call(scard_call_context* smartcard, wStream* out,
762
                                      SMARTCARD_OPERATION* operation)
763
0
{
764
0
  LONG status = 0;
765
0
  ReadCache_Return ret = { 0 };
766
0
  ReadCacheW_Call* call = NULL;
767
768
0
  WINPR_ASSERT(smartcard);
769
0
  WINPR_ASSERT(out);
770
0
  WINPR_ASSERT(operation);
771
772
0
  call = &operation->call.readCacheW;
773
774
0
  if (!call->Common.fPbDataIsNULL)
775
0
    ret.cbDataLen = SCARD_AUTOALLOCATE;
776
777
0
  ret.ReturnCode =
778
0
      wrap(smartcard, SCardReadCacheW, operation->hContext, call->Common.CardIdentifier,
779
0
           call->Common.FreshnessCounter, call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
780
781
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
782
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
783
0
  {
784
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheW", ret.ReturnCode);
785
0
  }
786
787
0
  status = smartcard_pack_read_cache_return(out, &ret);
788
789
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
790
791
0
  if (status != SCARD_S_SUCCESS)
792
0
    return status;
793
794
0
  return ret.ReturnCode;
795
0
}
796
797
static LONG smartcard_WriteCacheA_Call(scard_call_context* smartcard,
798
                                       WINPR_ATTR_UNUSED wStream* out,
799
                                       SMARTCARD_OPERATION* operation)
800
0
{
801
0
  Long_Return ret = { 0 };
802
0
  WriteCacheA_Call* call = NULL;
803
804
0
  WINPR_ASSERT(smartcard);
805
0
  WINPR_ASSERT(out);
806
0
  WINPR_ASSERT(operation);
807
808
0
  call = &operation->call.writeCacheA;
809
810
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheA, operation->hContext,
811
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
812
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
813
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheA", ret.ReturnCode);
814
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheA");
815
0
  return ret.ReturnCode;
816
0
}
817
818
static LONG smartcard_WriteCacheW_Call(scard_call_context* smartcard,
819
                                       WINPR_ATTR_UNUSED wStream* out,
820
                                       SMARTCARD_OPERATION* operation)
821
0
{
822
0
  Long_Return ret = { 0 };
823
0
  WriteCacheW_Call* call = NULL;
824
825
0
  WINPR_ASSERT(smartcard);
826
0
  WINPR_ASSERT(out);
827
0
  WINPR_ASSERT(operation);
828
829
0
  call = &operation->call.writeCacheW;
830
831
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheW, operation->hContext,
832
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
833
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
834
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheW", ret.ReturnCode);
835
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheW");
836
0
  return ret.ReturnCode;
837
0
}
838
839
static LONG smartcard_GetTransmitCount_Call(scard_call_context* smartcard, wStream* out,
840
                                            SMARTCARD_OPERATION* operation)
841
0
{
842
0
  LONG status = 0;
843
0
  GetTransmitCount_Return ret = { 0 };
844
845
0
  WINPR_ASSERT(smartcard);
846
0
  WINPR_ASSERT(out);
847
0
  WINPR_ASSERT(operation);
848
849
0
  ret.ReturnCode = wrap(smartcard, SCardGetTransmitCount, operation->hCard, &ret.cTransmitCount);
850
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetTransmitCount", ret.ReturnCode);
851
0
  status = smartcard_pack_get_transmit_count_return(out, &ret);
852
0
  if (status != SCARD_S_SUCCESS)
853
0
    return status;
854
855
0
  return ret.ReturnCode;
856
0
}
857
858
static LONG smartcard_ReleaseStartedEvent_Call(scard_call_context* smartcard, wStream* out,
859
                                               SMARTCARD_OPERATION* operation)
860
0
{
861
0
  WINPR_UNUSED(smartcard);
862
0
  WINPR_UNUSED(out);
863
0
  WINPR_UNUSED(operation);
864
865
0
  WLog_Print(smartcard->log, WLOG_WARN,
866
0
             "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
867
0
             "this is not supported?!?");
868
0
  return SCARD_E_UNSUPPORTED_FEATURE;
869
0
}
870
871
static LONG smartcard_GetReaderIcon_Call(scard_call_context* smartcard, wStream* out,
872
                                         SMARTCARD_OPERATION* operation)
873
0
{
874
0
  LONG status = 0;
875
0
  GetReaderIcon_Return ret = { 0 };
876
0
  GetReaderIcon_Call* call = NULL;
877
878
0
  WINPR_ASSERT(smartcard);
879
0
  WINPR_ASSERT(out);
880
0
  WINPR_ASSERT(operation);
881
882
0
  call = &operation->call.getReaderIcon;
883
884
0
  ret.cbDataLen = SCARD_AUTOALLOCATE;
885
0
  ret.ReturnCode = wrap(smartcard, SCardGetReaderIconW, operation->hContext, call->szReaderName,
886
0
                        (LPBYTE)&ret.pbData, &ret.cbDataLen);
887
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetReaderIconW", ret.ReturnCode);
888
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cbDataLen == SCARD_AUTOALLOCATE))
889
0
    return SCARD_F_UNKNOWN_ERROR;
890
891
0
  status = smartcard_pack_get_reader_icon_return(out, &ret);
892
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
893
0
  if (status != SCARD_S_SUCCESS)
894
0
    return status;
895
896
0
  return ret.ReturnCode;
897
0
}
898
899
static LONG smartcard_GetDeviceTypeId_Call(scard_call_context* smartcard, wStream* out,
900
                                           SMARTCARD_OPERATION* operation)
901
0
{
902
0
  LONG status = 0;
903
0
  GetDeviceTypeId_Return ret = { 0 };
904
0
  GetDeviceTypeId_Call* call = NULL;
905
906
0
  WINPR_ASSERT(smartcard);
907
0
  WINPR_ASSERT(out);
908
0
  WINPR_ASSERT(operation);
909
910
0
  call = &operation->call.getDeviceTypeId;
911
912
0
  ret.ReturnCode = wrap(smartcard, SCardGetDeviceTypeIdW, operation->hContext, call->szReaderName,
913
0
                        &ret.dwDeviceId);
914
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetDeviceTypeIdW", ret.ReturnCode);
915
916
0
  status = smartcard_pack_device_type_id_return(out, &ret);
917
0
  if (status != SCARD_S_SUCCESS)
918
0
    return status;
919
920
0
  return ret.ReturnCode;
921
0
}
922
923
static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard, wStream* out,
924
                                            SMARTCARD_OPERATION* operation)
925
0
{
926
0
  LONG status = STATUS_NO_MEMORY;
927
0
  DWORD dwTimeOut = 0;
928
0
  const DWORD dwTimeStep = 100;
929
0
  GetStatusChange_Return ret = { 0 };
930
0
  GetStatusChangeA_Call* call = NULL;
931
0
  LPSCARD_READERSTATEA rgReaderStates = NULL;
932
933
0
  WINPR_ASSERT(smartcard);
934
0
  WINPR_ASSERT(out);
935
0
  WINPR_ASSERT(operation);
936
937
0
  call = &operation->call.getStatusChangeA;
938
0
  dwTimeOut = call->dwTimeOut;
939
940
0
  if (call->cReaders > 0)
941
0
  {
942
0
    ret.cReaders = call->cReaders;
943
0
    rgReaderStates = calloc(ret.cReaders, sizeof(SCARD_READERSTATEA));
944
0
    ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
945
0
    if (!rgReaderStates || !ret.rgReaderStates)
946
0
      goto fail;
947
0
  }
948
949
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
950
0
  {
951
0
    if (call->cReaders > 0)
952
0
      memcpy(rgReaderStates, call->rgReaderStates,
953
0
             call->cReaders * sizeof(SCARD_READERSTATEA));
954
0
    ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
955
0
                          MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
956
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
957
0
      break;
958
0
    if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0)
959
0
      break;
960
0
    if (dwTimeOut != INFINITE)
961
0
      x += dwTimeStep;
962
0
  }
963
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", ret.ReturnCode);
964
965
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
966
0
  {
967
0
    const SCARD_READERSTATEA* cur = &rgReaderStates[index];
968
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
969
970
0
    rout->dwCurrentState = cur->dwCurrentState;
971
0
    rout->dwEventState = cur->dwEventState;
972
0
    rout->cbAtr = cur->cbAtr;
973
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
974
0
  }
975
976
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
977
0
fail:
978
0
  free(ret.rgReaderStates);
979
0
  free(rgReaderStates);
980
0
  if (status != SCARD_S_SUCCESS)
981
0
    return status;
982
0
  return ret.ReturnCode;
983
0
}
984
985
static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard, wStream* out,
986
                                            SMARTCARD_OPERATION* operation)
987
0
{
988
0
  LONG status = STATUS_NO_MEMORY;
989
0
  DWORD dwTimeOut = 0;
990
0
  const DWORD dwTimeStep = 100;
991
0
  GetStatusChange_Return ret = { 0 };
992
0
  LPSCARD_READERSTATEW rgReaderStates = NULL;
993
994
0
  WINPR_ASSERT(smartcard);
995
0
  WINPR_ASSERT(out);
996
0
  WINPR_ASSERT(operation);
997
998
0
  GetStatusChangeW_Call* call = &operation->call.getStatusChangeW;
999
0
  dwTimeOut = call->dwTimeOut;
1000
1001
0
  if (call->cReaders > 0)
1002
0
  {
1003
0
    ret.cReaders = call->cReaders;
1004
0
    rgReaderStates = calloc(ret.cReaders, sizeof(SCARD_READERSTATEW));
1005
0
    ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
1006
0
    if (!rgReaderStates || !ret.rgReaderStates)
1007
0
      goto fail;
1008
0
  }
1009
1010
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1011
0
  {
1012
0
    if (call->cReaders > 0)
1013
0
      memcpy(rgReaderStates, call->rgReaderStates,
1014
0
             call->cReaders * sizeof(SCARD_READERSTATEW));
1015
0
    {
1016
0
      ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeW, operation->hContext,
1017
0
                            MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1018
0
    }
1019
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
1020
0
      break;
1021
0
    if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0)
1022
0
      break;
1023
0
    if (dwTimeOut != INFINITE)
1024
0
      x += dwTimeStep;
1025
0
  }
1026
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", ret.ReturnCode);
1027
1028
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
1029
0
  {
1030
0
    const SCARD_READERSTATEW* cur = &rgReaderStates[index];
1031
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
1032
1033
0
    rout->dwCurrentState = cur->dwCurrentState;
1034
0
    rout->dwEventState = cur->dwEventState;
1035
0
    rout->cbAtr = cur->cbAtr;
1036
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1037
0
  }
1038
1039
0
  status = smartcard_pack_get_status_change_return(out, &ret, TRUE);
1040
0
fail:
1041
0
  free(ret.rgReaderStates);
1042
0
  free(rgReaderStates);
1043
0
  if (status != SCARD_S_SUCCESS)
1044
0
    return status;
1045
0
  return ret.ReturnCode;
1046
0
}
1047
1048
static LONG smartcard_Cancel_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1049
                                  SMARTCARD_OPERATION* operation)
1050
0
{
1051
0
  Long_Return ret = { 0 };
1052
1053
0
  WINPR_ASSERT(smartcard);
1054
0
  WINPR_ASSERT(out);
1055
0
  WINPR_ASSERT(operation);
1056
1057
0
  ret.ReturnCode = wrap(smartcard, SCardCancel, operation->hContext);
1058
0
  scard_log_status_error_wlog(smartcard->log, "SCardCancel", ret.ReturnCode);
1059
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Cancel");
1060
0
  return ret.ReturnCode;
1061
0
}
1062
1063
static LONG smartcard_ConnectA_Call(scard_call_context* smartcard, wStream* out,
1064
                                    SMARTCARD_OPERATION* operation)
1065
0
{
1066
0
  LONG status = 0;
1067
0
  SCARDHANDLE hCard = 0;
1068
0
  Connect_Return ret = { 0 };
1069
0
  ConnectA_Call* call = NULL;
1070
1071
0
  WINPR_ASSERT(smartcard);
1072
0
  WINPR_ASSERT(out);
1073
0
  WINPR_ASSERT(operation);
1074
1075
0
  call = &operation->call.connectA;
1076
1077
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1078
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1079
0
  {
1080
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1081
0
  }
1082
1083
0
  ret.ReturnCode = wrap(smartcard, SCardConnectA, operation->hContext, (char*)call->szReader,
1084
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1085
0
                        &ret.dwActiveProtocol);
1086
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1087
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1088
1089
0
  status = smartcard_pack_connect_return(out, &ret);
1090
0
  if (status != SCARD_S_SUCCESS)
1091
0
    goto out_fail;
1092
1093
0
  status = ret.ReturnCode;
1094
0
out_fail:
1095
1096
0
  return status;
1097
0
}
1098
1099
static LONG smartcard_ConnectW_Call(scard_call_context* smartcard, wStream* out,
1100
                                    SMARTCARD_OPERATION* operation)
1101
0
{
1102
0
  LONG status = 0;
1103
0
  SCARDHANDLE hCard = 0;
1104
0
  Connect_Return ret = { 0 };
1105
0
  ConnectW_Call* call = NULL;
1106
1107
0
  WINPR_ASSERT(smartcard);
1108
0
  WINPR_ASSERT(out);
1109
0
  WINPR_ASSERT(operation);
1110
1111
0
  call = &operation->call.connectW;
1112
1113
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1114
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1115
0
  {
1116
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1117
0
  }
1118
1119
0
  ret.ReturnCode = wrap(smartcard, SCardConnectW, operation->hContext, (WCHAR*)call->szReader,
1120
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1121
0
                        &ret.dwActiveProtocol);
1122
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1123
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1124
1125
0
  status = smartcard_pack_connect_return(out, &ret);
1126
0
  if (status != SCARD_S_SUCCESS)
1127
0
    goto out_fail;
1128
1129
0
  status = ret.ReturnCode;
1130
0
out_fail:
1131
1132
0
  return status;
1133
0
}
1134
1135
static LONG smartcard_Reconnect_Call(scard_call_context* smartcard, wStream* out,
1136
                                     SMARTCARD_OPERATION* operation)
1137
0
{
1138
0
  LONG status = 0;
1139
0
  Reconnect_Return ret = { 0 };
1140
0
  Reconnect_Call* call = NULL;
1141
1142
0
  WINPR_ASSERT(smartcard);
1143
0
  WINPR_ASSERT(out);
1144
0
  WINPR_ASSERT(operation);
1145
1146
0
  call = &operation->call.reconnect;
1147
0
  ret.ReturnCode =
1148
0
      wrap(smartcard, SCardReconnect, operation->hCard, call->dwShareMode,
1149
0
           call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
1150
0
  scard_log_status_error_wlog(smartcard->log, "SCardReconnect", ret.ReturnCode);
1151
0
  status = smartcard_pack_reconnect_return(out, &ret);
1152
0
  if (status != SCARD_S_SUCCESS)
1153
0
    return status;
1154
1155
0
  return ret.ReturnCode;
1156
0
}
1157
1158
static LONG smartcard_Disconnect_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1159
                                      SMARTCARD_OPERATION* operation)
1160
0
{
1161
0
  Long_Return ret = { 0 };
1162
0
  HCardAndDisposition_Call* call = NULL;
1163
1164
0
  WINPR_ASSERT(smartcard);
1165
0
  WINPR_ASSERT(out);
1166
0
  WINPR_ASSERT(operation);
1167
1168
0
  call = &operation->call.hCardAndDisposition;
1169
1170
0
  ret.ReturnCode = wrap(smartcard, SCardDisconnect, operation->hCard, call->dwDisposition);
1171
0
  scard_log_status_error_wlog(smartcard->log, "SCardDisconnect", ret.ReturnCode);
1172
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Disconnect");
1173
1174
0
  return ret.ReturnCode;
1175
0
}
1176
1177
static LONG smartcard_BeginTransaction_Call(scard_call_context* smartcard,
1178
                                            WINPR_ATTR_UNUSED wStream* out,
1179
                                            SMARTCARD_OPERATION* operation)
1180
0
{
1181
0
  Long_Return ret = { 0 };
1182
1183
0
  WINPR_ASSERT(smartcard);
1184
0
  WINPR_ASSERT(out);
1185
0
  WINPR_ASSERT(operation);
1186
1187
0
  ret.ReturnCode = wrap(smartcard, SCardBeginTransaction, operation->hCard);
1188
0
  scard_log_status_error_wlog(smartcard->log, "SCardBeginTransaction", ret.ReturnCode);
1189
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "BeginTransaction");
1190
0
  return ret.ReturnCode;
1191
0
}
1192
1193
static LONG smartcard_EndTransaction_Call(scard_call_context* smartcard,
1194
                                          WINPR_ATTR_UNUSED wStream* out,
1195
                                          SMARTCARD_OPERATION* operation)
1196
0
{
1197
0
  Long_Return ret = { 0 };
1198
0
  HCardAndDisposition_Call* call = NULL;
1199
1200
0
  WINPR_ASSERT(smartcard);
1201
0
  WINPR_ASSERT(out);
1202
0
  WINPR_ASSERT(operation);
1203
1204
0
  call = &operation->call.hCardAndDisposition;
1205
1206
0
  ret.ReturnCode = wrap(smartcard, SCardEndTransaction, operation->hCard, call->dwDisposition);
1207
0
  scard_log_status_error_wlog(smartcard->log, "SCardEndTransaction", ret.ReturnCode);
1208
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "EndTransaction");
1209
0
  return ret.ReturnCode;
1210
0
}
1211
1212
static LONG smartcard_State_Call(scard_call_context* smartcard, wStream* out,
1213
                                 SMARTCARD_OPERATION* operation)
1214
0
{
1215
0
  LONG status = 0;
1216
0
  State_Return ret = { 0 };
1217
1218
0
  WINPR_ASSERT(smartcard);
1219
0
  WINPR_ASSERT(out);
1220
0
  WINPR_ASSERT(operation);
1221
1222
0
  ret.cbAtrLen = SCARD_ATR_LENGTH;
1223
0
  ret.ReturnCode = wrap(smartcard, SCardState, operation->hCard, &ret.dwState, &ret.dwProtocol,
1224
0
                        (BYTE*)&ret.rgAtr, &ret.cbAtrLen);
1225
1226
0
  scard_log_status_error_wlog(smartcard->log, "SCardState", ret.ReturnCode);
1227
0
  status = smartcard_pack_state_return(out, &ret);
1228
0
  if (status != SCARD_S_SUCCESS)
1229
0
    return status;
1230
1231
0
  return ret.ReturnCode;
1232
0
}
1233
1234
static LONG smartcard_StatusA_Call(scard_call_context* smartcard, wStream* out,
1235
                                   SMARTCARD_OPERATION* operation)
1236
0
{
1237
0
  LONG status = 0;
1238
0
  Status_Return ret = { 0 };
1239
0
  DWORD cchReaderLen = 0;
1240
0
  DWORD cbAtrLen = 0;
1241
0
  LPSTR mszReaderNames = NULL;
1242
0
  Status_Call* call = NULL;
1243
1244
0
  WINPR_ASSERT(smartcard);
1245
0
  WINPR_ASSERT(out);
1246
0
  WINPR_ASSERT(operation);
1247
1248
0
  call = &operation->call.status;
1249
1250
0
  call->cbAtrLen = 32;
1251
0
  cbAtrLen = call->cbAtrLen;
1252
1253
0
  if (call->fmszReaderNamesIsNULL)
1254
0
    cchReaderLen = 0;
1255
0
  else
1256
0
    cchReaderLen = SCARD_AUTOALLOCATE;
1257
1258
0
  status = ret.ReturnCode =
1259
0
      wrap(smartcard, SCardStatusA, operation->hCard,
1260
0
           call->fmszReaderNamesIsNULL ? NULL : (LPSTR)&mszReaderNames, &cchReaderLen,
1261
0
           &ret.dwState, &ret.dwProtocol, cbAtrLen ? (BYTE*)&ret.pbAtr : NULL, &cbAtrLen);
1262
1263
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusA", status);
1264
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchReaderLen == SCARD_AUTOALLOCATE))
1265
0
    return SCARD_F_UNKNOWN_ERROR;
1266
1267
0
  if (status == SCARD_S_SUCCESS)
1268
0
  {
1269
0
    if (!call->fmszReaderNamesIsNULL)
1270
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1271
1272
0
    ret.cBytes = cchReaderLen;
1273
1274
0
    if (call->cbAtrLen)
1275
0
      ret.cbAtrLen = cbAtrLen;
1276
0
  }
1277
1278
0
  status = smartcard_pack_status_return(out, &ret, FALSE);
1279
1280
0
  if (mszReaderNames)
1281
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1282
1283
0
  if (status != SCARD_S_SUCCESS)
1284
0
    return status;
1285
0
  return ret.ReturnCode;
1286
0
}
1287
1288
static LONG smartcard_StatusW_Call(scard_call_context* smartcard, wStream* out,
1289
                                   SMARTCARD_OPERATION* operation)
1290
0
{
1291
0
  LONG status = 0;
1292
0
  Status_Return ret = { 0 };
1293
0
  LPWSTR mszReaderNames = NULL;
1294
0
  Status_Call* call = NULL;
1295
0
  DWORD cbAtrLen = 0;
1296
1297
0
  WINPR_ASSERT(smartcard);
1298
0
  WINPR_ASSERT(out);
1299
0
  WINPR_ASSERT(operation);
1300
1301
0
  call = &operation->call.status;
1302
1303
  /**
1304
   * [MS-RDPESC]
1305
   * According to 2.2.2.18 Status_Call cbAtrLen is unused an must be ignored upon receipt.
1306
   */
1307
0
  cbAtrLen = call->cbAtrLen = 32;
1308
1309
0
  if (call->fmszReaderNamesIsNULL)
1310
0
    ret.cBytes = 0;
1311
0
  else
1312
0
    ret.cBytes = SCARD_AUTOALLOCATE;
1313
1314
0
  status = ret.ReturnCode =
1315
0
      wrap(smartcard, SCardStatusW, operation->hCard,
1316
0
           call->fmszReaderNamesIsNULL ? NULL : (LPWSTR)&mszReaderNames, &ret.cBytes,
1317
0
           &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
1318
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusW", status);
1319
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cBytes == SCARD_AUTOALLOCATE))
1320
0
    return SCARD_F_UNKNOWN_ERROR;
1321
1322
0
  size_t blen = 0;
1323
0
  if (status == SCARD_S_SUCCESS)
1324
0
  {
1325
0
    if (!call->fmszReaderNamesIsNULL)
1326
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1327
1328
0
    ret.cbAtrLen = cbAtrLen;
1329
0
  }
1330
1331
0
  if (ret.cBytes != SCARD_AUTOALLOCATE)
1332
0
  {
1333
    /* SCardStatusW returns number of characters, we need number of bytes */
1334
0
    WINPR_ASSERT(ret.cBytes < SCARD_AUTOALLOCATE / sizeof(WCHAR));
1335
0
    blen = sizeof(WCHAR) * ret.cBytes;
1336
0
    WINPR_ASSERT(blen <= UINT32_MAX);
1337
0
    ret.cBytes = (UINT32)blen;
1338
0
  }
1339
1340
0
  status = smartcard_pack_status_return(out, &ret, TRUE);
1341
0
  if (status != SCARD_S_SUCCESS)
1342
0
    return status;
1343
1344
0
  if (mszReaderNames)
1345
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1346
1347
0
  return ret.ReturnCode;
1348
0
}
1349
1350
static LONG smartcard_Transmit_Call(scard_call_context* smartcard, wStream* out,
1351
                                    SMARTCARD_OPERATION* operation)
1352
0
{
1353
0
  LONG status = 0;
1354
0
  Transmit_Return ret = { 0 };
1355
0
  Transmit_Call* call = NULL;
1356
1357
0
  WINPR_ASSERT(smartcard);
1358
0
  WINPR_ASSERT(out);
1359
0
  WINPR_ASSERT(operation);
1360
1361
0
  call = &operation->call.transmit;
1362
0
  ret.cbRecvLength = 0;
1363
0
  ret.pbRecvBuffer = NULL;
1364
1365
0
  if (call->cbRecvLength && !call->fpbRecvBufferIsNULL)
1366
0
  {
1367
0
    if (call->cbRecvLength >= 66560)
1368
0
      call->cbRecvLength = 66560;
1369
1370
0
    ret.cbRecvLength = call->cbRecvLength;
1371
0
    ret.pbRecvBuffer = (BYTE*)malloc(ret.cbRecvLength);
1372
1373
0
    if (!ret.pbRecvBuffer)
1374
0
      return STATUS_NO_MEMORY;
1375
0
  }
1376
1377
0
  ret.pioRecvPci = call->pioRecvPci;
1378
0
  ret.ReturnCode =
1379
0
      wrap(smartcard, SCardTransmit, operation->hCard, call->pioSendPci, call->pbSendBuffer,
1380
0
           call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
1381
1382
0
  scard_log_status_error_wlog(smartcard->log, "SCardTransmit", ret.ReturnCode);
1383
1384
0
  status = smartcard_pack_transmit_return(out, &ret);
1385
0
  free(ret.pbRecvBuffer);
1386
1387
0
  if (status != SCARD_S_SUCCESS)
1388
0
    return status;
1389
0
  return ret.ReturnCode;
1390
0
}
1391
1392
static LONG smartcard_Control_Call(scard_call_context* smartcard, wStream* out,
1393
                                   SMARTCARD_OPERATION* operation)
1394
0
{
1395
0
  LONG status = 0;
1396
0
  Control_Return ret = { 0 };
1397
0
  Control_Call* call = NULL;
1398
1399
0
  WINPR_ASSERT(smartcard);
1400
0
  WINPR_ASSERT(out);
1401
0
  WINPR_ASSERT(operation);
1402
1403
0
  call = &operation->call.control;
1404
0
  ret.cbOutBufferSize = call->cbOutBufferSize;
1405
0
  ret.pvOutBuffer = (BYTE*)malloc(call->cbOutBufferSize);
1406
1407
0
  if (!ret.pvOutBuffer)
1408
0
    return SCARD_E_NO_MEMORY;
1409
1410
0
  ret.ReturnCode =
1411
0
      wrap(smartcard, SCardControl, operation->hCard, call->dwControlCode, call->pvInBuffer,
1412
0
           call->cbInBufferSize, ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
1413
0
  scard_log_status_error_wlog(smartcard->log, "SCardControl", ret.ReturnCode);
1414
0
  status = smartcard_pack_control_return(out, &ret);
1415
1416
0
  free(ret.pvOutBuffer);
1417
0
  if (status != SCARD_S_SUCCESS)
1418
0
    return status;
1419
0
  return ret.ReturnCode;
1420
0
}
1421
1422
static LONG smartcard_GetAttrib_Call(scard_call_context* smartcard, wStream* out,
1423
                                     SMARTCARD_OPERATION* operation)
1424
0
{
1425
0
  BOOL autoAllocate = FALSE;
1426
0
  LONG status = 0;
1427
0
  DWORD cbAttrLen = 0;
1428
0
  LPBYTE pbAttr = NULL;
1429
0
  GetAttrib_Return ret = { 0 };
1430
0
  const GetAttrib_Call* call = NULL;
1431
1432
0
  WINPR_ASSERT(smartcard);
1433
0
  WINPR_ASSERT(operation);
1434
1435
0
  call = &operation->call.getAttrib;
1436
1437
0
  if (!call->fpbAttrIsNULL)
1438
0
  {
1439
0
    autoAllocate = (call->cbAttrLen == SCARD_AUTOALLOCATE) ? TRUE : FALSE;
1440
0
    cbAttrLen = call->cbAttrLen;
1441
0
    if (cbAttrLen && !autoAllocate)
1442
0
    {
1443
0
      ret.pbAttr = (BYTE*)malloc(cbAttrLen);
1444
1445
0
      if (!ret.pbAttr)
1446
0
        return SCARD_E_NO_MEMORY;
1447
0
    }
1448
1449
0
    pbAttr = autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr;
1450
0
  }
1451
1452
0
  ret.ReturnCode =
1453
0
      wrap(smartcard, SCardGetAttrib, operation->hCard, call->dwAttrId, pbAttr, &cbAttrLen);
1454
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetAttrib", ret.ReturnCode);
1455
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cbAttrLen == SCARD_AUTOALLOCATE))
1456
0
    return SCARD_F_UNKNOWN_ERROR;
1457
1458
0
  ret.cbAttrLen = cbAttrLen;
1459
1460
0
  status = smartcard_pack_get_attrib_return(out, &ret, call->dwAttrId, call->cbAttrLen);
1461
1462
0
  if (autoAllocate)
1463
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbAttr);
1464
0
  else
1465
0
    free(ret.pbAttr);
1466
0
  return status;
1467
0
}
1468
1469
static LONG smartcard_SetAttrib_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1470
                                     SMARTCARD_OPERATION* operation)
1471
0
{
1472
0
  Long_Return ret = { 0 };
1473
0
  SetAttrib_Call* call = NULL;
1474
1475
0
  WINPR_ASSERT(smartcard);
1476
0
  WINPR_ASSERT(out);
1477
0
  WINPR_ASSERT(operation);
1478
1479
0
  call = &operation->call.setAttrib;
1480
1481
0
  ret.ReturnCode = wrap(smartcard, SCardSetAttrib, operation->hCard, call->dwAttrId, call->pbAttr,
1482
0
                        call->cbAttrLen);
1483
0
  scard_log_status_error_wlog(smartcard->log, "SCardSetAttrib", ret.ReturnCode);
1484
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SetAttrib");
1485
1486
0
  return ret.ReturnCode;
1487
0
}
1488
1489
static LONG smartcard_AccessStartedEvent_Call(scard_call_context* smartcard,
1490
                                              WINPR_ATTR_UNUSED wStream* out,
1491
                                              SMARTCARD_OPERATION* operation)
1492
0
{
1493
0
  LONG status = SCARD_S_SUCCESS;
1494
1495
0
  WINPR_ASSERT(smartcard);
1496
0
  WINPR_ASSERT(out);
1497
0
  WINPR_UNUSED(operation);
1498
1499
0
  if (!smartcard->StartedEvent)
1500
0
    smartcard->StartedEvent = wrap_ptr(smartcard, SCardAccessStartedEvent);
1501
1502
0
  if (!smartcard->StartedEvent)
1503
0
    status = SCARD_E_NO_SERVICE;
1504
1505
0
  return status;
1506
0
}
1507
1508
static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStream* out,
1509
                                             SMARTCARD_OPERATION* operation)
1510
0
{
1511
0
  LONG status = 0;
1512
0
  GetStatusChange_Return ret = { 0 };
1513
0
  LPSCARD_READERSTATEA states = NULL;
1514
0
  LocateCardsByATRA_Call* call = NULL;
1515
1516
0
  WINPR_ASSERT(smartcard);
1517
0
  WINPR_ASSERT(operation);
1518
1519
0
  call = &operation->call.locateCardsByATRA;
1520
0
  states = (LPSCARD_READERSTATEA)calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1521
1522
0
  if (!states)
1523
0
    return STATUS_NO_MEMORY;
1524
1525
0
  for (UINT32 i = 0; i < call->cReaders; i++)
1526
0
  {
1527
0
    LPSCARD_READERSTATEA state = &states[i];
1528
0
    state->szReader = call->rgReaderStates[i].szReader;
1529
0
    state->dwCurrentState = call->rgReaderStates[i].dwCurrentState;
1530
0
    state->dwEventState = call->rgReaderStates[i].dwEventState;
1531
0
    state->cbAtr = call->rgReaderStates[i].cbAtr;
1532
0
    CopyMemory(&(state->rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36);
1533
0
  }
1534
1535
0
  status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1536
0
                                 0x000001F4, states, call->cReaders);
1537
1538
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", status);
1539
0
  for (UINT32 i = 0; i < call->cAtrs; i++)
1540
0
  {
1541
0
    for (UINT32 j = 0; j < call->cReaders; j++)
1542
0
    {
1543
0
      for (UINT32 k = 0; k < call->rgAtrMasks[i].cbAtr; k++)
1544
0
      {
1545
0
        if ((call->rgAtrMasks[i].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]) !=
1546
0
            (states[j].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]))
1547
0
        {
1548
0
          break;
1549
0
        }
1550
1551
0
        states[j].dwEventState |= SCARD_STATE_ATRMATCH;
1552
0
      }
1553
0
    }
1554
0
  }
1555
1556
0
  ret.cReaders = call->cReaders;
1557
0
  ret.rgReaderStates = NULL;
1558
1559
0
  if (ret.cReaders > 0)
1560
0
    ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
1561
1562
0
  if (!ret.rgReaderStates)
1563
0
  {
1564
0
    free(states);
1565
0
    return STATUS_NO_MEMORY;
1566
0
  }
1567
1568
0
  for (UINT32 i = 0; i < ret.cReaders; i++)
1569
0
  {
1570
0
    LPSCARD_READERSTATEA state = &states[i];
1571
0
    ret.rgReaderStates[i].dwCurrentState = state->dwCurrentState;
1572
0
    ret.rgReaderStates[i].dwEventState = state->dwEventState;
1573
0
    ret.rgReaderStates[i].cbAtr = state->cbAtr;
1574
0
    CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr),
1575
0
               sizeof(ret.rgReaderStates[i].rgbAtr));
1576
0
  }
1577
1578
0
  free(states);
1579
1580
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1581
1582
0
  free(ret.rgReaderStates);
1583
0
  if (status != SCARD_S_SUCCESS)
1584
0
    return status;
1585
0
  return ret.ReturnCode;
1586
0
}
1587
1588
LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* out,
1589
                                       NTSTATUS* pIoStatus, SMARTCARD_OPERATION* operation)
1590
0
{
1591
0
  LONG result = 0;
1592
0
  UINT32 offset = 0;
1593
0
  size_t objectBufferLength = 0;
1594
1595
0
  WINPR_ASSERT(smartcard);
1596
0
  WINPR_ASSERT(out);
1597
0
  WINPR_ASSERT(pIoStatus);
1598
0
  WINPR_ASSERT(operation);
1599
1600
0
  const UINT32 ioControlCode = operation->ioControlCode;
1601
  /**
1602
   * [MS-RDPESC] 3.2.5.1: Sending Outgoing Messages:
1603
   * the output buffer length SHOULD be set to 2048
1604
   *
1605
   * Since it's a SHOULD and not a MUST, we don't care
1606
   * about it, but we still reserve at least 2048 bytes.
1607
   */
1608
0
  const size_t outMaxLen = MAX(2048, operation->outputBufferLength);
1609
0
  if (!Stream_EnsureRemainingCapacity(out, outMaxLen))
1610
0
    return SCARD_E_NO_MEMORY;
1611
1612
  /* Device Control Response */
1613
0
  Stream_Write_UINT32(out, 0);                            /* OutputBufferLength (4 bytes) */
1614
0
  Stream_Zero(out, SMARTCARD_COMMON_TYPE_HEADER_LENGTH);  /* CommonTypeHeader (8 bytes) */
1615
0
  Stream_Zero(out, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
1616
0
  Stream_Write_UINT32(out, 0);                            /* Result (4 bytes) */
1617
1618
  /* Call */
1619
0
  switch (ioControlCode)
1620
0
  {
1621
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1622
0
      result = smartcard_EstablishContext_Call(smartcard, out, operation);
1623
0
      break;
1624
1625
0
    case SCARD_IOCTL_RELEASECONTEXT:
1626
0
      result = smartcard_ReleaseContext_Call(smartcard, out, operation);
1627
0
      break;
1628
1629
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1630
0
      result = smartcard_IsValidContext_Call(smartcard, out, operation);
1631
0
      break;
1632
1633
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1634
0
      result = smartcard_ListReaderGroupsA_Call(smartcard, out, operation);
1635
0
      break;
1636
1637
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1638
0
      result = smartcard_ListReaderGroupsW_Call(smartcard, out, operation);
1639
0
      break;
1640
1641
0
    case SCARD_IOCTL_LISTREADERSA:
1642
0
      result = smartcard_ListReadersA_Call(smartcard, out, operation);
1643
0
      break;
1644
1645
0
    case SCARD_IOCTL_LISTREADERSW:
1646
0
      result = smartcard_ListReadersW_Call(smartcard, out, operation);
1647
0
      break;
1648
1649
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1650
0
      result = smartcard_IntroduceReaderGroupA_Call(smartcard, out, operation);
1651
0
      break;
1652
1653
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1654
0
      result = smartcard_IntroduceReaderGroupW_Call(smartcard, out, operation);
1655
0
      break;
1656
1657
0
    case SCARD_IOCTL_FORGETREADERGROUPA:
1658
0
      result = smartcard_ForgetReaderA_Call(smartcard, out, operation);
1659
0
      break;
1660
1661
0
    case SCARD_IOCTL_FORGETREADERGROUPW:
1662
0
      result = smartcard_ForgetReaderW_Call(smartcard, out, operation);
1663
0
      break;
1664
1665
0
    case SCARD_IOCTL_INTRODUCEREADERA:
1666
0
      result = smartcard_IntroduceReaderA_Call(smartcard, out, operation);
1667
0
      break;
1668
1669
0
    case SCARD_IOCTL_INTRODUCEREADERW:
1670
0
      result = smartcard_IntroduceReaderW_Call(smartcard, out, operation);
1671
0
      break;
1672
1673
0
    case SCARD_IOCTL_FORGETREADERA:
1674
0
      result = smartcard_ForgetReaderA_Call(smartcard, out, operation);
1675
0
      break;
1676
1677
0
    case SCARD_IOCTL_FORGETREADERW:
1678
0
      result = smartcard_ForgetReaderW_Call(smartcard, out, operation);
1679
0
      break;
1680
1681
0
    case SCARD_IOCTL_ADDREADERTOGROUPA:
1682
0
      result = smartcard_AddReaderToGroupA_Call(smartcard, out, operation);
1683
0
      break;
1684
1685
0
    case SCARD_IOCTL_ADDREADERTOGROUPW:
1686
0
      result = smartcard_AddReaderToGroupW_Call(smartcard, out, operation);
1687
0
      break;
1688
1689
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1690
0
      result = smartcard_RemoveReaderFromGroupA_Call(smartcard, out, operation);
1691
0
      break;
1692
1693
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1694
0
      result = smartcard_RemoveReaderFromGroupW_Call(smartcard, out, operation);
1695
0
      break;
1696
1697
0
    case SCARD_IOCTL_LOCATECARDSA:
1698
0
      result = smartcard_LocateCardsA_Call(smartcard, out, operation);
1699
0
      break;
1700
1701
0
    case SCARD_IOCTL_LOCATECARDSW:
1702
0
      result = smartcard_LocateCardsW_Call(smartcard, out, operation);
1703
0
      break;
1704
1705
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1706
0
      result = smartcard_GetStatusChangeA_Call(smartcard, out, operation);
1707
0
      break;
1708
1709
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1710
0
      result = smartcard_GetStatusChangeW_Call(smartcard, out, operation);
1711
0
      break;
1712
1713
0
    case SCARD_IOCTL_CANCEL:
1714
0
      result = smartcard_Cancel_Call(smartcard, out, operation);
1715
0
      break;
1716
1717
0
    case SCARD_IOCTL_CONNECTA:
1718
0
      result = smartcard_ConnectA_Call(smartcard, out, operation);
1719
0
      break;
1720
1721
0
    case SCARD_IOCTL_CONNECTW:
1722
0
      result = smartcard_ConnectW_Call(smartcard, out, operation);
1723
0
      break;
1724
1725
0
    case SCARD_IOCTL_RECONNECT:
1726
0
      result = smartcard_Reconnect_Call(smartcard, out, operation);
1727
0
      break;
1728
1729
0
    case SCARD_IOCTL_DISCONNECT:
1730
0
      result = smartcard_Disconnect_Call(smartcard, out, operation);
1731
0
      break;
1732
1733
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1734
0
      result = smartcard_BeginTransaction_Call(smartcard, out, operation);
1735
0
      break;
1736
1737
0
    case SCARD_IOCTL_ENDTRANSACTION:
1738
0
      result = smartcard_EndTransaction_Call(smartcard, out, operation);
1739
0
      break;
1740
1741
0
    case SCARD_IOCTL_STATE:
1742
0
      result = smartcard_State_Call(smartcard, out, operation);
1743
0
      break;
1744
1745
0
    case SCARD_IOCTL_STATUSA:
1746
0
      result = smartcard_StatusA_Call(smartcard, out, operation);
1747
0
      break;
1748
1749
0
    case SCARD_IOCTL_STATUSW:
1750
0
      result = smartcard_StatusW_Call(smartcard, out, operation);
1751
0
      break;
1752
1753
0
    case SCARD_IOCTL_TRANSMIT:
1754
0
      result = smartcard_Transmit_Call(smartcard, out, operation);
1755
0
      break;
1756
1757
0
    case SCARD_IOCTL_CONTROL:
1758
0
      result = smartcard_Control_Call(smartcard, out, operation);
1759
0
      break;
1760
1761
0
    case SCARD_IOCTL_GETATTRIB:
1762
0
      result = smartcard_GetAttrib_Call(smartcard, out, operation);
1763
0
      break;
1764
1765
0
    case SCARD_IOCTL_SETATTRIB:
1766
0
      result = smartcard_SetAttrib_Call(smartcard, out, operation);
1767
0
      break;
1768
1769
0
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1770
0
      result = smartcard_AccessStartedEvent_Call(smartcard, out, operation);
1771
0
      break;
1772
1773
0
    case SCARD_IOCTL_LOCATECARDSBYATRA:
1774
0
      result = smartcard_LocateCardsByATRA_Call(smartcard, out, operation);
1775
0
      break;
1776
1777
0
    case SCARD_IOCTL_LOCATECARDSBYATRW:
1778
0
      result = smartcard_LocateCardsW_Call(smartcard, out, operation);
1779
0
      break;
1780
1781
0
    case SCARD_IOCTL_READCACHEA:
1782
0
      result = smartcard_ReadCacheA_Call(smartcard, out, operation);
1783
0
      break;
1784
1785
0
    case SCARD_IOCTL_READCACHEW:
1786
0
      result = smartcard_ReadCacheW_Call(smartcard, out, operation);
1787
0
      break;
1788
1789
0
    case SCARD_IOCTL_WRITECACHEA:
1790
0
      result = smartcard_WriteCacheA_Call(smartcard, out, operation);
1791
0
      break;
1792
1793
0
    case SCARD_IOCTL_WRITECACHEW:
1794
0
      result = smartcard_WriteCacheW_Call(smartcard, out, operation);
1795
0
      break;
1796
1797
0
    case SCARD_IOCTL_GETTRANSMITCOUNT:
1798
0
      result = smartcard_GetTransmitCount_Call(smartcard, out, operation);
1799
0
      break;
1800
1801
0
    case SCARD_IOCTL_RELEASETARTEDEVENT:
1802
0
      result = smartcard_ReleaseStartedEvent_Call(smartcard, out, operation);
1803
0
      break;
1804
1805
0
    case SCARD_IOCTL_GETREADERICON:
1806
0
      result = smartcard_GetReaderIcon_Call(smartcard, out, operation);
1807
0
      break;
1808
1809
0
    case SCARD_IOCTL_GETDEVICETYPEID:
1810
0
      result = smartcard_GetDeviceTypeId_Call(smartcard, out, operation);
1811
0
      break;
1812
1813
0
    default:
1814
0
      result = STATUS_UNSUCCESSFUL;
1815
0
      break;
1816
0
  }
1817
1818
  /**
1819
   * [MS-RPCE] 2.2.6.3 Primitive Type Serialization
1820
   * The type MUST be aligned on an 8-byte boundary. If the size of the
1821
   * primitive type is not a multiple of 8 bytes, the data MUST be padded.
1822
   */
1823
1824
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
1825
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
1826
0
  {
1827
0
    offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH);
1828
0
    smartcard_pack_write_size_align(out, Stream_GetPosition(out) - offset, 8);
1829
0
  }
1830
1831
0
  if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) &&
1832
0
      (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) &&
1833
0
      (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE))
1834
0
  {
1835
0
    WLog_Print(smartcard->log, WLOG_WARN,
1836
0
               "IRP failure: %s (0x%08" PRIX32 "), status: %s (0x%08" PRIX32 ")",
1837
0
               scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode,
1838
0
               SCardGetErrorString(result), result);
1839
0
  }
1840
1841
0
  *pIoStatus = STATUS_SUCCESS;
1842
1843
0
  if ((result & 0xC0000000L) == 0xC0000000L)
1844
0
  {
1845
    /* NTSTATUS error */
1846
0
    *pIoStatus = result;
1847
0
    WLog_Print(smartcard->log, WLOG_WARN,
1848
0
               "IRP failure: %s (0x%08" PRIX32 "), ntstatus: 0x%08" PRIX32 "",
1849
0
               scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result);
1850
0
  }
1851
1852
0
  Stream_SealLength(out);
1853
0
  size_t outputBufferLength = Stream_Length(out);
1854
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1855
0
  outputBufferLength -= (RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1856
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH);
1857
0
  objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH;
1858
0
  WINPR_ASSERT(outputBufferLength <= UINT32_MAX);
1859
0
  WINPR_ASSERT(objectBufferLength <= UINT32_MAX);
1860
0
  Stream_SetPosition(out, RDPDR_DEVICE_IO_RESPONSE_LENGTH);
1861
1862
  /* [MS-RDPESC] 3.2.5.2 Processing Incoming Replies
1863
   *
1864
   * if the output buffer is too small, reply with STATUS_BUFFER_TOO_SMALL
1865
   * and a outputBufferLength of 0.
1866
   * The message should then be retransmitted from the server with a doubled
1867
   * buffer size.
1868
   */
1869
0
  if (outputBufferLength > operation->outputBufferLength)
1870
0
  {
1871
0
    WLog_Print(smartcard->log, WLOG_WARN,
1872
0
               "IRP warn: expected outputBufferLength %" PRIu32 ", but current limit %" PRIu32
1873
0
               ", respond with STATUS_BUFFER_TOO_SMALL",
1874
0
               operation->outputBufferLength, outputBufferLength);
1875
1876
0
    *pIoStatus = STATUS_BUFFER_TOO_SMALL;
1877
0
    result = *pIoStatus;
1878
0
    outputBufferLength = 0;
1879
0
    objectBufferLength = 0;
1880
0
  }
1881
1882
  /* Device Control Response */
1883
0
  Stream_Write_UINT32(out, (UINT32)outputBufferLength); /* OutputBufferLength (4 bytes) */
1884
0
  smartcard_pack_common_type_header(out);               /* CommonTypeHeader (8 bytes) */
1885
0
  smartcard_pack_private_type_header(
1886
0
      out, (UINT32)objectBufferLength); /* PrivateTypeHeader (8 bytes) */
1887
0
  Stream_Write_INT32(out, result);      /* Result (4 bytes) */
1888
0
  Stream_SetPosition(out, Stream_Length(out));
1889
0
  return SCARD_S_SUCCESS;
1890
0
}
1891
1892
void context_free(void* arg)
1893
0
{
1894
0
  struct s_scard_context_element* element = arg;
1895
0
  if (!arg)
1896
0
    return;
1897
1898
0
  if (element->fn_free)
1899
0
    element->fn_free(element->context);
1900
0
  free(element);
1901
0
}
1902
1903
scard_call_context* smartcard_call_context_new(const rdpSettings* settings)
1904
0
{
1905
0
  wObject* obj = NULL;
1906
0
  scard_call_context* ctx = NULL;
1907
1908
0
  WINPR_ASSERT(settings);
1909
0
  ctx = calloc(1, sizeof(scard_call_context));
1910
0
  if (!ctx)
1911
0
    goto fail;
1912
1913
0
  ctx->log = WLog_Get(SCARD_TAG);
1914
0
  WINPR_ASSERT(ctx->log);
1915
1916
0
  ctx->stopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
1917
0
  if (!ctx->stopEvent)
1918
0
    goto fail;
1919
1920
0
  ctx->names = LinkedList_New();
1921
0
  if (!ctx->names)
1922
0
    goto fail;
1923
1924
0
#if defined(WITH_SMARTCARD_EMULATE)
1925
0
  ctx->useEmulatedCard = freerdp_settings_get_bool(settings, FreeRDP_SmartcardEmulation);
1926
0
#endif
1927
1928
0
  if (ctx->useEmulatedCard)
1929
0
  {
1930
0
#if defined(WITH_SMARTCARD_EMULATE)
1931
0
    ctx->emulation = Emulate_New(settings);
1932
0
    if (!ctx->emulation)
1933
0
      goto fail;
1934
#else
1935
    WLog_Print(ctx->log, WLOG_ERROR, "Smartcard emulation requested, but not supported!");
1936
    goto fail;
1937
#endif
1938
0
  }
1939
0
  else
1940
0
  {
1941
0
    const char* WinSCardModule = freerdp_settings_get_string(settings, FreeRDP_WinSCardModule);
1942
0
    if (WinSCardModule)
1943
0
    {
1944
0
      ctx->hWinSCardLibrary = LoadLibraryX(WinSCardModule);
1945
1946
0
      if (!ctx->hWinSCardLibrary)
1947
0
      {
1948
0
        WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard library: '%s'",
1949
0
                   WinSCardModule);
1950
0
        goto fail;
1951
0
      }
1952
1953
0
      if (!WinSCard_LoadApiTableFunctions(&ctx->WinSCardApi, ctx->hWinSCardLibrary))
1954
0
        goto fail;
1955
0
      ctx->pWinSCardApi = &ctx->WinSCardApi;
1956
0
    }
1957
0
    else
1958
0
    {
1959
0
      ctx->pWinSCardApi = WinPR_GetSCardApiFunctionTable();
1960
0
    }
1961
1962
0
    if (!ctx->pWinSCardApi)
1963
0
    {
1964
0
      WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard API!");
1965
0
      goto fail;
1966
0
    }
1967
0
  }
1968
1969
0
  ctx->rgSCardContextList = HashTable_New(FALSE);
1970
0
  if (!ctx->rgSCardContextList)
1971
0
    goto fail;
1972
1973
0
  obj = HashTable_ValueObject(ctx->rgSCardContextList);
1974
0
  WINPR_ASSERT(obj);
1975
0
  obj->fnObjectFree = context_free;
1976
1977
0
  return ctx;
1978
0
fail:
1979
0
  WINPR_PRAGMA_DIAG_PUSH
1980
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1981
0
  smartcard_call_context_free(ctx);
1982
0
  WINPR_PRAGMA_DIAG_POP
1983
0
  return NULL;
1984
0
}
1985
1986
void smartcard_call_context_free(scard_call_context* ctx)
1987
0
{
1988
0
  if (!ctx)
1989
0
    return;
1990
1991
0
  smartcard_call_context_signal_stop(ctx, FALSE);
1992
1993
0
  LinkedList_Free(ctx->names);
1994
0
  if (ctx->StartedEvent)
1995
0
  {
1996
0
    WINPR_ASSERT(ctx->useEmulatedCard || ctx->pWinSCardApi);
1997
0
    wrap(ctx, SCardReleaseStartedEvent);
1998
0
  }
1999
2000
0
  if (ctx->useEmulatedCard)
2001
0
  {
2002
0
#ifdef WITH_SMARTCARD_EMULATE
2003
0
    if (ctx->emulation)
2004
0
    {
2005
0
      Emulate_Free(ctx->emulation);
2006
0
      ctx->emulation = NULL;
2007
0
    }
2008
0
#endif
2009
0
  }
2010
2011
0
  if (ctx->hWinSCardLibrary)
2012
0
  {
2013
0
    ZeroMemory(&ctx->WinSCardApi, sizeof(SCardApiFunctionTable));
2014
0
    FreeLibrary(ctx->hWinSCardLibrary);
2015
0
    ctx->hWinSCardLibrary = NULL;
2016
0
  }
2017
2018
0
  ctx->pWinSCardApi = NULL;
2019
2020
0
  HashTable_Free(ctx->rgSCardContextList);
2021
0
  (void)CloseHandle(ctx->stopEvent);
2022
0
  free(ctx);
2023
0
}
2024
2025
BOOL smartcard_call_context_add(scard_call_context* ctx, const char* name)
2026
0
{
2027
0
  WINPR_ASSERT(ctx);
2028
0
  WINPR_ASSERT(name);
2029
0
  return LinkedList_AddLast(ctx->names, name);
2030
0
}
2031
2032
BOOL smartcard_call_cancel_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2033
0
{
2034
0
  WINPR_ASSERT(ctx);
2035
0
  if (wrap(ctx, SCardIsValidContext, hContext) == SCARD_S_SUCCESS)
2036
0
  {
2037
0
    wrap(ctx, SCardCancel, hContext);
2038
0
  }
2039
0
  return TRUE;
2040
0
}
2041
2042
BOOL smartcard_call_release_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2043
0
{
2044
0
  WINPR_ASSERT(ctx);
2045
0
  wrap(ctx, SCardReleaseContext, hContext);
2046
0
  return TRUE;
2047
0
}
2048
2049
BOOL smartcard_call_cancel_all_context(scard_call_context* ctx)
2050
0
{
2051
0
  WINPR_ASSERT(ctx);
2052
2053
0
  HashTable_Clear(ctx->rgSCardContextList);
2054
0
  return TRUE;
2055
0
}
2056
2057
BOOL smarcard_call_set_callbacks(scard_call_context* ctx, void* userdata,
2058
                                 void* (*fn_new)(void*, SCARDCONTEXT), void (*fn_free)(void*))
2059
0
{
2060
0
  WINPR_ASSERT(ctx);
2061
0
  ctx->userdata = userdata;
2062
0
  ctx->fn_new = fn_new;
2063
0
  ctx->fn_free = fn_free;
2064
0
  return TRUE;
2065
0
}
2066
2067
void* smartcard_call_get_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2068
0
{
2069
0
  struct s_scard_context_element* element = NULL;
2070
2071
0
  WINPR_ASSERT(ctx);
2072
0
  element = HashTable_GetItemValue(ctx->rgSCardContextList, (void*)hContext);
2073
0
  if (!element)
2074
0
    return NULL;
2075
0
  return element->context;
2076
0
}
2077
2078
BOOL smartcard_call_is_configured(scard_call_context* ctx)
2079
0
{
2080
0
  WINPR_ASSERT(ctx);
2081
2082
0
#if defined(WITH_SMARTCARD_EMULATE)
2083
0
  if (ctx->useEmulatedCard)
2084
0
    return Emulate_IsConfigured(ctx->emulation);
2085
0
#endif
2086
2087
0
  return FALSE;
2088
0
}
2089
2090
BOOL smartcard_call_context_signal_stop(scard_call_context* ctx, BOOL reset)
2091
0
{
2092
0
  WINPR_ASSERT(ctx);
2093
0
  if (!ctx->stopEvent)
2094
0
    return TRUE;
2095
2096
0
  if (reset)
2097
0
    return ResetEvent(ctx->stopEvent);
2098
0
  else
2099
0
    return SetEvent(ctx->stopEvent);
2100
0
}