Coverage Report

Created: 2026-08-31 06:29

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.rgReaderStates = nullptr;
654
655
0
  if (call->cReaders > 0)
656
0
  {
657
0
    ret.rgReaderStates =
658
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
659
660
0
    if (!ret.rgReaderStates)
661
0
      return STATUS_NO_MEMORY;
662
0
    ret.cReaders = call->cReaders;
663
0
  }
664
665
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
666
0
  {
667
0
    ReaderState_Return* cur = &ret.rgReaderStates[x];
668
669
0
    cur->dwCurrentState = call->rgReaderStates[x].dwCurrentState;
670
0
    cur->dwEventState = call->rgReaderStates[x].dwEventState;
671
0
    cur->cbAtr = call->rgReaderStates[x].cbAtr;
672
0
    CopyMemory(&(cur->rgbAtr), &(call->rgReaderStates[x].rgbAtr), sizeof(cur->rgbAtr));
673
0
    if (!smartcard_reader_state_return_is_valid(x, cur))
674
0
    {
675
0
      free(ret.rgReaderStates);
676
0
      return SCARD_E_INVALID_ATR;
677
0
    }
678
0
  }
679
680
0
  status = smartcard_pack_locate_cards_return(out, &ret);
681
682
0
  if (status != SCARD_S_SUCCESS)
683
0
    return status;
684
685
0
  return ret.ReturnCode;
686
0
}
687
688
static LONG smartcard_LocateCardsW_Call(scard_call_context* smartcard, wStream* out,
689
                                        SMARTCARD_OPERATION* operation)
690
0
{
691
0
  LONG status = 0;
692
0
  LocateCards_Return ret = WINPR_C_ARRAY_INIT;
693
0
  LocateCardsW_Call* call = nullptr;
694
695
0
  WINPR_ASSERT(smartcard);
696
0
  WINPR_ASSERT(operation);
697
698
0
  call = &operation->call.locateCardsW;
699
700
0
  ret.ReturnCode = wrap(smartcard, SCardLocateCardsW, operation->hContext, call->mszCards,
701
0
                        call->rgReaderStates, call->cReaders);
702
0
  scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsW", ret.ReturnCode);
703
0
  ret.rgReaderStates = nullptr;
704
705
0
  if (call->cReaders > 0)
706
0
  {
707
0
    ret.rgReaderStates =
708
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
709
710
0
    if (!ret.rgReaderStates)
711
0
      return STATUS_NO_MEMORY;
712
0
    ret.cReaders = call->cReaders;
713
0
  }
714
715
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
716
0
  {
717
0
    ReaderState_Return* cur = &ret.rgReaderStates[x];
718
719
0
    cur->dwCurrentState = call->rgReaderStates[x].dwCurrentState;
720
0
    cur->dwEventState = call->rgReaderStates[x].dwEventState;
721
0
    cur->cbAtr = call->rgReaderStates[x].cbAtr;
722
0
    CopyMemory(&(cur->rgbAtr), &(call->rgReaderStates[x].rgbAtr), sizeof(cur->rgbAtr));
723
0
    if (!smartcard_reader_state_return_is_valid(x, cur))
724
0
    {
725
0
      free(ret.rgReaderStates);
726
0
      return SCARD_E_INVALID_ATR;
727
0
    }
728
0
  }
729
730
0
  status = smartcard_pack_locate_cards_return(out, &ret);
731
732
0
  if (status != SCARD_S_SUCCESS)
733
0
    return status;
734
735
0
  return ret.ReturnCode;
736
0
}
737
738
static LONG smartcard_ReadCacheA_Call(scard_call_context* smartcard, wStream* out,
739
                                      SMARTCARD_OPERATION* operation)
740
0
{
741
0
  LONG status = 0;
742
0
  BOOL autoalloc = 0;
743
0
  ReadCache_Return ret = WINPR_C_ARRAY_INIT;
744
0
  ReadCacheA_Call* call = nullptr;
745
746
0
  WINPR_ASSERT(smartcard);
747
0
  WINPR_ASSERT(out);
748
0
  WINPR_ASSERT(operation);
749
750
0
  call = &operation->call.readCacheA;
751
0
  autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
752
753
0
  if (!call->Common.fPbDataIsNULL)
754
0
  {
755
0
    if (!autoalloc)
756
0
    {
757
0
      ret.pbData = malloc(call->Common.cbDataLen);
758
0
      if (!ret.pbData)
759
0
        return SCARD_F_INTERNAL_ERROR;
760
0
    }
761
0
    ret.cbDataLen = call->Common.cbDataLen;
762
0
  }
763
764
0
  if (autoalloc)
765
0
    ret.ReturnCode = wrap(smartcard, SCardReadCacheA, operation->hContext,
766
0
                          call->Common.CardIdentifier, call->Common.FreshnessCounter,
767
0
                          call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
768
0
  else
769
0
    ret.ReturnCode =
770
0
        wrap(smartcard, SCardReadCacheA, operation->hContext, call->Common.CardIdentifier,
771
0
             call->Common.FreshnessCounter, call->szLookupName, ret.pbData, &ret.cbDataLen);
772
773
0
  WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
774
0
             ret.cbDataLen);
775
776
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
777
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
778
0
  {
779
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheA", ret.ReturnCode);
780
0
  }
781
782
0
  status = smartcard_pack_read_cache_return(out, &ret);
783
0
  if (autoalloc)
784
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
785
0
  else
786
0
    free(ret.pbData);
787
0
  if (status != SCARD_S_SUCCESS)
788
0
    return status;
789
790
0
  return ret.ReturnCode;
791
0
}
792
793
static LONG smartcard_ReadCacheW_Call(scard_call_context* smartcard, wStream* out,
794
                                      SMARTCARD_OPERATION* operation)
795
0
{
796
0
  LONG status = 0;
797
0
  ReadCache_Return ret = WINPR_C_ARRAY_INIT;
798
0
  ReadCacheW_Call* call = nullptr;
799
800
0
  WINPR_ASSERT(smartcard);
801
0
  WINPR_ASSERT(out);
802
0
  WINPR_ASSERT(operation);
803
804
0
  call = &operation->call.readCacheW;
805
806
0
  if (!call->Common.fPbDataIsNULL)
807
0
    ret.cbDataLen = SCARD_AUTOALLOCATE;
808
809
0
  ret.ReturnCode =
810
0
      wrap(smartcard, SCardReadCacheW, operation->hContext, call->Common.CardIdentifier,
811
0
           call->Common.FreshnessCounter, call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
812
813
0
  if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
814
0
  {
815
0
    char buffer[128] = WINPR_C_ARRAY_INIT;
816
0
    (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
817
0
    WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer, ret.cbDataLen);
818
0
  }
819
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
820
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
821
0
  {
822
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheW", ret.ReturnCode);
823
0
  }
824
825
0
  status = smartcard_pack_read_cache_return(out, &ret);
826
827
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
828
829
0
  if (status != SCARD_S_SUCCESS)
830
0
    return status;
831
832
0
  return ret.ReturnCode;
833
0
}
834
835
static LONG smartcard_WriteCacheA_Call(scard_call_context* smartcard,
836
                                       WINPR_ATTR_UNUSED wStream* out,
837
                                       SMARTCARD_OPERATION* operation)
838
0
{
839
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
840
0
  WriteCacheA_Call* call = nullptr;
841
842
0
  WINPR_ASSERT(smartcard);
843
0
  WINPR_ASSERT(out);
844
0
  WINPR_ASSERT(operation);
845
846
0
  call = &operation->call.writeCacheA;
847
848
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheA, operation->hContext,
849
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
850
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
851
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheA", ret.ReturnCode);
852
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheA");
853
0
  WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
854
0
             call->Common.cbDataLen);
855
0
  return ret.ReturnCode;
856
0
}
857
858
static LONG smartcard_WriteCacheW_Call(scard_call_context* smartcard,
859
                                       WINPR_ATTR_UNUSED wStream* out,
860
                                       SMARTCARD_OPERATION* operation)
861
0
{
862
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
863
0
  WriteCacheW_Call* call = nullptr;
864
865
0
  WINPR_ASSERT(smartcard);
866
0
  WINPR_ASSERT(out);
867
0
  WINPR_ASSERT(operation);
868
869
0
  call = &operation->call.writeCacheW;
870
871
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheW, operation->hContext,
872
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
873
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
874
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheW", ret.ReturnCode);
875
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheW");
876
877
0
  if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
878
0
  {
879
0
    char buffer[128] = WINPR_C_ARRAY_INIT;
880
0
    (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
881
0
    WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer,
882
0
               call->Common.cbDataLen);
883
0
  }
884
0
  return ret.ReturnCode;
885
0
}
886
887
static LONG smartcard_GetTransmitCount_Call(scard_call_context* smartcard, wStream* out,
888
                                            SMARTCARD_OPERATION* operation)
889
0
{
890
0
  LONG status = 0;
891
0
  GetTransmitCount_Return ret = WINPR_C_ARRAY_INIT;
892
893
0
  WINPR_ASSERT(smartcard);
894
0
  WINPR_ASSERT(out);
895
0
  WINPR_ASSERT(operation);
896
897
0
  ret.ReturnCode = wrap(smartcard, SCardGetTransmitCount, operation->hCard, &ret.cTransmitCount);
898
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetTransmitCount", ret.ReturnCode);
899
0
  status = smartcard_pack_get_transmit_count_return(out, &ret);
900
0
  if (status != SCARD_S_SUCCESS)
901
0
    return status;
902
903
0
  return ret.ReturnCode;
904
0
}
905
906
static LONG smartcard_ReleaseStartedEvent_Call(scard_call_context* smartcard, wStream* out,
907
                                               SMARTCARD_OPERATION* operation)
908
0
{
909
0
  WINPR_UNUSED(smartcard);
910
0
  WINPR_UNUSED(out);
911
0
  WINPR_UNUSED(operation);
912
913
0
  WLog_Print(smartcard->log, WLOG_WARN,
914
0
             "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
915
0
             "this is not supported?!?");
916
0
  return SCARD_E_UNSUPPORTED_FEATURE;
917
0
}
918
919
static LONG smartcard_GetReaderIcon_Call(scard_call_context* smartcard, wStream* out,
920
                                         SMARTCARD_OPERATION* operation)
921
0
{
922
0
  LONG status = 0;
923
0
  GetReaderIcon_Return ret = WINPR_C_ARRAY_INIT;
924
0
  GetReaderIcon_Call* call = nullptr;
925
926
0
  WINPR_ASSERT(smartcard);
927
0
  WINPR_ASSERT(out);
928
0
  WINPR_ASSERT(operation);
929
930
0
  call = &operation->call.getReaderIcon;
931
932
0
  ret.cbDataLen = SCARD_AUTOALLOCATE;
933
0
  ret.ReturnCode = wrap(smartcard, SCardGetReaderIconW, operation->hContext, call->szReaderName,
934
0
                        (LPBYTE)&ret.pbData, &ret.cbDataLen);
935
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetReaderIconW", ret.ReturnCode);
936
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cbDataLen == SCARD_AUTOALLOCATE))
937
0
    return SCARD_F_UNKNOWN_ERROR;
938
939
0
  status = smartcard_pack_get_reader_icon_return(out, &ret);
940
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
941
0
  if (status != SCARD_S_SUCCESS)
942
0
    return status;
943
944
0
  return ret.ReturnCode;
945
0
}
946
947
static LONG smartcard_GetDeviceTypeId_Call(scard_call_context* smartcard, wStream* out,
948
                                           SMARTCARD_OPERATION* operation)
949
0
{
950
0
  LONG status = 0;
951
0
  GetDeviceTypeId_Return ret = WINPR_C_ARRAY_INIT;
952
0
  GetDeviceTypeId_Call* call = nullptr;
953
954
0
  WINPR_ASSERT(smartcard);
955
0
  WINPR_ASSERT(out);
956
0
  WINPR_ASSERT(operation);
957
958
0
  call = &operation->call.getDeviceTypeId;
959
960
0
  ret.ReturnCode = wrap(smartcard, SCardGetDeviceTypeIdW, operation->hContext, call->szReaderName,
961
0
                        &ret.dwDeviceId);
962
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetDeviceTypeIdW", ret.ReturnCode);
963
964
0
  status = smartcard_pack_device_type_id_return(out, &ret);
965
0
  if (status != SCARD_S_SUCCESS)
966
0
    return status;
967
968
0
  return ret.ReturnCode;
969
0
}
970
971
static BOOL smartcard_context_was_aborted(scard_call_context* smartcard)
972
0
{
973
0
  WINPR_ASSERT(smartcard);
974
975
0
  HANDLE handles[] = { smartcard->stopEvent, freerdp_abort_event(smartcard->context) };
976
0
  const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, 0);
977
0
  return (rc >= WAIT_OBJECT_0) && (rc <= WAIT_OBJECT_0 + ARRAYSIZE(handles));
978
0
}
979
980
static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard, wStream* out,
981
                                            SMARTCARD_OPERATION* operation)
982
0
{
983
0
  LONG status = STATUS_NO_MEMORY;
984
0
  DWORD dwTimeOut = 0;
985
0
  const DWORD dwTimeStep = 100;
986
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
987
0
  GetStatusChangeA_Call* call = nullptr;
988
0
  LPSCARD_READERSTATEA rgReaderStates = nullptr;
989
990
0
  WINPR_ASSERT(smartcard);
991
0
  WINPR_ASSERT(out);
992
0
  WINPR_ASSERT(operation);
993
994
0
  call = &operation->call.getStatusChangeA;
995
0
  dwTimeOut = call->dwTimeOut;
996
997
0
  if (call->cReaders > 0)
998
0
  {
999
0
    rgReaderStates = calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1000
0
    ret.rgReaderStates =
1001
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1002
0
    if (!rgReaderStates || !ret.rgReaderStates)
1003
0
      goto fail;
1004
1005
0
    ret.cReaders = call->cReaders;
1006
0
  }
1007
1008
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1009
0
  {
1010
0
    if (call->cReaders > 0)
1011
0
      memcpy(rgReaderStates, call->rgReaderStates,
1012
0
             call->cReaders * sizeof(SCARD_READERSTATEA));
1013
0
    ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1014
0
                          MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1015
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
1016
0
      break;
1017
0
    if (smartcard_context_was_aborted(smartcard))
1018
0
      break;
1019
0
    if (dwTimeOut != INFINITE)
1020
0
      x += dwTimeStep;
1021
0
  }
1022
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", ret.ReturnCode);
1023
1024
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
1025
0
  {
1026
0
    const SCARD_READERSTATEA* cur = &rgReaderStates[index];
1027
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
1028
1029
0
    rout->dwCurrentState = cur->dwCurrentState;
1030
0
    rout->dwEventState = cur->dwEventState;
1031
0
    rout->cbAtr = cur->cbAtr;
1032
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1033
0
    if (!smartcard_reader_state_return_is_valid(index, rout))
1034
0
      goto fail;
1035
0
  }
1036
1037
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1038
0
fail:
1039
0
  free(ret.rgReaderStates);
1040
0
  free(rgReaderStates);
1041
0
  if (status != SCARD_S_SUCCESS)
1042
0
    return status;
1043
0
  return ret.ReturnCode;
1044
0
}
1045
1046
static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard, wStream* out,
1047
                                            SMARTCARD_OPERATION* operation)
1048
0
{
1049
0
  LONG status = STATUS_NO_MEMORY;
1050
0
  DWORD dwTimeOut = 0;
1051
0
  const DWORD dwTimeStep = 100;
1052
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1053
0
  LPSCARD_READERSTATEW rgReaderStates = nullptr;
1054
1055
0
  WINPR_ASSERT(smartcard);
1056
0
  WINPR_ASSERT(out);
1057
0
  WINPR_ASSERT(operation);
1058
1059
0
  GetStatusChangeW_Call* call = &operation->call.getStatusChangeW;
1060
0
  dwTimeOut = call->dwTimeOut;
1061
1062
0
  if (call->cReaders > 0)
1063
0
  {
1064
0
    rgReaderStates = calloc(call->cReaders, sizeof(SCARD_READERSTATEW));
1065
0
    ret.rgReaderStates =
1066
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1067
0
    if (!rgReaderStates || !ret.rgReaderStates)
1068
0
      goto fail;
1069
1070
0
    ret.cReaders = call->cReaders;
1071
0
  }
1072
1073
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1074
0
  {
1075
0
    if (call->cReaders > 0)
1076
0
      memcpy(rgReaderStates, call->rgReaderStates,
1077
0
             call->cReaders * sizeof(SCARD_READERSTATEW));
1078
0
    {
1079
0
      ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeW, operation->hContext,
1080
0
                            MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1081
0
    }
1082
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
1083
0
      break;
1084
0
    if (smartcard_context_was_aborted(smartcard))
1085
0
      break;
1086
0
    if (dwTimeOut != INFINITE)
1087
0
      x += dwTimeStep;
1088
0
  }
1089
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", ret.ReturnCode);
1090
1091
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
1092
0
  {
1093
0
    const SCARD_READERSTATEW* cur = &rgReaderStates[index];
1094
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
1095
1096
0
    rout->dwCurrentState = cur->dwCurrentState;
1097
0
    rout->dwEventState = cur->dwEventState;
1098
0
    rout->cbAtr = cur->cbAtr;
1099
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1100
0
    if (!smartcard_reader_state_return_is_valid(index, rout))
1101
0
      goto fail;
1102
0
  }
1103
1104
0
  status = smartcard_pack_get_status_change_return(out, &ret, TRUE);
1105
0
fail:
1106
0
  free(ret.rgReaderStates);
1107
0
  free(rgReaderStates);
1108
0
  if (status != SCARD_S_SUCCESS)
1109
0
    return status;
1110
0
  return ret.ReturnCode;
1111
0
}
1112
1113
static LONG smartcard_Cancel_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1114
                                  SMARTCARD_OPERATION* operation)
1115
0
{
1116
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1117
1118
0
  WINPR_ASSERT(smartcard);
1119
0
  WINPR_ASSERT(out);
1120
0
  WINPR_ASSERT(operation);
1121
1122
0
  ret.ReturnCode = wrap(smartcard, SCardCancel, operation->hContext);
1123
0
  scard_log_status_error_wlog(smartcard->log, "SCardCancel", ret.ReturnCode);
1124
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Cancel");
1125
0
  return ret.ReturnCode;
1126
0
}
1127
1128
static LONG smartcard_ConnectA_Call(scard_call_context* smartcard, wStream* out,
1129
                                    SMARTCARD_OPERATION* operation)
1130
0
{
1131
0
  LONG status = 0;
1132
0
  SCARDHANDLE hCard = 0;
1133
0
  Connect_Return ret = WINPR_C_ARRAY_INIT;
1134
0
  ConnectA_Call* call = nullptr;
1135
1136
0
  WINPR_ASSERT(smartcard);
1137
0
  WINPR_ASSERT(out);
1138
0
  WINPR_ASSERT(operation);
1139
1140
0
  call = &operation->call.connectA;
1141
1142
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1143
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1144
0
  {
1145
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1146
0
  }
1147
1148
0
  ret.ReturnCode = wrap(smartcard, SCardConnectA, operation->hContext, (char*)call->szReader,
1149
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1150
0
                        &ret.dwActiveProtocol);
1151
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1152
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1153
1154
0
  status = smartcard_pack_connect_return(out, &ret);
1155
0
  if (status != SCARD_S_SUCCESS)
1156
0
    goto out_fail;
1157
1158
0
  status = ret.ReturnCode;
1159
0
out_fail:
1160
1161
0
  return status;
1162
0
}
1163
1164
static LONG smartcard_ConnectW_Call(scard_call_context* smartcard, wStream* out,
1165
                                    SMARTCARD_OPERATION* operation)
1166
0
{
1167
0
  LONG status = 0;
1168
0
  SCARDHANDLE hCard = 0;
1169
0
  Connect_Return ret = WINPR_C_ARRAY_INIT;
1170
0
  ConnectW_Call* call = nullptr;
1171
1172
0
  WINPR_ASSERT(smartcard);
1173
0
  WINPR_ASSERT(out);
1174
0
  WINPR_ASSERT(operation);
1175
1176
0
  call = &operation->call.connectW;
1177
1178
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1179
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1180
0
  {
1181
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1182
0
  }
1183
1184
0
  ret.ReturnCode = wrap(smartcard, SCardConnectW, operation->hContext, (WCHAR*)call->szReader,
1185
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1186
0
                        &ret.dwActiveProtocol);
1187
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1188
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1189
1190
0
  status = smartcard_pack_connect_return(out, &ret);
1191
0
  if (status != SCARD_S_SUCCESS)
1192
0
    goto out_fail;
1193
1194
0
  status = ret.ReturnCode;
1195
0
out_fail:
1196
1197
0
  return status;
1198
0
}
1199
1200
static LONG smartcard_Reconnect_Call(scard_call_context* smartcard, wStream* out,
1201
                                     SMARTCARD_OPERATION* operation)
1202
0
{
1203
0
  LONG status = 0;
1204
0
  Reconnect_Return ret = WINPR_C_ARRAY_INIT;
1205
0
  Reconnect_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.reconnect;
1212
0
  ret.ReturnCode =
1213
0
      wrap(smartcard, SCardReconnect, operation->hCard, call->dwShareMode,
1214
0
           call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
1215
0
  scard_log_status_error_wlog(smartcard->log, "SCardReconnect", ret.ReturnCode);
1216
0
  status = smartcard_pack_reconnect_return(out, &ret);
1217
0
  if (status != SCARD_S_SUCCESS)
1218
0
    return status;
1219
1220
0
  return ret.ReturnCode;
1221
0
}
1222
1223
static LONG smartcard_Disconnect_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1224
                                      SMARTCARD_OPERATION* operation)
1225
0
{
1226
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1227
0
  HCardAndDisposition_Call* call = nullptr;
1228
1229
0
  WINPR_ASSERT(smartcard);
1230
0
  WINPR_ASSERT(out);
1231
0
  WINPR_ASSERT(operation);
1232
1233
0
  call = &operation->call.hCardAndDisposition;
1234
1235
0
  ret.ReturnCode = wrap(smartcard, SCardDisconnect, operation->hCard, call->dwDisposition);
1236
0
  scard_log_status_error_wlog(smartcard->log, "SCardDisconnect", ret.ReturnCode);
1237
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Disconnect");
1238
1239
0
  return ret.ReturnCode;
1240
0
}
1241
1242
static LONG smartcard_BeginTransaction_Call(scard_call_context* smartcard,
1243
                                            WINPR_ATTR_UNUSED wStream* out,
1244
                                            SMARTCARD_OPERATION* operation)
1245
0
{
1246
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1247
1248
0
  WINPR_ASSERT(smartcard);
1249
0
  WINPR_ASSERT(out);
1250
0
  WINPR_ASSERT(operation);
1251
1252
0
  ret.ReturnCode = wrap(smartcard, SCardBeginTransaction, operation->hCard);
1253
0
  scard_log_status_error_wlog(smartcard->log, "SCardBeginTransaction", ret.ReturnCode);
1254
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "BeginTransaction");
1255
0
  return ret.ReturnCode;
1256
0
}
1257
1258
static LONG smartcard_EndTransaction_Call(scard_call_context* smartcard,
1259
                                          WINPR_ATTR_UNUSED wStream* out,
1260
                                          SMARTCARD_OPERATION* operation)
1261
0
{
1262
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1263
0
  HCardAndDisposition_Call* call = nullptr;
1264
1265
0
  WINPR_ASSERT(smartcard);
1266
0
  WINPR_ASSERT(out);
1267
0
  WINPR_ASSERT(operation);
1268
1269
0
  call = &operation->call.hCardAndDisposition;
1270
1271
0
  ret.ReturnCode = wrap(smartcard, SCardEndTransaction, operation->hCard, call->dwDisposition);
1272
0
  scard_log_status_error_wlog(smartcard->log, "SCardEndTransaction", ret.ReturnCode);
1273
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "EndTransaction");
1274
0
  return ret.ReturnCode;
1275
0
}
1276
1277
static LONG smartcard_State_Call(scard_call_context* smartcard, wStream* out,
1278
                                 SMARTCARD_OPERATION* operation)
1279
0
{
1280
0
  LONG status = 0;
1281
0
  State_Return ret = WINPR_C_ARRAY_INIT;
1282
1283
0
  WINPR_ASSERT(smartcard);
1284
0
  WINPR_ASSERT(out);
1285
0
  WINPR_ASSERT(operation);
1286
1287
0
  ret.cbAtrLen = SCARD_ATR_LENGTH;
1288
0
  ret.ReturnCode = wrap(smartcard, SCardState, operation->hCard, &ret.dwState, &ret.dwProtocol,
1289
0
                        (BYTE*)&ret.rgAtr, &ret.cbAtrLen);
1290
1291
0
  scard_log_status_error_wlog(smartcard->log, "SCardState", ret.ReturnCode);
1292
0
  status = smartcard_pack_state_return(out, &ret);
1293
0
  if (status != SCARD_S_SUCCESS)
1294
0
    return status;
1295
1296
0
  return ret.ReturnCode;
1297
0
}
1298
1299
static LONG smartcard_StatusA_Call(scard_call_context* smartcard, wStream* out,
1300
                                   SMARTCARD_OPERATION* operation)
1301
0
{
1302
0
  LONG status = 0;
1303
0
  Status_Return ret = WINPR_C_ARRAY_INIT;
1304
0
  DWORD cchReaderLen = 0;
1305
0
  DWORD cbAtrLen = 0;
1306
0
  LPSTR mszReaderNames = nullptr;
1307
0
  Status_Call* call = nullptr;
1308
1309
0
  WINPR_ASSERT(smartcard);
1310
0
  WINPR_ASSERT(out);
1311
0
  WINPR_ASSERT(operation);
1312
1313
0
  call = &operation->call.status;
1314
1315
0
  call->cbAtrLen = 32;
1316
0
  cbAtrLen = call->cbAtrLen;
1317
1318
0
  if (call->fmszReaderNamesIsNULL)
1319
0
    cchReaderLen = 0;
1320
0
  else
1321
0
    cchReaderLen = SCARD_AUTOALLOCATE;
1322
1323
0
  status = ret.ReturnCode =
1324
0
      wrap(smartcard, SCardStatusA, operation->hCard,
1325
0
           call->fmszReaderNamesIsNULL ? nullptr : (LPSTR)&mszReaderNames, &cchReaderLen,
1326
0
           &ret.dwState, &ret.dwProtocol, cbAtrLen ? (BYTE*)&ret.pbAtr : nullptr, &cbAtrLen);
1327
1328
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusA", status);
1329
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchReaderLen == SCARD_AUTOALLOCATE))
1330
0
    return SCARD_F_UNKNOWN_ERROR;
1331
1332
0
  if (status == SCARD_S_SUCCESS)
1333
0
  {
1334
0
    if (!call->fmszReaderNamesIsNULL)
1335
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1336
1337
0
    ret.cBytes = cchReaderLen;
1338
1339
0
    if (call->cbAtrLen)
1340
0
      ret.cbAtrLen = cbAtrLen;
1341
0
  }
1342
1343
0
  status = smartcard_pack_status_return(out, &ret, FALSE);
1344
1345
0
  if (mszReaderNames)
1346
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1347
1348
0
  if (status != SCARD_S_SUCCESS)
1349
0
    return status;
1350
0
  return ret.ReturnCode;
1351
0
}
1352
1353
static LONG smartcard_StatusW_Call(scard_call_context* smartcard, wStream* out,
1354
                                   SMARTCARD_OPERATION* operation)
1355
0
{
1356
0
  LONG status = 0;
1357
0
  Status_Return ret = WINPR_C_ARRAY_INIT;
1358
0
  LPWSTR mszReaderNames = nullptr;
1359
0
  Status_Call* call = nullptr;
1360
0
  DWORD cbAtrLen = 0;
1361
1362
0
  WINPR_ASSERT(smartcard);
1363
0
  WINPR_ASSERT(out);
1364
0
  WINPR_ASSERT(operation);
1365
1366
0
  call = &operation->call.status;
1367
1368
  /**
1369
   * [MS-RDPESC]
1370
   * According to 2.2.2.18 Status_Call cbAtrLen is unused an must be ignored upon receipt.
1371
   */
1372
0
  cbAtrLen = call->cbAtrLen = 32;
1373
1374
0
  if (call->fmszReaderNamesIsNULL)
1375
0
    ret.cBytes = 0;
1376
0
  else
1377
0
    ret.cBytes = SCARD_AUTOALLOCATE;
1378
1379
0
  status = ret.ReturnCode =
1380
0
      wrap(smartcard, SCardStatusW, operation->hCard,
1381
0
           call->fmszReaderNamesIsNULL ? nullptr : (LPWSTR)&mszReaderNames, &ret.cBytes,
1382
0
           &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
1383
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusW", status);
1384
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cBytes == SCARD_AUTOALLOCATE))
1385
0
    return SCARD_F_UNKNOWN_ERROR;
1386
1387
0
  size_t blen = 0;
1388
0
  if (status == SCARD_S_SUCCESS)
1389
0
  {
1390
0
    if (!call->fmszReaderNamesIsNULL)
1391
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1392
1393
0
    ret.cbAtrLen = cbAtrLen;
1394
0
  }
1395
1396
0
  if (ret.cBytes != SCARD_AUTOALLOCATE)
1397
0
  {
1398
    /* SCardStatusW returns number of characters, we need number of bytes */
1399
0
    WINPR_ASSERT(ret.cBytes < SCARD_AUTOALLOCATE / sizeof(WCHAR));
1400
0
    blen = sizeof(WCHAR) * ret.cBytes;
1401
0
    WINPR_ASSERT(blen <= UINT32_MAX);
1402
0
    ret.cBytes = (UINT32)blen;
1403
0
  }
1404
1405
0
  status = smartcard_pack_status_return(out, &ret, TRUE);
1406
0
  if (status != SCARD_S_SUCCESS)
1407
0
    return status;
1408
1409
0
  if (mszReaderNames)
1410
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1411
1412
0
  return ret.ReturnCode;
1413
0
}
1414
1415
static LONG smartcard_Transmit_Call(scard_call_context* smartcard, wStream* out,
1416
                                    SMARTCARD_OPERATION* operation)
1417
0
{
1418
0
  LONG status = 0;
1419
0
  Transmit_Return ret = WINPR_C_ARRAY_INIT;
1420
0
  Transmit_Call* call = nullptr;
1421
1422
0
  WINPR_ASSERT(smartcard);
1423
0
  WINPR_ASSERT(out);
1424
0
  WINPR_ASSERT(operation);
1425
1426
0
  call = &operation->call.transmit;
1427
0
  ret.cbRecvLength = 0;
1428
0
  ret.pbRecvBuffer = nullptr;
1429
1430
0
  if (call->cbRecvLength && !call->fpbRecvBufferIsNULL)
1431
0
  {
1432
0
    if (call->cbRecvLength >= 66560)
1433
0
      call->cbRecvLength = 66560;
1434
1435
0
    const UINT32 cbRecvLength = call->cbRecvLength;
1436
0
    ret.pbRecvBuffer = (BYTE*)malloc(cbRecvLength);
1437
1438
0
    if (!ret.pbRecvBuffer)
1439
0
      return STATUS_NO_MEMORY;
1440
0
    ret.cbRecvLength = cbRecvLength;
1441
0
  }
1442
1443
0
  ret.pioRecvPci = call->pioRecvPci;
1444
0
  ret.ReturnCode =
1445
0
      wrap(smartcard, SCardTransmit, operation->hCard, call->pioSendPci, call->pbSendBuffer,
1446
0
           call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
1447
1448
0
  scard_log_status_error_wlog(smartcard->log, "SCardTransmit", ret.ReturnCode);
1449
1450
0
  status = smartcard_pack_transmit_return(out, &ret);
1451
0
  free(ret.pbRecvBuffer);
1452
1453
0
  if (status != SCARD_S_SUCCESS)
1454
0
    return status;
1455
0
  return ret.ReturnCode;
1456
0
}
1457
1458
static LONG smartcard_Control_Call(scard_call_context* smartcard, wStream* out,
1459
                                   SMARTCARD_OPERATION* operation)
1460
0
{
1461
0
  LONG status = 0;
1462
0
  Control_Return ret = WINPR_C_ARRAY_INIT;
1463
0
  Control_Call* call = nullptr;
1464
1465
0
  WINPR_ASSERT(smartcard);
1466
0
  WINPR_ASSERT(out);
1467
0
  WINPR_ASSERT(operation);
1468
1469
0
  call = &operation->call.control;
1470
0
  ret.pvOutBuffer = (BYTE*)malloc(call->cbOutBufferSize);
1471
1472
0
  if (!ret.pvOutBuffer)
1473
0
    return SCARD_E_NO_MEMORY;
1474
0
  ret.cbOutBufferSize = call->cbOutBufferSize;
1475
1476
0
  ret.ReturnCode =
1477
0
      wrap(smartcard, SCardControl, operation->hCard, call->dwControlCode, call->pvInBuffer,
1478
0
           call->cbInBufferSize, ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
1479
0
  scard_log_status_error_wlog(smartcard->log, "SCardControl", ret.ReturnCode);
1480
0
  status = smartcard_pack_control_return(out, &ret);
1481
1482
0
  free(ret.pvOutBuffer);
1483
0
  if (status != SCARD_S_SUCCESS)
1484
0
    return status;
1485
0
  return ret.ReturnCode;
1486
0
}
1487
1488
static LONG smartcard_GetAttrib_Call(scard_call_context* smartcard, wStream* out,
1489
                                     SMARTCARD_OPERATION* operation)
1490
0
{
1491
0
  BOOL autoAllocate = FALSE;
1492
0
  LONG status = 0;
1493
0
  DWORD cbAttrLen = 0;
1494
0
  LPBYTE pbAttr = nullptr;
1495
0
  GetAttrib_Return ret = WINPR_C_ARRAY_INIT;
1496
0
  const GetAttrib_Call* call = nullptr;
1497
1498
0
  WINPR_ASSERT(smartcard);
1499
0
  WINPR_ASSERT(operation);
1500
1501
0
  call = &operation->call.getAttrib;
1502
1503
0
  if (!call->fpbAttrIsNULL)
1504
0
  {
1505
0
    autoAllocate = (call->cbAttrLen == SCARD_AUTOALLOCATE);
1506
0
    cbAttrLen = call->cbAttrLen;
1507
0
    if (cbAttrLen && !autoAllocate)
1508
0
    {
1509
0
      ret.pbAttr = (BYTE*)malloc(cbAttrLen);
1510
1511
0
      if (!ret.pbAttr)
1512
0
        return SCARD_E_NO_MEMORY;
1513
0
    }
1514
1515
0
    pbAttr = autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr;
1516
0
  }
1517
1518
0
  ret.ReturnCode =
1519
0
      wrap(smartcard, SCardGetAttrib, operation->hCard, call->dwAttrId, pbAttr, &cbAttrLen);
1520
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetAttrib", ret.ReturnCode);
1521
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cbAttrLen == SCARD_AUTOALLOCATE))
1522
0
    return SCARD_F_UNKNOWN_ERROR;
1523
1524
0
  ret.cbAttrLen = cbAttrLen;
1525
1526
0
  status = smartcard_pack_get_attrib_return(out, &ret, call->dwAttrId, call->cbAttrLen);
1527
1528
0
  if (autoAllocate)
1529
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbAttr);
1530
0
  else
1531
0
    free(ret.pbAttr);
1532
0
  return status;
1533
0
}
1534
1535
static LONG smartcard_SetAttrib_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1536
                                     SMARTCARD_OPERATION* operation)
1537
0
{
1538
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1539
0
  SetAttrib_Call* call = nullptr;
1540
1541
0
  WINPR_ASSERT(smartcard);
1542
0
  WINPR_ASSERT(out);
1543
0
  WINPR_ASSERT(operation);
1544
1545
0
  call = &operation->call.setAttrib;
1546
1547
0
  ret.ReturnCode = wrap(smartcard, SCardSetAttrib, operation->hCard, call->dwAttrId, call->pbAttr,
1548
0
                        call->cbAttrLen);
1549
0
  scard_log_status_error_wlog(smartcard->log, "SCardSetAttrib", ret.ReturnCode);
1550
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SetAttrib");
1551
1552
0
  return ret.ReturnCode;
1553
0
}
1554
1555
static LONG smartcard_AccessStartedEvent_Call(scard_call_context* smartcard,
1556
                                              WINPR_ATTR_UNUSED wStream* out,
1557
                                              SMARTCARD_OPERATION* operation)
1558
0
{
1559
0
  LONG status = SCARD_S_SUCCESS;
1560
1561
0
  WINPR_ASSERT(smartcard);
1562
0
  WINPR_ASSERT(out);
1563
0
  WINPR_UNUSED(operation);
1564
1565
0
  if (!smartcard->StartedEvent)
1566
0
    smartcard->StartedEvent = wrap_ptr(smartcard, SCardAccessStartedEvent);
1567
1568
0
  if (!smartcard->StartedEvent)
1569
0
    status = SCARD_E_NO_SERVICE;
1570
1571
0
  return status;
1572
0
}
1573
1574
static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStream* out,
1575
                                             SMARTCARD_OPERATION* operation)
1576
0
{
1577
0
  LONG status = 0;
1578
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1579
0
  LPSCARD_READERSTATEA states = nullptr;
1580
0
  LocateCardsByATRA_Call* call = nullptr;
1581
1582
0
  WINPR_ASSERT(smartcard);
1583
0
  WINPR_ASSERT(operation);
1584
1585
0
  call = &operation->call.locateCardsByATRA;
1586
0
  states = (LPSCARD_READERSTATEA)calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1587
1588
0
  if (!states)
1589
0
    return STATUS_NO_MEMORY;
1590
1591
0
  for (UINT32 i = 0; i < call->cReaders; i++)
1592
0
  {
1593
0
    LPSCARD_READERSTATEA state = &states[i];
1594
0
    state->szReader = call->rgReaderStates[i].szReader;
1595
0
    state->dwCurrentState = call->rgReaderStates[i].dwCurrentState;
1596
0
    state->dwEventState = call->rgReaderStates[i].dwEventState;
1597
0
    state->cbAtr = call->rgReaderStates[i].cbAtr;
1598
0
    CopyMemory(&(state->rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36);
1599
0
  }
1600
1601
0
  status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1602
0
                                 0x000001F4, states, call->cReaders);
1603
1604
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", status);
1605
0
  for (UINT32 i = 0; i < call->cAtrs; i++)
1606
0
  {
1607
0
    for (UINT32 j = 0; j < call->cReaders; j++)
1608
0
    {
1609
0
      for (UINT32 k = 0; k < call->rgAtrMasks[i].cbAtr; k++)
1610
0
      {
1611
0
        if ((call->rgAtrMasks[i].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]) !=
1612
0
            (states[j].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]))
1613
0
        {
1614
0
          break;
1615
0
        }
1616
1617
0
        states[j].dwEventState |= SCARD_STATE_ATRMATCH;
1618
0
      }
1619
0
    }
1620
0
  }
1621
1622
0
  ret.rgReaderStates = nullptr;
1623
1624
0
  if (call->cReaders > 0)
1625
0
    ret.rgReaderStates =
1626
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1627
1628
0
  if (!ret.rgReaderStates)
1629
0
  {
1630
0
    free(states);
1631
0
    return STATUS_NO_MEMORY;
1632
0
  }
1633
1634
0
  ret.cReaders = call->cReaders;
1635
1636
0
  for (UINT32 i = 0; i < ret.cReaders; i++)
1637
0
  {
1638
0
    LPSCARD_READERSTATEA state = &states[i];
1639
0
    ReaderState_Return* cur = &ret.rgReaderStates[i];
1640
1641
0
    cur->dwCurrentState = state->dwCurrentState;
1642
0
    cur->dwEventState = state->dwEventState;
1643
0
    cur->cbAtr = state->cbAtr;
1644
0
    CopyMemory(&(cur->rgbAtr), &(state->rgbAtr), sizeof(cur->rgbAtr));
1645
1646
0
    if (!smartcard_reader_state_return_is_valid(i, cur))
1647
0
    {
1648
0
      free(states);
1649
0
      free(ret.rgReaderStates);
1650
0
      return SCARD_E_INVALID_ATR;
1651
0
    }
1652
0
  }
1653
1654
0
  free(states);
1655
1656
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1657
1658
0
  free(ret.rgReaderStates);
1659
0
  if (status != SCARD_S_SUCCESS)
1660
0
    return status;
1661
0
  return ret.ReturnCode;
1662
0
}
1663
1664
LONG smartcard_irp_device_control_call(scard_call_context* ctx, wStream* out, NTSTATUS* pIoStatus,
1665
                                       SMARTCARD_OPERATION* operation)
1666
0
{
1667
0
  LONG result = 0;
1668
0
  UINT32 offset = 0;
1669
0
  size_t objectBufferLength = 0;
1670
1671
0
  WINPR_ASSERT(ctx);
1672
0
  WINPR_ASSERT(out);
1673
0
  WINPR_ASSERT(pIoStatus);
1674
0
  WINPR_ASSERT(operation);
1675
1676
0
  const UINT32 ioControlCode = operation->ioControlCode;
1677
  /**
1678
   * [MS-RDPESC] 3.2.5.1: Sending Outgoing Messages:
1679
   * the output buffer length SHOULD be set to 2048
1680
   *
1681
   * Since it's a SHOULD and not a MUST, we don't care
1682
   * about it, but we still reserve at least 2048 bytes.
1683
   */
1684
0
  const size_t outMaxLen = MAX(2048, operation->outputBufferLength);
1685
0
  if (!Stream_EnsureRemainingCapacity(out, outMaxLen))
1686
0
    return SCARD_E_NO_MEMORY;
1687
1688
  /* Device Control Response */
1689
0
  Stream_Write_UINT32(out, 0);                            /* OutputBufferLength (4 bytes) */
1690
0
  Stream_Zero(out, SMARTCARD_COMMON_TYPE_HEADER_LENGTH);  /* CommonTypeHeader (8 bytes) */
1691
0
  Stream_Zero(out, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
1692
0
  Stream_Write_UINT32(out, 0);                            /* Result (4 bytes) */
1693
1694
  /* Call */
1695
0
  switch (ioControlCode)
1696
0
  {
1697
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1698
0
      result = smartcard_EstablishContext_Call(ctx, out, operation);
1699
0
      break;
1700
1701
0
    case SCARD_IOCTL_RELEASECONTEXT:
1702
0
      result = smartcard_ReleaseContext_Call(ctx, out, operation);
1703
0
      break;
1704
1705
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1706
0
      result = smartcard_IsValidContext_Call(ctx, out, operation);
1707
0
      break;
1708
1709
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1710
0
      result = smartcard_ListReaderGroupsA_Call(ctx, out, operation);
1711
0
      break;
1712
1713
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1714
0
      result = smartcard_ListReaderGroupsW_Call(ctx, out, operation);
1715
0
      break;
1716
1717
0
    case SCARD_IOCTL_LISTREADERSA:
1718
0
      result = smartcard_ListReadersA_Call(ctx, out, operation);
1719
0
      break;
1720
1721
0
    case SCARD_IOCTL_LISTREADERSW:
1722
0
      result = smartcard_ListReadersW_Call(ctx, out, operation);
1723
0
      break;
1724
1725
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1726
0
      result = smartcard_IntroduceReaderGroupA_Call(ctx, out, operation);
1727
0
      break;
1728
1729
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1730
0
      result = smartcard_IntroduceReaderGroupW_Call(ctx, out, operation);
1731
0
      break;
1732
1733
0
    case SCARD_IOCTL_FORGETREADERGROUPA:
1734
0
      result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1735
0
      break;
1736
1737
0
    case SCARD_IOCTL_FORGETREADERGROUPW:
1738
0
      result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1739
0
      break;
1740
1741
0
    case SCARD_IOCTL_INTRODUCEREADERA:
1742
0
      result = smartcard_IntroduceReaderA_Call(ctx, out, operation);
1743
0
      break;
1744
1745
0
    case SCARD_IOCTL_INTRODUCEREADERW:
1746
0
      result = smartcard_IntroduceReaderW_Call(ctx, out, operation);
1747
0
      break;
1748
1749
0
    case SCARD_IOCTL_FORGETREADERA:
1750
0
      result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1751
0
      break;
1752
1753
0
    case SCARD_IOCTL_FORGETREADERW:
1754
0
      result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1755
0
      break;
1756
1757
0
    case SCARD_IOCTL_ADDREADERTOGROUPA:
1758
0
      result = smartcard_AddReaderToGroupA_Call(ctx, out, operation);
1759
0
      break;
1760
1761
0
    case SCARD_IOCTL_ADDREADERTOGROUPW:
1762
0
      result = smartcard_AddReaderToGroupW_Call(ctx, out, operation);
1763
0
      break;
1764
1765
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1766
0
      result = smartcard_RemoveReaderFromGroupA_Call(ctx, out, operation);
1767
0
      break;
1768
1769
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1770
0
      result = smartcard_RemoveReaderFromGroupW_Call(ctx, out, operation);
1771
0
      break;
1772
1773
0
    case SCARD_IOCTL_LOCATECARDSA:
1774
0
      result = smartcard_LocateCardsA_Call(ctx, out, operation);
1775
0
      break;
1776
1777
0
    case SCARD_IOCTL_LOCATECARDSW:
1778
0
      result = smartcard_LocateCardsW_Call(ctx, out, operation);
1779
0
      break;
1780
1781
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1782
0
      result = smartcard_GetStatusChangeA_Call(ctx, out, operation);
1783
0
      break;
1784
1785
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1786
0
      result = smartcard_GetStatusChangeW_Call(ctx, out, operation);
1787
0
      break;
1788
1789
0
    case SCARD_IOCTL_CANCEL:
1790
0
      result = smartcard_Cancel_Call(ctx, out, operation);
1791
0
      break;
1792
1793
0
    case SCARD_IOCTL_CONNECTA:
1794
0
      result = smartcard_ConnectA_Call(ctx, out, operation);
1795
0
      break;
1796
1797
0
    case SCARD_IOCTL_CONNECTW:
1798
0
      result = smartcard_ConnectW_Call(ctx, out, operation);
1799
0
      break;
1800
1801
0
    case SCARD_IOCTL_RECONNECT:
1802
0
      result = smartcard_Reconnect_Call(ctx, out, operation);
1803
0
      break;
1804
1805
0
    case SCARD_IOCTL_DISCONNECT:
1806
0
      result = smartcard_Disconnect_Call(ctx, out, operation);
1807
0
      break;
1808
1809
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1810
0
      result = smartcard_BeginTransaction_Call(ctx, out, operation);
1811
0
      break;
1812
1813
0
    case SCARD_IOCTL_ENDTRANSACTION:
1814
0
      result = smartcard_EndTransaction_Call(ctx, out, operation);
1815
0
      break;
1816
1817
0
    case SCARD_IOCTL_STATE:
1818
0
      result = smartcard_State_Call(ctx, out, operation);
1819
0
      break;
1820
1821
0
    case SCARD_IOCTL_STATUSA:
1822
0
      result = smartcard_StatusA_Call(ctx, out, operation);
1823
0
      break;
1824
1825
0
    case SCARD_IOCTL_STATUSW:
1826
0
      result = smartcard_StatusW_Call(ctx, out, operation);
1827
0
      break;
1828
1829
0
    case SCARD_IOCTL_TRANSMIT:
1830
0
      result = smartcard_Transmit_Call(ctx, out, operation);
1831
0
      break;
1832
1833
0
    case SCARD_IOCTL_CONTROL:
1834
0
      result = smartcard_Control_Call(ctx, out, operation);
1835
0
      break;
1836
1837
0
    case SCARD_IOCTL_GETATTRIB:
1838
0
      result = smartcard_GetAttrib_Call(ctx, out, operation);
1839
0
      break;
1840
1841
0
    case SCARD_IOCTL_SETATTRIB:
1842
0
      result = smartcard_SetAttrib_Call(ctx, out, operation);
1843
0
      break;
1844
1845
0
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1846
0
      result = smartcard_AccessStartedEvent_Call(ctx, out, operation);
1847
0
      break;
1848
1849
0
    case SCARD_IOCTL_LOCATECARDSBYATRA:
1850
0
      result = smartcard_LocateCardsByATRA_Call(ctx, out, operation);
1851
0
      break;
1852
1853
0
    case SCARD_IOCTL_LOCATECARDSBYATRW:
1854
0
      result = smartcard_LocateCardsW_Call(ctx, out, operation);
1855
0
      break;
1856
1857
0
    case SCARD_IOCTL_READCACHEA:
1858
0
      result = smartcard_ReadCacheA_Call(ctx, out, operation);
1859
0
      break;
1860
1861
0
    case SCARD_IOCTL_READCACHEW:
1862
0
      result = smartcard_ReadCacheW_Call(ctx, out, operation);
1863
0
      break;
1864
1865
0
    case SCARD_IOCTL_WRITECACHEA:
1866
0
      result = smartcard_WriteCacheA_Call(ctx, out, operation);
1867
0
      break;
1868
1869
0
    case SCARD_IOCTL_WRITECACHEW:
1870
0
      result = smartcard_WriteCacheW_Call(ctx, out, operation);
1871
0
      break;
1872
1873
0
    case SCARD_IOCTL_GETTRANSMITCOUNT:
1874
0
      result = smartcard_GetTransmitCount_Call(ctx, out, operation);
1875
0
      break;
1876
1877
0
    case SCARD_IOCTL_RELEASETARTEDEVENT:
1878
0
      result = smartcard_ReleaseStartedEvent_Call(ctx, out, operation);
1879
0
      break;
1880
1881
0
    case SCARD_IOCTL_GETREADERICON:
1882
0
      result = smartcard_GetReaderIcon_Call(ctx, out, operation);
1883
0
      break;
1884
1885
0
    case SCARD_IOCTL_GETDEVICETYPEID:
1886
0
      result = smartcard_GetDeviceTypeId_Call(ctx, out, operation);
1887
0
      break;
1888
1889
0
    default:
1890
0
      result = STATUS_UNSUCCESSFUL;
1891
0
      break;
1892
0
  }
1893
1894
  /**
1895
   * [MS-RPCE] 2.2.6.3 Primitive Type Serialization
1896
   * The type MUST be aligned on an 8-byte boundary. If the size of the
1897
   * primitive type is not a multiple of 8 bytes, the data MUST be padded.
1898
   */
1899
1900
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
1901
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
1902
0
  {
1903
0
    offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH);
1904
0
    const LONG rc = smartcard_pack_write_size_align(out, Stream_GetPosition(out) - offset, 8);
1905
0
    if (rc != SCARD_S_SUCCESS)
1906
0
      result = rc;
1907
0
  }
1908
1909
0
  if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) &&
1910
0
      (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) &&
1911
0
      (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE))
1912
0
  {
1913
0
    scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
1914
0
                                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1915
0
  }
1916
1917
0
  *pIoStatus = STATUS_SUCCESS;
1918
1919
0
  if ((result & 0xC0000000L) == 0xC0000000L)
1920
0
  {
1921
    /* NTSTATUS error */
1922
0
    *pIoStatus = result;
1923
1924
0
    scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
1925
0
                                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1926
0
  }
1927
1928
0
  Stream_SealLength(out);
1929
0
  size_t outputBufferLength = Stream_Length(out);
1930
0
  size_t dataEndPos = outputBufferLength;
1931
1932
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1933
0
  outputBufferLength -= (RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1934
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH);
1935
0
  objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH;
1936
0
  WINPR_ASSERT(outputBufferLength <= UINT32_MAX);
1937
0
  WINPR_ASSERT(objectBufferLength <= UINT32_MAX);
1938
0
  if (!Stream_SetPosition(out, RDPDR_DEVICE_IO_RESPONSE_LENGTH))
1939
0
    return SCARD_E_BAD_SEEK;
1940
1941
  /* [MS-RDPESC] 3.2.5.2 Processing Incoming Replies
1942
   *
1943
   * if the output buffer is too small, reply with STATUS_BUFFER_TOO_SMALL
1944
   * and a outputBufferLength of 0.
1945
   * The message should then be retransmitted from the server with a doubled
1946
   * buffer size.
1947
   */
1948
0
  if (outputBufferLength > operation->outputBufferLength)
1949
0
  {
1950
0
    WLog_Print(ctx->log, WLOG_DEBUG,
1951
0
               "IRP  warn: expected outputBufferLength %" PRIuz ", but current limit %" PRIu32
1952
0
               ", respond with STATUS_BUFFER_TOO_SMALL for retransmit with larger buffer",
1953
0
               outputBufferLength, operation->outputBufferLength);
1954
1955
0
    *pIoStatus = STATUS_BUFFER_TOO_SMALL;
1956
0
    result = *pIoStatus;
1957
0
    outputBufferLength = 0;
1958
0
    objectBufferLength = 0;
1959
0
  }
1960
0
  else
1961
0
  {
1962
0
    WLog_Print(ctx->log, WLOG_TRACE, "IRP trace: outputBufferLength %" PRIuz ", limit %" PRIu32,
1963
0
               outputBufferLength, operation->outputBufferLength);
1964
0
  }
1965
1966
  /* Device Control Response */
1967
0
  Stream_Write_UINT32(out, (UINT32)outputBufferLength); /* OutputBufferLength (4 bytes) */
1968
0
  smartcard_pack_common_type_header(out);               /* CommonTypeHeader (8 bytes) */
1969
0
  smartcard_pack_private_type_header(
1970
0
      out, (UINT32)objectBufferLength); /* PrivateTypeHeader (8 bytes) */
1971
0
  Stream_Write_INT32(out, result);      /* Result (4 bytes) */
1972
0
  if (result == STATUS_BUFFER_TOO_SMALL)
1973
0
    Stream_SealLength(out);
1974
0
  else if (!Stream_SetPosition(out, dataEndPos))
1975
0
    return SCARD_E_BAD_SEEK;
1976
0
  return SCARD_S_SUCCESS;
1977
0
}
1978
1979
void context_free(void* arg)
1980
0
{
1981
0
  struct s_scard_context_element* element = arg;
1982
0
  if (!arg)
1983
0
    return;
1984
1985
0
  if (element->fn_free)
1986
0
    element->fn_free(element->context);
1987
0
  free(element);
1988
0
}
1989
1990
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
1991
scard_call_context* smartcard_call_context_new(const rdpSettings* settings)
1992
0
{
1993
0
  const freerdp* inst = freerdp_settings_get_pointer(settings, FreeRDP_instance);
1994
0
  if (!inst || !inst->context)
1995
0
    return nullptr;
1996
0
  return smartcard_call_context_new_with_context(inst->context);
1997
0
}
1998
#endif
1999
2000
scard_call_context* smartcard_call_context_new_with_context(rdpContext* context)
2001
0
{
2002
0
  WINPR_ASSERT(context);
2003
0
  scard_call_context* ctx = calloc(1, sizeof(scard_call_context));
2004
0
  if (!ctx)
2005
0
    goto fail;
2006
2007
0
  ctx->context = context;
2008
2009
0
  const rdpSettings* settings = context->settings;
2010
0
  WINPR_ASSERT(settings);
2011
2012
0
  ctx->log = WLog_Get(SCARD_TAG);
2013
0
  WINPR_ASSERT(ctx->log);
2014
2015
0
  ctx->stopEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr);
2016
0
  if (!ctx->stopEvent)
2017
0
    goto fail;
2018
2019
0
  ctx->names = LinkedList_New();
2020
0
  if (!ctx->names)
2021
0
    goto fail;
2022
2023
0
#if defined(WITH_SMARTCARD_EMULATE)
2024
0
  ctx->useEmulatedCard = freerdp_settings_get_bool(settings, FreeRDP_SmartcardEmulation);
2025
0
#endif
2026
2027
0
  if (ctx->useEmulatedCard)
2028
0
  {
2029
0
#if defined(WITH_SMARTCARD_EMULATE)
2030
0
    ctx->emulation = Emulate_New(settings);
2031
0
    if (!ctx->emulation)
2032
0
      goto fail;
2033
#else
2034
    WLog_Print(ctx->log, WLOG_ERROR, "Smartcard emulation requested, but not supported!");
2035
    goto fail;
2036
#endif
2037
0
  }
2038
0
  else
2039
0
  {
2040
0
    const char* WinSCardModule = freerdp_settings_get_string(settings, FreeRDP_WinSCardModule);
2041
0
    if (WinSCardModule)
2042
0
    {
2043
0
      ctx->hWinSCardLibrary = LoadLibraryX(WinSCardModule);
2044
2045
0
      if (!ctx->hWinSCardLibrary)
2046
0
      {
2047
0
        WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard library: '%s'",
2048
0
                   WinSCardModule);
2049
0
        goto fail;
2050
0
      }
2051
2052
0
      if (!WinSCard_LoadApiTableFunctions(&ctx->WinSCardApi, ctx->hWinSCardLibrary))
2053
0
        goto fail;
2054
0
      ctx->pWinSCardApi = &ctx->WinSCardApi;
2055
0
    }
2056
0
    else
2057
0
    {
2058
0
      ctx->pWinSCardApi = WinPR_GetSCardApiFunctionTable();
2059
0
    }
2060
2061
0
    if (!ctx->pWinSCardApi)
2062
0
    {
2063
0
      WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard API!");
2064
0
      goto fail;
2065
0
    }
2066
0
  }
2067
2068
0
  ctx->rgSCardContextList = HashTable_New(FALSE);
2069
0
  if (!ctx->rgSCardContextList)
2070
0
    goto fail;
2071
2072
0
  {
2073
0
    wObject* obj = HashTable_ValueObject(ctx->rgSCardContextList);
2074
0
    WINPR_ASSERT(obj);
2075
0
    obj->fnObjectFree = context_free;
2076
0
  }
2077
2078
0
  return ctx;
2079
0
fail:
2080
0
  WINPR_PRAGMA_DIAG_PUSH
2081
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2082
0
  smartcard_call_context_free(ctx);
2083
0
  WINPR_PRAGMA_DIAG_POP
2084
0
  return nullptr;
2085
0
}
2086
2087
void smartcard_call_context_free(scard_call_context* ctx)
2088
0
{
2089
0
  if (!ctx)
2090
0
    return;
2091
2092
0
  smartcard_call_context_signal_stop(ctx, FALSE);
2093
2094
0
  LinkedList_Free(ctx->names);
2095
0
  if (ctx->StartedEvent)
2096
0
  {
2097
0
    WINPR_ASSERT(ctx->useEmulatedCard || ctx->pWinSCardApi);
2098
0
    wrap_raw(ctx, SCardReleaseStartedEvent);
2099
0
  }
2100
2101
0
  if (ctx->useEmulatedCard)
2102
0
  {
2103
0
#ifdef WITH_SMARTCARD_EMULATE
2104
0
    if (ctx->emulation)
2105
0
    {
2106
0
      Emulate_Free(ctx->emulation);
2107
0
      ctx->emulation = nullptr;
2108
0
    }
2109
0
#endif
2110
0
  }
2111
2112
0
  if (ctx->hWinSCardLibrary)
2113
0
  {
2114
0
    ZeroMemory(&ctx->WinSCardApi, sizeof(SCardApiFunctionTable));
2115
0
    FreeLibrary(ctx->hWinSCardLibrary);
2116
0
    ctx->hWinSCardLibrary = nullptr;
2117
0
  }
2118
2119
0
  ctx->pWinSCardApi = nullptr;
2120
2121
0
  HashTable_Free(ctx->rgSCardContextList);
2122
0
  (void)CloseHandle(ctx->stopEvent);
2123
0
  free(ctx);
2124
0
}
2125
2126
BOOL smartcard_call_context_add(scard_call_context* ctx, const char* name)
2127
0
{
2128
0
  WINPR_ASSERT(ctx);
2129
0
  WINPR_ASSERT(name);
2130
0
  return LinkedList_AddLast(ctx->names, name);
2131
0
}
2132
2133
BOOL smartcard_call_cancel_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2134
0
{
2135
0
  WINPR_ASSERT(ctx);
2136
0
  if (wrap(ctx, SCardIsValidContext, hContext) == SCARD_S_SUCCESS)
2137
0
  {
2138
0
    wrap(ctx, SCardCancel, hContext);
2139
0
  }
2140
0
  return TRUE;
2141
0
}
2142
2143
BOOL smartcard_call_release_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2144
0
{
2145
0
  WINPR_ASSERT(ctx);
2146
0
  wrap(ctx, SCardReleaseContext, hContext);
2147
0
  return TRUE;
2148
0
}
2149
2150
BOOL smartcard_call_cancel_all_context(scard_call_context* ctx)
2151
0
{
2152
0
  if (!ctx)
2153
0
    return FALSE;
2154
2155
0
  HashTable_Clear(ctx->rgSCardContextList);
2156
0
  return TRUE;
2157
0
}
2158
2159
BOOL smarcard_call_set_callbacks(scard_call_context* ctx, void* userdata,
2160
                                 void* (*fn_new)(void*, SCARDCONTEXT), void (*fn_free)(void*))
2161
0
{
2162
0
  WINPR_ASSERT(ctx);
2163
0
  ctx->userdata = userdata;
2164
0
  ctx->fn_new = fn_new;
2165
0
  ctx->fn_free = fn_free;
2166
0
  return TRUE;
2167
0
}
2168
2169
void* smartcard_call_get_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2170
0
{
2171
0
  struct s_scard_context_element* element = nullptr;
2172
2173
0
  WINPR_ASSERT(ctx);
2174
0
  element = HashTable_GetItemValue(ctx->rgSCardContextList, (void*)hContext);
2175
0
  if (!element)
2176
0
    return nullptr;
2177
0
  return element->context;
2178
0
}
2179
2180
BOOL smartcard_call_is_configured(scard_call_context* ctx)
2181
0
{
2182
0
  WINPR_ASSERT(ctx);
2183
2184
0
#if defined(WITH_SMARTCARD_EMULATE)
2185
0
  if (ctx->useEmulatedCard)
2186
0
    return Emulate_IsConfigured(ctx->emulation);
2187
0
#endif
2188
2189
0
  return FALSE;
2190
0
}
2191
2192
BOOL smartcard_call_context_signal_stop(scard_call_context* ctx, BOOL reset)
2193
0
{
2194
0
  WINPR_ASSERT(ctx);
2195
2196
0
  if (!ctx->stopEvent)
2197
0
    return TRUE;
2198
2199
0
  if (reset)
2200
0
    return ResetEvent(ctx->stopEvent);
2201
0
  else
2202
0
    return SetEvent(ctx->stopEvent);
2203
0
}