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