FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 size_t length = 0;
2411 char* namePCSC = NULL;
2412 char* pbAttrA = NULL;
2413 DWORD cbAttrLen = 0;
2414 WCHAR* pbAttrW = NULL;
2415 SCARDCONTEXT hContext = 0;
2416 LONG status = SCARD_S_SUCCESS;
2417
2418 hContext = PCSC_GetCardContextFromHandle(hCard);
2419
2420 if (!hContext)
2421 return SCARD_E_INVALID_HANDLE;
2422
2423 if (!pcbAttrLen)
2424 return SCARD_E_INVALID_PARAMETER;
2425 cbAttrLen = *pcbAttrLen;
2426 *pcbAttrLen = SCARD_AUTOALLOCATE;
2427 status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
2428 (LPBYTE)&pbAttrA, pcbAttrLen);
2429
2430 if (status != SCARD_S_SUCCESS)
2431 {
2432 *pcbAttrLen = SCARD_AUTOALLOCATE;
2433 status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
2434 (LPBYTE)&pbAttrW, pcbAttrLen);
2435
2436 if (status != SCARD_S_SUCCESS)
2437 return status;
2438
2439 namePCSC = ConvertMszWCharNToUtf8Alloc(pbAttrW, *pcbAttrLen, NULL);
2440 PCSC_SCardFreeMemory_Internal(hContext, pbAttrW);
2441 }
2442 else
2443 {
2444 namePCSC = _strdup(pbAttrA);
2445
2446 if (!namePCSC)
2447 return SCARD_E_NO_MEMORY;
2448
2449 PCSC_SCardFreeMemory_Internal(hContext, pbAttrA);
2450 }
2451
2452 length = strlen(namePCSC);
2453
2454 if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W)
2455 {
2456 size_t size = 0;
2457 WCHAR* friendlyNameW = ConvertUtf8ToWCharAlloc(namePCSC, &size);
2458 /* length here includes null terminator */
2459
2460 if (!friendlyNameW)
2461 status = SCARD_E_NO_MEMORY;
2462 else
2463 {
2464 length = size;
2465
2466 if (cbAttrLen == SCARD_AUTOALLOCATE)
2467 {
2468 WINPR_ASSERT(length <= UINT32_MAX / sizeof(WCHAR));
2469 *(WCHAR**)pbAttr = friendlyNameW;
2470 *pcbAttrLen = (UINT32)length * sizeof(WCHAR);
2471 PCSC_AddMemoryBlock(hContext, friendlyNameW);
2472 }
2473 else
2474 {
2475 if ((length * 2) > cbAttrLen)
2476 status = SCARD_E_INSUFFICIENT_BUFFER;
2477 else
2478 {
2479 WINPR_ASSERT(length <= UINT32_MAX / sizeof(WCHAR));
2480 CopyMemory(pbAttr, (BYTE*)friendlyNameW, (length * sizeof(WCHAR)));
2481 *pcbAttrLen = (UINT32)length * sizeof(WCHAR);
2482 }
2483 free(friendlyNameW);
2484 }
2485 }
2486 free(namePCSC);
2487 }
2488 else
2489 {
2490 if (cbAttrLen == SCARD_AUTOALLOCATE)
2491 {
2492 *(CHAR**)pbAttr = namePCSC;
2493 WINPR_ASSERT(length <= UINT32_MAX);
2494 *pcbAttrLen = (UINT32)length;
2495 PCSC_AddMemoryBlock(hContext, namePCSC);
2496 }
2497 else
2498 {
2499 if ((length + 1) > cbAttrLen)
2500 status = SCARD_E_INSUFFICIENT_BUFFER;
2501 else
2502 {
2503 CopyMemory(pbAttr, namePCSC, length + 1);
2504 WINPR_ASSERT(length <= UINT32_MAX);
2505 *pcbAttrLen = (UINT32)length;
2506 }
2507 free(namePCSC);
2508 }
2509 }
2510
2511 return status;
2512}
2513
2514static LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2515 LPDWORD pcbAttrLen)
2516{
2517 DWORD cbAttrLen = 0;
2518 SCARDCONTEXT hContext = 0;
2519 BOOL pcbAttrLenAlloc = FALSE;
2520 LONG status = SCARD_S_SUCCESS;
2521
2522 if (NULL == pcbAttrLen)
2523 return SCARD_E_INVALID_PARAMETER;
2524
2525 cbAttrLen = *pcbAttrLen;
2526
2527 if (*pcbAttrLen == SCARD_AUTOALLOCATE)
2528 {
2529 if (NULL == pbAttr)
2530 return SCARD_E_INVALID_PARAMETER;
2531
2532 pcbAttrLenAlloc = TRUE;
2533 *(BYTE**)pbAttr = NULL;
2534 }
2535 else
2536 {
2541 if (*pcbAttrLen > PCSC_MAX_BUFFER_SIZE)
2542 *pcbAttrLen = PCSC_MAX_BUFFER_SIZE;
2543 }
2544
2545 hContext = PCSC_GetCardContextFromHandle(hCard);
2546
2547 if (!hContext)
2548 return SCARD_E_INVALID_HANDLE;
2549
2550 if ((dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A) ||
2551 (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W))
2552 {
2553 status = PCSC_SCardGetAttrib_FriendlyName(hCard, dwAttrId, pbAttr, pcbAttrLen);
2554 return status;
2555 }
2556
2557 status = PCSC_SCardGetAttrib_Internal(hCard, dwAttrId, pbAttr, pcbAttrLen);
2558
2559 if (status == SCARD_S_SUCCESS)
2560 {
2561 if (dwAttrId == SCARD_ATTR_VENDOR_NAME)
2562 {
2563 if (pbAttr)
2564 {
2565 const char* vendorName = NULL;
2566
2572 if (pcbAttrLenAlloc)
2573 vendorName = (char*)*(BYTE**)pbAttr;
2574 else
2575 vendorName = (char*)pbAttr;
2576
2577 if (vendorName)
2578 {
2579 size_t len = strnlen(vendorName, *pcbAttrLen);
2580 WINPR_ASSERT(len <= UINT32_MAX);
2581 *pcbAttrLen = (DWORD)len;
2582 }
2583 else
2584 *pcbAttrLen = 0;
2585 }
2586 }
2587 }
2588 else
2589 {
2590
2591 if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
2592 {
2593 if (!pcbAttrLenAlloc)
2594 {
2595 PCSC_DWORD dwState = 0;
2596 PCSC_DWORD cbAtrLen = 0;
2597 PCSC_DWORD dwProtocol = 0;
2598 PCSC_DWORD cchReaderLen = 0;
2599 status = (LONG)g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState,
2600 &dwProtocol, NULL, &cbAtrLen);
2601
2602 if (status == SCARD_S_SUCCESS)
2603 {
2604 if (cbAttrLen < sizeof(DWORD))
2605 return SCARD_E_INSUFFICIENT_BUFFER;
2606
2607 *(DWORD*)pbAttr = PCSC_ConvertProtocolsToWinSCard(dwProtocol);
2608 *pcbAttrLen = sizeof(DWORD);
2609 }
2610 }
2611 }
2612 else if (dwAttrId == SCARD_ATTR_CHANNEL_ID)
2613 {
2614 if (!pcbAttrLenAlloc)
2615 {
2616 UINT32 channelType = 0x20; /* USB */
2617 UINT32 channelNumber = 0;
2618
2619 if (cbAttrLen < sizeof(DWORD))
2620 return SCARD_E_INSUFFICIENT_BUFFER;
2621
2622 status = SCARD_S_SUCCESS;
2623 *(DWORD*)pbAttr = (channelType << 16u) | channelNumber;
2624 *pcbAttrLen = sizeof(DWORD);
2625 }
2626 }
2627 else if (dwAttrId == SCARD_ATTR_VENDOR_IFD_TYPE)
2628 {
2629 }
2630 else if (dwAttrId == SCARD_ATTR_DEFAULT_CLK)
2631 {
2632 }
2633 else if (dwAttrId == SCARD_ATTR_DEFAULT_DATA_RATE)
2634 {
2635 }
2636 else if (dwAttrId == SCARD_ATTR_MAX_CLK)
2637 {
2638 }
2639 else if (dwAttrId == SCARD_ATTR_MAX_DATA_RATE)
2640 {
2641 }
2642 else if (dwAttrId == SCARD_ATTR_MAX_IFSD)
2643 {
2644 }
2645 else if (dwAttrId == SCARD_ATTR_CHARACTERISTICS)
2646 {
2647 }
2648 else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_A)
2649 {
2650 }
2651 else if (dwAttrId == SCARD_ATTR_DEVICE_UNIT)
2652 {
2653 }
2654 else if (dwAttrId == SCARD_ATTR_POWER_MGMT_SUPPORT)
2655 {
2656 }
2657 else if (dwAttrId == SCARD_ATTR_CURRENT_CLK)
2658 {
2659 }
2660 else if (dwAttrId == SCARD_ATTR_CURRENT_F)
2661 {
2662 }
2663 else if (dwAttrId == SCARD_ATTR_CURRENT_D)
2664 {
2665 }
2666 else if (dwAttrId == SCARD_ATTR_CURRENT_N)
2667 {
2668 }
2669 else if (dwAttrId == SCARD_ATTR_CURRENT_CWT)
2670 {
2671 }
2672 else if (dwAttrId == SCARD_ATTR_CURRENT_BWT)
2673 {
2674 }
2675 else if (dwAttrId == SCARD_ATTR_CURRENT_IFSC)
2676 {
2677 }
2678 else if (dwAttrId == SCARD_ATTR_CURRENT_EBC_ENCODING)
2679 {
2680 }
2681 else if (dwAttrId == SCARD_ATTR_CURRENT_IFSD)
2682 {
2683 }
2684 else if (dwAttrId == SCARD_ATTR_ICC_TYPE_PER_ATR)
2685 {
2686 }
2687 }
2688
2689 return status;
2690}
2691
2692static LONG WINAPI PCSC_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2693 DWORD cbAttrLen)
2694{
2695 PCSC_LONG status = SCARD_S_SUCCESS;
2696 PCSC_SCARDHANDLE* pCard = NULL;
2697 PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
2698 PCSC_DWORD pcsc_cbAttrLen = (PCSC_DWORD)cbAttrLen;
2699
2700 if (!g_PCSC.pfnSCardSetAttrib)
2701 return PCSC_SCard_LogError("g_PCSC.pfnSCardSetAttrib");
2702
2703 pCard = PCSC_GetCardHandleData(hCard);
2704
2705 if (!pCard)
2706 return SCARD_E_INVALID_VALUE;
2707
2708 PCSC_WaitForCardAccess(0, hCard, pCard->shared);
2709 status = g_PCSC.pfnSCardSetAttrib(hCard, pcsc_dwAttrId, pbAttr, pcsc_cbAttrLen);
2710 return PCSC_MapErrorCodeToWinSCard(status);
2711}
2712
2713static LONG WINAPI PCSC_SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
2714{
2715 WINPR_UNUSED(pDlgStruc);
2716
2717 return SCARD_E_UNSUPPORTED_FEATURE;
2718}
2719
2720static LONG WINAPI PCSC_SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
2721{
2722 WINPR_UNUSED(pDlgStruc);
2723 return SCARD_E_UNSUPPORTED_FEATURE;
2724}
2725
2726static LONG WINAPI PCSC_GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
2727{
2728 WINPR_UNUSED(pDlgStruc);
2729 return SCARD_E_UNSUPPORTED_FEATURE;
2730}
2731
2732static LONG WINAPI PCSC_GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
2733{
2734 WINPR_UNUSED(pDlgStruc);
2735 return SCARD_E_UNSUPPORTED_FEATURE;
2736}
2737
2738static LONG WINAPI PCSC_SCardDlgExtendedError(void)
2739{
2740
2741 return SCARD_E_UNSUPPORTED_FEATURE;
2742}
2743
2744static char* card_id_and_name_a(const UUID* CardIdentifier, LPCSTR LookupName)
2745{
2746 WINPR_ASSERT(CardIdentifier);
2747 WINPR_ASSERT(LookupName);
2748
2749 size_t len = strlen(LookupName) + 34;
2750 char* id = malloc(len);
2751 if (!id)
2752 return NULL;
2753
2754 (void)snprintf(id, len, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X\\%s",
2755 CardIdentifier->Data1, CardIdentifier->Data2, CardIdentifier->Data3,
2756 CardIdentifier->Data4[0], CardIdentifier->Data4[1], CardIdentifier->Data4[2],
2757 CardIdentifier->Data4[3], CardIdentifier->Data4[4], CardIdentifier->Data4[5],
2758 CardIdentifier->Data4[6], CardIdentifier->Data4[7], LookupName);
2759 return id;
2760}
2761
2762static char* card_id_and_name_w(const UUID* CardIdentifier, LPCWSTR LookupName)
2763{
2764 char* res = NULL;
2765 char* tmp = ConvertWCharToUtf8Alloc(LookupName, NULL);
2766 if (!tmp)
2767 return NULL;
2768 res = card_id_and_name_a(CardIdentifier, tmp);
2769 free(tmp);
2770 return res;
2771}
2772
2773static LONG WINAPI PCSC_SCardReadCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
2774 DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
2775 DWORD* DataLen)
2776{
2777 PCSC_CACHE_ITEM* data = NULL;
2778 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2779 if (!ctx)
2780 return SCARD_E_INVALID_HANDLE;
2781
2782 char* id = card_id_and_name_a(CardIdentifier, LookupName);
2783
2784 data = HashTable_GetItemValue(ctx->cache, id);
2785 free(id);
2786 if (!data)
2787 {
2788 *DataLen = 0;
2789 return SCARD_W_CACHE_ITEM_NOT_FOUND;
2790 }
2791
2792 if (FreshnessCounter != data->freshness)
2793 {
2794 *DataLen = 0;
2795 return SCARD_W_CACHE_ITEM_STALE;
2796 }
2797
2798 if (*DataLen == SCARD_AUTOALLOCATE)
2799 {
2800 BYTE* mem = calloc(1, data->len);
2801 if (!mem)
2802 return SCARD_E_NO_MEMORY;
2803
2804 if (!PCSC_AddMemoryBlock(hContext, mem))
2805 {
2806 free(mem);
2807 return SCARD_E_NO_MEMORY;
2808 }
2809
2810 memcpy(mem, data->data, data->len);
2811 *(BYTE**)Data = mem;
2812 }
2813 else
2814 memcpy(Data, data->data, data->len);
2815 *DataLen = data->len;
2816 return SCARD_S_SUCCESS;
2817}
2818
2819static LONG WINAPI PCSC_SCardReadCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
2820 DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
2821 DWORD* DataLen)
2822{
2823 PCSC_CACHE_ITEM* data = NULL;
2824 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2825 if (!ctx)
2826 return SCARD_E_INVALID_HANDLE;
2827
2828 char* id = card_id_and_name_w(CardIdentifier, LookupName);
2829
2830 data = HashTable_GetItemValue(ctx->cache, id);
2831 free(id);
2832
2833 if (!data)
2834 {
2835 *DataLen = 0;
2836 return SCARD_W_CACHE_ITEM_NOT_FOUND;
2837 }
2838
2839 if (FreshnessCounter != data->freshness)
2840 {
2841 *DataLen = 0;
2842 return SCARD_W_CACHE_ITEM_STALE;
2843 }
2844
2845 if (*DataLen == SCARD_AUTOALLOCATE)
2846 {
2847 BYTE* mem = calloc(1, data->len);
2848 if (!mem)
2849 return SCARD_E_NO_MEMORY;
2850
2851 if (!PCSC_AddMemoryBlock(hContext, mem))
2852 {
2853 free(mem);
2854 return SCARD_E_NO_MEMORY;
2855 }
2856
2857 memcpy(mem, data->data, data->len);
2858 *(BYTE**)Data = mem;
2859 }
2860 else
2861 memcpy(Data, data->data, data->len);
2862 *DataLen = data->len;
2863 return SCARD_S_SUCCESS;
2864}
2865
2866static LONG WINAPI PCSC_SCardWriteCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
2867 DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
2868 DWORD DataLen)
2869{
2870 PCSC_CACHE_ITEM* data = NULL;
2871 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2872 char* id = NULL;
2873
2874 if (!ctx)
2875 return SCARD_E_FILE_NOT_FOUND;
2876
2877 id = card_id_and_name_a(CardIdentifier, LookupName);
2878
2879 if (!id)
2880 return SCARD_E_NO_MEMORY;
2881
2882 data = malloc(sizeof(PCSC_CACHE_ITEM));
2883 if (!data)
2884 {
2885 free(id);
2886 return SCARD_E_NO_MEMORY;
2887 }
2888 data->data = calloc(DataLen, 1);
2889 if (!data->data)
2890 {
2891 free(id);
2892 free(data);
2893 return SCARD_E_NO_MEMORY;
2894 }
2895 data->len = DataLen;
2896 data->freshness = FreshnessCounter;
2897 memcpy(data->data, Data, data->len);
2898
2899 HashTable_Remove(ctx->cache, id);
2900 const BOOL rc = HashTable_Insert(ctx->cache, id, data);
2901 free(id);
2902
2903 if (!rc)
2904 {
2905 pcsc_cache_item_free(data);
2906 return SCARD_E_NO_MEMORY;
2907 }
2908
2909 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
2910 return SCARD_S_SUCCESS;
2911}
2912
2913static LONG WINAPI PCSC_SCardWriteCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
2914 DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
2915 DWORD DataLen)
2916{
2917 PCSC_CACHE_ITEM* data = NULL;
2918 PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
2919 char* id = NULL;
2920 if (!ctx)
2921 return SCARD_E_FILE_NOT_FOUND;
2922
2923 id = card_id_and_name_w(CardIdentifier, LookupName);
2924
2925 if (!id)
2926 return SCARD_E_NO_MEMORY;
2927
2928 data = malloc(sizeof(PCSC_CACHE_ITEM));
2929 if (!data)
2930 {
2931 free(id);
2932 return SCARD_E_NO_MEMORY;
2933 }
2934 data->data = malloc(DataLen);
2935 if (!data->data)
2936 {
2937 free(id);
2938 free(data);
2939 return SCARD_E_NO_MEMORY;
2940 }
2941 data->len = DataLen;
2942 data->freshness = FreshnessCounter;
2943 memcpy(data->data, Data, data->len);
2944
2945 HashTable_Remove(ctx->cache, id);
2946 const BOOL rc = HashTable_Insert(ctx->cache, id, data);
2947 free(id);
2948
2949 if (!rc)
2950 {
2951 pcsc_cache_item_free(data);
2952 return SCARD_E_NO_MEMORY;
2953 }
2954
2955 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
2956 return SCARD_S_SUCCESS;
2957}
2958
2959static LONG WINAPI PCSC_SCardGetReaderIconA(
2960 SCARDCONTEXT hContext, LPCSTR szReaderName,
2961 LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
2962{
2963 WINPR_UNUSED(hContext);
2964 WINPR_UNUSED(szReaderName);
2965 WINPR_UNUSED(pbIcon);
2966 WINPR_ASSERT(pcbIcon);
2967 *pcbIcon = 0;
2968 return SCARD_E_UNSUPPORTED_FEATURE;
2969}
2970
2971static LONG WINAPI PCSC_SCardGetReaderIconW(
2972 SCARDCONTEXT hContext, LPCWSTR szReaderName,
2973 LPBYTE pbIcon /* NOLINT(readability-non-const-parameter) */, LPDWORD pcbIcon)
2974{
2975 WINPR_UNUSED(hContext);
2976 WINPR_UNUSED(szReaderName);
2977 WINPR_UNUSED(pbIcon);
2978 WINPR_ASSERT(pcbIcon);
2979 *pcbIcon = 0;
2980 return SCARD_E_UNSUPPORTED_FEATURE;
2981}
2982
2983static LONG WINAPI PCSC_SCardGetDeviceTypeIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
2984 LPDWORD pdwDeviceTypeId)
2985{
2986 WINPR_UNUSED(hContext);
2987 WINPR_UNUSED(szReaderName);
2988 WINPR_UNUSED(pdwDeviceTypeId);
2989 if (pdwDeviceTypeId)
2990 *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
2991 return SCARD_S_SUCCESS;
2992}
2993
2994static LONG WINAPI PCSC_SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
2995 LPDWORD pdwDeviceTypeId)
2996{
2997 WINPR_UNUSED(hContext);
2998 WINPR_UNUSED(szReaderName);
2999 if (pdwDeviceTypeId)
3000 *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
3001 return SCARD_S_SUCCESS;
3002}
3003
3004static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdA(
3005 SCARDCONTEXT hContext, LPCSTR szReaderName,
3006 LPSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3007 LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3008{
3009 WINPR_UNUSED(hContext);
3010 WINPR_UNUSED(szReaderName);
3011 WINPR_UNUSED(szDeviceInstanceId);
3012 WINPR_UNUSED(pcchDeviceInstanceId);
3013 return SCARD_E_UNSUPPORTED_FEATURE;
3014}
3015
3016static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdW(
3017 SCARDCONTEXT hContext, LPCWSTR szReaderName,
3018 LPWSTR szDeviceInstanceId /* NOLINT(readability-non-const-parameter) */,
3019 LPDWORD pcchDeviceInstanceId /* NOLINT(readability-non-const-parameter) */)
3020{
3021 WINPR_UNUSED(hContext);
3022 WINPR_UNUSED(szReaderName);
3023 WINPR_UNUSED(szDeviceInstanceId);
3024 WINPR_UNUSED(pcchDeviceInstanceId);
3025 return SCARD_E_UNSUPPORTED_FEATURE;
3026}
3027
3028static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdA(
3029 SCARDCONTEXT hContext, LPCSTR szDeviceInstanceId,
3030 LPSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3031 LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3032{
3033 WINPR_UNUSED(hContext);
3034 WINPR_UNUSED(szDeviceInstanceId);
3035 WINPR_UNUSED(mszReaders);
3036 WINPR_UNUSED(pcchReaders);
3037 return SCARD_E_UNSUPPORTED_FEATURE;
3038}
3039
3040static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdW(
3041 SCARDCONTEXT hContext, LPCWSTR szDeviceInstanceId,
3042 LPWSTR mszReaders /* NOLINT(readability-non-const-parameter) */,
3043 LPDWORD pcchReaders /* NOLINT(readability-non-const-parameter) */)
3044{
3045 WINPR_UNUSED(hContext);
3046 WINPR_UNUSED(szDeviceInstanceId);
3047 WINPR_UNUSED(mszReaders);
3048 WINPR_UNUSED(pcchReaders);
3049 return SCARD_E_UNSUPPORTED_FEATURE;
3050}
3051
3052static LONG WINAPI PCSC_SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
3053{
3054
3055 WINPR_UNUSED(hContext);
3056 WINPR_UNUSED(dwEvent);
3057 return SCARD_E_UNSUPPORTED_FEATURE;
3058}
3059
3060#ifdef __MACOSX__
3061unsigned int determineMacOSXVersion(void)
3062{
3063 int mib[2];
3064 size_t len = 0;
3065 char* kernelVersion = NULL;
3066 char* tok = NULL;
3067 unsigned int version = 0;
3068 long majorVersion = 0;
3069 long minorVersion = 0;
3070 long patchVersion = 0;
3071 int count = 0;
3072 char* context = NULL;
3073 mib[0] = CTL_KERN;
3074 mib[1] = KERN_OSRELEASE;
3075
3076 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
3077 return 0;
3078
3079 kernelVersion = calloc(len, sizeof(char));
3080
3081 if (!kernelVersion)
3082 return 0;
3083
3084 if (sysctl(mib, 2, kernelVersion, &len, NULL, 0) != 0)
3085 {
3086 free(kernelVersion);
3087 return 0;
3088 }
3089
3090 tok = strtok_s(kernelVersion, ".", &context);
3091 errno = 0;
3092
3093 while (tok)
3094 {
3095 switch (count)
3096 {
3097 case 0:
3098 majorVersion = strtol(tok, NULL, 0);
3099
3100 if (errno != 0)
3101 goto fail;
3102
3103 break;
3104
3105 case 1:
3106 minorVersion = strtol(tok, NULL, 0);
3107
3108 if (errno != 0)
3109 goto fail;
3110
3111 break;
3112
3113 case 2:
3114 patchVersion = strtol(tok, NULL, 0);
3115
3116 if (errno != 0)
3117 goto fail;
3118
3119 break;
3120 }
3121
3122 tok = strtok_s(NULL, ".", &context);
3123 count++;
3124 }
3125
3129 if (majorVersion < 5)
3130 {
3131 if (minorVersion < 4)
3132 version = 0x10000000;
3133 else
3134 version = 0x10010000;
3135 }
3136 else
3137 {
3138 switch (majorVersion)
3139 {
3140 case 5:
3141 version = 0x10010000;
3142 break;
3143
3144 case 6:
3145 version = 0x10020000;
3146 break;
3147
3148 case 7:
3149 version = 0x10030000;
3150 break;
3151
3152 case 8:
3153 version = 0x10040000;
3154 break;
3155
3156 case 9:
3157 version = 0x10050000;
3158 break;
3159
3160 case 10:
3161 version = 0x10060000;
3162 break;
3163
3164 case 11:
3165 version = 0x10070000;
3166 break;
3167
3168 case 12:
3169 version = 0x10080000;
3170 break;
3171
3172 case 13:
3173 version = 0x10090000;
3174 break;
3175
3176 default:
3177 version = 0x10100000;
3178 break;
3179 }
3180
3181 version |= (minorVersion << 8) | (patchVersion);
3182 }
3183
3184fail:
3185 free(kernelVersion);
3186 return version;
3187}
3188#endif
3189
3190static const SCardApiFunctionTable PCSC_SCardApiFunctionTable = {
3191 0, /* dwVersion */
3192 0, /* dwFlags */
3193
3194 PCSC_SCardEstablishContext, /* SCardEstablishContext */
3195 PCSC_SCardReleaseContext, /* SCardReleaseContext */
3196 PCSC_SCardIsValidContext, /* SCardIsValidContext */
3197 PCSC_SCardListReaderGroupsA, /* SCardListReaderGroupsA */
3198 PCSC_SCardListReaderGroupsW, /* SCardListReaderGroupsW */
3199 PCSC_SCardListReadersA, /* SCardListReadersA */
3200 PCSC_SCardListReadersW, /* SCardListReadersW */
3201 PCSC_SCardListCardsA, /* SCardListCardsA */
3202 PCSC_SCardListCardsW, /* SCardListCardsW */
3203 PCSC_SCardListInterfacesA, /* SCardListInterfacesA */
3204 PCSC_SCardListInterfacesW, /* SCardListInterfacesW */
3205 PCSC_SCardGetProviderIdA, /* SCardGetProviderIdA */
3206 PCSC_SCardGetProviderIdW, /* SCardGetProviderIdW */
3207 PCSC_SCardGetCardTypeProviderNameA, /* SCardGetCardTypeProviderNameA */
3208 PCSC_SCardGetCardTypeProviderNameW, /* SCardGetCardTypeProviderNameW */
3209 PCSC_SCardIntroduceReaderGroupA, /* SCardIntroduceReaderGroupA */
3210 PCSC_SCardIntroduceReaderGroupW, /* SCardIntroduceReaderGroupW */
3211 PCSC_SCardForgetReaderGroupA, /* SCardForgetReaderGroupA */
3212 PCSC_SCardForgetReaderGroupW, /* SCardForgetReaderGroupW */
3213 PCSC_SCardIntroduceReaderA, /* SCardIntroduceReaderA */
3214 PCSC_SCardIntroduceReaderW, /* SCardIntroduceReaderW */
3215 PCSC_SCardForgetReaderA, /* SCardForgetReaderA */
3216 PCSC_SCardForgetReaderW, /* SCardForgetReaderW */
3217 PCSC_SCardAddReaderToGroupA, /* SCardAddReaderToGroupA */
3218 PCSC_SCardAddReaderToGroupW, /* SCardAddReaderToGroupW */
3219 PCSC_SCardRemoveReaderFromGroupA, /* SCardRemoveReaderFromGroupA */
3220 PCSC_SCardRemoveReaderFromGroupW, /* SCardRemoveReaderFromGroupW */
3221 PCSC_SCardIntroduceCardTypeA, /* SCardIntroduceCardTypeA */
3222 PCSC_SCardIntroduceCardTypeW, /* SCardIntroduceCardTypeW */
3223 PCSC_SCardSetCardTypeProviderNameA, /* SCardSetCardTypeProviderNameA */
3224 PCSC_SCardSetCardTypeProviderNameW, /* SCardSetCardTypeProviderNameW */
3225 PCSC_SCardForgetCardTypeA, /* SCardForgetCardTypeA */
3226 PCSC_SCardForgetCardTypeW, /* SCardForgetCardTypeW */
3227 PCSC_SCardFreeMemory, /* SCardFreeMemory */
3228 PCSC_SCardAccessStartedEvent, /* SCardAccessStartedEvent */
3229 PCSC_SCardReleaseStartedEvent, /* SCardReleaseStartedEvent */
3230 PCSC_SCardLocateCardsA, /* SCardLocateCardsA */
3231 PCSC_SCardLocateCardsW, /* SCardLocateCardsW */
3232 PCSC_SCardLocateCardsByATRA, /* SCardLocateCardsByATRA */
3233 PCSC_SCardLocateCardsByATRW, /* SCardLocateCardsByATRW */
3234 PCSC_SCardGetStatusChangeA, /* SCardGetStatusChangeA */
3235 PCSC_SCardGetStatusChangeW, /* SCardGetStatusChangeW */
3236 PCSC_SCardCancel, /* SCardCancel */
3237 PCSC_SCardConnectA, /* SCardConnectA */
3238 PCSC_SCardConnectW, /* SCardConnectW */
3239 PCSC_SCardReconnect, /* SCardReconnect */
3240 PCSC_SCardDisconnect, /* SCardDisconnect */
3241 PCSC_SCardBeginTransaction, /* SCardBeginTransaction */
3242 PCSC_SCardEndTransaction, /* SCardEndTransaction */
3243 PCSC_SCardCancelTransaction, /* SCardCancelTransaction */
3244 PCSC_SCardState, /* SCardState */
3245 PCSC_SCardStatusA, /* SCardStatusA */
3246 PCSC_SCardStatusW, /* SCardStatusW */
3247 PCSC_SCardTransmit, /* SCardTransmit */
3248 PCSC_SCardGetTransmitCount, /* SCardGetTransmitCount */
3249 PCSC_SCardControl, /* SCardControl */
3250 PCSC_SCardGetAttrib, /* SCardGetAttrib */
3251 PCSC_SCardSetAttrib, /* SCardSetAttrib */
3252 PCSC_SCardUIDlgSelectCardA, /* SCardUIDlgSelectCardA */
3253 PCSC_SCardUIDlgSelectCardW, /* SCardUIDlgSelectCardW */
3254 PCSC_GetOpenCardNameA, /* GetOpenCardNameA */
3255 PCSC_GetOpenCardNameW, /* GetOpenCardNameW */
3256 PCSC_SCardDlgExtendedError, /* SCardDlgExtendedError */
3257 PCSC_SCardReadCacheA, /* SCardReadCacheA */
3258 PCSC_SCardReadCacheW, /* SCardReadCacheW */
3259 PCSC_SCardWriteCacheA, /* SCardWriteCacheA */
3260 PCSC_SCardWriteCacheW, /* SCardWriteCacheW */
3261 PCSC_SCardGetReaderIconA, /* SCardGetReaderIconA */
3262 PCSC_SCardGetReaderIconW, /* SCardGetReaderIconW */
3263 PCSC_SCardGetDeviceTypeIdA, /* SCardGetDeviceTypeIdA */
3264 PCSC_SCardGetDeviceTypeIdW, /* SCardGetDeviceTypeIdW */
3265 PCSC_SCardGetReaderDeviceInstanceIdA, /* SCardGetReaderDeviceInstanceIdA */
3266 PCSC_SCardGetReaderDeviceInstanceIdW, /* SCardGetReaderDeviceInstanceIdW */
3267 PCSC_SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
3268 PCSC_SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
3269 PCSC_SCardAudit /* SCardAudit */
3270};
3271
3272const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void)
3273{
3274 return &PCSC_SCardApiFunctionTable;
3275}
3276
3277int PCSC_InitializeSCardApi(void)
3278{
3279 /* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
3280 SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
3281#ifdef __MACOSX__
3282 g_PCSCModule = LoadLibraryX("/System/Library/Frameworks/PCSC.framework/PCSC");
3283 OSXVersion = determineMacOSXVersion();
3284
3285 if (OSXVersion == 0)
3286 return -1;
3287
3288#else
3289 g_PCSCModule = LoadLibraryA("libpcsclite.so.1");
3290
3291 if (!g_PCSCModule)
3292 g_PCSCModule = LoadLibraryA("libpcsclite.so");
3293
3294#endif
3295
3296 if (!g_PCSCModule)
3297 return -1;
3298
3299 /* symbols defined in winpr/smartcard.h, might pose an issue with the GetProcAddress macro
3300 * below. therefore undefine them here */
3301#undef SCardListReaderGroups
3302#undef SCardListReaders
3303#undef SCardListCards
3304#undef SCardListInterfaces
3305#undef SCardGetProviderId
3306#undef SCardGetCardTypeProviderName
3307#undef SCardIntroduceReaderGroup
3308#undef SCardForgetReaderGroup
3309#undef SCardIntroduceReader
3310#undef SCardForgetReader
3311#undef SCardAddReaderToGroup
3312#undef SCardRemoveReaderFromGroup
3313#undef SCardIntroduceCardType
3314#undef SCardSetCardTypeProviderName
3315#undef SCardForgetCardType
3316#undef SCardLocateCards
3317#undef SCardLocateCardsByATR
3318#undef SCardGetStatusChange
3319#undef SCardConnect
3320#undef SCardStatus
3321#undef SCardUIDlgSelectCard
3322#undef GetOpenCardName
3323#undef SCardReadCache
3324#undef SCardWriteCache
3325#undef SCardGetReaderIcon
3326#undef SCardGetDeviceTypeId
3327#undef SCardGetReaderDeviceInstanceId
3328#undef SCardListReadersWithDeviceInstanceId
3329
3330 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEstablishContext);
3331 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReleaseContext);
3332 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardIsValidContext);
3333 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardConnect);
3334 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReconnect);
3335 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardDisconnect);
3336 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardBeginTransaction);
3337 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEndTransaction);
3338 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardStatus);
3339 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetStatusChange);
3340
3341#ifdef __MACOSX__
3342
3343 if (OSXVersion >= 0x10050600)
3344 {
3345 WINSCARD_LOAD_PROC_EX(g_PCSCModule, g_PCSC, SCardControl, SCardControl132);
3346 }
3347 else
3348 {
3349 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3350 }
3351#else
3352 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
3353#endif
3354 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardTransmit);
3355 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaderGroups);
3356 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaders);
3357 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardCancel);
3358 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetAttrib);
3359 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardSetAttrib);
3360 g_PCSC.pfnSCardFreeMemory = NULL;
3361#ifndef __APPLE__
3362 WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardFreeMemory);
3363#endif
3364
3365 if (g_PCSC.pfnSCardFreeMemory)
3366 g_SCardAutoAllocate = TRUE;
3367
3368#ifdef DISABLE_PCSC_SCARD_AUTOALLOCATE
3369 g_PCSC.pfnSCardFreeMemory = NULL;
3370 g_SCardAutoAllocate = FALSE;
3371#endif
3372#ifdef __APPLE__
3373 g_PnP_Notification = FALSE;
3374#endif
3375 return 1;
3376}
3377
3378#endif
Definition wtypes.h:252
This struct contains function pointer to initialize/free objects.
Definition collections.h:57