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