Coverage Report

Created: 2026-03-07 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/smartcard/smartcard_pcsc.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Smart Card API
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2020 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2020 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/config.h>
23
24
#ifndef _WIN32
25
26
#ifdef __APPLE__
27
#include <sys/types.h>
28
#include <sys/param.h>
29
#include <sys/sysctl.h>
30
#include <string.h>
31
#include <ctype.h>
32
#include <errno.h>
33
#endif
34
35
#include <stdio.h>
36
#include <stdlib.h>
37
38
#include <winpr/crt.h>
39
#include <winpr/assert.h>
40
#include <winpr/synch.h>
41
#include <winpr/library.h>
42
#include <winpr/smartcard.h>
43
#include <winpr/collections.h>
44
#include <winpr/environment.h>
45
46
#include "smartcard_pcsc.h"
47
48
#include "../log.h"
49
#define TAG WINPR_TAG("smartcard")
50
51
#ifndef MIN
52
0
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
53
#endif
54
55
#define WINSCARD_LOAD_PROC_EX(module, pcsc, _fname, _name)                   \
56
0
  do                                                                       \
57
0
  {                                                                        \
58
0
    WINPR_PRAGMA_DIAG_PUSH                                               \
59
0
    WINPR_PRAGMA_DIAG_IGNORED_PEDANTIC                                   \
60
0
    pcsc.pfn##_fname = GetProcAddressAs(module, #_name, fnPCSC##_fname); \
61
0
    WINPR_PRAGMA_DIAG_POP                                                \
62
0
  } while (0)
63
64
0
#define WINSCARD_LOAD_PROC(module, pcsc, _name) WINSCARD_LOAD_PROC_EX(module, pcsc, _name, _name)
65
66
/**
67
 * PC/SC transactions:
68
 * http://developersblog.wwpass.com/?p=180
69
 */
70
71
/**
72
 * Smart Card Logon on Windows Vista:
73
 * http://blogs.msdn.com/b/shivaram/archive/2007/02/26/smart-card-logon-on-windows-vista.aspx
74
 */
75
76
/**
77
 * The Smart Card Cryptographic Service Provider Cookbook:
78
 * http://msdn.microsoft.com/en-us/library/ms953432.aspx
79
 *
80
 * SCARDCONTEXT
81
 *
82
 * The context is a communication channel with the smart card resource manager and
83
 * all calls to the resource manager must go through this link.
84
 *
85
 * All functions that take a context as a parameter or a card handle as parameter,
86
 * which is indirectly associated with a particular context, may be blocking calls.
87
 * Examples of these are SCardGetStatusChange and SCardBeginTransaction, which takes
88
 * a card handle as a parameter. If such a function blocks then all operations wanting
89
 * to use the context are blocked as well. So, it is recommended that a CSP using
90
 * monitoring establishes at least two contexts with the resource manager; one for
91
 * monitoring (with SCardGetStatusChange) and one for other operations.
92
 *
93
 * If multiple cards are present, it is recommended that a separate context or pair
94
 * of contexts be established for each card to prevent operations on one card from
95
 * blocking operations on another.
96
 *
97
 * Example one
98
 *
99
 * The example below shows what can happen if a CSP using SCardGetStatusChange for
100
 * monitoring does not establish two contexts with the resource manager.
101
 * The context becomes unusable until SCardGetStatusChange unblocks.
102
 *
103
 * In this example, there is one process running called P1.
104
 * P1 calls SCardEstablishContext, which returns the context hCtx.
105
 * P1 calls SCardConnect (with the hCtx context) which returns a handle to the card, hCard.
106
 * P1 calls SCardGetStatusChange (with the hCtx context) which blocks because
107
 * there are no status changes to report.
108
 * Until the thread running SCardGetStatusChange unblocks, another thread in P1 trying to
109
 * perform an operation using the context hCtx (or the card hCard) will also be blocked.
110
 *
111
 * Example two
112
 *
113
 * The example below shows how transaction control ensures that operations meant to be
114
 * performed without interruption can do so safely within a transaction.
115
 *
116
 * In this example, there are two different processes running; P1 and P2.
117
 * P1 calls SCardEstablishContext, which returns the context hCtx1.
118
 * P2 calls SCardEstablishContext, which returns the context hCtx2.
119
 * P1 calls SCardConnect (with the hCtx1 context) which returns a handle to the card, hCard1.
120
 * P2 calls SCardConnect (with the hCtx2 context) which returns a handle to the same card, hCard2.
121
 * P1 calls SCardBeginTransaction (with the hCard 1 context).
122
 * Until P1 calls SCardEndTransaction (with the hCard1 context),
123
 * any operation using hCard2 will be blocked.
124
 * Once an operation using hCard2 is blocked and until it's returning,
125
 * any operation using hCtx2 (and hCard2) will also be blocked.
126
 */
127
128
//#define DISABLE_PCSC_SCARD_AUTOALLOCATE
129
#include "smartcard_pcsc.h"
130
131
0
#define PCSC_SCARD_PCI_T0 (&g_PCSC_rgSCardT0Pci)
132
0
#define PCSC_SCARD_PCI_T1 (&g_PCSC_rgSCardT1Pci)
133
0
#define PCSC_SCARD_PCI_RAW (&g_PCSC_rgSCardRawPci)
134
135
typedef PCSC_LONG (*fnPCSCSCardEstablishContext)(PCSC_DWORD dwScope, LPCVOID pvReserved1,
136
                                                 LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
137
typedef PCSC_LONG (*fnPCSCSCardReleaseContext)(SCARDCONTEXT hContext);
138
typedef PCSC_LONG (*fnPCSCSCardIsValidContext)(SCARDCONTEXT hContext);
139
typedef PCSC_LONG (*fnPCSCSCardConnect)(SCARDCONTEXT hContext, LPCSTR szReader,
140
                                        PCSC_DWORD dwShareMode, PCSC_DWORD dwPreferredProtocols,
141
                                        LPSCARDHANDLE phCard, PCSC_LPDWORD pdwActiveProtocol);
142
typedef PCSC_LONG (*fnPCSCSCardReconnect)(SCARDHANDLE hCard, PCSC_DWORD dwShareMode,
143
                                          PCSC_DWORD dwPreferredProtocols,
144
                                          PCSC_DWORD dwInitialization,
145
                                          PCSC_LPDWORD pdwActiveProtocol);
146
typedef PCSC_LONG (*fnPCSCSCardDisconnect)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
147
typedef PCSC_LONG (*fnPCSCSCardBeginTransaction)(SCARDHANDLE hCard);
148
typedef PCSC_LONG (*fnPCSCSCardEndTransaction)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
149
typedef PCSC_LONG (*fnPCSCSCardStatus)(SCARDHANDLE hCard, LPSTR mszReaderName,
150
                                       PCSC_LPDWORD pcchReaderLen, PCSC_LPDWORD pdwState,
151
                                       PCSC_LPDWORD pdwProtocol, LPBYTE pbAtr,
152
                                       PCSC_LPDWORD pcbAtrLen);
153
typedef PCSC_LONG (*fnPCSCSCardGetStatusChange)(SCARDCONTEXT hContext, PCSC_DWORD dwTimeout,
154
                                                PCSC_SCARD_READERSTATE* rgReaderStates,
155
                                                PCSC_DWORD cReaders);
156
typedef PCSC_LONG (*fnPCSCSCardControl)(SCARDHANDLE hCard, PCSC_DWORD dwControlCode,
157
                                        LPCVOID pbSendBuffer, PCSC_DWORD cbSendLength,
158
                                        LPVOID pbRecvBuffer, PCSC_DWORD cbRecvLength,
159
                                        PCSC_LPDWORD lpBytesReturned);
160
typedef PCSC_LONG (*fnPCSCSCardTransmit)(SCARDHANDLE hCard, const PCSC_SCARD_IO_REQUEST* pioSendPci,
161
                                         LPCBYTE pbSendBuffer, PCSC_DWORD cbSendLength,
162
                                         PCSC_SCARD_IO_REQUEST* pioRecvPci, LPBYTE pbRecvBuffer,
163
                                         PCSC_LPDWORD pcbRecvLength);
164
typedef PCSC_LONG (*fnPCSCSCardListReaderGroups)(SCARDCONTEXT hContext, LPSTR mszGroups,
165
                                                 PCSC_LPDWORD pcchGroups);
166
typedef PCSC_LONG (*fnPCSCSCardListReaders)(SCARDCONTEXT hContext, LPCSTR mszGroups,
167
                                            LPSTR mszReaders, PCSC_LPDWORD pcchReaders);
168
typedef PCSC_LONG (*fnPCSCSCardFreeMemory)(SCARDCONTEXT hContext, LPCVOID pvMem);
169
typedef PCSC_LONG (*fnPCSCSCardCancel)(SCARDCONTEXT hContext);
170
typedef PCSC_LONG (*fnPCSCSCardGetAttrib)(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPBYTE pbAttr,
171
                                          PCSC_LPDWORD pcbAttrLen);
172
typedef PCSC_LONG (*fnPCSCSCardSetAttrib)(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPCBYTE pbAttr,
173
                                          PCSC_DWORD cbAttrLen);
174
175
typedef struct
176
{
177
  WINPR_ATTR_NODISCARD fnPCSCSCardEstablishContext pfnSCardEstablishContext;
178
  WINPR_ATTR_NODISCARD fnPCSCSCardReleaseContext pfnSCardReleaseContext;
179
  WINPR_ATTR_NODISCARD fnPCSCSCardIsValidContext pfnSCardIsValidContext;
180
  WINPR_ATTR_NODISCARD fnPCSCSCardConnect pfnSCardConnect;
181
  WINPR_ATTR_NODISCARD fnPCSCSCardReconnect pfnSCardReconnect;
182
  WINPR_ATTR_NODISCARD fnPCSCSCardDisconnect pfnSCardDisconnect;
183
  WINPR_ATTR_NODISCARD fnPCSCSCardBeginTransaction pfnSCardBeginTransaction;
184
  WINPR_ATTR_NODISCARD fnPCSCSCardEndTransaction pfnSCardEndTransaction;
185
  WINPR_ATTR_NODISCARD fnPCSCSCardStatus pfnSCardStatus;
186
  WINPR_ATTR_NODISCARD fnPCSCSCardGetStatusChange pfnSCardGetStatusChange;
187
  WINPR_ATTR_NODISCARD fnPCSCSCardControl pfnSCardControl;
188
  WINPR_ATTR_NODISCARD fnPCSCSCardTransmit pfnSCardTransmit;
189
  WINPR_ATTR_NODISCARD fnPCSCSCardListReaderGroups pfnSCardListReaderGroups;
190
  WINPR_ATTR_NODISCARD fnPCSCSCardListReaders pfnSCardListReaders;
191
  fnPCSCSCardFreeMemory pfnSCardFreeMemory;
192
  fnPCSCSCardCancel pfnSCardCancel;
193
  WINPR_ATTR_NODISCARD fnPCSCSCardGetAttrib pfnSCardGetAttrib;
194
  WINPR_ATTR_NODISCARD fnPCSCSCardSetAttrib pfnSCardSetAttrib;
195
} PCSCFunctionTable;
196
197
typedef struct
198
{
199
  DWORD len;
200
  DWORD freshness;
201
  BYTE* data;
202
} PCSC_CACHE_ITEM;
203
204
typedef struct
205
{
206
  SCARDHANDLE owner;
207
  CRITICAL_SECTION lock;
208
  SCARDCONTEXT hContext;
209
  DWORD dwCardHandleCount;
210
  BOOL isTransactionLocked;
211
  wHashTable* cache;
212
} PCSC_SCARDCONTEXT;
213
214
typedef struct
215
{
216
  BOOL shared;
217
  SCARDCONTEXT hSharedContext;
218
} PCSC_SCARDHANDLE;
219
220
static HMODULE g_PCSCModule = nullptr;
221
static PCSCFunctionTable g_PCSC = WINPR_C_ARRAY_INIT;
222
223
static HANDLE g_StartedEvent = nullptr;
224
static int g_StartedEventRefCount = 0;
225
226
static BOOL g_SCardAutoAllocate = FALSE;
227
static BOOL g_PnP_Notification = TRUE;
228
229
#ifdef __MACOSX__
230
static unsigned int OSXVersion = 0;
231
#endif
232
233
static wListDictionary* g_CardHandles = nullptr;
234
static wListDictionary* g_CardContexts = nullptr;
235
static wListDictionary* g_MemoryBlocks = nullptr;
236
static INIT_ONCE g_CardHandleInitializer = INIT_ONCE_STATIC_INIT;
237
238
static const char SMARTCARD_PNP_NOTIFICATION_A[] = "\\\\?PnP?\\Notification";
239
240
static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT0Pci = { SCARD_PROTOCOL_T0,
241
                                                         sizeof(PCSC_SCARD_IO_REQUEST) };
242
static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT1Pci = { SCARD_PROTOCOL_T1,
243
                                                         sizeof(PCSC_SCARD_IO_REQUEST) };
244
static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardRawPci = { PCSC_SCARD_PROTOCOL_RAW,
245
                                                          sizeof(PCSC_SCARD_IO_REQUEST) };
246
247
static void clearHandles(void)
248
0
{
249
0
  ListDictionary_Free(g_CardHandles);
250
0
  ListDictionary_Free(g_CardContexts);
251
0
  ListDictionary_Free(g_MemoryBlocks);
252
253
0
  g_CardHandles = nullptr;
254
0
  g_CardContexts = nullptr;
255
0
  g_MemoryBlocks = nullptr;
256
0
}
257
258
WINPR_ATTR_NODISCARD
259
static BOOL initializeHandles(WINPR_ATTR_UNUSED PINIT_ONCE InitOnce,
260
                              WINPR_ATTR_UNUSED PVOID Parameter, WINPR_ATTR_UNUSED PVOID* Context)
261
0
{
262
0
  g_CardHandles = ListDictionary_New(TRUE);
263
0
  g_CardContexts = ListDictionary_New(TRUE);
264
0
  g_MemoryBlocks = ListDictionary_New(TRUE);
265
0
  (void)atexit(clearHandles);
266
0
  return g_CardHandles && g_CardContexts && g_MemoryBlocks;
267
0
}
268
269
WINPR_ATTR_NODISCARD
270
static BOOL init(void)
271
0
{
272
0
  return InitOnceExecuteOnce(&g_CardHandleInitializer, initializeHandles, nullptr, nullptr);
273
0
}
274
275
static LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPVOID pvMem);
276
277
WINPR_ATTR_NODISCARD
278
static LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope, LPCVOID pvReserved1,
279
                                                       LPCVOID pvReserved2,
280
                                                       LPSCARDCONTEXT phContext);
281
282
WINPR_ATTR_NODISCARD
283
static LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext);
284
285
WINPR_ATTR_NODISCARD
286
static LONG PCSC_SCard_LogError(const char* what)
287
0
{
288
0
  WLog_WARN(TAG, "Missing function pointer %s=nullptr", what);
289
0
  return SCARD_E_UNSUPPORTED_FEATURE;
290
0
}
291
292
WINPR_ATTR_NODISCARD
293
static LONG PCSC_MapErrorCodeToWinSCard(PCSC_LONG errorCode)
294
0
{
295
  /**
296
   * pcsc-lite returns SCARD_E_UNEXPECTED when it
297
   * should return SCARD_E_UNSUPPORTED_FEATURE.
298
   *
299
   * Additionally, the pcsc-lite headers incorrectly
300
   * define SCARD_E_UNSUPPORTED_FEATURE to 0x8010001F,
301
   * when the real value should be 0x80100022.
302
   */
303
0
  if (errorCode != SCARD_S_SUCCESS)
304
0
  {
305
0
    if (errorCode == SCARD_E_UNEXPECTED)
306
0
      errorCode = SCARD_E_UNSUPPORTED_FEATURE;
307
0
  }
308
309
0
  return (LONG)errorCode;
310
0
}
311
312
WINPR_ATTR_NODISCARD
313
static DWORD PCSC_ConvertCardStateToWinSCard(DWORD dwCardState, PCSC_LONG status)
314
0
{
315
  /**
316
   * pcsc-lite's SCardStatus returns a bit-field, not an enumerated value.
317
   *
318
   *         State             WinSCard           pcsc-lite
319
   *
320
   *      SCARD_UNKNOWN           0                0x0001
321
   *      SCARD_ABSENT            1                0x0002
322
   *      SCARD_PRESENT           2                0x0004
323
   *      SCARD_SWALLOWED         3                0x0008
324
   *      SCARD_POWERED           4                0x0010
325
   *      SCARD_NEGOTIABLE        5                0x0020
326
   *      SCARD_SPECIFIC          6                0x0040
327
   *
328
   * pcsc-lite also never sets SCARD_SPECIFIC,
329
   * which is expected by some windows applications.
330
   */
331
0
  if (status == SCARD_S_SUCCESS)
332
0
  {
333
0
    if ((dwCardState & PCSC_SCARD_NEGOTIABLE) || (dwCardState & PCSC_SCARD_SPECIFIC))
334
0
      return SCARD_SPECIFIC;
335
0
  }
336
337
0
  if (dwCardState & PCSC_SCARD_POWERED)
338
0
    return SCARD_POWERED;
339
340
0
  if (dwCardState & PCSC_SCARD_NEGOTIABLE)
341
0
    return SCARD_NEGOTIABLE;
342
343
0
  if (dwCardState & PCSC_SCARD_SPECIFIC)
344
0
    return SCARD_SPECIFIC;
345
346
0
  if (dwCardState & PCSC_SCARD_ABSENT)
347
0
    return SCARD_ABSENT;
348
349
0
  if (dwCardState & PCSC_SCARD_PRESENT)
350
0
    return SCARD_PRESENT;
351
352
0
  if (dwCardState & PCSC_SCARD_SWALLOWED)
353
0
    return SCARD_SWALLOWED;
354
355
0
  if (dwCardState & PCSC_SCARD_UNKNOWN)
356
0
    return SCARD_UNKNOWN;
357
358
0
  return SCARD_UNKNOWN;
359
0
}
360
361
WINPR_ATTR_NODISCARD
362
static DWORD PCSC_ConvertProtocolsToWinSCard(PCSC_DWORD dwProtocols)
363
0
{
364
  /**
365
   * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW,
366
   * and also has SCARD_PROTOCOL_T15 which is not in WinSCard.
367
   */
368
0
  if (dwProtocols & PCSC_SCARD_PROTOCOL_RAW)
369
0
  {
370
0
    dwProtocols &= ~PCSC_SCARD_PROTOCOL_RAW;
371
0
    dwProtocols |= SCARD_PROTOCOL_RAW;
372
0
  }
373
374
0
  if (dwProtocols & PCSC_SCARD_PROTOCOL_T15)
375
0
  {
376
0
    dwProtocols &= ~PCSC_SCARD_PROTOCOL_T15;
377
0
  }
378
379
0
  return (DWORD)dwProtocols;
380
0
}
381
382
WINPR_ATTR_NODISCARD
383
static DWORD PCSC_ConvertProtocolsFromWinSCard(DWORD dwProtocols)
384
0
{
385
  /**
386
   * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW,
387
   * and it does not define WinSCard's SCARD_PROTOCOL_DEFAULT.
388
   */
389
0
  if (dwProtocols & SCARD_PROTOCOL_RAW)
390
0
  {
391
0
    dwProtocols &= ~SCARD_PROTOCOL_RAW;
392
0
    dwProtocols |= PCSC_SCARD_PROTOCOL_RAW;
393
0
  }
394
395
0
  if (dwProtocols & SCARD_PROTOCOL_DEFAULT)
396
0
  {
397
0
    dwProtocols &= ~SCARD_PROTOCOL_DEFAULT;
398
0
  }
399
400
0
  if (dwProtocols == SCARD_PROTOCOL_UNDEFINED)
401
0
  {
402
0
    dwProtocols = SCARD_PROTOCOL_Tx;
403
0
  }
404
405
0
  return dwProtocols;
406
0
}
407
408
WINPR_ATTR_NODISCARD
409
static PCSC_SCARDCONTEXT* PCSC_GetCardContextData(SCARDCONTEXT hContext)
410
0
{
411
0
  if (!init())
412
0
    return nullptr;
413
414
0
  PCSC_SCARDCONTEXT* pContext =
415
0
      (PCSC_SCARDCONTEXT*)ListDictionary_GetItemValue(g_CardContexts, (void*)hContext);
416
417
0
  if (!pContext)
418
0
    return nullptr;
419
420
0
  return pContext;
421
0
}
422
423
static void pcsc_cache_item_free(void* ptr)
424
0
{
425
0
  PCSC_CACHE_ITEM* data = ptr;
426
0
  if (data)
427
0
    free(data->data);
428
0
  free(data);
429
0
}
430
431
static PCSC_SCARDCONTEXT* PCSC_EstablishCardContext(SCARDCONTEXT hContext)
432
0
{
433
0
  if (!init())
434
0
    return nullptr;
435
436
0
  PCSC_SCARDCONTEXT* pContext = (PCSC_SCARDCONTEXT*)calloc(1, sizeof(PCSC_SCARDCONTEXT));
437
438
0
  if (!pContext)
439
0
    return nullptr;
440
441
0
  pContext->hContext = hContext;
442
443
0
  if (!InitializeCriticalSectionAndSpinCount(&(pContext->lock), 4000))
444
0
    goto error_spinlock;
445
446
0
  pContext->cache = HashTable_New(FALSE);
447
0
  if (!pContext->cache)
448
0
    goto errors;
449
0
  if (!HashTable_SetupForStringData(pContext->cache, FALSE))
450
0
    goto errors;
451
0
  {
452
0
    wObject* obj = HashTable_ValueObject(pContext->cache);
453
0
    obj->fnObjectFree = pcsc_cache_item_free;
454
0
  }
455
456
0
  if (!ListDictionary_Add(g_CardContexts, (void*)hContext, (void*)pContext))
457
0
    goto errors;
458
459
0
  return pContext;
460
0
errors:
461
0
  HashTable_Free(pContext->cache);
462
0
  DeleteCriticalSection(&(pContext->lock));
463
0
error_spinlock:
464
0
  free(pContext);
465
0
  return nullptr;
466
0
}
467
468
static void PCSC_ReleaseCardContext(SCARDCONTEXT hContext)
469
0
{
470
0
  PCSC_SCARDCONTEXT* pContext = PCSC_GetCardContextData(hContext);
471
472
0
  if (!pContext)
473
0
  {
474
0
    WLog_ERR(TAG, "PCSC_ReleaseCardContext: null pContext!");
475
0
    return;
476
0
  }
477
478
0
  DeleteCriticalSection(&(pContext->lock));
479
0
  HashTable_Free(pContext->cache);
480
0
  free(pContext);
481
482
0
  if (init())
483
0
    ListDictionary_Remove(g_CardContexts, (void*)hContext);
484
0
}
485
486
WINPR_ATTR_NODISCARD
487
static BOOL PCSC_LockCardContext(SCARDCONTEXT hContext)
488
0
{
489
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
490
0
  pContext = PCSC_GetCardContextData(hContext);
491
492
0
  if (!pContext)
493
0
  {
494
0
    WLog_ERR(TAG, "PCSC_LockCardContext: invalid context (%p)", (void*)hContext);
495
0
    return FALSE;
496
0
  }
497
498
0
  EnterCriticalSection(&(pContext->lock));
499
0
  return TRUE;
500
0
}
501
502
WINPR_ATTR_NODISCARD
503
static BOOL PCSC_UnlockCardContext(SCARDCONTEXT hContext)
504
0
{
505
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
506
0
  pContext = PCSC_GetCardContextData(hContext);
507
508
0
  if (!pContext)
509
0
  {
510
0
    WLog_ERR(TAG, "PCSC_UnlockCardContext: invalid context (%p)", (void*)hContext);
511
0
    return FALSE;
512
0
  }
513
514
0
  LeaveCriticalSection(&(pContext->lock));
515
0
  return TRUE;
516
0
}
517
518
WINPR_ATTR_NODISCARD
519
static PCSC_SCARDHANDLE* PCSC_GetCardHandleData(SCARDHANDLE hCard)
520
0
{
521
0
  if (!init())
522
0
    return nullptr;
523
524
0
  PCSC_SCARDHANDLE* pCard =
525
0
      (PCSC_SCARDHANDLE*)ListDictionary_GetItemValue(g_CardHandles, (void*)hCard);
526
527
0
  if (!pCard)
528
0
    return nullptr;
529
530
0
  return pCard;
531
0
}
532
533
WINPR_ATTR_NODISCARD
534
static SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard)
535
0
{
536
0
  PCSC_SCARDHANDLE* pCard = nullptr;
537
0
  pCard = PCSC_GetCardHandleData(hCard);
538
539
0
  if (!pCard)
540
0
    return 0;
541
542
0
  return pCard->hSharedContext;
543
0
}
544
545
static BOOL PCSC_WaitForCardAccess(SCARDCONTEXT hContext, SCARDHANDLE hCard, BOOL shared)
546
0
{
547
0
  BOOL status = TRUE;
548
0
  PCSC_SCARDHANDLE* pCard = nullptr;
549
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
550
551
0
  if (!hCard)
552
0
  {
553
    /* SCardConnect */
554
0
    pContext = PCSC_GetCardContextData(hContext);
555
556
0
    if (!pContext)
557
0
      return FALSE;
558
559
0
    if (!pContext->owner)
560
0
      return TRUE;
561
562
    /* wait for card ownership */
563
0
    return TRUE;
564
0
  }
565
566
0
  pCard = PCSC_GetCardHandleData(hCard);
567
568
0
  if (!pCard)
569
0
    return FALSE;
570
571
0
  shared = pCard->shared;
572
0
  hContext = pCard->hSharedContext;
573
0
  pContext = PCSC_GetCardContextData(hContext);
574
575
0
  if (!pContext)
576
0
    return FALSE;
577
578
0
  if (!pContext->owner)
579
0
  {
580
    /* card is not owned */
581
0
    if (!shared)
582
0
      pContext->owner = hCard;
583
584
0
    return TRUE;
585
0
  }
586
587
0
  if (pContext->owner == hCard)
588
0
  {
589
    /* already card owner */
590
0
  }
591
0
  else
592
0
  {
593
    /* wait for card ownership */
594
0
  }
595
596
0
  return status;
597
0
}
598
599
static BOOL PCSC_ReleaseCardAccess(SCARDCONTEXT hContext, SCARDHANDLE hCard)
600
0
{
601
0
  PCSC_SCARDHANDLE* pCard = nullptr;
602
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
603
604
0
  if (!hCard)
605
0
  {
606
    /* release current owner */
607
0
    pContext = PCSC_GetCardContextData(hContext);
608
609
0
    if (!pContext)
610
0
      return FALSE;
611
612
0
    hCard = pContext->owner;
613
614
0
    if (!hCard)
615
0
      return TRUE;
616
617
0
    pCard = PCSC_GetCardHandleData(hCard);
618
619
0
    if (!pCard)
620
0
      return FALSE;
621
622
    /* release card ownership */
623
0
    pContext->owner = 0;
624
0
    return TRUE;
625
0
  }
626
627
0
  pCard = PCSC_GetCardHandleData(hCard);
628
629
0
  if (!pCard)
630
0
    return FALSE;
631
632
0
  hContext = pCard->hSharedContext;
633
0
  pContext = PCSC_GetCardContextData(hContext);
634
635
0
  if (!pContext)
636
0
    return FALSE;
637
638
0
  if (pContext->owner == hCard)
639
0
  {
640
    /* release card ownership */
641
0
    pContext->owner = 0;
642
0
  }
643
644
0
  return TRUE;
645
0
}
646
647
static void PCSC_DisconnectCardHandle(PCSC_SCARDHANDLE* pCard)
648
0
{
649
0
  if (!pCard)
650
0
    return;
651
652
0
  PCSC_SCARDCONTEXT* pContext = PCSC_GetCardContextData(pCard->hSharedContext);
653
0
  if (init())
654
0
    ListDictionary_Remove(g_CardHandles, (void*)pCard);
655
0
  free(pCard);
656
657
0
  if (!pContext)
658
0
  {
659
0
    WLog_ERR(TAG, "PCSC_DisconnectCardHandle: null pContext!");
660
0
    return;
661
0
  }
662
663
0
  pContext->dwCardHandleCount--;
664
0
}
665
666
WINPR_ATTR_MALLOC(PCSC_DisconnectCardHandle, 1)
667
static PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDHANDLE hCard)
668
0
{
669
0
  if (!init())
670
0
    return nullptr;
671
672
0
  PCSC_SCARDCONTEXT* pContext = PCSC_GetCardContextData(hSharedContext);
673
674
0
  if (!pContext)
675
0
  {
676
0
    WLog_ERR(TAG, "PCSC_ConnectCardHandle: null pContext!");
677
0
    return nullptr;
678
0
  }
679
680
0
  PCSC_SCARDHANDLE* pCard = (PCSC_SCARDHANDLE*)calloc(1, sizeof(PCSC_SCARDHANDLE));
681
682
0
  if (!pCard)
683
0
    return nullptr;
684
685
0
  pCard->hSharedContext = hSharedContext;
686
687
0
  if (!ListDictionary_Add(g_CardHandles, (void*)hCard, (void*)pCard))
688
0
    goto error;
689
690
0
  pContext->dwCardHandleCount++;
691
0
  return pCard;
692
0
error:
693
0
  free(pCard);
694
0
  return nullptr;
695
0
}
696
697
static BOOL PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem)
698
0
{
699
0
  if (!init())
700
0
    return FALSE;
701
0
  return ListDictionary_Add(g_MemoryBlocks, pvMem, (void*)hContext);
702
0
}
703
704
WINPR_ATTR_NODISCARD
705
static void* PCSC_RemoveMemoryBlock(SCARDCONTEXT hContext, void* pvMem)
706
0
{
707
0
  WINPR_UNUSED(hContext);
708
709
0
  if (!init())
710
0
    return nullptr;
711
712
0
  return ListDictionary_Take(g_MemoryBlocks, pvMem);
713
0
}
714
715
/**
716
 * Standard Windows Smart Card API (PCSC)
717
 */
718
WINPR_ATTR_NODISCARD
719
static LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope, LPCVOID pvReserved1,
720
                                                       LPCVOID pvReserved2,
721
                                                       LPSCARDCONTEXT phContext)
722
0
{
723
0
  WINPR_UNUSED(dwScope); /* SCARD_SCOPE_SYSTEM is the only scope supported by pcsc-lite */
724
0
  PCSC_LONG status = SCARD_S_SUCCESS;
725
726
0
  if (!g_PCSC.pfnSCardEstablishContext)
727
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardEstablishContext");
728
729
0
  status =
730
0
      g_PCSC.pfnSCardEstablishContext(SCARD_SCOPE_SYSTEM, pvReserved1, pvReserved2, phContext);
731
0
  return PCSC_MapErrorCodeToWinSCard(status);
732
0
}
733
734
WINPR_ATTR_NODISCARD
735
static LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
736
                                              LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
737
0
{
738
0
  LONG status = 0;
739
740
0
  status = PCSC_SCardEstablishContext_Internal(dwScope, pvReserved1, pvReserved2, phContext);
741
742
0
  if (status == SCARD_S_SUCCESS)
743
0
    PCSC_EstablishCardContext(*phContext);
744
745
0
  return status;
746
0
}
747
748
WINPR_ATTR_NODISCARD
749
static LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext)
750
0
{
751
0
  PCSC_LONG status = SCARD_S_SUCCESS;
752
753
0
  if (!g_PCSC.pfnSCardReleaseContext)
754
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardReleaseContext");
755
756
0
  if (!hContext)
757
0
  {
758
0
    WLog_ERR(TAG, "SCardReleaseContext: null hContext");
759
0
    return PCSC_MapErrorCodeToWinSCard(SCARD_E_INVALID_HANDLE);
760
0
  }
761
762
0
  status = g_PCSC.pfnSCardReleaseContext(hContext);
763
0
  return PCSC_MapErrorCodeToWinSCard(status);
764
0
}
765
766
WINPR_ATTR_NODISCARD
767
static LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
768
0
{
769
0
  LONG status = SCARD_S_SUCCESS;
770
771
0
  status = PCSC_SCardReleaseContext_Internal(hContext);
772
0
  PCSC_ReleaseCardContext(hContext);
773
774
0
  return status;
775
0
}
776
777
WINPR_ATTR_NODISCARD
778
static LONG WINAPI PCSC_SCardIsValidContext(SCARDCONTEXT hContext)
779
0
{
780
0
  PCSC_LONG status = SCARD_S_SUCCESS;
781
782
0
  if (!g_PCSC.pfnSCardIsValidContext)
783
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardIsValidContext");
784
785
0
  status = g_PCSC.pfnSCardIsValidContext(hContext);
786
0
  return PCSC_MapErrorCodeToWinSCard(status);
787
0
}
788
789
WINPR_ATTR_NODISCARD
790
static LONG WINAPI PCSC_SCardListReaderGroups_Internal(SCARDCONTEXT hContext, LPSTR mszGroups,
791
                                                       LPDWORD pcchGroups)
792
0
{
793
0
  PCSC_LONG status = SCARD_S_SUCCESS;
794
0
  BOOL pcchGroupsAlloc = FALSE;
795
0
  PCSC_DWORD pcsc_cchGroups = 0;
796
797
0
  if (!pcchGroups)
798
0
    return SCARD_E_INVALID_PARAMETER;
799
800
0
  if (!g_PCSC.pfnSCardListReaderGroups)
801
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
802
803
0
  if (*pcchGroups == SCARD_AUTOALLOCATE)
804
0
    pcchGroupsAlloc = TRUE;
805
806
0
  pcsc_cchGroups = pcchGroupsAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcchGroups;
807
808
0
  if (pcchGroupsAlloc && !g_SCardAutoAllocate)
809
0
  {
810
0
    pcsc_cchGroups = 0;
811
0
    status = g_PCSC.pfnSCardListReaderGroups(hContext, nullptr, &pcsc_cchGroups);
812
813
0
    if (status == SCARD_S_SUCCESS)
814
0
    {
815
0
      LPSTR tmp = calloc(1, pcsc_cchGroups);
816
817
0
      if (!tmp)
818
0
        return SCARD_E_NO_MEMORY;
819
820
0
      status = g_PCSC.pfnSCardListReaderGroups(hContext, tmp, &pcsc_cchGroups);
821
822
0
      if (status != SCARD_S_SUCCESS)
823
0
      {
824
0
        free(tmp);
825
0
        tmp = nullptr;
826
0
      }
827
0
      else
828
0
        PCSC_AddMemoryBlock(hContext, tmp);
829
830
0
      *(LPSTR*)mszGroups = tmp;
831
0
    }
832
0
  }
833
0
  else
834
0
  {
835
0
    status = g_PCSC.pfnSCardListReaderGroups(hContext, mszGroups, &pcsc_cchGroups);
836
0
  }
837
838
0
  *pcchGroups = (DWORD)pcsc_cchGroups;
839
0
  return PCSC_MapErrorCodeToWinSCard(status);
840
0
}
841
842
WINPR_ATTR_NODISCARD
843
static LONG WINAPI PCSC_SCardListReaderGroupsA(SCARDCONTEXT hContext, LPSTR mszGroups,
844
                                               LPDWORD pcchGroups)
845
0
{
846
0
  LONG status = SCARD_S_SUCCESS;
847
848
0
  if (!g_PCSC.pfnSCardListReaderGroups)
849
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
850
851
0
  if (!PCSC_LockCardContext(hContext))
852
0
    return SCARD_E_INVALID_HANDLE;
853
854
0
  status = PCSC_SCardListReaderGroups_Internal(hContext, mszGroups, pcchGroups);
855
856
0
  if (!PCSC_UnlockCardContext(hContext))
857
0
    return SCARD_E_INVALID_HANDLE;
858
859
0
  return status;
860
0
}
861
862
WINPR_ATTR_NODISCARD
863
static LONG WINAPI PCSC_SCardListReaderGroupsW(SCARDCONTEXT hContext, LPWSTR mszGroups,
864
                                               LPDWORD pcchGroups)
865
0
{
866
0
  LPSTR mszGroupsA = nullptr;
867
0
  LPSTR* pMszGroupsA = &mszGroupsA;
868
0
  LONG status = SCARD_S_SUCCESS;
869
870
0
  if (!g_PCSC.pfnSCardListReaderGroups)
871
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
872
873
0
  if (!PCSC_LockCardContext(hContext))
874
0
    return SCARD_E_INVALID_HANDLE;
875
876
0
  status = PCSC_SCardListReaderGroups_Internal(hContext, (LPSTR)&mszGroupsA, pcchGroups);
877
878
0
  if (status == SCARD_S_SUCCESS)
879
0
  {
880
0
    size_t size = 0;
881
0
    WCHAR* str = ConvertMszUtf8NToWCharAlloc(*pMszGroupsA, *pcchGroups, &size);
882
0
    if (!str)
883
0
      return SCARD_E_NO_MEMORY;
884
0
    *(WCHAR**)mszGroups = str;
885
0
    *pcchGroups = (DWORD)size;
886
0
    PCSC_AddMemoryBlock(hContext, str);
887
0
    PCSC_SCardFreeMemory_Internal(hContext, *pMszGroupsA);
888
0
  }
889
890
0
  if (!PCSC_UnlockCardContext(hContext))
891
0
    return SCARD_E_INVALID_HANDLE;
892
893
0
  return status;
894
0
}
895
896
WINPR_ATTR_NODISCARD
897
static LONG WINAPI PCSC_SCardListReaders_Internal(SCARDCONTEXT hContext, LPCSTR mszGroups,
898
                                                  LPSTR mszReaders, LPDWORD pcchReaders)
899
0
{
900
0
  PCSC_LONG status = SCARD_S_SUCCESS;
901
0
  BOOL pcchReadersAlloc = FALSE;
902
0
  PCSC_DWORD pcsc_cchReaders = 0;
903
0
  if (!pcchReaders)
904
0
    return SCARD_E_INVALID_PARAMETER;
905
906
0
  if (!g_PCSC.pfnSCardListReaders)
907
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
908
909
0
  mszGroups = nullptr; /* mszGroups is not supported by pcsc-lite */
910
911
0
  if (*pcchReaders == SCARD_AUTOALLOCATE)
912
0
    pcchReadersAlloc = TRUE;
913
914
0
  pcsc_cchReaders = pcchReadersAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcchReaders;
915
916
0
  if (pcchReadersAlloc && !g_SCardAutoAllocate)
917
0
  {
918
0
    pcsc_cchReaders = 0;
919
0
    status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, nullptr, &pcsc_cchReaders);
920
921
0
    if (status == SCARD_S_SUCCESS)
922
0
    {
923
0
      char* tmp = calloc(1, pcsc_cchReaders);
924
925
0
      if (!tmp)
926
0
        return SCARD_E_NO_MEMORY;
927
928
0
      status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, tmp, &pcsc_cchReaders);
929
930
0
      if (status != SCARD_S_SUCCESS)
931
0
      {
932
0
        free(tmp);
933
0
        tmp = nullptr;
934
0
      }
935
0
      else
936
0
        PCSC_AddMemoryBlock(hContext, tmp);
937
938
0
      *(char**)mszReaders = tmp;
939
0
    }
940
0
  }
941
0
  else
942
0
  {
943
0
    status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, mszReaders, &pcsc_cchReaders);
944
0
  }
945
946
0
  *pcchReaders = (DWORD)pcsc_cchReaders;
947
0
  return PCSC_MapErrorCodeToWinSCard(status);
948
0
}
949
950
WINPR_ATTR_NODISCARD
951
static LONG WINAPI PCSC_SCardListReadersA(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders,
952
                                          LPDWORD pcchReaders)
953
0
{
954
0
  BOOL nullCardContext = FALSE;
955
0
  LONG status = SCARD_S_SUCCESS;
956
957
0
  if (!g_PCSC.pfnSCardListReaders)
958
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
959
960
0
  if (!hContext)
961
0
  {
962
0
    status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, nullptr, nullptr, &hContext);
963
964
0
    if (status != SCARD_S_SUCCESS)
965
0
      return status;
966
967
0
    nullCardContext = TRUE;
968
0
  }
969
970
0
  if (!PCSC_LockCardContext(hContext))
971
0
    return SCARD_E_INVALID_HANDLE;
972
973
0
  status = PCSC_SCardListReaders_Internal(hContext, mszGroups, mszReaders, pcchReaders);
974
975
0
  if (!PCSC_UnlockCardContext(hContext))
976
0
    return SCARD_E_INVALID_HANDLE;
977
978
0
  if (nullCardContext)
979
0
  {
980
0
    status = PCSC_SCardReleaseContext(hContext);
981
0
  }
982
983
0
  return status;
984
0
}
985
986
WINPR_ATTR_NODISCARD
987
static LONG WINAPI PCSC_SCardListReadersW(SCARDCONTEXT hContext, LPCWSTR mszGroups,
988
                                          LPWSTR mszReaders, LPDWORD pcchReaders)
989
0
{
990
0
  LPSTR mszGroupsA = nullptr;
991
0
  LPSTR mszReadersA = nullptr;
992
0
  LONG status = SCARD_S_SUCCESS;
993
0
  BOOL nullCardContext = FALSE;
994
995
0
  if (!g_PCSC.pfnSCardListReaders)
996
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
997
998
0
  if (!hContext)
999
0
  {
1000
0
    status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, nullptr, nullptr, &hContext);
1001
1002
0
    if (status != SCARD_S_SUCCESS)
1003
0
      return status;
1004
1005
0
    nullCardContext = TRUE;
1006
0
  }
1007
1008
0
  if (!PCSC_LockCardContext(hContext))
1009
0
    return SCARD_E_INVALID_HANDLE;
1010
1011
0
  if (mszGroups)
1012
0
  {
1013
0
    mszGroupsA = ConvertWCharToUtf8Alloc(mszGroups, nullptr);
1014
0
    if (!mszGroupsA)
1015
0
      return SCARD_E_NO_MEMORY;
1016
0
  }
1017
1018
0
  union
1019
0
  {
1020
0
    LPSTR* ppc;
1021
0
    LPSTR pc;
1022
0
  } cnv;
1023
0
  cnv.ppc = &mszReadersA;
1024
1025
0
  status = PCSC_SCardListReaders_Internal(hContext, mszGroupsA, cnv.pc, pcchReaders);
1026
0
  free(mszGroupsA);
1027
0
  if (status == SCARD_S_SUCCESS)
1028
0
  {
1029
0
    size_t size = 0;
1030
0
    WCHAR* str = ConvertMszUtf8NToWCharAlloc(mszReadersA, *pcchReaders, &size);
1031
0
    PCSC_SCardFreeMemory_Internal(hContext, mszReadersA);
1032
0
    if (!str || (size > UINT32_MAX))
1033
0
      return SCARD_E_NO_MEMORY;
1034
1035
0
    *(LPWSTR*)mszReaders = str;
1036
0
    *pcchReaders = (DWORD)size;
1037
0
    PCSC_AddMemoryBlock(hContext, str);
1038
0
  }
1039
1040
0
  if (!PCSC_UnlockCardContext(hContext))
1041
0
    return SCARD_E_INVALID_HANDLE;
1042
1043
0
  if (nullCardContext)
1044
0
  {
1045
0
    status = PCSC_SCardReleaseContext(hContext);
1046
0
  }
1047
1048
0
  return status;
1049
0
}
1050
1051
typedef struct
1052
{
1053
  BYTE atr[64];
1054
  size_t atrLen;
1055
  const char* cardName;
1056
} PcscKnownAtr;
1057
1058
static PcscKnownAtr knownAtrs[] = {
1059
  /* Yubico YubiKey 5 NFC (PKI) */
1060
  { { 0x3B, 0xFD, 0x13, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x15, 0x80, 0x73, 0xC0,
1061
      0x21, 0xC0, 0x57, 0x59, 0x75, 0x62, 0x69, 0x4B, 0x65, 0x79, 0x40 },
1062
    23,
1063
    "NIST SP 800-73 [PIV]" },
1064
  /* PIVKey C910 PKI Smart Card (eID) */
1065
  { { 0x3B, 0xFC, 0x18, 0x00, 0x00, 0x81, 0x31, 0x80, 0x45, 0x90, 0x67,
1066
      0x46, 0x4A, 0x00, 0x64, 0x16, 0x06, 0xF2, 0x72, 0x7E, 0x00, 0xE0 },
1067
    22,
1068
    "PIVKey Feitian (E0)" }
1069
};
1070
1071
#ifndef ARRAY_LENGTH
1072
0
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
1073
#endif
1074
1075
WINPR_ATTR_NODISCARD
1076
static const char* findCardByAtr(LPCBYTE pbAtr)
1077
0
{
1078
0
  for (size_t i = 0; i < ARRAY_LENGTH(knownAtrs); i++)
1079
0
  {
1080
0
    if (memcmp(knownAtrs[i].atr, pbAtr, knownAtrs[i].atrLen) == 0)
1081
0
      return knownAtrs[i].cardName;
1082
0
  }
1083
1084
0
  return nullptr;
1085
0
}
1086
1087
WINPR_ATTR_NODISCARD
1088
static LONG WINAPI PCSC_SCardListCardsA(WINPR_ATTR_UNUSED SCARDCONTEXT hContext, LPCBYTE pbAtr,
1089
                                        LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
1090
                                        CHAR* mszCards, LPDWORD pcchCards)
1091
0
{
1092
0
  const char* cardName = nullptr;
1093
0
  DWORD outputLen = 1;
1094
0
  CHAR* output = nullptr;
1095
0
  BOOL autoAllocate = 0;
1096
1097
0
  if (!pbAtr || rgquidInterfaces || cguidInterfaceCount)
1098
0
    return SCARD_E_UNSUPPORTED_FEATURE;
1099
1100
0
  if (!pcchCards)
1101
0
    return SCARD_E_INVALID_PARAMETER;
1102
1103
0
  autoAllocate = (*pcchCards == SCARD_AUTOALLOCATE);
1104
1105
0
  cardName = findCardByAtr(pbAtr);
1106
0
  if (cardName)
1107
0
    outputLen += strlen(cardName) + 1;
1108
1109
0
  *pcchCards = outputLen;
1110
0
  if (autoAllocate)
1111
0
  {
1112
0
    output = malloc(outputLen);
1113
0
    if (!output)
1114
0
      return SCARD_E_NO_MEMORY;
1115
1116
0
    *((LPSTR*)mszCards) = output;
1117
0
  }
1118
0
  else
1119
0
  {
1120
0
    if (!mszCards)
1121
0
      return SCARD_S_SUCCESS;
1122
1123
0
    if (*pcchCards < outputLen)
1124
0
      return SCARD_E_INSUFFICIENT_BUFFER;
1125
1126
0
    output = mszCards;
1127
0
  }
1128
1129
0
  if (cardName)
1130
0
  {
1131
0
    size_t toCopy = strlen(cardName) + 1;
1132
0
    memcpy(output, cardName, toCopy);
1133
0
    output += toCopy;
1134
0
  }
1135
1136
0
  *output = '\0';
1137
1138
0
  return SCARD_S_SUCCESS;
1139
0
}
1140
1141
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardListCardsW(
1142
    WINPR_ATTR_UNUSED SCARDCONTEXT hContext, LPCBYTE pbAtr, LPCGUID rgquidInterfaces,
1143
    DWORD cguidInterfaceCount, WCHAR* mszCards, LPDWORD pcchCards)
1144
0
{
1145
0
  const char* cardName = nullptr;
1146
0
  DWORD outputLen = 1;
1147
0
  WCHAR* output = nullptr;
1148
0
  BOOL autoAllocate = 0;
1149
1150
0
  if (!pbAtr || rgquidInterfaces || cguidInterfaceCount)
1151
0
    return SCARD_E_UNSUPPORTED_FEATURE;
1152
1153
0
  if (!pcchCards)
1154
0
    return SCARD_E_INVALID_PARAMETER;
1155
1156
0
  autoAllocate = (*pcchCards == SCARD_AUTOALLOCATE);
1157
1158
0
  cardName = findCardByAtr(pbAtr);
1159
0
  if (cardName)
1160
0
    outputLen += strlen(cardName) + 1;
1161
1162
0
  *pcchCards = outputLen;
1163
0
  if (autoAllocate)
1164
0
  {
1165
0
    output = calloc(outputLen, sizeof(WCHAR));
1166
0
    if (!output)
1167
0
      return SCARD_E_NO_MEMORY;
1168
1169
0
    *((LPWSTR*)mszCards) = output;
1170
0
  }
1171
0
  else
1172
0
  {
1173
0
    if (!mszCards)
1174
0
      return SCARD_S_SUCCESS;
1175
1176
0
    if (*pcchCards < outputLen)
1177
0
      return SCARD_E_INSUFFICIENT_BUFFER;
1178
1179
0
    output = mszCards;
1180
0
  }
1181
1182
0
  if (cardName)
1183
0
  {
1184
0
    size_t toCopy = strlen(cardName) + 1;
1185
0
    if (ConvertUtf8ToWChar(cardName, output, toCopy) < 0)
1186
0
      return SCARD_F_INTERNAL_ERROR;
1187
0
    output += toCopy;
1188
0
  }
1189
1190
0
  *output = 0;
1191
1192
0
  return SCARD_S_SUCCESS;
1193
0
}
1194
1195
WINPR_ATTR_NODISCARD
1196
static LONG WINAPI
1197
PCSC_SCardListInterfacesA(SCARDCONTEXT hContext, LPCSTR szCard, LPGUID pguidInterfaces,
1198
                          LPDWORD pcguidInterfaces /* NOLINT(readability-non-const-parameter) */)
1199
0
{
1200
0
  WINPR_UNUSED(hContext);
1201
0
  WINPR_UNUSED(szCard);
1202
0
  WINPR_UNUSED(pguidInterfaces);
1203
0
  WINPR_UNUSED(pcguidInterfaces);
1204
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1205
0
}
1206
1207
WINPR_ATTR_NODISCARD
1208
static LONG WINAPI
1209
PCSC_SCardListInterfacesW(SCARDCONTEXT hContext, LPCWSTR szCard, LPGUID pguidInterfaces,
1210
                          LPDWORD pcguidInterfaces /* NOLINT(readability-non-const-parameter) */)
1211
0
{
1212
0
  WINPR_UNUSED(hContext);
1213
0
  WINPR_UNUSED(szCard);
1214
0
  WINPR_UNUSED(pguidInterfaces);
1215
0
  WINPR_UNUSED(pcguidInterfaces);
1216
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1217
0
}
1218
1219
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetProviderIdA(SCARDCONTEXT hContext,
1220
                                                                 LPCSTR szCard,
1221
                                                                 LPGUID pguidProviderId)
1222
0
{
1223
0
  WINPR_UNUSED(hContext);
1224
0
  WINPR_UNUSED(szCard);
1225
0
  WINPR_UNUSED(pguidProviderId);
1226
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1227
0
}
1228
1229
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetProviderIdW(SCARDCONTEXT hContext,
1230
                                                                 LPCWSTR szCard,
1231
                                                                 LPGUID pguidProviderId)
1232
0
{
1233
0
  WINPR_UNUSED(hContext);
1234
0
  WINPR_UNUSED(szCard);
1235
0
  WINPR_UNUSED(pguidProviderId);
1236
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1237
0
}
1238
1239
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetCardTypeProviderNameA(
1240
    SCARDCONTEXT hContext, LPCSTR szCardName, DWORD dwProviderId,
1241
    CHAR* szProvider /* NOLINT(readability-non-const-parameter) */,
1242
    LPDWORD pcchProvider /* NOLINT(readability-non-const-parameter) */)
1243
0
{
1244
0
  WINPR_UNUSED(hContext);
1245
0
  WINPR_UNUSED(szCardName);
1246
0
  WINPR_UNUSED(dwProviderId);
1247
0
  WINPR_UNUSED(szProvider);
1248
0
  WINPR_UNUSED(pcchProvider);
1249
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1250
0
}
1251
1252
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetCardTypeProviderNameW(
1253
    SCARDCONTEXT hContext, LPCWSTR szCardName, DWORD dwProviderId,
1254
    WCHAR* szProvider /* NOLINT(readability-non-const-parameter) */,
1255
    LPDWORD pcchProvider /* NOLINT(readability-non-const-parameter) */)
1256
0
{
1257
0
  WINPR_UNUSED(hContext);
1258
0
  WINPR_UNUSED(szCardName);
1259
0
  WINPR_UNUSED(dwProviderId);
1260
0
  WINPR_UNUSED(szProvider);
1261
0
  WINPR_UNUSED(pcchProvider);
1262
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1263
0
}
1264
1265
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardIntroduceReaderGroupA(SCARDCONTEXT hContext,
1266
                                                                        LPCSTR szGroupName)
1267
0
{
1268
0
  WINPR_UNUSED(hContext);
1269
0
  WINPR_UNUSED(szGroupName);
1270
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1271
0
}
1272
1273
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardIntroduceReaderGroupW(SCARDCONTEXT hContext,
1274
                                                                        LPCWSTR szGroupName)
1275
0
{
1276
0
  WINPR_UNUSED(hContext);
1277
0
  WINPR_UNUSED(szGroupName);
1278
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1279
0
}
1280
1281
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetReaderGroupA(SCARDCONTEXT hContext,
1282
                                                                     LPCSTR szGroupName)
1283
0
{
1284
0
  WINPR_UNUSED(hContext);
1285
0
  WINPR_UNUSED(szGroupName);
1286
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1287
0
}
1288
1289
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetReaderGroupW(SCARDCONTEXT hContext,
1290
                                                                     LPCWSTR szGroupName)
1291
0
{
1292
0
  WINPR_UNUSED(hContext);
1293
0
  WINPR_UNUSED(szGroupName);
1294
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1295
0
}
1296
1297
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardIntroduceReaderA(SCARDCONTEXT hContext,
1298
                                                                   LPCSTR szReaderName,
1299
                                                                   LPCSTR szDeviceName)
1300
0
{
1301
0
  WINPR_UNUSED(hContext);
1302
0
  WINPR_UNUSED(szReaderName);
1303
0
  WINPR_UNUSED(szDeviceName);
1304
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1305
0
}
1306
1307
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardIntroduceReaderW(SCARDCONTEXT hContext,
1308
                                                                   LPCWSTR szReaderName,
1309
                                                                   LPCWSTR szDeviceName)
1310
0
{
1311
0
  WINPR_UNUSED(hContext);
1312
0
  WINPR_UNUSED(szReaderName);
1313
0
  WINPR_UNUSED(szDeviceName);
1314
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1315
0
}
1316
1317
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetReaderA(SCARDCONTEXT hContext,
1318
                                                                LPCSTR szReaderName)
1319
0
{
1320
0
  WINPR_UNUSED(hContext);
1321
0
  WINPR_UNUSED(szReaderName);
1322
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1323
0
}
1324
1325
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetReaderW(SCARDCONTEXT hContext,
1326
                                                                LPCWSTR szReaderName)
1327
0
{
1328
0
  WINPR_UNUSED(hContext);
1329
0
  WINPR_UNUSED(szReaderName);
1330
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1331
0
}
1332
1333
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardAddReaderToGroupA(SCARDCONTEXT hContext,
1334
                                                                    LPCSTR szReaderName,
1335
                                                                    LPCSTR szGroupName)
1336
0
{
1337
0
  WINPR_UNUSED(hContext);
1338
0
  WINPR_UNUSED(szReaderName);
1339
0
  WINPR_UNUSED(szGroupName);
1340
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1341
0
}
1342
1343
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardAddReaderToGroupW(SCARDCONTEXT hContext,
1344
                                                                    LPCWSTR szReaderName,
1345
                                                                    LPCWSTR szGroupName)
1346
0
{
1347
0
  WINPR_UNUSED(hContext);
1348
0
  WINPR_UNUSED(szReaderName);
1349
0
  WINPR_UNUSED(szGroupName);
1350
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1351
0
}
1352
1353
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardRemoveReaderFromGroupA(SCARDCONTEXT hContext,
1354
                                                                         LPCSTR szReaderName,
1355
                                                                         LPCSTR szGroupName)
1356
0
{
1357
0
  WINPR_UNUSED(hContext);
1358
0
  WINPR_UNUSED(szReaderName);
1359
0
  WINPR_UNUSED(szGroupName);
1360
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1361
0
}
1362
1363
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardRemoveReaderFromGroupW(SCARDCONTEXT hContext,
1364
                                                                         LPCWSTR szReaderName,
1365
                                                                         LPCWSTR szGroupName)
1366
0
{
1367
0
  WINPR_UNUSED(hContext);
1368
0
  WINPR_UNUSED(szReaderName);
1369
0
  WINPR_UNUSED(szGroupName);
1370
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1371
0
}
1372
1373
WINPR_ATTR_NODISCARD static LONG WINAPI
1374
PCSC_SCardIntroduceCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName, LPCGUID pguidPrimaryProvider,
1375
                             LPCGUID rgguidInterfaces, DWORD dwInterfaceCount, LPCBYTE pbAtr,
1376
                             LPCBYTE pbAtrMask, DWORD cbAtrLen)
1377
0
{
1378
0
  WINPR_UNUSED(hContext);
1379
0
  WINPR_UNUSED(szCardName);
1380
0
  WINPR_UNUSED(pguidPrimaryProvider);
1381
0
  WINPR_UNUSED(rgguidInterfaces);
1382
0
  WINPR_UNUSED(dwInterfaceCount);
1383
0
  WINPR_UNUSED(pbAtr);
1384
0
  WINPR_UNUSED(pbAtrMask);
1385
0
  WINPR_UNUSED(cbAtrLen);
1386
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1387
0
}
1388
1389
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardIntroduceCardTypeW(
1390
    SCARDCONTEXT hContext, LPCWSTR szCardName, LPCGUID pguidPrimaryProvider,
1391
    LPCGUID rgguidInterfaces, DWORD dwInterfaceCount, LPCBYTE pbAtr, LPCBYTE pbAtrMask,
1392
    DWORD cbAtrLen)
1393
0
{
1394
0
  WINPR_UNUSED(hContext);
1395
0
  WINPR_UNUSED(szCardName);
1396
0
  WINPR_UNUSED(pguidPrimaryProvider);
1397
0
  WINPR_UNUSED(rgguidInterfaces);
1398
0
  WINPR_UNUSED(dwInterfaceCount);
1399
0
  WINPR_UNUSED(pbAtr);
1400
0
  WINPR_UNUSED(pbAtrMask);
1401
0
  WINPR_UNUSED(cbAtrLen);
1402
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1403
0
}
1404
1405
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardSetCardTypeProviderNameA(SCARDCONTEXT hContext,
1406
                                                                           LPCSTR szCardName,
1407
                                                                           DWORD dwProviderId,
1408
                                                                           LPCSTR szProvider)
1409
0
{
1410
0
  WINPR_UNUSED(hContext);
1411
0
  WINPR_UNUSED(szCardName);
1412
0
  WINPR_UNUSED(dwProviderId);
1413
0
  WINPR_UNUSED(szProvider);
1414
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1415
0
}
1416
1417
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardSetCardTypeProviderNameW(SCARDCONTEXT hContext,
1418
                                                                           LPCWSTR szCardName,
1419
                                                                           DWORD dwProviderId,
1420
                                                                           LPCWSTR szProvider)
1421
0
{
1422
0
  WINPR_UNUSED(hContext);
1423
0
  WINPR_UNUSED(szCardName);
1424
0
  WINPR_UNUSED(dwProviderId);
1425
0
  WINPR_UNUSED(szProvider);
1426
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1427
0
}
1428
1429
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetCardTypeA(SCARDCONTEXT hContext,
1430
                                                                  LPCSTR szCardName)
1431
0
{
1432
0
  WINPR_UNUSED(hContext);
1433
0
  WINPR_UNUSED(szCardName);
1434
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1435
0
}
1436
1437
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardForgetCardTypeW(SCARDCONTEXT hContext,
1438
                                                                  LPCWSTR szCardName)
1439
0
{
1440
0
  WINPR_UNUSED(hContext);
1441
0
  WINPR_UNUSED(szCardName);
1442
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1443
0
}
1444
1445
static LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPVOID pvMem)
1446
0
{
1447
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1448
1449
0
  if (PCSC_RemoveMemoryBlock(hContext, pvMem))
1450
0
  {
1451
0
    free((void*)pvMem);
1452
0
    status = SCARD_S_SUCCESS;
1453
0
  }
1454
0
  else
1455
0
  {
1456
0
    if (g_PCSC.pfnSCardFreeMemory)
1457
0
    {
1458
0
      status = g_PCSC.pfnSCardFreeMemory(hContext, pvMem);
1459
0
    }
1460
0
  }
1461
1462
0
  return PCSC_MapErrorCodeToWinSCard(status);
1463
0
}
1464
1465
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem)
1466
0
{
1467
0
  LONG status = SCARD_S_SUCCESS;
1468
1469
0
  if (hContext)
1470
0
  {
1471
0
    if (!PCSC_LockCardContext(hContext))
1472
0
      return SCARD_E_INVALID_HANDLE;
1473
0
  }
1474
1475
0
  status = PCSC_SCardFreeMemory_Internal(hContext, pvMem);
1476
1477
0
  if (hContext)
1478
0
  {
1479
0
    if (!PCSC_UnlockCardContext(hContext))
1480
0
      return SCARD_E_INVALID_HANDLE;
1481
0
  }
1482
1483
0
  return status;
1484
0
}
1485
1486
WINPR_ATTR_NODISCARD
1487
static HANDLE WINAPI PCSC_SCardAccessStartedEvent(void)
1488
0
{
1489
0
  LONG status = 0;
1490
0
  SCARDCONTEXT hContext = 0;
1491
1492
0
  status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, nullptr, nullptr, &hContext);
1493
1494
0
  if (status != SCARD_S_SUCCESS)
1495
0
    return nullptr;
1496
1497
0
  status = PCSC_SCardReleaseContext(hContext);
1498
1499
0
  if (status != SCARD_S_SUCCESS)
1500
0
    return nullptr;
1501
1502
0
  if (!g_StartedEvent)
1503
0
  {
1504
0
    if (!(g_StartedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1505
0
      return nullptr;
1506
1507
0
    if (!SetEvent(g_StartedEvent))
1508
0
    {
1509
0
      (void)CloseHandle(g_StartedEvent);
1510
0
      return nullptr;
1511
0
    }
1512
0
  }
1513
1514
0
  g_StartedEventRefCount++;
1515
0
  return g_StartedEvent;
1516
0
}
1517
1518
static void WINAPI PCSC_SCardReleaseStartedEvent(void)
1519
0
{
1520
0
  g_StartedEventRefCount--;
1521
1522
0
  if (g_StartedEventRefCount == 0)
1523
0
  {
1524
0
    if (g_StartedEvent)
1525
0
    {
1526
0
      (void)CloseHandle(g_StartedEvent);
1527
0
      g_StartedEvent = nullptr;
1528
0
    }
1529
0
  }
1530
0
}
1531
1532
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardLocateCardsA(SCARDCONTEXT hContext,
1533
                                                               LPCSTR mszCards,
1534
                                                               LPSCARD_READERSTATEA rgReaderStates,
1535
                                                               DWORD cReaders)
1536
0
{
1537
0
  WINPR_UNUSED(hContext);
1538
0
  WINPR_UNUSED(mszCards);
1539
0
  WINPR_UNUSED(rgReaderStates);
1540
0
  WINPR_UNUSED(cReaders);
1541
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1542
0
}
1543
1544
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardLocateCardsW(SCARDCONTEXT hContext,
1545
                                                               LPCWSTR mszCards,
1546
                                                               LPSCARD_READERSTATEW rgReaderStates,
1547
                                                               DWORD cReaders)
1548
0
{
1549
0
  WINPR_UNUSED(hContext);
1550
0
  WINPR_UNUSED(mszCards);
1551
0
  WINPR_UNUSED(rgReaderStates);
1552
0
  WINPR_UNUSED(cReaders);
1553
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1554
0
}
1555
1556
WINPR_ATTR_NODISCARD static LONG WINAPI
1557
PCSC_SCardLocateCardsByATRA(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks, DWORD cAtrs,
1558
                            LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
1559
0
{
1560
0
  WINPR_UNUSED(hContext);
1561
0
  WINPR_UNUSED(rgAtrMasks);
1562
0
  WINPR_UNUSED(cAtrs);
1563
0
  WINPR_UNUSED(rgReaderStates);
1564
0
  WINPR_UNUSED(cReaders);
1565
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1566
0
}
1567
1568
WINPR_ATTR_NODISCARD static LONG WINAPI
1569
PCSC_SCardLocateCardsByATRW(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks, DWORD cAtrs,
1570
                            LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
1571
0
{
1572
0
  WINPR_UNUSED(hContext);
1573
0
  WINPR_UNUSED(rgAtrMasks);
1574
0
  WINPR_UNUSED(cAtrs);
1575
0
  WINPR_UNUSED(rgReaderStates);
1576
0
  WINPR_UNUSED(cReaders);
1577
0
  return SCARD_E_UNSUPPORTED_FEATURE;
1578
0
}
1579
1580
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetStatusChange_Internal(
1581
    SCARDCONTEXT hContext, DWORD dwTimeout, LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
1582
0
{
1583
0
  INT64* map = nullptr;
1584
0
  PCSC_DWORD cMappedReaders = 0;
1585
0
  PCSC_SCARD_READERSTATE* states = nullptr;
1586
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1587
0
  PCSC_DWORD pcsc_dwTimeout = (PCSC_DWORD)dwTimeout;
1588
0
  PCSC_DWORD pcsc_cReaders = (PCSC_DWORD)cReaders;
1589
1590
0
  if (!g_PCSC.pfnSCardGetStatusChange)
1591
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardGetStatusChange");
1592
1593
0
  if (!cReaders)
1594
0
    return SCARD_S_SUCCESS;
1595
1596
  /* pcsc-lite interprets value 0 as INFINITE, work around the problem by using value 1 */
1597
0
  pcsc_dwTimeout = pcsc_dwTimeout ? pcsc_dwTimeout : 1;
1598
  /**
1599
   * Apple's SmartCard Services (not vanilla pcsc-lite) appears to have trouble with the
1600
   * "\\\\?PnP?\\Notification" reader name. I am always getting EXC_BAD_ACCESS with it.
1601
   *
1602
   * The SmartCard Services tarballs can be found here:
1603
   * http://opensource.apple.com/tarballs/SmartCardServices/
1604
   *
1605
   * The "\\\\?PnP?\\Notification" string cannot be found anywhere in the sources,
1606
   * while this string is present in the vanilla pcsc-lite sources.
1607
   *
1608
   * To work around this apparent lack of "\\\\?PnP?\\Notification" support,
1609
   * we have to filter rgReaderStates to exclude the special PnP reader name.
1610
   */
1611
0
  map = (INT64*)calloc(pcsc_cReaders, sizeof(INT64));
1612
1613
0
  if (!map)
1614
0
    return SCARD_E_NO_MEMORY;
1615
1616
0
  states = (PCSC_SCARD_READERSTATE*)calloc(pcsc_cReaders, sizeof(PCSC_SCARD_READERSTATE));
1617
1618
0
  if (!states)
1619
0
  {
1620
0
    free(map);
1621
0
    return SCARD_E_NO_MEMORY;
1622
0
  }
1623
1624
0
  PCSC_DWORD j = 0;
1625
0
  for (PCSC_DWORD i = 0; i < pcsc_cReaders; i++)
1626
0
  {
1627
0
    if (!g_PnP_Notification)
1628
0
    {
1629
0
      LPSCARD_READERSTATEA reader = &rgReaderStates[i];
1630
0
      if (!reader->szReader)
1631
0
        continue;
1632
0
      if (0 == _stricmp(reader->szReader, SMARTCARD_PNP_NOTIFICATION_A))
1633
0
      {
1634
0
        map[i] = -1; /* unmapped */
1635
0
        continue;
1636
0
      }
1637
0
    }
1638
1639
0
    map[i] = (INT64)j;
1640
0
    states[j].szReader = rgReaderStates[i].szReader;
1641
0
    states[j].dwCurrentState = rgReaderStates[i].dwCurrentState;
1642
0
    states[j].pvUserData = rgReaderStates[i].pvUserData;
1643
0
    states[j].dwEventState = rgReaderStates[i].dwEventState;
1644
0
    states[j].cbAtr = rgReaderStates[i].cbAtr;
1645
0
    CopyMemory(&(states[j].rgbAtr), &(rgReaderStates[i].rgbAtr), PCSC_MAX_ATR_SIZE);
1646
0
    j++;
1647
0
  }
1648
1649
0
  cMappedReaders = j;
1650
1651
0
  if (cMappedReaders > 0)
1652
0
  {
1653
0
    status = g_PCSC.pfnSCardGetStatusChange(hContext, pcsc_dwTimeout, states, cMappedReaders);
1654
0
  }
1655
0
  else
1656
0
  {
1657
0
    status = SCARD_S_SUCCESS;
1658
0
  }
1659
1660
0
  for (PCSC_DWORD i = 0; i < pcsc_cReaders; i++)
1661
0
  {
1662
0
    if (map[i] < 0)
1663
0
      continue; /* unmapped */
1664
1665
0
    PCSC_DWORD k = (PCSC_DWORD)map[i];
1666
0
    rgReaderStates[i].dwCurrentState = (DWORD)states[k].dwCurrentState;
1667
0
    rgReaderStates[i].cbAtr = (DWORD)states[k].cbAtr;
1668
0
    CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[k].rgbAtr), PCSC_MAX_ATR_SIZE);
1669
0
    rgReaderStates[i].dwEventState = (DWORD)states[k].dwEventState;
1670
0
  }
1671
1672
0
  free(map);
1673
0
  free(states);
1674
0
  return PCSC_MapErrorCodeToWinSCard(status);
1675
0
}
1676
1677
WINPR_ATTR_NODISCARD
1678
static LONG WINAPI PCSC_SCardGetStatusChangeA(SCARDCONTEXT hContext, DWORD dwTimeout,
1679
                                              LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
1680
0
{
1681
0
  LONG status = SCARD_S_SUCCESS;
1682
1683
0
  if (!PCSC_LockCardContext(hContext))
1684
0
    return SCARD_E_INVALID_HANDLE;
1685
1686
0
  status = PCSC_SCardGetStatusChange_Internal(hContext, dwTimeout, rgReaderStates, cReaders);
1687
1688
0
  if (!PCSC_UnlockCardContext(hContext))
1689
0
    return SCARD_E_INVALID_HANDLE;
1690
1691
0
  return status;
1692
0
}
1693
1694
WINPR_ATTR_NODISCARD
1695
static LONG WINAPI PCSC_SCardGetStatusChangeW(SCARDCONTEXT hContext, DWORD dwTimeout,
1696
                                              LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
1697
0
{
1698
0
  LPSCARD_READERSTATEA states = nullptr;
1699
0
  LONG status = SCARD_S_SUCCESS;
1700
1701
0
  if (!g_PCSC.pfnSCardGetStatusChange)
1702
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardGetStatusChange");
1703
1704
0
  if (!PCSC_LockCardContext(hContext))
1705
0
    return SCARD_E_INVALID_HANDLE;
1706
1707
0
  states = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA));
1708
1709
0
  if (!states)
1710
0
  {
1711
0
    (void)PCSC_UnlockCardContext(hContext);
1712
0
    return SCARD_E_NO_MEMORY;
1713
0
  }
1714
1715
0
  for (DWORD index = 0; index < cReaders; index++)
1716
0
  {
1717
0
    const LPSCARD_READERSTATEW curReader = &rgReaderStates[index];
1718
0
    LPSCARD_READERSTATEA cur = &states[index];
1719
1720
0
    cur->szReader = ConvertWCharToUtf8Alloc(curReader->szReader, nullptr);
1721
0
    cur->pvUserData = curReader->pvUserData;
1722
0
    cur->dwCurrentState = curReader->dwCurrentState;
1723
0
    cur->dwEventState = curReader->dwEventState;
1724
0
    cur->cbAtr = curReader->cbAtr;
1725
0
    CopyMemory(&(cur->rgbAtr), &(curReader->rgbAtr), ARRAYSIZE(cur->rgbAtr));
1726
0
  }
1727
1728
0
  status = PCSC_SCardGetStatusChange_Internal(hContext, dwTimeout, states, cReaders);
1729
1730
0
  for (DWORD index = 0; index < cReaders; index++)
1731
0
  {
1732
0
    free((void*)states[index].szReader);
1733
0
    rgReaderStates[index].pvUserData = states[index].pvUserData;
1734
0
    rgReaderStates[index].dwCurrentState = states[index].dwCurrentState;
1735
0
    rgReaderStates[index].dwEventState = states[index].dwEventState;
1736
0
    rgReaderStates[index].cbAtr = states[index].cbAtr;
1737
0
    CopyMemory(&(rgReaderStates[index].rgbAtr), &(states[index].rgbAtr), 36);
1738
0
  }
1739
1740
0
  free(states);
1741
1742
0
  if (!PCSC_UnlockCardContext(hContext))
1743
0
    return SCARD_E_INVALID_HANDLE;
1744
1745
0
  return status;
1746
0
}
1747
1748
static LONG WINAPI PCSC_SCardCancel(SCARDCONTEXT hContext)
1749
0
{
1750
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1751
1752
0
  if (!g_PCSC.pfnSCardCancel)
1753
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardCancel");
1754
1755
0
  status = g_PCSC.pfnSCardCancel(hContext);
1756
0
  return PCSC_MapErrorCodeToWinSCard(status);
1757
0
}
1758
1759
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardConnect_Internal(
1760
    SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols,
1761
    LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
1762
0
{
1763
0
  BOOL shared = 0;
1764
0
  const char* szReaderPCSC = nullptr;
1765
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1766
0
  PCSC_SCARDHANDLE* pCard = nullptr;
1767
0
  PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD)dwShareMode;
1768
0
  PCSC_DWORD pcsc_dwPreferredProtocols = 0;
1769
0
  PCSC_DWORD pcsc_dwActiveProtocol = 0;
1770
1771
0
  if (!g_PCSC.pfnSCardConnect)
1772
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardConnect");
1773
1774
0
  shared = (dwShareMode == SCARD_SHARE_DIRECT) != 0;
1775
0
  PCSC_WaitForCardAccess(hContext, 0, shared);
1776
0
  szReaderPCSC = szReader;
1777
1778
  /**
1779
   * As stated here :
1780
   * https://pcsclite.alioth.debian.org/api/group__API.html#ga4e515829752e0a8dbc4d630696a8d6a5
1781
   * SCARD_PROTOCOL_UNDEFINED is valid for dwPreferredProtocols (only) if dwShareMode ==
1782
   * SCARD_SHARE_DIRECT and allows to send control commands to the reader (with SCardControl())
1783
   * even if a card is not present in the reader
1784
   */
1785
0
  if (pcsc_dwShareMode == SCARD_SHARE_DIRECT && dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED)
1786
0
    pcsc_dwPreferredProtocols = SCARD_PROTOCOL_UNDEFINED;
1787
0
  else
1788
0
    pcsc_dwPreferredProtocols =
1789
0
        (PCSC_DWORD)PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
1790
1791
0
  status = g_PCSC.pfnSCardConnect(hContext, szReaderPCSC, pcsc_dwShareMode,
1792
0
                                  pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol);
1793
1794
0
  if (status == SCARD_S_SUCCESS)
1795
0
  {
1796
0
    pCard = PCSC_ConnectCardHandle(hContext, *phCard);
1797
0
    *pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwActiveProtocol);
1798
0
    pCard->shared = shared;
1799
1800
    // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ListDictionary_Add takes ownership of pCard
1801
0
    PCSC_WaitForCardAccess(hContext, pCard->hSharedContext, shared);
1802
0
  }
1803
1804
0
  return PCSC_MapErrorCodeToWinSCard(status);
1805
0
}
1806
1807
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardConnectA(SCARDCONTEXT hContext, LPCSTR szReader,
1808
                                                           DWORD dwShareMode,
1809
                                                           DWORD dwPreferredProtocols,
1810
                                                           LPSCARDHANDLE phCard,
1811
                                                           LPDWORD pdwActiveProtocol)
1812
0
{
1813
0
  LONG status = SCARD_S_SUCCESS;
1814
1815
0
  if (!PCSC_LockCardContext(hContext))
1816
0
    return SCARD_E_INVALID_HANDLE;
1817
1818
0
  status = PCSC_SCardConnect_Internal(hContext, szReader, dwShareMode, dwPreferredProtocols,
1819
0
                                      phCard, pdwActiveProtocol);
1820
1821
0
  if (!PCSC_UnlockCardContext(hContext))
1822
0
    return SCARD_E_INVALID_HANDLE;
1823
1824
0
  return status;
1825
0
}
1826
1827
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardConnectW(SCARDCONTEXT hContext, LPCWSTR szReader,
1828
                                                           DWORD dwShareMode,
1829
                                                           DWORD dwPreferredProtocols,
1830
                                                           LPSCARDHANDLE phCard,
1831
                                                           LPDWORD pdwActiveProtocol)
1832
0
{
1833
0
  LPSTR szReaderA = nullptr;
1834
0
  LONG status = SCARD_S_SUCCESS;
1835
1836
0
  if (!PCSC_LockCardContext(hContext))
1837
0
    return SCARD_E_INVALID_HANDLE;
1838
1839
0
  if (szReader)
1840
0
  {
1841
0
    szReaderA = ConvertWCharToUtf8Alloc(szReader, nullptr);
1842
0
    if (!szReaderA)
1843
0
      return SCARD_E_INSUFFICIENT_BUFFER;
1844
0
  }
1845
1846
0
  status = PCSC_SCardConnect_Internal(hContext, szReaderA, dwShareMode, dwPreferredProtocols,
1847
0
                                      phCard, pdwActiveProtocol);
1848
0
  free(szReaderA);
1849
1850
0
  if (!PCSC_UnlockCardContext(hContext))
1851
0
    return SCARD_E_INVALID_HANDLE;
1852
1853
0
  return status;
1854
0
}
1855
1856
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
1857
                                                            DWORD dwPreferredProtocols,
1858
                                                            DWORD dwInitialization,
1859
                                                            LPDWORD pdwActiveProtocol)
1860
0
{
1861
0
  BOOL shared = 0;
1862
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1863
0
  PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD)dwShareMode;
1864
0
  PCSC_DWORD pcsc_dwPreferredProtocols = 0;
1865
0
  PCSC_DWORD pcsc_dwInitialization = (PCSC_DWORD)dwInitialization;
1866
0
  PCSC_DWORD pcsc_dwActiveProtocol = 0;
1867
1868
0
  if (!g_PCSC.pfnSCardReconnect)
1869
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardReconnect");
1870
1871
0
  shared = (dwShareMode == SCARD_SHARE_DIRECT) != 0;
1872
0
  PCSC_WaitForCardAccess(0, hCard, shared);
1873
0
  pcsc_dwPreferredProtocols = (PCSC_DWORD)PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
1874
0
  status = g_PCSC.pfnSCardReconnect(hCard, pcsc_dwShareMode, pcsc_dwPreferredProtocols,
1875
0
                                    pcsc_dwInitialization, &pcsc_dwActiveProtocol);
1876
1877
0
  *pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwActiveProtocol);
1878
0
  return PCSC_MapErrorCodeToWinSCard(status);
1879
0
}
1880
1881
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1882
0
{
1883
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1884
0
  PCSC_DWORD pcsc_dwDisposition = (PCSC_DWORD)dwDisposition;
1885
1886
0
  if (!g_PCSC.pfnSCardDisconnect)
1887
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardDisconnect");
1888
1889
0
  status = g_PCSC.pfnSCardDisconnect(hCard, pcsc_dwDisposition);
1890
1891
0
  if (status == SCARD_S_SUCCESS)
1892
0
  {
1893
0
    PCSC_SCARDHANDLE* pCard = PCSC_GetCardHandleData(hCard);
1894
0
    PCSC_DisconnectCardHandle(pCard);
1895
0
  }
1896
1897
0
  PCSC_ReleaseCardAccess(0, hCard);
1898
0
  return PCSC_MapErrorCodeToWinSCard(status);
1899
0
}
1900
1901
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
1902
0
{
1903
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1904
0
  PCSC_SCARDHANDLE* pCard = nullptr;
1905
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
1906
1907
0
  if (!g_PCSC.pfnSCardBeginTransaction)
1908
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardBeginTransaction");
1909
1910
0
  pCard = PCSC_GetCardHandleData(hCard);
1911
1912
0
  if (!pCard)
1913
0
    return SCARD_E_INVALID_HANDLE;
1914
1915
0
  pContext = PCSC_GetCardContextData(pCard->hSharedContext);
1916
1917
0
  if (!pContext)
1918
0
    return SCARD_E_INVALID_HANDLE;
1919
1920
0
  if (pContext->isTransactionLocked)
1921
0
    return SCARD_S_SUCCESS; /* disable nested transactions */
1922
1923
0
  status = g_PCSC.pfnSCardBeginTransaction(hCard);
1924
1925
0
  pContext->isTransactionLocked = TRUE;
1926
0
  return PCSC_MapErrorCodeToWinSCard(status);
1927
0
}
1928
1929
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardEndTransaction(SCARDHANDLE hCard,
1930
                                                                 DWORD dwDisposition)
1931
0
{
1932
0
  PCSC_LONG status = SCARD_S_SUCCESS;
1933
0
  PCSC_SCARDHANDLE* pCard = nullptr;
1934
0
  PCSC_SCARDCONTEXT* pContext = nullptr;
1935
0
  PCSC_DWORD pcsc_dwDisposition = (PCSC_DWORD)dwDisposition;
1936
1937
0
  if (!g_PCSC.pfnSCardEndTransaction)
1938
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardEndTransaction");
1939
1940
0
  pCard = PCSC_GetCardHandleData(hCard);
1941
1942
0
  if (!pCard)
1943
0
    return SCARD_E_INVALID_HANDLE;
1944
1945
0
  pContext = PCSC_GetCardContextData(pCard->hSharedContext);
1946
1947
0
  if (!pContext)
1948
0
    return SCARD_E_INVALID_HANDLE;
1949
1950
0
  PCSC_ReleaseCardAccess(0, hCard);
1951
1952
0
  if (!pContext->isTransactionLocked)
1953
0
    return SCARD_S_SUCCESS; /* disable nested transactions */
1954
1955
0
  status = g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
1956
1957
0
  pContext->isTransactionLocked = FALSE;
1958
0
  return PCSC_MapErrorCodeToWinSCard(status);
1959
0
}
1960
1961
static LONG WINAPI PCSC_SCardCancelTransaction(SCARDHANDLE hCard)
1962
0
{
1963
0
  WINPR_UNUSED(hCard);
1964
0
  return SCARD_S_SUCCESS;
1965
0
}
1966
1967
/*
1968
 * PCSC returns a string but Windows SCardStatus requires the return to be a multi string.
1969
 * Therefore extra length checks and additional buffer allocation is required
1970
 */
1971
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardStatus_Internal(
1972
    SCARDHANDLE hCard, LPSTR mszReaderNames, LPDWORD pcchReaderLen, LPDWORD pdwState,
1973
    LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen, BOOL unicode)
1974
0
{
1975
0
  PCSC_SCARDHANDLE* pCard = nullptr;
1976
0
  SCARDCONTEXT hContext = 0;
1977
0
  PCSC_LONG status = 0;
1978
0
  PCSC_DWORD pcsc_cchReaderLen = 0;
1979
0
  PCSC_DWORD pcsc_cbAtrLen = 0;
1980
0
  PCSC_DWORD pcsc_dwState = 0;
1981
0
  PCSC_DWORD pcsc_dwProtocol = 0;
1982
0
  BOOL allocateReader = FALSE;
1983
0
  BOOL allocateAtr = FALSE;
1984
0
  LPSTR readerNames = mszReaderNames;
1985
0
  LPBYTE atr = pbAtr;
1986
0
  LPSTR tReader = nullptr;
1987
0
  LPBYTE tATR = nullptr;
1988
1989
0
  if (!g_PCSC.pfnSCardStatus)
1990
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardStatus");
1991
1992
0
  pCard = PCSC_GetCardHandleData(hCard);
1993
1994
0
  if (!pCard)
1995
0
    return SCARD_E_INVALID_VALUE;
1996
1997
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
1998
0
  hContext = PCSC_GetCardContextFromHandle(hCard);
1999
2000
0
  if (!hContext)
2001
0
    return SCARD_E_INVALID_VALUE;
2002
2003
0
  status = g_PCSC.pfnSCardStatus(hCard, nullptr, &pcsc_cchReaderLen, nullptr, nullptr, nullptr,
2004
0
                                 &pcsc_cbAtrLen);
2005
2006
0
  if (status != STATUS_SUCCESS)
2007
0
    return PCSC_MapErrorCodeToWinSCard(status);
2008
2009
0
  pcsc_cchReaderLen++;
2010
2011
0
  if (unicode)
2012
0
    pcsc_cchReaderLen *= 2;
2013
2014
0
  if (pcchReaderLen)
2015
0
  {
2016
0
    if (*pcchReaderLen == SCARD_AUTOALLOCATE)
2017
0
      allocateReader = TRUE;
2018
0
    else if (mszReaderNames && (*pcchReaderLen < pcsc_cchReaderLen))
2019
0
      return SCARD_E_INSUFFICIENT_BUFFER;
2020
0
    else
2021
0
      pcsc_cchReaderLen = *pcchReaderLen;
2022
0
  }
2023
2024
0
  if (pcbAtrLen)
2025
0
  {
2026
0
    if (*pcbAtrLen == SCARD_AUTOALLOCATE)
2027
0
      allocateAtr = TRUE;
2028
0
    else if (pbAtr && (*pcbAtrLen < pcsc_cbAtrLen))
2029
0
      return SCARD_E_INSUFFICIENT_BUFFER;
2030
0
    else
2031
0
      pcsc_cbAtrLen = *pcbAtrLen;
2032
0
  }
2033
2034
0
  if (allocateReader && pcsc_cchReaderLen > 0 && mszReaderNames)
2035
0
  {
2036
#ifdef __MACOSX__
2037
2038
    /**
2039
     * Workaround for SCardStatus Bug in MAC OS X Yosemite
2040
     */
2041
    if (OSXVersion == 0x10100000)
2042
      pcsc_cchReaderLen++;
2043
2044
#endif
2045
0
    tReader = calloc(sizeof(CHAR), pcsc_cchReaderLen + 1);
2046
2047
0
    if (!tReader)
2048
0
    {
2049
0
      status = ERROR_NOT_ENOUGH_MEMORY;
2050
0
      goto out_fail;
2051
0
    }
2052
2053
0
    readerNames = tReader;
2054
0
  }
2055
2056
0
  if (allocateAtr && pcsc_cbAtrLen > 0 && pbAtr)
2057
0
  {
2058
0
    tATR = calloc(1, pcsc_cbAtrLen);
2059
2060
0
    if (!tATR)
2061
0
    {
2062
0
      status = ERROR_NOT_ENOUGH_MEMORY;
2063
0
      goto out_fail;
2064
0
    }
2065
2066
0
    atr = tATR;
2067
0
  }
2068
2069
0
  status = g_PCSC.pfnSCardStatus(hCard, readerNames, &pcsc_cchReaderLen, &pcsc_dwState,
2070
0
                                 &pcsc_dwProtocol, atr, &pcsc_cbAtrLen);
2071
2072
0
  if (status != STATUS_SUCCESS)
2073
0
    goto out_fail;
2074
2075
0
  if (tATR)
2076
0
  {
2077
0
    PCSC_AddMemoryBlock(hContext, tATR);
2078
0
    *(BYTE**)pbAtr = tATR;
2079
0
  }
2080
2081
0
  if (tReader)
2082
0
  {
2083
0
    if (unicode)
2084
0
    {
2085
0
      size_t size = 0;
2086
0
      WCHAR* tmp = ConvertMszUtf8NToWCharAlloc(tReader, pcsc_cchReaderLen + 1, &size);
2087
2088
0
      if (tmp == nullptr)
2089
0
      {
2090
0
        status = ERROR_NOT_ENOUGH_MEMORY;
2091
0
        goto out_fail;
2092
0
      }
2093
2094
0
      free(tReader);
2095
2096
0
      PCSC_AddMemoryBlock(hContext, tmp);
2097
0
      *(WCHAR**)mszReaderNames = tmp;
2098
0
    }
2099
0
    else
2100
0
    {
2101
0
      tReader[pcsc_cchReaderLen - 1] = '\0';
2102
0
      PCSC_AddMemoryBlock(hContext, tReader);
2103
0
      *(char**)mszReaderNames = tReader;
2104
0
    }
2105
0
  }
2106
2107
0
  pcsc_dwState &= 0xFFFF;
2108
2109
0
  if (pdwState)
2110
0
    *pdwState = PCSC_ConvertCardStateToWinSCard((DWORD)pcsc_dwState, status);
2111
2112
0
  if (pdwProtocol)
2113
0
    *pdwProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwProtocol);
2114
2115
0
  if (pcbAtrLen)
2116
0
    *pcbAtrLen = (DWORD)pcsc_cbAtrLen;
2117
2118
0
  if (pcchReaderLen)
2119
0
  {
2120
0
    WINPR_ASSERT(pcsc_cchReaderLen < UINT32_MAX);
2121
0
    *pcchReaderLen = (DWORD)pcsc_cchReaderLen + 1u;
2122
0
  }
2123
2124
0
  return (LONG)status;
2125
0
out_fail:
2126
0
  free(tReader);
2127
0
  free(tATR);
2128
0
  return (LONG)status;
2129
0
}
2130
2131
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardState(SCARDHANDLE hCard, LPDWORD pdwState,
2132
                                                        LPDWORD pdwProtocol, LPBYTE pbAtr,
2133
                                                        LPDWORD pcbAtrLen)
2134
0
{
2135
0
  DWORD cchReaderLen = 0;
2136
0
  SCARDCONTEXT hContext = 0;
2137
0
  LPSTR mszReaderNames = nullptr;
2138
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2139
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2140
0
  DWORD pcsc_dwState = 0;
2141
0
  DWORD pcsc_dwProtocol = 0;
2142
0
  DWORD pcsc_cbAtrLen = 0;
2143
2144
0
  if (pcbAtrLen)
2145
0
    pcsc_cbAtrLen = (DWORD)*pcbAtrLen;
2146
2147
0
  if (!g_PCSC.pfnSCardStatus)
2148
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardStatus");
2149
2150
0
  pCard = PCSC_GetCardHandleData(hCard);
2151
2152
0
  if (!pCard)
2153
0
    return SCARD_E_INVALID_VALUE;
2154
2155
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2156
0
  hContext = PCSC_GetCardContextFromHandle(hCard);
2157
2158
0
  if (!hContext)
2159
0
    return SCARD_E_INVALID_VALUE;
2160
2161
0
  cchReaderLen = SCARD_AUTOALLOCATE;
2162
0
  status = PCSC_SCardStatus_Internal(hCard, (LPSTR)&mszReaderNames, &cchReaderLen, &pcsc_dwState,
2163
0
                                     &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen, FALSE);
2164
2165
0
  if (mszReaderNames)
2166
0
    PCSC_SCardFreeMemory_Internal(hContext, mszReaderNames);
2167
2168
0
  *pdwState = pcsc_dwState;
2169
0
  *pdwProtocol = PCSC_ConvertProtocolsToWinSCard(pcsc_dwProtocol);
2170
0
  if (pcbAtrLen)
2171
0
    *pcbAtrLen = pcsc_cbAtrLen;
2172
0
  return PCSC_MapErrorCodeToWinSCard(status);
2173
0
}
2174
2175
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardStatusA(SCARDHANDLE hCard, LPSTR mszReaderNames,
2176
                                                          LPDWORD pcchReaderLen, LPDWORD pdwState,
2177
                                                          LPDWORD pdwProtocol, LPBYTE pbAtr,
2178
                                                          LPDWORD pcbAtrLen)
2179
0
{
2180
2181
0
  return PCSC_SCardStatus_Internal(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol,
2182
0
                                   pbAtr, pcbAtrLen, FALSE);
2183
0
}
2184
2185
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardStatusW(SCARDHANDLE hCard, LPWSTR mszReaderNames,
2186
                                                          LPDWORD pcchReaderLen, LPDWORD pdwState,
2187
                                                          LPDWORD pdwProtocol, LPBYTE pbAtr,
2188
                                                          LPDWORD pcbAtrLen)
2189
0
{
2190
2191
0
  return PCSC_SCardStatus_Internal(hCard, (LPSTR)mszReaderNames, pcchReaderLen, pdwState,
2192
0
                                   pdwProtocol, pbAtr, pcbAtrLen, TRUE);
2193
0
}
2194
2195
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardTransmit(
2196
    SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength,
2197
    LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
2198
0
{
2199
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2200
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2201
0
  PCSC_DWORD cbExtraBytes = 0;
2202
0
  BYTE* pbExtraBytes = nullptr;
2203
0
  BYTE* pcsc_pbExtraBytes = nullptr;
2204
0
  PCSC_DWORD pcsc_cbSendLength = (PCSC_DWORD)cbSendLength;
2205
0
  PCSC_DWORD pcsc_cbRecvLength = 0;
2206
0
  union
2207
0
  {
2208
0
    const PCSC_SCARD_IO_REQUEST* pcs;
2209
0
    PCSC_SCARD_IO_REQUEST* ps;
2210
0
    LPSCARD_IO_REQUEST lps;
2211
0
    LPCSCARD_IO_REQUEST lpcs;
2212
0
    BYTE* pb;
2213
0
  } sendPci, recvPci, inRecvPci, inSendPci;
2214
2215
0
  sendPci.ps = nullptr;
2216
0
  recvPci.ps = nullptr;
2217
0
  inRecvPci.lps = pioRecvPci;
2218
0
  inSendPci.lpcs = pioSendPci;
2219
2220
0
  if (!g_PCSC.pfnSCardTransmit)
2221
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardTransmit");
2222
2223
0
  pCard = PCSC_GetCardHandleData(hCard);
2224
2225
0
  if (!pCard)
2226
0
    return SCARD_E_INVALID_VALUE;
2227
2228
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2229
2230
0
  if (!pcbRecvLength)
2231
0
    return SCARD_E_INVALID_PARAMETER;
2232
2233
0
  if (*pcbRecvLength == SCARD_AUTOALLOCATE)
2234
0
    return SCARD_E_INVALID_PARAMETER;
2235
2236
0
  pcsc_cbRecvLength = (PCSC_DWORD)*pcbRecvLength;
2237
2238
0
  if (!inSendPci.lpcs)
2239
0
  {
2240
0
    PCSC_DWORD dwState = 0;
2241
0
    PCSC_DWORD cbAtrLen = 0;
2242
0
    PCSC_DWORD dwProtocol = 0;
2243
0
    PCSC_DWORD cchReaderLen = 0;
2244
    /**
2245
     * pcsc-lite cannot have a null pioSendPci parameter, unlike WinSCard.
2246
     * Query the current protocol and use default SCARD_IO_REQUEST for it.
2247
     */
2248
0
    status = g_PCSC.pfnSCardStatus(hCard, nullptr, &cchReaderLen, &dwState, &dwProtocol,
2249
0
                                   nullptr, &cbAtrLen);
2250
2251
0
    if (status == SCARD_S_SUCCESS)
2252
0
    {
2253
0
      if (dwProtocol == SCARD_PROTOCOL_T0)
2254
0
        sendPci.pcs = PCSC_SCARD_PCI_T0;
2255
0
      else if (dwProtocol == SCARD_PROTOCOL_T1)
2256
0
        sendPci.pcs = PCSC_SCARD_PCI_T1;
2257
0
      else if (dwProtocol == PCSC_SCARD_PROTOCOL_RAW)
2258
0
        sendPci.pcs = PCSC_SCARD_PCI_RAW;
2259
0
    }
2260
0
  }
2261
0
  else
2262
0
  {
2263
0
    cbExtraBytes = inSendPci.lpcs->cbPciLength - sizeof(SCARD_IO_REQUEST);
2264
0
    sendPci.ps = (PCSC_SCARD_IO_REQUEST*)malloc(sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes);
2265
2266
0
    if (!sendPci.ps)
2267
0
      return SCARD_E_NO_MEMORY;
2268
2269
0
    sendPci.ps->dwProtocol = (PCSC_DWORD)inSendPci.lpcs->dwProtocol;
2270
0
    sendPci.ps->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes;
2271
0
    pbExtraBytes = &(inSendPci.pb)[sizeof(SCARD_IO_REQUEST)];
2272
0
    pcsc_pbExtraBytes = &(sendPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
2273
0
    CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes);
2274
0
  }
2275
2276
0
  if (inRecvPci.lps)
2277
0
  {
2278
0
    cbExtraBytes = inRecvPci.lps->cbPciLength - sizeof(SCARD_IO_REQUEST);
2279
0
    recvPci.ps = (PCSC_SCARD_IO_REQUEST*)malloc(sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes);
2280
2281
0
    if (!recvPci.ps)
2282
0
    {
2283
0
      if (inSendPci.lpcs)
2284
0
        free(sendPci.ps);
2285
2286
0
      return SCARD_E_NO_MEMORY;
2287
0
    }
2288
2289
0
    recvPci.ps->dwProtocol = (PCSC_DWORD)inRecvPci.lps->dwProtocol;
2290
0
    recvPci.ps->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes;
2291
0
    pbExtraBytes = &(inRecvPci.pb)[sizeof(SCARD_IO_REQUEST)];
2292
0
    pcsc_pbExtraBytes = &(recvPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
2293
0
    CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes);
2294
0
  }
2295
2296
0
  status = g_PCSC.pfnSCardTransmit(hCard, sendPci.ps, pbSendBuffer, pcsc_cbSendLength, recvPci.ps,
2297
0
                                   pbRecvBuffer, &pcsc_cbRecvLength);
2298
2299
0
  *pcbRecvLength = (DWORD)pcsc_cbRecvLength;
2300
2301
0
  if (inSendPci.lpcs)
2302
0
    free(sendPci.ps); /* pcsc_pioSendPci is dynamically allocated only when pioSendPci is
2303
                              non null */
2304
2305
0
  if (inRecvPci.lps)
2306
0
  {
2307
0
    cbExtraBytes = inRecvPci.lps->cbPciLength - sizeof(SCARD_IO_REQUEST);
2308
0
    pbExtraBytes = &(inRecvPci.pb)[sizeof(SCARD_IO_REQUEST)];
2309
0
    pcsc_pbExtraBytes = &(recvPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
2310
0
    CopyMemory(pbExtraBytes, pcsc_pbExtraBytes, cbExtraBytes); /* copy extra bytes */
2311
0
    free(recvPci.ps); /* pcsc_pioRecvPci is dynamically allocated only when pioRecvPci is
2312
                              non null */
2313
0
  }
2314
2315
0
  return PCSC_MapErrorCodeToWinSCard(status);
2316
0
}
2317
2318
WINPR_ATTR_NODISCARD static LONG WINAPI
2319
PCSC_SCardGetTransmitCount(SCARDHANDLE hCard, WINPR_ATTR_UNUSED LPDWORD pcTransmitCount)
2320
0
{
2321
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2322
2323
0
  pCard = PCSC_GetCardHandleData(hCard);
2324
2325
0
  if (!pCard)
2326
0
    return SCARD_E_INVALID_VALUE;
2327
2328
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2329
0
  return SCARD_S_SUCCESS;
2330
0
}
2331
2332
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardControl(SCARDHANDLE hCard, DWORD dwControlCode,
2333
                                                          LPCVOID lpInBuffer, DWORD cbInBufferSize,
2334
                                                          LPVOID lpOutBuffer, DWORD cbOutBufferSize,
2335
                                                          LPDWORD lpBytesReturned)
2336
0
{
2337
0
  DWORD IoCtlFunction = 0;
2338
0
  DWORD IoCtlDeviceType = 0;
2339
0
  BOOL getFeatureRequest = FALSE;
2340
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2341
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2342
0
  PCSC_DWORD pcsc_dwControlCode = 0;
2343
0
  PCSC_DWORD pcsc_cbInBufferSize = (PCSC_DWORD)cbInBufferSize;
2344
0
  PCSC_DWORD pcsc_cbOutBufferSize = (PCSC_DWORD)cbOutBufferSize;
2345
0
  PCSC_DWORD pcsc_BytesReturned = 0;
2346
2347
0
  if (!g_PCSC.pfnSCardControl)
2348
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardControl");
2349
2350
0
  pCard = PCSC_GetCardHandleData(hCard);
2351
2352
0
  if (!pCard)
2353
0
    return SCARD_E_INVALID_VALUE;
2354
2355
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2356
  /**
2357
   * PCSCv2 Part 10:
2358
   * http://www.pcscworkgroup.com/specifications/files/pcsc10_v2.02.09.pdf
2359
   *
2360
   * Smart Card Driver IOCTLs:
2361
   * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548988/
2362
   *
2363
   * Converting Windows Feature Request IOCTL code to the pcsc-lite control code:
2364
   * http://musclecard.996296.n3.nabble.com/Converting-Windows-Feature-Request-IOCTL-code-to-the-pcsc-lite-control-code-td4906.html
2365
   */
2366
0
  IoCtlFunction = FUNCTION_FROM_CTL_CODE(dwControlCode);
2367
0
  IoCtlDeviceType = DEVICE_TYPE_FROM_CTL_CODE(dwControlCode);
2368
2369
0
  if (dwControlCode == IOCTL_SMARTCARD_GET_FEATURE_REQUEST)
2370
0
    getFeatureRequest = TRUE;
2371
2372
0
  if (IoCtlDeviceType == FILE_DEVICE_SMARTCARD)
2373
0
    dwControlCode = PCSC_SCARD_CTL_CODE(IoCtlFunction);
2374
2375
0
  pcsc_dwControlCode = (PCSC_DWORD)dwControlCode;
2376
0
  status = g_PCSC.pfnSCardControl(hCard, pcsc_dwControlCode, lpInBuffer, pcsc_cbInBufferSize,
2377
0
                                  lpOutBuffer, pcsc_cbOutBufferSize, &pcsc_BytesReturned);
2378
2379
0
  *lpBytesReturned = (DWORD)pcsc_BytesReturned;
2380
2381
0
  if (getFeatureRequest)
2382
0
  {
2383
0
    UINT32 count = 0;
2384
0
    PCSC_TLV_STRUCTURE* tlv = (PCSC_TLV_STRUCTURE*)lpOutBuffer;
2385
2386
0
    if ((*lpBytesReturned % sizeof(PCSC_TLV_STRUCTURE)) != 0)
2387
0
      return SCARD_E_UNEXPECTED;
2388
2389
0
    count = *lpBytesReturned / sizeof(PCSC_TLV_STRUCTURE);
2390
2391
0
    for (DWORD index = 0; index < count; index++)
2392
0
    {
2393
0
      if (tlv[index].length != 4)
2394
0
        return SCARD_E_UNEXPECTED;
2395
0
    }
2396
0
  }
2397
2398
0
  return PCSC_MapErrorCodeToWinSCard(status);
2399
0
}
2400
2401
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetAttrib_Internal(SCARDHANDLE hCard,
2402
                                                                     DWORD dwAttrId, LPBYTE pbAttr,
2403
                                                                     LPDWORD pcbAttrLen)
2404
0
{
2405
0
  SCARDCONTEXT hContext = 0;
2406
0
  BOOL pcbAttrLenAlloc = FALSE;
2407
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2408
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2409
0
  PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
2410
0
  PCSC_DWORD pcsc_cbAttrLen = 0;
2411
2412
0
  if (!g_PCSC.pfnSCardGetAttrib)
2413
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardGetAttrib");
2414
2415
0
  pCard = PCSC_GetCardHandleData(hCard);
2416
2417
0
  if (!pCard)
2418
0
    return SCARD_E_INVALID_VALUE;
2419
2420
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2421
0
  hContext = PCSC_GetCardContextFromHandle(hCard);
2422
2423
0
  if (!hContext)
2424
0
    return SCARD_E_INVALID_HANDLE;
2425
2426
0
  if (!pcbAttrLen)
2427
0
    return SCARD_E_INVALID_PARAMETER;
2428
2429
0
  if (*pcbAttrLen == SCARD_AUTOALLOCATE)
2430
0
  {
2431
0
    if (!pbAttr)
2432
0
      return SCARD_E_INVALID_PARAMETER;
2433
0
    pcbAttrLenAlloc = TRUE;
2434
0
  }
2435
2436
0
  pcsc_cbAttrLen = pcbAttrLenAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcbAttrLen;
2437
2438
0
  if (pcbAttrLenAlloc && !g_SCardAutoAllocate)
2439
0
  {
2440
0
    pcsc_cbAttrLen = 0;
2441
0
    status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, nullptr, &pcsc_cbAttrLen);
2442
2443
0
    if (status == SCARD_S_SUCCESS)
2444
0
    {
2445
0
      BYTE* tmp = (BYTE*)calloc(1, pcsc_cbAttrLen);
2446
2447
0
      if (!tmp)
2448
0
        return SCARD_E_NO_MEMORY;
2449
2450
0
      status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, tmp, &pcsc_cbAttrLen);
2451
2452
0
      if (status != SCARD_S_SUCCESS)
2453
0
      {
2454
0
        free(tmp);
2455
0
        tmp = nullptr;
2456
0
      }
2457
0
      else
2458
0
        PCSC_AddMemoryBlock(hContext, tmp);
2459
0
      *(BYTE**)pbAttr = tmp;
2460
0
    }
2461
0
  }
2462
0
  else
2463
0
  {
2464
0
    status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, pbAttr, &pcsc_cbAttrLen);
2465
0
  }
2466
2467
0
  if (status == SCARD_S_SUCCESS)
2468
0
    *pcbAttrLen = (DWORD)pcsc_cbAttrLen;
2469
0
  return PCSC_MapErrorCodeToWinSCard(status);
2470
0
}
2471
2472
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetAttrib_FriendlyName(SCARDHANDLE hCard,
2473
                                                                         DWORD dwAttrId,
2474
                                                                         LPBYTE pbAttr,
2475
                                                                         LPDWORD pcbAttrLen)
2476
0
{
2477
0
  char* namePCSC = nullptr;
2478
0
  char* pbAttrA = nullptr;
2479
2480
0
  SCARDCONTEXT hContext = PCSC_GetCardContextFromHandle(hCard);
2481
2482
0
  if (!hContext)
2483
0
    return SCARD_E_INVALID_HANDLE;
2484
2485
0
  if (!pcbAttrLen)
2486
0
    return SCARD_E_INVALID_PARAMETER;
2487
0
  const DWORD cbAttrLen = *pcbAttrLen;
2488
0
  *pcbAttrLen = SCARD_AUTOALLOCATE;
2489
0
  LONG status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
2490
0
                                             (LPBYTE)&pbAttrA, pcbAttrLen);
2491
2492
0
  if (status != SCARD_S_SUCCESS)
2493
0
  {
2494
0
    WCHAR* pbAttrW = nullptr;
2495
2496
0
    *pcbAttrLen = SCARD_AUTOALLOCATE;
2497
0
    status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
2498
0
                                          (LPBYTE)&pbAttrW, pcbAttrLen);
2499
2500
0
    if (status != SCARD_S_SUCCESS)
2501
0
      return status;
2502
2503
0
    namePCSC = ConvertMszWCharNToUtf8Alloc(pbAttrW, *pcbAttrLen, nullptr);
2504
0
    PCSC_SCardFreeMemory_Internal(hContext, pbAttrW);
2505
0
  }
2506
0
  else
2507
0
  {
2508
0
    namePCSC = strndup(pbAttrA, *pcbAttrLen);
2509
2510
0
    if (!namePCSC)
2511
0
      return SCARD_E_NO_MEMORY;
2512
2513
0
    PCSC_SCardFreeMemory_Internal(hContext, pbAttrA);
2514
0
  }
2515
2516
0
  size_t length = strnlen(namePCSC, *pcbAttrLen);
2517
2518
0
  if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W)
2519
0
  {
2520
0
    size_t size = 0;
2521
0
    WCHAR* friendlyNameW = ConvertUtf8NToWCharAlloc(namePCSC, length, &size);
2522
    /* length here includes null terminator */
2523
2524
0
    if (!friendlyNameW)
2525
0
      status = SCARD_E_NO_MEMORY;
2526
0
    else
2527
0
    {
2528
0
      length = size + 1;
2529
2530
0
      if (cbAttrLen == SCARD_AUTOALLOCATE)
2531
0
      {
2532
0
        WINPR_ASSERT(length <= UINT32_MAX / sizeof(WCHAR));
2533
0
        *(WCHAR**)pbAttr = friendlyNameW;
2534
0
        *pcbAttrLen = (UINT32)length * sizeof(WCHAR);
2535
0
        PCSC_AddMemoryBlock(hContext, friendlyNameW);
2536
0
      }
2537
0
      else
2538
0
      {
2539
0
        const size_t wlen = length * sizeof(WCHAR);
2540
0
        *pcbAttrLen = WINPR_ASSERTING_INT_CAST(uint32_t, wlen);
2541
0
        if ((wlen > cbAttrLen) && pbAttr)
2542
0
          status = SCARD_E_INSUFFICIENT_BUFFER;
2543
0
        else if (pbAttr)
2544
0
          CopyMemory(pbAttr, friendlyNameW, (length * sizeof(WCHAR)));
2545
2546
0
        free(friendlyNameW);
2547
0
      }
2548
0
    }
2549
0
    free(namePCSC);
2550
0
  }
2551
0
  else
2552
0
  {
2553
0
    length++; /* Include '\0' in length */
2554
0
    if (cbAttrLen == SCARD_AUTOALLOCATE)
2555
0
    {
2556
0
      *(CHAR**)pbAttr = namePCSC;
2557
0
      WINPR_ASSERT(length <= UINT32_MAX);
2558
0
      *pcbAttrLen = (UINT32)length;
2559
0
      PCSC_AddMemoryBlock(hContext, namePCSC);
2560
0
    }
2561
0
    else
2562
0
    {
2563
0
      *pcbAttrLen = WINPR_ASSERTING_INT_CAST(uint32_t, length);
2564
0
      if ((length > cbAttrLen) && pbAttr)
2565
0
        status = SCARD_E_INSUFFICIENT_BUFFER;
2566
0
      else if (pbAttr)
2567
0
        CopyMemory(pbAttr, namePCSC, length);
2568
2569
0
      free(namePCSC);
2570
0
    }
2571
0
  }
2572
2573
0
  return status;
2574
0
}
2575
2576
static LONG PCSC_ReadDeviceSystemNameGet(WINPR_ATTR_UNUSED SCARDCONTEXT hContext, SCARDHANDLE hCard,
2577
                                         DWORD dwAttrId, LPBYTE* pbAttr, LPDWORD pcbAttrLen)
2578
0
{
2579
0
  PCSC_DWORD cchReader = 0;
2580
0
  PCSC_DWORD cbAtr = 0;
2581
0
  PCSC_DWORD dwState = 0;
2582
0
  PCSC_DWORD dwProtocol = 0;
2583
2584
0
  const PCSC_LONG rc =
2585
0
      g_PCSC.pfnSCardStatus(hCard, nullptr, &cchReader, &dwState, &dwProtocol, nullptr, &cbAtr);
2586
0
  if (rc != SCARD_S_SUCCESS)
2587
0
    return (LONG)rc;
2588
2589
0
  void* tmp = calloc(cchReader + 1, sizeof(CHAR));
2590
0
  if (!tmp)
2591
0
    return SCARD_E_NO_MEMORY;
2592
0
  const PCSC_LONG rc2 =
2593
0
      g_PCSC.pfnSCardStatus(hCard, tmp, &cchReader, &dwState, &dwProtocol, nullptr, &cbAtr);
2594
0
  if (rc2 != SCARD_S_SUCCESS)
2595
0
  {
2596
0
    free(tmp);
2597
0
    return (LONG)rc2;
2598
0
  }
2599
2600
0
  if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_W)
2601
0
  {
2602
0
    size_t len = 0;
2603
0
    void* data = ConvertMszUtf8NToWCharAlloc(tmp, cchReader, &len);
2604
0
    if (!data)
2605
0
    {
2606
0
      free(tmp);
2607
0
      return SCARD_E_NO_MEMORY;
2608
0
    }
2609
0
    len *= sizeof(WCHAR);
2610
2611
0
    cchReader = WINPR_ASSERTING_INT_CAST(PCSC_DWORD, len);
2612
0
    free(tmp);
2613
0
    tmp = data;
2614
0
  }
2615
2616
0
  *pbAttr = tmp;
2617
0
  *pcbAttrLen = WINPR_ASSERTING_INT_CAST(DWORD, cchReader);
2618
0
  return SCARD_S_SUCCESS;
2619
0
}
2620
2621
static LONG PCSC_ReadDeviceSystemName(WINPR_ATTR_UNUSED SCARDCONTEXT hContext, SCARDHANDLE hCard,
2622
                                      DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
2623
0
{
2624
0
  BYTE* tmp = nullptr;
2625
0
  DWORD cbAttrLen = 0;
2626
0
  const LONG rc = PCSC_ReadDeviceSystemNameGet(hContext, hCard, dwAttrId, &tmp, &cbAttrLen);
2627
0
  if (rc != SCARD_S_SUCCESS)
2628
0
    return rc;
2629
2630
0
  if (*pcbAttrLen == SCARD_AUTOALLOCATE)
2631
0
  {
2632
0
    if (!PCSC_AddMemoryBlock(hContext, tmp))
2633
0
    {
2634
0
      free(tmp);
2635
0
      return SCARD_E_NO_MEMORY;
2636
0
    }
2637
2638
0
    *pcbAttrLen = cbAttrLen;
2639
0
    *(BYTE**)pbAttr = tmp;
2640
0
    return SCARD_S_SUCCESS;
2641
0
  }
2642
2643
0
  if (pbAttr)
2644
0
    memcpy(pbAttr, tmp, MIN(cbAttrLen, *pcbAttrLen));
2645
0
  free(tmp);
2646
2647
0
  if (pbAttr)
2648
0
  {
2649
0
    if (cbAttrLen > *pcbAttrLen)
2650
0
      return SCARD_E_INSUFFICIENT_BUFFER;
2651
0
  }
2652
2653
0
  *pcbAttrLen = cbAttrLen;
2654
2655
0
  return SCARD_S_SUCCESS;
2656
0
}
2657
2658
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
2659
                                                            LPBYTE pbAttr, LPDWORD pcbAttrLen)
2660
0
{
2661
0
  DWORD cbAttrLen = 0;
2662
0
  SCARDCONTEXT hContext = 0;
2663
0
  BOOL pcbAttrLenAlloc = FALSE;
2664
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2665
2666
0
  if (nullptr == pcbAttrLen)
2667
0
    return SCARD_E_INVALID_PARAMETER;
2668
2669
0
  cbAttrLen = *pcbAttrLen;
2670
2671
0
  if (*pcbAttrLen == SCARD_AUTOALLOCATE)
2672
0
  {
2673
0
    if (nullptr == pbAttr)
2674
0
      return SCARD_E_INVALID_PARAMETER;
2675
2676
0
    pcbAttrLenAlloc = TRUE;
2677
0
    *(BYTE**)pbAttr = nullptr;
2678
0
  }
2679
0
  else
2680
0
  {
2681
    /**
2682
     * pcsc-lite returns SCARD_E_INSUFFICIENT_BUFFER if the given
2683
     * buffer size is larger than PCSC_MAX_BUFFER_SIZE (264)
2684
     */
2685
0
    if (*pcbAttrLen > PCSC_MAX_BUFFER_SIZE)
2686
0
      *pcbAttrLen = PCSC_MAX_BUFFER_SIZE;
2687
0
  }
2688
2689
0
  hContext = PCSC_GetCardContextFromHandle(hCard);
2690
2691
0
  if (!hContext)
2692
0
    return SCARD_E_INVALID_HANDLE;
2693
2694
0
  if ((dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A) ||
2695
0
      (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W))
2696
0
  {
2697
0
    return PCSC_SCardGetAttrib_FriendlyName(hCard, dwAttrId, pbAttr, pcbAttrLen);
2698
0
  }
2699
2700
0
  status = PCSC_SCardGetAttrib_Internal(hCard, dwAttrId, pbAttr, pcbAttrLen);
2701
2702
0
  if (status == SCARD_S_SUCCESS)
2703
0
  {
2704
0
    if (dwAttrId == SCARD_ATTR_VENDOR_NAME)
2705
0
    {
2706
0
      if (pbAttr)
2707
0
      {
2708
0
        const char* vendorName = nullptr;
2709
2710
        /**
2711
         * pcsc-lite adds a null terminator to the vendor name,
2712
         * while WinSCard doesn't. Strip the null terminator.
2713
         */
2714
2715
0
        if (pcbAttrLenAlloc)
2716
0
          vendorName = (char*)*(BYTE**)pbAttr;
2717
0
        else
2718
0
          vendorName = (char*)pbAttr;
2719
2720
0
        if (vendorName)
2721
0
        {
2722
0
          size_t len = strnlen(vendorName, *pcbAttrLen);
2723
0
          WINPR_ASSERT(len < UINT32_MAX);
2724
0
          *pcbAttrLen = (DWORD)len + 1;
2725
0
        }
2726
0
        else
2727
0
          *pcbAttrLen = 0;
2728
0
      }
2729
0
    }
2730
0
  }
2731
0
  else
2732
0
  {
2733
0
    if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
2734
0
    {
2735
0
      if (!pcbAttrLenAlloc)
2736
0
      {
2737
0
        PCSC_DWORD dwState = 0;
2738
0
        PCSC_DWORD cbAtrLen = 0;
2739
0
        PCSC_DWORD dwProtocol = 0;
2740
0
        PCSC_DWORD cchReaderLen = 0;
2741
0
        status = g_PCSC.pfnSCardStatus(hCard, nullptr, &cchReaderLen, &dwState, &dwProtocol,
2742
0
                                       nullptr, &cbAtrLen);
2743
2744
0
        if (status == SCARD_S_SUCCESS)
2745
0
        {
2746
0
          if ((cbAttrLen < sizeof(DWORD)) && pbAttr)
2747
0
            return SCARD_E_INSUFFICIENT_BUFFER;
2748
2749
0
          if (pbAttr)
2750
0
            *(DWORD*)pbAttr = PCSC_ConvertProtocolsToWinSCard(dwProtocol);
2751
0
          *pcbAttrLen = sizeof(DWORD);
2752
0
        }
2753
0
      }
2754
0
    }
2755
0
    else if (dwAttrId == SCARD_ATTR_CHANNEL_ID)
2756
0
    {
2757
0
      if (!pcbAttrLenAlloc)
2758
0
      {
2759
0
        UINT32 channelType = 0x20; /* USB */
2760
0
        UINT32 channelNumber = 0;
2761
2762
0
        if ((cbAttrLen < sizeof(DWORD)) && pbAttr)
2763
0
          return SCARD_E_INSUFFICIENT_BUFFER;
2764
2765
0
        status = SCARD_S_SUCCESS;
2766
0
        if (pbAttr)
2767
0
          *(DWORD*)pbAttr = (channelType << 16u) | channelNumber;
2768
0
        *pcbAttrLen = sizeof(DWORD);
2769
0
      }
2770
0
    }
2771
0
    else if (dwAttrId == SCARD_ATTR_VENDOR_IFD_TYPE)
2772
0
    {
2773
0
    }
2774
0
    else if (dwAttrId == SCARD_ATTR_DEFAULT_CLK)
2775
0
    {
2776
0
    }
2777
0
    else if (dwAttrId == SCARD_ATTR_DEFAULT_DATA_RATE)
2778
0
    {
2779
0
    }
2780
0
    else if (dwAttrId == SCARD_ATTR_MAX_CLK)
2781
0
    {
2782
0
    }
2783
0
    else if (dwAttrId == SCARD_ATTR_MAX_DATA_RATE)
2784
0
    {
2785
0
    }
2786
0
    else if (dwAttrId == SCARD_ATTR_MAX_IFSD)
2787
0
    {
2788
0
    }
2789
0
    else if (dwAttrId == SCARD_ATTR_CHARACTERISTICS)
2790
0
    {
2791
0
    }
2792
0
    else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_A)
2793
0
    {
2794
0
      status = PCSC_ReadDeviceSystemName(hContext, hCard, dwAttrId, pbAttr, pcbAttrLen);
2795
0
    }
2796
0
    else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_W)
2797
0
    {
2798
0
      status = PCSC_ReadDeviceSystemName(hContext, hCard, dwAttrId, pbAttr, pcbAttrLen);
2799
0
    }
2800
0
    else if (dwAttrId == SCARD_ATTR_DEVICE_UNIT)
2801
0
    {
2802
0
    }
2803
0
    else if (dwAttrId == SCARD_ATTR_POWER_MGMT_SUPPORT)
2804
0
    {
2805
0
    }
2806
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_CLK)
2807
0
    {
2808
0
    }
2809
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_F)
2810
0
    {
2811
0
    }
2812
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_D)
2813
0
    {
2814
0
    }
2815
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_N)
2816
0
    {
2817
0
    }
2818
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_CWT)
2819
0
    {
2820
0
    }
2821
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_BWT)
2822
0
    {
2823
0
    }
2824
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_IFSC)
2825
0
    {
2826
0
    }
2827
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_EBC_ENCODING)
2828
0
    {
2829
0
    }
2830
0
    else if (dwAttrId == SCARD_ATTR_CURRENT_IFSD)
2831
0
    {
2832
0
    }
2833
0
    else if (dwAttrId == SCARD_ATTR_ICC_TYPE_PER_ATR)
2834
0
    {
2835
0
    }
2836
0
  }
2837
2838
0
  return WINPR_ASSERTING_INT_CAST(LONG, status);
2839
0
}
2840
2841
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId,
2842
                                                            LPCBYTE pbAttr, DWORD cbAttrLen)
2843
0
{
2844
0
  PCSC_LONG status = SCARD_S_SUCCESS;
2845
0
  PCSC_SCARDHANDLE* pCard = nullptr;
2846
0
  PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
2847
0
  PCSC_DWORD pcsc_cbAttrLen = (PCSC_DWORD)cbAttrLen;
2848
2849
0
  if (!g_PCSC.pfnSCardSetAttrib)
2850
0
    return PCSC_SCard_LogError("g_PCSC.pfnSCardSetAttrib");
2851
2852
0
  pCard = PCSC_GetCardHandleData(hCard);
2853
2854
0
  if (!pCard)
2855
0
    return SCARD_E_INVALID_VALUE;
2856
2857
0
  PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2858
0
  status = g_PCSC.pfnSCardSetAttrib(hCard, pcsc_dwAttrId, pbAttr, pcsc_cbAttrLen);
2859
0
  return PCSC_MapErrorCodeToWinSCard(status);
2860
0
}
2861
2862
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
2863
0
{
2864
0
  WINPR_UNUSED(pDlgStruc);
2865
2866
0
  return SCARD_E_UNSUPPORTED_FEATURE;
2867
0
}
2868
2869
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
2870
0
{
2871
0
  WINPR_UNUSED(pDlgStruc);
2872
0
  return SCARD_E_UNSUPPORTED_FEATURE;
2873
0
}
2874
2875
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
2876
0
{
2877
0
  WINPR_UNUSED(pDlgStruc);
2878
0
  return SCARD_E_UNSUPPORTED_FEATURE;
2879
0
}
2880
2881
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
2882
0
{
2883
0
  WINPR_UNUSED(pDlgStruc);
2884
0
  return SCARD_E_UNSUPPORTED_FEATURE;
2885
0
}
2886
2887
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardDlgExtendedError(void)
2888
0
{
2889
2890
0
  return SCARD_E_UNSUPPORTED_FEATURE;
2891
0
}
2892
2893
WINPR_ATTR_NODISCARD
2894
static char* card_id_and_name_a(const UUID* CardIdentifier, LPCSTR LookupName)
2895
0
{
2896
0
  WINPR_ASSERT(CardIdentifier);
2897
0
  WINPR_ASSERT(LookupName);
2898
2899
0
  size_t len = strlen(LookupName) + 34;
2900
0
  char* id = malloc(len);
2901
0
  if (!id)
2902
0
    return nullptr;
2903
2904
0
  (void)snprintf(id, len, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X\\%s",
2905
0
                 CardIdentifier->Data1, CardIdentifier->Data2, CardIdentifier->Data3,
2906
0
                 CardIdentifier->Data4[0], CardIdentifier->Data4[1], CardIdentifier->Data4[2],
2907
0
                 CardIdentifier->Data4[3], CardIdentifier->Data4[4], CardIdentifier->Data4[5],
2908
0
                 CardIdentifier->Data4[6], CardIdentifier->Data4[7], LookupName);
2909
0
  return id;
2910
0
}
2911
2912
WINPR_ATTR_NODISCARD
2913
static char* card_id_and_name_w(const UUID* CardIdentifier, LPCWSTR LookupName)
2914
0
{
2915
0
  char* res = nullptr;
2916
0
  char* tmp = ConvertWCharToUtf8Alloc(LookupName, nullptr);
2917
0
  if (!tmp)
2918
0
    return nullptr;
2919
0
  res = card_id_and_name_a(CardIdentifier, tmp);
2920
0
  free(tmp);
2921
0
  return res;
2922
0
}
2923
2924
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardReadCacheA(SCARDCONTEXT hContext,
2925
                                                             UUID* CardIdentifier,
2926
                                                             DWORD FreshnessCounter,
2927
                                                             LPSTR LookupName, PBYTE Data,
2928
                                                             DWORD* DataLen)
2929
0
{
2930
0
  PCSC_CACHE_ITEM* data = nullptr;
2931
0
  PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2932
0
  if (!ctx)
2933
0
    return SCARD_E_INVALID_HANDLE;
2934
2935
0
  char* id = card_id_and_name_a(CardIdentifier, LookupName);
2936
2937
0
  data = HashTable_GetItemValue(ctx->cache, id);
2938
0
  free(id);
2939
0
  if (!data)
2940
0
  {
2941
0
    *DataLen = 0;
2942
0
    return SCARD_W_CACHE_ITEM_NOT_FOUND;
2943
0
  }
2944
2945
0
  if (FreshnessCounter != data->freshness)
2946
0
  {
2947
0
    *DataLen = 0;
2948
0
    return SCARD_W_CACHE_ITEM_STALE;
2949
0
  }
2950
2951
0
  if (*DataLen == SCARD_AUTOALLOCATE)
2952
0
  {
2953
0
    BYTE* mem = calloc(1, data->len);
2954
0
    if (!mem)
2955
0
      return SCARD_E_NO_MEMORY;
2956
2957
0
    if (!PCSC_AddMemoryBlock(hContext, mem))
2958
0
    {
2959
0
      free(mem);
2960
0
      return SCARD_E_NO_MEMORY;
2961
0
    }
2962
2963
0
    memcpy(mem, data->data, data->len);
2964
0
    *(BYTE**)Data = mem;
2965
0
  }
2966
0
  else
2967
0
    memcpy(Data, data->data, data->len);
2968
0
  *DataLen = data->len;
2969
0
  return SCARD_S_SUCCESS;
2970
0
}
2971
2972
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardReadCacheW(SCARDCONTEXT hContext,
2973
                                                             UUID* CardIdentifier,
2974
                                                             DWORD FreshnessCounter,
2975
                                                             LPWSTR LookupName, PBYTE Data,
2976
                                                             DWORD* DataLen)
2977
0
{
2978
0
  PCSC_CACHE_ITEM* data = nullptr;
2979
0
  PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2980
0
  if (!ctx)
2981
0
    return SCARD_E_INVALID_HANDLE;
2982
2983
0
  char* id = card_id_and_name_w(CardIdentifier, LookupName);
2984
2985
0
  data = HashTable_GetItemValue(ctx->cache, id);
2986
0
  free(id);
2987
2988
0
  if (!data)
2989
0
  {
2990
0
    *DataLen = 0;
2991
0
    return SCARD_W_CACHE_ITEM_NOT_FOUND;
2992
0
  }
2993
2994
0
  if (FreshnessCounter != data->freshness)
2995
0
  {
2996
0
    *DataLen = 0;
2997
0
    return SCARD_W_CACHE_ITEM_STALE;
2998
0
  }
2999
3000
0
  if (*DataLen == SCARD_AUTOALLOCATE)
3001
0
  {
3002
0
    BYTE* mem = calloc(1, data->len);
3003
0
    if (!mem)
3004
0
      return SCARD_E_NO_MEMORY;
3005
3006
0
    if (!PCSC_AddMemoryBlock(hContext, mem))
3007
0
    {
3008
0
      free(mem);
3009
0
      return SCARD_E_NO_MEMORY;
3010
0
    }
3011
3012
0
    memcpy(mem, data->data, data->len);
3013
0
    *(BYTE**)Data = mem;
3014
0
  }
3015
0
  else
3016
0
    memcpy(Data, data->data, data->len);
3017
0
  *DataLen = data->len;
3018
0
  return SCARD_S_SUCCESS;
3019
0
}
3020
3021
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardWriteCacheA(SCARDCONTEXT hContext,
3022
                                                              UUID* CardIdentifier,
3023
                                                              DWORD FreshnessCounter,
3024
                                                              LPSTR LookupName, PBYTE Data,
3025
                                                              DWORD DataLen)
3026
0
{
3027
0
  PCSC_CACHE_ITEM* data = nullptr;
3028
0
  PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
3029
0
  char* id = nullptr;
3030
3031
0
  if (!ctx)
3032
0
    return SCARD_E_FILE_NOT_FOUND;
3033
3034
0
  id = card_id_and_name_a(CardIdentifier, LookupName);
3035
3036
0
  if (!id)
3037
0
    return SCARD_E_NO_MEMORY;
3038
3039
0
  data = malloc(sizeof(PCSC_CACHE_ITEM));
3040
0
  if (!data)
3041
0
  {
3042
0
    free(id);
3043
0
    return SCARD_E_NO_MEMORY;
3044
0
  }
3045
0
  data->data = calloc(DataLen, 1);
3046
0
  if (!data->data)
3047
0
  {
3048
0
    free(id);
3049
0
    free(data);
3050
0
    return SCARD_E_NO_MEMORY;
3051
0
  }
3052
0
  data->len = DataLen;
3053
0
  data->freshness = FreshnessCounter;
3054
0
  memcpy(data->data, Data, data->len);
3055
3056
0
  HashTable_Remove(ctx->cache, id);
3057
0
  const BOOL rc = HashTable_Insert(ctx->cache, id, data);
3058
0
  free(id);
3059
3060
0
  if (!rc)
3061
0
  {
3062
0
    pcsc_cache_item_free(data);
3063
0
    return SCARD_E_NO_MEMORY;
3064
0
  }
3065
3066
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
3067
0
  return SCARD_S_SUCCESS;
3068
0
}
3069
3070
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardWriteCacheW(SCARDCONTEXT hContext,
3071
                                                              UUID* CardIdentifier,
3072
                                                              DWORD FreshnessCounter,
3073
                                                              LPWSTR LookupName, PBYTE Data,
3074
                                                              DWORD DataLen)
3075
0
{
3076
0
  PCSC_CACHE_ITEM* data = nullptr;
3077
0
  PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
3078
0
  char* id = nullptr;
3079
0
  if (!ctx)
3080
0
    return SCARD_E_FILE_NOT_FOUND;
3081
3082
0
  id = card_id_and_name_w(CardIdentifier, LookupName);
3083
3084
0
  if (!id)
3085
0
    return SCARD_E_NO_MEMORY;
3086
3087
0
  data = malloc(sizeof(PCSC_CACHE_ITEM));
3088
0
  if (!data)
3089
0
  {
3090
0
    free(id);
3091
0
    return SCARD_E_NO_MEMORY;
3092
0
  }
3093
0
  data->data = malloc(DataLen);
3094
0
  if (!data->data)
3095
0
  {
3096
0
    free(id);
3097
0
    free(data);
3098
0
    return SCARD_E_NO_MEMORY;
3099
0
  }
3100
0
  data->len = DataLen;
3101
0
  data->freshness = FreshnessCounter;
3102
0
  memcpy(data->data, Data, data->len);
3103
3104
0
  HashTable_Remove(ctx->cache, id);
3105
0
  const BOOL rc = HashTable_Insert(ctx->cache, id, data);
3106
0
  free(id);
3107
3108
0
  if (!rc)
3109
0
  {
3110
0
    pcsc_cache_item_free(data);
3111
0
    return SCARD_E_NO_MEMORY;
3112
0
  }
3113
3114
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
3115
0
  return SCARD_S_SUCCESS;
3116
0
}
3117
3118
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetReaderIconA(
3119
    SCARDCONTEXT hContext, LPCSTR szReaderName,
3120
    LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
3121
0
{
3122
0
  WINPR_UNUSED(hContext);
3123
0
  WINPR_UNUSED(szReaderName);
3124
0
  WINPR_UNUSED(pbIcon);
3125
0
  WINPR_ASSERT(pcbIcon);
3126
0
  *pcbIcon = 0;
3127
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3128
0
}
3129
3130
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetReaderIconW(
3131
    SCARDCONTEXT hContext, LPCWSTR szReaderName,
3132
    LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
3133
0
{
3134
0
  WINPR_UNUSED(hContext);
3135
0
  WINPR_UNUSED(szReaderName);
3136
0
  WINPR_UNUSED(pbIcon);
3137
0
  WINPR_ASSERT(pcbIcon);
3138
0
  *pcbIcon = 0;
3139
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3140
0
}
3141
3142
WINPR_ATTR_NODISCARD static LONG WINAPI PCSC_SCardGetDeviceTypeIdA(SCARDCONTEXT hContext,
3143
                                                                   LPCSTR szReaderName,
3144
                                                                   LPDWORD pdwDeviceTypeId)
3145
0
{
3146
0
  WINPR_UNUSED(hContext);
3147
0
  WINPR_UNUSED(szReaderName);
3148
0
  WINPR_UNUSED(pdwDeviceTypeId);
3149
0
  if (pdwDeviceTypeId)
3150
0
    *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
3151
0
  return SCARD_S_SUCCESS;
3152
0
}
3153
3154
WINPR_ATTR_NODISCARD
3155
static LONG WINAPI PCSC_SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
3156
                                              LPDWORD pdwDeviceTypeId)
3157
0
{
3158
0
  WINPR_UNUSED(hContext);
3159
0
  WINPR_UNUSED(szReaderName);
3160
0
  if (pdwDeviceTypeId)
3161
0
    *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
3162
0
  return SCARD_S_SUCCESS;
3163
0
}
3164
3165
WINPR_ATTR_NODISCARD
3166
static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdA(
3167
    SCARDCONTEXT hContext, LPCSTR szReaderName,
3168
    LPSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3169
    LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3170
0
{
3171
0
  WINPR_UNUSED(hContext);
3172
0
  WINPR_UNUSED(szReaderName);
3173
0
  WINPR_UNUSED(szDeviceInstanceId);
3174
0
  WINPR_UNUSED(pcchDeviceInstanceId);
3175
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3176
0
}
3177
3178
WINPR_ATTR_NODISCARD
3179
static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdW(
3180
    SCARDCONTEXT hContext, LPCWSTR szReaderName,
3181
    LPWSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3182
    LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3183
0
{
3184
0
  WINPR_UNUSED(hContext);
3185
0
  WINPR_UNUSED(szReaderName);
3186
0
  WINPR_UNUSED(szDeviceInstanceId);
3187
0
  WINPR_UNUSED(pcchDeviceInstanceId);
3188
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3189
0
}
3190
3191
WINPR_ATTR_NODISCARD
3192
static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdA(
3193
    SCARDCONTEXT hContext, LPCSTR szDeviceInstanceId,
3194
    LPSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3195
    LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3196
0
{
3197
0
  WINPR_UNUSED(hContext);
3198
0
  WINPR_UNUSED(szDeviceInstanceId);
3199
0
  WINPR_UNUSED(mszReaders);
3200
0
  WINPR_UNUSED(pcchReaders);
3201
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3202
0
}
3203
3204
WINPR_ATTR_NODISCARD
3205
static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdW(
3206
    SCARDCONTEXT hContext, LPCWSTR szDeviceInstanceId,
3207
    LPWSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3208
    LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3209
0
{
3210
0
  WINPR_UNUSED(hContext);
3211
0
  WINPR_UNUSED(szDeviceInstanceId);
3212
0
  WINPR_UNUSED(mszReaders);
3213
0
  WINPR_UNUSED(pcchReaders);
3214
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3215
0
}
3216
3217
WINPR_ATTR_NODISCARD
3218
static LONG WINAPI PCSC_SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
3219
0
{
3220
3221
0
  WINPR_UNUSED(hContext);
3222
0
  WINPR_UNUSED(dwEvent);
3223
0
  return SCARD_E_UNSUPPORTED_FEATURE;
3224
0
}
3225
3226
#ifdef __MACOSX__
3227
WINPR_ATTR_NODISCARD
3228
unsigned int determineMacOSXVersion(void)
3229
{
3230
  int mib[2];
3231
  size_t len = 0;
3232
  char* kernelVersion = nullptr;
3233
  char* tok = nullptr;
3234
  unsigned int version = 0;
3235
  long majorVersion = 0;
3236
  long minorVersion = 0;
3237
  long patchVersion = 0;
3238
  int count = 0;
3239
  char* context = nullptr;
3240
  mib[0] = CTL_KERN;
3241
  mib[1] = KERN_OSRELEASE;
3242
3243
  if (sysctl(mib, 2, nullptr, &len, nullptr, 0) != 0)
3244
    return 0;
3245
3246
  kernelVersion = calloc(len, sizeof(char));
3247
3248
  if (!kernelVersion)
3249
    return 0;
3250
3251
  if (sysctl(mib, 2, kernelVersion, &len, nullptr, 0) != 0)
3252
  {
3253
    free(kernelVersion);
3254
    return 0;
3255
  }
3256
3257
  tok = strtok_s(kernelVersion, ".", &context);
3258
  errno = 0;
3259
3260
  while (tok)
3261
  {
3262
    switch (count)
3263
    {
3264
      case 0:
3265
        majorVersion = strtol(tok, nullptr, 0);
3266
3267
        if (errno != 0)
3268
          goto fail;
3269
3270
        break;
3271
3272
      case 1:
3273
        minorVersion = strtol(tok, nullptr, 0);
3274
3275
        if (errno != 0)
3276
          goto fail;
3277
3278
        break;
3279
3280
      case 2:
3281
        patchVersion = strtol(tok, nullptr, 0);
3282
3283
        if (errno != 0)
3284
          goto fail;
3285
3286
        break;
3287
    }
3288
3289
    tok = strtok_s(nullptr, ".", &context);
3290
    count++;
3291
  }
3292
3293
  /**
3294
   * Source : http://en.wikipedia.org/wiki/Darwin_(operating_system)
3295
   **/
3296
  if (majorVersion < 5)
3297
  {
3298
    if (minorVersion < 4)
3299
      version = 0x10000000;
3300
    else
3301
      version = 0x10010000;
3302
  }
3303
  else
3304
  {
3305
    switch (majorVersion)
3306
    {
3307
      case 5:
3308
        version = 0x10010000;
3309
        break;
3310
3311
      case 6:
3312
        version = 0x10020000;
3313
        break;
3314
3315
      case 7:
3316
        version = 0x10030000;
3317
        break;
3318
3319
      case 8:
3320
        version = 0x10040000;
3321
        break;
3322
3323
      case 9:
3324
        version = 0x10050000;
3325
        break;
3326
3327
      case 10:
3328
        version = 0x10060000;
3329
        break;
3330
3331
      case 11:
3332
        version = 0x10070000;
3333
        break;
3334
3335
      case 12:
3336
        version = 0x10080000;
3337
        break;
3338
3339
      case 13:
3340
        version = 0x10090000;
3341
        break;
3342
3343
      default:
3344
        version = 0x10100000;
3345
        break;
3346
    }
3347
3348
    version |= (minorVersion << 8) | (patchVersion);
3349
  }
3350
3351
fail:
3352
  free(kernelVersion);
3353
  return version;
3354
}
3355
#endif
3356
3357
static const SCardApiFunctionTable PCSC_SCardApiFunctionTable = {
3358
  0, /* dwVersion */
3359
  0, /* dwFlags */
3360
3361
  PCSC_SCardEstablishContext,                 /* SCardEstablishContext */
3362
  PCSC_SCardReleaseContext,                   /* SCardReleaseContext */
3363
  PCSC_SCardIsValidContext,                   /* SCardIsValidContext */
3364
  PCSC_SCardListReaderGroupsA,                /* SCardListReaderGroupsA */
3365
  PCSC_SCardListReaderGroupsW,                /* SCardListReaderGroupsW */
3366
  PCSC_SCardListReadersA,                     /* SCardListReadersA */
3367
  PCSC_SCardListReadersW,                     /* SCardListReadersW */
3368
  PCSC_SCardListCardsA,                       /* SCardListCardsA */
3369
  PCSC_SCardListCardsW,                       /* SCardListCardsW */
3370
  PCSC_SCardListInterfacesA,                  /* SCardListInterfacesA */
3371
  PCSC_SCardListInterfacesW,                  /* SCardListInterfacesW */
3372
  PCSC_SCardGetProviderIdA,                   /* SCardGetProviderIdA */
3373
  PCSC_SCardGetProviderIdW,                   /* SCardGetProviderIdW */
3374
  PCSC_SCardGetCardTypeProviderNameA,         /* SCardGetCardTypeProviderNameA */
3375
  PCSC_SCardGetCardTypeProviderNameW,         /* SCardGetCardTypeProviderNameW */
3376
  PCSC_SCardIntroduceReaderGroupA,            /* SCardIntroduceReaderGroupA */
3377
  PCSC_SCardIntroduceReaderGroupW,            /* SCardIntroduceReaderGroupW */
3378
  PCSC_SCardForgetReaderGroupA,               /* SCardForgetReaderGroupA */
3379
  PCSC_SCardForgetReaderGroupW,               /* SCardForgetReaderGroupW */
3380
  PCSC_SCardIntroduceReaderA,                 /* SCardIntroduceReaderA */
3381
  PCSC_SCardIntroduceReaderW,                 /* SCardIntroduceReaderW */
3382
  PCSC_SCardForgetReaderA,                    /* SCardForgetReaderA */
3383
  PCSC_SCardForgetReaderW,                    /* SCardForgetReaderW */
3384
  PCSC_SCardAddReaderToGroupA,                /* SCardAddReaderToGroupA */
3385
  PCSC_SCardAddReaderToGroupW,                /* SCardAddReaderToGroupW */
3386
  PCSC_SCardRemoveReaderFromGroupA,           /* SCardRemoveReaderFromGroupA */
3387
  PCSC_SCardRemoveReaderFromGroupW,           /* SCardRemoveReaderFromGroupW */
3388
  PCSC_SCardIntroduceCardTypeA,               /* SCardIntroduceCardTypeA */
3389
  PCSC_SCardIntroduceCardTypeW,               /* SCardIntroduceCardTypeW */
3390
  PCSC_SCardSetCardTypeProviderNameA,         /* SCardSetCardTypeProviderNameA */
3391
  PCSC_SCardSetCardTypeProviderNameW,         /* SCardSetCardTypeProviderNameW */
3392
  PCSC_SCardForgetCardTypeA,                  /* SCardForgetCardTypeA */
3393
  PCSC_SCardForgetCardTypeW,                  /* SCardForgetCardTypeW */
3394
  PCSC_SCardFreeMemory,                       /* SCardFreeMemory */
3395
  PCSC_SCardAccessStartedEvent,               /* SCardAccessStartedEvent */
3396
  PCSC_SCardReleaseStartedEvent,              /* SCardReleaseStartedEvent */
3397
  PCSC_SCardLocateCardsA,                     /* SCardLocateCardsA */
3398
  PCSC_SCardLocateCardsW,                     /* SCardLocateCardsW */
3399
  PCSC_SCardLocateCardsByATRA,                /* SCardLocateCardsByATRA */
3400
  PCSC_SCardLocateCardsByATRW,                /* SCardLocateCardsByATRW */
3401
  PCSC_SCardGetStatusChangeA,                 /* SCardGetStatusChangeA */
3402
  PCSC_SCardGetStatusChangeW,                 /* SCardGetStatusChangeW */
3403
  PCSC_SCardCancel,                           /* SCardCancel */
3404
  PCSC_SCardConnectA,                         /* SCardConnectA */
3405
  PCSC_SCardConnectW,                         /* SCardConnectW */
3406
  PCSC_SCardReconnect,                        /* SCardReconnect */
3407
  PCSC_SCardDisconnect,                       /* SCardDisconnect */
3408
  PCSC_SCardBeginTransaction,                 /* SCardBeginTransaction */
3409
  PCSC_SCardEndTransaction,                   /* SCardEndTransaction */
3410
  PCSC_SCardCancelTransaction,                /* SCardCancelTransaction */
3411
  PCSC_SCardState,                            /* SCardState */
3412
  PCSC_SCardStatusA,                          /* SCardStatusA */
3413
  PCSC_SCardStatusW,                          /* SCardStatusW */
3414
  PCSC_SCardTransmit,                         /* SCardTransmit */
3415
  PCSC_SCardGetTransmitCount,                 /* SCardGetTransmitCount */
3416
  PCSC_SCardControl,                          /* SCardControl */
3417
  PCSC_SCardGetAttrib,                        /* SCardGetAttrib */
3418
  PCSC_SCardSetAttrib,                        /* SCardSetAttrib */
3419
  PCSC_SCardUIDlgSelectCardA,                 /* SCardUIDlgSelectCardA */
3420
  PCSC_SCardUIDlgSelectCardW,                 /* SCardUIDlgSelectCardW */
3421
  PCSC_GetOpenCardNameA,                      /* GetOpenCardNameA */
3422
  PCSC_GetOpenCardNameW,                      /* GetOpenCardNameW */
3423
  PCSC_SCardDlgExtendedError,                 /* SCardDlgExtendedError */
3424
  PCSC_SCardReadCacheA,                       /* SCardReadCacheA */
3425
  PCSC_SCardReadCacheW,                       /* SCardReadCacheW */
3426
  PCSC_SCardWriteCacheA,                      /* SCardWriteCacheA */
3427
  PCSC_SCardWriteCacheW,                      /* SCardWriteCacheW */
3428
  PCSC_SCardGetReaderIconA,                   /* SCardGetReaderIconA */
3429
  PCSC_SCardGetReaderIconW,                   /* SCardGetReaderIconW */
3430
  PCSC_SCardGetDeviceTypeIdA,                 /* SCardGetDeviceTypeIdA */
3431
  PCSC_SCardGetDeviceTypeIdW,                 /* SCardGetDeviceTypeIdW */
3432
  PCSC_SCardGetReaderDeviceInstanceIdA,       /* SCardGetReaderDeviceInstanceIdA */
3433
  PCSC_SCardGetReaderDeviceInstanceIdW,       /* SCardGetReaderDeviceInstanceIdW */
3434
  PCSC_SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
3435
  PCSC_SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
3436
  PCSC_SCardAudit                             /* SCardAudit */
3437
};
3438
3439
const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void)
3440
0
{
3441
0
  return &PCSC_SCardApiFunctionTable;
3442
0
}
3443
3444
int PCSC_InitializeSCardApi(void)
3445
0
{
3446
  /* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
3447
0
  SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
3448
#ifdef __MACOSX__
3449
  g_PCSCModule = LoadLibraryX("/System/Library/Frameworks/PCSC.framework/PCSC");
3450
  OSXVersion = determineMacOSXVersion();
3451
3452
  if (OSXVersion == 0)
3453
    return -1;
3454
3455
#else
3456
0
  g_PCSCModule = LoadLibraryA("libpcsclite.so.1");
3457
3458
0
  if (!g_PCSCModule)
3459
0
    g_PCSCModule = LoadLibraryA("libpcsclite.so");
3460
3461
0
#endif
3462
3463
0
  if (!g_PCSCModule)
3464
0
    return -1;
3465
3466
    /* symbols defined in winpr/smartcard.h, might pose an issue with the GetProcAddress macro
3467
     * below. therefore undefine them here */
3468
0
#undef SCardListReaderGroups
3469
0
#undef SCardListReaders
3470
0
#undef SCardListCards
3471
0
#undef SCardListInterfaces
3472
0
#undef SCardGetProviderId
3473
0
#undef SCardGetCardTypeProviderName
3474
0
#undef SCardIntroduceReaderGroup
3475
0
#undef SCardForgetReaderGroup
3476
0
#undef SCardIntroduceReader
3477
0
#undef SCardForgetReader
3478
0
#undef SCardAddReaderToGroup
3479
0
#undef SCardRemoveReaderFromGroup
3480
0
#undef SCardIntroduceCardType
3481
0
#undef SCardSetCardTypeProviderName
3482
0
#undef SCardForgetCardType
3483
0
#undef SCardLocateCards
3484
0
#undef SCardLocateCardsByATR
3485
0
#undef SCardGetStatusChange
3486
0
#undef SCardConnect
3487
0
#undef SCardStatus
3488
0
#undef SCardUIDlgSelectCard
3489
0
#undef GetOpenCardName
3490
0
#undef SCardReadCache
3491
0
#undef SCardWriteCache
3492
0
#undef SCardGetReaderIcon
3493
0
#undef SCardGetDeviceTypeId
3494
0
#undef SCardGetReaderDeviceInstanceId
3495
0
#undef SCardListReadersWithDeviceInstanceId
3496
3497
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEstablishContext);
3498
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReleaseContext);
3499
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardIsValidContext);
3500
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardConnect);
3501
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReconnect);
3502
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardDisconnect);
3503
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardBeginTransaction);
3504
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEndTransaction);
3505
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardStatus);
3506
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetStatusChange);
3507
3508
#ifdef __MACOSX__
3509
3510
  if (OSXVersion >= 0x10050600)
3511
  {
3512
    WINSCARD_LOAD_PROC_EX(g_PCSCModule, g_PCSC, SCardControl, SCardControl132);
3513
  }
3514
  else
3515
  {
3516
    WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3517
  }
3518
#else
3519
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3520
0
#endif
3521
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardTransmit);
3522
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaderGroups);
3523
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaders);
3524
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardCancel);
3525
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetAttrib);
3526
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardSetAttrib);
3527
0
  g_PCSC.pfnSCardFreeMemory = nullptr;
3528
0
#ifndef __APPLE__
3529
0
  WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardFreeMemory);
3530
0
#endif
3531
3532
0
  if (g_PCSC.pfnSCardFreeMemory)
3533
0
    g_SCardAutoAllocate = TRUE;
3534
3535
#ifdef DISABLE_PCSC_SCARD_AUTOALLOCATE
3536
  g_PCSC.pfnSCardFreeMemory = nullptr;
3537
  g_SCardAutoAllocate = FALSE;
3538
#endif
3539
#ifdef __APPLE__
3540
  g_PnP_Notification = FALSE;
3541
#endif
3542
0
  return 1;
3543
0
}
3544
3545
#endif