Coverage Report

Created: 2023-09-25 06:56

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