diff options
Diffstat (limited to '')
-rw-r--r-- | winpr/libwinpr/smartcard/CMakeLists.txt | 60 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/ModuleOptions.cmake | 9 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard.c | 1283 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard.h | 31 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_inspect.c | 1363 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_inspect.h | 30 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_pcsc.c | 3357 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_pcsc.h | 175 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_windows.c | 126 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/smartcard_windows.h | 28 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/test/CMakeLists.txt | 26 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/test/TestSmartCardListReaders.c | 53 | ||||
-rw-r--r-- | winpr/libwinpr/smartcard/test/TestSmartCardStatus.c | 160 |
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; +} |