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