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