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