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