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 = NULL;
221static PCSCFunctionTable g_PCSC = { 0 };
222
223static HANDLE g_StartedEvent = NULL;
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 = NULL;
234static wListDictionary* g_CardContexts = NULL;
235static wListDictionary* g_MemoryBlocks = NULL;
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=NULL", 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 = NULL;
373
374 if (!g_CardContexts)
375 return NULL;
376
377 pContext = (PCSC_SCARDCONTEXT*)ListDictionary_GetItemValue(g_CardContexts, (void*)hContext);
378
379 if (!pContext)
380 return NULL;
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 = NULL;
396 pContext = (PCSC_SCARDCONTEXT*)calloc(1, sizeof(PCSC_SCARDCONTEXT));
397
398 if (!pContext)
399 return NULL;
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 NULL;
434}
435
436static void PCSC_ReleaseCardContext(SCARDCONTEXT hContext)
437{
438 PCSC_SCARDCONTEXT* pContext = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
490
491 if (!g_CardHandles)
492 return NULL;
493
494 pCard = (PCSC_SCARDHANDLE*)ListDictionary_GetItemValue(g_CardHandles, (void*)hCard);
495
496 if (!pCard)
497 return NULL;
498
499 return pCard;
500}
501
502static SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard)
503{
504 PCSC_SCARDHANDLE* pCard = NULL;
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 = NULL;
517 PCSC_SCARDCONTEXT* pContext = NULL;
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 = NULL;
570 PCSC_SCARDCONTEXT* pContext = NULL;
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 = NULL;
618 PCSC_SCARDCONTEXT* pContext = NULL;
619 pContext = PCSC_GetCardContextData(hSharedContext);
620
621 if (!pContext)
622 {
623 WLog_ERR(TAG, "PCSC_ConnectCardHandle: null pContext!");
624 return NULL;
625 }
626
627 pCard = (PCSC_SCARDHANDLE*)calloc(1, sizeof(PCSC_SCARDHANDLE));
628
629 if (!pCard)
630 return NULL;
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 NULL;
650}
651
652static void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
653{
654 PCSC_SCARDHANDLE* pCard = NULL;
655 PCSC_SCARDCONTEXT* pContext = NULL;
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 NULL;
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, NULL, &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 = NULL;
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 = NULL;
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 = NULL; /* 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, NULL, &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 = NULL;
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, NULL, NULL, &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 = NULL;
969 LPSTR mszReadersA = NULL;
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, NULL, NULL, &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, NULL);
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 NULL;
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 = NULL;
1069 DWORD outputLen = 1;
1070 CHAR* output = NULL;
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 = NULL;
1122 DWORD outputLen = 1;
1123 WCHAR* output = NULL;
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, NULL, NULL, &hContext);
1446
1447 if (status != SCARD_S_SUCCESS)
1448 return NULL;
1449
1450 status = PCSC_SCardReleaseContext(hContext);
1451
1452 if (status != SCARD_S_SUCCESS)
1453 return NULL;
1454
1455 if (!g_StartedEvent)
1456 {
1457 if (!(g_StartedEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
1458 return NULL;
1459
1460 if (!SetEvent(g_StartedEvent))
1461 {
1462 (void)CloseHandle(g_StartedEvent);
1463 return NULL;
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 = NULL;
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 = NULL;
1534 PCSC_DWORD cMappedReaders = 0;
1535 PCSC_SCARD_READERSTATE* states = NULL;
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 = NULL;
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, NULL);
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 = NULL;
1713 PCSC_LONG status = SCARD_S_SUCCESS;
1714 PCSC_SCARDHANDLE* pCard = NULL;
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) ? TRUE : FALSE;
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 = NULL;
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, NULL);
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) ? TRUE : FALSE;
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 = NULL;
1847 PCSC_SCARDCONTEXT* pContext = NULL;
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 = NULL;
1875 PCSC_SCARDCONTEXT* pContext = NULL;
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 = NULL;
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 = NULL;
1929 LPBYTE tATR = NULL;
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 =
1946 g_PCSC.pfnSCardStatus(hCard, NULL, &pcsc_cchReaderLen, NULL, NULL, NULL, &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 == NULL)
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 = NULL;
2079 PCSC_LONG status = SCARD_S_SUCCESS;
2080 PCSC_SCARDHANDLE* pCard = NULL;
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 = NULL;
2141 PCSC_DWORD cbExtraBytes = 0;
2142 BYTE* pbExtraBytes = NULL;
2143 BYTE* pcsc_pbExtraBytes = NULL;
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 = NULL;
2156 recvPci.ps = NULL;
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, NULL, &cchReaderLen, &dwState, &dwProtocol, NULL,
2189 &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 = NULL;
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 = NULL;
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 = NULL;
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, NULL, &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 = NULL;
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 = NULL;
2415 char* pbAttrA = NULL;
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 = NULL;
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, NULL);
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_ReadDeviceSystemName(WINPR_ATTR_UNUSED SCARDCONTEXT hContext, SCARDHANDLE hCard,
2514 DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
2515{
2516 /* Get reader name from SCardStatus */
2517 PCSC_DWORD dwState = 0;
2518 PCSC_DWORD dwProtocol = 0;
2519 LONG status = 0;
2520
2521 DWORD cbAttrLen = *pcbAttrLen;
2522 if (cbAttrLen == SCARD_AUTOALLOCATE)
2523 return SCARD_E_UNEXPECTED;
2524
2525 if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_W)
2526 cbAttrLen /= sizeof(WCHAR);
2527
2528 PCSC_DWORD cbAtr = 0;
2529 PCSC_DWORD cchReader = cbAttrLen;
2530 const PCSC_LONG rc = g_PCSC.pfnSCardStatus(hCard, (LPSTR)pbAttr, &cchReader, &dwState,
2531 &dwProtocol, NULL, &cbAtr);
2532
2533 *pcbAttrLen = WINPR_ASSERTING_INT_CAST(DWORD, cchReader);
2534 status = WINPR_ASSERTING_INT_CAST(LONG, rc);
2535 if (status != SCARD_S_SUCCESS)
2536 return status;
2537
2538 if (cchReader > cbAttrLen)
2539 return SCARD_E_INSUFFICIENT_BUFFER;
2540
2541 if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_W)
2542 {
2543 size_t wlen = 0;
2544 WCHAR* tmp = ConvertMszUtf8NToWCharAlloc((LPSTR)pbAttr, cchReader, &wlen);
2545 if (!tmp)
2546 return SCARD_E_NO_MEMORY;
2547
2548 /* utf-8 to utf-16 is no simple y=x*2, check again if the size fits. */
2549 if (wlen > cbAttrLen)
2550 {
2551 free(tmp);
2552 return SCARD_E_INSUFFICIENT_BUFFER;
2553 }
2554 *pcbAttrLen = WINPR_ASSERTING_INT_CAST(DWORD, MIN(wlen, cchReader) * sizeof(WCHAR));
2555 memcpy(pbAttr, tmp, *pcbAttrLen);
2556 free(tmp);
2557 }
2558
2559 return status;
2560}
2561
2562static LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2563 LPDWORD pcbAttrLen)
2564{
2565 DWORD cbAttrLen = 0;
2566 SCARDCONTEXT hContext = 0;
2567 BOOL pcbAttrLenAlloc = FALSE;
2568 PCSC_LONG status = SCARD_S_SUCCESS;
2569
2570 if (NULL == pcbAttrLen)
2571 return SCARD_E_INVALID_PARAMETER;
2572
2573 cbAttrLen = *pcbAttrLen;
2574
2575 if (*pcbAttrLen == SCARD_AUTOALLOCATE)
2576 {
2577 if (NULL == pbAttr)
2578 return SCARD_E_INVALID_PARAMETER;
2579
2580 pcbAttrLenAlloc = TRUE;
2581 *(BYTE**)pbAttr = NULL;
2582 }
2583 else
2584 {
2589 if (*pcbAttrLen > PCSC_MAX_BUFFER_SIZE)
2590 *pcbAttrLen = PCSC_MAX_BUFFER_SIZE;
2591 }
2592
2593 hContext = PCSC_GetCardContextFromHandle(hCard);
2594
2595 if (!hContext)
2596 return SCARD_E_INVALID_HANDLE;
2597
2598 if ((dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A) ||
2599 (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W))
2600 {
2601 return PCSC_SCardGetAttrib_FriendlyName(hCard, dwAttrId, pbAttr, pcbAttrLen);
2602 }
2603
2604 status = PCSC_SCardGetAttrib_Internal(hCard, dwAttrId, pbAttr, pcbAttrLen);
2605
2606 if (status == SCARD_S_SUCCESS)
2607 {
2608 if (dwAttrId == SCARD_ATTR_VENDOR_NAME)
2609 {
2610 if (pbAttr)
2611 {
2612 const char* vendorName = NULL;
2613
2619 if (pcbAttrLenAlloc)
2620 vendorName = (char*)*(BYTE**)pbAttr;
2621 else
2622 vendorName = (char*)pbAttr;
2623
2624 if (vendorName)
2625 {
2626 size_t len = strnlen(vendorName, *pcbAttrLen);
2627 WINPR_ASSERT(len < UINT32_MAX);
2628 *pcbAttrLen = (DWORD)len + 1;
2629 }
2630 else
2631 *pcbAttrLen = 0;
2632 }
2633 }
2634 }
2635 else
2636 {
2637 if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
2638 {
2639 if (!pcbAttrLenAlloc)
2640 {
2641 PCSC_DWORD dwState = 0;
2642 PCSC_DWORD cbAtrLen = 0;
2643 PCSC_DWORD dwProtocol = 0;
2644 PCSC_DWORD cchReaderLen = 0;
2645 status = g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState, &dwProtocol,
2646 NULL, &cbAtrLen);
2647
2648 if (status == SCARD_S_SUCCESS)
2649 {
2650 if ((cbAttrLen < sizeof(DWORD)) && pbAttr)
2651 return SCARD_E_INSUFFICIENT_BUFFER;
2652
2653 if (pbAttr)
2654 *(DWORD*)pbAttr = PCSC_ConvertProtocolsToWinSCard(dwProtocol);
2655 *pcbAttrLen = sizeof(DWORD);
2656 }
2657 }
2658 }
2659 else if (dwAttrId == SCARD_ATTR_CHANNEL_ID)
2660 {
2661 if (!pcbAttrLenAlloc)
2662 {
2663 UINT32 channelType = 0x20; /* USB */
2664 UINT32 channelNumber = 0;
2665
2666 if ((cbAttrLen < sizeof(DWORD)) && pbAttr)
2667 return SCARD_E_INSUFFICIENT_BUFFER;
2668
2669 status = SCARD_S_SUCCESS;
2670 if (pbAttr)
2671 *(DWORD*)pbAttr = (channelType << 16u) | channelNumber;
2672 *pcbAttrLen = sizeof(DWORD);
2673 }
2674 }
2675 else if (dwAttrId == SCARD_ATTR_VENDOR_IFD_TYPE)
2676 {
2677 }
2678 else if (dwAttrId == SCARD_ATTR_DEFAULT_CLK)
2679 {
2680 }
2681 else if (dwAttrId == SCARD_ATTR_DEFAULT_DATA_RATE)
2682 {
2683 }
2684 else if (dwAttrId == SCARD_ATTR_MAX_CLK)
2685 {
2686 }
2687 else if (dwAttrId == SCARD_ATTR_MAX_DATA_RATE)
2688 {
2689 }
2690 else if (dwAttrId == SCARD_ATTR_MAX_IFSD)
2691 {
2692 }
2693 else if (dwAttrId == SCARD_ATTR_CHARACTERISTICS)
2694 {
2695 }
2696 else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_A)
2697 {
2698 if (!pcbAttrLenAlloc)
2699 status = PCSC_ReadDeviceSystemName(hContext, hCard, dwAttrId, pbAttr, pcbAttrLen);
2700 }
2701 else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_W)
2702 {
2703 if (!pcbAttrLenAlloc)
2704 status = PCSC_ReadDeviceSystemName(hContext, hCard, dwAttrId, pbAttr, pcbAttrLen);
2705 }
2706 else if (dwAttrId == SCARD_ATTR_DEVICE_UNIT)
2707 {
2708 }
2709 else if (dwAttrId == SCARD_ATTR_POWER_MGMT_SUPPORT)
2710 {
2711 }
2712 else if (dwAttrId == SCARD_ATTR_CURRENT_CLK)
2713 {
2714 }
2715 else if (dwAttrId == SCARD_ATTR_CURRENT_F)
2716 {
2717 }
2718 else if (dwAttrId == SCARD_ATTR_CURRENT_D)
2719 {
2720 }
2721 else if (dwAttrId == SCARD_ATTR_CURRENT_N)
2722 {
2723 }
2724 else if (dwAttrId == SCARD_ATTR_CURRENT_CWT)
2725 {
2726 }
2727 else if (dwAttrId == SCARD_ATTR_CURRENT_BWT)
2728 {
2729 }
2730 else if (dwAttrId == SCARD_ATTR_CURRENT_IFSC)
2731 {
2732 }
2733 else if (dwAttrId == SCARD_ATTR_CURRENT_EBC_ENCODING)
2734 {
2735 }
2736 else if (dwAttrId == SCARD_ATTR_CURRENT_IFSD)
2737 {
2738 }
2739 else if (dwAttrId == SCARD_ATTR_ICC_TYPE_PER_ATR)
2740 {
2741 }
2742 }
2743
2744 return WINPR_ASSERTING_INT_CAST(LONG, status);
2745}
2746
2747static LONG WINAPI PCSC_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2748 DWORD cbAttrLen)
2749{
2750 PCSC_LONG status = SCARD_S_SUCCESS;
2751 PCSC_SCARDHANDLE* pCard = NULL;
2752 PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
2753 PCSC_DWORD pcsc_cbAttrLen = (PCSC_DWORD)cbAttrLen;
2754
2755 if (!g_PCSC.pfnSCardSetAttrib)
2756 return PCSC_SCard_LogError("g_PCSC.pfnSCardSetAttrib");
2757
2758 pCard = PCSC_GetCardHandleData(hCard);
2759
2760 if (!pCard)
2761 return SCARD_E_INVALID_VALUE;
2762
2763 PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2764 status = g_PCSC.pfnSCardSetAttrib(hCard, pcsc_dwAttrId, pbAttr, pcsc_cbAttrLen);
2765 return PCSC_MapErrorCodeToWinSCard(status);
2766}
2767
2768static LONG WINAPI PCSC_SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
2769{
2770 WINPR_UNUSED(pDlgStruc);
2771
2772 return SCARD_E_UNSUPPORTED_FEATURE;
2773}
2774
2775static LONG WINAPI PCSC_SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
2776{
2777 WINPR_UNUSED(pDlgStruc);
2778 return SCARD_E_UNSUPPORTED_FEATURE;
2779}
2780
2781static LONG WINAPI PCSC_GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
2782{
2783 WINPR_UNUSED(pDlgStruc);
2784 return SCARD_E_UNSUPPORTED_FEATURE;
2785}
2786
2787static LONG WINAPI PCSC_GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
2788{
2789 WINPR_UNUSED(pDlgStruc);
2790 return SCARD_E_UNSUPPORTED_FEATURE;
2791}
2792
2793static LONG WINAPI PCSC_SCardDlgExtendedError(void)
2794{
2795
2796 return SCARD_E_UNSUPPORTED_FEATURE;
2797}
2798
2799static char* card_id_and_name_a(const UUID* CardIdentifier, LPCSTR LookupName)
2800{
2801 WINPR_ASSERT(CardIdentifier);
2802 WINPR_ASSERT(LookupName);
2803
2804 size_t len = strlen(LookupName) + 34;
2805 char* id = malloc(len);
2806 if (!id)
2807 return NULL;
2808
2809 (void)snprintf(id, len, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X\\%s",
2810 CardIdentifier->Data1, CardIdentifier->Data2, CardIdentifier->Data3,
2811 CardIdentifier->Data4[0], CardIdentifier->Data4[1], CardIdentifier->Data4[2],
2812 CardIdentifier->Data4[3], CardIdentifier->Data4[4], CardIdentifier->Data4[5],
2813 CardIdentifier->Data4[6], CardIdentifier->Data4[7], LookupName);
2814 return id;
2815}
2816
2817static char* card_id_and_name_w(const UUID* CardIdentifier, LPCWSTR LookupName)
2818{
2819 char* res = NULL;
2820 char* tmp = ConvertWCharToUtf8Alloc(LookupName, NULL);
2821 if (!tmp)
2822 return NULL;
2823 res = card_id_and_name_a(CardIdentifier, tmp);
2824 free(tmp);
2825 return res;
2826}
2827
2828static LONG WINAPI PCSC_SCardReadCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
2829 DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
2830 DWORD* DataLen)
2831{
2832 PCSC_CACHE_ITEM* data = NULL;
2833 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2834 if (!ctx)
2835 return SCARD_E_INVALID_HANDLE;
2836
2837 char* id = card_id_and_name_a(CardIdentifier, LookupName);
2838
2839 data = HashTable_GetItemValue(ctx->cache, id);
2840 free(id);
2841 if (!data)
2842 {
2843 *DataLen = 0;
2844 return SCARD_W_CACHE_ITEM_NOT_FOUND;
2845 }
2846
2847 if (FreshnessCounter != data->freshness)
2848 {
2849 *DataLen = 0;
2850 return SCARD_W_CACHE_ITEM_STALE;
2851 }
2852
2853 if (*DataLen == SCARD_AUTOALLOCATE)
2854 {
2855 BYTE* mem = calloc(1, data->len);
2856 if (!mem)
2857 return SCARD_E_NO_MEMORY;
2858
2859 if (!PCSC_AddMemoryBlock(hContext, mem))
2860 {
2861 free(mem);
2862 return SCARD_E_NO_MEMORY;
2863 }
2864
2865 memcpy(mem, data->data, data->len);
2866 *(BYTE**)Data = mem;
2867 }
2868 else
2869 memcpy(Data, data->data, data->len);
2870 *DataLen = data->len;
2871 return SCARD_S_SUCCESS;
2872}
2873
2874static LONG WINAPI PCSC_SCardReadCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
2875 DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
2876 DWORD* DataLen)
2877{
2878 PCSC_CACHE_ITEM* data = NULL;
2879 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2880 if (!ctx)
2881 return SCARD_E_INVALID_HANDLE;
2882
2883 char* id = card_id_and_name_w(CardIdentifier, LookupName);
2884
2885 data = HashTable_GetItemValue(ctx->cache, id);
2886 free(id);
2887
2888 if (!data)
2889 {
2890 *DataLen = 0;
2891 return SCARD_W_CACHE_ITEM_NOT_FOUND;
2892 }
2893
2894 if (FreshnessCounter != data->freshness)
2895 {
2896 *DataLen = 0;
2897 return SCARD_W_CACHE_ITEM_STALE;
2898 }
2899
2900 if (*DataLen == SCARD_AUTOALLOCATE)
2901 {
2902 BYTE* mem = calloc(1, data->len);
2903 if (!mem)
2904 return SCARD_E_NO_MEMORY;
2905
2906 if (!PCSC_AddMemoryBlock(hContext, mem))
2907 {
2908 free(mem);
2909 return SCARD_E_NO_MEMORY;
2910 }
2911
2912 memcpy(mem, data->data, data->len);
2913 *(BYTE**)Data = mem;
2914 }
2915 else
2916 memcpy(Data, data->data, data->len);
2917 *DataLen = data->len;
2918 return SCARD_S_SUCCESS;
2919}
2920
2921static LONG WINAPI PCSC_SCardWriteCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
2922 DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
2923 DWORD DataLen)
2924{
2925 PCSC_CACHE_ITEM* data = NULL;
2926 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2927 char* id = NULL;
2928
2929 if (!ctx)
2930 return SCARD_E_FILE_NOT_FOUND;
2931
2932 id = card_id_and_name_a(CardIdentifier, LookupName);
2933
2934 if (!id)
2935 return SCARD_E_NO_MEMORY;
2936
2937 data = malloc(sizeof(PCSC_CACHE_ITEM));
2938 if (!data)
2939 {
2940 free(id);
2941 return SCARD_E_NO_MEMORY;
2942 }
2943 data->data = calloc(DataLen, 1);
2944 if (!data->data)
2945 {
2946 free(id);
2947 free(data);
2948 return SCARD_E_NO_MEMORY;
2949 }
2950 data->len = DataLen;
2951 data->freshness = FreshnessCounter;
2952 memcpy(data->data, Data, data->len);
2953
2954 HashTable_Remove(ctx->cache, id);
2955 const BOOL rc = HashTable_Insert(ctx->cache, id, data);
2956 free(id);
2957
2958 if (!rc)
2959 {
2960 pcsc_cache_item_free(data);
2961 return SCARD_E_NO_MEMORY;
2962 }
2963
2964 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
2965 return SCARD_S_SUCCESS;
2966}
2967
2968static LONG WINAPI PCSC_SCardWriteCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
2969 DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
2970 DWORD DataLen)
2971{
2972 PCSC_CACHE_ITEM* data = NULL;
2973 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2974 char* id = NULL;
2975 if (!ctx)
2976 return SCARD_E_FILE_NOT_FOUND;
2977
2978 id = card_id_and_name_w(CardIdentifier, LookupName);
2979
2980 if (!id)
2981 return SCARD_E_NO_MEMORY;
2982
2983 data = malloc(sizeof(PCSC_CACHE_ITEM));
2984 if (!data)
2985 {
2986 free(id);
2987 return SCARD_E_NO_MEMORY;
2988 }
2989 data->data = malloc(DataLen);
2990 if (!data->data)
2991 {
2992 free(id);
2993 free(data);
2994 return SCARD_E_NO_MEMORY;
2995 }
2996 data->len = DataLen;
2997 data->freshness = FreshnessCounter;
2998 memcpy(data->data, Data, data->len);
2999
3000 HashTable_Remove(ctx->cache, id);
3001 const BOOL rc = HashTable_Insert(ctx->cache, id, data);
3002 free(id);
3003
3004 if (!rc)
3005 {
3006 pcsc_cache_item_free(data);
3007 return SCARD_E_NO_MEMORY;
3008 }
3009
3010 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
3011 return SCARD_S_SUCCESS;
3012}
3013
3014static LONG WINAPI PCSC_SCardGetReaderIconA(
3015 SCARDCONTEXT hContext, LPCSTR szReaderName,
3016 LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
3017{
3018 WINPR_UNUSED(hContext);
3019 WINPR_UNUSED(szReaderName);
3020 WINPR_UNUSED(pbIcon);
3021 WINPR_ASSERT(pcbIcon);
3022 *pcbIcon = 0;
3023 return SCARD_E_UNSUPPORTED_FEATURE;
3024}
3025
3026static LONG WINAPI PCSC_SCardGetReaderIconW(
3027 SCARDCONTEXT hContext, LPCWSTR szReaderName,
3028 LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
3029{
3030 WINPR_UNUSED(hContext);
3031 WINPR_UNUSED(szReaderName);
3032 WINPR_UNUSED(pbIcon);
3033 WINPR_ASSERT(pcbIcon);
3034 *pcbIcon = 0;
3035 return SCARD_E_UNSUPPORTED_FEATURE;
3036}
3037
3038static LONG WINAPI PCSC_SCardGetDeviceTypeIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
3039 LPDWORD pdwDeviceTypeId)
3040{
3041 WINPR_UNUSED(hContext);
3042 WINPR_UNUSED(szReaderName);
3043 WINPR_UNUSED(pdwDeviceTypeId);
3044 if (pdwDeviceTypeId)
3045 *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
3046 return SCARD_S_SUCCESS;
3047}
3048
3049static LONG WINAPI PCSC_SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
3050 LPDWORD pdwDeviceTypeId)
3051{
3052 WINPR_UNUSED(hContext);
3053 WINPR_UNUSED(szReaderName);
3054 if (pdwDeviceTypeId)
3055 *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
3056 return SCARD_S_SUCCESS;
3057}
3058
3059static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdA(
3060 SCARDCONTEXT hContext, LPCSTR szReaderName,
3061 LPSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3062 LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3063{
3064 WINPR_UNUSED(hContext);
3065 WINPR_UNUSED(szReaderName);
3066 WINPR_UNUSED(szDeviceInstanceId);
3067 WINPR_UNUSED(pcchDeviceInstanceId);
3068 return SCARD_E_UNSUPPORTED_FEATURE;
3069}
3070
3071static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdW(
3072 SCARDCONTEXT hContext, LPCWSTR szReaderName,
3073 LPWSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3074 LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3075{
3076 WINPR_UNUSED(hContext);
3077 WINPR_UNUSED(szReaderName);
3078 WINPR_UNUSED(szDeviceInstanceId);
3079 WINPR_UNUSED(pcchDeviceInstanceId);
3080 return SCARD_E_UNSUPPORTED_FEATURE;
3081}
3082
3083static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdA(
3084 SCARDCONTEXT hContext, LPCSTR szDeviceInstanceId,
3085 LPSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3086 LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3087{
3088 WINPR_UNUSED(hContext);
3089 WINPR_UNUSED(szDeviceInstanceId);
3090 WINPR_UNUSED(mszReaders);
3091 WINPR_UNUSED(pcchReaders);
3092 return SCARD_E_UNSUPPORTED_FEATURE;
3093}
3094
3095static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdW(
3096 SCARDCONTEXT hContext, LPCWSTR szDeviceInstanceId,
3097 LPWSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3098 LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3099{
3100 WINPR_UNUSED(hContext);
3101 WINPR_UNUSED(szDeviceInstanceId);
3102 WINPR_UNUSED(mszReaders);
3103 WINPR_UNUSED(pcchReaders);
3104 return SCARD_E_UNSUPPORTED_FEATURE;
3105}
3106
3107static LONG WINAPI PCSC_SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
3108{
3109
3110 WINPR_UNUSED(hContext);
3111 WINPR_UNUSED(dwEvent);
3112 return SCARD_E_UNSUPPORTED_FEATURE;
3113}
3114
3115#ifdef __MACOSX__
3116unsigned int determineMacOSXVersion(void)
3117{
3118 int mib[2];
3119 size_t len = 0;
3120 char* kernelVersion = NULL;
3121 char* tok = NULL;
3122 unsigned int version = 0;
3123 long majorVersion = 0;
3124 long minorVersion = 0;
3125 long patchVersion = 0;
3126 int count = 0;
3127 char* context = NULL;
3128 mib[0] = CTL_KERN;
3129 mib[1] = KERN_OSRELEASE;
3130
3131 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
3132 return 0;
3133
3134 kernelVersion = calloc(len, sizeof(char));
3135
3136 if (!kernelVersion)
3137 return 0;
3138
3139 if (sysctl(mib, 2, kernelVersion, &len, NULL, 0) != 0)
3140 {
3141 free(kernelVersion);
3142 return 0;
3143 }
3144
3145 tok = strtok_s(kernelVersion, ".", &context);
3146 errno = 0;
3147
3148 while (tok)
3149 {
3150 switch (count)
3151 {
3152 case 0:
3153 majorVersion = strtol(tok, NULL, 0);
3154
3155 if (errno != 0)
3156 goto fail;
3157
3158 break;
3159
3160 case 1:
3161 minorVersion = strtol(tok, NULL, 0);
3162
3163 if (errno != 0)
3164 goto fail;
3165
3166 break;
3167
3168 case 2:
3169 patchVersion = strtol(tok, NULL, 0);
3170
3171 if (errno != 0)
3172 goto fail;
3173
3174 break;
3175 }
3176
3177 tok = strtok_s(NULL, ".", &context);
3178 count++;
3179 }
3180
3184 if (majorVersion < 5)
3185 {
3186 if (minorVersion < 4)
3187 version = 0x10000000;
3188 else
3189 version = 0x10010000;
3190 }
3191 else
3192 {
3193 switch (majorVersion)
3194 {
3195 case 5:
3196 version = 0x10010000;
3197 break;
3198
3199 case 6:
3200 version = 0x10020000;
3201 break;
3202
3203 case 7:
3204 version = 0x10030000;
3205 break;
3206
3207 case 8:
3208 version = 0x10040000;
3209 break;
3210
3211 case 9:
3212 version = 0x10050000;
3213 break;
3214
3215 case 10:
3216 version = 0x10060000;
3217 break;
3218
3219 case 11:
3220 version = 0x10070000;
3221 break;
3222
3223 case 12:
3224 version = 0x10080000;
3225 break;
3226
3227 case 13:
3228 version = 0x10090000;
3229 break;
3230
3231 default:
3232 version = 0x10100000;
3233 break;
3234 }
3235
3236 version |= (minorVersion << 8) | (patchVersion);
3237 }
3238
3239fail:
3240 free(kernelVersion);
3241 return version;
3242}
3243#endif
3244
3245static const SCardApiFunctionTable PCSC_SCardApiFunctionTable = {
3246 0, /* dwVersion */
3247 0, /* dwFlags */
3248
3249 PCSC_SCardEstablishContext, /* SCardEstablishContext */
3250 PCSC_SCardReleaseContext, /* SCardReleaseContext */
3251 PCSC_SCardIsValidContext, /* SCardIsValidContext */
3252 PCSC_SCardListReaderGroupsA, /* SCardListReaderGroupsA */
3253 PCSC_SCardListReaderGroupsW, /* SCardListReaderGroupsW */
3254 PCSC_SCardListReadersA, /* SCardListReadersA */
3255 PCSC_SCardListReadersW, /* SCardListReadersW */
3256 PCSC_SCardListCardsA, /* SCardListCardsA */
3257 PCSC_SCardListCardsW, /* SCardListCardsW */
3258 PCSC_SCardListInterfacesA, /* SCardListInterfacesA */
3259 PCSC_SCardListInterfacesW, /* SCardListInterfacesW */
3260 PCSC_SCardGetProviderIdA, /* SCardGetProviderIdA */
3261 PCSC_SCardGetProviderIdW, /* SCardGetProviderIdW */
3262 PCSC_SCardGetCardTypeProviderNameA, /* SCardGetCardTypeProviderNameA */
3263 PCSC_SCardGetCardTypeProviderNameW, /* SCardGetCardTypeProviderNameW */
3264 PCSC_SCardIntroduceReaderGroupA, /* SCardIntroduceReaderGroupA */
3265 PCSC_SCardIntroduceReaderGroupW, /* SCardIntroduceReaderGroupW */
3266 PCSC_SCardForgetReaderGroupA, /* SCardForgetReaderGroupA */
3267 PCSC_SCardForgetReaderGroupW, /* SCardForgetReaderGroupW */
3268 PCSC_SCardIntroduceReaderA, /* SCardIntroduceReaderA */
3269 PCSC_SCardIntroduceReaderW, /* SCardIntroduceReaderW */
3270 PCSC_SCardForgetReaderA, /* SCardForgetReaderA */
3271 PCSC_SCardForgetReaderW, /* SCardForgetReaderW */
3272 PCSC_SCardAddReaderToGroupA, /* SCardAddReaderToGroupA */
3273 PCSC_SCardAddReaderToGroupW, /* SCardAddReaderToGroupW */
3274 PCSC_SCardRemoveReaderFromGroupA, /* SCardRemoveReaderFromGroupA */
3275 PCSC_SCardRemoveReaderFromGroupW, /* SCardRemoveReaderFromGroupW */
3276 PCSC_SCardIntroduceCardTypeA, /* SCardIntroduceCardTypeA */
3277 PCSC_SCardIntroduceCardTypeW, /* SCardIntroduceCardTypeW */
3278 PCSC_SCardSetCardTypeProviderNameA, /* SCardSetCardTypeProviderNameA */
3279 PCSC_SCardSetCardTypeProviderNameW, /* SCardSetCardTypeProviderNameW */
3280 PCSC_SCardForgetCardTypeA, /* SCardForgetCardTypeA */
3281 PCSC_SCardForgetCardTypeW, /* SCardForgetCardTypeW */
3282 PCSC_SCardFreeMemory, /* SCardFreeMemory */
3283 PCSC_SCardAccessStartedEvent, /* SCardAccessStartedEvent */
3284 PCSC_SCardReleaseStartedEvent, /* SCardReleaseStartedEvent */
3285 PCSC_SCardLocateCardsA, /* SCardLocateCardsA */
3286 PCSC_SCardLocateCardsW, /* SCardLocateCardsW */
3287 PCSC_SCardLocateCardsByATRA, /* SCardLocateCardsByATRA */
3288 PCSC_SCardLocateCardsByATRW, /* SCardLocateCardsByATRW */
3289 PCSC_SCardGetStatusChangeA, /* SCardGetStatusChangeA */
3290 PCSC_SCardGetStatusChangeW, /* SCardGetStatusChangeW */
3291 PCSC_SCardCancel, /* SCardCancel */
3292 PCSC_SCardConnectA, /* SCardConnectA */
3293 PCSC_SCardConnectW, /* SCardConnectW */
3294 PCSC_SCardReconnect, /* SCardReconnect */
3295 PCSC_SCardDisconnect, /* SCardDisconnect */
3296 PCSC_SCardBeginTransaction, /* SCardBeginTransaction */
3297 PCSC_SCardEndTransaction, /* SCardEndTransaction */
3298 PCSC_SCardCancelTransaction, /* SCardCancelTransaction */
3299 PCSC_SCardState, /* SCardState */
3300 PCSC_SCardStatusA, /* SCardStatusA */
3301 PCSC_SCardStatusW, /* SCardStatusW */
3302 PCSC_SCardTransmit, /* SCardTransmit */
3303 PCSC_SCardGetTransmitCount, /* SCardGetTransmitCount */
3304 PCSC_SCardControl, /* SCardControl */
3305 PCSC_SCardGetAttrib, /* SCardGetAttrib */
3306 PCSC_SCardSetAttrib, /* SCardSetAttrib */
3307 PCSC_SCardUIDlgSelectCardA, /* SCardUIDlgSelectCardA */
3308 PCSC_SCardUIDlgSelectCardW, /* SCardUIDlgSelectCardW */
3309 PCSC_GetOpenCardNameA, /* GetOpenCardNameA */
3310 PCSC_GetOpenCardNameW, /* GetOpenCardNameW */
3311 PCSC_SCardDlgExtendedError, /* SCardDlgExtendedError */
3312 PCSC_SCardReadCacheA, /* SCardReadCacheA */
3313 PCSC_SCardReadCacheW, /* SCardReadCacheW */
3314 PCSC_SCardWriteCacheA, /* SCardWriteCacheA */
3315 PCSC_SCardWriteCacheW, /* SCardWriteCacheW */
3316 PCSC_SCardGetReaderIconA, /* SCardGetReaderIconA */
3317 PCSC_SCardGetReaderIconW, /* SCardGetReaderIconW */
3318 PCSC_SCardGetDeviceTypeIdA, /* SCardGetDeviceTypeIdA */
3319 PCSC_SCardGetDeviceTypeIdW, /* SCardGetDeviceTypeIdW */
3320 PCSC_SCardGetReaderDeviceInstanceIdA, /* SCardGetReaderDeviceInstanceIdA */
3321 PCSC_SCardGetReaderDeviceInstanceIdW, /* SCardGetReaderDeviceInstanceIdW */
3322 PCSC_SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
3323 PCSC_SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
3324 PCSC_SCardAudit /* SCardAudit */
3325};
3326
3327const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void)
3328{
3329 return &PCSC_SCardApiFunctionTable;
3330}
3331
3332int PCSC_InitializeSCardApi(void)
3333{
3334 /* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
3335 SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
3336#ifdef __MACOSX__
3337 g_PCSCModule = LoadLibraryX("/System/Library/Frameworks/PCSC.framework/PCSC");
3338 OSXVersion = determineMacOSXVersion();
3339
3340 if (OSXVersion == 0)
3341 return -1;
3342
3343#else
3344 g_PCSCModule = LoadLibraryA("libpcsclite.so.1");
3345
3346 if (!g_PCSCModule)
3347 g_PCSCModule = LoadLibraryA("libpcsclite.so");
3348
3349#endif
3350
3351 if (!g_PCSCModule)
3352 return -1;
3353
3354 /* symbols defined in winpr/smartcard.h, might pose an issue with the GetProcAddress macro
3355 * below. therefore undefine them here */
3356#undef SCardListReaderGroups
3357#undef SCardListReaders
3358#undef SCardListCards
3359#undef SCardListInterfaces
3360#undef SCardGetProviderId
3361#undef SCardGetCardTypeProviderName
3362#undef SCardIntroduceReaderGroup
3363#undef SCardForgetReaderGroup
3364#undef SCardIntroduceReader
3365#undef SCardForgetReader
3366#undef SCardAddReaderToGroup
3367#undef SCardRemoveReaderFromGroup
3368#undef SCardIntroduceCardType
3369#undef SCardSetCardTypeProviderName
3370#undef SCardForgetCardType
3371#undef SCardLocateCards
3372#undef SCardLocateCardsByATR
3373#undef SCardGetStatusChange
3374#undef SCardConnect
3375#undef SCardStatus
3376#undef SCardUIDlgSelectCard
3377#undef GetOpenCardName
3378#undef SCardReadCache
3379#undef SCardWriteCache
3380#undef SCardGetReaderIcon
3381#undef SCardGetDeviceTypeId
3382#undef SCardGetReaderDeviceInstanceId
3383#undef SCardListReadersWithDeviceInstanceId
3384
3385 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEstablishContext);
3386 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReleaseContext);
3387 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardIsValidContext);
3388 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardConnect);
3389 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReconnect);
3390 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardDisconnect);
3391 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardBeginTransaction);
3392 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEndTransaction);
3393 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardStatus);
3394 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetStatusChange);
3395
3396#ifdef __MACOSX__
3397
3398 if (OSXVersion >= 0x10050600)
3399 {
3400 WINSCARD_LOAD_PROC_EX(g_PCSCModule, g_PCSC, SCardControl, SCardControl132);
3401 }
3402 else
3403 {
3404 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3405 }
3406#else
3407 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3408#endif
3409 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardTransmit);
3410 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaderGroups);
3411 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaders);
3412 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardCancel);
3413 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetAttrib);
3414 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardSetAttrib);
3415 g_PCSC.pfnSCardFreeMemory = NULL;
3416#ifndef __APPLE__
3417 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardFreeMemory);
3418#endif
3419
3420 if (g_PCSC.pfnSCardFreeMemory)
3421 g_SCardAutoAllocate = TRUE;
3422
3423#ifdef DISABLE_PCSC_SCARD_AUTOALLOCATE
3424 g_PCSC.pfnSCardFreeMemory = NULL;
3425 g_SCardAutoAllocate = FALSE;
3426#endif
3427#ifdef __APPLE__
3428 g_PnP_Notification = FALSE;
3429#endif
3430 return 1;
3431}
3432
3433#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