Coverage Report

Created: 2026-10-15 06:26

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