Coverage Report

Created: 2024-09-08 06:16

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