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