summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/smartcard
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--winpr/libwinpr/smartcard/CMakeLists.txt60
-rw-r--r--winpr/libwinpr/smartcard/ModuleOptions.cmake9
-rw-r--r--winpr/libwinpr/smartcard/smartcard.c1283
-rw-r--r--winpr/libwinpr/smartcard/smartcard.h31
-rw-r--r--winpr/libwinpr/smartcard/smartcard_inspect.c1363
-rw-r--r--winpr/libwinpr/smartcard/smartcard_inspect.h30
-rw-r--r--winpr/libwinpr/smartcard/smartcard_pcsc.c3357
-rw-r--r--winpr/libwinpr/smartcard/smartcard_pcsc.h175
-rw-r--r--winpr/libwinpr/smartcard/smartcard_windows.c126
-rw-r--r--winpr/libwinpr/smartcard/smartcard_windows.h28
-rw-r--r--winpr/libwinpr/smartcard/test/CMakeLists.txt26
-rw-r--r--winpr/libwinpr/smartcard/test/TestSmartCardListReaders.c53
-rw-r--r--winpr/libwinpr/smartcard/test/TestSmartCardStatus.c160
13 files changed, 6701 insertions, 0 deletions
diff --git a/winpr/libwinpr/smartcard/CMakeLists.txt b/winpr/libwinpr/smartcard/CMakeLists.txt
new file mode 100644
index 0000000..68e5277
--- /dev/null
+++ b/winpr/libwinpr/smartcard/CMakeLists.txt
@@ -0,0 +1,60 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-smartcard cmake build script
+#
+# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(MODULE_PREFIX "WINPR_SMARTCARD")
+
+if(PCSC_WINPR_FOUND)
+ winpr_definition_add(-DWITH_WINPR_PCSC)
+endif()
+
+option(WITH_SMARTCARD_PCSC "Enable smartcard PCSC backend" ON)
+
+
+set(${MODULE_PREFIX}_SRCS
+ smartcard.c
+ smartcard.h)
+
+if(WITH_SMARTCARD_PCSC)
+ winpr_definition_add(-DWITH_SMARTCARD_PCSC)
+ list(APPEND ${MODULE_PREFIX}_SRCS
+ smartcard_pcsc.c
+ smartcard_pcsc.h)
+endif()
+
+if(WITH_SMARTCARD_INSPECT)
+ winpr_definition_add(-DWITH_SMARTCARD_INSPECT)
+ list(APPEND ${MODULE_PREFIX}_SRCS
+ smartcard_inspect.c
+ smartcard_inspect.h)
+endif()
+
+if(WIN32)
+ list(APPEND ${MODULE_PREFIX}_SRCS
+ smartcard_windows.c
+ smartcard_windows.h)
+endif()
+
+winpr_module_add(${${MODULE_PREFIX}_SRCS})
+
+if(PCSC_WINPR_FOUND)
+ winpr_library_add_private(${PCSC_WINPR_LIBRARY})
+endif()
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
+
diff --git a/winpr/libwinpr/smartcard/ModuleOptions.cmake b/winpr/libwinpr/smartcard/ModuleOptions.cmake
new file mode 100644
index 0000000..afb4a1e
--- /dev/null
+++ b/winpr/libwinpr/smartcard/ModuleOptions.cmake
@@ -0,0 +1,9 @@
+
+set(MINWIN_LAYER "0")
+set(MINWIN_GROUP "none")
+set(MINWIN_MAJOR_VERSION "0")
+set(MINWIN_MINOR_VERSION "0")
+set(MINWIN_SHORT_NAME "smartcard")
+set(MINWIN_LONG_NAME "Smart Card API")
+set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")
+
diff --git a/winpr/libwinpr/smartcard/smartcard.c b/winpr/libwinpr/smartcard/smartcard.c
new file mode 100644
index 0000000..0a79663
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard.c
@@ -0,0 +1,1283 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2020 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2020 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/library.h>
+#include <winpr/smartcard.h>
+#include <winpr/synch.h>
+#include <winpr/wlog.h>
+#include <winpr/assert.h>
+
+#include "../log.h"
+
+#include "smartcard.h"
+
+#if defined(WITH_SMARTCARD_INSPECT)
+#include "smartcard_inspect.h"
+#endif
+
+static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
+static const SCardApiFunctionTable* g_SCardApi = NULL;
+
+#define TAG WINPR_TAG("smartcard")
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define SCARDAPI_STUB_CALL_LONG(_name, ...) \
+ InitOnceExecuteOnce(&g_Initialized, InitializeSCardApiStubs, NULL, NULL); \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ return SCARD_E_NO_SERVICE; \
+ } \
+ return g_SCardApi->pfn##_name(__VA_ARGS__)
+
+#define SCARDAPI_STUB_CALL_HANDLE(_name, ...) \
+ InitOnceExecuteOnce(&g_Initialized, InitializeSCardApiStubs, NULL, NULL); \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ return NULL; \
+ } \
+ return g_SCardApi->pfn##_name(__VA_ARGS__)
+
+#define SCARDAPI_STUB_CALL_VOID(_name, ...) \
+ InitOnceExecuteOnce(&g_Initialized, InitializeSCardApiStubs, NULL, NULL); \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ return; \
+ } \
+ g_SCardApi->pfn##_name(__VA_ARGS__)
+
+/**
+ * Standard Windows Smart Card API
+ */
+
+const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
+const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
+const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
+
+static BOOL CALLBACK InitializeSCardApiStubs(PINIT_ONCE once, PVOID param, PVOID* context)
+{
+#ifdef _WIN32
+ if (Windows_InitializeSCardApi() >= 0)
+ g_SCardApi = Windows_GetSCardApiFunctionTable();
+#else
+#if defined(WITH_SMARTCARD_PCSC)
+ if (PCSC_InitializeSCardApi() >= 0)
+ g_SCardApi = PCSC_GetSCardApiFunctionTable();
+#endif
+#endif
+
+#if defined(WITH_SMARTCARD_INSPECT)
+ g_SCardApi = Inspect_RegisterSCardApi(g_SCardApi);
+#endif
+ return TRUE;
+}
+
+WINSCARDAPI LONG WINAPI SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardEstablishContext, dwScope, pvReserved1, pvReserved2, phContext);
+}
+
+WINSCARDAPI LONG WINAPI SCardReleaseContext(SCARDCONTEXT hContext)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardReleaseContext, hContext);
+}
+
+WINSCARDAPI LONG WINAPI SCardIsValidContext(SCARDCONTEXT hContext)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIsValidContext, hContext);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReaderGroupsA(SCARDCONTEXT hContext, LPSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReaderGroupsA, hContext, mszGroups, pcchGroups);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReaderGroupsW(SCARDCONTEXT hContext, LPWSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReaderGroupsW, hContext, mszGroups, pcchGroups);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReadersA(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReadersA, hContext, mszGroups, mszReaders, pcchReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReadersW(SCARDCONTEXT hContext, LPCWSTR mszGroups,
+ LPWSTR mszReaders, LPDWORD pcchReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReadersW, hContext, mszGroups, mszReaders, pcchReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardListCardsA(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ CHAR* mszCards, LPDWORD pcchCards)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListCardsA, hContext, pbAtr, rgquidInterfaces, cguidInterfaceCount,
+ mszCards, pcchCards);
+}
+
+WINSCARDAPI LONG WINAPI SCardListCardsW(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ WCHAR* mszCards, LPDWORD pcchCards)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListCardsW, hContext, pbAtr, rgquidInterfaces, cguidInterfaceCount,
+ mszCards, pcchCards);
+}
+
+WINSCARDAPI LONG WINAPI SCardListInterfacesA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListInterfacesA, hContext, szCard, pguidInterfaces,
+ pcguidInterfaces);
+}
+
+WINSCARDAPI LONG WINAPI SCardListInterfacesW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListInterfacesW, hContext, szCard, pguidInterfaces,
+ pcguidInterfaces);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetProviderIdA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidProviderId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetProviderIdA, hContext, szCard, pguidProviderId);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetProviderIdW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidProviderId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetProviderIdW, hContext, szCard, pguidProviderId);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, CHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetCardTypeProviderNameA, hContext, szCardName, dwProviderId,
+ szProvider, pcchProvider);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, WCHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetCardTypeProviderNameW, hContext, szCardName, dwProviderId,
+ szProvider, pcchProvider);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceReaderGroupA, hContext, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceReaderGroupW, hContext, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetReaderGroupA, hContext, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetReaderGroupW, hContext, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szDeviceName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceReaderA, hContext, szReaderName, szDeviceName);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szDeviceName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceReaderW, hContext, szReaderName, szDeviceName);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetReaderA, hContext, szReaderName);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetReaderW, hContext, szReaderName);
+}
+
+WINSCARDAPI LONG WINAPI SCardAddReaderToGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardAddReaderToGroupA, hContext, szReaderName, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardAddReaderToGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardAddReaderToGroupW, hContext, szReaderName, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardRemoveReaderFromGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardRemoveReaderFromGroupA, hContext, szReaderName, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardRemoveReaderFromGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardRemoveReaderFromGroupW, hContext, szReaderName, szGroupName);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceCardTypeA, hContext, szCardName, pguidPrimaryProvider,
+ rgguidInterfaces, dwInterfaceCount, pbAtr, pbAtrMask, cbAtrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardIntroduceCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardIntroduceCardTypeW, hContext, szCardName, pguidPrimaryProvider,
+ rgguidInterfaces, dwInterfaceCount, pbAtr, pbAtrMask, cbAtrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardSetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, LPCSTR szProvider)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardSetCardTypeProviderNameA, hContext, szCardName, dwProviderId,
+ szProvider);
+}
+
+WINSCARDAPI LONG WINAPI SCardSetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, LPCWSTR szProvider)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardSetCardTypeProviderNameW, hContext, szCardName, dwProviderId,
+ szProvider);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetCardTypeA, hContext, szCardName);
+}
+
+WINSCARDAPI LONG WINAPI SCardForgetCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardForgetCardTypeW, hContext, szCardName);
+}
+
+WINSCARDAPI LONG WINAPI SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardFreeMemory, hContext, pvMem);
+}
+
+WINSCARDAPI HANDLE WINAPI SCardAccessStartedEvent(void)
+{
+ SCARDAPI_STUB_CALL_HANDLE(SCardAccessStartedEvent);
+}
+
+WINSCARDAPI void WINAPI SCardReleaseStartedEvent(void)
+{
+ SCARDAPI_STUB_CALL_VOID(SCardReleaseStartedEvent);
+}
+
+WINSCARDAPI LONG WINAPI SCardLocateCardsA(SCARDCONTEXT hContext, LPCSTR mszCards,
+ LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardLocateCardsA, hContext, mszCards, rgReaderStates, cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardLocateCardsW(SCARDCONTEXT hContext, LPCWSTR mszCards,
+ LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardLocateCardsW, hContext, mszCards, rgReaderStates, cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardLocateCardsByATRA(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEA rgReaderStates,
+ DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardLocateCardsByATRA, hContext, rgAtrMasks, cAtrs, rgReaderStates,
+ cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardLocateCardsByATRW(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEW rgReaderStates,
+ DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardLocateCardsByATRW, hContext, rgAtrMasks, cAtrs, rgReaderStates,
+ cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetStatusChangeA(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetStatusChangeA, hContext, dwTimeout, rgReaderStates, cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetStatusChangeW(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetStatusChangeW, hContext, dwTimeout, rgReaderStates, cReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardCancel(SCARDCONTEXT hContext)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardCancel, hContext);
+}
+
+WINSCARDAPI LONG WINAPI SCardConnectA(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardConnectA, hContext, szReader, dwShareMode, dwPreferredProtocols,
+ phCard, pdwActiveProtocol);
+}
+
+WINSCARDAPI LONG WINAPI SCardConnectW(SCARDCONTEXT hContext, LPCWSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardConnectW, hContext, szReader, dwShareMode, dwPreferredProtocols,
+ phCard, pdwActiveProtocol);
+}
+
+WINSCARDAPI LONG WINAPI SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, DWORD dwInitialization,
+ LPDWORD pdwActiveProtocol)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardReconnect, hCard, dwShareMode, dwPreferredProtocols,
+ dwInitialization, pdwActiveProtocol);
+}
+
+WINSCARDAPI LONG WINAPI SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardDisconnect, hCard, dwDisposition);
+}
+
+WINSCARDAPI LONG WINAPI SCardBeginTransaction(SCARDHANDLE hCard)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardBeginTransaction, hCard);
+}
+
+WINSCARDAPI LONG WINAPI SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardEndTransaction, hCard, dwDisposition);
+}
+
+WINSCARDAPI LONG WINAPI SCardCancelTransaction(SCARDHANDLE hCard)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardCancelTransaction, hCard);
+}
+
+WINSCARDAPI LONG WINAPI SCardState(SCARDHANDLE hCard, LPDWORD pdwState, LPDWORD pdwProtocol,
+ LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardState, hCard, pdwState, pdwProtocol, pbAtr, pcbAtrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardStatusA(SCARDHANDLE hCard, LPSTR mszReaderNames, LPDWORD pcchReaderLen,
+ LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr,
+ LPDWORD pcbAtrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardStatusA, hCard, mszReaderNames, pcchReaderLen, pdwState,
+ pdwProtocol, pbAtr, pcbAtrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardStatusW(SCARDHANDLE hCard, LPWSTR mszReaderNames,
+ LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol,
+ LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardStatusW, hCard, mszReaderNames, pcchReaderLen, pdwState,
+ pdwProtocol, pbAtr, pcbAtrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
+ LPCBYTE pbSendBuffer, DWORD cbSendLength,
+ LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
+ LPDWORD pcbRecvLength)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardTransmit, hCard, pioSendPci, pbSendBuffer, cbSendLength,
+ pioRecvPci, pbRecvBuffer, pcbRecvLength);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetTransmitCount(SCARDHANDLE hCard, LPDWORD pcTransmitCount)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetTransmitCount, hCard, pcTransmitCount);
+}
+
+WINSCARDAPI LONG WINAPI SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID lpInBuffer,
+ DWORD cbInBufferSize, LPVOID lpOutBuffer,
+ DWORD cbOutBufferSize, LPDWORD lpBytesReturned)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardControl, hCard, dwControlCode, lpInBuffer, cbInBufferSize,
+ lpOutBuffer, cbOutBufferSize, lpBytesReturned);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
+ LPDWORD pcbAttrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetAttrib, hCard, dwAttrId, pbAttr, pcbAttrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
+ DWORD cbAttrLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardSetAttrib, hCard, dwAttrId, pbAttr, cbAttrLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardUIDlgSelectCardA, pDlgStruc);
+}
+
+WINSCARDAPI LONG WINAPI SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardUIDlgSelectCardW, pDlgStruc);
+}
+
+WINSCARDAPI LONG WINAPI GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
+{
+ SCARDAPI_STUB_CALL_LONG(GetOpenCardNameA, pDlgStruc);
+}
+
+WINSCARDAPI LONG WINAPI GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
+{
+ SCARDAPI_STUB_CALL_LONG(GetOpenCardNameW, pDlgStruc);
+}
+
+WINSCARDAPI LONG WINAPI SCardDlgExtendedError(void)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardDlgExtendedError);
+}
+
+WINSCARDAPI LONG WINAPI SCardReadCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardReadCacheA, hContext, CardIdentifier, FreshnessCounter, LookupName,
+ Data, DataLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardReadCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardReadCacheW, hContext, CardIdentifier, FreshnessCounter, LookupName,
+ Data, DataLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardWriteCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardWriteCacheA, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardWriteCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardWriteCacheW, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetReaderIconA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetReaderIconA, hContext, szReaderName, pbIcon, pcbIcon);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetReaderIconW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetReaderIconW, hContext, szReaderName, pbIcon, pcbIcon);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetDeviceTypeIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetDeviceTypeIdA, hContext, szReaderName, pdwDeviceTypeId);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetDeviceTypeIdW, hContext, szReaderName, pdwDeviceTypeId);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetReaderDeviceInstanceIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetReaderDeviceInstanceIdA, hContext, szReaderName,
+ szDeviceInstanceId, pcchDeviceInstanceId);
+}
+
+WINSCARDAPI LONG WINAPI SCardGetReaderDeviceInstanceIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPWSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardGetReaderDeviceInstanceIdW, hContext, szReaderName,
+ szDeviceInstanceId, pcchDeviceInstanceId);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReadersWithDeviceInstanceIdA(SCARDCONTEXT hContext,
+ LPCSTR szDeviceInstanceId,
+ LPSTR mszReaders, LPDWORD pcchReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReadersWithDeviceInstanceIdA, hContext, szDeviceInstanceId,
+ mszReaders, pcchReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardListReadersWithDeviceInstanceIdW(SCARDCONTEXT hContext,
+ LPCWSTR szDeviceInstanceId,
+ LPWSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardListReadersWithDeviceInstanceIdW, hContext, szDeviceInstanceId,
+ mszReaders, pcchReaders);
+}
+
+WINSCARDAPI LONG WINAPI SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
+{
+ SCARDAPI_STUB_CALL_LONG(SCardAudit, hContext, dwEvent);
+}
+
+/**
+ * Extended API
+ */
+
+WINSCARDAPI const char* WINAPI SCardGetErrorString(LONG errorCode)
+{
+ switch (errorCode)
+ {
+ case SCARD_S_SUCCESS:
+ return "SCARD_S_SUCCESS";
+
+ case SCARD_F_INTERNAL_ERROR:
+ return "SCARD_F_INTERNAL_ERROR";
+
+ case SCARD_E_CANCELLED:
+ return "SCARD_E_CANCELLED";
+
+ case SCARD_E_INVALID_HANDLE:
+ return "SCARD_E_INVALID_HANDLE";
+
+ case SCARD_E_INVALID_PARAMETER:
+ return "SCARD_E_INVALID_PARAMETER";
+
+ case SCARD_E_INVALID_TARGET:
+ return "SCARD_E_INVALID_TARGET";
+
+ case SCARD_E_NO_MEMORY:
+ return "SCARD_E_NO_MEMORY";
+
+ case SCARD_F_WAITED_TOO_LONG:
+ return "SCARD_F_WAITED_TOO_LONG";
+
+ case SCARD_E_INSUFFICIENT_BUFFER:
+ return "SCARD_E_INSUFFICIENT_BUFFER";
+
+ case SCARD_E_UNKNOWN_READER:
+ return "SCARD_E_UNKNOWN_READER";
+
+ case SCARD_E_TIMEOUT:
+ return "SCARD_E_TIMEOUT";
+
+ case SCARD_E_SHARING_VIOLATION:
+ return "SCARD_E_SHARING_VIOLATION";
+
+ case SCARD_E_NO_SMARTCARD:
+ return "SCARD_E_NO_SMARTCARD";
+
+ case SCARD_E_UNKNOWN_CARD:
+ return "SCARD_E_UNKNOWN_CARD";
+
+ case SCARD_E_CANT_DISPOSE:
+ return "SCARD_E_CANT_DISPOSE";
+
+ case SCARD_E_PROTO_MISMATCH:
+ return "SCARD_E_PROTO_MISMATCH";
+
+ case SCARD_E_NOT_READY:
+ return "SCARD_E_NOT_READY";
+
+ case SCARD_E_INVALID_VALUE:
+ return "SCARD_E_INVALID_VALUE";
+
+ case SCARD_E_SYSTEM_CANCELLED:
+ return "SCARD_E_SYSTEM_CANCELLED";
+
+ case SCARD_F_COMM_ERROR:
+ return "SCARD_F_COMM_ERROR";
+
+ case SCARD_F_UNKNOWN_ERROR:
+ return "SCARD_F_UNKNOWN_ERROR";
+
+ case SCARD_E_INVALID_ATR:
+ return "SCARD_E_INVALID_ATR";
+
+ case SCARD_E_NOT_TRANSACTED:
+ return "SCARD_E_NOT_TRANSACTED";
+
+ case SCARD_E_READER_UNAVAILABLE:
+ return "SCARD_E_READER_UNAVAILABLE";
+
+ case SCARD_P_SHUTDOWN:
+ return "SCARD_P_SHUTDOWN";
+
+ case SCARD_E_PCI_TOO_SMALL:
+ return "SCARD_E_PCI_TOO_SMALL";
+
+ case SCARD_E_READER_UNSUPPORTED:
+ return "SCARD_E_READER_UNSUPPORTED";
+
+ case SCARD_E_DUPLICATE_READER:
+ return "SCARD_E_DUPLICATE_READER";
+
+ case SCARD_E_CARD_UNSUPPORTED:
+ return "SCARD_E_CARD_UNSUPPORTED";
+
+ case SCARD_E_NO_SERVICE:
+ return "SCARD_E_NO_SERVICE";
+
+ case SCARD_E_SERVICE_STOPPED:
+ return "SCARD_E_SERVICE_STOPPED";
+
+ case SCARD_E_UNEXPECTED:
+ return "SCARD_E_UNEXPECTED";
+
+ case SCARD_E_ICC_INSTALLATION:
+ return "SCARD_E_ICC_INSTALLATION";
+
+ case SCARD_E_ICC_CREATEORDER:
+ return "SCARD_E_ICC_CREATEORDER";
+
+ case SCARD_E_UNSUPPORTED_FEATURE:
+ return "SCARD_E_UNSUPPORTED_FEATURE";
+
+ case SCARD_E_DIR_NOT_FOUND:
+ return "SCARD_E_DIR_NOT_FOUND";
+
+ case SCARD_E_FILE_NOT_FOUND:
+ return "SCARD_E_FILE_NOT_FOUND";
+
+ case SCARD_E_NO_DIR:
+ return "SCARD_E_NO_DIR";
+
+ case SCARD_E_NO_FILE:
+ return "SCARD_E_NO_FILE";
+
+ case SCARD_E_NO_ACCESS:
+ return "SCARD_E_NO_ACCESS";
+
+ case SCARD_E_WRITE_TOO_MANY:
+ return "SCARD_E_WRITE_TOO_MANY";
+
+ case SCARD_E_BAD_SEEK:
+ return "SCARD_E_BAD_SEEK";
+
+ case SCARD_E_INVALID_CHV:
+ return "SCARD_E_INVALID_CHV";
+
+ case SCARD_E_UNKNOWN_RES_MNG:
+ return "SCARD_E_UNKNOWN_RES_MNG";
+
+ case SCARD_E_NO_SUCH_CERTIFICATE:
+ return "SCARD_E_NO_SUCH_CERTIFICATE";
+
+ case SCARD_E_CERTIFICATE_UNAVAILABLE:
+ return "SCARD_E_CERTIFICATE_UNAVAILABLE";
+
+ case SCARD_E_NO_READERS_AVAILABLE:
+ return "SCARD_E_NO_READERS_AVAILABLE";
+
+ case SCARD_E_COMM_DATA_LOST:
+ return "SCARD_E_COMM_DATA_LOST";
+
+ case SCARD_E_NO_KEY_CONTAINER:
+ return "SCARD_E_NO_KEY_CONTAINER";
+
+ case SCARD_E_SERVER_TOO_BUSY:
+ return "SCARD_E_SERVER_TOO_BUSY";
+
+ case SCARD_E_PIN_CACHE_EXPIRED:
+ return "SCARD_E_PIN_CACHE_EXPIRED";
+
+ case SCARD_E_NO_PIN_CACHE:
+ return "SCARD_E_NO_PIN_CACHE";
+
+ case SCARD_E_READ_ONLY_CARD:
+ return "SCARD_E_READ_ONLY_CARD";
+
+ case SCARD_W_UNSUPPORTED_CARD:
+ return "SCARD_W_UNSUPPORTED_CARD";
+
+ case SCARD_W_UNRESPONSIVE_CARD:
+ return "SCARD_W_UNRESPONSIVE_CARD";
+
+ case SCARD_W_UNPOWERED_CARD:
+ return "SCARD_W_UNPOWERED_CARD";
+
+ case SCARD_W_RESET_CARD:
+ return "SCARD_W_RESET_CARD";
+
+ case SCARD_W_REMOVED_CARD:
+ return "SCARD_W_REMOVED_CARD";
+
+ case SCARD_W_SECURITY_VIOLATION:
+ return "SCARD_W_SECURITY_VIOLATION";
+
+ case SCARD_W_WRONG_CHV:
+ return "SCARD_W_WRONG_CHV";
+
+ case SCARD_W_CHV_BLOCKED:
+ return "SCARD_W_CHV_BLOCKED";
+
+ case SCARD_W_EOF:
+ return "SCARD_W_EOF";
+
+ case SCARD_W_CANCELLED_BY_USER:
+ return "SCARD_W_CANCELLED_BY_USER";
+
+ case SCARD_W_CARD_NOT_AUTHENTICATED:
+ return "SCARD_W_CARD_NOT_AUTHENTICATED";
+
+ case SCARD_W_CACHE_ITEM_NOT_FOUND:
+ return "SCARD_W_CACHE_ITEM_NOT_FOUND";
+
+ case SCARD_W_CACHE_ITEM_STALE:
+ return "SCARD_W_CACHE_ITEM_STALE";
+
+ case SCARD_W_CACHE_ITEM_TOO_BIG:
+ return "SCARD_W_CACHE_ITEM_TOO_BIG";
+
+ default:
+ return "SCARD_E_UNKNOWN";
+ }
+}
+
+WINSCARDAPI const char* WINAPI SCardGetAttributeString(DWORD dwAttrId)
+{
+ switch (dwAttrId)
+ {
+ case SCARD_ATTR_VENDOR_NAME:
+ return "SCARD_ATTR_VENDOR_NAME";
+
+ case SCARD_ATTR_VENDOR_IFD_TYPE:
+ return "SCARD_ATTR_VENDOR_IFD_TYPE";
+
+ case SCARD_ATTR_VENDOR_IFD_VERSION:
+ return "SCARD_ATTR_VENDOR_IFD_VERSION";
+
+ case SCARD_ATTR_VENDOR_IFD_SERIAL_NO:
+ return "SCARD_ATTR_VENDOR_IFD_SERIAL_NO";
+
+ case SCARD_ATTR_CHANNEL_ID:
+ return "SCARD_ATTR_CHANNEL_ID";
+
+ case SCARD_ATTR_PROTOCOL_TYPES:
+ return "SCARD_ATTR_PROTOCOL_TYPES";
+
+ case SCARD_ATTR_DEFAULT_CLK:
+ return "SCARD_ATTR_DEFAULT_CLK";
+
+ case SCARD_ATTR_MAX_CLK:
+ return "SCARD_ATTR_MAX_CLK";
+
+ case SCARD_ATTR_DEFAULT_DATA_RATE:
+ return "SCARD_ATTR_DEFAULT_DATA_RATE";
+
+ case SCARD_ATTR_MAX_DATA_RATE:
+ return "SCARD_ATTR_MAX_DATA_RATE";
+
+ case SCARD_ATTR_MAX_IFSD:
+ return "SCARD_ATTR_MAX_IFSD";
+
+ case SCARD_ATTR_POWER_MGMT_SUPPORT:
+ return "SCARD_ATTR_POWER_MGMT_SUPPORT";
+
+ case SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE:
+ return "SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE";
+
+ case SCARD_ATTR_USER_AUTH_INPUT_DEVICE:
+ return "SCARD_ATTR_USER_AUTH_INPUT_DEVICE";
+
+ case SCARD_ATTR_CHARACTERISTICS:
+ return "SCARD_ATTR_CHARACTERISTICS";
+
+ case SCARD_ATTR_CURRENT_PROTOCOL_TYPE:
+ return "SCARD_ATTR_CURRENT_PROTOCOL_TYPE";
+
+ case SCARD_ATTR_CURRENT_CLK:
+ return "SCARD_ATTR_CURRENT_CLK";
+
+ case SCARD_ATTR_CURRENT_F:
+ return "SCARD_ATTR_CURRENT_F";
+
+ case SCARD_ATTR_CURRENT_D:
+ return "SCARD_ATTR_CURRENT_D";
+
+ case SCARD_ATTR_CURRENT_N:
+ return "SCARD_ATTR_CURRENT_N";
+
+ case SCARD_ATTR_CURRENT_W:
+ return "SCARD_ATTR_CURRENT_W";
+
+ case SCARD_ATTR_CURRENT_IFSC:
+ return "SCARD_ATTR_CURRENT_IFSC";
+
+ case SCARD_ATTR_CURRENT_IFSD:
+ return "SCARD_ATTR_CURRENT_IFSD";
+
+ case SCARD_ATTR_CURRENT_BWT:
+ return "SCARD_ATTR_CURRENT_BWT";
+
+ case SCARD_ATTR_CURRENT_CWT:
+ return "SCARD_ATTR_CURRENT_CWT";
+
+ case SCARD_ATTR_CURRENT_EBC_ENCODING:
+ return "SCARD_ATTR_CURRENT_EBC_ENCODING";
+
+ case SCARD_ATTR_EXTENDED_BWT:
+ return "SCARD_ATTR_EXTENDED_BWT";
+
+ case SCARD_ATTR_ICC_PRESENCE:
+ return "SCARD_ATTR_ICC_PRESENCE";
+
+ case SCARD_ATTR_ICC_INTERFACE_STATUS:
+ return "SCARD_ATTR_ICC_INTERFACE_STATUS";
+
+ case SCARD_ATTR_CURRENT_IO_STATE:
+ return "SCARD_ATTR_CURRENT_IO_STATE";
+
+ case SCARD_ATTR_ATR_STRING:
+ return "SCARD_ATTR_ATR_STRING";
+
+ case SCARD_ATTR_ICC_TYPE_PER_ATR:
+ return "SCARD_ATTR_ICC_TYPE_PER_ATR";
+
+ case SCARD_ATTR_ESC_RESET:
+ return "SCARD_ATTR_ESC_RESET";
+
+ case SCARD_ATTR_ESC_CANCEL:
+ return "SCARD_ATTR_ESC_CANCEL";
+
+ case SCARD_ATTR_ESC_AUTHREQUEST:
+ return "SCARD_ATTR_ESC_AUTHREQUEST";
+
+ case SCARD_ATTR_MAXINPUT:
+ return "SCARD_ATTR_MAXINPUT";
+
+ case SCARD_ATTR_DEVICE_UNIT:
+ return "SCARD_ATTR_DEVICE_UNIT";
+
+ case SCARD_ATTR_DEVICE_IN_USE:
+ return "SCARD_ATTR_DEVICE_IN_USE";
+
+ case SCARD_ATTR_DEVICE_FRIENDLY_NAME_A:
+ return "SCARD_ATTR_DEVICE_FRIENDLY_NAME_A";
+
+ case SCARD_ATTR_DEVICE_SYSTEM_NAME_A:
+ return "SCARD_ATTR_DEVICE_SYSTEM_NAME_A";
+
+ case SCARD_ATTR_DEVICE_FRIENDLY_NAME_W:
+ return "SCARD_ATTR_DEVICE_FRIENDLY_NAME_W";
+
+ case SCARD_ATTR_DEVICE_SYSTEM_NAME_W:
+ return "SCARD_ATTR_DEVICE_SYSTEM_NAME_W";
+
+ case SCARD_ATTR_SUPRESS_T1_IFS_REQUEST:
+ return "SCARD_ATTR_SUPRESS_T1_IFS_REQUEST";
+
+ default:
+ return "SCARD_ATTR_UNKNOWN";
+ }
+}
+
+WINSCARDAPI const char* WINAPI SCardGetProtocolString(DWORD dwProtocols)
+{
+ if (dwProtocols == SCARD_PROTOCOL_UNDEFINED)
+ return "SCARD_PROTOCOL_UNDEFINED";
+
+ if (dwProtocols == SCARD_PROTOCOL_T0)
+ return "SCARD_PROTOCOL_T0";
+
+ if (dwProtocols == SCARD_PROTOCOL_T1)
+ return "SCARD_PROTOCOL_T1";
+
+ if (dwProtocols == SCARD_PROTOCOL_Tx)
+ return "SCARD_PROTOCOL_Tx";
+
+ if (dwProtocols == SCARD_PROTOCOL_RAW)
+ return "SCARD_PROTOCOL_RAW";
+
+ if (dwProtocols == SCARD_PROTOCOL_DEFAULT)
+ return "SCARD_PROTOCOL_DEFAULT";
+
+ if (dwProtocols == (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_RAW))
+ return "SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_RAW";
+
+ if (dwProtocols == (SCARD_PROTOCOL_T1 | SCARD_PROTOCOL_RAW))
+ return "SCARD_PROTOCOL_T1 | SCARD_PROTOCOL_RAW";
+
+ if (dwProtocols == (SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW))
+ return "SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW";
+
+ return "SCARD_PROTOCOL_UNKNOWN";
+}
+
+WINSCARDAPI const char* WINAPI SCardGetShareModeString(DWORD dwShareMode)
+{
+ switch (dwShareMode)
+ {
+ case SCARD_SHARE_EXCLUSIVE:
+ return "SCARD_SHARE_EXCLUSIVE";
+
+ case SCARD_SHARE_SHARED:
+ return "SCARD_SHARE_SHARED";
+
+ case SCARD_SHARE_DIRECT:
+ return "SCARD_SHARE_DIRECT";
+
+ default:
+ return "SCARD_SHARE_UNKNOWN";
+ }
+}
+
+WINSCARDAPI const char* WINAPI SCardGetDispositionString(DWORD dwDisposition)
+{
+ switch (dwDisposition)
+ {
+ case SCARD_LEAVE_CARD:
+ return "SCARD_LEAVE_CARD";
+
+ case SCARD_RESET_CARD:
+ return "SCARD_RESET_CARD";
+
+ case SCARD_UNPOWER_CARD:
+ return "SCARD_UNPOWER_CARD";
+
+ default:
+ return "SCARD_UNKNOWN_CARD";
+ }
+}
+
+WINSCARDAPI const char* WINAPI SCardGetScopeString(DWORD dwScope)
+{
+ switch (dwScope)
+ {
+ case SCARD_SCOPE_USER:
+ return "SCARD_SCOPE_USER";
+
+ case SCARD_SCOPE_TERMINAL:
+ return "SCARD_SCOPE_TERMINAL";
+
+ case SCARD_SCOPE_SYSTEM:
+ return "SCARD_SCOPE_SYSTEM";
+
+ default:
+ return "SCARD_SCOPE_UNKNOWN";
+ }
+}
+
+WINSCARDAPI const char* WINAPI SCardGetCardStateString(DWORD dwCardState)
+{
+ switch (dwCardState)
+ {
+ case SCARD_UNKNOWN:
+ return "SCARD_UNKNOWN";
+
+ case SCARD_ABSENT:
+ return "SCARD_ABSENT";
+
+ case SCARD_PRESENT:
+ return "SCARD_PRESENT";
+
+ case SCARD_SWALLOWED:
+ return "SCARD_SWALLOWED";
+
+ case SCARD_POWERED:
+ return "SCARD_POWERED";
+
+ case SCARD_NEGOTIABLE:
+ return "SCARD_NEGOTIABLE";
+
+ case SCARD_SPECIFIC:
+ return "SCARD_SPECIFIC";
+
+ default:
+ return "SCARD_UNKNOWN";
+ }
+}
+
+WINSCARDAPI char* WINAPI SCardGetReaderStateString(DWORD dwReaderState)
+{
+ const size_t size = 512;
+ char* buffer = calloc(size, sizeof(char));
+
+ if (!buffer)
+ return NULL;
+
+ if (dwReaderState & SCARD_STATE_IGNORE)
+ winpr_str_append("SCARD_STATE_IGNORE", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_CHANGED)
+ winpr_str_append("SCARD_STATE_CHANGED", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_UNKNOWN)
+ winpr_str_append("SCARD_STATE_UNKNOWN", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_UNAVAILABLE)
+ winpr_str_append("SCARD_STATE_UNAVAILABLE", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_EMPTY)
+ winpr_str_append("SCARD_STATE_EMPTY", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_PRESENT)
+ winpr_str_append("SCARD_STATE_PRESENT", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_ATRMATCH)
+ winpr_str_append("SCARD_STATE_ATRMATCH", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_EXCLUSIVE)
+ winpr_str_append("SCARD_STATE_EXCLUSIVE", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_INUSE)
+ winpr_str_append("SCARD_STATE_INUSE", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_MUTE)
+ winpr_str_append("SCARD_STATE_MUTE", buffer, size, "|");
+
+ if (dwReaderState & SCARD_STATE_UNPOWERED)
+ winpr_str_append("SCARD_STATE_UNPOWERED", buffer, size, "|");
+
+ if (!buffer[0])
+ winpr_str_append("SCARD_STATE_UNAWARE", buffer, size, "|");
+
+ return buffer;
+}
+
+#define WINSCARD_LOAD_PROC(_name, ...) \
+ do \
+ { \
+ WINPR_PRAGMA_DIAG_PUSH \
+ WINPR_PRAGMA_DIAG_IGNORED_PEDANTIC \
+ pWinSCardApiTable->pfn##_name = (fn##_name)GetProcAddress(hWinSCardLibrary, #_name); \
+ WINPR_PRAGMA_DIAG_POP \
+ } while (0)
+
+BOOL WinSCard_LoadApiTableFunctions(PSCardApiFunctionTable pWinSCardApiTable,
+ HMODULE hWinSCardLibrary)
+{
+ WINPR_ASSERT(pWinSCardApiTable);
+ WINPR_ASSERT(hWinSCardLibrary);
+
+ WINSCARD_LOAD_PROC(SCardEstablishContext);
+ WINSCARD_LOAD_PROC(SCardReleaseContext);
+ WINSCARD_LOAD_PROC(SCardIsValidContext);
+ WINSCARD_LOAD_PROC(SCardListReaderGroupsA);
+ WINSCARD_LOAD_PROC(SCardListReaderGroupsW);
+ WINSCARD_LOAD_PROC(SCardListReadersA);
+ WINSCARD_LOAD_PROC(SCardListReadersW);
+ WINSCARD_LOAD_PROC(SCardListCardsA);
+ WINSCARD_LOAD_PROC(SCardListCardsW);
+ WINSCARD_LOAD_PROC(SCardListInterfacesA);
+ WINSCARD_LOAD_PROC(SCardListInterfacesW);
+ WINSCARD_LOAD_PROC(SCardGetProviderIdA);
+ WINSCARD_LOAD_PROC(SCardGetProviderIdW);
+ WINSCARD_LOAD_PROC(SCardGetCardTypeProviderNameA);
+ WINSCARD_LOAD_PROC(SCardGetCardTypeProviderNameW);
+ WINSCARD_LOAD_PROC(SCardIntroduceReaderGroupA);
+ WINSCARD_LOAD_PROC(SCardIntroduceReaderGroupW);
+ WINSCARD_LOAD_PROC(SCardForgetReaderGroupA);
+ WINSCARD_LOAD_PROC(SCardForgetReaderGroupW);
+ WINSCARD_LOAD_PROC(SCardIntroduceReaderA);
+ WINSCARD_LOAD_PROC(SCardIntroduceReaderW);
+ WINSCARD_LOAD_PROC(SCardForgetReaderA);
+ WINSCARD_LOAD_PROC(SCardForgetReaderW);
+ WINSCARD_LOAD_PROC(SCardAddReaderToGroupA);
+ WINSCARD_LOAD_PROC(SCardAddReaderToGroupW);
+ WINSCARD_LOAD_PROC(SCardRemoveReaderFromGroupA);
+ WINSCARD_LOAD_PROC(SCardRemoveReaderFromGroupW);
+ WINSCARD_LOAD_PROC(SCardIntroduceCardTypeA);
+ WINSCARD_LOAD_PROC(SCardIntroduceCardTypeW);
+ WINSCARD_LOAD_PROC(SCardSetCardTypeProviderNameA);
+ WINSCARD_LOAD_PROC(SCardSetCardTypeProviderNameW);
+ WINSCARD_LOAD_PROC(SCardForgetCardTypeA);
+ WINSCARD_LOAD_PROC(SCardForgetCardTypeW);
+ WINSCARD_LOAD_PROC(SCardFreeMemory);
+ WINSCARD_LOAD_PROC(SCardAccessStartedEvent);
+ WINSCARD_LOAD_PROC(SCardReleaseStartedEvent);
+ WINSCARD_LOAD_PROC(SCardLocateCardsA);
+ WINSCARD_LOAD_PROC(SCardLocateCardsW);
+ WINSCARD_LOAD_PROC(SCardLocateCardsByATRA);
+ WINSCARD_LOAD_PROC(SCardLocateCardsByATRW);
+ WINSCARD_LOAD_PROC(SCardGetStatusChangeA);
+ WINSCARD_LOAD_PROC(SCardGetStatusChangeW);
+ WINSCARD_LOAD_PROC(SCardCancel);
+ WINSCARD_LOAD_PROC(SCardConnectA);
+ WINSCARD_LOAD_PROC(SCardConnectW);
+ WINSCARD_LOAD_PROC(SCardReconnect);
+ WINSCARD_LOAD_PROC(SCardDisconnect);
+ WINSCARD_LOAD_PROC(SCardBeginTransaction);
+ WINSCARD_LOAD_PROC(SCardEndTransaction);
+ WINSCARD_LOAD_PROC(SCardCancelTransaction);
+ WINSCARD_LOAD_PROC(SCardState);
+ WINSCARD_LOAD_PROC(SCardStatusA);
+ WINSCARD_LOAD_PROC(SCardStatusW);
+ WINSCARD_LOAD_PROC(SCardTransmit);
+ WINSCARD_LOAD_PROC(SCardGetTransmitCount);
+ WINSCARD_LOAD_PROC(SCardControl);
+ WINSCARD_LOAD_PROC(SCardGetAttrib);
+ WINSCARD_LOAD_PROC(SCardSetAttrib);
+ WINSCARD_LOAD_PROC(SCardUIDlgSelectCardA);
+ WINSCARD_LOAD_PROC(SCardUIDlgSelectCardW);
+ WINSCARD_LOAD_PROC(GetOpenCardNameA);
+ WINSCARD_LOAD_PROC(GetOpenCardNameW);
+ WINSCARD_LOAD_PROC(SCardDlgExtendedError);
+ WINSCARD_LOAD_PROC(SCardReadCacheA);
+ WINSCARD_LOAD_PROC(SCardReadCacheW);
+ WINSCARD_LOAD_PROC(SCardWriteCacheA);
+ WINSCARD_LOAD_PROC(SCardWriteCacheW);
+ WINSCARD_LOAD_PROC(SCardGetReaderIconA);
+ WINSCARD_LOAD_PROC(SCardGetReaderIconW);
+ WINSCARD_LOAD_PROC(SCardGetDeviceTypeIdA);
+ WINSCARD_LOAD_PROC(SCardGetDeviceTypeIdW);
+ WINSCARD_LOAD_PROC(SCardGetReaderDeviceInstanceIdA);
+ WINSCARD_LOAD_PROC(SCardGetReaderDeviceInstanceIdW);
+ WINSCARD_LOAD_PROC(SCardListReadersWithDeviceInstanceIdA);
+ WINSCARD_LOAD_PROC(SCardListReadersWithDeviceInstanceIdW);
+ WINSCARD_LOAD_PROC(SCardAudit);
+
+ return TRUE;
+}
+
+static const SCardApiFunctionTable WinPR_SCardApiFunctionTable = {
+ 0, /* dwVersion */
+ 0, /* dwFlags */
+
+ SCardEstablishContext, /* SCardEstablishContext */
+ SCardReleaseContext, /* SCardReleaseContext */
+ SCardIsValidContext, /* SCardIsValidContext */
+ SCardListReaderGroupsA, /* SCardListReaderGroupsA */
+ SCardListReaderGroupsW, /* SCardListReaderGroupsW */
+ SCardListReadersA, /* SCardListReadersA */
+ SCardListReadersW, /* SCardListReadersW */
+ SCardListCardsA, /* SCardListCardsA */
+ SCardListCardsW, /* SCardListCardsW */
+ SCardListInterfacesA, /* SCardListInterfacesA */
+ SCardListInterfacesW, /* SCardListInterfacesW */
+ SCardGetProviderIdA, /* SCardGetProviderIdA */
+ SCardGetProviderIdW, /* SCardGetProviderIdW */
+ SCardGetCardTypeProviderNameA, /* SCardGetCardTypeProviderNameA */
+ SCardGetCardTypeProviderNameW, /* SCardGetCardTypeProviderNameW */
+ SCardIntroduceReaderGroupA, /* SCardIntroduceReaderGroupA */
+ SCardIntroduceReaderGroupW, /* SCardIntroduceReaderGroupW */
+ SCardForgetReaderGroupA, /* SCardForgetReaderGroupA */
+ SCardForgetReaderGroupW, /* SCardForgetReaderGroupW */
+ SCardIntroduceReaderA, /* SCardIntroduceReaderA */
+ SCardIntroduceReaderW, /* SCardIntroduceReaderW */
+ SCardForgetReaderA, /* SCardForgetReaderA */
+ SCardForgetReaderW, /* SCardForgetReaderW */
+ SCardAddReaderToGroupA, /* SCardAddReaderToGroupA */
+ SCardAddReaderToGroupW, /* SCardAddReaderToGroupW */
+ SCardRemoveReaderFromGroupA, /* SCardRemoveReaderFromGroupA */
+ SCardRemoveReaderFromGroupW, /* SCardRemoveReaderFromGroupW */
+ SCardIntroduceCardTypeA, /* SCardIntroduceCardTypeA */
+ SCardIntroduceCardTypeW, /* SCardIntroduceCardTypeW */
+ SCardSetCardTypeProviderNameA, /* SCardSetCardTypeProviderNameA */
+ SCardSetCardTypeProviderNameW, /* SCardSetCardTypeProviderNameW */
+ SCardForgetCardTypeA, /* SCardForgetCardTypeA */
+ SCardForgetCardTypeW, /* SCardForgetCardTypeW */
+ SCardFreeMemory, /* SCardFreeMemory */
+ SCardAccessStartedEvent, /* SCardAccessStartedEvent */
+ SCardReleaseStartedEvent, /* SCardReleaseStartedEvent */
+ SCardLocateCardsA, /* SCardLocateCardsA */
+ SCardLocateCardsW, /* SCardLocateCardsW */
+ SCardLocateCardsByATRA, /* SCardLocateCardsByATRA */
+ SCardLocateCardsByATRW, /* SCardLocateCardsByATRW */
+ SCardGetStatusChangeA, /* SCardGetStatusChangeA */
+ SCardGetStatusChangeW, /* SCardGetStatusChangeW */
+ SCardCancel, /* SCardCancel */
+ SCardConnectA, /* SCardConnectA */
+ SCardConnectW, /* SCardConnectW */
+ SCardReconnect, /* SCardReconnect */
+ SCardDisconnect, /* SCardDisconnect */
+ SCardBeginTransaction, /* SCardBeginTransaction */
+ SCardEndTransaction, /* SCardEndTransaction */
+ SCardCancelTransaction, /* SCardCancelTransaction */
+ SCardState, /* SCardState */
+ SCardStatusA, /* SCardStatusA */
+ SCardStatusW, /* SCardStatusW */
+ SCardTransmit, /* SCardTransmit */
+ SCardGetTransmitCount, /* SCardGetTransmitCount */
+ SCardControl, /* SCardControl */
+ SCardGetAttrib, /* SCardGetAttrib */
+ SCardSetAttrib, /* SCardSetAttrib */
+ SCardUIDlgSelectCardA, /* SCardUIDlgSelectCardA */
+ SCardUIDlgSelectCardW, /* SCardUIDlgSelectCardW */
+ GetOpenCardNameA, /* GetOpenCardNameA */
+ GetOpenCardNameW, /* GetOpenCardNameW */
+ SCardDlgExtendedError, /* SCardDlgExtendedError */
+ SCardReadCacheA, /* SCardReadCacheA */
+ SCardReadCacheW, /* SCardReadCacheW */
+ SCardWriteCacheA, /* SCardWriteCacheA */
+ SCardWriteCacheW, /* SCardWriteCacheW */
+ SCardGetReaderIconA, /* SCardGetReaderIconA */
+ SCardGetReaderIconW, /* SCardGetReaderIconW */
+ SCardGetDeviceTypeIdA, /* SCardGetDeviceTypeIdA */
+ SCardGetDeviceTypeIdW, /* SCardGetDeviceTypeIdW */
+ SCardGetReaderDeviceInstanceIdA, /* SCardGetReaderDeviceInstanceIdA */
+ SCardGetReaderDeviceInstanceIdW, /* SCardGetReaderDeviceInstanceIdW */
+ SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
+ SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
+ SCardAudit /* SCardAudit */
+};
+
+const SCardApiFunctionTable* WinPR_GetSCardApiFunctionTable(void)
+{
+ return &WinPR_SCardApiFunctionTable;
+}
diff --git a/winpr/libwinpr/smartcard/smartcard.h b/winpr/libwinpr/smartcard/smartcard.h
new file mode 100644
index 0000000..e9279bc
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard.h
@@ -0,0 +1,31 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_SMARTCARD_PRIVATE_H
+#define WINPR_SMARTCARD_PRIVATE_H
+
+#include <winpr/smartcard.h>
+
+#ifndef _WIN32
+#include "smartcard_pcsc.h"
+#else
+#include "smartcard_windows.h"
+#endif
+
+#endif /* WINPR_SMARTCARD_PRIVATE_H */
diff --git a/winpr/libwinpr/smartcard/smartcard_inspect.c b/winpr/libwinpr/smartcard/smartcard_inspect.c
new file mode 100644
index 0000000..6b3ffff
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_inspect.c
@@ -0,0 +1,1363 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2020 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2020 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/wlog.h>
+#include <winpr/file.h>
+#include <winpr/path.h>
+#include <winpr/library.h>
+#include <winpr/smartcard.h>
+
+#include "smartcard_inspect.h"
+
+#include "../log.h"
+#define TAG WINPR_TAG("smartcard.inspect")
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define SCARDAPI_STUB_CALL_LONG(status, _name, ...) \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ status = SCARD_E_NO_SERVICE; \
+ } \
+ else \
+ status = g_SCardApi->pfn##_name(__VA_ARGS__)
+
+#define SCARDAPI_STUB_CALL_HANDLE(status, _name, ...) \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ status = NULL; \
+ } \
+ else \
+ status = g_SCardApi->pfn##_name(__VA_ARGS__)
+
+#define SCARDAPI_STUB_CALL_VOID(_name, ...) \
+ if (!g_SCardApi || !g_SCardApi->pfn##_name) \
+ { \
+ WLog_DBG(TAG, "Missing function pointer g_SCardApi=%p->" xstr(pfn##_name) "=%p", \
+ g_SCardApi, g_SCardApi ? g_SCardApi->pfn##_name : NULL); \
+ } \
+ else \
+ g_SCardApi->pfn##_name(__VA_ARGS__)
+
+static const DWORD g_LogLevel = WLOG_DEBUG;
+static wLog* g_Log = NULL;
+
+static const SCardApiFunctionTable* g_SCardApi = NULL;
+
+/**
+ * Standard Windows Smart Card API
+ */
+
+static LONG WINAPI Inspect_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardEstablishContext { dwScope: %s (0x%08" PRIX32 ")",
+ SCardGetScopeString(dwScope), dwScope);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardEstablishContext, dwScope, pvReserved1, pvReserved2,
+ phContext);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardEstablishContext } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardReleaseContext(SCARDCONTEXT hContext)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReleaseContext { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardReleaseContext, hContext);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReleaseContext } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIsValidContext(SCARDCONTEXT hContext)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIsValidContext { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIsValidContext, hContext);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIsValidContext } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReaderGroupsA(SCARDCONTEXT hContext, LPSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReaderGroupsA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReaderGroupsA, hContext, mszGroups, pcchGroups);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReaderGroupsA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReaderGroupsW(SCARDCONTEXT hContext, LPWSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReaderGroupsW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReaderGroupsW, hContext, mszGroups, pcchGroups);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReaderGroupsW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReadersA(SCARDCONTEXT hContext, LPCSTR mszGroups,
+ LPSTR mszReaders, LPDWORD pcchReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReadersA, hContext, mszGroups, mszReaders,
+ pcchReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReadersW(SCARDCONTEXT hContext, LPCWSTR mszGroups,
+ LPWSTR mszReaders, LPDWORD pcchReaders)
+{
+ LONG status = 0;
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReadersW, hContext, mszGroups, mszReaders,
+ pcchReaders);
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListCardsA(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ CHAR* mszCards, LPDWORD pcchCards)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListCardsA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListCardsA, hContext, pbAtr, rgquidInterfaces,
+ cguidInterfaceCount, mszCards, pcchCards);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListCardsA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListCardsW(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ WCHAR* mszCards, LPDWORD pcchCards)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListCardsW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListCardsW, hContext, pbAtr, rgquidInterfaces,
+ cguidInterfaceCount, mszCards, pcchCards);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListCardsW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListInterfacesA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListInterfacesA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListInterfacesA, hContext, szCard, pguidInterfaces,
+ pcguidInterfaces);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListInterfacesA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListInterfacesW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListInterfacesW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListInterfacesW, hContext, szCard, pguidInterfaces,
+ pcguidInterfaces);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListInterfacesW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetProviderIdA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidProviderId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetProviderIdA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetProviderIdA, hContext, szCard, pguidProviderId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetProviderIdA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetProviderIdW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidProviderId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetProviderIdW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetProviderIdW, hContext, szCard, pguidProviderId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetProviderIdW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, CHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetCardTypeProviderNameA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetCardTypeProviderNameA, hContext, szCardName,
+ dwProviderId, szProvider, pcchProvider);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, WCHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetCardTypeProviderNameW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetCardTypeProviderNameW, hContext, szCardName,
+ dwProviderId, szProvider, pcchProvider);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderGroupA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceReaderGroupA, hContext, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderGroupA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderGroupW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceReaderGroupW, hContext, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderGroupW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderGroupA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetReaderGroupA, hContext, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderGroupA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderGroupW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetReaderGroupW, hContext, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderGroupW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szDeviceName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceReaderA, hContext, szReaderName, szDeviceName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szDeviceName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceReaderW, hContext, szReaderName, szDeviceName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceReaderW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetReaderA, hContext, szReaderName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetReaderW, hContext, szReaderName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetReaderW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardAddReaderToGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAddReaderToGroupA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardAddReaderToGroupA, hContext, szReaderName, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAddReaderToGroupA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardAddReaderToGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAddReaderToGroupW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardAddReaderToGroupW, hContext, szReaderName, szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAddReaderToGroupW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardRemoveReaderFromGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardRemoveReaderFromGroupA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardRemoveReaderFromGroupA, hContext, szReaderName,
+ szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardRemoveReaderFromGroupA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardRemoveReaderFromGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardRemoveReaderFromGroupW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardRemoveReaderFromGroupW, hContext, szReaderName,
+ szGroupName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardRemoveReaderFromGroupW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceCardTypeA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceCardTypeA, hContext, szCardName,
+ pguidPrimaryProvider, rgguidInterfaces, dwInterfaceCount, pbAtr,
+ pbAtrMask, cbAtrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceCardTypeA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardIntroduceCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceCardTypeW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardIntroduceCardTypeW, hContext, szCardName,
+ pguidPrimaryProvider, rgguidInterfaces, dwInterfaceCount, pbAtr,
+ pbAtrMask, cbAtrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardIntroduceCardTypeW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardSetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, LPCSTR szProvider)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetCardTypeProviderNameA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardSetCardTypeProviderNameA, hContext, szCardName,
+ dwProviderId, szProvider);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardSetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, LPCWSTR szProvider)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetCardTypeProviderNameA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardSetCardTypeProviderNameW, hContext, szCardName,
+ dwProviderId, szProvider);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetCardTypeA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetCardTypeA, hContext, szCardName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetCardTypeA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardForgetCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetCardTypeW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardForgetCardTypeW, hContext, szCardName);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardForgetCardTypeW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardFreeMemory { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardFreeMemory, hContext, pvMem);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardFreeMemory } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static HANDLE WINAPI Inspect_SCardAccessStartedEvent(void)
+{
+ HANDLE hEvent = NULL;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAccessStartedEvent {");
+
+ SCARDAPI_STUB_CALL_HANDLE(hEvent, SCardAccessStartedEvent);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAccessStartedEvent } hEvent: %p", hEvent);
+
+ return hEvent;
+}
+
+static void WINAPI Inspect_SCardReleaseStartedEvent(void)
+{
+ WLog_Print(g_Log, g_LogLevel, "SCardReleaseStartedEvent {");
+
+ SCARDAPI_STUB_CALL_VOID(SCardReleaseStartedEvent);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReleaseStartedEvent }");
+}
+
+static LONG WINAPI Inspect_SCardLocateCardsA(SCARDCONTEXT hContext, LPCSTR mszCards,
+ LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardLocateCardsA, hContext, mszCards, rgReaderStates,
+ cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardLocateCardsW(SCARDCONTEXT hContext, LPCWSTR mszCards,
+ LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardLocateCardsW, hContext, mszCards, rgReaderStates,
+ cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardLocateCardsByATRA(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEA rgReaderStates,
+ DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsByATRA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardLocateCardsByATRA, hContext, rgAtrMasks, cAtrs,
+ rgReaderStates, cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsByATRA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardLocateCardsByATRW(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEW rgReaderStates,
+ DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsByATRW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardLocateCardsByATRW, hContext, rgAtrMasks, cAtrs,
+ rgReaderStates, cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardLocateCardsByATRW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetStatusChangeA(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEA rgReaderStates,
+ DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetStatusChangeA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetStatusChangeA, hContext, dwTimeout, rgReaderStates,
+ cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetStatusChangeA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetStatusChangeW(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEW rgReaderStates,
+ DWORD cReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetStatusChangeW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetStatusChangeW, hContext, dwTimeout, rgReaderStates,
+ cReaders);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetStatusChangeW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardCancel(SCARDCONTEXT hContext)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardCancel { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardCancel, hContext);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardCancel } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardConnectA(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardConnectA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardConnectA, hContext, szReader, dwShareMode,
+ dwPreferredProtocols, phCard, pdwActiveProtocol);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardConnectA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardConnectW(SCARDCONTEXT hContext, LPCWSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardConnectW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardConnectW, hContext, szReader, dwShareMode,
+ dwPreferredProtocols, phCard, pdwActiveProtocol);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardConnectW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, DWORD dwInitialization,
+ LPDWORD pdwActiveProtocol)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReconnect { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardReconnect, hCard, dwShareMode, dwPreferredProtocols,
+ dwInitialization, pdwActiveProtocol);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReconnect } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardDisconnect { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardDisconnect, hCard, dwDisposition);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardDisconnect } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardBeginTransaction(SCARDHANDLE hCard)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardBeginTransaction { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardBeginTransaction, hCard);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardBeginTransaction } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardEndTransaction { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardEndTransaction, hCard, dwDisposition);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardEndTransaction } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardCancelTransaction(SCARDHANDLE hCard)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardCancelTransaction { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardCancelTransaction, hCard);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardCancelTransaction } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardState(SCARDHANDLE hCard, LPDWORD pdwState, LPDWORD pdwProtocol,
+ LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardState { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardState, hCard, pdwState, pdwProtocol, pbAtr, pcbAtrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardState } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardStatusA(SCARDHANDLE hCard, LPSTR mszReaderNames,
+ LPDWORD pcchReaderLen, LPDWORD pdwState,
+ LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardStatusA { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardStatusA, hCard, mszReaderNames, pcchReaderLen, pdwState,
+ pdwProtocol, pbAtr, pcbAtrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardStatusA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardStatusW(SCARDHANDLE hCard, LPWSTR mszReaderNames,
+ LPDWORD pcchReaderLen, LPDWORD pdwState,
+ LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardStatusW { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardStatusW, hCard, mszReaderNames, pcchReaderLen, pdwState,
+ pdwProtocol, pbAtr, pcbAtrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardStatusW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
+ LPCBYTE pbSendBuffer, DWORD cbSendLength,
+ LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
+ LPDWORD pcbRecvLength)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardTransmit { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardTransmit, hCard, pioSendPci, pbSendBuffer, cbSendLength,
+ pioRecvPci, pbRecvBuffer, pcbRecvLength);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardTransmit } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetTransmitCount(SCARDHANDLE hCard, LPDWORD pcTransmitCount)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetTransmitCount { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetTransmitCount, hCard, pcTransmitCount);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetTransmitCount } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID lpInBuffer,
+ DWORD cbInBufferSize, LPVOID lpOutBuffer,
+ DWORD cbOutBufferSize, LPDWORD lpBytesReturned)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardControl { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardControl, hCard, dwControlCode, lpInBuffer, cbInBufferSize,
+ lpOutBuffer, cbOutBufferSize, lpBytesReturned);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardControl } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
+ LPDWORD pcbAttrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetAttrib { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetAttrib, hCard, dwAttrId, pbAttr, pcbAttrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetAttrib } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
+ DWORD cbAttrLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetAttrib { hCard: %p", (void*)hCard);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardSetAttrib, hCard, dwAttrId, pbAttr, cbAttrLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardSetAttrib } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardUIDlgSelectCardA {");
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardUIDlgSelectCardA, pDlgStruc);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardUIDlgSelectCardA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardUIDlgSelectCardW {");
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardUIDlgSelectCardW, pDlgStruc);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardUIDlgSelectCardW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "GetOpenCardNameA {");
+
+ SCARDAPI_STUB_CALL_LONG(status, GetOpenCardNameA, pDlgStruc);
+
+ WLog_Print(g_Log, g_LogLevel, "GetOpenCardNameA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "GetOpenCardNameW {");
+
+ SCARDAPI_STUB_CALL_LONG(status, GetOpenCardNameW, pDlgStruc);
+
+ WLog_Print(g_Log, g_LogLevel, "GetOpenCardNameW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardDlgExtendedError(void)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardDlgExtendedError {");
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardDlgExtendedError);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardDlgExtendedError } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardReadCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReadCacheA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardReadCacheA, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReadCacheA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardReadCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReadCacheW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardReadCacheW, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardReadCacheW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardWriteCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardWriteCacheA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardWriteCacheA, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardWriteCacheA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardWriteCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardWriteCacheW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardWriteCacheW, hContext, CardIdentifier, FreshnessCounter,
+ LookupName, Data, DataLen);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardWriteCacheW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetReaderIconA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderIconA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetReaderIconA, hContext, szReaderName, pbIcon, pcbIcon);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderIconA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetReaderIconW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderIconW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetReaderIconW, hContext, szReaderName, pbIcon, pcbIcon);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderIconW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetDeviceTypeIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetDeviceTypeIdA { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetDeviceTypeIdA, hContext, szReaderName, pdwDeviceTypeId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetDeviceTypeIdA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetDeviceTypeIdW { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetDeviceTypeIdW, hContext, szReaderName, pdwDeviceTypeId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetDeviceTypeIdW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetReaderDeviceInstanceIdA(SCARDCONTEXT hContext,
+ LPCSTR szReaderName,
+ LPSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderDeviceInstanceIdA { hContext: %p",
+ (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetReaderDeviceInstanceIdA, hContext, szReaderName,
+ szDeviceInstanceId, pcchDeviceInstanceId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardGetReaderDeviceInstanceIdW(SCARDCONTEXT hContext,
+ LPCWSTR szReaderName,
+ LPWSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderDeviceInstanceIdW { hContext: %p",
+ (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardGetReaderDeviceInstanceIdW, hContext, szReaderName,
+ szDeviceInstanceId, pcchDeviceInstanceId);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardGetReaderDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReadersWithDeviceInstanceIdA(SCARDCONTEXT hContext,
+ LPCSTR szDeviceInstanceId,
+ LPSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersWithDeviceInstanceIdA { hContext: %p",
+ (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReadersWithDeviceInstanceIdA, hContext,
+ szDeviceInstanceId, mszReaders, pcchReaders);
+
+ WLog_Print(g_Log, g_LogLevel,
+ "SCardListReadersWithDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardListReadersWithDeviceInstanceIdW(SCARDCONTEXT hContext,
+ LPCWSTR szDeviceInstanceId,
+ LPWSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardListReadersWithDeviceInstanceIdW { hContext: %p",
+ (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardListReadersWithDeviceInstanceIdW, hContext,
+ szDeviceInstanceId, mszReaders, pcchReaders);
+
+ WLog_Print(g_Log, g_LogLevel,
+ "SCardListReadersWithDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+static LONG WINAPI Inspect_SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
+{
+ LONG status = 0;
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAudit { hContext: %p", (void*)hContext);
+
+ SCARDAPI_STUB_CALL_LONG(status, SCardAudit, hContext, dwEvent);
+
+ WLog_Print(g_Log, g_LogLevel, "SCardAudit } status: %s (0x%08" PRIX32 ")",
+ SCardGetErrorString(status), status);
+
+ return status;
+}
+
+/**
+ * Extended API
+ */
+
+static const SCardApiFunctionTable Inspect_SCardApiFunctionTable = {
+ 0, /* dwVersion */
+ 0, /* dwFlags */
+
+ Inspect_SCardEstablishContext, /* SCardEstablishContext */
+ Inspect_SCardReleaseContext, /* SCardReleaseContext */
+ Inspect_SCardIsValidContext, /* SCardIsValidContext */
+ Inspect_SCardListReaderGroupsA, /* SCardListReaderGroupsA */
+ Inspect_SCardListReaderGroupsW, /* SCardListReaderGroupsW */
+ Inspect_SCardListReadersA, /* SCardListReadersA */
+ Inspect_SCardListReadersW, /* SCardListReadersW */
+ Inspect_SCardListCardsA, /* SCardListCardsA */
+ Inspect_SCardListCardsW, /* SCardListCardsW */
+ Inspect_SCardListInterfacesA, /* SCardListInterfacesA */
+ Inspect_SCardListInterfacesW, /* SCardListInterfacesW */
+ Inspect_SCardGetProviderIdA, /* SCardGetProviderIdA */
+ Inspect_SCardGetProviderIdW, /* SCardGetProviderIdW */
+ Inspect_SCardGetCardTypeProviderNameA, /* SCardGetCardTypeProviderNameA */
+ Inspect_SCardGetCardTypeProviderNameW, /* SCardGetCardTypeProviderNameW */
+ Inspect_SCardIntroduceReaderGroupA, /* SCardIntroduceReaderGroupA */
+ Inspect_SCardIntroduceReaderGroupW, /* SCardIntroduceReaderGroupW */
+ Inspect_SCardForgetReaderGroupA, /* SCardForgetReaderGroupA */
+ Inspect_SCardForgetReaderGroupW, /* SCardForgetReaderGroupW */
+ Inspect_SCardIntroduceReaderA, /* SCardIntroduceReaderA */
+ Inspect_SCardIntroduceReaderW, /* SCardIntroduceReaderW */
+ Inspect_SCardForgetReaderA, /* SCardForgetReaderA */
+ Inspect_SCardForgetReaderW, /* SCardForgetReaderW */
+ Inspect_SCardAddReaderToGroupA, /* SCardAddReaderToGroupA */
+ Inspect_SCardAddReaderToGroupW, /* SCardAddReaderToGroupW */
+ Inspect_SCardRemoveReaderFromGroupA, /* SCardRemoveReaderFromGroupA */
+ Inspect_SCardRemoveReaderFromGroupW, /* SCardRemoveReaderFromGroupW */
+ Inspect_SCardIntroduceCardTypeA, /* SCardIntroduceCardTypeA */
+ Inspect_SCardIntroduceCardTypeW, /* SCardIntroduceCardTypeW */
+ Inspect_SCardSetCardTypeProviderNameA, /* SCardSetCardTypeProviderNameA */
+ Inspect_SCardSetCardTypeProviderNameW, /* SCardSetCardTypeProviderNameW */
+ Inspect_SCardForgetCardTypeA, /* SCardForgetCardTypeA */
+ Inspect_SCardForgetCardTypeW, /* SCardForgetCardTypeW */
+ Inspect_SCardFreeMemory, /* SCardFreeMemory */
+ Inspect_SCardAccessStartedEvent, /* SCardAccessStartedEvent */
+ Inspect_SCardReleaseStartedEvent, /* SCardReleaseStartedEvent */
+ Inspect_SCardLocateCardsA, /* SCardLocateCardsA */
+ Inspect_SCardLocateCardsW, /* SCardLocateCardsW */
+ Inspect_SCardLocateCardsByATRA, /* SCardLocateCardsByATRA */
+ Inspect_SCardLocateCardsByATRW, /* SCardLocateCardsByATRW */
+ Inspect_SCardGetStatusChangeA, /* SCardGetStatusChangeA */
+ Inspect_SCardGetStatusChangeW, /* SCardGetStatusChangeW */
+ Inspect_SCardCancel, /* SCardCancel */
+ Inspect_SCardConnectA, /* SCardConnectA */
+ Inspect_SCardConnectW, /* SCardConnectW */
+ Inspect_SCardReconnect, /* SCardReconnect */
+ Inspect_SCardDisconnect, /* SCardDisconnect */
+ Inspect_SCardBeginTransaction, /* SCardBeginTransaction */
+ Inspect_SCardEndTransaction, /* SCardEndTransaction */
+ Inspect_SCardCancelTransaction, /* SCardCancelTransaction */
+ Inspect_SCardState, /* SCardState */
+ Inspect_SCardStatusA, /* SCardStatusA */
+ Inspect_SCardStatusW, /* SCardStatusW */
+ Inspect_SCardTransmit, /* SCardTransmit */
+ Inspect_SCardGetTransmitCount, /* SCardGetTransmitCount */
+ Inspect_SCardControl, /* SCardControl */
+ Inspect_SCardGetAttrib, /* SCardGetAttrib */
+ Inspect_SCardSetAttrib, /* SCardSetAttrib */
+ Inspect_SCardUIDlgSelectCardA, /* SCardUIDlgSelectCardA */
+ Inspect_SCardUIDlgSelectCardW, /* SCardUIDlgSelectCardW */
+ Inspect_GetOpenCardNameA, /* GetOpenCardNameA */
+ Inspect_GetOpenCardNameW, /* GetOpenCardNameW */
+ Inspect_SCardDlgExtendedError, /* SCardDlgExtendedError */
+ Inspect_SCardReadCacheA, /* SCardReadCacheA */
+ Inspect_SCardReadCacheW, /* SCardReadCacheW */
+ Inspect_SCardWriteCacheA, /* SCardWriteCacheA */
+ Inspect_SCardWriteCacheW, /* SCardWriteCacheW */
+ Inspect_SCardGetReaderIconA, /* SCardGetReaderIconA */
+ Inspect_SCardGetReaderIconW, /* SCardGetReaderIconW */
+ Inspect_SCardGetDeviceTypeIdA, /* SCardGetDeviceTypeIdA */
+ Inspect_SCardGetDeviceTypeIdW, /* SCardGetDeviceTypeIdW */
+ Inspect_SCardGetReaderDeviceInstanceIdA, /* SCardGetReaderDeviceInstanceIdA */
+ Inspect_SCardGetReaderDeviceInstanceIdW, /* SCardGetReaderDeviceInstanceIdW */
+ Inspect_SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
+ Inspect_SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
+ Inspect_SCardAudit /* SCardAudit */
+};
+
+static void Inspect_InitLog(void)
+{
+ if (g_Log)
+ return;
+
+ if (!(g_Log = WLog_Get("WinSCard")))
+ return;
+}
+
+const SCardApiFunctionTable* Inspect_RegisterSCardApi(const SCardApiFunctionTable* pSCardApi)
+{
+ g_SCardApi = pSCardApi;
+
+ Inspect_InitLog();
+
+ return &Inspect_SCardApiFunctionTable;
+}
diff --git a/winpr/libwinpr/smartcard/smartcard_inspect.h b/winpr/libwinpr/smartcard/smartcard_inspect.h
new file mode 100644
index 0000000..482dd97
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_inspect.h
@@ -0,0 +1,30 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2020 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2020 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_SMARTCARD_INSPECT_PRIVATE_H
+#define WINPR_SMARTCARD_INSPECT_PRIVATE_H
+
+#include <winpr/platform.h>
+#include <winpr/smartcard.h>
+
+const SCardApiFunctionTable* Inspect_RegisterSCardApi(const SCardApiFunctionTable* pSCardApi);
+
+#endif /* WINPR_SMARTCARD_INSPECT_PRIVATE_H */
diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c
new file mode 100644
index 0000000..fb04d56
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c
@@ -0,0 +1,3357 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2020 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2020 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#ifndef _WIN32
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/synch.h>
+#include <winpr/library.h>
+#include <winpr/smartcard.h>
+#include <winpr/collections.h>
+#include <winpr/environment.h>
+
+#include "smartcard_pcsc.h"
+
+#include "../log.h"
+#define TAG WINPR_TAG("smartcard")
+
+#define WINSCARD_LOAD_PROC_EX(module, pcsc, _fname, _name, ...) \
+ do \
+ { \
+ WINPR_PRAGMA_DIAG_PUSH \
+ WINPR_PRAGMA_DIAG_IGNORED_PEDANTIC \
+ pcsc.pfn##_fname = (fnPCSC##_fname)GetProcAddress(module, #_name); \
+ WINPR_PRAGMA_DIAG_POP \
+ } while (0)
+
+#define WINSCARD_LOAD_PROC(module, pcsc, _name, ...) \
+ WINSCARD_LOAD_PROC_EX(module, pcsc, _name, _name, ##__VA_ARGS__)
+
+/**
+ * PC/SC transactions:
+ * http://developersblog.wwpass.com/?p=180
+ */
+
+/**
+ * Smart Card Logon on Windows Vista:
+ * http://blogs.msdn.com/b/shivaram/archive/2007/02/26/smart-card-logon-on-windows-vista.aspx
+ */
+
+/**
+ * The Smart Card Cryptographic Service Provider Cookbook:
+ * http://msdn.microsoft.com/en-us/library/ms953432.aspx
+ *
+ * SCARDCONTEXT
+ *
+ * The context is a communication channel with the smart card resource manager and
+ * all calls to the resource manager must go through this link.
+ *
+ * All functions that take a context as a parameter or a card handle as parameter,
+ * which is indirectly associated with a particular context, may be blocking calls.
+ * Examples of these are SCardGetStatusChange and SCardBeginTransaction, which takes
+ * a card handle as a parameter. If such a function blocks then all operations wanting
+ * to use the context are blocked as well. So, it is recommended that a CSP using
+ * monitoring establishes at least two contexts with the resource manager; one for
+ * monitoring (with SCardGetStatusChange) and one for other operations.
+ *
+ * If multiple cards are present, it is recommended that a separate context or pair
+ * of contexts be established for each card to prevent operations on one card from
+ * blocking operations on another.
+ *
+ * Example one
+ *
+ * The example below shows what can happen if a CSP using SCardGetStatusChange for
+ * monitoring does not establish two contexts with the resource manager.
+ * The context becomes unusable until SCardGetStatusChange unblocks.
+ *
+ * In this example, there is one process running called P1.
+ * P1 calls SCardEstablishContext, which returns the context hCtx.
+ * P1 calls SCardConnect (with the hCtx context) which returns a handle to the card, hCard.
+ * P1 calls SCardGetStatusChange (with the hCtx context) which blocks because
+ * there are no status changes to report.
+ * Until the thread running SCardGetStatusChange unblocks, another thread in P1 trying to
+ * perform an operation using the context hCtx (or the card hCard) will also be blocked.
+ *
+ * Example two
+ *
+ * The example below shows how transaction control ensures that operations meant to be
+ * performed without interruption can do so safely within a transaction.
+ *
+ * In this example, there are two different processes running; P1 and P2.
+ * P1 calls SCardEstablishContext, which returns the context hCtx1.
+ * P2 calls SCardEstablishContext, which returns the context hCtx2.
+ * P1 calls SCardConnect (with the hCtx1 context) which returns a handle to the card, hCard1.
+ * P2 calls SCardConnect (with the hCtx2 context) which returns a handle to the same card, hCard2.
+ * P1 calls SCardBeginTransaction (with the hCard 1 context).
+ * Until P1 calls SCardEndTransaction (with the hCard1 context),
+ * any operation using hCard2 will be blocked.
+ * Once an operation using hCard2 is blocked and until it's returning,
+ * any operation using hCtx2 (and hCard2) will also be blocked.
+ */
+
+//#define DISABLE_PCSC_SCARD_AUTOALLOCATE
+#include "smartcard_pcsc.h"
+
+#define PCSC_SCARD_PCI_T0 (&g_PCSC_rgSCardT0Pci)
+#define PCSC_SCARD_PCI_T1 (&g_PCSC_rgSCardT1Pci)
+#define PCSC_SCARD_PCI_RAW (&g_PCSC_rgSCardRawPci)
+
+typedef PCSC_LONG (*fnPCSCSCardEstablishContext)(PCSC_DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
+typedef PCSC_LONG (*fnPCSCSCardReleaseContext)(SCARDCONTEXT hContext);
+typedef PCSC_LONG (*fnPCSCSCardIsValidContext)(SCARDCONTEXT hContext);
+typedef PCSC_LONG (*fnPCSCSCardConnect)(SCARDCONTEXT hContext, LPCSTR szReader,
+ PCSC_DWORD dwShareMode, PCSC_DWORD dwPreferredProtocols,
+ LPSCARDHANDLE phCard, PCSC_LPDWORD pdwActiveProtocol);
+typedef PCSC_LONG (*fnPCSCSCardReconnect)(SCARDHANDLE hCard, PCSC_DWORD dwShareMode,
+ PCSC_DWORD dwPreferredProtocols,
+ PCSC_DWORD dwInitialization,
+ PCSC_LPDWORD pdwActiveProtocol);
+typedef PCSC_LONG (*fnPCSCSCardDisconnect)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
+typedef PCSC_LONG (*fnPCSCSCardBeginTransaction)(SCARDHANDLE hCard);
+typedef PCSC_LONG (*fnPCSCSCardEndTransaction)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
+typedef PCSC_LONG (*fnPCSCSCardStatus)(SCARDHANDLE hCard, LPSTR mszReaderName,
+ PCSC_LPDWORD pcchReaderLen, PCSC_LPDWORD pdwState,
+ PCSC_LPDWORD pdwProtocol, LPBYTE pbAtr,
+ PCSC_LPDWORD pcbAtrLen);
+typedef PCSC_LONG (*fnPCSCSCardGetStatusChange)(SCARDCONTEXT hContext, PCSC_DWORD dwTimeout,
+ PCSC_SCARD_READERSTATE* rgReaderStates,
+ PCSC_DWORD cReaders);
+typedef PCSC_LONG (*fnPCSCSCardControl)(SCARDHANDLE hCard, PCSC_DWORD dwControlCode,
+ LPCVOID pbSendBuffer, PCSC_DWORD cbSendLength,
+ LPVOID pbRecvBuffer, PCSC_DWORD cbRecvLength,
+ PCSC_LPDWORD lpBytesReturned);
+typedef PCSC_LONG (*fnPCSCSCardTransmit)(SCARDHANDLE hCard, const PCSC_SCARD_IO_REQUEST* pioSendPci,
+ LPCBYTE pbSendBuffer, PCSC_DWORD cbSendLength,
+ PCSC_SCARD_IO_REQUEST* pioRecvPci, LPBYTE pbRecvBuffer,
+ PCSC_LPDWORD pcbRecvLength);
+typedef PCSC_LONG (*fnPCSCSCardListReaderGroups)(SCARDCONTEXT hContext, LPSTR mszGroups,
+ PCSC_LPDWORD pcchGroups);
+typedef PCSC_LONG (*fnPCSCSCardListReaders)(SCARDCONTEXT hContext, LPCSTR mszGroups,
+ LPSTR mszReaders, PCSC_LPDWORD pcchReaders);
+typedef PCSC_LONG (*fnPCSCSCardFreeMemory)(SCARDCONTEXT hContext, LPCVOID pvMem);
+typedef PCSC_LONG (*fnPCSCSCardCancel)(SCARDCONTEXT hContext);
+typedef PCSC_LONG (*fnPCSCSCardGetAttrib)(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPBYTE pbAttr,
+ PCSC_LPDWORD pcbAttrLen);
+typedef PCSC_LONG (*fnPCSCSCardSetAttrib)(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPCBYTE pbAttr,
+ PCSC_DWORD cbAttrLen);
+
+typedef struct
+{
+ fnPCSCSCardEstablishContext pfnSCardEstablishContext;
+ fnPCSCSCardReleaseContext pfnSCardReleaseContext;
+ fnPCSCSCardIsValidContext pfnSCardIsValidContext;
+ fnPCSCSCardConnect pfnSCardConnect;
+ fnPCSCSCardReconnect pfnSCardReconnect;
+ fnPCSCSCardDisconnect pfnSCardDisconnect;
+ fnPCSCSCardBeginTransaction pfnSCardBeginTransaction;
+ fnPCSCSCardEndTransaction pfnSCardEndTransaction;
+ fnPCSCSCardStatus pfnSCardStatus;
+ fnPCSCSCardGetStatusChange pfnSCardGetStatusChange;
+ fnPCSCSCardControl pfnSCardControl;
+ fnPCSCSCardTransmit pfnSCardTransmit;
+ fnPCSCSCardListReaderGroups pfnSCardListReaderGroups;
+ fnPCSCSCardListReaders pfnSCardListReaders;
+ fnPCSCSCardFreeMemory pfnSCardFreeMemory;
+ fnPCSCSCardCancel pfnSCardCancel;
+ fnPCSCSCardGetAttrib pfnSCardGetAttrib;
+ fnPCSCSCardSetAttrib pfnSCardSetAttrib;
+} PCSCFunctionTable;
+
+typedef struct
+{
+ DWORD len;
+ DWORD freshness;
+ BYTE* data;
+} PCSC_CACHE_ITEM;
+
+typedef struct
+{
+ SCARDHANDLE owner;
+ CRITICAL_SECTION lock;
+ SCARDCONTEXT hContext;
+ DWORD dwCardHandleCount;
+ BOOL isTransactionLocked;
+ wHashTable* cache;
+} PCSC_SCARDCONTEXT;
+
+typedef struct
+{
+ BOOL shared;
+ SCARDCONTEXT hSharedContext;
+} PCSC_SCARDHANDLE;
+
+static HMODULE g_PCSCModule = NULL;
+static PCSCFunctionTable g_PCSC = { 0 };
+
+static HANDLE g_StartedEvent = NULL;
+static int g_StartedEventRefCount = 0;
+
+static BOOL g_SCardAutoAllocate = FALSE;
+static BOOL g_PnP_Notification = TRUE;
+
+#ifdef __MACOSX__
+static unsigned int OSXVersion = 0;
+#endif
+
+static wListDictionary* g_CardHandles = NULL;
+static wListDictionary* g_CardContexts = NULL;
+static wListDictionary* g_MemoryBlocks = NULL;
+
+static const char SMARTCARD_PNP_NOTIFICATION_A[] = "\\\\?PnP?\\Notification";
+
+static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT0Pci = { SCARD_PROTOCOL_T0,
+ sizeof(PCSC_SCARD_IO_REQUEST) };
+static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT1Pci = { SCARD_PROTOCOL_T1,
+ sizeof(PCSC_SCARD_IO_REQUEST) };
+static const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardRawPci = { PCSC_SCARD_PROTOCOL_RAW,
+ sizeof(PCSC_SCARD_IO_REQUEST) };
+
+static LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPVOID pvMem);
+static LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2,
+ LPSCARDCONTEXT phContext);
+static LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext);
+
+static LONG PCSC_SCard_LogError(const char* what)
+{
+ WLog_WARN(TAG, "Missing function pointer %s=NULL", what);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG PCSC_MapErrorCodeToWinSCard(PCSC_LONG errorCode)
+{
+ /**
+ * pcsc-lite returns SCARD_E_UNEXPECTED when it
+ * should return SCARD_E_UNSUPPORTED_FEATURE.
+ *
+ * Additionally, the pcsc-lite headers incorrectly
+ * define SCARD_E_UNSUPPORTED_FEATURE to 0x8010001F,
+ * when the real value should be 0x80100022.
+ */
+ if (errorCode != SCARD_S_SUCCESS)
+ {
+ if (errorCode == SCARD_E_UNEXPECTED)
+ errorCode = SCARD_E_UNSUPPORTED_FEATURE;
+ }
+
+ return (LONG)errorCode;
+}
+
+static DWORD PCSC_ConvertCardStateToWinSCard(DWORD dwCardState, PCSC_LONG status)
+{
+ /**
+ * pcsc-lite's SCardStatus returns a bit-field, not an enumerated value.
+ *
+ * State WinSCard pcsc-lite
+ *
+ * SCARD_UNKNOWN 0 0x0001
+ * SCARD_ABSENT 1 0x0002
+ * SCARD_PRESENT 2 0x0004
+ * SCARD_SWALLOWED 3 0x0008
+ * SCARD_POWERED 4 0x0010
+ * SCARD_NEGOTIABLE 5 0x0020
+ * SCARD_SPECIFIC 6 0x0040
+ *
+ * pcsc-lite also never sets SCARD_SPECIFIC,
+ * which is expected by some windows applications.
+ */
+ if (status == SCARD_S_SUCCESS)
+ {
+ if ((dwCardState & PCSC_SCARD_NEGOTIABLE) || (dwCardState & PCSC_SCARD_SPECIFIC))
+ return SCARD_SPECIFIC;
+ }
+
+ if (dwCardState & PCSC_SCARD_POWERED)
+ return SCARD_POWERED;
+
+ if (dwCardState & PCSC_SCARD_NEGOTIABLE)
+ return SCARD_NEGOTIABLE;
+
+ if (dwCardState & PCSC_SCARD_SPECIFIC)
+ return SCARD_SPECIFIC;
+
+ if (dwCardState & PCSC_SCARD_ABSENT)
+ return SCARD_ABSENT;
+
+ if (dwCardState & PCSC_SCARD_PRESENT)
+ return SCARD_PRESENT;
+
+ if (dwCardState & PCSC_SCARD_SWALLOWED)
+ return SCARD_SWALLOWED;
+
+ if (dwCardState & PCSC_SCARD_UNKNOWN)
+ return SCARD_UNKNOWN;
+
+ return SCARD_UNKNOWN;
+}
+
+static DWORD PCSC_ConvertProtocolsToWinSCard(PCSC_DWORD dwProtocols)
+{
+ /**
+ * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW,
+ * and also has SCARD_PROTOCOL_T15 which is not in WinSCard.
+ */
+ if (dwProtocols & PCSC_SCARD_PROTOCOL_RAW)
+ {
+ dwProtocols &= ~PCSC_SCARD_PROTOCOL_RAW;
+ dwProtocols |= SCARD_PROTOCOL_RAW;
+ }
+
+ if (dwProtocols & PCSC_SCARD_PROTOCOL_T15)
+ {
+ dwProtocols &= ~PCSC_SCARD_PROTOCOL_T15;
+ }
+
+ return (DWORD)dwProtocols;
+}
+
+static DWORD PCSC_ConvertProtocolsFromWinSCard(DWORD dwProtocols)
+{
+ /**
+ * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW,
+ * and it does not define WinSCard's SCARD_PROTOCOL_DEFAULT.
+ */
+ if (dwProtocols & SCARD_PROTOCOL_RAW)
+ {
+ dwProtocols &= ~SCARD_PROTOCOL_RAW;
+ dwProtocols |= PCSC_SCARD_PROTOCOL_RAW;
+ }
+
+ if (dwProtocols & SCARD_PROTOCOL_DEFAULT)
+ {
+ dwProtocols &= ~SCARD_PROTOCOL_DEFAULT;
+ }
+
+ if (dwProtocols == SCARD_PROTOCOL_UNDEFINED)
+ {
+ dwProtocols = SCARD_PROTOCOL_Tx;
+ }
+
+ return dwProtocols;
+}
+
+static PCSC_SCARDCONTEXT* PCSC_GetCardContextData(SCARDCONTEXT hContext)
+{
+ PCSC_SCARDCONTEXT* pContext = NULL;
+
+ if (!g_CardContexts)
+ return NULL;
+
+ pContext = (PCSC_SCARDCONTEXT*)ListDictionary_GetItemValue(g_CardContexts, (void*)hContext);
+
+ if (!pContext)
+ return NULL;
+
+ return pContext;
+}
+
+static void pcsc_cache_item_free(void* ptr)
+{
+ PCSC_CACHE_ITEM* data = ptr;
+ if (data)
+ free(data->data);
+ free(data);
+}
+
+static PCSC_SCARDCONTEXT* PCSC_EstablishCardContext(SCARDCONTEXT hContext)
+{
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pContext = (PCSC_SCARDCONTEXT*)calloc(1, sizeof(PCSC_SCARDCONTEXT));
+
+ if (!pContext)
+ return NULL;
+
+ pContext->hContext = hContext;
+
+ if (!InitializeCriticalSectionAndSpinCount(&(pContext->lock), 4000))
+ goto error_spinlock;
+
+ pContext->cache = HashTable_New(FALSE);
+ if (!pContext->cache)
+ goto errors;
+ if (!HashTable_SetupForStringData(pContext->cache, FALSE))
+ goto errors;
+ {
+ wObject* obj = HashTable_ValueObject(pContext->cache);
+ obj->fnObjectFree = pcsc_cache_item_free;
+ }
+
+ if (!g_CardContexts)
+ {
+ g_CardContexts = ListDictionary_New(TRUE);
+
+ if (!g_CardContexts)
+ goto errors;
+ }
+
+ if (!ListDictionary_Add(g_CardContexts, (void*)hContext, (void*)pContext))
+ goto errors;
+
+ return pContext;
+errors:
+ HashTable_Free(pContext->cache);
+ DeleteCriticalSection(&(pContext->lock));
+error_spinlock:
+ free(pContext);
+ return NULL;
+}
+
+static void PCSC_ReleaseCardContext(SCARDCONTEXT hContext)
+{
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ {
+ WLog_ERR(TAG, "PCSC_ReleaseCardContext: null pContext!");
+ return;
+ }
+
+ DeleteCriticalSection(&(pContext->lock));
+ HashTable_Free(pContext->cache);
+ free(pContext);
+
+ if (!g_CardContexts)
+ return;
+
+ ListDictionary_Remove(g_CardContexts, (void*)hContext);
+}
+
+static BOOL PCSC_LockCardContext(SCARDCONTEXT hContext)
+{
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ {
+ WLog_ERR(TAG, "PCSC_LockCardContext: invalid context (%p)", (void*)hContext);
+ return FALSE;
+ }
+
+ EnterCriticalSection(&(pContext->lock));
+ return TRUE;
+}
+
+static BOOL PCSC_UnlockCardContext(SCARDCONTEXT hContext)
+{
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ {
+ WLog_ERR(TAG, "PCSC_UnlockCardContext: invalid context (%p)", (void*)hContext);
+ return FALSE;
+ }
+
+ LeaveCriticalSection(&(pContext->lock));
+ return TRUE;
+}
+
+static PCSC_SCARDHANDLE* PCSC_GetCardHandleData(SCARDHANDLE hCard)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+
+ if (!g_CardHandles)
+ return NULL;
+
+ pCard = (PCSC_SCARDHANDLE*)ListDictionary_GetItemValue(g_CardHandles, (void*)hCard);
+
+ if (!pCard)
+ return NULL;
+
+ return pCard;
+}
+
+static SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return 0;
+
+ return pCard->hSharedContext;
+}
+
+static BOOL PCSC_WaitForCardAccess(SCARDCONTEXT hContext, SCARDHANDLE hCard, BOOL shared)
+{
+ BOOL status = TRUE;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+
+ if (!hCard)
+ {
+ /* SCardConnect */
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ return FALSE;
+
+ if (!pContext->owner)
+ return TRUE;
+
+ /* wait for card ownership */
+ return TRUE;
+ }
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return FALSE;
+
+ shared = pCard->shared;
+ hContext = pCard->hSharedContext;
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ return FALSE;
+
+ if (!pContext->owner)
+ {
+ /* card is not owned */
+ if (!shared)
+ pContext->owner = hCard;
+
+ return TRUE;
+ }
+
+ if (pContext->owner == hCard)
+ {
+ /* already card owner */
+ }
+ else
+ {
+ /* wait for card ownership */
+ }
+
+ return status;
+}
+
+static BOOL PCSC_ReleaseCardAccess(SCARDCONTEXT hContext, SCARDHANDLE hCard)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+
+ if (!hCard)
+ {
+ /* release current owner */
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ return FALSE;
+
+ hCard = pContext->owner;
+
+ if (!hCard)
+ return TRUE;
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return FALSE;
+
+ /* release card ownership */
+ pContext->owner = 0;
+ return TRUE;
+ }
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return FALSE;
+
+ hContext = pCard->hSharedContext;
+ pContext = PCSC_GetCardContextData(hContext);
+
+ if (!pContext)
+ return FALSE;
+
+ if (pContext->owner == hCard)
+ {
+ /* release card ownership */
+ pContext->owner = 0;
+ }
+
+ return TRUE;
+}
+
+static PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDHANDLE hCard)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pContext = PCSC_GetCardContextData(hSharedContext);
+
+ if (!pContext)
+ {
+ WLog_ERR(TAG, "PCSC_ConnectCardHandle: null pContext!");
+ return NULL;
+ }
+
+ pCard = (PCSC_SCARDHANDLE*)calloc(1, sizeof(PCSC_SCARDHANDLE));
+
+ if (!pCard)
+ return NULL;
+
+ pCard->hSharedContext = hSharedContext;
+
+ if (!g_CardHandles)
+ {
+ g_CardHandles = ListDictionary_New(TRUE);
+
+ if (!g_CardHandles)
+ goto error;
+ }
+
+ if (!ListDictionary_Add(g_CardHandles, (void*)hCard, (void*)pCard))
+ goto error;
+
+ pContext->dwCardHandleCount++;
+ return pCard;
+error:
+ free(pCard);
+ return NULL;
+}
+
+static void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return;
+
+ pContext = PCSC_GetCardContextData(pCard->hSharedContext);
+ free(pCard);
+
+ if (!g_CardHandles)
+ return;
+
+ ListDictionary_Remove(g_CardHandles, (void*)hCard);
+
+ if (!pContext)
+ {
+ WLog_ERR(TAG, "PCSC_DisconnectCardHandle: null pContext!");
+ return;
+ }
+
+ pContext->dwCardHandleCount--;
+}
+
+static BOOL PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem)
+{
+ if (!g_MemoryBlocks)
+ {
+ g_MemoryBlocks = ListDictionary_New(TRUE);
+
+ if (!g_MemoryBlocks)
+ return FALSE;
+ }
+
+ return ListDictionary_Add(g_MemoryBlocks, pvMem, (void*)hContext);
+}
+
+static void* PCSC_RemoveMemoryBlock(SCARDCONTEXT hContext, void* pvMem)
+{
+ WINPR_UNUSED(hContext);
+
+ if (!g_MemoryBlocks)
+ return NULL;
+
+ return ListDictionary_Take(g_MemoryBlocks, pvMem);
+}
+
+/**
+ * Standard Windows Smart Card API (PCSC)
+ */
+
+static LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2,
+ LPSCARDCONTEXT phContext)
+{
+ WINPR_UNUSED(dwScope); /* SCARD_SCOPE_SYSTEM is the only scope supported by pcsc-lite */
+ PCSC_LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardEstablishContext)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardEstablishContext");
+
+ status =
+ g_PCSC.pfnSCardEstablishContext(SCARD_SCOPE_SYSTEM, pvReserved1, pvReserved2, phContext);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+ LONG status = 0;
+
+ status = PCSC_SCardEstablishContext_Internal(dwScope, pvReserved1, pvReserved2, phContext);
+
+ if (status == SCARD_S_SUCCESS)
+ PCSC_EstablishCardContext(*phContext);
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardReleaseContext)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardReleaseContext");
+
+ if (!hContext)
+ {
+ WLog_ERR(TAG, "SCardReleaseContext: null hContext");
+ return PCSC_MapErrorCodeToWinSCard(status);
+ }
+
+ status = g_PCSC.pfnSCardReleaseContext(hContext);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
+{
+ LONG status = SCARD_S_SUCCESS;
+
+ status = PCSC_SCardReleaseContext_Internal(hContext);
+
+ if (status != SCARD_S_SUCCESS)
+ PCSC_ReleaseCardContext(hContext);
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardIsValidContext(SCARDCONTEXT hContext)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardIsValidContext)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardIsValidContext");
+
+ status = g_PCSC.pfnSCardIsValidContext(hContext);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardListReaderGroups_Internal(SCARDCONTEXT hContext, LPSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ BOOL pcchGroupsAlloc = FALSE;
+ PCSC_DWORD pcsc_cchGroups = 0;
+
+ if (!pcchGroups)
+ return SCARD_E_INVALID_PARAMETER;
+
+ if (!g_PCSC.pfnSCardListReaderGroups)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
+
+ if (*pcchGroups == SCARD_AUTOALLOCATE)
+ pcchGroupsAlloc = TRUE;
+
+ pcsc_cchGroups = pcchGroupsAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcchGroups;
+
+ if (pcchGroupsAlloc && !g_SCardAutoAllocate)
+ {
+ pcsc_cchGroups = 0;
+ status = g_PCSC.pfnSCardListReaderGroups(hContext, NULL, &pcsc_cchGroups);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ LPSTR tmp = calloc(1, pcsc_cchGroups);
+
+ if (!tmp)
+ return SCARD_E_NO_MEMORY;
+
+ status = g_PCSC.pfnSCardListReaderGroups(hContext, tmp, &pcsc_cchGroups);
+
+ if (status != SCARD_S_SUCCESS)
+ {
+ free(tmp);
+ tmp = NULL;
+ }
+ else
+ PCSC_AddMemoryBlock(hContext, tmp);
+
+ *(LPSTR*)mszGroups = tmp;
+ }
+ }
+ else
+ {
+ status = g_PCSC.pfnSCardListReaderGroups(hContext, mszGroups, &pcsc_cchGroups);
+ }
+
+ *pcchGroups = (DWORD)pcsc_cchGroups;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardListReaderGroupsA(SCARDCONTEXT hContext, LPSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardListReaderGroups)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ status = PCSC_SCardListReaderGroups_Internal(hContext, mszGroups, pcchGroups);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardListReaderGroupsW(SCARDCONTEXT hContext, LPWSTR mszGroups,
+ LPDWORD pcchGroups)
+{
+ LPSTR mszGroupsA = NULL;
+ LPSTR* pMszGroupsA = &mszGroupsA;
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardListReaderGroups)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaderGroups");
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ status = PCSC_SCardListReaderGroups_Internal(hContext, (LPSTR)&mszGroupsA, pcchGroups);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ size_t size = 0;
+ WCHAR* str = ConvertMszUtf8NToWCharAlloc(*pMszGroupsA, *pcchGroups, &size);
+ if (!str)
+ return SCARD_E_NO_MEMORY;
+ *(WCHAR**)mszGroups = str;
+ *pcchGroups = (DWORD)size;
+ PCSC_AddMemoryBlock(hContext, str);
+ PCSC_SCardFreeMemory_Internal(hContext, *pMszGroupsA);
+ }
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardListReaders_Internal(SCARDCONTEXT hContext, LPCSTR mszGroups,
+ LPSTR mszReaders, LPDWORD pcchReaders)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ BOOL pcchReadersAlloc = FALSE;
+ PCSC_DWORD pcsc_cchReaders = 0;
+ if (!pcchReaders)
+ return SCARD_E_INVALID_PARAMETER;
+
+ if (!g_PCSC.pfnSCardListReaders)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
+
+ mszGroups = NULL; /* mszGroups is not supported by pcsc-lite */
+
+ if (*pcchReaders == SCARD_AUTOALLOCATE)
+ pcchReadersAlloc = TRUE;
+
+ pcsc_cchReaders = pcchReadersAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcchReaders;
+
+ if (pcchReadersAlloc && !g_SCardAutoAllocate)
+ {
+ pcsc_cchReaders = 0;
+ status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, NULL, &pcsc_cchReaders);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ char* tmp = calloc(1, pcsc_cchReaders);
+
+ if (!tmp)
+ return SCARD_E_NO_MEMORY;
+
+ status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, tmp, &pcsc_cchReaders);
+
+ if (status != SCARD_S_SUCCESS)
+ {
+ free(tmp);
+ tmp = NULL;
+ }
+ else
+ PCSC_AddMemoryBlock(hContext, tmp);
+
+ *(char**)mszReaders = tmp;
+ }
+ }
+ else
+ {
+ status = g_PCSC.pfnSCardListReaders(hContext, mszGroups, mszReaders, &pcsc_cchReaders);
+ }
+
+ *pcchReaders = (DWORD)pcsc_cchReaders;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardListReadersA(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ BOOL nullCardContext = FALSE;
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardListReaders)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
+
+ if (!hContext)
+ {
+ status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+ if (status != SCARD_S_SUCCESS)
+ return status;
+
+ nullCardContext = TRUE;
+ }
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ status = PCSC_SCardListReaders_Internal(hContext, mszGroups, mszReaders, pcchReaders);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ if (nullCardContext)
+ {
+ status = PCSC_SCardReleaseContext(hContext);
+ }
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardListReadersW(SCARDCONTEXT hContext, LPCWSTR mszGroups,
+ LPWSTR mszReaders, LPDWORD pcchReaders)
+{
+ LPSTR mszGroupsA = NULL;
+ LPSTR mszReadersA = NULL;
+ LONG status = SCARD_S_SUCCESS;
+ BOOL nullCardContext = FALSE;
+
+ if (!g_PCSC.pfnSCardListReaders)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardListReaders");
+
+ if (!hContext)
+ {
+ status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+ if (status != SCARD_S_SUCCESS)
+ return status;
+
+ nullCardContext = TRUE;
+ }
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ mszGroups = NULL; /* mszGroups is not supported by pcsc-lite */
+
+ if (mszGroups)
+ {
+ mszGroupsA = ConvertWCharToUtf8Alloc(mszGroups, NULL);
+ if (!mszGroups)
+ return SCARD_E_NO_MEMORY;
+ }
+
+ status =
+ PCSC_SCardListReaders_Internal(hContext, mszGroupsA, (LPSTR*)&mszReadersA, pcchReaders);
+ if (status == SCARD_S_SUCCESS)
+ {
+ size_t size = 0;
+ WCHAR* str = ConvertMszUtf8NToWCharAlloc(mszReadersA, *pcchReaders, &size);
+ PCSC_SCardFreeMemory_Internal(hContext, mszReadersA);
+ if (!str || (size > UINT32_MAX))
+ {
+ free(mszGroupsA);
+ return SCARD_E_NO_MEMORY;
+ }
+ *(LPWSTR*)mszReaders = str;
+ *pcchReaders = (DWORD)size;
+ PCSC_AddMemoryBlock(hContext, str);
+ }
+
+ free(mszGroupsA);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ if (nullCardContext)
+ {
+ status = PCSC_SCardReleaseContext(hContext);
+ }
+
+ return status;
+}
+
+typedef struct
+{
+ BYTE atr[64];
+ size_t atrLen;
+ const char* cardName;
+} PcscKnownAtr;
+
+static PcscKnownAtr knownAtrs[] = {
+ /* Yubico YubiKey 5 NFC (PKI) */
+ { { 0x3B, 0xFD, 0x13, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x15, 0x80, 0x73, 0xC0,
+ 0x21, 0xC0, 0x57, 0x59, 0x75, 0x62, 0x69, 0x4B, 0x65, 0x79, 0x40 },
+ 23,
+ "NIST SP 800-73 [PIV]" },
+ /* PIVKey C910 PKI Smart Card (eID) */
+ { { 0x3B, 0xFC, 0x18, 0x00, 0x00, 0x81, 0x31, 0x80, 0x45, 0x90, 0x67,
+ 0x46, 0x4A, 0x00, 0x64, 0x16, 0x06, 0xF2, 0x72, 0x7E, 0x00, 0xE0 },
+ 22,
+ "PIVKey Feitian (E0)" }
+};
+
+#ifndef ARRAY_LENGTH
+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
+#endif
+
+static const char* findCardByAtr(LPCBYTE pbAtr)
+{
+ for (size_t i = 0; i < ARRAY_LENGTH(knownAtrs); i++)
+ {
+ if (memcmp(knownAtrs[i].atr, pbAtr, knownAtrs[i].atrLen) == 0)
+ return knownAtrs[i].cardName;
+ }
+
+ return NULL;
+}
+
+static LONG WINAPI PCSC_SCardListCardsA(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ CHAR* mszCards, LPDWORD pcchCards)
+{
+ const char* cardName = NULL;
+ DWORD outputLen = 1;
+ CHAR* output = NULL;
+ BOOL autoAllocate = 0;
+
+ if (!pbAtr || rgquidInterfaces || cguidInterfaceCount)
+ return SCARD_E_UNSUPPORTED_FEATURE;
+
+ if (!pcchCards)
+ return SCARD_E_INVALID_PARAMETER;
+
+ autoAllocate = (*pcchCards == SCARD_AUTOALLOCATE);
+
+ cardName = findCardByAtr(pbAtr);
+ if (cardName)
+ outputLen += strlen(cardName) + 1;
+
+ *pcchCards = outputLen;
+ if (autoAllocate)
+ {
+ output = malloc(outputLen);
+ if (!output)
+ return SCARD_E_NO_MEMORY;
+
+ *((LPSTR*)mszCards) = output;
+ }
+ else
+ {
+ if (!mszCards)
+ return SCARD_S_SUCCESS;
+
+ if (*pcchCards < outputLen)
+ return SCARD_E_INSUFFICIENT_BUFFER;
+
+ output = mszCards;
+ }
+
+ if (cardName)
+ {
+ size_t toCopy = strlen(cardName) + 1;
+ memcpy(output, cardName, toCopy);
+ output += toCopy;
+ }
+
+ *output = '\0';
+
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardListCardsW(SCARDCONTEXT hContext, LPCBYTE pbAtr,
+ LPCGUID rgquidInterfaces, DWORD cguidInterfaceCount,
+ WCHAR* mszCards, LPDWORD pcchCards)
+{
+ const char* cardName = NULL;
+ DWORD outputLen = 1;
+ WCHAR* output = NULL;
+ BOOL autoAllocate = 0;
+
+ if (!pbAtr || rgquidInterfaces || cguidInterfaceCount)
+ return SCARD_E_UNSUPPORTED_FEATURE;
+
+ if (!pcchCards)
+ return SCARD_E_INVALID_PARAMETER;
+
+ autoAllocate = (*pcchCards == SCARD_AUTOALLOCATE);
+
+ cardName = findCardByAtr(pbAtr);
+ if (cardName)
+ outputLen += strlen(cardName) + 1;
+
+ *pcchCards = outputLen;
+ if (autoAllocate)
+ {
+ output = malloc(outputLen * 2);
+ if (!output)
+ return SCARD_E_NO_MEMORY;
+
+ *((LPWSTR*)mszCards) = output;
+ }
+ else
+ {
+ if (!mszCards)
+ return SCARD_S_SUCCESS;
+
+ if (*pcchCards < outputLen)
+ return SCARD_E_INSUFFICIENT_BUFFER;
+
+ output = mszCards;
+ }
+
+ if (cardName)
+ {
+ size_t toCopy = strlen(cardName) + 1;
+ if (ConvertUtf8ToWChar(cardName, output, toCopy) < 0)
+ return SCARD_F_INTERNAL_ERROR;
+ output += toCopy;
+ }
+
+ *output = 0;
+
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardListInterfacesA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCard);
+ WINPR_UNUSED(pguidInterfaces);
+ WINPR_UNUSED(pcguidInterfaces);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardListInterfacesW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidInterfaces, LPDWORD pcguidInterfaces)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCard);
+ WINPR_UNUSED(pguidInterfaces);
+ WINPR_UNUSED(pcguidInterfaces);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetProviderIdA(SCARDCONTEXT hContext, LPCSTR szCard,
+ LPGUID pguidProviderId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCard);
+ WINPR_UNUSED(pguidProviderId);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetProviderIdW(SCARDCONTEXT hContext, LPCWSTR szCard,
+ LPGUID pguidProviderId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCard);
+ WINPR_UNUSED(pguidProviderId);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, CHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(dwProviderId);
+ WINPR_UNUSED(szProvider);
+ WINPR_UNUSED(pcchProvider);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, WCHAR* szProvider,
+ LPDWORD pcchProvider)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(dwProviderId);
+ WINPR_UNUSED(szProvider);
+ WINPR_UNUSED(pcchProvider);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetReaderGroupA(SCARDCONTEXT hContext, LPCSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetReaderGroupW(SCARDCONTEXT hContext, LPCWSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szDeviceName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szDeviceName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szDeviceName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szDeviceName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetReaderA(SCARDCONTEXT hContext, LPCSTR szReaderName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetReaderW(SCARDCONTEXT hContext, LPCWSTR szReaderName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardAddReaderToGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardAddReaderToGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardRemoveReaderFromGroupA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPCSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardRemoveReaderFromGroupW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPCWSTR szGroupName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szGroupName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(pguidPrimaryProvider);
+ WINPR_UNUSED(rgguidInterfaces);
+ WINPR_UNUSED(dwInterfaceCount);
+ WINPR_UNUSED(pbAtr);
+ WINPR_UNUSED(pbAtrMask);
+ WINPR_UNUSED(cbAtrLen);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardIntroduceCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ LPCGUID pguidPrimaryProvider,
+ LPCGUID rgguidInterfaces, DWORD dwInterfaceCount,
+ LPCBYTE pbAtr, LPCBYTE pbAtrMask, DWORD cbAtrLen)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(pguidPrimaryProvider);
+ WINPR_UNUSED(rgguidInterfaces);
+ WINPR_UNUSED(dwInterfaceCount);
+ WINPR_UNUSED(pbAtr);
+ WINPR_UNUSED(pbAtrMask);
+ WINPR_UNUSED(cbAtrLen);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardSetCardTypeProviderNameA(SCARDCONTEXT hContext, LPCSTR szCardName,
+ DWORD dwProviderId, LPCSTR szProvider)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(dwProviderId);
+ WINPR_UNUSED(szProvider);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardSetCardTypeProviderNameW(SCARDCONTEXT hContext, LPCWSTR szCardName,
+ DWORD dwProviderId, LPCWSTR szProvider)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ WINPR_UNUSED(dwProviderId);
+ WINPR_UNUSED(szProvider);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardForgetCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szCardName);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPVOID pvMem)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+
+ if (PCSC_RemoveMemoryBlock(hContext, pvMem))
+ {
+ free((void*)pvMem);
+ status = SCARD_S_SUCCESS;
+ }
+ else
+ {
+ if (g_PCSC.pfnSCardFreeMemory)
+ {
+ status = g_PCSC.pfnSCardFreeMemory(hContext, pvMem);
+ }
+ }
+
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem)
+{
+ LONG status = SCARD_S_SUCCESS;
+
+ if (hContext)
+ {
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+ }
+
+ status = PCSC_SCardFreeMemory_Internal(hContext, pvMem);
+
+ if (hContext)
+ {
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+ }
+
+ return status;
+}
+
+static HANDLE WINAPI PCSC_SCardAccessStartedEvent(void)
+{
+ LONG status = 0;
+ SCARDCONTEXT hContext = 0;
+
+ status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+ if (status != SCARD_S_SUCCESS)
+ return NULL;
+
+ status = PCSC_SCardReleaseContext(hContext);
+
+ if (status != SCARD_S_SUCCESS)
+ return NULL;
+
+ if (!g_StartedEvent)
+ {
+ if (!(g_StartedEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ return NULL;
+
+ if (!SetEvent(g_StartedEvent))
+ {
+ CloseHandle(g_StartedEvent);
+ return NULL;
+ }
+ }
+
+ g_StartedEventRefCount++;
+ return g_StartedEvent;
+}
+
+static void WINAPI PCSC_SCardReleaseStartedEvent(void)
+{
+ g_StartedEventRefCount--;
+
+ if (g_StartedEventRefCount == 0)
+ {
+ if (g_StartedEvent)
+ {
+ CloseHandle(g_StartedEvent);
+ g_StartedEvent = NULL;
+ }
+ }
+}
+
+static LONG WINAPI PCSC_SCardLocateCardsA(SCARDCONTEXT hContext, LPCSTR mszCards,
+ LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(mszCards);
+ WINPR_UNUSED(rgReaderStates);
+ WINPR_UNUSED(cReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardLocateCardsW(SCARDCONTEXT hContext, LPCWSTR mszCards,
+ LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(mszCards);
+ WINPR_UNUSED(rgReaderStates);
+ WINPR_UNUSED(cReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardLocateCardsByATRA(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEA rgReaderStates,
+ DWORD cReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(rgAtrMasks);
+ WINPR_UNUSED(cAtrs);
+ WINPR_UNUSED(rgReaderStates);
+ WINPR_UNUSED(cReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardLocateCardsByATRW(SCARDCONTEXT hContext, LPSCARD_ATRMASK rgAtrMasks,
+ DWORD cAtrs, LPSCARD_READERSTATEW rgReaderStates,
+ DWORD cReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(rgAtrMasks);
+ WINPR_UNUSED(cAtrs);
+ WINPR_UNUSED(rgReaderStates);
+ WINPR_UNUSED(cReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEA rgReaderStates,
+ DWORD cReaders)
+{
+ INT64* map = NULL;
+ PCSC_DWORD cMappedReaders = 0;
+ PCSC_SCARD_READERSTATE* states = NULL;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_DWORD pcsc_dwTimeout = (PCSC_DWORD)dwTimeout;
+ PCSC_DWORD pcsc_cReaders = (PCSC_DWORD)cReaders;
+
+ if (!g_PCSC.pfnSCardGetStatusChange)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardGetStatusChange");
+
+ if (!cReaders)
+ return SCARD_S_SUCCESS;
+
+ /* pcsc-lite interprets value 0 as INFINITE, work around the problem by using value 1 */
+ pcsc_dwTimeout = pcsc_dwTimeout ? pcsc_dwTimeout : 1;
+ /**
+ * Apple's SmartCard Services (not vanilla pcsc-lite) appears to have trouble with the
+ * "\\\\?PnP?\\Notification" reader name. I am always getting EXC_BAD_ACCESS with it.
+ *
+ * The SmartCard Services tarballs can be found here:
+ * http://opensource.apple.com/tarballs/SmartCardServices/
+ *
+ * The "\\\\?PnP?\\Notification" string cannot be found anywhere in the sources,
+ * while this string is present in the vanilla pcsc-lite sources.
+ *
+ * To work around this apparent lack of "\\\\?PnP?\\Notification" support,
+ * we have to filter rgReaderStates to exclude the special PnP reader name.
+ */
+ map = (INT64*)calloc(pcsc_cReaders, sizeof(INT64));
+
+ if (!map)
+ return SCARD_E_NO_MEMORY;
+
+ states = (PCSC_SCARD_READERSTATE*)calloc(pcsc_cReaders, sizeof(PCSC_SCARD_READERSTATE));
+
+ if (!states)
+ {
+ free(map);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ PCSC_DWORD j = 0;
+ for (PCSC_DWORD i = 0; i < pcsc_cReaders; i++)
+ {
+ if (!g_PnP_Notification)
+ {
+ LPSCARD_READERSTATEA reader = &rgReaderStates[i];
+ if (!reader->szReader)
+ continue;
+ if (0 == _stricmp(reader->szReader, SMARTCARD_PNP_NOTIFICATION_A))
+ {
+ map[i] = -1; /* unmapped */
+ continue;
+ }
+ }
+
+ map[i] = (INT64)j;
+ states[j].szReader = rgReaderStates[i].szReader;
+ states[j].dwCurrentState = rgReaderStates[i].dwCurrentState;
+ states[j].pvUserData = rgReaderStates[i].pvUserData;
+ states[j].dwEventState = rgReaderStates[i].dwEventState;
+ states[j].cbAtr = rgReaderStates[i].cbAtr;
+ CopyMemory(&(states[j].rgbAtr), &(rgReaderStates[i].rgbAtr), PCSC_MAX_ATR_SIZE);
+ j++;
+ }
+
+ cMappedReaders = j;
+
+ if (cMappedReaders > 0)
+ {
+ status = g_PCSC.pfnSCardGetStatusChange(hContext, pcsc_dwTimeout, states, cMappedReaders);
+ }
+ else
+ {
+ status = SCARD_S_SUCCESS;
+ }
+
+ for (PCSC_DWORD i = 0; i < pcsc_cReaders; i++)
+ {
+ if (map[i] < 0)
+ continue; /* unmapped */
+
+ PCSC_DWORD j = (PCSC_DWORD)map[i];
+ rgReaderStates[i].dwCurrentState = (DWORD)states[j].dwCurrentState;
+ rgReaderStates[i].cbAtr = (DWORD)states[j].cbAtr;
+ CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[j].rgbAtr), PCSC_MAX_ATR_SIZE);
+ rgReaderStates[i].dwEventState = (DWORD)states[j].dwEventState;
+ }
+
+ free(map);
+ free(states);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardGetStatusChangeA(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEA rgReaderStates, DWORD cReaders)
+{
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ status = PCSC_SCardGetStatusChange_Internal(hContext, dwTimeout, rgReaderStates, cReaders);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardGetStatusChangeW(SCARDCONTEXT hContext, DWORD dwTimeout,
+ LPSCARD_READERSTATEW rgReaderStates, DWORD cReaders)
+{
+ LPSCARD_READERSTATEA states = NULL;
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardGetStatusChange)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardGetStatusChange");
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ states = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA));
+
+ if (!states)
+ {
+ PCSC_UnlockCardContext(hContext);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ for (DWORD index = 0; index < cReaders; index++)
+ {
+ const LPSCARD_READERSTATEW curReader = &rgReaderStates[index];
+ LPSCARD_READERSTATEA cur = &states[index];
+
+ cur->szReader = ConvertWCharToUtf8Alloc(curReader->szReader, NULL);
+ cur->pvUserData = curReader->pvUserData;
+ cur->dwCurrentState = curReader->dwCurrentState;
+ cur->dwEventState = curReader->dwEventState;
+ cur->cbAtr = curReader->cbAtr;
+ CopyMemory(&(cur->rgbAtr), &(curReader->rgbAtr), ARRAYSIZE(cur->rgbAtr));
+ }
+
+ status = PCSC_SCardGetStatusChange_Internal(hContext, dwTimeout, states, cReaders);
+
+ for (DWORD index = 0; index < cReaders; index++)
+ {
+ free((void*)states[index].szReader);
+ rgReaderStates[index].pvUserData = states[index].pvUserData;
+ rgReaderStates[index].dwCurrentState = states[index].dwCurrentState;
+ rgReaderStates[index].dwEventState = states[index].dwEventState;
+ rgReaderStates[index].cbAtr = states[index].cbAtr;
+ CopyMemory(&(rgReaderStates[index].rgbAtr), &(states[index].rgbAtr), 36);
+ }
+
+ free(states);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardCancel(SCARDCONTEXT hContext)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+
+ if (!g_PCSC.pfnSCardCancel)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardCancel");
+
+ status = g_PCSC.pfnSCardCancel(hContext);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext, LPCSTR szReader,
+ DWORD dwShareMode, DWORD dwPreferredProtocols,
+ LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
+{
+ BOOL shared = 0;
+ const char* szReaderPCSC = NULL;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD)dwShareMode;
+ PCSC_DWORD pcsc_dwPreferredProtocols = 0;
+ PCSC_DWORD pcsc_dwActiveProtocol = 0;
+
+ if (!g_PCSC.pfnSCardConnect)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardConnect");
+
+ shared = (dwShareMode == SCARD_SHARE_DIRECT) ? TRUE : FALSE;
+ PCSC_WaitForCardAccess(hContext, 0, shared);
+ szReaderPCSC = szReader;
+
+ /**
+ * As stated here :
+ * https://pcsclite.alioth.debian.org/api/group__API.html#ga4e515829752e0a8dbc4d630696a8d6a5
+ * SCARD_PROTOCOL_UNDEFINED is valid for dwPreferredProtocols (only) if dwShareMode ==
+ * SCARD_SHARE_DIRECT and allows to send control commands to the reader (with SCardControl())
+ * even if a card is not present in the reader
+ */
+ if (pcsc_dwShareMode == SCARD_SHARE_DIRECT && dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED)
+ pcsc_dwPreferredProtocols = SCARD_PROTOCOL_UNDEFINED;
+ else
+ pcsc_dwPreferredProtocols =
+ (PCSC_DWORD)PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
+
+ status = g_PCSC.pfnSCardConnect(hContext, szReaderPCSC, pcsc_dwShareMode,
+ pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ pCard = PCSC_ConnectCardHandle(hContext, *phCard);
+ *pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwActiveProtocol);
+ pCard->shared = shared;
+
+ // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ListDictionary_Add takes ownership of pCard
+ PCSC_WaitForCardAccess(hContext, pCard->hSharedContext, shared);
+ }
+
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardConnectA(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ status = PCSC_SCardConnect_Internal(hContext, szReader, dwShareMode, dwPreferredProtocols,
+ phCard, pdwActiveProtocol);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardConnectW(SCARDCONTEXT hContext, LPCWSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
+ LPDWORD pdwActiveProtocol)
+{
+ LPSTR szReaderA = NULL;
+ LONG status = SCARD_S_SUCCESS;
+
+ if (!PCSC_LockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ if (szReader)
+ {
+ szReaderA = ConvertWCharToUtf8Alloc(szReader, NULL);
+ if (!szReaderA)
+ return SCARD_E_INSUFFICIENT_BUFFER;
+ }
+
+ status = PCSC_SCardConnect_Internal(hContext, szReaderA, dwShareMode, dwPreferredProtocols,
+ phCard, pdwActiveProtocol);
+ free(szReaderA);
+
+ if (!PCSC_UnlockCardContext(hContext))
+ return SCARD_E_INVALID_HANDLE;
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, DWORD dwInitialization,
+ LPDWORD pdwActiveProtocol)
+{
+ BOOL shared = 0;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD)dwShareMode;
+ PCSC_DWORD pcsc_dwPreferredProtocols = 0;
+ PCSC_DWORD pcsc_dwInitialization = (PCSC_DWORD)dwInitialization;
+ PCSC_DWORD pcsc_dwActiveProtocol = 0;
+
+ if (!g_PCSC.pfnSCardReconnect)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardReconnect");
+
+ shared = (dwShareMode == SCARD_SHARE_DIRECT) ? TRUE : FALSE;
+ PCSC_WaitForCardAccess(0, hCard, shared);
+ pcsc_dwPreferredProtocols = (PCSC_DWORD)PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
+ status = g_PCSC.pfnSCardReconnect(hCard, pcsc_dwShareMode, pcsc_dwPreferredProtocols,
+ pcsc_dwInitialization, &pcsc_dwActiveProtocol);
+
+ *pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwActiveProtocol);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_DWORD pcsc_dwDisposition = (PCSC_DWORD)dwDisposition;
+
+ if (!g_PCSC.pfnSCardDisconnect)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardDisconnect");
+
+ status = g_PCSC.pfnSCardDisconnect(hCard, pcsc_dwDisposition);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ PCSC_DisconnectCardHandle(hCard);
+ }
+
+ PCSC_ReleaseCardAccess(0, hCard);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+
+ if (!g_PCSC.pfnSCardBeginTransaction)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardBeginTransaction");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_HANDLE;
+
+ pContext = PCSC_GetCardContextData(pCard->hSharedContext);
+
+ if (!pContext)
+ return SCARD_E_INVALID_HANDLE;
+
+ if (pContext->isTransactionLocked)
+ return SCARD_S_SUCCESS; /* disable nested transactions */
+
+ status = g_PCSC.pfnSCardBeginTransaction(hCard);
+
+ pContext->isTransactionLocked = TRUE;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_SCARDCONTEXT* pContext = NULL;
+ PCSC_DWORD pcsc_dwDisposition = (PCSC_DWORD)dwDisposition;
+
+ if (!g_PCSC.pfnSCardEndTransaction)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardEndTransaction");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_HANDLE;
+
+ pContext = PCSC_GetCardContextData(pCard->hSharedContext);
+
+ if (!pContext)
+ return SCARD_E_INVALID_HANDLE;
+
+ PCSC_ReleaseCardAccess(0, hCard);
+
+ if (!pContext->isTransactionLocked)
+ return SCARD_S_SUCCESS; /* disable nested transactions */
+
+ status = g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
+
+ pContext->isTransactionLocked = FALSE;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardCancelTransaction(SCARDHANDLE hCard)
+{
+ WINPR_UNUSED(hCard);
+ return SCARD_S_SUCCESS;
+}
+
+/*
+ * PCSC returns a string but Windows SCardStatus requires the return to be a multi string.
+ * Therefore extra length checks and additional buffer allocation is required
+ */
+static LONG WINAPI PCSC_SCardStatus_Internal(SCARDHANDLE hCard, LPSTR mszReaderNames,
+ LPDWORD pcchReaderLen, LPDWORD pdwState,
+ LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen,
+ BOOL unicode)
+{
+ PCSC_SCARDHANDLE* pCard = NULL;
+ SCARDCONTEXT hContext = 0;
+ PCSC_LONG status = 0;
+ PCSC_DWORD pcsc_cchReaderLen = 0;
+ PCSC_DWORD pcsc_cbAtrLen = 0;
+ PCSC_DWORD pcsc_dwState = 0;
+ PCSC_DWORD pcsc_dwProtocol = 0;
+ BOOL allocateReader = FALSE;
+ BOOL allocateAtr = FALSE;
+ LPSTR readerNames = mszReaderNames;
+ LPBYTE atr = pbAtr;
+ LPSTR tReader = NULL;
+ LPBYTE tATR = NULL;
+
+ if (!g_PCSC.pfnSCardStatus)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardStatus");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ hContext = PCSC_GetCardContextFromHandle(hCard);
+
+ if (!hContext)
+ return SCARD_E_INVALID_VALUE;
+
+ status =
+ g_PCSC.pfnSCardStatus(hCard, NULL, &pcsc_cchReaderLen, NULL, NULL, NULL, &pcsc_cbAtrLen);
+
+ if (status != STATUS_SUCCESS)
+ return PCSC_MapErrorCodeToWinSCard(status);
+
+ pcsc_cchReaderLen++;
+
+ if (unicode)
+ pcsc_cchReaderLen *= 2;
+
+ if (pcchReaderLen)
+ {
+ if (*pcchReaderLen == SCARD_AUTOALLOCATE)
+ allocateReader = TRUE;
+ else if (mszReaderNames && (*pcchReaderLen < pcsc_cchReaderLen))
+ return SCARD_E_INSUFFICIENT_BUFFER;
+ else
+ pcsc_cchReaderLen = *pcchReaderLen;
+ }
+
+ if (pcbAtrLen)
+ {
+ if (*pcbAtrLen == SCARD_AUTOALLOCATE)
+ allocateAtr = TRUE;
+ else if (pbAtr && (*pcbAtrLen < pcsc_cbAtrLen))
+ return SCARD_E_INSUFFICIENT_BUFFER;
+ else
+ pcsc_cbAtrLen = *pcbAtrLen;
+ }
+
+ if (allocateReader && pcsc_cchReaderLen > 0 && mszReaderNames)
+ {
+#ifdef __MACOSX__
+
+ /**
+ * Workaround for SCardStatus Bug in MAC OS X Yosemite
+ */
+ if (OSXVersion == 0x10100000)
+ pcsc_cchReaderLen++;
+
+#endif
+ tReader = calloc(sizeof(CHAR), pcsc_cchReaderLen + 1);
+
+ if (!tReader)
+ {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto out_fail;
+ }
+
+ readerNames = tReader;
+ }
+
+ if (allocateAtr && pcsc_cbAtrLen > 0 && pbAtr)
+ {
+ tATR = calloc(1, pcsc_cbAtrLen);
+
+ if (!tATR)
+ {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto out_fail;
+ }
+
+ atr = tATR;
+ }
+
+ status = g_PCSC.pfnSCardStatus(hCard, readerNames, &pcsc_cchReaderLen, &pcsc_dwState,
+ &pcsc_dwProtocol, atr, &pcsc_cbAtrLen);
+
+ if (status != STATUS_SUCCESS)
+ goto out_fail;
+
+ if (tATR)
+ {
+ PCSC_AddMemoryBlock(hContext, tATR);
+ *(BYTE**)pbAtr = tATR;
+ }
+
+ if (tReader)
+ {
+ if (unicode)
+ {
+ size_t size = 0;
+ WCHAR* tmp = ConvertMszUtf8NToWCharAlloc(tReader, pcsc_cchReaderLen + 1, &size);
+
+ if (tmp == NULL)
+ {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto out_fail;
+ }
+
+ free(tReader);
+
+ PCSC_AddMemoryBlock(hContext, tmp);
+ *(WCHAR**)mszReaderNames = tmp;
+ }
+ else
+ {
+ tReader[pcsc_cchReaderLen - 1] = '\0';
+ PCSC_AddMemoryBlock(hContext, tReader);
+ *(char**)mszReaderNames = tReader;
+ }
+ }
+
+ pcsc_dwState &= 0xFFFF;
+
+ if (pdwState)
+ *pdwState = PCSC_ConvertCardStateToWinSCard((DWORD)pcsc_dwState, status);
+
+ if (pdwProtocol)
+ *pdwProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwProtocol);
+
+ if (pcbAtrLen)
+ *pcbAtrLen = (DWORD)pcsc_cbAtrLen;
+
+ if (pcchReaderLen)
+ {
+ WINPR_ASSERT(pcsc_cchReaderLen < UINT32_MAX);
+ *pcchReaderLen = (DWORD)pcsc_cchReaderLen + 1u;
+ }
+
+ return (LONG)status;
+out_fail:
+ free(tReader);
+ free(tATR);
+ return (LONG)status;
+}
+
+static LONG WINAPI PCSC_SCardState(SCARDHANDLE hCard, LPDWORD pdwState, LPDWORD pdwProtocol,
+ LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+ DWORD cchReaderLen = 0;
+ SCARDCONTEXT hContext = 0;
+ LPSTR mszReaderNames = NULL;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ DWORD pcsc_dwState = 0;
+ DWORD pcsc_dwProtocol = 0;
+ DWORD pcsc_cbAtrLen = 0;
+
+ if (pcbAtrLen)
+ pcsc_cbAtrLen = (DWORD)*pcbAtrLen;
+
+ if (!g_PCSC.pfnSCardStatus)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardStatus");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ hContext = PCSC_GetCardContextFromHandle(hCard);
+
+ if (!hContext)
+ return SCARD_E_INVALID_VALUE;
+
+ cchReaderLen = SCARD_AUTOALLOCATE;
+ status = PCSC_SCardStatus_Internal(hCard, (LPSTR)&mszReaderNames, &cchReaderLen, &pcsc_dwState,
+ &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen, FALSE);
+
+ if (mszReaderNames)
+ PCSC_SCardFreeMemory_Internal(hContext, mszReaderNames);
+
+ *pdwState = (DWORD)pcsc_dwState;
+ *pdwProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD)pcsc_dwProtocol);
+ if (pcbAtrLen)
+ *pcbAtrLen = (DWORD)pcsc_cbAtrLen;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardStatusA(SCARDHANDLE hCard, LPSTR mszReaderNames, LPDWORD pcchReaderLen,
+ LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr,
+ LPDWORD pcbAtrLen)
+{
+
+ return PCSC_SCardStatus_Internal(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol,
+ pbAtr, pcbAtrLen, FALSE);
+}
+
+static LONG WINAPI PCSC_SCardStatusW(SCARDHANDLE hCard, LPWSTR mszReaderNames,
+ LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol,
+ LPBYTE pbAtr, LPDWORD pcbAtrLen)
+{
+
+ return PCSC_SCardStatus_Internal(hCard, (LPSTR)mszReaderNames, pcchReaderLen, pdwState,
+ pdwProtocol, pbAtr, pcbAtrLen, TRUE);
+}
+
+static LONG WINAPI PCSC_SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
+ LPCBYTE pbSendBuffer, DWORD cbSendLength,
+ LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
+ LPDWORD pcbRecvLength)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_DWORD cbExtraBytes = 0;
+ BYTE* pbExtraBytes = NULL;
+ BYTE* pcsc_pbExtraBytes = NULL;
+ PCSC_DWORD pcsc_cbSendLength = (PCSC_DWORD)cbSendLength;
+ PCSC_DWORD pcsc_cbRecvLength = 0;
+ union
+ {
+ const PCSC_SCARD_IO_REQUEST* pcs;
+ PCSC_SCARD_IO_REQUEST* ps;
+ LPSCARD_IO_REQUEST lps;
+ LPCSCARD_IO_REQUEST lpcs;
+ BYTE* pb;
+ } sendPci, recvPci, inRecvPci, inSendPci;
+
+ sendPci.ps = NULL;
+ recvPci.ps = NULL;
+ inRecvPci.lps = pioRecvPci;
+ inSendPci.lpcs = pioSendPci;
+
+ if (!g_PCSC.pfnSCardTransmit)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardTransmit");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+
+ if (!pcbRecvLength)
+ return SCARD_E_INVALID_PARAMETER;
+
+ if (*pcbRecvLength == SCARD_AUTOALLOCATE)
+ return SCARD_E_INVALID_PARAMETER;
+
+ pcsc_cbRecvLength = (PCSC_DWORD)*pcbRecvLength;
+
+ if (!inSendPci.lpcs)
+ {
+ PCSC_DWORD dwState = 0;
+ PCSC_DWORD cbAtrLen = 0;
+ PCSC_DWORD dwProtocol = 0;
+ PCSC_DWORD cchReaderLen = 0;
+ /**
+ * pcsc-lite cannot have a null pioSendPci parameter, unlike WinSCard.
+ * Query the current protocol and use default SCARD_IO_REQUEST for it.
+ */
+ status = g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState, &dwProtocol, NULL,
+ &cbAtrLen);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ if (dwProtocol == SCARD_PROTOCOL_T0)
+ sendPci.pcs = PCSC_SCARD_PCI_T0;
+ else if (dwProtocol == SCARD_PROTOCOL_T1)
+ sendPci.pcs = PCSC_SCARD_PCI_T1;
+ else if (dwProtocol == PCSC_SCARD_PROTOCOL_RAW)
+ sendPci.pcs = PCSC_SCARD_PCI_RAW;
+ }
+ }
+ else
+ {
+ cbExtraBytes = inSendPci.lpcs->cbPciLength - sizeof(SCARD_IO_REQUEST);
+ sendPci.ps = (PCSC_SCARD_IO_REQUEST*)malloc(sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes);
+
+ if (!sendPci.ps)
+ return SCARD_E_NO_MEMORY;
+
+ sendPci.ps->dwProtocol = (PCSC_DWORD)inSendPci.lpcs->dwProtocol;
+ sendPci.ps->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes;
+ pbExtraBytes = &(inSendPci.pb)[sizeof(SCARD_IO_REQUEST)];
+ pcsc_pbExtraBytes = &(sendPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
+ CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes);
+ }
+
+ if (inRecvPci.lps)
+ {
+ cbExtraBytes = inRecvPci.lps->cbPciLength - sizeof(SCARD_IO_REQUEST);
+ recvPci.ps = (PCSC_SCARD_IO_REQUEST*)malloc(sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes);
+
+ if (!recvPci.ps)
+ {
+ if (inSendPci.lpcs)
+ free(sendPci.ps);
+
+ return SCARD_E_NO_MEMORY;
+ }
+
+ recvPci.ps->dwProtocol = (PCSC_DWORD)inRecvPci.lps->dwProtocol;
+ recvPci.ps->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes;
+ pbExtraBytes = &(inRecvPci.pb)[sizeof(SCARD_IO_REQUEST)];
+ pcsc_pbExtraBytes = &(recvPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
+ CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes);
+ }
+
+ status = g_PCSC.pfnSCardTransmit(hCard, sendPci.ps, pbSendBuffer, pcsc_cbSendLength, recvPci.ps,
+ pbRecvBuffer, &pcsc_cbRecvLength);
+
+ *pcbRecvLength = (DWORD)pcsc_cbRecvLength;
+
+ if (inSendPci.lpcs)
+ free(sendPci.ps); /* pcsc_pioSendPci is dynamically allocated only when pioSendPci is
+ non null */
+
+ if (inRecvPci.lps)
+ {
+ cbExtraBytes = inRecvPci.lps->cbPciLength - sizeof(SCARD_IO_REQUEST);
+ pbExtraBytes = &(inRecvPci.pb)[sizeof(SCARD_IO_REQUEST)];
+ pcsc_pbExtraBytes = &(recvPci.pb)[sizeof(PCSC_SCARD_IO_REQUEST)];
+ CopyMemory(pbExtraBytes, pcsc_pbExtraBytes, cbExtraBytes); /* copy extra bytes */
+ free(recvPci.ps); /* pcsc_pioRecvPci is dynamically allocated only when pioRecvPci is
+ non null */
+ }
+
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardGetTransmitCount(SCARDHANDLE hCard, LPDWORD pcTransmitCount)
+{
+ WINPR_UNUSED(pcTransmitCount);
+ PCSC_SCARDHANDLE* pCard = NULL;
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID lpInBuffer,
+ DWORD cbInBufferSize, LPVOID lpOutBuffer,
+ DWORD cbOutBufferSize, LPDWORD lpBytesReturned)
+{
+ DWORD IoCtlFunction = 0;
+ DWORD IoCtlDeviceType = 0;
+ BOOL getFeatureRequest = FALSE;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_DWORD pcsc_dwControlCode = 0;
+ PCSC_DWORD pcsc_cbInBufferSize = (PCSC_DWORD)cbInBufferSize;
+ PCSC_DWORD pcsc_cbOutBufferSize = (PCSC_DWORD)cbOutBufferSize;
+ PCSC_DWORD pcsc_BytesReturned = 0;
+
+ if (!g_PCSC.pfnSCardControl)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardControl");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ /**
+ * PCSCv2 Part 10:
+ * http://www.pcscworkgroup.com/specifications/files/pcsc10_v2.02.09.pdf
+ *
+ * Smart Card Driver IOCTLs:
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548988/
+ *
+ * Converting Windows Feature Request IOCTL code to the pcsc-lite control code:
+ * http://musclecard.996296.n3.nabble.com/Converting-Windows-Feature-Request-IOCTL-code-to-the-pcsc-lite-control-code-td4906.html
+ */
+ IoCtlFunction = FUNCTION_FROM_CTL_CODE(dwControlCode);
+ IoCtlDeviceType = DEVICE_TYPE_FROM_CTL_CODE(dwControlCode);
+
+ if (dwControlCode == IOCTL_SMARTCARD_GET_FEATURE_REQUEST)
+ getFeatureRequest = TRUE;
+
+ if (IoCtlDeviceType == FILE_DEVICE_SMARTCARD)
+ dwControlCode = PCSC_SCARD_CTL_CODE(IoCtlFunction);
+
+ pcsc_dwControlCode = (PCSC_DWORD)dwControlCode;
+ status = g_PCSC.pfnSCardControl(hCard, pcsc_dwControlCode, lpInBuffer, pcsc_cbInBufferSize,
+ lpOutBuffer, pcsc_cbOutBufferSize, &pcsc_BytesReturned);
+
+ *lpBytesReturned = (DWORD)pcsc_BytesReturned;
+
+ if (getFeatureRequest)
+ {
+ UINT32 count = 0;
+ PCSC_TLV_STRUCTURE* tlv = (PCSC_TLV_STRUCTURE*)lpOutBuffer;
+
+ if ((*lpBytesReturned % sizeof(PCSC_TLV_STRUCTURE)) != 0)
+ return SCARD_E_UNEXPECTED;
+
+ count = *lpBytesReturned / sizeof(PCSC_TLV_STRUCTURE);
+
+ for (DWORD index = 0; index < count; index++)
+ {
+ if (tlv[index].length != 4)
+ return SCARD_E_UNEXPECTED;
+ }
+ }
+
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardGetAttrib_Internal(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
+ LPDWORD pcbAttrLen)
+{
+ SCARDCONTEXT hContext = 0;
+ BOOL pcbAttrLenAlloc = FALSE;
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
+ PCSC_DWORD pcsc_cbAttrLen = 0;
+
+ if (!g_PCSC.pfnSCardGetAttrib)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardGetAttrib");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ hContext = PCSC_GetCardContextFromHandle(hCard);
+
+ if (!hContext)
+ return SCARD_E_INVALID_HANDLE;
+
+ if (!pcbAttrLen)
+ return SCARD_E_INVALID_PARAMETER;
+
+ if (*pcbAttrLen == SCARD_AUTOALLOCATE)
+ {
+ if (!pbAttr)
+ return SCARD_E_INVALID_PARAMETER;
+ pcbAttrLenAlloc = TRUE;
+ }
+
+ pcsc_cbAttrLen = pcbAttrLenAlloc ? PCSC_SCARD_AUTOALLOCATE : (PCSC_DWORD)*pcbAttrLen;
+
+ if (pcbAttrLenAlloc && !g_SCardAutoAllocate)
+ {
+ pcsc_cbAttrLen = 0;
+ status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, NULL, &pcsc_cbAttrLen);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ BYTE* tmp = (BYTE*)calloc(1, pcsc_cbAttrLen);
+
+ if (!tmp)
+ return SCARD_E_NO_MEMORY;
+
+ status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, tmp, &pcsc_cbAttrLen);
+
+ if (status != SCARD_S_SUCCESS)
+ free(tmp);
+ else
+ PCSC_AddMemoryBlock(hContext, tmp);
+ *(BYTE**)pbAttr = tmp;
+ }
+ }
+ else
+ {
+ status = g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, pbAttr, &pcsc_cbAttrLen);
+ }
+
+ if (status == SCARD_S_SUCCESS)
+ *pcbAttrLen = (DWORD)pcsc_cbAttrLen;
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardGetAttrib_FriendlyName(SCARDHANDLE hCard, DWORD dwAttrId,
+ LPBYTE pbAttr, LPDWORD pcbAttrLen)
+{
+ size_t length = 0;
+ char* namePCSC = NULL;
+ char* pbAttrA = NULL;
+ DWORD cbAttrLen = 0;
+ WCHAR* pbAttrW = NULL;
+ SCARDCONTEXT hContext = 0;
+ LONG status = SCARD_S_SUCCESS;
+
+ hContext = PCSC_GetCardContextFromHandle(hCard);
+
+ if (!hContext)
+ return SCARD_E_INVALID_HANDLE;
+
+ if (!pcbAttrLen)
+ return SCARD_E_INVALID_PARAMETER;
+ cbAttrLen = *pcbAttrLen;
+ *pcbAttrLen = SCARD_AUTOALLOCATE;
+ status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
+ (LPBYTE)&pbAttrA, pcbAttrLen);
+
+ if (status != SCARD_S_SUCCESS)
+ {
+ *pcbAttrLen = SCARD_AUTOALLOCATE;
+ status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
+ (LPBYTE)&pbAttrW, pcbAttrLen);
+
+ if (status != SCARD_S_SUCCESS)
+ return status;
+
+ namePCSC = ConvertMszWCharNToUtf8Alloc(pbAttrW, *pcbAttrLen, NULL);
+ PCSC_SCardFreeMemory_Internal(hContext, pbAttrW);
+ }
+ else
+ {
+ namePCSC = _strdup(pbAttrA);
+
+ if (!namePCSC)
+ return SCARD_E_NO_MEMORY;
+
+ PCSC_SCardFreeMemory_Internal(hContext, pbAttrA);
+ }
+
+ length = strlen(namePCSC);
+
+ if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W)
+ {
+ size_t size = 0;
+ WCHAR* friendlyNameW = ConvertUtf8ToWCharAlloc(namePCSC, &size);
+ /* length here includes null terminator */
+
+ if (!friendlyNameW)
+ status = SCARD_E_NO_MEMORY;
+ else
+ {
+ length = size;
+
+ if (cbAttrLen == SCARD_AUTOALLOCATE)
+ {
+ WINPR_ASSERT(length <= UINT32_MAX / sizeof(WCHAR));
+ *(WCHAR**)pbAttr = friendlyNameW;
+ *pcbAttrLen = (UINT32)length * sizeof(WCHAR);
+ PCSC_AddMemoryBlock(hContext, friendlyNameW);
+ }
+ else
+ {
+ if ((length * 2) > cbAttrLen)
+ status = SCARD_E_INSUFFICIENT_BUFFER;
+ else
+ {
+ WINPR_ASSERT(length <= UINT32_MAX / sizeof(WCHAR));
+ CopyMemory(pbAttr, (BYTE*)friendlyNameW, (length * sizeof(WCHAR)));
+ *pcbAttrLen = (UINT32)length * sizeof(WCHAR);
+ }
+ free(friendlyNameW);
+ }
+ }
+ free(namePCSC);
+ }
+ else
+ {
+ if (cbAttrLen == SCARD_AUTOALLOCATE)
+ {
+ *(CHAR**)pbAttr = namePCSC;
+ WINPR_ASSERT(length <= UINT32_MAX);
+ *pcbAttrLen = (UINT32)length;
+ PCSC_AddMemoryBlock(hContext, namePCSC);
+ }
+ else
+ {
+ if ((length + 1) > cbAttrLen)
+ status = SCARD_E_INSUFFICIENT_BUFFER;
+ else
+ {
+ CopyMemory(pbAttr, namePCSC, length + 1);
+ WINPR_ASSERT(length <= UINT32_MAX);
+ *pcbAttrLen = (UINT32)length;
+ }
+ free(namePCSC);
+ }
+ }
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
+ LPDWORD pcbAttrLen)
+{
+ DWORD cbAttrLen = 0;
+ SCARDCONTEXT hContext = 0;
+ BOOL pcbAttrLenAlloc = FALSE;
+ LONG status = SCARD_S_SUCCESS;
+
+ if (NULL == pcbAttrLen)
+ return SCARD_E_INVALID_PARAMETER;
+
+ cbAttrLen = *pcbAttrLen;
+
+ if (*pcbAttrLen == SCARD_AUTOALLOCATE)
+ {
+ if (NULL == pbAttr)
+ return SCARD_E_INVALID_PARAMETER;
+
+ pcbAttrLenAlloc = TRUE;
+ *(BYTE**)pbAttr = NULL;
+ }
+ else
+ {
+ /**
+ * pcsc-lite returns SCARD_E_INSUFFICIENT_BUFFER if the given
+ * buffer size is larger than PCSC_MAX_BUFFER_SIZE (264)
+ */
+ if (*pcbAttrLen > PCSC_MAX_BUFFER_SIZE)
+ *pcbAttrLen = PCSC_MAX_BUFFER_SIZE;
+ }
+
+ hContext = PCSC_GetCardContextFromHandle(hCard);
+
+ if (!hContext)
+ return SCARD_E_INVALID_HANDLE;
+
+ if ((dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A) ||
+ (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W))
+ {
+ status = PCSC_SCardGetAttrib_FriendlyName(hCard, dwAttrId, pbAttr, pcbAttrLen);
+ return status;
+ }
+
+ status = PCSC_SCardGetAttrib_Internal(hCard, dwAttrId, pbAttr, pcbAttrLen);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ if (dwAttrId == SCARD_ATTR_VENDOR_NAME)
+ {
+ if (pbAttr)
+ {
+ const char* vendorName = NULL;
+
+ /**
+ * pcsc-lite adds a null terminator to the vendor name,
+ * while WinSCard doesn't. Strip the null terminator.
+ */
+
+ if (pcbAttrLenAlloc)
+ vendorName = (char*)*(BYTE**)pbAttr;
+ else
+ vendorName = (char*)pbAttr;
+
+ if (vendorName)
+ {
+ size_t len = strnlen(vendorName, *pcbAttrLen);
+ WINPR_ASSERT(len <= UINT32_MAX);
+ *pcbAttrLen = (DWORD)len;
+ }
+ else
+ *pcbAttrLen = 0;
+ }
+ }
+ }
+ else
+ {
+
+ if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
+ {
+ if (!pcbAttrLenAlloc)
+ {
+ PCSC_DWORD dwState = 0;
+ PCSC_DWORD cbAtrLen = 0;
+ PCSC_DWORD dwProtocol = 0;
+ PCSC_DWORD cchReaderLen = 0;
+ status = (LONG)g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState,
+ &dwProtocol, NULL, &cbAtrLen);
+
+ if (status == SCARD_S_SUCCESS)
+ {
+ if (cbAttrLen < sizeof(DWORD))
+ return SCARD_E_INSUFFICIENT_BUFFER;
+
+ *(DWORD*)pbAttr = PCSC_ConvertProtocolsToWinSCard(dwProtocol);
+ *pcbAttrLen = sizeof(DWORD);
+ }
+ }
+ }
+ else if (dwAttrId == SCARD_ATTR_CHANNEL_ID)
+ {
+ if (!pcbAttrLenAlloc)
+ {
+ UINT32 channelType = 0x20; /* USB */
+ UINT32 channelNumber = 0;
+
+ if (cbAttrLen < sizeof(DWORD))
+ return SCARD_E_INSUFFICIENT_BUFFER;
+
+ status = SCARD_S_SUCCESS;
+ *(DWORD*)pbAttr = (channelType << 16u) | channelNumber;
+ *pcbAttrLen = sizeof(DWORD);
+ }
+ }
+ else if (dwAttrId == SCARD_ATTR_VENDOR_IFD_TYPE)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_DEFAULT_CLK)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_DEFAULT_DATA_RATE)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_MAX_CLK)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_MAX_DATA_RATE)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_MAX_IFSD)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CHARACTERISTICS)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_A)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_DEVICE_UNIT)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_POWER_MGMT_SUPPORT)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_CLK)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_F)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_D)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_N)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_CWT)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_BWT)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_IFSC)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_EBC_ENCODING)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_CURRENT_IFSD)
+ {
+ }
+ else if (dwAttrId == SCARD_ATTR_ICC_TYPE_PER_ATR)
+ {
+ }
+ }
+
+ return status;
+}
+
+static LONG WINAPI PCSC_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
+ DWORD cbAttrLen)
+{
+ PCSC_LONG status = SCARD_S_SUCCESS;
+ PCSC_SCARDHANDLE* pCard = NULL;
+ PCSC_DWORD pcsc_dwAttrId = (PCSC_DWORD)dwAttrId;
+ PCSC_DWORD pcsc_cbAttrLen = (PCSC_DWORD)cbAttrLen;
+
+ if (!g_PCSC.pfnSCardSetAttrib)
+ return PCSC_SCard_LogError("g_PCSC.pfnSCardSetAttrib");
+
+ pCard = PCSC_GetCardHandleData(hCard);
+
+ if (!pCard)
+ return SCARD_E_INVALID_VALUE;
+
+ PCSC_WaitForCardAccess(0, hCard, pCard->shared);
+ status = g_PCSC.pfnSCardSetAttrib(hCard, pcsc_dwAttrId, pbAttr, pcsc_cbAttrLen);
+ return PCSC_MapErrorCodeToWinSCard(status);
+}
+
+static LONG WINAPI PCSC_SCardUIDlgSelectCardA(LPOPENCARDNAMEA_EX pDlgStruc)
+{
+ WINPR_UNUSED(pDlgStruc);
+
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardUIDlgSelectCardW(LPOPENCARDNAMEW_EX pDlgStruc)
+{
+ WINPR_UNUSED(pDlgStruc);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_GetOpenCardNameA(LPOPENCARDNAMEA pDlgStruc)
+{
+ WINPR_UNUSED(pDlgStruc);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_GetOpenCardNameW(LPOPENCARDNAMEW pDlgStruc)
+{
+ WINPR_UNUSED(pDlgStruc);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardDlgExtendedError(void)
+{
+
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static char* card_id_and_name_a(const UUID* CardIdentifier, LPCSTR LookupName)
+{
+ WINPR_ASSERT(CardIdentifier);
+ WINPR_ASSERT(LookupName);
+
+ size_t len = strlen(LookupName) + 34;
+ char* id = malloc(len);
+ if (!id)
+ return NULL;
+
+ snprintf(id, len, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X\\%s", CardIdentifier->Data1,
+ CardIdentifier->Data2, CardIdentifier->Data3, CardIdentifier->Data4[0],
+ CardIdentifier->Data4[1], CardIdentifier->Data4[2], CardIdentifier->Data4[3],
+ CardIdentifier->Data4[4], CardIdentifier->Data4[5], CardIdentifier->Data4[6],
+ CardIdentifier->Data4[7], LookupName);
+ return id;
+}
+
+static char* card_id_and_name_w(const UUID* CardIdentifier, LPCWSTR LookupName)
+{
+ char* res = NULL;
+ char* tmp = ConvertWCharToUtf8Alloc(LookupName, NULL);
+ if (!tmp)
+ return NULL;
+ res = card_id_and_name_a(CardIdentifier, tmp);
+ free(tmp);
+ return res;
+}
+
+static LONG WINAPI PCSC_SCardReadCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ PCSC_CACHE_ITEM* data = NULL;
+ PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
+ char* id = card_id_and_name_a(CardIdentifier, LookupName);
+
+ data = HashTable_GetItemValue(ctx->cache, id);
+ free(id);
+ if (!data)
+ {
+ *DataLen = 0;
+ return SCARD_W_CACHE_ITEM_NOT_FOUND;
+ }
+
+ if (FreshnessCounter != data->freshness)
+ {
+ *DataLen = 0;
+ return SCARD_W_CACHE_ITEM_STALE;
+ }
+
+ if (*DataLen == SCARD_AUTOALLOCATE)
+ {
+ BYTE* mem = calloc(1, data->len);
+ if (!mem)
+ return SCARD_E_NO_MEMORY;
+
+ if (!PCSC_AddMemoryBlock(hContext, mem))
+ {
+ free(mem);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ memcpy(mem, data->data, data->len);
+ *(BYTE**)Data = mem;
+ }
+ else
+ memcpy(Data, data->data, data->len);
+ *DataLen = data->len;
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardReadCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD* DataLen)
+{
+ PCSC_CACHE_ITEM* data = NULL;
+ PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
+ char* id = card_id_and_name_w(CardIdentifier, LookupName);
+
+ data = HashTable_GetItemValue(ctx->cache, id);
+ free(id);
+
+ if (!data)
+ {
+ *DataLen = 0;
+ return SCARD_W_CACHE_ITEM_NOT_FOUND;
+ }
+
+ if (FreshnessCounter != data->freshness)
+ {
+ *DataLen = 0;
+ return SCARD_W_CACHE_ITEM_STALE;
+ }
+
+ if (*DataLen == SCARD_AUTOALLOCATE)
+ {
+ BYTE* mem = calloc(1, data->len);
+ if (!mem)
+ return SCARD_E_NO_MEMORY;
+
+ if (!PCSC_AddMemoryBlock(hContext, mem))
+ {
+ free(mem);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ memcpy(mem, data->data, data->len);
+ *(BYTE**)Data = mem;
+ }
+ else
+ memcpy(Data, data->data, data->len);
+ *DataLen = data->len;
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardWriteCacheA(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ PCSC_CACHE_ITEM* data = NULL;
+ PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
+ char* id = NULL;
+
+ if (!ctx)
+ return SCARD_E_FILE_NOT_FOUND;
+
+ id = card_id_and_name_a(CardIdentifier, LookupName);
+
+ if (!id)
+ return SCARD_E_NO_MEMORY;
+
+ data = malloc(sizeof(PCSC_CACHE_ITEM));
+ if (!data)
+ {
+ free(id);
+ return SCARD_E_NO_MEMORY;
+ }
+ data->data = calloc(DataLen, 1);
+ if (!data->data)
+ {
+ free(id);
+ free(data);
+ return SCARD_E_NO_MEMORY;
+ }
+ data->len = DataLen;
+ data->freshness = FreshnessCounter;
+ memcpy(data->data, Data, data->len);
+
+ HashTable_Remove(ctx->cache, id);
+ const BOOL rc = HashTable_Insert(ctx->cache, id, data);
+ free(id);
+
+ if (!rc)
+ {
+ pcsc_cache_item_free(data);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardWriteCacheW(SCARDCONTEXT hContext, UUID* CardIdentifier,
+ DWORD FreshnessCounter, LPWSTR LookupName, PBYTE Data,
+ DWORD DataLen)
+{
+ PCSC_CACHE_ITEM* data = NULL;
+ PCSC_SCARDCONTEXT* ctx = PCSC_GetCardContextData(hContext);
+ char* id = NULL;
+ if (!ctx)
+ return SCARD_E_FILE_NOT_FOUND;
+
+ id = card_id_and_name_w(CardIdentifier, LookupName);
+
+ if (!id)
+ return SCARD_E_NO_MEMORY;
+
+ data = malloc(sizeof(PCSC_CACHE_ITEM));
+ if (!data)
+ {
+ free(id);
+ return SCARD_E_NO_MEMORY;
+ }
+ data->data = malloc(DataLen);
+ if (!data->data)
+ {
+ free(id);
+ free(data);
+ return SCARD_E_NO_MEMORY;
+ }
+ data->len = DataLen;
+ data->freshness = FreshnessCounter;
+ memcpy(data->data, Data, data->len);
+
+ HashTable_Remove(ctx->cache, id);
+ const BOOL rc = HashTable_Insert(ctx->cache, id, data);
+ free(id);
+
+ if (!rc)
+ {
+ pcsc_cache_item_free(data);
+ return SCARD_E_NO_MEMORY;
+ }
+
+ // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns data
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardGetReaderIconA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(pbIcon);
+ WINPR_UNUSED(pcbIcon);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetReaderIconW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPBYTE pbIcon, LPDWORD pcbIcon)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(pbIcon);
+ WINPR_UNUSED(pcbIcon);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetDeviceTypeIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(pdwDeviceTypeId);
+ if (pdwDeviceTypeId)
+ *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardGetDeviceTypeIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPDWORD pdwDeviceTypeId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ if (pdwDeviceTypeId)
+ *pdwDeviceTypeId = SCARD_READER_TYPE_USB;
+ return SCARD_S_SUCCESS;
+}
+
+static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdA(SCARDCONTEXT hContext, LPCSTR szReaderName,
+ LPSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szDeviceInstanceId);
+ WINPR_UNUSED(pcchDeviceInstanceId);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardGetReaderDeviceInstanceIdW(SCARDCONTEXT hContext, LPCWSTR szReaderName,
+ LPWSTR szDeviceInstanceId,
+ LPDWORD pcchDeviceInstanceId)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szReaderName);
+ WINPR_UNUSED(szDeviceInstanceId);
+ WINPR_UNUSED(pcchDeviceInstanceId);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdA(SCARDCONTEXT hContext,
+ LPCSTR szDeviceInstanceId,
+ LPSTR mszReaders, LPDWORD pcchReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szDeviceInstanceId);
+ WINPR_UNUSED(mszReaders);
+ WINPR_UNUSED(pcchReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardListReadersWithDeviceInstanceIdW(SCARDCONTEXT hContext,
+ LPCWSTR szDeviceInstanceId,
+ LPWSTR mszReaders,
+ LPDWORD pcchReaders)
+{
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(szDeviceInstanceId);
+ WINPR_UNUSED(mszReaders);
+ WINPR_UNUSED(pcchReaders);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG WINAPI PCSC_SCardAudit(SCARDCONTEXT hContext, DWORD dwEvent)
+{
+
+ WINPR_UNUSED(hContext);
+ WINPR_UNUSED(dwEvent);
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+#ifdef __MACOSX__
+unsigned int determineMacOSXVersion(void)
+{
+ int mib[2];
+ size_t len = 0;
+ char* kernelVersion = NULL;
+ char* tok = NULL;
+ unsigned int version = 0;
+ long majorVersion = 0;
+ long minorVersion = 0;
+ long patchVersion = 0;
+ int count = 0;
+ char* context = NULL;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELEASE;
+
+ if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
+ return 0;
+
+ kernelVersion = calloc(len, sizeof(char));
+
+ if (!kernelVersion)
+ return 0;
+
+ if (sysctl(mib, 2, kernelVersion, &len, NULL, 0) != 0)
+ {
+ free(kernelVersion);
+ return 0;
+ }
+
+ tok = strtok_s(kernelVersion, ".", &context);
+ errno = 0;
+
+ while (tok)
+ {
+ switch (count)
+ {
+ case 0:
+ majorVersion = strtol(tok, NULL, 0);
+
+ if (errno != 0)
+ goto fail;
+
+ break;
+
+ case 1:
+ minorVersion = strtol(tok, NULL, 0);
+
+ if (errno != 0)
+ goto fail;
+
+ break;
+
+ case 2:
+ patchVersion = strtol(tok, NULL, 0);
+
+ if (errno != 0)
+ goto fail;
+
+ break;
+ }
+
+ tok = strtok_s(NULL, ".", &context);
+ count++;
+ }
+
+ /**
+ * Source : http://en.wikipedia.org/wiki/Darwin_(operating_system)
+ **/
+ if (majorVersion < 5)
+ {
+ if (minorVersion < 4)
+ version = 0x10000000;
+ else
+ version = 0x10010000;
+ }
+ else
+ {
+ switch (majorVersion)
+ {
+ case 5:
+ version = 0x10010000;
+ break;
+
+ case 6:
+ version = 0x10020000;
+ break;
+
+ case 7:
+ version = 0x10030000;
+ break;
+
+ case 8:
+ version = 0x10040000;
+ break;
+
+ case 9:
+ version = 0x10050000;
+ break;
+
+ case 10:
+ version = 0x10060000;
+ break;
+
+ case 11:
+ version = 0x10070000;
+ break;
+
+ case 12:
+ version = 0x10080000;
+ break;
+
+ case 13:
+ version = 0x10090000;
+ break;
+
+ default:
+ version = 0x10100000;
+ break;
+ }
+
+ version |= (minorVersion << 8) | (patchVersion);
+ }
+
+fail:
+ free(kernelVersion);
+ return version;
+}
+#endif
+
+static const SCardApiFunctionTable PCSC_SCardApiFunctionTable = {
+ 0, /* dwVersion */
+ 0, /* dwFlags */
+
+ PCSC_SCardEstablishContext, /* SCardEstablishContext */
+ PCSC_SCardReleaseContext, /* SCardReleaseContext */
+ PCSC_SCardIsValidContext, /* SCardIsValidContext */
+ PCSC_SCardListReaderGroupsA, /* SCardListReaderGroupsA */
+ PCSC_SCardListReaderGroupsW, /* SCardListReaderGroupsW */
+ PCSC_SCardListReadersA, /* SCardListReadersA */
+ PCSC_SCardListReadersW, /* SCardListReadersW */
+ PCSC_SCardListCardsA, /* SCardListCardsA */
+ PCSC_SCardListCardsW, /* SCardListCardsW */
+ PCSC_SCardListInterfacesA, /* SCardListInterfacesA */
+ PCSC_SCardListInterfacesW, /* SCardListInterfacesW */
+ PCSC_SCardGetProviderIdA, /* SCardGetProviderIdA */
+ PCSC_SCardGetProviderIdW, /* SCardGetProviderIdW */
+ PCSC_SCardGetCardTypeProviderNameA, /* SCardGetCardTypeProviderNameA */
+ PCSC_SCardGetCardTypeProviderNameW, /* SCardGetCardTypeProviderNameW */
+ PCSC_SCardIntroduceReaderGroupA, /* SCardIntroduceReaderGroupA */
+ PCSC_SCardIntroduceReaderGroupW, /* SCardIntroduceReaderGroupW */
+ PCSC_SCardForgetReaderGroupA, /* SCardForgetReaderGroupA */
+ PCSC_SCardForgetReaderGroupW, /* SCardForgetReaderGroupW */
+ PCSC_SCardIntroduceReaderA, /* SCardIntroduceReaderA */
+ PCSC_SCardIntroduceReaderW, /* SCardIntroduceReaderW */
+ PCSC_SCardForgetReaderA, /* SCardForgetReaderA */
+ PCSC_SCardForgetReaderW, /* SCardForgetReaderW */
+ PCSC_SCardAddReaderToGroupA, /* SCardAddReaderToGroupA */
+ PCSC_SCardAddReaderToGroupW, /* SCardAddReaderToGroupW */
+ PCSC_SCardRemoveReaderFromGroupA, /* SCardRemoveReaderFromGroupA */
+ PCSC_SCardRemoveReaderFromGroupW, /* SCardRemoveReaderFromGroupW */
+ PCSC_SCardIntroduceCardTypeA, /* SCardIntroduceCardTypeA */
+ PCSC_SCardIntroduceCardTypeW, /* SCardIntroduceCardTypeW */
+ PCSC_SCardSetCardTypeProviderNameA, /* SCardSetCardTypeProviderNameA */
+ PCSC_SCardSetCardTypeProviderNameW, /* SCardSetCardTypeProviderNameW */
+ PCSC_SCardForgetCardTypeA, /* SCardForgetCardTypeA */
+ PCSC_SCardForgetCardTypeW, /* SCardForgetCardTypeW */
+ PCSC_SCardFreeMemory, /* SCardFreeMemory */
+ PCSC_SCardAccessStartedEvent, /* SCardAccessStartedEvent */
+ PCSC_SCardReleaseStartedEvent, /* SCardReleaseStartedEvent */
+ PCSC_SCardLocateCardsA, /* SCardLocateCardsA */
+ PCSC_SCardLocateCardsW, /* SCardLocateCardsW */
+ PCSC_SCardLocateCardsByATRA, /* SCardLocateCardsByATRA */
+ PCSC_SCardLocateCardsByATRW, /* SCardLocateCardsByATRW */
+ PCSC_SCardGetStatusChangeA, /* SCardGetStatusChangeA */
+ PCSC_SCardGetStatusChangeW, /* SCardGetStatusChangeW */
+ PCSC_SCardCancel, /* SCardCancel */
+ PCSC_SCardConnectA, /* SCardConnectA */
+ PCSC_SCardConnectW, /* SCardConnectW */
+ PCSC_SCardReconnect, /* SCardReconnect */
+ PCSC_SCardDisconnect, /* SCardDisconnect */
+ PCSC_SCardBeginTransaction, /* SCardBeginTransaction */
+ PCSC_SCardEndTransaction, /* SCardEndTransaction */
+ PCSC_SCardCancelTransaction, /* SCardCancelTransaction */
+ PCSC_SCardState, /* SCardState */
+ PCSC_SCardStatusA, /* SCardStatusA */
+ PCSC_SCardStatusW, /* SCardStatusW */
+ PCSC_SCardTransmit, /* SCardTransmit */
+ PCSC_SCardGetTransmitCount, /* SCardGetTransmitCount */
+ PCSC_SCardControl, /* SCardControl */
+ PCSC_SCardGetAttrib, /* SCardGetAttrib */
+ PCSC_SCardSetAttrib, /* SCardSetAttrib */
+ PCSC_SCardUIDlgSelectCardA, /* SCardUIDlgSelectCardA */
+ PCSC_SCardUIDlgSelectCardW, /* SCardUIDlgSelectCardW */
+ PCSC_GetOpenCardNameA, /* GetOpenCardNameA */
+ PCSC_GetOpenCardNameW, /* GetOpenCardNameW */
+ PCSC_SCardDlgExtendedError, /* SCardDlgExtendedError */
+ PCSC_SCardReadCacheA, /* SCardReadCacheA */
+ PCSC_SCardReadCacheW, /* SCardReadCacheW */
+ PCSC_SCardWriteCacheA, /* SCardWriteCacheA */
+ PCSC_SCardWriteCacheW, /* SCardWriteCacheW */
+ PCSC_SCardGetReaderIconA, /* SCardGetReaderIconA */
+ PCSC_SCardGetReaderIconW, /* SCardGetReaderIconW */
+ PCSC_SCardGetDeviceTypeIdA, /* SCardGetDeviceTypeIdA */
+ PCSC_SCardGetDeviceTypeIdW, /* SCardGetDeviceTypeIdW */
+ PCSC_SCardGetReaderDeviceInstanceIdA, /* SCardGetReaderDeviceInstanceIdA */
+ PCSC_SCardGetReaderDeviceInstanceIdW, /* SCardGetReaderDeviceInstanceIdW */
+ PCSC_SCardListReadersWithDeviceInstanceIdA, /* SCardListReadersWithDeviceInstanceIdA */
+ PCSC_SCardListReadersWithDeviceInstanceIdW, /* SCardListReadersWithDeviceInstanceIdW */
+ PCSC_SCardAudit /* SCardAudit */
+};
+
+const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void)
+{
+ return &PCSC_SCardApiFunctionTable;
+}
+
+int PCSC_InitializeSCardApi(void)
+{
+ /* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
+ SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
+#ifdef __MACOSX__
+ g_PCSCModule = LoadLibraryX("/System/Library/Frameworks/PCSC.framework/PCSC");
+ OSXVersion = determineMacOSXVersion();
+
+ if (OSXVersion == 0)
+ return -1;
+
+#else
+ g_PCSCModule = LoadLibraryA("libpcsclite.so.1");
+
+ if (!g_PCSCModule)
+ g_PCSCModule = LoadLibraryA("libpcsclite.so");
+
+#endif
+
+ if (!g_PCSCModule)
+ return -1;
+
+ /* symbols defined in winpr/smartcard.h, might pose an issue with the GetProcAddress macro
+ * below. therefore undefine them here */
+#undef SCardListReaderGroups
+#undef SCardListReaders
+#undef SCardListCards
+#undef SCardListInterfaces
+#undef SCardGetProviderId
+#undef SCardGetCardTypeProviderName
+#undef SCardIntroduceReaderGroup
+#undef SCardForgetReaderGroup
+#undef SCardIntroduceReader
+#undef SCardForgetReader
+#undef SCardAddReaderToGroup
+#undef SCardRemoveReaderFromGroup
+#undef SCardIntroduceCardType
+#undef SCardSetCardTypeProviderName
+#undef SCardForgetCardType
+#undef SCardLocateCards
+#undef SCardLocateCardsByATR
+#undef SCardGetStatusChange
+#undef SCardConnect
+#undef SCardStatus
+#undef SCardUIDlgSelectCard
+#undef GetOpenCardName
+#undef SCardReadCache
+#undef SCardWriteCache
+#undef SCardGetReaderIcon
+#undef SCardGetDeviceTypeId
+#undef SCardGetReaderDeviceInstanceId
+#undef SCardListReadersWithDeviceInstanceId
+
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEstablishContext);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReleaseContext);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardIsValidContext);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardConnect);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardReconnect);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardDisconnect);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardBeginTransaction);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardEndTransaction);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardStatus);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetStatusChange);
+
+#ifdef __MACOSX__
+
+ if (OSXVersion >= 0x10050600)
+ {
+ WINSCARD_LOAD_PROC_EX(g_PCSCModule, g_PCSC, SCardControl, SCardControl132);
+ }
+ else
+ {
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
+ }
+#else
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardControl);
+#endif
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardTransmit);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaderGroups);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardListReaders);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardCancel);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardGetAttrib);
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardSetAttrib);
+ g_PCSC.pfnSCardFreeMemory = NULL;
+#ifndef __APPLE__
+ WINSCARD_LOAD_PROC(g_PCSCModule, g_PCSC, SCardFreeMemory);
+#endif
+
+ if (g_PCSC.pfnSCardFreeMemory)
+ g_SCardAutoAllocate = TRUE;
+
+#ifdef DISABLE_PCSC_SCARD_AUTOALLOCATE
+ g_PCSC.pfnSCardFreeMemory = NULL;
+ g_SCardAutoAllocate = FALSE;
+#endif
+#ifdef __APPLE__
+ g_PnP_Notification = FALSE;
+#endif
+ return 1;
+}
+
+#endif
diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.h b/winpr/libwinpr/smartcard/smartcard_pcsc.h
new file mode 100644
index 0000000..9ff822d
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_pcsc.h
@@ -0,0 +1,175 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2020 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2020 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_SMARTCARD_PCSC_PRIVATE_H
+#define WINPR_SMARTCARD_PCSC_PRIVATE_H
+
+#ifndef _WIN32
+
+#include <winpr/platform.h>
+#include <winpr/smartcard.h>
+
+/**
+ * On Windows, DWORD and ULONG are defined to unsigned long.
+ * However, 64-bit Windows uses the LLP64 model which defines
+ * unsigned long as a 4-byte type, while most non-Windows
+ * systems use the LP64 model where unsigned long is 8 bytes.
+ *
+ * WinPR correctly defines DWORD and ULONG to be 4-byte types
+ * regardless of LLP64/LP64, but this has the side effect of
+ * breaking compatibility with the broken pcsc-lite types.
+ *
+ * To make matters worse, pcsc-lite correctly defines
+ * the data types on OS X, but not on other platforms.
+ */
+
+#ifdef __APPLE__
+
+#include <stdint.h>
+
+#ifndef BYTE
+typedef uint8_t PCSC_BYTE;
+#endif
+typedef uint8_t PCSC_UCHAR;
+typedef PCSC_UCHAR* PCSC_PUCHAR;
+typedef uint16_t PCSC_USHORT;
+
+#ifndef __COREFOUNDATION_CFPLUGINCOM__
+typedef uint32_t PCSC_ULONG;
+typedef void* PCSC_LPVOID;
+typedef int16_t PCSC_BOOL;
+#endif
+
+typedef PCSC_ULONG* PCSC_PULONG;
+typedef const void* PCSC_LPCVOID;
+typedef uint32_t PCSC_DWORD;
+typedef PCSC_DWORD* PCSC_PDWORD;
+typedef uint16_t PCSC_WORD;
+typedef int32_t PCSC_LONG;
+typedef const char* PCSC_LPCSTR;
+typedef const PCSC_BYTE* PCSC_LPCBYTE;
+typedef PCSC_BYTE* PCSC_LPBYTE;
+typedef PCSC_DWORD* PCSC_LPDWORD;
+typedef char* PCSC_LPSTR;
+
+#else
+
+#ifndef BYTE
+typedef unsigned char PCSC_BYTE;
+#endif
+typedef unsigned char PCSC_UCHAR;
+typedef PCSC_UCHAR* PCSC_PUCHAR;
+typedef unsigned short PCSC_USHORT;
+
+#ifndef __COREFOUNDATION_CFPLUGINCOM__
+typedef unsigned long PCSC_ULONG;
+typedef void* PCSC_LPVOID;
+#endif
+
+typedef const void* PCSC_LPCVOID;
+typedef unsigned long PCSC_DWORD;
+typedef PCSC_DWORD* PCSC_PDWORD;
+typedef long PCSC_LONG;
+typedef const char* PCSC_LPCSTR;
+typedef const PCSC_BYTE* PCSC_LPCBYTE;
+typedef PCSC_BYTE* PCSC_LPBYTE;
+typedef PCSC_DWORD* PCSC_LPDWORD;
+typedef char* PCSC_LPSTR;
+
+/* these types were deprecated but still used by old drivers and
+ * applications. So just declare and use them. */
+typedef PCSC_LPSTR PCSC_LPTSTR;
+typedef PCSC_LPCSTR PCSC_LPCTSTR;
+
+/* types unused by pcsc-lite */
+typedef short PCSC_BOOL;
+typedef unsigned short PCSC_WORD;
+typedef PCSC_ULONG* PCSC_PULONG;
+
+#endif
+
+#define PCSC_SCARD_UNKNOWN 0x0001
+#define PCSC_SCARD_ABSENT 0x0002
+#define PCSC_SCARD_PRESENT 0x0004
+#define PCSC_SCARD_SWALLOWED 0x0008
+#define PCSC_SCARD_POWERED 0x0010
+#define PCSC_SCARD_NEGOTIABLE 0x0020
+#define PCSC_SCARD_SPECIFIC 0x0040
+
+#define PCSC_SCARD_PROTOCOL_RAW 0x00000004u
+#define PCSC_SCARD_PROTOCOL_T15 0x00000008u
+
+#define PCSC_MAX_BUFFER_SIZE 264
+#define PCSC_MAX_BUFFER_SIZE_EXTENDED (4 + 3 + (1 << 16) + 3 + 2)
+
+#define PCSC_MAX_ATR_SIZE 33
+
+#define PCSC_SCARD_AUTOALLOCATE (PCSC_DWORD)(-1)
+
+#define PCSC_SCARD_CTL_CODE(code) (0x42000000 + (code))
+#define PCSC_CM_IOCTL_GET_FEATURE_REQUEST PCSC_SCARD_CTL_CODE(3400)
+
+/**
+ * pcsc-lite defines SCARD_READERSTATE, SCARD_IO_REQUEST as packed
+ * on Mac OS X only and uses default packing everywhere else.
+ */
+
+#ifdef __APPLE__
+#pragma pack(push, 1)
+#endif
+
+typedef struct
+{
+ LPCSTR szReader;
+ LPVOID pvUserData;
+ PCSC_DWORD dwCurrentState;
+ PCSC_DWORD dwEventState;
+ PCSC_DWORD cbAtr;
+ BYTE rgbAtr[PCSC_MAX_ATR_SIZE]; /* WinSCard: 36, PCSC: 33 */
+} PCSC_SCARD_READERSTATE;
+
+typedef struct
+{
+ PCSC_DWORD dwProtocol;
+ PCSC_DWORD cbPciLength;
+} PCSC_SCARD_IO_REQUEST;
+
+#ifdef __APPLE__
+#pragma pack(pop)
+#endif
+
+#pragma pack(push, 1)
+
+typedef struct
+{
+ BYTE tag;
+ BYTE length;
+ UINT32 value;
+} PCSC_TLV_STRUCTURE;
+
+#pragma pack(pop)
+
+int PCSC_InitializeSCardApi(void);
+const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void);
+
+#endif
+
+#endif /* WINPR_SMARTCARD_PCSC_PRIVATE_H */
diff --git a/winpr/libwinpr/smartcard/smartcard_windows.c b/winpr/libwinpr/smartcard/smartcard_windows.c
new file mode 100644
index 0000000..967a2a0
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_windows.c
@@ -0,0 +1,126 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/library.h>
+#include <winpr/smartcard.h>
+
+#include "smartcard_windows.h"
+
+static HMODULE g_WinSCardModule = NULL;
+
+static SCardApiFunctionTable Windows_SCardApiFunctionTable = {
+ 0, /* dwVersion */
+ 0, /* dwFlags */
+
+ NULL, /* SCardEstablishContext */
+ NULL, /* SCardReleaseContext */
+ NULL, /* SCardIsValidContext */
+ NULL, /* SCardListReaderGroupsA */
+ NULL, /* SCardListReaderGroupsW */
+ NULL, /* SCardListReadersA */
+ NULL, /* SCardListReadersW */
+ NULL, /* SCardListCardsA */
+ NULL, /* SCardListCardsW */
+ NULL, /* SCardListInterfacesA */
+ NULL, /* SCardListInterfacesW */
+ NULL, /* SCardGetProviderIdA */
+ NULL, /* SCardGetProviderIdW */
+ NULL, /* SCardGetCardTypeProviderNameA */
+ NULL, /* SCardGetCardTypeProviderNameW */
+ NULL, /* SCardIntroduceReaderGroupA */
+ NULL, /* SCardIntroduceReaderGroupW */
+ NULL, /* SCardForgetReaderGroupA */
+ NULL, /* SCardForgetReaderGroupW */
+ NULL, /* SCardIntroduceReaderA */
+ NULL, /* SCardIntroduceReaderW */
+ NULL, /* SCardForgetReaderA */
+ NULL, /* SCardForgetReaderW */
+ NULL, /* SCardAddReaderToGroupA */
+ NULL, /* SCardAddReaderToGroupW */
+ NULL, /* SCardRemoveReaderFromGroupA */
+ NULL, /* SCardRemoveReaderFromGroupW */
+ NULL, /* SCardIntroduceCardTypeA */
+ NULL, /* SCardIntroduceCardTypeW */
+ NULL, /* SCardSetCardTypeProviderNameA */
+ NULL, /* SCardSetCardTypeProviderNameW */
+ NULL, /* SCardForgetCardTypeA */
+ NULL, /* SCardForgetCardTypeW */
+ NULL, /* SCardFreeMemory */
+ NULL, /* SCardAccessStartedEvent */
+ NULL, /* SCardReleaseStartedEvent */
+ NULL, /* SCardLocateCardsA */
+ NULL, /* SCardLocateCardsW */
+ NULL, /* SCardLocateCardsByATRA */
+ NULL, /* SCardLocateCardsByATRW */
+ NULL, /* SCardGetStatusChangeA */
+ NULL, /* SCardGetStatusChangeW */
+ NULL, /* SCardCancel */
+ NULL, /* SCardConnectA */
+ NULL, /* SCardConnectW */
+ NULL, /* SCardReconnect */
+ NULL, /* SCardDisconnect */
+ NULL, /* SCardBeginTransaction */
+ NULL, /* SCardEndTransaction */
+ NULL, /* SCardCancelTransaction */
+ NULL, /* SCardState */
+ NULL, /* SCardStatusA */
+ NULL, /* SCardStatusW */
+ NULL, /* SCardTransmit */
+ NULL, /* SCardGetTransmitCount */
+ NULL, /* SCardControl */
+ NULL, /* SCardGetAttrib */
+ NULL, /* SCardSetAttrib */
+ NULL, /* SCardUIDlgSelectCardA */
+ NULL, /* SCardUIDlgSelectCardW */
+ NULL, /* GetOpenCardNameA */
+ NULL, /* GetOpenCardNameW */
+ NULL, /* SCardDlgExtendedError */
+ NULL, /* SCardReadCacheA */
+ NULL, /* SCardReadCacheW */
+ NULL, /* SCardWriteCacheA */
+ NULL, /* SCardWriteCacheW */
+ NULL, /* SCardGetReaderIconA */
+ NULL, /* SCardGetReaderIconW */
+ NULL, /* SCardGetDeviceTypeIdA */
+ NULL, /* SCardGetDeviceTypeIdW */
+ NULL, /* SCardGetReaderDeviceInstanceIdA */
+ NULL, /* SCardGetReaderDeviceInstanceIdW */
+ NULL, /* SCardListReadersWithDeviceInstanceIdA */
+ NULL, /* SCardListReadersWithDeviceInstanceIdW */
+ NULL /* SCardAudit */
+};
+
+const SCardApiFunctionTable* Windows_GetSCardApiFunctionTable(void)
+{
+ return &Windows_SCardApiFunctionTable;
+}
+
+int Windows_InitializeSCardApi(void)
+{
+ g_WinSCardModule = LoadLibraryA("WinSCard.dll");
+
+ if (!g_WinSCardModule)
+ return -1;
+
+ WinSCard_LoadApiTableFunctions(&Windows_SCardApiFunctionTable, g_WinSCardModule);
+ return 1;
+}
diff --git a/winpr/libwinpr/smartcard/smartcard_windows.h b/winpr/libwinpr/smartcard/smartcard_windows.h
new file mode 100644
index 0000000..4df72b0
--- /dev/null
+++ b/winpr/libwinpr/smartcard/smartcard_windows.h
@@ -0,0 +1,28 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Smart Card API
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_SMARTCARD_WINSCARD_PRIVATE_H
+#define WINPR_SMARTCARD_WINSCARD_PRIVATE_H
+
+#include <winpr/smartcard.h>
+
+int Windows_InitializeSCardApi(void);
+const SCardApiFunctionTable* Windows_GetSCardApiFunctionTable(void);
+
+#endif /* WINPR_SMARTCARD_WINSCARD_PRIVATE_H */
diff --git a/winpr/libwinpr/smartcard/test/CMakeLists.txt b/winpr/libwinpr/smartcard/test/CMakeLists.txt
new file mode 100644
index 0000000..4d8e107
--- /dev/null
+++ b/winpr/libwinpr/smartcard/test/CMakeLists.txt
@@ -0,0 +1,26 @@
+
+set(MODULE_NAME "TestSmartCard")
+set(MODULE_PREFIX "TEST_SMARTCARD")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestSmartCardListReaders.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_link_libraries(${MODULE_NAME} winpr)
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
+
diff --git a/winpr/libwinpr/smartcard/test/TestSmartCardListReaders.c b/winpr/libwinpr/smartcard/test/TestSmartCardListReaders.c
new file mode 100644
index 0000000..637200b
--- /dev/null
+++ b/winpr/libwinpr/smartcard/test/TestSmartCardListReaders.c
@@ -0,0 +1,53 @@
+
+#include <winpr/crt.h>
+#include <winpr/smartcard.h>
+
+int TestSmartCardListReaders(int argc, char* argv[])
+{
+ LONG lStatus = 0;
+ LPSTR pReader = NULL;
+ SCARDCONTEXT hSC = 0;
+ LPSTR mszReaders = NULL;
+ DWORD cchReaders = SCARD_AUTOALLOCATE;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ lStatus = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC);
+
+ if (lStatus != SCARD_S_SUCCESS)
+ {
+ printf("SCardEstablishContext failure: %s (0x%08" PRIX32 ")\n",
+ SCardGetErrorString(lStatus), lStatus);
+ return 0;
+ }
+
+ lStatus = SCardListReadersA(hSC, NULL, (LPSTR)&mszReaders, &cchReaders);
+
+ if (lStatus != SCARD_S_SUCCESS)
+ {
+ if (lStatus == SCARD_E_NO_READERS_AVAILABLE)
+ printf("SCARD_E_NO_READERS_AVAILABLE\n");
+ else
+ return -1;
+ }
+ else
+ {
+ pReader = mszReaders;
+
+ while (*pReader)
+ {
+ printf("Reader: %s\n", pReader);
+ pReader = pReader + strlen((CHAR*)pReader) + 1;
+ }
+
+ lStatus = SCardFreeMemory(hSC, mszReaders);
+
+ if (lStatus != SCARD_S_SUCCESS)
+ printf("Failed SCardFreeMemory\n");
+ }
+
+ SCardReleaseContext(hSC);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/smartcard/test/TestSmartCardStatus.c b/winpr/libwinpr/smartcard/test/TestSmartCardStatus.c
new file mode 100644
index 0000000..011f0ce
--- /dev/null
+++ b/winpr/libwinpr/smartcard/test/TestSmartCardStatus.c
@@ -0,0 +1,160 @@
+// compile against PCSC gcc -o scardtest TestSmartCardStatus.c -DPCSC=1 -I /usr/include/PCSC
+// -lpcsclite
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(__APPLE__) || defined(PCSC)
+#include <PCSC/winscard.h>
+#include <PCSC/wintypes.h>
+#elif defined(__linux__)
+#include <winpr/crt.h>
+#include <winpr/smartcard.h>
+#include <winpr/synch.h>
+#else
+#include <winscard.h>
+#endif
+
+#if defined(PCSC)
+int main(int argc, char* argv[])
+#else
+int TestSmartCardStatus(int argc, char* argv[])
+#endif
+{
+ SCARDCONTEXT hContext;
+ LPSTR mszReaders;
+ DWORD cchReaders = 0;
+ DWORD err;
+ SCARDHANDLE hCard;
+ DWORD dwActiveProtocol;
+ char name[100];
+ char* aname = NULL;
+ char* aatr = NULL;
+ DWORD len;
+ BYTE atr[32];
+ DWORD atrlen = 32;
+ DWORD status = 0;
+ DWORD protocol = 0;
+ err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("ScardEstablishedContext: 0x%08x\n", err);
+ return -1;
+ }
+
+ err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
+
+ if (err != 0)
+ {
+ printf("ScardListReaders: 0x%08x\n", err);
+ return -1;
+ }
+
+ mszReaders = calloc(cchReaders, sizeof(char));
+
+ if (!mszReaders)
+ {
+ printf("calloc\n");
+ return -1;
+ }
+
+ err = SCardListReaders(hContext, "SCard$AllReaders", mszReaders, &cchReaders);
+
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("ScardListReaders: 0x%08x\n", err);
+ return -1;
+ }
+
+ printf("Reader: %s\n", mszReaders);
+ err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
+
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("ScardConnect: 0x%08x\n", err);
+ return -1;
+ }
+
+ free(mszReaders);
+
+ printf("# test 1 - get reader length\n");
+ err = SCardStatus(hCard, NULL, &len, NULL, NULL, NULL, NULL);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("reader name length: %u\n", len);
+
+ printf("# test 2 - get reader name value\n");
+ err = SCardStatus(hCard, name, &len, NULL, NULL, NULL, NULL);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("Reader name: %s (%ld)\n", name, strlen(name));
+
+ printf("# test 3 - get all values - pre allocated\n");
+ err = SCardStatus(hCard, name, &len, &status, &protocol, atr, &atrlen);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("Reader name: %s (%ld/len %u)\n", name, strlen(name), len);
+ printf("status: 0x%08X\n", status);
+ printf("proto: 0x%08X\n", protocol);
+ printf("atrlen: %u\n", atrlen);
+
+ printf("# test 4 - get all values - auto allocate\n");
+ len = atrlen = SCARD_AUTOALLOCATE;
+ err = SCardStatus(hCard, (LPSTR)&aname, &len, &status, &protocol, (LPBYTE)&aatr, &atrlen);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("Reader name: %s (%ld/%u)\n", aname, strlen(aname), len);
+ printf("status: 0x%08X\n", status);
+ printf("proto: 0x%08X\n", protocol);
+ printf("atrlen: %u\n", atrlen);
+ SCardFreeMemory(hContext, aname);
+ SCardFreeMemory(hContext, aatr);
+
+ printf("# test 5 - get status and protocol only\n");
+ err = SCardStatus(hCard, NULL, NULL, &status, &protocol, NULL, NULL);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("status: 0x%08X\n", status);
+ printf("proto: 0x%08X\n", protocol);
+
+ printf("# test 6 - get atr only auto allocated\n");
+ atrlen = SCARD_AUTOALLOCATE;
+ err = SCardStatus(hCard, NULL, NULL, NULL, NULL, (LPBYTE)&aatr, &atrlen);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("atrlen: %u\n", atrlen);
+ SCardFreeMemory(hContext, aatr);
+
+ printf("# test 7 - get atr only pre allocated\n");
+ atrlen = 32;
+ err = SCardStatus(hCard, NULL, NULL, NULL, NULL, atr, &atrlen);
+ if (err != SCARD_S_SUCCESS)
+ {
+ printf("SCardStatus: 0x%08x\n", err);
+ return -1;
+ }
+ printf("atrlen: %u\n", atrlen);
+ SCardDisconnect(hCard, SCARD_LEAVE_CARD);
+ SCardReleaseContext(hContext);
+
+ return 0;
+}