Merge pull request #1885 from awakecoding/master
SmartCard fixes and workarounds
This commit is contained in:
commit
3854bdff29
@ -553,14 +553,14 @@ static UINT32 smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
|
||||
status = ret.ReturnCode = SCardConnectA(operation->hContext, (char*) call->szReader, call->Common.dwShareMode,
|
||||
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
|
||||
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
|
||||
|
||||
smartcard_trace_connect_return(smartcard, &ret);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (status)
|
||||
@ -605,14 +605,14 @@ static UINT32 smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
|
||||
status = ret.ReturnCode = SCardConnectW(operation->hContext, (WCHAR*) call->szReader, call->Common.dwShareMode,
|
||||
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
|
||||
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
|
||||
|
||||
smartcard_trace_connect_return(smartcard, &ret);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (status)
|
||||
|
@ -1890,6 +1890,12 @@ void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, GetAttrib_Re
|
||||
{
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "pbAttr: %.*s", ret->cbAttrLen, (char*) ret->pbAttr);
|
||||
}
|
||||
else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
|
||||
{
|
||||
UINT32 dwProtocolType = *((UINT32*) ret->pbAttr);
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "dwProtocolType: %s (0x%04X)",
|
||||
SCardGetProtocolString(dwProtocolType), dwProtocolType);
|
||||
}
|
||||
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "}");
|
||||
}
|
||||
|
@ -103,16 +103,18 @@
|
||||
|
||||
struct _PCSC_SCARDCONTEXT
|
||||
{
|
||||
SCARDCONTEXT hContext;
|
||||
SCARDHANDLE hCard;
|
||||
CRITICAL_SECTION lock;
|
||||
SCARDCONTEXT hContext;
|
||||
DWORD dwCardHandleCount;
|
||||
BOOL isTransactionLocked;
|
||||
};
|
||||
typedef struct _PCSC_SCARDCONTEXT PCSC_SCARDCONTEXT;
|
||||
|
||||
struct _PCSC_SCARDHANDLE
|
||||
{
|
||||
SCARDCONTEXT hContext;
|
||||
CRITICAL_SECTION lock;
|
||||
SCARDCONTEXT hSharedContext;
|
||||
SCARDCONTEXT hPrivateContext;
|
||||
};
|
||||
typedef struct _PCSC_SCARDHANDLE PCSC_SCARDHANDLE;
|
||||
|
||||
@ -132,6 +134,32 @@ static int g_StartedEventRefCount = 0;
|
||||
static BOOL g_SCardAutoAllocate = FALSE;
|
||||
static BOOL g_PnP_Notification = TRUE;
|
||||
|
||||
/**
|
||||
* g_LockTransactions: enable pcsc-lite SCardBeginTransaction/SCardEndTransaction.
|
||||
*
|
||||
* After wasting months trying to fix and work around an appalling number of serious issues
|
||||
* in both the pcsc-lite client library and the pcscd daemon, I decided to just give up on
|
||||
* the transaction system. Using them inevitably leads to multiple SCardConnect calls deadlocking.
|
||||
*
|
||||
* It is not very clear how WinSCard transactions should lock: some logs on Windows show that is
|
||||
* possible to call SCardBeginTransaction twice on the same SCARDHANDLE without the second call
|
||||
* being blocked. Worse, in this specific case one corresponding SCardEndTransaction is missing.
|
||||
*
|
||||
* pcsc-lite apparently implements these "nested" transactions as well, because it allows the same
|
||||
* SCARDHANDLE to be locked more than once with a counter. However, there must be a bug even in the
|
||||
* latest pcsc-lite daemon as we still get deadlocked on SCardConnect calls when using those.
|
||||
*
|
||||
* Trying to disable nested transactions by letting pcsc-lite know about only one transaction level
|
||||
* gives the same deadlocks on SCardConnect. In other words, there are serious deadlock issues in
|
||||
* pcsc-lite even when disabling nested transactions.
|
||||
*
|
||||
* Transactions are simply too much of a pain to support properly without deadlocking the entire
|
||||
* smartcard subsystem. In practice, there is not much of a difference if locking occurs or not.
|
||||
* We could revisit transactions later on based on the demand, but for now we just want things to work.
|
||||
*/
|
||||
|
||||
static BOOL g_LockTransactions = FALSE;
|
||||
|
||||
static wArrayList* g_Readers = NULL;
|
||||
static wListDictionary* g_CardHandles = NULL;
|
||||
static wListDictionary* g_CardContexts = NULL;
|
||||
@ -147,6 +175,9 @@ const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(PC
|
||||
const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardRawPci = { PCSC_SCARD_PROTOCOL_RAW, sizeof(PCSC_SCARD_IO_REQUEST) };
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPCVOID pvMem);
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext);
|
||||
|
||||
LONG PCSC_MapErrorCodeToWinSCard(LONG errorCode)
|
||||
{
|
||||
@ -313,7 +344,10 @@ void PCSC_ReleaseCardContext(SCARDCONTEXT hContext)
|
||||
pContext = PCSC_GetCardContextData(hContext);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_ReleaseCardContext: null pContext!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&(pContext->lock));
|
||||
|
||||
@ -383,22 +417,34 @@ SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard)
|
||||
if (!pCard)
|
||||
return 0;
|
||||
|
||||
return pCard->hContext;
|
||||
return pCard->hPrivateContext;
|
||||
}
|
||||
|
||||
PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard)
|
||||
PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTEXT hPrivateContext, SCARDHANDLE hCard)
|
||||
{
|
||||
PCSC_SCARDHANDLE* pCard;
|
||||
PCSC_SCARDCONTEXT* pContext;
|
||||
|
||||
pContext = PCSC_GetCardContextData(hSharedContext);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_ConnectCardHandle: null pContext!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pCard = (PCSC_SCARDHANDLE*) calloc(1, sizeof(PCSC_SCARDHANDLE));
|
||||
|
||||
if (!pCard)
|
||||
return NULL;
|
||||
|
||||
pCard->hContext = hContext;
|
||||
pCard->hSharedContext = hSharedContext;
|
||||
pCard->hPrivateContext = hPrivateContext;
|
||||
|
||||
InitializeCriticalSectionAndSpinCount(&(pCard->lock), 4000);
|
||||
|
||||
pContext->dwCardHandleCount++;
|
||||
|
||||
if (!g_CardHandles)
|
||||
g_CardHandles = ListDictionary_New(TRUE);
|
||||
|
||||
@ -410,6 +456,7 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCar
|
||||
void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
|
||||
{
|
||||
PCSC_SCARDHANDLE* pCard;
|
||||
PCSC_SCARDCONTEXT* pContext;
|
||||
|
||||
pCard = PCSC_GetCardHandleData(hCard);
|
||||
|
||||
@ -418,12 +465,24 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
|
||||
|
||||
DeleteCriticalSection(&(pCard->lock));
|
||||
|
||||
pContext = PCSC_GetCardContextData(pCard->hSharedContext);
|
||||
|
||||
PCSC_SCardReleaseContext_Internal(pCard->hPrivateContext);
|
||||
|
||||
free(pCard);
|
||||
|
||||
if (!g_CardHandles)
|
||||
return;
|
||||
|
||||
ListDictionary_Remove(g_CardHandles, (void*) hCard);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_DisconnectCardHandle: null pContext!");
|
||||
return;
|
||||
}
|
||||
|
||||
pContext->dwCardHandleCount--;
|
||||
}
|
||||
|
||||
BOOL PCSC_LockCardHandle(SCARDHANDLE hCard)
|
||||
@ -847,7 +906,7 @@ void* PCSC_SCardAllocMemory(SCARDCONTEXT hContext, size_t size)
|
||||
* Standard Windows Smart Card API (PCSC)
|
||||
*/
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
@ -861,13 +920,23 @@ WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
||||
status = (LONG) g_PCSC.pfnSCardEstablishContext(pcsc_dwScope, pvReserved1, pvReserved2, phContext);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
||||
status = PCSC_SCardEstablishContext_Internal(dwScope, pvReserved1, pvReserved2, phContext);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
PCSC_EstablishCardContext(*phContext);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
||||
@ -883,7 +952,16 @@ WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
|
||||
status = (LONG) g_PCSC.pfnSCardReleaseContext(hContext);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
if (!status)
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI 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;
|
||||
@ -1590,6 +1668,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
||||
{
|
||||
char* szReaderPCSC;
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
SCARDCONTEXT hPrivateContext = 0;
|
||||
PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD) dwShareMode;
|
||||
PCSC_DWORD pcsc_dwPreferredProtocols = 0;
|
||||
PCSC_DWORD pcsc_dwActiveProtocol = 0;
|
||||
@ -1597,6 +1676,11 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
||||
if (!g_PCSC.pfnSCardConnect)
|
||||
return SCARD_E_NO_SERVICE;
|
||||
|
||||
status = PCSC_SCardEstablishContext_Internal(SCARD_SCOPE_SYSTEM, NULL, NULL, &hPrivateContext);
|
||||
|
||||
if (status != SCARD_S_SUCCESS)
|
||||
return status;
|
||||
|
||||
szReaderPCSC = PCSC_GetReaderNameFromAlias((char*) szReader);
|
||||
|
||||
if (!szReaderPCSC)
|
||||
@ -1604,15 +1688,19 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
||||
|
||||
pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardConnect(hContext, szReaderPCSC,
|
||||
status = (LONG) g_PCSC.pfnSCardConnect(hPrivateContext, szReaderPCSC,
|
||||
pcsc_dwShareMode, pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
{
|
||||
PCSC_ConnectCardHandle(hContext, *phCard);
|
||||
PCSC_ConnectCardHandle(hContext, hPrivateContext, *phCard);
|
||||
*pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD) pcsc_dwActiveProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
PCSC_SCardReleaseContext(hPrivateContext);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -1704,12 +1792,32 @@ WINSCARDAPI LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposit
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
PCSC_SCARDHANDLE* pCard = NULL;
|
||||
PCSC_SCARDCONTEXT* pContext = NULL;
|
||||
|
||||
if (!g_PCSC.pfnSCardBeginTransaction)
|
||||
return SCARD_E_NO_SERVICE;
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardBeginTransaction(hCard);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
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 */
|
||||
|
||||
if (g_LockTransactions)
|
||||
{
|
||||
status = (LONG) g_PCSC.pfnSCardBeginTransaction(hCard);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
}
|
||||
|
||||
pContext->isTransactionLocked = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -1717,13 +1825,33 @@ WINSCARDAPI LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
|
||||
{
|
||||
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 SCARD_E_NO_SERVICE;
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
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 */
|
||||
|
||||
if (g_LockTransactions)
|
||||
{
|
||||
status = (LONG) g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
}
|
||||
|
||||
pContext->isTransactionLocked = FALSE;
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -2648,7 +2776,7 @@ extern int PCSC_InitializeSCardApi_Link(void);
|
||||
int PCSC_InitializeSCardApi(void)
|
||||
{
|
||||
/* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
|
||||
//SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
|
||||
SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
|
||||
|
||||
#ifndef DISABLE_PCSC_LINK
|
||||
if (PCSC_InitializeSCardApi_Link() >= 0)
|
||||
|
Loading…
Reference in New Issue
Block a user