Merge pull request #1885 from awakecoding/master

SmartCard fixes and workarounds
This commit is contained in:
Marc-André Moreau 2014-06-04 12:41:08 -04:00
commit 3854bdff29
3 changed files with 156 additions and 22 deletions

View File

@ -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)

View File

@ -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, "}");
}

View File

@ -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)