Coverage Report

Created: 2026-04-12 07:03

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