Coverage Report

Created: 2026-02-26 06:54

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