Coverage Report

Created: 2026-10-15 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/emu/scard/smartcard_emulate.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Smart Card API emulation
4
 *
5
 * Copyright 2021 Armin Novak <armin.novak@thincast.com>
6
 * Copyright 2021 Thincast Technologies GmbH
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <freerdp/config.h>
22
#include <freerdp/freerdp.h>
23
24
#include <winpr/crt.h>
25
#include <winpr/wlog.h>
26
#include <winpr/file.h>
27
#include <winpr/path.h>
28
#include <winpr/library.h>
29
#include <winpr/smartcard.h>
30
#include <winpr/collections.h>
31
#include <winpr/crypto.h>
32
#include <winpr/interlocked.h>
33
34
#include <freerdp/emulate/scard/smartcard_emulate.h>
35
#include "FreeRDP.ico.h"
36
37
#include "smartcard_virtual_gids.h"
38
39
0
#define MAX_CACHE_ITEM_SIZE 4096
40
0
#define MAX_CACHE_ITEM_VALUES 4096
41
42
0
#define VGIDS_DEFAULT_RETRY_COUNTER 3
43
44
typedef struct
45
{
46
  SCARDCONTEXT context;
47
  wHashTable* table;
48
} HandleCleanLoopArg;
49
50
static CHAR g_ReaderNameA[] = { 'F', 'r', 'e', 'e', 'R', 'D', 'P', ' ',  'E',
51
                              'm', 'u', 'l', 'a', 't', 'o', 'r', '\0', '\0' };
52
static INIT_ONCE g_ReaderNameWGuard = INIT_ONCE_STATIC_INIT;
53
static WCHAR g_ReaderNameW[32] = WINPR_C_ARRAY_INIT;
54
static size_t g_ReaderNameWLen = 0;
55
56
WINPR_ATTR_MALLOC(free, 1)
57
static char* card_id_and_name_a(const UUID* CardIdentifier, LPCSTR LookupName)
58
0
{
59
0
  if (!CardIdentifier || !LookupName)
60
0
    return nullptr;
61
62
0
  size_t len = strlen(LookupName) + 34;
63
0
  char* id = malloc(len);
64
0
  if (!id)
65
0
    return nullptr;
66
67
0
  (void)snprintf(id, len, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X\\%s",
68
0
                 CardIdentifier->Data1, CardIdentifier->Data2, CardIdentifier->Data3,
69
0
                 CardIdentifier->Data4[0], CardIdentifier->Data4[1], CardIdentifier->Data4[2],
70
0
                 CardIdentifier->Data4[3], CardIdentifier->Data4[4], CardIdentifier->Data4[5],
71
0
                 CardIdentifier->Data4[6], CardIdentifier->Data4[7], LookupName);
72
0
  return id;
73
0
}
74
75
WINPR_ATTR_MALLOC(free, 1)
76
static char* card_id_and_name_w(const UUID* CardIdentifier, LPCWSTR LookupName)
77
0
{
78
0
  char* res = nullptr;
79
0
  char* tmp = ConvertWCharToUtf8Alloc(LookupName, nullptr);
80
0
  if (!tmp)
81
0
    return nullptr;
82
0
  res = card_id_and_name_a(CardIdentifier, tmp);
83
0
  free(tmp);
84
0
  return res;
85
0
}
86
87
WINPR_ATTR_NODISCARD
88
static BOOL CALLBACK g_ReaderNameWInit(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
89
0
{
90
0
  WINPR_UNUSED(InitOnce);
91
0
  WINPR_UNUSED(Parameter);
92
0
  WINPR_UNUSED(Context);
93
0
  InitializeConstWCharFromUtf8(g_ReaderNameA, g_ReaderNameW, ARRAYSIZE(g_ReaderNameW));
94
0
  g_ReaderNameWLen = _wcsnlen(g_ReaderNameW, ARRAYSIZE(g_ReaderNameW) - 2) + 2;
95
0
  return TRUE;
96
0
}
97
98
struct smartcard_emulation_context
99
{
100
  const rdpSettings* settings;
101
  DWORD log_default_level;
102
  wLog* log;
103
  wHashTable* contexts;
104
  wHashTable* handles;
105
  BOOL configured;
106
  const char* pem;
107
  const char* key;
108
  const char* pin;
109
  wHashTable* pinCounters;
110
};
111
112
typedef struct
113
{
114
  char* pin;
115
  UINT16 curRetryCounter;
116
  UINT16 retryCounter;
117
} SmartcardPinCounterEntry;
118
119
0
#define MAX_EMULATED_READERS 1
120
typedef struct
121
{
122
  ULONG readerState;
123
  SCARD_READERSTATEA readerStateA[MAX_EMULATED_READERS];
124
  SCARD_READERSTATEW readerStateW[MAX_EMULATED_READERS];
125
  wHashTable* cards;
126
  wArrayList* strings;
127
  wHashTable* cache;
128
  BOOL canceled;
129
  volatile LONG semaphore;
130
} SCardContext;
131
132
typedef struct
133
{
134
  union
135
  {
136
    void* pv;
137
    CHAR* pc;
138
    WCHAR* pw;
139
  } szReader;
140
  BOOL unicode;
141
  BOOL transaction;
142
  DWORD transmitcount;
143
  DWORD dwShareMode;
144
  DWORD dwActiveProtocol;
145
  SCARDCONTEXT hContext;
146
  SCARDHANDLE card;
147
  vgidsContext* vgids;
148
  size_t referencecount;
149
} SCardHandle;
150
151
typedef struct
152
{
153
  DWORD freshness;
154
  DWORD size;
155
  char data[MAX_CACHE_ITEM_SIZE];
156
} SCardCacheItem;
157
158
WINPR_ATTR_NODISCARD
159
static SCardHandle* find_reader(SmartcardEmulationContext* smartcard, const void* szReader,
160
                                BOOL unicode);
161
162
static const BYTE ATR[] = { 0x3b, 0xf7, 0x18, 0x00, 0x00, 0x80, 0x31, 0xfe, 0x45,
163
                          0x73, 0x66, 0x74, 0x65, 0x2d, 0x6e, 0x66, 0xc4 };
164
165
WINPR_ATTR_NODISCARD
166
static BOOL scard_status_transition(SCardContext* context)
167
0
{
168
0
  WINPR_ASSERT(context);
169
170
0
  switch (context->readerState)
171
0
  {
172
0
    default:
173
0
    case 0:
174
0
    {
175
0
      SCARD_READERSTATEA* reader = &context->readerStateA[0];
176
0
      reader->szReader = g_ReaderNameA;
177
0
      reader->dwEventState = SCARD_STATE_PRESENT;
178
0
      reader->cbAtr = sizeof(ATR);
179
0
      memcpy(reader->rgbAtr, ATR, sizeof(ATR));
180
0
    }
181
0
      {
182
0
        if (!InitOnceExecuteOnce(&g_ReaderNameWGuard, g_ReaderNameWInit, nullptr, nullptr))
183
0
          return FALSE;
184
0
        SCARD_READERSTATEW* reader = &context->readerStateW[0];
185
0
        reader->szReader = g_ReaderNameW;
186
0
        reader->dwEventState = SCARD_STATE_PRESENT;
187
0
        reader->cbAtr = sizeof(ATR);
188
0
        memcpy(reader->rgbAtr, ATR, sizeof(ATR));
189
0
      }
190
0
      context->readerState = 42;
191
0
      break;
192
0
  }
193
194
0
  return TRUE;
195
0
}
196
197
WINPR_ATTR_NODISCARD
198
static UINT32 scard_copy_strings(SCardContext* ctx, void* dst, size_t dstSize, const void* src,
199
                                 size_t srcSize)
200
0
{
201
0
  WINPR_ASSERT(ctx);
202
0
  WINPR_ASSERT(dst);
203
204
0
  WINPR_ASSERT(srcSize <= UINT32_MAX);
205
0
  WINPR_ASSERT(dstSize <= UINT32_MAX);
206
207
0
  if (dstSize == SCARD_AUTOALLOCATE)
208
0
  {
209
0
    if (srcSize == 0)
210
0
      return 0;
211
212
0
    void* tmp = malloc(srcSize);
213
0
    if (!tmp)
214
0
      return 0;
215
0
    memcpy(tmp, src, srcSize);
216
0
    ArrayList_Append(ctx->strings, tmp);
217
0
    *((void**)dst) = tmp;
218
0
    return (UINT32)srcSize;
219
0
  }
220
0
  else
221
0
  {
222
0
    const size_t min = MIN(dstSize, srcSize);
223
0
    memcpy(dst, src, min);
224
0
    return (UINT32)min;
225
0
  }
226
0
}
227
228
static void waitForCancel(SCardContext* ctx)
229
0
{
230
0
  WINPR_ASSERT(ctx);
231
0
  while (InterlockedCompareExchange(&ctx->semaphore, 0, 0) > 0)
232
0
    Sleep(10);
233
0
}
234
235
static void scard_context_free(void* context)
236
0
{
237
0
  SCardContext* ctx = context;
238
0
  if (ctx)
239
0
  {
240
    /* HACK: There might be long running calls in background still active.
241
     * Emulation does ~100ms polling loops to check if we're still ok, so do a 2 * 100ms delay
242
     * to ensure such calls are terminated.
243
     *
244
     * See Emulate_SCardGetStatusChangeA and Emulate_SCardGetStatusChangeW
245
     */
246
0
    ctx->canceled = TRUE;
247
0
    waitForCancel(ctx);
248
249
0
    HashTable_Free(ctx->cards);
250
0
    ArrayList_Free(ctx->strings);
251
0
    HashTable_Free(ctx->cache);
252
0
  }
253
0
  free(ctx);
254
0
}
255
256
WINPR_ATTR_MALLOC(scard_context_free, 1)
257
static SCardContext* scard_context_new(void)
258
0
{
259
0
  SCardContext* ctx = calloc(1, sizeof(SCardContext));
260
0
  if (!ctx)
261
0
    return nullptr;
262
263
0
  ctx->strings = ArrayList_New(FALSE);
264
0
  if (!ctx->strings)
265
0
    goto fail;
266
0
  else
267
0
  {
268
0
    wObject* obj = ArrayList_Object(ctx->strings);
269
0
    WINPR_ASSERT(obj);
270
0
    obj->fnObjectFree = free;
271
0
  }
272
273
0
  ctx->cache = HashTable_New(FALSE);
274
0
  if (!ctx->cache)
275
0
    goto fail;
276
0
  if (!HashTable_SetupForStringData(ctx->cache, FALSE))
277
0
    goto fail;
278
0
  else
279
0
  {
280
0
    wObject* val = HashTable_ValueObject(ctx->cache);
281
0
    WINPR_ASSERT(val);
282
0
    val->fnObjectFree = free;
283
0
  }
284
285
0
  if (!scard_status_transition(ctx))
286
0
    goto fail;
287
0
  return ctx;
288
0
fail:
289
0
  scard_context_free(ctx);
290
0
  return nullptr;
291
0
}
292
293
static void scard_handle_free(void* handle)
294
0
{
295
0
  SCardHandle* hdl = handle;
296
0
  if (hdl)
297
0
  {
298
0
    free(hdl->szReader.pv);
299
0
    vgids_free(hdl->vgids);
300
0
  }
301
0
  free(hdl);
302
0
}
303
304
WINPR_ATTR_MALLOC(scard_handle_free, 1)
305
static SCardHandle* scard_handle_new(SmartcardEmulationContext* smartcard, SCARDCONTEXT context,
306
                                     const void* name, BOOL unicode)
307
0
{
308
0
  SCardHandle* hdl = nullptr;
309
310
0
  WINPR_ASSERT(smartcard);
311
312
0
  hdl = calloc(1, sizeof(SCardHandle));
313
0
  if (!hdl)
314
0
    goto fail;
315
316
  /* ATTENTION: Do not use _strdup or _wcsdup!
317
   * These strings are required to be double nullptr terminated!
318
   */
319
0
  if (unicode)
320
0
  {
321
0
    size_t s = _wcslen(name);
322
323
0
    hdl->szReader.pw = calloc(s + 2, sizeof(WCHAR));
324
0
    if (!hdl->szReader.pw)
325
0
      goto fail;
326
0
    memcpy(hdl->szReader.pv, name, s * sizeof(WCHAR));
327
0
  }
328
0
  else
329
0
  {
330
0
    size_t s = strlen(name);
331
332
0
    hdl->szReader.pc = calloc(s + 2, sizeof(CHAR));
333
0
    if (!hdl->szReader.pc)
334
0
      goto fail;
335
0
    memcpy(hdl->szReader.pv, name, s * sizeof(CHAR));
336
0
  }
337
338
0
  if (!hdl->szReader.pv)
339
0
    goto fail;
340
341
0
  hdl->vgids = vgids_new(smartcard);
342
0
  if (!hdl->vgids)
343
0
    goto fail;
344
345
0
  {
346
0
    const char* pem =
347
0
        freerdp_settings_get_string(smartcard->settings, FreeRDP_SmartcardCertificate);
348
0
    const char* key =
349
0
        freerdp_settings_get_string(smartcard->settings, FreeRDP_SmartcardPrivateKey);
350
351
0
    const char* pin = freerdp_settings_get_string(smartcard->settings, FreeRDP_Password);
352
353
0
    if (!vgids_init(hdl->vgids, pem, key, pin))
354
0
      goto fail;
355
0
  }
356
357
0
  hdl->unicode = unicode;
358
0
  hdl->hContext = context;
359
0
  return hdl;
360
361
0
fail:
362
0
  scard_handle_free(hdl);
363
0
  return nullptr;
364
0
}
365
366
WINPR_ATTR_NODISCARD
367
static LONG scard_handle_valid(SmartcardEmulationContext* smartcard, SCARDHANDLE handle)
368
0
{
369
0
  WINPR_ASSERT(smartcard);
370
371
0
  SCardHandle* ctx = HashTable_GetItemValue(smartcard->handles, (const void*)handle);
372
0
  if (!ctx)
373
0
    return SCARD_E_INVALID_HANDLE;
374
375
0
  return SCARD_S_SUCCESS;
376
0
}
377
378
WINPR_ATTR_NODISCARD
379
static LONG scard_reader_name_valid_a(SmartcardEmulationContext* smartcard, SCARDCONTEXT context,
380
                                      const char* name)
381
0
{
382
0
  SCardContext* ctx = nullptr;
383
384
0
  WINPR_ASSERT(smartcard);
385
0
  ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)context);
386
387
0
  WINPR_ASSERT(name);
388
0
  WINPR_ASSERT(ctx);
389
390
0
  for (size_t x = 0; x < MAX_EMULATED_READERS; x++)
391
0
  {
392
0
    const SCARD_READERSTATEA* reader = &ctx->readerStateA[x];
393
0
    if (strcmp(reader->szReader, name) == 0)
394
0
      return SCARD_S_SUCCESS;
395
0
  }
396
397
0
  return SCARD_E_UNKNOWN_READER;
398
0
}
399
400
WINPR_ATTR_NODISCARD
401
static LONG scard_reader_name_valid_w(SmartcardEmulationContext* smartcard, SCARDCONTEXT context,
402
                                      const WCHAR* name)
403
0
{
404
0
  SCardContext* ctx = nullptr;
405
406
0
  WINPR_ASSERT(smartcard);
407
0
  ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)context);
408
409
0
  WINPR_ASSERT(name);
410
0
  WINPR_ASSERT(ctx);
411
412
0
  for (size_t x = 0; x < MAX_EMULATED_READERS; x++)
413
0
  {
414
0
    const SCARD_READERSTATEW* reader = &ctx->readerStateW[x];
415
0
    if (_wcscmp(reader->szReader, name) == 0)
416
0
      return SCARD_S_SUCCESS;
417
0
  }
418
419
0
  return SCARD_E_UNKNOWN_READER;
420
0
}
421
422
/**
423
 * Standard Windows Smart Card API
424
 */
425
426
LONG WINAPI Emulate_SCardEstablishContext(SmartcardEmulationContext* smartcard, DWORD dwScope,
427
                                          LPCVOID pvReserved1, LPCVOID pvReserved2,
428
                                          LPSCARDCONTEXT phContext)
429
0
{
430
0
  LONG status = SCARD_E_NO_MEMORY;
431
0
  SCardContext* ctx = nullptr;
432
433
0
  WINPR_ASSERT(smartcard);
434
435
0
  ctx = scard_context_new();
436
437
0
  WINPR_UNUSED(pvReserved1);
438
0
  WINPR_UNUSED(pvReserved2);
439
440
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
441
0
             "SCardEstablishContext { dwScope: %s (0x%08" PRIX32 ")",
442
0
             SCardGetScopeString(dwScope), dwScope);
443
444
0
  if (ctx)
445
0
  {
446
0
    SCARDCONTEXT context = WINPR_C_ARRAY_INIT;
447
448
0
    if (winpr_RAND(&context, sizeof(SCARDCONTEXT)) >= 0)
449
0
    {
450
0
      if (HashTable_Insert(smartcard->contexts, (const void*)context, ctx))
451
0
      {
452
0
        *phContext = context;
453
0
        status = SCARD_S_SUCCESS;
454
0
      }
455
0
    }
456
0
  }
457
458
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
459
0
             "SCardEstablishContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
460
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
461
462
0
  if (status != SCARD_S_SUCCESS)
463
0
    scard_context_free(ctx);
464
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of ctx
465
0
  return status;
466
0
}
467
468
WINPR_ATTR_NODISCARD
469
static BOOL remove_handles(const void* key, void* value, void* arg)
470
0
{
471
0
  WINPR_ASSERT(arg);
472
0
  WINPR_ASSERT(value);
473
474
0
  const HandleCleanLoopArg* harg = arg;
475
0
  SCardHandle* handle = value;
476
0
  if (handle->hContext == harg->context)
477
0
  {
478
0
    if (!HashTable_Remove(harg->table, key))
479
0
      return FALSE;
480
0
  }
481
0
  return TRUE;
482
0
}
483
484
LONG WINAPI Emulate_SCardReleaseContext(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext)
485
0
{
486
0
  LONG status = SCARD_S_SUCCESS;
487
488
0
  WINPR_ASSERT(smartcard);
489
490
0
  SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
491
492
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReleaseContext { hContext: %p",
493
0
             (void*)hContext);
494
495
0
  HandleCleanLoopArg arg = { .context = hContext, .table = smartcard->handles };
496
0
  if (!HashTable_Foreach(smartcard->handles, remove_handles, &arg))
497
0
    status = SCARD_E_INVALID_HANDLE;
498
499
0
  if (value)
500
0
    HashTable_Remove(smartcard->contexts, (const void*)hContext);
501
502
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
503
0
             "SCardReleaseContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
504
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
505
506
0
  return status;
507
0
}
508
509
LONG WINAPI Emulate_SCardIsValidContext(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext)
510
0
{
511
0
  LONG status = 0;
512
513
0
  WINPR_ASSERT(smartcard);
514
515
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardIsValidContext { hContext: %p",
516
0
             (void*)hContext);
517
518
0
  status = HashTable_Contains(smartcard->contexts, (const void*)hContext)
519
0
               ? SCARD_S_SUCCESS
520
0
               : SCARD_E_INVALID_HANDLE;
521
0
  if (status == SCARD_S_SUCCESS)
522
0
  {
523
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
524
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
525
0
    if (!value)
526
0
      return SCARD_F_INTERNAL_ERROR;
527
0
  }
528
529
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
530
0
             "SCardIsValidContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
531
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
532
533
0
  return status;
534
0
}
535
536
LONG WINAPI Emulate_SCardListReaderGroupsA(
537
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
538
    LPSTR mszGroups /* NOLINT(readability-non-const-parameter) */, LPDWORD pcchGroups)
539
0
{
540
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
541
542
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
543
0
             "SCardListReaderGroupsA { hContext: %p", (void*)hContext);
544
545
0
  WINPR_UNUSED(mszGroups);
546
0
  WINPR_UNUSED(pcchGroups);
547
548
  /* Not required, return not supported */
549
0
  if (status == SCARD_S_SUCCESS)
550
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
551
552
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
553
0
             "SCardListReaderGroupsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
554
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
555
556
0
  return status;
557
0
}
558
559
LONG WINAPI Emulate_SCardListReaderGroupsW(
560
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
561
    LPWSTR mszGroups /* NOLINT(readability-non-const-parameter) */, LPDWORD pcchGroups)
562
0
{
563
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
564
565
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
566
0
             "SCardListReaderGroupsW { hContext: %p", (void*)hContext);
567
568
0
  WINPR_UNUSED(mszGroups);
569
0
  WINPR_UNUSED(pcchGroups);
570
571
  /* Not required, return not supported */
572
0
  if (status == SCARD_S_SUCCESS)
573
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
574
575
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
576
0
             "SCardListReaderGroupsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
577
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
578
579
0
  return status;
580
0
}
581
582
LONG WINAPI Emulate_SCardListReadersA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
583
                                      LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
584
0
{
585
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
586
0
  if (!pcchReaders)
587
0
    status = SCARD_E_INVALID_PARAMETER;
588
589
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListReadersA { hContext: %p",
590
0
             (void*)hContext);
591
592
0
  WINPR_UNUSED(mszGroups); /* Not required */
593
594
0
  if (SCARD_S_SUCCESS == status)
595
0
  {
596
0
    SCardContext* value =
597
0
        (SCardContext*)HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
598
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
599
600
    // TODO: If emulator not ready return SCARD_E_NO_READERS_AVAILABLE
601
602
    // TODO: argument mszGrous
603
604
    /* Return length only */
605
0
    if (!mszReaders)
606
0
      *pcchReaders = ARRAYSIZE(g_ReaderNameA);
607
0
    else
608
0
    {
609
0
      *pcchReaders = scard_copy_strings(value, mszReaders, *pcchReaders, g_ReaderNameA,
610
0
                                        sizeof(g_ReaderNameA));
611
0
    }
612
0
  }
613
614
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
615
0
             "SCardListReadersA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
616
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
617
618
0
  return status;
619
0
}
620
621
LONG WINAPI Emulate_SCardListReadersW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
622
                                      LPCWSTR mszGroups, LPWSTR mszReaders, LPDWORD pcchReaders)
623
0
{
624
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
625
626
0
  if (!pcchReaders)
627
0
    status = SCARD_E_INVALID_PARAMETER;
628
629
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListReadersW { hContext: %p",
630
0
             (void*)hContext);
631
632
0
  WINPR_UNUSED(mszGroups); /* Not required */
633
634
0
  if (!InitOnceExecuteOnce(&g_ReaderNameWGuard, g_ReaderNameWInit, nullptr, nullptr))
635
0
    return FALSE;
636
0
  if (SCARD_S_SUCCESS == status)
637
0
  {
638
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
639
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
640
641
    // TODO: If emulator not ready return SCARD_E_NO_READERS_AVAILABLE
642
643
    // TODO: argument mszGrous
644
645
    /* Return length only */
646
0
    if (!mszReaders)
647
0
    {
648
0
      WINPR_ASSERT(g_ReaderNameWLen <= UINT32_MAX);
649
0
      *pcchReaders = (UINT32)g_ReaderNameWLen;
650
0
    }
651
0
    else
652
0
    {
653
0
      *pcchReaders = scard_copy_strings(value, mszReaders, *pcchReaders, g_ReaderNameW,
654
0
                                        g_ReaderNameWLen * sizeof(WCHAR)) /
655
0
                     sizeof(WCHAR);
656
0
    }
657
0
  }
658
659
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
660
0
             "SCardListReadersW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
661
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
662
663
0
  return status;
664
0
}
665
666
LONG WINAPI Emulate_SCardListCardsA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
667
                                    LPCBYTE pbAtr, LPCGUID rgquidInterfaces,
668
                                    DWORD cguidInterfaceCount,
669
                                    CHAR* mszCards /* NOLINT(readability-non-const-parameter) */,
670
                                    LPDWORD pcchCards /* NOLINT(readability-non-const-parameter) */)
671
0
{
672
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
673
674
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListCardsA { hContext: %p",
675
0
             (void*)hContext);
676
677
0
  WINPR_UNUSED(pbAtr);
678
0
  WINPR_UNUSED(rgquidInterfaces);
679
0
  WINPR_UNUSED(cguidInterfaceCount);
680
0
  WINPR_UNUSED(mszCards);
681
0
  WINPR_UNUSED(pcchCards);
682
683
  /* Not required, return not supported */
684
0
  if (status == SCARD_S_SUCCESS)
685
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
686
687
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
688
0
             "SCardListCardsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
689
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
690
691
0
  return status;
692
0
}
693
694
LONG WINAPI Emulate_SCardListCardsW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
695
                                    LPCBYTE pbAtr, LPCGUID rgquidInterfaces,
696
                                    DWORD cguidInterfaceCount,
697
                                    WCHAR* mszCards /* NOLINT(readability-non-const-parameter) */,
698
                                    LPDWORD pcchCards /* NOLINT(readability-non-const-parameter) */)
699
0
{
700
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
701
702
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListCardsW { hContext: %p",
703
0
             (void*)hContext);
704
705
0
  WINPR_UNUSED(pbAtr);
706
0
  WINPR_UNUSED(rgquidInterfaces);
707
0
  WINPR_UNUSED(cguidInterfaceCount);
708
0
  WINPR_UNUSED(mszCards);
709
0
  WINPR_UNUSED(pcchCards);
710
711
  /* Not required, return not supported */
712
0
  if (status == SCARD_S_SUCCESS)
713
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
714
715
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
716
0
             "SCardListCardsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
717
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
718
719
0
  return status;
720
0
}
721
722
LONG WINAPI Emulate_SCardListInterfacesA(
723
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCSTR szCard,
724
    LPGUID pguidInterfaces, LPDWORD pcguidInterfaces /* NOLINT(readability-non-const-parameter) */)
725
0
{
726
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
727
728
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListInterfacesA { hContext: %p",
729
0
             (void*)hContext);
730
731
0
  WINPR_UNUSED(szCard);
732
0
  WINPR_UNUSED(pguidInterfaces);
733
0
  WINPR_UNUSED(pcguidInterfaces);
734
735
  /* Not required, return not supported */
736
0
  if (status == SCARD_S_SUCCESS)
737
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
738
739
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
740
0
             "SCardListInterfacesA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
741
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
742
743
0
  return status;
744
0
}
745
746
LONG WINAPI Emulate_SCardListInterfacesW(
747
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCWSTR szCard,
748
    LPGUID pguidInterfaces, LPDWORD pcguidInterfaces /* NOLINT(readability-non-const-parameter) */)
749
0
{
750
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
751
752
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardListInterfacesW { hContext: %p",
753
0
             (void*)hContext);
754
755
0
  WINPR_UNUSED(szCard);
756
0
  WINPR_UNUSED(pguidInterfaces);
757
0
  WINPR_UNUSED(pcguidInterfaces);
758
759
  /* Not required, return not supported */
760
0
  if (status == SCARD_S_SUCCESS)
761
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
762
763
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
764
0
             "SCardListInterfacesW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
765
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
766
767
0
  return status;
768
0
}
769
770
LONG WINAPI Emulate_SCardGetProviderIdA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
771
                                        LPCSTR szCard, LPGUID pguidProviderId)
772
0
{
773
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
774
775
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetProviderIdA { hContext: %p",
776
0
             (void*)hContext);
777
778
0
  WINPR_UNUSED(szCard);
779
0
  WINPR_UNUSED(pguidProviderId);
780
781
  /* Not required, return not supported */
782
0
  if (status == SCARD_S_SUCCESS)
783
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
784
785
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
786
0
             "SCardGetProviderIdA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
787
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
788
789
0
  return status;
790
0
}
791
792
LONG WINAPI Emulate_SCardGetProviderIdW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
793
                                        LPCWSTR szCard, LPGUID pguidProviderId)
794
0
{
795
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
796
797
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetProviderIdW { hContext: %p",
798
0
             (void*)hContext);
799
800
0
  WINPR_UNUSED(szCard);
801
0
  WINPR_UNUSED(pguidProviderId);
802
803
  /* Not required, return not supported */
804
0
  if (status == SCARD_S_SUCCESS)
805
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
806
807
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
808
0
             "SCardGetProviderIdW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
809
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
810
811
0
  return status;
812
0
}
813
814
LONG WINAPI Emulate_SCardGetCardTypeProviderNameA(
815
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCSTR szCardName,
816
    DWORD dwProviderId, CHAR* szProvider /* NOLINT(readability-non-const-parameter) */,
817
    LPDWORD pcchProvider /* NOLINT(readability-non-const-parameter) */)
818
0
{
819
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
820
821
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
822
0
             "SCardGetCardTypeProviderNameA { hContext: %p", (void*)hContext);
823
824
0
  WINPR_UNUSED(szCardName);
825
0
  WINPR_UNUSED(dwProviderId);
826
0
  WINPR_UNUSED(szProvider);
827
0
  WINPR_UNUSED(pcchProvider);
828
829
  /* Not required, return not supported */
830
0
  if (status == SCARD_S_SUCCESS)
831
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
832
833
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
834
0
             "SCardGetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")",
835
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
836
837
0
  return status;
838
0
}
839
840
LONG WINAPI Emulate_SCardGetCardTypeProviderNameW(
841
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCWSTR szCardName,
842
    DWORD dwProviderId, WCHAR* szProvider /* NOLINT(readability-non-const-parameter) */,
843
    LPDWORD pcchProvider /* NOLINT(readability-non-const-parameter) */)
844
0
{
845
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
846
847
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
848
0
             "SCardGetCardTypeProviderNameW { hContext: %p", (void*)hContext);
849
850
0
  WINPR_UNUSED(szCardName);
851
0
  WINPR_UNUSED(dwProviderId);
852
0
  WINPR_UNUSED(szProvider);
853
0
  WINPR_UNUSED(pcchProvider);
854
855
  /* Not required, return not supported */
856
0
  if (status == SCARD_S_SUCCESS)
857
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
858
859
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
860
0
             "SCardGetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")",
861
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
862
863
0
  return status;
864
0
}
865
866
LONG WINAPI Emulate_SCardIntroduceReaderGroupA(SmartcardEmulationContext* smartcard,
867
                                               SCARDCONTEXT hContext, LPCSTR szGroupName)
868
0
{
869
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
870
871
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
872
0
             "SCardIntroduceReaderGroupA { hContext: %p", (void*)hContext);
873
874
0
  WINPR_UNUSED(szGroupName);
875
876
  /* Not required, return not supported */
877
0
  if (status == SCARD_S_SUCCESS)
878
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
879
880
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
881
0
             "SCardIntroduceReaderGroupA } status: %s (0x%08" PRIX32 ")",
882
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
883
884
0
  return status;
885
0
}
886
887
LONG WINAPI Emulate_SCardIntroduceReaderGroupW(SmartcardEmulationContext* smartcard,
888
                                               SCARDCONTEXT hContext, LPCWSTR szGroupName)
889
0
{
890
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
891
892
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
893
0
             "SCardIntroduceReaderGroupW { hContext: %p", (void*)hContext);
894
895
0
  WINPR_UNUSED(szGroupName);
896
897
  /* Not required, return not supported */
898
0
  if (status == SCARD_S_SUCCESS)
899
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
900
901
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
902
0
             "SCardIntroduceReaderGroupW } status: %s (0x%08" PRIX32 ")",
903
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
904
905
0
  return status;
906
0
}
907
908
LONG WINAPI Emulate_SCardForgetReaderGroupA(SmartcardEmulationContext* smartcard,
909
                                            SCARDCONTEXT hContext, LPCSTR szGroupName)
910
0
{
911
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
912
913
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
914
0
             "SCardForgetReaderGroupA { hContext: %p", (void*)hContext);
915
916
0
  WINPR_UNUSED(szGroupName);
917
918
  /* Not required, return not supported */
919
0
  if (status == SCARD_S_SUCCESS)
920
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
921
922
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
923
0
             "SCardForgetReaderGroupA } status: %s (0x%08" PRIX32 ")",
924
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
925
926
0
  return status;
927
0
}
928
929
LONG WINAPI Emulate_SCardForgetReaderGroupW(SmartcardEmulationContext* smartcard,
930
                                            SCARDCONTEXT hContext, LPCWSTR szGroupName)
931
0
{
932
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
933
934
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
935
0
             "SCardForgetReaderGroupW { hContext: %p", (void*)hContext);
936
937
0
  WINPR_UNUSED(szGroupName);
938
939
  /* Not required, return not supported */
940
0
  if (status == SCARD_S_SUCCESS)
941
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
942
943
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
944
0
             "SCardForgetReaderGroupW } status: %s (0x%08" PRIX32 ")",
945
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
946
947
0
  return status;
948
0
}
949
950
LONG WINAPI Emulate_SCardIntroduceReaderA(SmartcardEmulationContext* smartcard,
951
                                          SCARDCONTEXT hContext, LPCSTR szReaderName,
952
                                          LPCSTR szDeviceName)
953
0
{
954
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
955
956
0
  if (status == SCARD_S_SUCCESS)
957
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
958
959
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardIntroduceReaderA { hContext: %p",
960
0
             (void*)hContext);
961
962
0
  WINPR_UNUSED(szDeviceName);
963
964
  /* Not required, return not supported */
965
0
  if (status == SCARD_S_SUCCESS)
966
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
967
968
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
969
0
             "SCardIntroduceReaderA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
970
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
971
972
0
  return status;
973
0
}
974
975
LONG WINAPI Emulate_SCardIntroduceReaderW(SmartcardEmulationContext* smartcard,
976
                                          SCARDCONTEXT hContext, LPCWSTR szReaderName,
977
                                          LPCWSTR szDeviceName)
978
0
{
979
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
980
981
0
  if (status == SCARD_S_SUCCESS)
982
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
983
984
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardIntroduceReaderW { hContext: %p",
985
0
             (void*)hContext);
986
987
0
  WINPR_UNUSED(szDeviceName);
988
989
  /* Not required, return not supported */
990
0
  if (status == SCARD_S_SUCCESS)
991
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
992
993
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
994
0
             "SCardIntroduceReaderW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
995
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
996
997
0
  return status;
998
0
}
999
1000
LONG WINAPI Emulate_SCardForgetReaderA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1001
                                       LPCSTR szReaderName)
1002
0
{
1003
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1004
1005
0
  if (status == SCARD_S_SUCCESS)
1006
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
1007
1008
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardForgetReaderA { hContext: %p",
1009
0
             (void*)hContext);
1010
1011
  /* Not required, return not supported */
1012
0
  if (status == SCARD_S_SUCCESS)
1013
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1014
1015
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1016
0
             "SCardForgetReaderA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1017
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1018
1019
0
  return status;
1020
0
}
1021
1022
LONG WINAPI Emulate_SCardForgetReaderW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1023
                                       LPCWSTR szReaderName)
1024
0
{
1025
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1026
1027
0
  if (status == SCARD_S_SUCCESS)
1028
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
1029
1030
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardForgetReaderW { hContext: %p",
1031
0
             (void*)hContext);
1032
1033
  /* Not required, return not supported */
1034
0
  if (status == SCARD_S_SUCCESS)
1035
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1036
1037
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1038
0
             "SCardForgetReaderW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1039
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1040
1041
0
  return status;
1042
0
}
1043
1044
LONG WINAPI Emulate_SCardAddReaderToGroupA(SmartcardEmulationContext* smartcard,
1045
                                           SCARDCONTEXT hContext, LPCSTR szReaderName,
1046
                                           LPCSTR szGroupName)
1047
0
{
1048
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1049
1050
0
  if (status == SCARD_S_SUCCESS)
1051
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
1052
1053
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1054
0
             "SCardAddReaderToGroupA { hContext: %p", (void*)hContext);
1055
1056
0
  WINPR_UNUSED(szGroupName);
1057
1058
  /* Not required, return not supported */
1059
0
  if (status == SCARD_S_SUCCESS)
1060
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1061
1062
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1063
0
             "SCardAddReaderToGroupA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1064
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1065
1066
0
  return status;
1067
0
}
1068
1069
LONG WINAPI Emulate_SCardAddReaderToGroupW(SmartcardEmulationContext* smartcard,
1070
                                           SCARDCONTEXT hContext, LPCWSTR szReaderName,
1071
                                           LPCWSTR szGroupName)
1072
0
{
1073
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1074
1075
0
  if (status == SCARD_S_SUCCESS)
1076
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
1077
1078
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1079
0
             "SCardAddReaderToGroupW { hContext: %p", (void*)hContext);
1080
1081
0
  WINPR_UNUSED(szGroupName);
1082
1083
  /* Not required, return not supported */
1084
0
  if (status == SCARD_S_SUCCESS)
1085
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1086
1087
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1088
0
             "SCardAddReaderToGroupW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1089
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1090
1091
0
  return status;
1092
0
}
1093
1094
LONG WINAPI Emulate_SCardRemoveReaderFromGroupA(SmartcardEmulationContext* smartcard,
1095
                                                SCARDCONTEXT hContext, LPCSTR szReaderName,
1096
                                                LPCSTR szGroupName)
1097
0
{
1098
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1099
1100
0
  if (status == SCARD_S_SUCCESS)
1101
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
1102
1103
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1104
0
             "SCardRemoveReaderFromGroupA { hContext: %p", (void*)hContext);
1105
1106
0
  WINPR_UNUSED(szGroupName);
1107
1108
  /* Not required, return not supported */
1109
0
  if (status == SCARD_S_SUCCESS)
1110
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1111
1112
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1113
0
             "SCardRemoveReaderFromGroupA } status: %s (0x%08" PRIX32 ")",
1114
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1115
1116
0
  return status;
1117
0
}
1118
1119
LONG WINAPI Emulate_SCardRemoveReaderFromGroupW(SmartcardEmulationContext* smartcard,
1120
                                                SCARDCONTEXT hContext, LPCWSTR szReaderName,
1121
                                                LPCWSTR szGroupName)
1122
0
{
1123
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1124
1125
0
  if (status == SCARD_S_SUCCESS)
1126
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
1127
1128
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1129
0
             "SCardRemoveReaderFromGroupW { hContext: %p", (void*)hContext);
1130
1131
0
  WINPR_UNUSED(szGroupName);
1132
1133
  /* Not required, return not supported */
1134
0
  if (status == SCARD_S_SUCCESS)
1135
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1136
1137
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1138
0
             "SCardRemoveReaderFromGroupW } status: %s (0x%08" PRIX32 ")",
1139
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1140
1141
0
  return status;
1142
0
}
1143
1144
LONG WINAPI Emulate_SCardIntroduceCardTypeA(SmartcardEmulationContext* smartcard,
1145
                                            SCARDCONTEXT hContext, LPCSTR szCardName,
1146
                                            LPCGUID pguidPrimaryProvider, LPCGUID rgguidInterfaces,
1147
                                            DWORD dwInterfaceCount, LPCBYTE pbAtr,
1148
                                            LPCBYTE pbAtrMask, DWORD cbAtrLen)
1149
0
{
1150
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1151
1152
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1153
0
             "SCardIntroduceCardTypeA { hContext: %p", (void*)hContext);
1154
1155
0
  WINPR_UNUSED(szCardName);
1156
0
  WINPR_UNUSED(pguidPrimaryProvider);
1157
0
  WINPR_UNUSED(rgguidInterfaces);
1158
0
  WINPR_UNUSED(dwInterfaceCount);
1159
0
  WINPR_UNUSED(pbAtr);
1160
0
  WINPR_UNUSED(pbAtrMask);
1161
0
  WINPR_UNUSED(cbAtrLen);
1162
1163
  /* Not required, return not supported */
1164
0
  if (status == SCARD_S_SUCCESS)
1165
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1166
1167
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1168
0
             "SCardIntroduceCardTypeA } status: %s (0x%08" PRIX32 ")",
1169
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1170
1171
0
  return status;
1172
0
}
1173
1174
LONG WINAPI Emulate_SCardIntroduceCardTypeW(SmartcardEmulationContext* smartcard,
1175
                                            SCARDCONTEXT hContext, LPCWSTR szCardName,
1176
                                            LPCGUID pguidPrimaryProvider, LPCGUID rgguidInterfaces,
1177
                                            DWORD dwInterfaceCount, LPCBYTE pbAtr,
1178
                                            LPCBYTE pbAtrMask, DWORD cbAtrLen)
1179
0
{
1180
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1181
1182
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1183
0
             "SCardIntroduceCardTypeW { hContext: %p", (void*)hContext);
1184
1185
0
  WINPR_UNUSED(szCardName);
1186
0
  WINPR_UNUSED(pguidPrimaryProvider);
1187
0
  WINPR_UNUSED(rgguidInterfaces);
1188
0
  WINPR_UNUSED(dwInterfaceCount);
1189
0
  WINPR_UNUSED(pbAtr);
1190
0
  WINPR_UNUSED(pbAtrMask);
1191
0
  WINPR_UNUSED(cbAtrLen);
1192
1193
  /* Not required, return not supported */
1194
0
  if (status == SCARD_S_SUCCESS)
1195
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1196
1197
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1198
0
             "SCardIntroduceCardTypeW } status: %s (0x%08" PRIX32 ")",
1199
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1200
1201
0
  return status;
1202
0
}
1203
1204
LONG WINAPI Emulate_SCardSetCardTypeProviderNameA(SmartcardEmulationContext* smartcard,
1205
                                                  SCARDCONTEXT hContext, LPCSTR szCardName,
1206
                                                  DWORD dwProviderId, LPCSTR szProvider)
1207
0
{
1208
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1209
1210
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1211
0
             "SCardSetCardTypeProviderNameA { hContext: %p", (void*)hContext);
1212
1213
0
  WINPR_UNUSED(szCardName);
1214
0
  WINPR_UNUSED(dwProviderId);
1215
0
  WINPR_UNUSED(szProvider);
1216
1217
  /* Not required, return not supported */
1218
0
  if (status == SCARD_S_SUCCESS)
1219
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1220
1221
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1222
0
             "SCardSetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")",
1223
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1224
1225
0
  return status;
1226
0
}
1227
1228
LONG WINAPI Emulate_SCardSetCardTypeProviderNameW(SmartcardEmulationContext* smartcard,
1229
                                                  SCARDCONTEXT hContext, LPCWSTR szCardName,
1230
                                                  DWORD dwProviderId, LPCWSTR szProvider)
1231
0
{
1232
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1233
1234
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1235
0
             "SCardSetCardTypeProviderNameA { hContext: %p", (void*)hContext);
1236
1237
0
  WINPR_UNUSED(szCardName);
1238
0
  WINPR_UNUSED(dwProviderId);
1239
0
  WINPR_UNUSED(szProvider);
1240
1241
  /* Not required, return not supported */
1242
0
  if (status == SCARD_S_SUCCESS)
1243
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1244
1245
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1246
0
             "SCardSetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")",
1247
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
1248
1249
0
  return status;
1250
0
}
1251
1252
LONG WINAPI Emulate_SCardForgetCardTypeA(SmartcardEmulationContext* smartcard,
1253
                                         SCARDCONTEXT hContext, LPCSTR szCardName)
1254
0
{
1255
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1256
1257
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardForgetCardTypeA { hContext: %p",
1258
0
             (void*)hContext);
1259
1260
0
  WINPR_UNUSED(szCardName);
1261
1262
  /* Not required, return not supported */
1263
0
  if (status == SCARD_S_SUCCESS)
1264
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1265
1266
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1267
0
             "SCardForgetCardTypeA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1268
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1269
1270
0
  return status;
1271
0
}
1272
1273
LONG WINAPI Emulate_SCardForgetCardTypeW(SmartcardEmulationContext* smartcard,
1274
                                         SCARDCONTEXT hContext, LPCWSTR szCardName)
1275
0
{
1276
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1277
1278
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardForgetCardTypeW { hContext: %p",
1279
0
             (void*)hContext);
1280
1281
0
  WINPR_UNUSED(szCardName);
1282
1283
  /* Not required, return not supported */
1284
0
  if (status == SCARD_S_SUCCESS)
1285
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1286
1287
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1288
0
             "SCardForgetCardTypeW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1289
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1290
1291
0
  return status;
1292
0
}
1293
1294
LONG WINAPI Emulate_SCardFreeMemory(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1295
                                    LPVOID pvMem)
1296
0
{
1297
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1298
1299
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardFreeMemory { hContext: %p",
1300
0
             (void*)hContext);
1301
1302
0
  if (status == SCARD_S_SUCCESS)
1303
0
  {
1304
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
1305
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
1306
1307
0
    ArrayList_Remove(value->strings, pvMem);
1308
0
  }
1309
1310
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1311
0
             "SCardFreeMemory } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1312
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1313
1314
0
  return status;
1315
0
}
1316
1317
HANDLE WINAPI Emulate_SCardAccessStartedEvent(SmartcardEmulationContext* smartcard)
1318
0
{
1319
0
  HANDLE hEvent = nullptr;
1320
1321
0
  WINPR_ASSERT(smartcard);
1322
1323
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardAccessStartedEvent {");
1324
1325
  /* Not required, return random */
1326
0
  if (winpr_RAND((void*)&hEvent, sizeof(hEvent)) < 0)
1327
0
  {
1328
0
    (void)fprintf(stderr, "winpr_RAND failed.\n");
1329
0
  }
1330
1331
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardAccessStartedEvent } hEvent: %p",
1332
0
             hEvent);
1333
1334
0
  return hEvent;
1335
0
}
1336
1337
void WINAPI Emulate_SCardReleaseStartedEvent(SmartcardEmulationContext* smartcard)
1338
0
{
1339
0
  WINPR_ASSERT(smartcard);
1340
1341
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReleaseStartedEvent {");
1342
1343
  /* Not required, return not supported */
1344
1345
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReleaseStartedEvent }");
1346
0
}
1347
1348
LONG WINAPI Emulate_SCardLocateCardsA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1349
                                      LPCSTR mszCards, LPSCARD_READERSTATEA rgReaderStates,
1350
                                      DWORD cReaders)
1351
0
{
1352
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1353
1354
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardLocateCardsA { hContext: %p",
1355
0
             (void*)hContext);
1356
1357
0
  WINPR_UNUSED(mszCards);
1358
0
  WINPR_UNUSED(rgReaderStates);
1359
0
  WINPR_UNUSED(cReaders);
1360
1361
  /* Not required, return not supported */
1362
0
  if (status == SCARD_S_SUCCESS)
1363
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1364
1365
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1366
0
             "SCardLocateCardsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1367
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1368
1369
0
  return status;
1370
0
}
1371
1372
LONG WINAPI Emulate_SCardLocateCardsW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1373
                                      LPCWSTR mszCards, LPSCARD_READERSTATEW rgReaderStates,
1374
                                      DWORD cReaders)
1375
0
{
1376
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1377
1378
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardLocateCardsW { hContext: %p",
1379
0
             (void*)hContext);
1380
1381
0
  WINPR_UNUSED(mszCards);
1382
0
  WINPR_UNUSED(rgReaderStates);
1383
0
  WINPR_UNUSED(cReaders);
1384
1385
  /* Not required, return not supported */
1386
0
  if (status == SCARD_S_SUCCESS)
1387
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1388
1389
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1390
0
             "SCardLocateCardsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1391
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1392
1393
0
  return status;
1394
0
}
1395
1396
LONG WINAPI Emulate_SCardLocateCardsByATRA(SmartcardEmulationContext* smartcard,
1397
                                           SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
1398
                                           DWORD cAtrs, LPSCARD_READERSTATEA rgReaderStates,
1399
                                           DWORD cReaders)
1400
0
{
1401
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1402
1403
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1404
0
             "SCardLocateCardsByATRA { hContext: %p", (void*)hContext);
1405
1406
0
  WINPR_UNUSED(rgAtrMasks);
1407
0
  WINPR_UNUSED(cAtrs);
1408
0
  WINPR_UNUSED(rgReaderStates);
1409
0
  WINPR_UNUSED(cReaders);
1410
1411
  /* Not required, return not supported */
1412
0
  if (status == SCARD_S_SUCCESS)
1413
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1414
1415
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1416
0
             "SCardLocateCardsByATRA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1417
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1418
1419
0
  return status;
1420
0
}
1421
1422
LONG WINAPI Emulate_SCardLocateCardsByATRW(SmartcardEmulationContext* smartcard,
1423
                                           SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
1424
                                           DWORD cAtrs, LPSCARD_READERSTATEW rgReaderStates,
1425
                                           DWORD cReaders)
1426
0
{
1427
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1428
1429
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1430
0
             "SCardLocateCardsByATRW { hContext: %p", (void*)hContext);
1431
1432
0
  WINPR_UNUSED(rgAtrMasks);
1433
0
  WINPR_UNUSED(cAtrs);
1434
0
  WINPR_UNUSED(rgReaderStates);
1435
0
  WINPR_UNUSED(cReaders);
1436
1437
  /* Not required, return not supported */
1438
0
  if (status == SCARD_S_SUCCESS)
1439
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
1440
1441
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1442
0
             "SCardLocateCardsByATRW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1443
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1444
1445
0
  return status;
1446
0
}
1447
1448
LONG WINAPI Emulate_SCardGetStatusChangeA(SmartcardEmulationContext* smartcard,
1449
                                          SCARDCONTEXT hContext, DWORD dwTimeout,
1450
                                          LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
1451
0
{
1452
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1453
1454
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetStatusChangeA { hContext: %p",
1455
0
             (void*)hContext);
1456
1457
0
  if (status == SCARD_S_SUCCESS)
1458
0
  {
1459
0
    const DWORD diff = 100;
1460
0
    size_t eventCount = 0;
1461
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
1462
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
1463
1464
0
    InterlockedIncrement(&value->semaphore);
1465
1466
0
    const freerdp* inst = freerdp_settings_get_pointer(smartcard->settings, FreeRDP_instance);
1467
0
    WINPR_ASSERT(inst);
1468
1469
0
    status = SCARD_E_TIMEOUT;
1470
0
    do
1471
0
    {
1472
0
      for (size_t x = 0; x < cReaders; x++)
1473
0
      {
1474
0
        LPSCARD_READERSTATEA out = &rgReaderStates[x];
1475
1476
0
        for (size_t y = 0; y < MAX_EMULATED_READERS; y++)
1477
0
        {
1478
0
          const LPSCARD_READERSTATEA in = &value->readerStateA[y];
1479
0
          if (out->szReader && in->szReader && (strcmp(out->szReader, in->szReader) == 0))
1480
0
          {
1481
0
            HashTable_Lock(smartcard->handles);
1482
0
            const SCardHandle* hdl = find_reader(smartcard, in->szReader, FALSE);
1483
0
            out->dwEventState = in->dwEventState;
1484
0
            if (hdl)
1485
0
            {
1486
0
              out->dwEventState |= SCARD_STATE_INUSE;
1487
0
              if (hdl->dwShareMode == SCARD_SHARE_EXCLUSIVE)
1488
0
                out->dwEventState |= SCARD_STATE_EXCLUSIVE;
1489
0
            }
1490
0
            HashTable_Unlock(smartcard->handles);
1491
0
            if ((out->dwEventState & SCARD_STATE_EMPTY) !=
1492
0
                (out->dwCurrentState & SCARD_STATE_EMPTY))
1493
0
              out->dwEventState |= SCARD_STATE_CHANGED;
1494
0
            if ((out->dwEventState & SCARD_STATE_PRESENT) !=
1495
0
                (out->dwCurrentState & SCARD_STATE_PRESENT))
1496
0
              out->dwEventState |= SCARD_STATE_CHANGED;
1497
1498
0
            out->cbAtr = in->cbAtr;
1499
0
            memcpy(out->rgbAtr, in->rgbAtr, out->cbAtr);
1500
0
            if (out->dwEventState & SCARD_STATE_CHANGED)
1501
0
              eventCount++;
1502
0
          }
1503
0
        }
1504
0
      }
1505
0
      if (value->canceled)
1506
0
      {
1507
0
        status = SCARD_E_CANCELLED;
1508
0
        break;
1509
0
      }
1510
0
      if (eventCount != 0)
1511
0
      {
1512
0
        status = SCARD_S_SUCCESS;
1513
0
        break;
1514
0
      }
1515
0
      Sleep(diff);
1516
0
      if (dwTimeout != INFINITE)
1517
0
        dwTimeout -= MIN(dwTimeout, diff);
1518
0
      if (freerdp_shall_disconnect_context(inst->context))
1519
0
      {
1520
0
        status = SCARD_E_CANCELLED;
1521
0
        break;
1522
0
      }
1523
0
    } while (dwTimeout > 0);
1524
0
    InterlockedDecrement(&value->semaphore);
1525
0
  }
1526
1527
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1528
0
             "SCardGetStatusChangeA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1529
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1530
1531
0
  return status;
1532
0
}
1533
1534
LONG WINAPI Emulate_SCardGetStatusChangeW(SmartcardEmulationContext* smartcard,
1535
                                          SCARDCONTEXT hContext, DWORD dwTimeout,
1536
                                          LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
1537
0
{
1538
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1539
1540
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetStatusChangeW { hContext: %p",
1541
0
             (void*)hContext);
1542
1543
0
  if (status == SCARD_S_SUCCESS)
1544
0
  {
1545
0
    const DWORD diff = 100;
1546
0
    size_t eventCount = 0;
1547
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
1548
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
1549
1550
0
    InterlockedIncrement(&value->semaphore);
1551
0
    const freerdp* inst = freerdp_settings_get_pointer(smartcard->settings, FreeRDP_instance);
1552
0
    WINPR_ASSERT(inst);
1553
1554
0
    status = SCARD_E_TIMEOUT;
1555
0
    do
1556
0
    {
1557
0
      for (size_t x = 0; x < cReaders; x++)
1558
0
      {
1559
0
        LPSCARD_READERSTATEW out = &rgReaderStates[x];
1560
1561
0
        for (size_t y = 0; y < MAX_EMULATED_READERS; y++)
1562
0
        {
1563
0
          const LPSCARD_READERSTATEW in = &value->readerStateW[y];
1564
0
          if (out->szReader && in->szReader &&
1565
0
              (_wcscmp(out->szReader, in->szReader) == 0))
1566
0
          {
1567
0
            HashTable_Lock(smartcard->handles);
1568
0
            const SCardHandle* hdl = find_reader(smartcard, in->szReader, TRUE);
1569
0
            out->dwEventState = in->dwEventState;
1570
0
            if (hdl)
1571
0
            {
1572
0
              out->dwEventState |= SCARD_STATE_INUSE;
1573
0
              if (hdl->dwShareMode == SCARD_SHARE_EXCLUSIVE)
1574
0
                out->dwEventState |= SCARD_STATE_EXCLUSIVE;
1575
0
            }
1576
0
            HashTable_Unlock(smartcard->handles);
1577
0
            if ((out->dwEventState & SCARD_STATE_EMPTY) !=
1578
0
                (out->dwCurrentState & SCARD_STATE_EMPTY))
1579
0
              out->dwEventState |= SCARD_STATE_CHANGED;
1580
0
            if ((out->dwEventState & SCARD_STATE_PRESENT) !=
1581
0
                (out->dwCurrentState & SCARD_STATE_PRESENT))
1582
0
              out->dwEventState |= SCARD_STATE_CHANGED;
1583
0
            out->cbAtr = in->cbAtr;
1584
0
            memcpy(out->rgbAtr, in->rgbAtr, out->cbAtr);
1585
1586
0
            if (out->dwEventState & SCARD_STATE_CHANGED)
1587
0
              eventCount++;
1588
0
          }
1589
0
        }
1590
0
      }
1591
0
      if (value->canceled)
1592
0
      {
1593
0
        status = SCARD_E_CANCELLED;
1594
0
        break;
1595
0
      }
1596
0
      if (eventCount != 0)
1597
0
      {
1598
0
        status = SCARD_S_SUCCESS;
1599
0
        break;
1600
0
      }
1601
0
      Sleep(diff);
1602
0
      if (dwTimeout != INFINITE)
1603
0
        dwTimeout -= MIN(dwTimeout, diff);
1604
0
      if (freerdp_shall_disconnect_context(inst->context))
1605
0
      {
1606
0
        status = SCARD_E_CANCELLED;
1607
0
        break;
1608
0
      }
1609
0
    } while (dwTimeout > 0);
1610
0
    InterlockedDecrement(&value->semaphore);
1611
0
  }
1612
1613
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1614
0
             "SCardGetStatusChangeW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1615
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1616
1617
0
  return status;
1618
0
}
1619
1620
LONG WINAPI Emulate_SCardCancel(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext)
1621
0
{
1622
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1623
1624
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardCancel { hContext: %p",
1625
0
             (void*)hContext);
1626
1627
0
  if (status == SCARD_S_SUCCESS)
1628
0
  {
1629
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
1630
0
    WINPR_ASSERT(value);
1631
0
    value->canceled = TRUE;
1632
1633
0
    waitForCancel(value);
1634
0
  }
1635
1636
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1637
0
             "SCardCancel } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1638
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1639
1640
0
  return status;
1641
0
}
1642
1643
SCardHandle* find_reader(SmartcardEmulationContext* smartcard, const void* szReader, BOOL unicode)
1644
0
{
1645
0
  SCardHandle* hdl = nullptr;
1646
0
  ULONG_PTR* keys = nullptr;
1647
1648
0
  WINPR_ASSERT(smartcard);
1649
0
  const size_t count = HashTable_GetKeys(smartcard->handles, &keys);
1650
0
  for (size_t x = 0; x < count; x++)
1651
0
  {
1652
0
    SCardHandle* cur = HashTable_GetItemValue(smartcard->handles, (const void*)keys[x]);
1653
1654
    /* HashTable_GetKeys returns a snapshot taken under the lock, and each lookup here takes
1655
     * the lock again. A handle disconnected in between -- by the smartcard worker or by
1656
     * channel teardown -- is simply gone by now, which is not an invariant violation: skip
1657
     * it rather than assert, since WINPR_ASSERT aborts the process and the race only fires
1658
     * sometimes. */
1659
0
    if (!cur)
1660
0
      continue;
1661
1662
0
    if (cur->unicode != unicode)
1663
0
      continue;
1664
0
    if (!unicode && (strcmp(cur->szReader.pc, szReader) != 0))
1665
0
      continue;
1666
0
    if (unicode && (_wcscmp(cur->szReader.pw, szReader) != 0))
1667
0
      continue;
1668
0
    hdl = cur;
1669
0
    break;
1670
0
  }
1671
0
  free(keys);
1672
0
  return hdl;
1673
0
}
1674
1675
WINPR_ATTR_MALLOC(scard_handle_free, 1)
1676
static SCardHandle* reader2handle(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1677
                                  const void* szReader, BOOL unicode, DWORD dwShareMode,
1678
                                  SCARDHANDLE* phCard, DWORD dwPreferredProtocols,
1679
                                  LPDWORD pdwActiveProtocol)
1680
0
{
1681
0
  WINPR_ASSERT(phCard);
1682
0
  SCardHandle* hdl = nullptr;
1683
1684
0
  *phCard = 0;
1685
0
  if (Emulate_SCardIsValidContext(smartcard, hContext) != SCARD_S_SUCCESS)
1686
0
    goto fail;
1687
1688
0
  hdl = scard_handle_new(smartcard, hContext, szReader, unicode);
1689
0
  if (!hdl)
1690
0
    goto fail;
1691
1692
0
  if (winpr_RAND(&hdl->card, sizeof(hdl->card)) < 0)
1693
0
  {
1694
0
    scard_handle_free(hdl);
1695
0
    hdl = nullptr;
1696
0
    goto fail;
1697
0
  }
1698
0
  hdl->dwActiveProtocol = SCARD_PROTOCOL_T1;
1699
0
  hdl->dwShareMode = dwShareMode;
1700
1701
0
  DWORD activeProtocol = 0;
1702
0
  if (pdwActiveProtocol)
1703
0
  {
1704
0
    if ((hdl->dwActiveProtocol & dwPreferredProtocols) == 0)
1705
0
    {
1706
0
      scard_handle_free(hdl);
1707
0
      hdl = nullptr;
1708
0
      goto fail;
1709
0
    }
1710
0
    else
1711
0
      activeProtocol = hdl->dwActiveProtocol;
1712
0
  }
1713
1714
0
  if (!HashTable_Insert(smartcard->handles, (const void*)hdl->card, hdl))
1715
0
  {
1716
0
    scard_handle_free(hdl);
1717
0
    hdl = nullptr;
1718
0
    goto fail;
1719
0
  }
1720
1721
0
  hdl->referencecount++;
1722
0
  *pdwActiveProtocol = activeProtocol;
1723
0
  *phCard = hdl->card;
1724
1725
0
fail:
1726
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "{ %p }", (void*)*phCard);
1727
0
  return hdl;
1728
0
}
1729
1730
LONG WINAPI Emulate_SCardConnectA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1731
                                  LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols,
1732
                                  LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
1733
0
{
1734
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1735
1736
0
  if (!phCard || !pdwActiveProtocol)
1737
0
    status = SCARD_E_INVALID_PARAMETER;
1738
1739
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardConnectA { hContext: %p",
1740
0
             (void*)hContext);
1741
1742
0
  if (status == SCARD_S_SUCCESS)
1743
0
  {
1744
0
    if (!reader2handle(smartcard, hContext, szReader, FALSE, dwShareMode, phCard,
1745
0
                       dwPreferredProtocols, pdwActiveProtocol))
1746
0
      status = SCARD_E_NO_MEMORY;
1747
0
  }
1748
1749
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1750
0
             "SCardConnectA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1751
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1752
1753
0
  return status;
1754
0
}
1755
1756
LONG WINAPI Emulate_SCardConnectW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
1757
                                  LPCWSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols,
1758
                                  LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
1759
0
{
1760
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
1761
1762
0
  if (!phCard || !pdwActiveProtocol)
1763
0
    status = SCARD_E_INVALID_PARAMETER;
1764
1765
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardConnectW { hContext: %p",
1766
0
             (void*)hContext);
1767
1768
0
  if (status == SCARD_S_SUCCESS)
1769
0
  {
1770
0
    if (!reader2handle(smartcard, hContext, szReader, TRUE, dwShareMode, phCard,
1771
0
                       dwPreferredProtocols, pdwActiveProtocol))
1772
0
      status = SCARD_E_NO_MEMORY;
1773
0
  }
1774
1775
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1776
0
             "SCardConnectW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1777
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1778
1779
0
  return status;
1780
0
}
1781
1782
LONG WINAPI Emulate_SCardReconnect(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
1783
                                   DWORD dwShareMode, WINPR_ATTR_UNUSED DWORD dwPreferredProtocols,
1784
                                   WINPR_ATTR_UNUSED DWORD dwInitialization,
1785
                                   LPDWORD pdwActiveProtocol)
1786
0
{
1787
0
  LONG status = scard_handle_valid(smartcard, hCard);
1788
1789
0
  if (!pdwActiveProtocol)
1790
0
    status = SCARD_E_INVALID_PARAMETER;
1791
1792
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReconnect { hCard: %p",
1793
0
             (void*)hCard);
1794
1795
0
  if (status == SCARD_S_SUCCESS)
1796
0
  {
1797
0
    HashTable_Lock(smartcard->handles);
1798
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1799
0
    WINPR_ASSERT(hdl);
1800
1801
    // TODO: Implement
1802
0
    hdl->dwShareMode = dwShareMode;
1803
0
    hdl->transaction = FALSE;
1804
1805
0
    *pdwActiveProtocol = hdl->dwActiveProtocol;
1806
0
    HashTable_Unlock(smartcard->handles);
1807
0
  }
1808
1809
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1810
0
             "SCardReconnect } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1811
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1812
1813
0
  return status;
1814
0
}
1815
1816
LONG WINAPI Emulate_SCardDisconnect(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
1817
                                    DWORD dwDisposition)
1818
0
{
1819
0
  LONG status = scard_handle_valid(smartcard, hCard);
1820
1821
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardDisconnect { hCard: %p",
1822
0
             (void*)hCard);
1823
1824
0
  WINPR_UNUSED(dwDisposition); /* We just ignore this. All return values are static anyway */
1825
1826
0
  if (status == SCARD_S_SUCCESS)
1827
0
  {
1828
0
    HashTable_Lock(smartcard->handles);
1829
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1830
0
    WINPR_ASSERT(hdl);
1831
1832
0
    hdl->referencecount--;
1833
0
    if (hdl->referencecount == 0)
1834
0
      HashTable_Remove(smartcard->handles, (const void*)hCard);
1835
0
    HashTable_Unlock(smartcard->handles);
1836
0
  }
1837
1838
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1839
0
             "SCardDisconnect } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1840
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1841
1842
0
  return status;
1843
0
}
1844
1845
LONG WINAPI Emulate_SCardBeginTransaction(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard)
1846
0
{
1847
0
  LONG status = scard_handle_valid(smartcard, hCard);
1848
1849
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardBeginTransaction { hCard: %p",
1850
0
             (void*)hCard);
1851
1852
0
  if (status == SCARD_S_SUCCESS)
1853
0
  {
1854
0
    HashTable_Lock(smartcard->handles);
1855
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1856
0
    WINPR_ASSERT(hdl);
1857
0
    if (hdl->transaction)
1858
0
      status = SCARD_E_INVALID_VALUE;
1859
0
    else
1860
0
      hdl->transaction = TRUE;
1861
0
    HashTable_Unlock(smartcard->handles);
1862
0
  }
1863
1864
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1865
0
             "SCardBeginTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1866
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1867
1868
0
  return status;
1869
0
}
1870
1871
LONG WINAPI Emulate_SCardEndTransaction(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
1872
                                        DWORD dwDisposition)
1873
0
{
1874
0
  LONG status = scard_handle_valid(smartcard, hCard);
1875
1876
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardEndTransaction { hCard: %p",
1877
0
             (void*)hCard);
1878
1879
0
  WINPR_UNUSED(dwDisposition); /* We just ignore this. All return values are static anyway */
1880
1881
0
  if (status == SCARD_S_SUCCESS)
1882
0
  {
1883
0
    HashTable_Lock(smartcard->handles);
1884
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1885
0
    WINPR_ASSERT(hdl);
1886
0
    if (!hdl->transaction)
1887
0
      status = SCARD_E_NOT_TRANSACTED;
1888
0
    else
1889
0
      hdl->transaction = FALSE;
1890
0
    HashTable_Unlock(smartcard->handles);
1891
0
  }
1892
1893
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1894
0
             "SCardEndTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1895
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1896
1897
0
  return status;
1898
0
}
1899
1900
LONG WINAPI Emulate_SCardCancelTransaction(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard)
1901
0
{
1902
0
  LONG status = scard_handle_valid(smartcard, hCard);
1903
1904
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardCancelTransaction { hCard: %p",
1905
0
             (void*)hCard);
1906
1907
0
  if (status == SCARD_S_SUCCESS)
1908
0
  {
1909
0
    HashTable_Lock(smartcard->handles);
1910
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1911
0
    WINPR_ASSERT(hdl);
1912
0
    if (!hdl->transaction)
1913
0
      status = SCARD_E_NOT_TRANSACTED;
1914
0
    else
1915
0
      hdl->transaction = FALSE;
1916
0
    HashTable_Unlock(smartcard->handles);
1917
0
  }
1918
1919
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1920
0
             "SCardCancelTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1921
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1922
1923
0
  return status;
1924
0
}
1925
1926
LONG WINAPI Emulate_SCardState(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
1927
                               LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr,
1928
                               LPDWORD pcbAtrLen)
1929
0
{
1930
0
  LONG status = scard_handle_valid(smartcard, hCard);
1931
1932
0
  if (!pdwState || !pdwProtocol)
1933
0
    status = SCARD_E_INVALID_PARAMETER;
1934
1935
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardState { hCard: %p",
1936
0
             (void*)hCard);
1937
1938
0
  if (status == SCARD_S_SUCCESS)
1939
0
  {
1940
0
    HashTable_Lock(smartcard->handles);
1941
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
1942
0
    WINPR_ASSERT(hdl);
1943
1944
0
    if (pdwState)
1945
0
      *pdwState = SCARD_SPECIFIC;
1946
0
    if (pdwProtocol)
1947
0
      *pdwProtocol = SCARD_PROTOCOL_T1;
1948
1949
0
    if (pcbAtrLen)
1950
0
    {
1951
0
      SCardContext* ctx =
1952
0
          HashTable_GetItemValue(smartcard->contexts, (const void*)hdl->hContext);
1953
0
      WINPR_ASSERT(ctx);
1954
1955
0
      for (size_t x = 0; x < MAX_EMULATED_READERS; x++)
1956
0
      {
1957
0
        const SCARD_READERSTATEA* readerA = &ctx->readerStateA[x];
1958
0
        const SCARD_READERSTATEW* readerW = &ctx->readerStateW[x];
1959
0
        if (hdl->unicode)
1960
0
        {
1961
0
          if (_wcscmp(readerW->szReader, hdl->szReader.pw) == 0)
1962
0
          {
1963
0
            *pcbAtrLen = scard_copy_strings(ctx, pbAtr, *pcbAtrLen, readerW->rgbAtr,
1964
0
                                            readerW->cbAtr);
1965
0
          }
1966
0
        }
1967
0
        else
1968
0
        {
1969
0
          if (strcmp(readerA->szReader, hdl->szReader.pc) == 0)
1970
0
          {
1971
0
            *pcbAtrLen = scard_copy_strings(ctx, pbAtr, *pcbAtrLen, readerA->rgbAtr,
1972
0
                                            readerA->cbAtr);
1973
0
          }
1974
0
        }
1975
0
      }
1976
0
    }
1977
0
    HashTable_Unlock(smartcard->handles);
1978
0
  }
1979
1980
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
1981
0
             "SCardState } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
1982
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
1983
1984
0
  return status;
1985
0
}
1986
1987
LONG WINAPI Emulate_SCardStatusA(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
1988
                                 LPSTR mszReaderNames, LPDWORD pcchReaderLen, LPDWORD pdwState,
1989
                                 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1990
0
{
1991
0
  LONG status = scard_handle_valid(smartcard, hCard);
1992
1993
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardStatusA { hCard: %p",
1994
0
             (void*)hCard);
1995
1996
0
  if (status == SCARD_S_SUCCESS)
1997
0
  {
1998
0
    SCardContext* ctx = nullptr;
1999
0
    HashTable_Lock(smartcard->handles);
2000
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
2001
0
    WINPR_ASSERT(hdl);
2002
2003
0
    ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)hdl->hContext);
2004
0
    WINPR_ASSERT(ctx);
2005
2006
0
    if (pcchReaderLen)
2007
0
      *pcchReaderLen =
2008
0
          scard_copy_strings(ctx, mszReaderNames, *pcchReaderLen, hdl->szReader.pc,
2009
0
                             (UINT32)strlen(hdl->szReader.pc) + 2);
2010
2011
0
    if (pdwState)
2012
0
      *pdwState = SCARD_SPECIFIC;
2013
0
    if (pdwProtocol)
2014
0
      *pdwProtocol = SCARD_PROTOCOL_T1;
2015
2016
0
    if (pcbAtrLen)
2017
0
    {
2018
0
      for (size_t x = 0; x < MAX_EMULATED_READERS; x++)
2019
0
      {
2020
0
        const SCARD_READERSTATEA* reader = &ctx->readerStateA[x];
2021
0
        if (strcmp(reader->szReader, hdl->szReader.pc) == 0)
2022
0
        {
2023
0
          *pcbAtrLen =
2024
0
              scard_copy_strings(ctx, pbAtr, *pcbAtrLen, reader->rgbAtr, reader->cbAtr);
2025
0
        }
2026
0
      }
2027
0
    }
2028
0
    HashTable_Unlock(smartcard->handles);
2029
0
  }
2030
2031
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2032
0
             "SCardStatusA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2033
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2034
2035
0
  return status;
2036
0
}
2037
2038
LONG WINAPI Emulate_SCardStatusW(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
2039
                                 LPWSTR mszReaderNames, LPDWORD pcchReaderLen, LPDWORD pdwState,
2040
                                 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
2041
0
{
2042
0
  LONG status = scard_handle_valid(smartcard, hCard);
2043
2044
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardStatusW { hCard: %p",
2045
0
             (void*)hCard);
2046
2047
0
  if (status == SCARD_S_SUCCESS)
2048
0
  {
2049
0
    SCardContext* ctx = nullptr;
2050
0
    HashTable_Lock(smartcard->handles);
2051
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
2052
0
    WINPR_ASSERT(hdl);
2053
2054
0
    ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)hdl->hContext);
2055
0
    WINPR_ASSERT(ctx);
2056
2057
0
    if (pcchReaderLen)
2058
0
      *pcchReaderLen =
2059
0
          scard_copy_strings(ctx, mszReaderNames, *pcchReaderLen, hdl->szReader.pw,
2060
0
                             (UINT32)(_wcslen(hdl->szReader.pw) + 2) * sizeof(WCHAR)) /
2061
0
          sizeof(WCHAR);
2062
2063
0
    if (pdwState)
2064
0
      *pdwState = SCARD_SPECIFIC;
2065
0
    if (pdwProtocol)
2066
0
      *pdwProtocol = SCARD_PROTOCOL_T1;
2067
2068
0
    if (pcbAtrLen)
2069
0
    {
2070
0
      for (size_t x = 0; x < MAX_EMULATED_READERS; x++)
2071
0
      {
2072
0
        const SCARD_READERSTATEW* reader = &ctx->readerStateW[x];
2073
0
        if (_wcscmp(reader->szReader, hdl->szReader.pw) == 0)
2074
0
          *pcbAtrLen =
2075
0
              scard_copy_strings(ctx, pbAtr, *pcbAtrLen, reader->rgbAtr, reader->cbAtr);
2076
0
      }
2077
0
    }
2078
0
    HashTable_Unlock(smartcard->handles);
2079
0
  }
2080
2081
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2082
0
             "SCardStatusW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2083
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2084
2085
0
  return status;
2086
0
}
2087
2088
LONG WINAPI Emulate_SCardTransmit(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
2089
                                  LPCSCARD_IO_REQUEST pioSendPci, LPCBYTE pbSendBuffer,
2090
                                  DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci,
2091
                                  LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
2092
0
{
2093
0
  LONG status = scard_handle_valid(smartcard, hCard);
2094
2095
0
  if (!pioSendPci || !pbSendBuffer || !pbRecvBuffer || !pcbRecvLength)
2096
0
    status = SCARD_E_INVALID_PARAMETER;
2097
2098
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardTransmit { hCard: %p",
2099
0
             (void*)hCard);
2100
2101
0
  if (status == SCARD_S_SUCCESS)
2102
0
  {
2103
0
    BYTE* response = nullptr;
2104
0
    DWORD responseSize = 0;
2105
0
    HashTable_Lock(smartcard->handles);
2106
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
2107
0
    WINPR_ASSERT(hdl);
2108
2109
0
    hdl->transmitcount++;
2110
2111
0
    if (!vgids_process_apdu(hdl->vgids, pbSendBuffer, cbSendLength, &response, &responseSize))
2112
0
      status = SCARD_E_NO_SMARTCARD;
2113
0
    else
2114
0
    {
2115
0
      SCardContext* ctx =
2116
0
          HashTable_GetItemValue(smartcard->contexts, (const void*)hdl->hContext);
2117
0
      WINPR_ASSERT(ctx);
2118
2119
0
      *pcbRecvLength =
2120
0
          scard_copy_strings(ctx, pbRecvBuffer, *pcbRecvLength, response, responseSize);
2121
0
      free(response);
2122
2123
      /* Required */
2124
0
      if (pioRecvPci)
2125
0
        pioRecvPci->dwProtocol = hdl->dwActiveProtocol;
2126
0
    }
2127
0
    HashTable_Unlock(smartcard->handles);
2128
0
  }
2129
2130
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2131
0
             "SCardTransmit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2132
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2133
2134
0
  return status;
2135
0
}
2136
2137
LONG WINAPI Emulate_SCardGetTransmitCount(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
2138
                                          LPDWORD pcTransmitCount)
2139
0
{
2140
0
  LONG status = scard_handle_valid(smartcard, hCard);
2141
2142
0
  if (!pcTransmitCount)
2143
0
    status = SCARD_E_INVALID_PARAMETER;
2144
2145
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetTransmitCount { hCard: %p",
2146
0
             (void*)hCard);
2147
2148
0
  if (status == SCARD_S_SUCCESS)
2149
0
  {
2150
0
    HashTable_Lock(smartcard->handles);
2151
0
    SCardHandle* hdl = HashTable_GetItemValue(smartcard->handles, (const void*)hCard);
2152
0
    WINPR_ASSERT(hdl);
2153
2154
0
    *pcTransmitCount = hdl->transmitcount;
2155
0
    HashTable_Unlock(smartcard->handles);
2156
0
  }
2157
2158
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2159
0
             "SCardGetTransmitCount } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2160
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2161
2162
0
  return status;
2163
0
}
2164
2165
LONG WINAPI Emulate_SCardControl(
2166
    SmartcardEmulationContext* smartcard, SCARDHANDLE hCard, DWORD dwControlCode,
2167
    LPCVOID lpInBuffer, DWORD cbInBufferSize, LPVOID lpOutBuffer, DWORD cbOutBufferSize,
2168
    LPDWORD lpBytesReturned /* NOLINT(readability-non-const-parameter) */)
2169
0
{
2170
0
  LONG status = scard_handle_valid(smartcard, hCard);
2171
2172
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardControl { hCard: %p",
2173
0
             (void*)hCard);
2174
2175
0
  if (status == SCARD_S_SUCCESS)
2176
0
  {
2177
0
    WINPR_UNUSED(dwControlCode);
2178
0
    WINPR_UNUSED(lpInBuffer);
2179
0
    WINPR_UNUSED(cbInBufferSize);
2180
0
    WINPR_UNUSED(lpOutBuffer);
2181
0
    WINPR_UNUSED(cbOutBufferSize);
2182
0
    WINPR_UNUSED(lpBytesReturned);
2183
2184
    /* Not required, return not supported */
2185
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2186
0
  }
2187
2188
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2189
0
             "SCardControl } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2190
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2191
2192
0
  return status;
2193
0
}
2194
2195
LONG WINAPI Emulate_SCardGetAttrib(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
2196
                                   DWORD dwAttrId,
2197
                                   LPBYTE pbAttr /* NOLINT(readability-non-const-parameter) */,
2198
                                   LPDWORD pcbAttrLen /* NOLINT(readability-non-const-parameter) */)
2199
0
{
2200
0
  LONG status = scard_handle_valid(smartcard, hCard);
2201
2202
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetAttrib { hCard: %p",
2203
0
             (void*)hCard);
2204
2205
0
  WINPR_UNUSED(dwAttrId);
2206
0
  WINPR_UNUSED(pbAttr);
2207
0
  WINPR_UNUSED(pcbAttrLen);
2208
2209
  /* Not required, return not supported */
2210
0
  if (status == SCARD_S_SUCCESS)
2211
0
    status = SCARD_F_INTERNAL_ERROR;
2212
2213
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2214
0
             "SCardGetAttrib } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2215
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2216
2217
0
  return status;
2218
0
}
2219
2220
LONG WINAPI Emulate_SCardSetAttrib(SmartcardEmulationContext* smartcard, SCARDHANDLE hCard,
2221
                                   DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
2222
0
{
2223
0
  LONG status = scard_handle_valid(smartcard, hCard);
2224
2225
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardSetAttrib { hCard: %p",
2226
0
             (void*)hCard);
2227
2228
0
  WINPR_UNUSED(dwAttrId);
2229
0
  WINPR_UNUSED(pbAttr);
2230
0
  WINPR_UNUSED(cbAttrLen);
2231
2232
  /* Not required, return not supported */
2233
0
  if (status == SCARD_S_SUCCESS)
2234
0
    status = SCARD_F_INTERNAL_ERROR;
2235
2236
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2237
0
             "SCardSetAttrib } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2238
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2239
2240
0
  return status;
2241
0
}
2242
2243
LONG WINAPI Emulate_SCardUIDlgSelectCardA(SmartcardEmulationContext* smartcard,
2244
                                          LPOPENCARDNAMEA_EX pDlgStruc)
2245
0
{
2246
0
  LONG status = 0;
2247
2248
0
  WINPR_ASSERT(smartcard);
2249
2250
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardUIDlgSelectCardA {");
2251
2252
0
  WINPR_UNUSED(pDlgStruc);
2253
2254
  /* Not required, return not supported */
2255
0
  status = SCARD_E_UNSUPPORTED_FEATURE;
2256
2257
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2258
0
             "SCardUIDlgSelectCardA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2259
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2260
2261
0
  return status;
2262
0
}
2263
2264
LONG WINAPI Emulate_SCardUIDlgSelectCardW(SmartcardEmulationContext* smartcard,
2265
                                          LPOPENCARDNAMEW_EX pDlgStruc)
2266
0
{
2267
0
  LONG status = 0;
2268
2269
0
  WINPR_ASSERT(smartcard);
2270
2271
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardUIDlgSelectCardW {");
2272
2273
0
  WINPR_UNUSED(pDlgStruc);
2274
2275
  /* Not required, return not supported */
2276
0
  status = SCARD_E_UNSUPPORTED_FEATURE;
2277
2278
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2279
0
             "SCardUIDlgSelectCardW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2280
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2281
2282
0
  return status;
2283
0
}
2284
2285
LONG WINAPI Emulate_GetOpenCardNameA(SmartcardEmulationContext* smartcard,
2286
                                     LPOPENCARDNAMEA pDlgStruc)
2287
0
{
2288
0
  LONG status = 0;
2289
2290
0
  WINPR_ASSERT(smartcard);
2291
2292
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "GetOpenCardNameA {");
2293
2294
0
  WINPR_UNUSED(pDlgStruc);
2295
2296
  /* Not required, return not supported */
2297
0
  status = SCARD_E_UNSUPPORTED_FEATURE;
2298
2299
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2300
0
             "GetOpenCardNameA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2301
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2302
2303
0
  return status;
2304
0
}
2305
2306
LONG WINAPI Emulate_GetOpenCardNameW(SmartcardEmulationContext* smartcard,
2307
                                     LPOPENCARDNAMEW pDlgStruc)
2308
0
{
2309
0
  LONG status = 0;
2310
2311
0
  WINPR_ASSERT(smartcard);
2312
2313
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "GetOpenCardNameW {");
2314
2315
0
  WINPR_UNUSED(pDlgStruc);
2316
2317
  /* Not required, return not supported */
2318
0
  status = SCARD_E_UNSUPPORTED_FEATURE;
2319
2320
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2321
0
             "GetOpenCardNameW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2322
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2323
2324
0
  return status;
2325
0
}
2326
2327
LONG WINAPI Emulate_SCardDlgExtendedError(SmartcardEmulationContext* smartcard)
2328
0
{
2329
0
  LONG status = 0;
2330
2331
0
  WINPR_ASSERT(smartcard);
2332
2333
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardDlgExtendedError {");
2334
2335
  /* Not required, return not supported */
2336
0
  status = SCARD_E_UNSUPPORTED_FEATURE;
2337
2338
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2339
0
             "SCardDlgExtendedError } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2340
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2341
2342
0
  return status;
2343
0
}
2344
2345
LONG WINAPI Emulate_SCardReadCacheA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2346
                                    UUID* CardIdentifier, DWORD FreshnessCounter, LPSTR LookupName,
2347
                                    PBYTE Data, DWORD* DataLen)
2348
0
{
2349
0
  DWORD count = 0;
2350
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2351
2352
0
  if (!CardIdentifier || !DataLen)
2353
0
    status = SCARD_E_INVALID_PARAMETER;
2354
2355
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReadCacheA { hContext: %p",
2356
0
             (void*)hContext);
2357
2358
0
  if (DataLen)
2359
0
  {
2360
0
    count = *DataLen;
2361
0
    *DataLen = 0;
2362
0
  }
2363
2364
0
  if (status == SCARD_S_SUCCESS)
2365
0
  {
2366
0
    SCardCacheItem* data = nullptr;
2367
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2368
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
2369
2370
0
    char* id = card_id_and_name_a(CardIdentifier, LookupName);
2371
0
    if (id)
2372
0
      data = HashTable_GetItemValue(value->cache, id);
2373
0
    free(id);
2374
2375
0
    if (!data)
2376
0
      status = SCARD_W_CACHE_ITEM_NOT_FOUND;
2377
0
    else if (data->freshness != FreshnessCounter)
2378
0
      status = SCARD_W_CACHE_ITEM_STALE;
2379
0
    else
2380
0
      *DataLen = scard_copy_strings(value, Data, count, data->data, data->size);
2381
0
  }
2382
2383
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2384
0
             "SCardReadCacheA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2385
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2386
2387
0
  return status;
2388
0
}
2389
2390
LONG WINAPI Emulate_SCardReadCacheW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2391
                                    UUID* CardIdentifier, DWORD FreshnessCounter, LPWSTR LookupName,
2392
                                    PBYTE Data, DWORD* DataLen)
2393
0
{
2394
0
  DWORD count = 0;
2395
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2396
2397
0
  if (!CardIdentifier || !DataLen)
2398
0
    status = SCARD_E_INVALID_PARAMETER;
2399
2400
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardReadCacheW { hContext: %p",
2401
0
             (void*)hContext);
2402
2403
0
  if (DataLen)
2404
0
  {
2405
0
    count = *DataLen;
2406
0
    *DataLen = 0;
2407
0
  }
2408
2409
0
  if (status == SCARD_S_SUCCESS)
2410
0
  {
2411
0
    SCardCacheItem* data = nullptr;
2412
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2413
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
2414
2415
0
    char* id = card_id_and_name_w(CardIdentifier, LookupName);
2416
0
    data = HashTable_GetItemValue(value->cache, id);
2417
0
    free(id);
2418
0
    if (!data)
2419
0
      status = SCARD_W_CACHE_ITEM_NOT_FOUND;
2420
0
    else if (data->freshness != FreshnessCounter)
2421
0
      status = SCARD_W_CACHE_ITEM_STALE;
2422
0
    else
2423
0
      *DataLen = scard_copy_strings(value, Data, count, data->data, data->size);
2424
0
  }
2425
2426
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2427
0
             "SCardReadCacheW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2428
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2429
2430
0
  return status;
2431
0
}
2432
2433
WINPR_ATTR_NODISCARD
2434
static LONG insert_data(wHashTable* table, DWORD FreshnessCounter, const char* key,
2435
                        const PBYTE Data, DWORD DataLen)
2436
0
{
2437
0
  BOOL rc = 0;
2438
0
  SCardCacheItem* item = nullptr;
2439
2440
0
  WINPR_ASSERT(table);
2441
0
  WINPR_ASSERT(key);
2442
2443
0
  if (DataLen > MAX_CACHE_ITEM_SIZE)
2444
0
    return SCARD_W_CACHE_ITEM_TOO_BIG;
2445
2446
0
  if (HashTable_Count(table) > MAX_CACHE_ITEM_VALUES)
2447
0
    return SCARD_E_WRITE_TOO_MANY;
2448
2449
0
  item = HashTable_GetItemValue(table, key);
2450
0
  if (!item)
2451
0
  {
2452
0
    item = calloc(1, sizeof(SCardCacheItem));
2453
0
    if (!item)
2454
0
      return SCARD_E_NO_MEMORY;
2455
2456
0
    rc = HashTable_Insert(table, key, item);
2457
0
    if (!rc)
2458
0
    {
2459
0
      free(item);
2460
0
      return SCARD_E_NO_MEMORY;
2461
0
    }
2462
0
  }
2463
2464
0
  if (item->freshness > FreshnessCounter)
2465
0
    return SCARD_W_CACHE_ITEM_STALE;
2466
0
  item->freshness = FreshnessCounter;
2467
0
  item->size = DataLen;
2468
0
  memcpy(item->data, Data, DataLen);
2469
2470
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of item
2471
0
  return SCARD_S_SUCCESS;
2472
0
}
2473
2474
LONG WINAPI Emulate_SCardWriteCacheA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2475
                                     UUID* CardIdentifier, DWORD FreshnessCounter, LPSTR LookupName,
2476
                                     PBYTE Data, DWORD DataLen)
2477
0
{
2478
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2479
2480
0
  if (!CardIdentifier)
2481
0
    status = SCARD_E_INVALID_PARAMETER;
2482
2483
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardWriteCacheA { hContext: %p",
2484
0
             (void*)hContext);
2485
2486
0
  if (status == SCARD_S_SUCCESS)
2487
0
  {
2488
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2489
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
2490
2491
0
    char* id = card_id_and_name_a(CardIdentifier, LookupName);
2492
0
    if (!id)
2493
0
      status = SCARD_E_NO_MEMORY;
2494
0
    else
2495
0
    {
2496
0
      status = insert_data(value->cache, FreshnessCounter, id, Data, DataLen);
2497
0
      free(id);
2498
0
    }
2499
0
  }
2500
2501
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2502
0
             "SCardWriteCacheA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2503
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2504
2505
0
  return status;
2506
0
}
2507
2508
LONG WINAPI Emulate_SCardWriteCacheW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2509
                                     UUID* CardIdentifier, DWORD FreshnessCounter,
2510
                                     LPWSTR LookupName, PBYTE Data, DWORD DataLen)
2511
0
{
2512
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2513
2514
0
  if (!CardIdentifier)
2515
0
    status = SCARD_E_INVALID_PARAMETER;
2516
2517
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardWriteCacheW { hContext: %p",
2518
0
             (void*)hContext);
2519
2520
0
  if (status == SCARD_S_SUCCESS)
2521
0
  {
2522
0
    SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2523
0
    WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
2524
2525
0
    char* id = card_id_and_name_w(CardIdentifier, LookupName);
2526
0
    if (!id)
2527
0
      status = SCARD_E_NO_MEMORY;
2528
0
    else
2529
0
    {
2530
0
      status = insert_data(value->cache, FreshnessCounter, id, Data, DataLen);
2531
0
      free(id);
2532
0
    }
2533
0
  }
2534
2535
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2536
0
             "SCardWriteCacheW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2537
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2538
2539
0
  return status;
2540
0
}
2541
2542
LONG WINAPI Emulate_SCardGetReaderIconA(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2543
                                        LPCSTR szReaderName, LPBYTE pbIcon, LPDWORD pcbIcon)
2544
0
{
2545
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2546
2547
0
  if (!szReaderName || !pcbIcon)
2548
0
    status = SCARD_E_INVALID_PARAMETER;
2549
2550
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetReaderIconA { hContext: %p",
2551
0
             (void*)hContext);
2552
2553
0
  if (status == SCARD_S_SUCCESS)
2554
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
2555
2556
0
  if (status == SCARD_S_SUCCESS)
2557
0
  {
2558
0
    SCardContext* ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2559
0
    WINPR_ASSERT(ctx);
2560
2561
0
    if (pbIcon)
2562
0
      *pcbIcon = scard_copy_strings(ctx, pbIcon, *pcbIcon, resources_FreeRDP_ico,
2563
0
                                    resources_FreeRDP_ico_len);
2564
0
    else
2565
0
      *pcbIcon = resources_FreeRDP_ico_len;
2566
0
  }
2567
2568
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2569
0
             "SCardGetReaderIconA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2570
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2571
2572
0
  return status;
2573
0
}
2574
2575
LONG WINAPI Emulate_SCardGetReaderIconW(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2576
                                        LPCWSTR szReaderName, LPBYTE pbIcon, LPDWORD pcbIcon)
2577
0
{
2578
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2579
2580
0
  if (!szReaderName || !pcbIcon)
2581
0
    status = SCARD_E_INVALID_PARAMETER;
2582
2583
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetReaderIconW { hContext: %p",
2584
0
             (void*)hContext);
2585
2586
0
  if (status == SCARD_S_SUCCESS)
2587
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
2588
2589
0
  if (status == SCARD_S_SUCCESS)
2590
0
  {
2591
0
    SCardContext* ctx = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
2592
0
    WINPR_ASSERT(ctx);
2593
2594
0
    if (pbIcon)
2595
0
      *pcbIcon = scard_copy_strings(ctx, pbIcon, *pcbIcon, resources_FreeRDP_ico,
2596
0
                                    resources_FreeRDP_ico_len);
2597
0
    else
2598
0
      *pcbIcon = resources_FreeRDP_ico_len;
2599
0
  }
2600
2601
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2602
0
             "SCardGetReaderIconW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2603
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2604
2605
0
  return status;
2606
0
}
2607
2608
LONG WINAPI Emulate_SCardGetDeviceTypeIdA(SmartcardEmulationContext* smartcard,
2609
                                          SCARDCONTEXT hContext, LPCSTR szReaderName,
2610
                                          LPDWORD pdwDeviceTypeId)
2611
0
{
2612
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2613
2614
0
  if (!pdwDeviceTypeId)
2615
0
    status = SCARD_E_INVALID_PARAMETER;
2616
2617
0
  if (status == SCARD_S_SUCCESS)
2618
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
2619
2620
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetDeviceTypeIdA { hContext: %p",
2621
0
             (void*)hContext);
2622
2623
0
  if (status == SCARD_S_SUCCESS)
2624
0
  {
2625
0
    *pdwDeviceTypeId = SCARD_READER_TYPE_USB; // SCARD_READER_TYPE_TPM
2626
0
  }
2627
2628
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2629
0
             "SCardGetDeviceTypeIdA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2630
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2631
2632
0
  return status;
2633
0
}
2634
2635
LONG WINAPI Emulate_SCardGetDeviceTypeIdW(SmartcardEmulationContext* smartcard,
2636
                                          SCARDCONTEXT hContext, LPCWSTR szReaderName,
2637
                                          LPDWORD pdwDeviceTypeId)
2638
0
{
2639
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2640
2641
0
  if (!pdwDeviceTypeId)
2642
0
    status = SCARD_E_INVALID_PARAMETER;
2643
2644
0
  if (status == SCARD_S_SUCCESS)
2645
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
2646
2647
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardGetDeviceTypeIdW { hContext: %p",
2648
0
             (void*)hContext);
2649
2650
0
  if (status == SCARD_S_SUCCESS)
2651
0
  {
2652
0
    *pdwDeviceTypeId = SCARD_READER_TYPE_USB; // SCARD_READER_TYPE_TPM
2653
0
  }
2654
2655
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2656
0
             "SCardGetDeviceTypeIdW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2657
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2658
2659
0
  return status;
2660
0
}
2661
2662
LONG WINAPI Emulate_SCardGetReaderDeviceInstanceIdA(
2663
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCSTR szReaderName,
2664
    LPSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
2665
    LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
2666
0
{
2667
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2668
2669
0
  if (status == SCARD_S_SUCCESS)
2670
0
    status = scard_reader_name_valid_a(smartcard, hContext, szReaderName);
2671
2672
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2673
0
             "SCardGetReaderDeviceInstanceIdA { hContext: %p", (void*)hContext);
2674
2675
0
  WINPR_UNUSED(szDeviceInstanceId);
2676
0
  WINPR_UNUSED(pcchDeviceInstanceId);
2677
2678
  /* Not required, return not supported */
2679
0
  if (status == SCARD_S_SUCCESS)
2680
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2681
2682
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2683
0
             "SCardGetReaderDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")",
2684
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
2685
2686
0
  return status;
2687
0
}
2688
2689
LONG WINAPI Emulate_SCardGetReaderDeviceInstanceIdW(
2690
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCWSTR szReaderName,
2691
    LPWSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
2692
    LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
2693
0
{
2694
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2695
2696
0
  if (status == SCARD_S_SUCCESS)
2697
0
    status = scard_reader_name_valid_w(smartcard, hContext, szReaderName);
2698
2699
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2700
0
             "SCardGetReaderDeviceInstanceIdW { hContext: %p", (void*)hContext);
2701
2702
0
  WINPR_UNUSED(szDeviceInstanceId);
2703
0
  WINPR_UNUSED(pcchDeviceInstanceId);
2704
2705
  /* Not required, return not supported */
2706
0
  if (status == SCARD_S_SUCCESS)
2707
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2708
2709
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2710
0
             "SCardGetReaderDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")",
2711
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
2712
2713
0
  return status;
2714
0
}
2715
2716
LONG WINAPI Emulate_SCardListReadersWithDeviceInstanceIdA(
2717
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCSTR szDeviceInstanceId,
2718
    LPSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
2719
    LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
2720
0
{
2721
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2722
2723
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2724
0
             "SCardListReadersWithDeviceInstanceIdA { hContext: %p", (void*)hContext);
2725
2726
0
  WINPR_UNUSED(szDeviceInstanceId);
2727
0
  WINPR_UNUSED(mszReaders);
2728
0
  WINPR_UNUSED(pcchReaders);
2729
2730
  /* Not required, return not supported */
2731
0
  if (status == SCARD_S_SUCCESS)
2732
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2733
2734
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2735
0
             "SCardListReadersWithDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")",
2736
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
2737
2738
0
  return status;
2739
0
}
2740
2741
LONG WINAPI Emulate_SCardListReadersWithDeviceInstanceIdW(
2742
    SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext, LPCWSTR szDeviceInstanceId,
2743
    LPWSTR mszReaders /* NOLINT(readability-non-const-parameter) */, LPDWORD pcchReaders)
2744
0
{
2745
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2746
2747
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2748
0
             "SCardListReadersWithDeviceInstanceIdW { hContext: %p", (void*)hContext);
2749
2750
0
  WINPR_UNUSED(szDeviceInstanceId);
2751
0
  WINPR_UNUSED(mszReaders);
2752
0
  WINPR_UNUSED(pcchReaders);
2753
2754
  /* Not required, return not supported */
2755
0
  if (status == SCARD_S_SUCCESS)
2756
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2757
2758
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2759
0
             "SCardListReadersWithDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")",
2760
0
             SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status));
2761
2762
0
  return status;
2763
0
}
2764
2765
LONG WINAPI Emulate_SCardAudit(SmartcardEmulationContext* smartcard, SCARDCONTEXT hContext,
2766
                               DWORD dwEvent)
2767
0
{
2768
0
  LONG status = Emulate_SCardIsValidContext(smartcard, hContext);
2769
2770
0
  WINPR_UNUSED(dwEvent);
2771
2772
0
  WLog_Print(smartcard->log, smartcard->log_default_level, "SCardAudit { hContext: %p",
2773
0
             (void*)hContext);
2774
2775
  // TODO: Implement
2776
0
  if (status == SCARD_S_SUCCESS)
2777
0
    status = SCARD_E_UNSUPPORTED_FEATURE;
2778
2779
0
  WLog_Print(smartcard->log, smartcard->log_default_level,
2780
0
             "SCardAudit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status),
2781
0
             WINPR_CXX_COMPAT_CAST(UINT32, status));
2782
2783
0
  return status;
2784
0
}
2785
2786
WINPR_ATTR_NODISCARD
2787
static BOOL context_equals(const void* pva, const void* pvb)
2788
0
{
2789
0
  const SCARDCONTEXT a = (const SCARDCONTEXT)pva;
2790
0
  const SCARDCONTEXT b = (const SCARDCONTEXT)pvb;
2791
0
  if (!a && !b)
2792
0
    return TRUE;
2793
0
  if (!a || !b)
2794
0
    return FALSE;
2795
2796
0
  return a == b;
2797
0
}
2798
2799
WINPR_ATTR_NODISCARD
2800
static BOOL handle_equals(const void* pva, const void* pvb)
2801
0
{
2802
0
  const SCARDHANDLE a = (const SCARDHANDLE)pva;
2803
0
  const SCARDHANDLE b = (const SCARDHANDLE)pvb;
2804
0
  if (!a && !b)
2805
0
    return TRUE;
2806
0
  if (!a || !b)
2807
0
    return FALSE;
2808
2809
0
  return a == b;
2810
0
}
2811
2812
static void entry_free(void* ptr)
2813
0
{
2814
0
  SmartcardPinCounterEntry* entry = ptr;
2815
0
  if (!entry)
2816
0
    return;
2817
2818
0
  winpr_zfree(entry->pin);
2819
0
  free(entry);
2820
0
}
2821
2822
WINPR_ATTR_MALLOC(entry_free, 1)
2823
static void* entry_clone(const void* other)
2824
0
{
2825
0
  const SmartcardPinCounterEntry* entry = other;
2826
0
  if (!entry)
2827
0
    return nullptr;
2828
2829
0
  SmartcardPinCounterEntry* clone = calloc(1, sizeof(SmartcardPinCounterEntry));
2830
0
  if (!clone)
2831
0
    return nullptr;
2832
0
  *clone = *entry;
2833
0
  if (entry->pin)
2834
0
  {
2835
0
    clone->pin = _strdup(entry->pin);
2836
0
    if (!clone->pin)
2837
0
    {
2838
0
      entry_free(clone);
2839
0
      return nullptr;
2840
0
    }
2841
0
  }
2842
0
  return clone;
2843
0
}
2844
2845
SmartcardEmulationContext* Emulate_New(const rdpSettings* settings)
2846
0
{
2847
0
  SmartcardEmulationContext* smartcard = nullptr;
2848
2849
0
  WINPR_ASSERT(settings);
2850
2851
0
  smartcard = calloc(1, sizeof(SmartcardEmulationContext));
2852
0
  if (!smartcard)
2853
0
    goto fail;
2854
2855
0
  smartcard->settings = settings;
2856
0
  smartcard->log = WLog_Get("EmulateSCard");
2857
0
  if (!smartcard->log)
2858
0
    goto fail;
2859
0
  smartcard->log_default_level = WLOG_TRACE;
2860
2861
0
  smartcard->contexts = HashTable_New(FALSE);
2862
0
  if (!smartcard->contexts)
2863
0
    goto fail;
2864
0
  else
2865
0
  {
2866
0
    wObject* obj = HashTable_KeyObject(smartcard->contexts);
2867
0
    WINPR_ASSERT(obj);
2868
0
    obj->fnObjectEquals = context_equals;
2869
0
  }
2870
0
  if (!smartcard->contexts)
2871
0
    goto fail;
2872
0
  else
2873
0
  {
2874
0
    wObject* obj = HashTable_ValueObject(smartcard->contexts);
2875
0
    WINPR_ASSERT(obj);
2876
0
    obj->fnObjectFree = scard_context_free;
2877
0
  }
2878
2879
0
  smartcard->handles = HashTable_New(TRUE);
2880
0
  if (!smartcard->handles)
2881
0
    goto fail;
2882
0
  else
2883
0
  {
2884
0
    wObject* obj = HashTable_KeyObject(smartcard->handles);
2885
0
    WINPR_ASSERT(obj);
2886
0
    obj->fnObjectEquals = handle_equals;
2887
0
  }
2888
0
  if (!smartcard->handles)
2889
0
    goto fail;
2890
0
  else
2891
0
  {
2892
0
    wObject* obj = HashTable_ValueObject(smartcard->handles);
2893
0
    WINPR_ASSERT(obj);
2894
0
    obj->fnObjectFree = scard_handle_free;
2895
0
  }
2896
2897
0
  smartcard->pinCounters = HashTable_New(TRUE);
2898
0
  if (!smartcard->pinCounters)
2899
0
    goto fail;
2900
0
  else if (!HashTable_SetupForStringData(smartcard->pinCounters, FALSE))
2901
0
    goto fail;
2902
0
  else
2903
0
  {
2904
0
    wObject* obj = HashTable_ValueObject(smartcard->pinCounters);
2905
0
    WINPR_ASSERT(obj);
2906
0
    obj->fnObjectEquals = nullptr;
2907
0
    obj->fnObjectFree = entry_free;
2908
0
    obj->fnObjectNew = entry_clone;
2909
0
  }
2910
0
  return smartcard;
2911
2912
0
fail:
2913
0
  WINPR_PRAGMA_DIAG_PUSH
2914
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2915
0
  Emulate_Free(smartcard);
2916
0
  WINPR_PRAGMA_DIAG_POP
2917
0
  return nullptr;
2918
0
}
2919
2920
void Emulate_Free(SmartcardEmulationContext* context)
2921
0
{
2922
0
  if (!context)
2923
0
    return;
2924
2925
0
  HashTable_Free(context->handles);
2926
0
  HashTable_Free(context->contexts);
2927
0
  HashTable_Free(context->pinCounters);
2928
0
  free(context);
2929
0
}
2930
2931
BOOL Emulate_IsConfigured(SmartcardEmulationContext* context)
2932
0
{
2933
0
  BOOL rc = FALSE;
2934
0
  vgidsContext* vgids = nullptr;
2935
0
  const char* pem = nullptr;
2936
0
  const char* key = nullptr;
2937
0
  const char* pin = nullptr;
2938
2939
0
  WINPR_ASSERT(context);
2940
2941
0
  pem = freerdp_settings_get_string(context->settings, FreeRDP_SmartcardCertificate);
2942
0
  key = freerdp_settings_get_string(context->settings, FreeRDP_SmartcardPrivateKey);
2943
0
  pin = freerdp_settings_get_string(context->settings, FreeRDP_Password);
2944
2945
  /* Cache result only, if no initialization arguments changed. */
2946
0
  if ((context->pem == pem) && (context->key == key) && (context->pin == pin))
2947
0
    return context->configured;
2948
2949
0
  context->pem = pem;
2950
0
  context->key = key;
2951
0
  context->pin = pin;
2952
2953
0
  vgids = vgids_new(context);
2954
0
  if (vgids)
2955
0
    rc = vgids_init(vgids, context->pem, context->key, context->pin);
2956
0
  vgids_free(vgids);
2957
2958
0
  context->configured = rc;
2959
0
  return rc;
2960
0
}
2961
2962
BOOL Emulate_SetupPin(SmartcardEmulationContext* context, const char* name, const char* pin)
2963
0
{
2964
0
  WINPR_ASSERT(context);
2965
2966
0
  const SmartcardPinCounterEntry entry = { .curRetryCounter = VGIDS_DEFAULT_RETRY_COUNTER,
2967
0
                                         .retryCounter = VGIDS_DEFAULT_RETRY_COUNTER,
2968
0
                                         .pin = WINPR_CAST_CONST_PTR_AWAY(pin, char*) };
2969
2970
0
  BOOL rc = FALSE;
2971
0
  HashTable_Lock(context->pinCounters);
2972
0
  const SmartcardPinCounterEntry* val = HashTable_GetItemValue(context->pinCounters, name);
2973
0
  if (!val)
2974
0
    rc = HashTable_Insert(context->pinCounters, name, &entry);
2975
0
  else
2976
0
  {
2977
0
    if (val->pin && pin)
2978
0
      rc = strcmp(val->pin, pin) == 0;
2979
0
  }
2980
0
  HashTable_Unlock(context->pinCounters);
2981
0
  return rc;
2982
0
}
2983
2984
BOOL Emulate_IsPinValid(SmartcardEmulationContext* context, const char* name, const char* pin,
2985
                        size_t bytelen, UINT16* remaining)
2986
0
{
2987
0
  WINPR_ASSERT(context);
2988
0
  WINPR_ASSERT(remaining);
2989
2990
0
  *remaining = 0;
2991
2992
0
  BOOL rc = FALSE;
2993
0
  HashTable_Lock(context->pinCounters);
2994
0
  SmartcardPinCounterEntry* val = HashTable_GetItemValue(context->pinCounters, name);
2995
0
  if (val)
2996
0
  {
2997
0
    if (val->pin && pin)
2998
0
    {
2999
0
      const size_t min = strlen(val->pin);
3000
0
      if (bytelen >= min)
3001
0
        rc = strncmp(val->pin, pin, min + 1) == 0;
3002
0
    }
3003
0
    if (!rc)
3004
0
    {
3005
0
      if (val->curRetryCounter > 0)
3006
0
        val->curRetryCounter--;
3007
0
      else
3008
0
        val->curRetryCounter = val->retryCounter;
3009
0
    }
3010
0
    *remaining = val->curRetryCounter;
3011
0
  }
3012
3013
0
  HashTable_Unlock(context->pinCounters);
3014
0
  return rc;
3015
0
}
3016
3017
BOOL Emulate_IsPinBlocked(SmartcardEmulationContext* context, const char* name)
3018
0
{
3019
0
  WINPR_ASSERT(context);
3020
3021
0
  BOOL rc = FALSE;
3022
0
  HashTable_Lock(context->pinCounters);
3023
0
  const SmartcardPinCounterEntry* val = HashTable_GetItemValue(context->pinCounters, name);
3024
0
  if (val)
3025
0
    rc = val->curRetryCounter == 0;
3026
0
  HashTable_Unlock(context->pinCounters);
3027
0
  return rc;
3028
0
}