#include <assert.h>
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/_endian.h>
#include "wintypes.h"
#include "pcsclite.h"
#include "pcscexport.h"
#include "winscard.h"
#include "debug.h"
#include "thread_generic.h"
#include "readerfactory.h"
#include "eventhandler.h"
#include "sys_generic.h"
#include "winscard_msg.h"
#include "readerstate.h"
#include <security_utilities/debugging.h>
#define SCARD_PROTOCOL_ANY_OLD 0x1000
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define PROFILE_START
#define PROFILE_END
struct _psChannelMap
{
SCARDHANDLE hCard;
LPSTR readerName;
};
typedef struct _psChannelMap CHANNEL_MAP, *PCHANNEL_MAP;
static struct _psContextMap
{
DWORD dwClientID;
SCARDCONTEXT hContext;
DWORD contextBlockStatus;
PCSCLITE_MUTEX_T mMutex;
CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
} psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS];
static short isExecuted = 0;
static int mapAddr = 0;
static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;
static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
static LONG SCardAddContext(SCARDCONTEXT, DWORD);
static LONG SCardGetContextIndice(SCARDCONTEXT);
static LONG SCardGetContextIndiceTH(SCARDCONTEXT);
static LONG SCardRemoveContext(SCARDCONTEXT);
static LONG SCardAddHandle(SCARDHANDLE, DWORD, LPSTR);
static LONG SCardGetIndicesFromHandle(SCARDHANDLE, PDWORD, PDWORD);
static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE, PDWORD, PDWORD);
static LONG SCardRemoveHandle(SCARDHANDLE);
static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
LPBYTE pbAttr, LPDWORD pcbAttrLen);
static LONG SCardCheckDaemonAvailability(void);
static int SCardInitializeOnce();
static int SHMClientCommunicationTimeout();
inline static LONG SCardLockThread(void);
inline static LONG SCardUnlockThread(void);
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
{
LONG rv;
PROFILE_START
SCardLockThread();
rv = SCardEstablishContextTH(dwScope, pvReserved1,
pvReserved2, phContext);
SCardUnlockThread();
PROFILE_END
return rv;
}
static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1,
LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
{
LONG rv;
establish_struct scEstablishStruct;
sharedSegmentMsg msgStruct;
DWORD dwClientID = 0;
if (phContext == NULL)
return SCARD_E_INVALID_PARAMETER;
else
*phContext = 0;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
if (isExecuted == 0)
{
SCardInitializeOnce();
isExecuted = 1;
}
if (SHMClientSetupSession(&dwClientID) != 0)
{
SYS_CloseFile(mapAddr);
return SCARD_E_NO_SERVICE;
}
{
sharedSegmentMsg msgStruct;
version_struct *veStr = (version_struct *)&msgStruct.data;
veStr->major = PROTOCOL_VERSION_MAJOR;
veStr->minor = PROTOCOL_VERSION_MINOR;
htonlVersionStruct(veStr);
if (-1 == WrapSHMWrite(CMD_VERSION, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout(), veStr))
return SCARD_E_NO_SERVICE;
if (-1 == SHMClientReadMessage(&msgStruct, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout()))
{
Log1(PCSC_LOG_ERROR, "Your pcscd is too old and does not support CMD_VERSION");
return SCARD_F_COMM_ERROR;
}
ntohlVersionStruct(veStr);
Log3(PCSC_LOG_ERROR, "Server is protocol version %d:%d",
veStr->major, veStr->minor);
if (veStr->rv != SCARD_S_SUCCESS)
return veStr->rv;
}
if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL)
{
return SCARD_E_INVALID_VALUE;
}
scEstablishStruct.dwScope = dwScope;
scEstablishStruct.phContext = 0;
scEstablishStruct.rv = 0;
htonlEstablishStruct(&scEstablishStruct);
rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID,
sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS,
(void *) &scEstablishStruct);
if (rv == -1)
return SCARD_E_NO_SERVICE;
rv = SHMClientReadMessage(&msgStruct, dwClientID, sizeof(establish_struct), SHMClientCommunicationTimeout());
if (rv == -1)
return SCARD_F_COMM_ERROR;
memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct));
ntohlEstablishStruct(&scEstablishStruct);
if (scEstablishStruct.rv != SCARD_S_SUCCESS)
return scEstablishStruct.rv;
*phContext = scEstablishStruct.phContext;
rv = SCardAddContext(*phContext, dwClientID);
return rv;
}
LONG SCardReleaseContext(SCARDCONTEXT hContext)
{
LONG rv;
release_struct scReleaseStruct;
sharedSegmentMsg msgStruct;
LONG dwContextIndex;
PROFILE_START
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
scReleaseStruct.hContext = hContext;
scReleaseStruct.rv = 0;
htonlReleaseStruct(&scReleaseStruct);
rv = WrapSHMWrite(SCARD_RELEASE_CONTEXT, psContextMap[dwContextIndex].dwClientID,
sizeof(scReleaseStruct),
PCSCLITE_MCLIENT_ATTEMPTS, (void *) &scReleaseStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(release_struct), SHMClientCommunicationTimeout());
memcpy(&scReleaseStruct, &msgStruct.data, sizeof(scReleaseStruct));
ntohlReleaseStruct(&scReleaseStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
SCardLockThread();
SCardRemoveContext(hContext);
SCardUnlockThread();
PROFILE_END
return scReleaseStruct.rv;
}
LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout)
{
return SCARD_S_SUCCESS;
}
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
LPDWORD pdwActiveProtocol)
{
LONG rv;
connect_struct scConnectStruct = {0,};
sharedSegmentMsg msgStruct = {0,};
LONG dwContextIndex;
PROFILE_START
if (phCard == NULL || pdwActiveProtocol == NULL)
return SCARD_E_INVALID_PARAMETER;
else
*phCard = 0;
if (szReader == NULL)
return SCARD_E_UNKNOWN_READER;
if (strlen(szReader) > MAX_READERNAME)
return SCARD_E_INVALID_VALUE;
if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
{
return SCARD_E_INVALID_VALUE;
}
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
scConnectStruct.hContext = hContext;
scConnectStruct.dwShareMode = dwShareMode;
scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
scConnectStruct.phCard = *phCard;
scConnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
htonlConnectStruct(&scConnectStruct);
rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID,
sizeof(scConnectStruct),
SHMClientCommunicationTimeout(), (void *) &scConnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(connect_struct), SHMClientCommunicationTimeout());
memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct));
ntohlConnectStruct(&scConnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
*phCard = scConnectStruct.phCard;
*pdwActiveProtocol = scConnectStruct.pdwActiveProtocol;
if (scConnectStruct.rv == SCARD_S_SUCCESS)
{
rv = SCardAddHandle(*phCard, dwContextIndex, (LPSTR) szReader);
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return rv;
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return scConnectStruct.rv;
}
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
DWORD dwPreferredProtocols, DWORD dwInitialization,
LPDWORD pdwActiveProtocol)
{
LONG rv;
reconnect_struct scReconnectStruct;
sharedSegmentMsg msgStruct;
int i;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
if (dwInitialization != SCARD_LEAVE_CARD &&
dwInitialization != SCARD_RESET_CARD &&
dwInitialization != SCARD_UNPOWER_CARD &&
dwInitialization != SCARD_EJECT_CARD)
{
return SCARD_E_INVALID_VALUE;
}
if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
{
return SCARD_E_INVALID_VALUE;
}
if (pdwActiveProtocol == NULL)
return SCARD_E_INVALID_PARAMETER;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
scReconnectStruct.hCard = hCard;
scReconnectStruct.dwShareMode = dwShareMode;
scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
scReconnectStruct.dwInitialization = dwInitialization;
scReconnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
htonlReconnectStruct(&scReconnectStruct);
rv = WrapSHMWrite(SCARD_RECONNECT, psContextMap[dwContextIndex].dwClientID,
sizeof(scReconnectStruct),
SHMClientCommunicationTimeout(), (void *) &scReconnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(reconnect_struct), SHMClientCommunicationTimeout());
memcpy(&scReconnectStruct, &msgStruct.data, sizeof(scReconnectStruct));
ntohlReconnectStruct(&scReconnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
*pdwActiveProtocol = scReconnectStruct.pdwActiveProtocol;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return scReconnectStruct.rv;
}
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
{
LONG rv;
disconnect_struct scDisconnectStruct;
sharedSegmentMsg msgStruct;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
if (dwDisposition != SCARD_LEAVE_CARD &&
dwDisposition != SCARD_RESET_CARD &&
dwDisposition != SCARD_UNPOWER_CARD &&
dwDisposition != SCARD_EJECT_CARD)
{
return SCARD_E_INVALID_VALUE;
}
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
scDisconnectStruct.hCard = hCard;
scDisconnectStruct.dwDisposition = dwDisposition;
htonlDisconnectStruct(&scDisconnectStruct);
rv = WrapSHMWrite(SCARD_DISCONNECT, psContextMap[dwContextIndex].dwClientID,
sizeof(scDisconnectStruct),
SHMClientCommunicationTimeout(), (void *) &scDisconnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(disconnect_struct), SHMClientCommunicationTimeout());
memcpy(&scDisconnectStruct, &msgStruct.data, sizeof(scDisconnectStruct));
ntohlDisconnectStruct(&scDisconnectStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
SCardRemoveHandle(hCard);
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return scDisconnectStruct.rv;
}
LONG SCardBeginTransaction(SCARDHANDLE hCard)
{
LONG rv;
begin_struct txBeginStruct = {0,}, rxBeginStruct = {0,};
int i;
sharedSegmentMsg msgStruct = {0,};
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
secdebug("pcscd", "SCardBeginTransaction: initial request: hCard: 0x%08X", hCard);
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
txBeginStruct.hCard = hCard;
htonlBeginStruct(&txBeginStruct);
do
{
rv = WrapSHMWrite(SCARD_BEGIN_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
sizeof(txBeginStruct),
SHMClientCommunicationTimeout(), (void *) &txBeginStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(begin_struct), SHMClientCommunicationTimeout());
memcpy(&rxBeginStruct, &msgStruct.data, sizeof(rxBeginStruct));
ntohlBeginStruct(&rxBeginStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
}
while (rxBeginStruct.rv == SCARD_E_SHARING_VIOLATION);
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
secdebug("pcscd", "SCardBeginTransaction: hCard: 0x%08X, returning: 0x%08X", rxBeginStruct.hCard, rxBeginStruct.rv);
return rxBeginStruct.rv;
}
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
{
LONG rv;
end_struct scEndStruct;
sharedSegmentMsg msgStruct;
int randnum, i;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
secdebug("pcscd", "SCardEndTransaction: initial request: hCard: 0x%08X, dwDisposition: 0x%04X",
hCard, dwDisposition);
randnum = 0;
if (dwDisposition != SCARD_LEAVE_CARD &&
dwDisposition != SCARD_RESET_CARD &&
dwDisposition != SCARD_UNPOWER_CARD &&
dwDisposition != SCARD_EJECT_CARD)
{
return SCARD_E_INVALID_VALUE;
}
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
scEndStruct.hCard = hCard;
scEndStruct.dwDisposition = dwDisposition;
htonlEndStruct(&scEndStruct);
rv = WrapSHMWrite(SCARD_END_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
sizeof(scEndStruct),
SHMClientCommunicationTimeout(), (void *) &scEndStruct);
secdebug("pcscd", "SCardEndTransaction: WrapSHMWrite result: 0x%08X", rv);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(end_struct), SHMClientCommunicationTimeout());
secdebug("pcscd", "SCardEndTransaction: SHMClientRead result: 0x%08X", rv);
memcpy(&scEndStruct, &msgStruct.data, sizeof(scEndStruct));
ntohlEndStruct(&scEndStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
randnum = SYS_Random(randnum, 1000.0, 10000.0);
SYS_USleep(randnum);
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
secdebug("pcscd", "SCardEndTransaction: returning: 0x%08X", scEndStruct.rv);
return scEndStruct.rv;
}
LONG SCardCancelTransaction(SCARDHANDLE hCard)
{
LONG rv;
cancel_struct scCancelStruct;
sharedSegmentMsg msgStruct;
int i;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
scCancelStruct.hCard = hCard;
htonlCancelStruct(&scCancelStruct);
rv = WrapSHMWrite(SCARD_CANCEL_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
sizeof(scCancelStruct),
SHMClientCommunicationTimeout(), (void *) &scCancelStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(cancel_struct), SHMClientCommunicationTimeout());
memcpy(&scCancelStruct, &msgStruct.data, sizeof(scCancelStruct));
ntohlCancelStruct(&scCancelStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return scCancelStruct.rv;
}
LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames,
LPDWORD pcchReaderLen, LPDWORD pdwState,
LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
{
DWORD dwReaderLen, atrOutputBufferSize;
LONG rv;
int i;
status_struct scStatusStruct;
sharedSegmentMsg msgStruct;
DWORD dwContextIndex, dwChannelIndex;
char *r;
PROFILE_START
if (pcchReaderLen == NULL || pcbAtrLen == NULL)
return SCARD_E_INVALID_PARAMETER;
dwReaderLen = *pcchReaderLen;
atrOutputBufferSize = *pcbAtrLen;
if (pdwState)
*pdwState = 0;
if (pdwProtocol)
*pdwProtocol = 0;
*pcchReaderLen = 0;
*pcbAtrLen = 0;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
memset(&scStatusStruct, 0, sizeof(scStatusStruct));
scStatusStruct.hCard = hCard;
scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
htonlStatusStruct(&scStatusStruct);
rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID,
sizeof(scStatusStruct),
SHMClientCommunicationTimeout(), (void *) &scStatusStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(status_struct), SHMClientCommunicationTimeout());
memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct));
ntohlStatusStruct(&scStatusStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
rv = scStatusStruct.rv;
if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return rv;
}
*pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1;
*pcbAtrLen = SharedReaderState_CardAtrLength(readerStates[i]);
if (pdwState)
*pdwState = SharedReaderState_State(readerStates[i]);
if (pdwProtocol)
*pdwProtocol = SharedReaderState_Protocol(readerStates[i]);
if (mszReaderNames)
{
if (*pcchReaderLen > dwReaderLen)
rv = SCARD_E_INSUFFICIENT_BUFFER;
strncpy(mszReaderNames,
psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,
dwReaderLen);
}
if (pbAtr)
{
if (*pcbAtrLen > atrOutputBufferSize)
rv = SCARD_E_INSUFFICIENT_BUFFER;
memcpy(pbAtr, SharedReaderState_CardAtr(readerStates[i]),
min(*pcbAtrLen, atrOutputBufferSize));
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return rv;
}
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
{
PSCARD_READERSTATE_A currReader;
PREADER_STATE rContext;
DWORD dwTime = 0;
DWORD dwState;
DWORD dwBreakFlag = 0;
int j;
LONG dwContextIndex;
int currentReaderCount = 0;
PROFILE_START
if (rgReaderStates == NULL && cReaders > 0)
return SCARD_E_INVALID_PARAMETER;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
if (cReaders == 0)
{
while (1)
{
int i;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (SharedReaderState_ReaderID(readerStates[i]) != 0)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return SCARD_S_SUCCESS;
}
}
if (dwTimeout == 0)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
SYS_USleep(PCSCLITE_STATUS_WAIT);
if (dwTimeout != INFINITE)
{
dwTime += PCSCLITE_STATUS_WAIT;
if (dwTime >= (dwTimeout * 1000))
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return SCARD_E_TIMEOUT;
}
}
}
}
else
if (cReaders >= PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INVALID_VALUE;
}
for (j = 0; j < cReaders; j++)
{
currReader = &rgReaderStates[j];
if (currReader->szReader == NULL)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INVALID_VALUE;
}
}
for (j = 0; j < cReaders; j++)
{
currReader = &rgReaderStates[j];
currReader->dwEventState = 0;
}
Log1(PCSC_LOG_DEBUG, "Event Loop Start");
psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING;
for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
if (SharedReaderState_ReaderID(readerStates[j]) != 0)
currentReaderCount++;
j = 0;
do
{
int newReaderCount = 0;
char ReaderCountChanged = 0;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return SCARD_E_NO_SERVICE;
}
if (j == 0)
{
int i;
for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
if (SharedReaderState_ReaderID(readerStates[i]) != 0)
newReaderCount++;
if (newReaderCount != currentReaderCount)
{
Log1(PCSC_LOG_INFO, "Reader list changed");
ReaderCountChanged = 1;
currentReaderCount = newReaderCount;
}
}
currReader = &rgReaderStates[j];
if (currReader->dwCurrentState & SCARD_STATE_IGNORE)
currReader->dwEventState = SCARD_STATE_IGNORE;
else
{
LPSTR lpcReaderName;
int i;
lpcReaderName = (char *) currReader->szReader;
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], lpcReaderName))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
currReader->dwEventState = SCARD_STATE_UNKNOWN;
else
{
currReader->dwEventState =
SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
else
{
if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
dwBreakFlag = 1;
}
rContext = readerStates[i];
dwState = SharedReaderState_State(rContext);
if (dwState & SCARD_UNKNOWN)
{
if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
else
{
currReader->dwEventState = SCARD_STATE_CHANGED |
SCARD_STATE_UNAVAILABLE;
dwBreakFlag = 1;
}
}
else
{
if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
{
currReader->dwEventState &=
~SCARD_STATE_UNAVAILABLE;
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
if (dwState & SCARD_PRESENT)
{
if (0 == SharedReaderState_CardAtrLength(rContext))
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
currReader->cbAtr = SharedReaderState_CardAtrLength(rContext);
memcpy(currReader->rgbAtr, SharedReaderState_CardAtr(rContext),
currReader->cbAtr);
}
else
currReader->cbAtr = 0;
if (dwState & SCARD_ABSENT)
{
currReader->dwEventState |= SCARD_STATE_EMPTY;
currReader->dwEventState &= ~SCARD_STATE_PRESENT;
currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
currReader->dwEventState &= ~SCARD_STATE_IGNORE;
currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
currReader->dwEventState &= ~SCARD_STATE_MUTE;
currReader->dwEventState &= ~SCARD_STATE_INUSE;
if (currReader->dwCurrentState & SCARD_STATE_PRESENT
|| currReader->dwCurrentState & SCARD_STATE_ATRMATCH
|| currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE
|| currReader->dwCurrentState & SCARD_STATE_INUSE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
} else if (dwState & SCARD_PRESENT)
{
currReader->dwEventState |= SCARD_STATE_PRESENT;
currReader->dwEventState &= ~SCARD_STATE_EMPTY;
currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
currReader->dwEventState &= ~SCARD_STATE_IGNORE;
currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
currReader->dwEventState &= ~SCARD_STATE_MUTE;
if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
if (dwState & SCARD_SWALLOWED)
{
if (currReader->dwCurrentState & SCARD_STATE_MUTE)
currReader->dwEventState |= SCARD_STATE_MUTE;
else
{
currReader->dwEventState |= SCARD_STATE_MUTE;
if (currReader->dwCurrentState
!= SCARD_STATE_UNAWARE)
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
else
{
if (currReader->dwCurrentState & SCARD_STATE_MUTE)
{
currReader->dwEventState |=
SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
}
DWORD sharing = SharedReaderState_Sharing(rContext);
if (sharing == -1)
{
currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
currReader->dwEventState &= ~SCARD_STATE_INUSE;
if (currReader->dwCurrentState & SCARD_STATE_INUSE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
else if (sharing >= 1)
{
if (dwState & SCARD_PRESENT)
{
currReader->dwEventState |= SCARD_STATE_INUSE;
currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
}
else if (sharing == 0)
{
currReader->dwEventState &= ~SCARD_STATE_INUSE;
currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
if (currReader->dwCurrentState & SCARD_STATE_INUSE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
else if (currReader-> dwCurrentState
& SCARD_STATE_EXCLUSIVE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
{
currReader->dwEventState |= SCARD_STATE_CHANGED;
dwBreakFlag = 1;
}
}
}
j = j + 1;
if (j == cReaders)
{
if (!dwBreakFlag)
{
if (ReaderCountChanged)
break;
}
j = 0;
}
if (psContextMap[dwContextIndex].contextBlockStatus
== BLOCK_STATUS_RESUME)
break;
if ((dwBreakFlag == 1) && (j == 0))
break;
if ((dwTimeout == 0) && (j == 0))
break;
if (dwTimeout != INFINITE && dwTimeout != 0)
{
if ((dwTime >= (dwTimeout * 1000)) && (j == 0))
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_TIMEOUT;
}
}
if (j == 0)
{
SYS_USleep(PCSCLITE_STATUS_WAIT);
dwTime += PCSCLITE_STATUS_WAIT;
}
}
while (1);
Log1(PCSC_LOG_DEBUG, "Event Loop End");
if (psContextMap[dwContextIndex].contextBlockStatus ==
BLOCK_STATUS_RESUME)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_CANCELLED;
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return SCARD_S_SUCCESS;
}
#undef SCardControl
LONG SCardControl(SCARDHANDLE hCard, const void *pbSendBuffer,
DWORD cbSendLength, void *pbRecvBuffer, LPDWORD pcbRecvLength)
{
SCARD_IO_REQUEST pioSendPci, pioRecvPci;
pioSendPci.dwProtocol = SCARD_PROTOCOL_RAW;
pioRecvPci.dwProtocol = SCARD_PROTOCOL_RAW;
return SCardTransmit(hCard, &pioSendPci, pbSendBuffer, cbSendLength,
&pioRecvPci, pbRecvBuffer, pcbRecvLength);
}
int32_t SCardControl132(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
LPDWORD lpBytesReturned)
{
LONG rv;
control_struct scControlStruct;
sharedSegmentMsg msgStruct;
int i;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
if (NULL != lpBytesReturned)
*lpBytesReturned = 0;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
|| (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INSUFFICIENT_BUFFER;
}
if ((cbSendLength > MAX_BUFFER_SIZE) || (cbRecvLength > MAX_BUFFER_SIZE))
{
unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
control_struct_extended *scControlStructExtended = (control_struct_extended *)buffer;
sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
scControlStructExtended->hCard = hCard;
scControlStructExtended->dwControlCode = dwControlCode;
scControlStructExtended->cbSendLength = cbSendLength;
scControlStructExtended->cbRecvLength = cbRecvLength;
scControlStructExtended->size = sizeof(*scControlStructExtended) + cbSendLength;
memcpy(scControlStructExtended->data, pbSendBuffer, cbSendLength);
size_t csesize = scControlStructExtended->size; htonlControlStructExtended(scControlStructExtended);
rv = WrapSHMWrite(SCARD_CONTROL_EXTENDED,
psContextMap[dwContextIndex].dwClientID,
csesize,
SHMClientCommunicationTimeout(), buffer);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(pmsgStruct, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
scControlStructExtended = (control_struct_extended *)&(pmsgStruct -> data);
ntohlControlStructExtended(scControlStructExtended);
if (scControlStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
{
rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
scControlStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
psContextMap[dwContextIndex].dwClientID,
SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
}
if (scControlStructExtended -> rv == SCARD_S_SUCCESS)
{
memcpy(pbRecvBuffer, scControlStructExtended -> data,
scControlStructExtended -> pdwBytesReturned);
memset(scControlStructExtended -> data, 0x00,
scControlStructExtended -> pdwBytesReturned);
}
if (NULL != lpBytesReturned)
*lpBytesReturned = scControlStructExtended -> pdwBytesReturned;
rv = scControlStructExtended -> rv;
}
else
{
scControlStruct.hCard = hCard;
scControlStruct.dwControlCode = dwControlCode;
scControlStruct.cbSendLength = cbSendLength;
scControlStruct.cbRecvLength = cbRecvLength;
memcpy(scControlStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
htonlControlStruct(&scControlStruct);
rv = WrapSHMWrite(SCARD_CONTROL, psContextMap[dwContextIndex].dwClientID,
sizeof(scControlStruct), SHMClientCommunicationTimeout(), &scControlStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(control_struct), SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
memcpy(&scControlStruct, &msgStruct.data, sizeof(scControlStruct));
ntohlControlStruct(&scControlStruct);
if (NULL != lpBytesReturned)
*lpBytesReturned = scControlStruct.dwBytesReturned;
if (scControlStruct.rv == SCARD_S_SUCCESS)
{
memcpy(pbRecvBuffer, scControlStruct.pbRecvBuffer,
scControlStruct.cbRecvLength);
memset(scControlStruct.pbRecvBuffer, 0x00,
sizeof(scControlStruct.pbRecvBuffer));
}
rv = scControlStruct.rv;
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return rv;
}
int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, uint8_t * pbAttr,
uint32_t * pcbAttrLen)
{
PROFILE_START
if (NULL == pcbAttrLen)
return SCARD_E_INVALID_PARAMETER;
if (NULL == pbAttr)
*pcbAttrLen = MAX_BUFFER_SIZE;
PROFILE_END
return SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, pbAttr,
pcbAttrLen);
}
int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, const uint8_t *pbAttr,
uint32_t cbAttrLen)
{
PROFILE_START
if (NULL == pbAttr || 0 == cbAttrLen)
return SCARD_E_INVALID_PARAMETER;
PROFILE_END
return SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
&cbAttrLen);
}
static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
LPBYTE pbAttr, LPDWORD pcbAttrLen)
{
PROFILE_START
LONG rv;
getset_struct scGetSetStruct;
sharedSegmentMsg msgStruct;
int i;
DWORD dwContextIndex, dwChannelIndex;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
if (*pcbAttrLen > MAX_BUFFER_SIZE)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INSUFFICIENT_BUFFER;
}
scGetSetStruct.hCard = hCard;
scGetSetStruct.dwAttrId = dwAttrId;
scGetSetStruct.cbAttrLen = *pcbAttrLen;
scGetSetStruct.rv = SCARD_E_NO_SERVICE;
if (SCARD_SET_ATTRIB == command)
memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
ntohlGetSetStruct(&scGetSetStruct);
rv = WrapSHMWrite(command,
psContextMap[dwContextIndex].dwClientID, sizeof(scGetSetStruct),
SHMClientCommunicationTimeout(), &scGetSetStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(getset_struct), SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
memcpy(&scGetSetStruct, &msgStruct.data, sizeof(scGetSetStruct));
ntohlGetSetStruct(&scGetSetStruct);
if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
{
if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
{
scGetSetStruct.cbAttrLen = *pcbAttrLen;
scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
}
else
*pcbAttrLen = scGetSetStruct.cbAttrLen;
if (pbAttr)
memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
}
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return scGetSetStruct.rv;
}
#include <syslog.h>
LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
LPCBYTE pbSendBuffer, DWORD cbSendLength,
LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
LPDWORD pcbRecvLength)
{
LONG rv;
int i;
DWORD dwContextIndex, dwChannelIndex;
PROFILE_START
if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
pcbRecvLength == NULL || pioSendPci == NULL)
return SCARD_E_INVALID_PARAMETER;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
if (rv == -1)
{
*pcbRecvLength = 0;
return SCARD_E_INVALID_HANDLE;
}
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_READER_UNAVAILABLE;
}
if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
|| (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INSUFFICIENT_BUFFER;
}
if ((cbSendLength > MAX_BUFFER_SIZE) || (*pcbRecvLength > MAX_BUFFER_SIZE))
{
unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
const sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
transmit_struct_extended *scTransmitStructExtended = (transmit_struct_extended *)buffer;
scTransmitStructExtended->hCard = hCard;
scTransmitStructExtended->cbSendLength = cbSendLength;
scTransmitStructExtended->pcbRecvLength = *pcbRecvLength;
scTransmitStructExtended->size = sizeof(*scTransmitStructExtended) + cbSendLength;
scTransmitStructExtended->pioSendPciProtocol = pioSendPci->dwProtocol;
scTransmitStructExtended->pioSendPciLength = pioSendPci->cbPciLength;
memcpy(scTransmitStructExtended->data, pbSendBuffer, cbSendLength);
secdebug("pcscd", "Extended APDU: initial request: hCard: 0x%08X, cbSendLength: %d",
hCard, cbSendLength);
secdebug("pcscd", " pcbRecvLength: %d", *pcbRecvLength);
if (pioRecvPci)
{
scTransmitStructExtended->pioRecvPciProtocol = pioRecvPci->dwProtocol;
scTransmitStructExtended->pioRecvPciLength = pioRecvPci->cbPciLength;
}
else
scTransmitStructExtended->pioRecvPciProtocol = SCARD_PROTOCOL_ANY;
size_t tsesize = scTransmitStructExtended->size; LogXxd(PCSC_LOG_INFO, "Extended APDU: sending: ", pbSendBuffer, cbSendLength);
htonlTransmitStructExtended(scTransmitStructExtended);
rv = WrapSHMWrite(SCARD_TRANSMIT_EXTENDED,
psContextMap[dwContextIndex].dwClientID,
tsesize,
SHMClientCommunicationTimeout(), buffer);
secdebug("pcscd", "Extended APDU: WrapSHMWrite result: %d [0x%08X]", rv, rv);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage((psharedSegmentMsg)buffer, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
scTransmitStructExtended = (transmit_struct_extended *)pmsgStruct->data;
ntohlTransmitStructExtended(scTransmitStructExtended);
secdebug("pcscd", "Extended APDU: reply received: hCard: 0x%08X, cbSendLength: %d",
hCard, cbSendLength);
secdebug("pcscd", " reply received: pcbRecvLength: %d, size: %llu",
scTransmitStructExtended->pcbRecvLength, scTransmitStructExtended->size);
secdebug("pcscd", " reply received: rv %d [0x%08X]",
scTransmitStructExtended -> rv, scTransmitStructExtended -> rv);
LogXxd(PCSC_LOG_INFO, "Extended APDU: received: ", scTransmitStructExtended->data, scTransmitStructExtended->pcbRecvLength);
if (scTransmitStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
{
rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
scTransmitStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
psContextMap[dwContextIndex].dwClientID,
SHMClientCommunicationTimeout());
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
}
if (scTransmitStructExtended -> rv == SCARD_S_SUCCESS)
{
memcpy(pbRecvBuffer, scTransmitStructExtended -> data,
scTransmitStructExtended -> pcbRecvLength);
memset(scTransmitStructExtended -> data, 0x00,
scTransmitStructExtended -> pcbRecvLength);
if (pioRecvPci)
{
pioRecvPci->dwProtocol = scTransmitStructExtended->pioRecvPciProtocol;
pioRecvPci->cbPciLength = scTransmitStructExtended->pioRecvPciLength;
}
}
*pcbRecvLength = scTransmitStructExtended -> pcbRecvLength;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
rv = scTransmitStructExtended -> rv;
}
else
{
transmit_struct scTransmitStruct;
sharedSegmentMsg msgStruct;
scTransmitStruct.hCard = hCard;
scTransmitStruct.cbSendLength = cbSendLength;
scTransmitStruct.pcbRecvLength = *pcbRecvLength;
scTransmitStruct.pioSendPciProtocol = pioSendPci->dwProtocol;
scTransmitStruct.pioSendPciLength = pioSendPci->cbPciLength;
memcpy(scTransmitStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
if (pioRecvPci)
{
scTransmitStruct.pioRecvPciProtocol = pioRecvPci->dwProtocol;
scTransmitStruct.pioRecvPciLength = pioRecvPci->cbPciLength;
}
else
scTransmitStruct.pioRecvPciProtocol = SCARD_PROTOCOL_ANY;
htonlTransmitStruct(&scTransmitStruct);
rv = WrapSHMWrite(SCARD_TRANSMIT,
psContextMap[dwContextIndex].dwClientID, sizeof(scTransmitStruct),
SHMClientCommunicationTimeout(), (void *) &scTransmitStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_NO_SERVICE;
}
rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(transmit_struct), SHMClientCommunicationTimeout());
memcpy(&scTransmitStruct, &msgStruct.data, sizeof(scTransmitStruct));
ntohlTransmitStruct(&scTransmitStruct);
if (rv == -1)
{
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_F_COMM_ERROR;
}
memset(scTransmitStruct.pbSendBuffer, 0x00, cbSendLength);
if (scTransmitStruct.rv == SCARD_S_SUCCESS)
{
memcpy(pbRecvBuffer, scTransmitStruct.pbRecvBuffer,
scTransmitStruct.pcbRecvLength);
memset(scTransmitStruct.pbRecvBuffer, 0x00,
scTransmitStruct.pcbRecvLength);
if (pioRecvPci)
{
pioRecvPci->dwProtocol = scTransmitStruct.pioRecvPciProtocol;
pioRecvPci->cbPciLength = scTransmitStruct.pioRecvPciLength;
}
}
*pcbRecvLength = scTransmitStruct.pcbRecvLength;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
rv = scTransmitStruct.rv;
}
PROFILE_END
return rv;
}
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups,
LPSTR mszReaders, LPDWORD pcchReaders)
{
DWORD dwReadersLen;
int i, lastChrPtr;
LONG dwContextIndex;
PROFILE_START
if (pcchReaders == NULL)
return SCARD_E_INVALID_PARAMETER;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
dwReadersLen = 0;
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
if (SharedReaderState_ReaderID(readerStates[i]) != 0)
dwReadersLen += strlen(SharedReaderState_ReaderName(readerStates[i])) + 1;
dwReadersLen += 1;
if ((mszReaders == NULL)
|| (*pcchReaders == 0))
{
*pcchReaders = dwReadersLen;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_S_SUCCESS;
}
if (*pcchReaders < dwReadersLen)
{
*pcchReaders = dwReadersLen;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
return SCARD_E_INSUFFICIENT_BUFFER;
}
lastChrPtr = 0;
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (SharedReaderState_ReaderID(readerStates[i]) != 0)
{
strcpy(&mszReaders[lastChrPtr], SharedReaderState_ReaderName(readerStates[i]));
lastChrPtr += strlen(SharedReaderState_ReaderName(readerStates[i]))+1;
}
}
mszReaders[lastChrPtr] = '\0';
*pcchReaders = dwReadersLen;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return SCARD_S_SUCCESS;
}
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
LPDWORD pcchGroups)
{
LONG rv = SCARD_S_SUCCESS;
LONG dwContextIndex;
PROFILE_START
const char ReaderGroup[] = "SCard$DefaultReaders";
const int dwGroups = strlen(ReaderGroup) + 2;
if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
return SCARD_E_NO_SERVICE;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
if (mszGroups)
{
if (*pcchGroups < dwGroups)
rv = SCARD_E_INSUFFICIENT_BUFFER;
else
{
memset(mszGroups, 0, dwGroups);
memcpy(mszGroups, ReaderGroup, strlen(ReaderGroup));
}
}
*pcchGroups = dwGroups;
SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
PROFILE_END
return rv;
}
LONG SCardCancel(SCARDCONTEXT hContext)
{
LONG dwContextIndex;
PROFILE_START
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
return SCARD_E_INVALID_HANDLE;
psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_RESUME;
PROFILE_END
return SCARD_S_SUCCESS;
}
LONG SCardIsValidContext(SCARDCONTEXT hContext)
{
LONG rv;
LONG dwContextIndex;
PROFILE_START
rv = SCARD_S_SUCCESS;
dwContextIndex = SCardGetContextIndice(hContext);
if (dwContextIndex == -1)
rv = SCARD_E_INVALID_HANDLE;
PROFILE_END
return rv;
}
static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
{
int i;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
{
if (psContextMap[i].hContext == 0)
{
psContextMap[i].hContext = hContext;
psContextMap[i].dwClientID = dwClientID;
psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
psContextMap[i].mMutex = malloc(sizeof(PCSCLITE_MUTEX));
SYS_MutexInit(psContextMap[i].mMutex);
return SCARD_S_SUCCESS;
}
}
return SCARD_E_NO_MEMORY;
}
static LONG SCardGetContextIndice(SCARDCONTEXT hContext)
{
LONG rv;
SCardLockThread();
rv = SCardGetContextIndiceTH(hContext);
SCardUnlockThread();
return rv;
}
static LONG SCardGetContextIndiceTH(SCARDCONTEXT hContext)
{
int i;
if (hContext == 0)
return -1;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
if (hContext == psContextMap[i].hContext)
return i;
return -1;
}
static LONG SCardRemoveContext(SCARDCONTEXT hContext)
{
LONG retIndice;
retIndice = SCardGetContextIndiceTH(hContext);
if (retIndice == -1)
return SCARD_E_INVALID_HANDLE;
else
{
int i;
psContextMap[retIndice].hContext = 0;
SHMClientCloseSession(psContextMap[retIndice].dwClientID);
psContextMap[retIndice].dwClientID = 0;
free(psContextMap[retIndice].mMutex);
psContextMap[retIndice].mMutex = NULL;
psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_RESUME;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
{
psContextMap[retIndice].psChannelMap[i].hCard = 0;
free(psContextMap[retIndice].psChannelMap[i].readerName);
psContextMap[retIndice].psChannelMap[i].readerName = NULL;
}
return SCARD_S_SUCCESS;
}
}
static LONG SCardAddHandle(SCARDHANDLE hCard, DWORD dwContextIndex,
LPSTR readerName)
{
int i;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
{
if (psContextMap[dwContextIndex].psChannelMap[i].hCard == 0)
{
psContextMap[dwContextIndex].psChannelMap[i].hCard = hCard;
psContextMap[dwContextIndex].psChannelMap[i].readerName = strdup(readerName);
return SCARD_S_SUCCESS;
}
}
return SCARD_E_NO_MEMORY;
}
static LONG SCardRemoveHandle(SCARDHANDLE hCard)
{
DWORD dwContextIndice, dwChannelIndice;
LONG rv;
rv = SCardGetIndicesFromHandle(hCard, &dwContextIndice, &dwChannelIndice);
if (rv == -1)
return SCARD_E_INVALID_HANDLE;
else
{
psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].hCard = 0;
free(psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName);
psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName = NULL;
return SCARD_S_SUCCESS;
}
}
static LONG SCardGetIndicesFromHandle(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
{
LONG rv;
if (0 == hCard)
return -1;
SCardLockThread();
rv = SCardGetIndicesFromHandleTH(hCard, pdwContextIndice, pdwChannelIndice);
SCardUnlockThread();
return rv;
}
static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
{
int i;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
{
if (psContextMap[i].hContext != 0)
{
int j;
for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
{
if (psContextMap[i].psChannelMap[j].hCard == hCard)
{
*pdwContextIndice = i;
*pdwChannelIndice = j;
return SCARD_S_SUCCESS;
}
}
}
}
return -1;
}
inline static LONG SCardLockThread(void)
{
return SYS_MutexLock(&clientMutex);
}
inline static LONG SCardUnlockThread(void)
{
return SYS_MutexUnLock(&clientMutex);
}
static LONG SCardCheckDaemonAvailability(void)
{
LONG rv;
struct stat statBuffer;
rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &statBuffer);
if (rv != 0)
{
Log1(PCSC_LOG_ERROR, "PCSC Not Running");
return SCARD_E_NO_SERVICE;
}
return SCARD_S_SUCCESS;
}
#ifdef __SUNPRO_C
#pragma fini (SCardUnload)
#endif
void DESTRUCTOR SCardUnload(void)
{
int i;
if (!isExecuted)
return;
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
{
if (readerStates[i] != NULL)
{
SYS_PublicMemoryUnmap(readerStates[i], sizeof(READER_STATE));
readerStates[i] = NULL;
}
}
SYS_CloseFile(mapAddr);
isExecuted = 0;
}
static int SCardInitializeOnce()
{
int pageSize;
int i;
SYS_Initialize();
mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0);
if (mapAddr < 0)
{
Log2(PCSC_LOG_ERROR, "Cannot open public shared file: %s",
PCSCLITE_PUBSHM_FILE);
return SCARD_E_NO_SERVICE;
}
pageSize = SYS_GetPageSize();
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
readerStates[i] =
(PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE),
mapAddr, (i * pageSize));
if (readerStates[i] == NULL)
{
Log1(PCSC_LOG_ERROR, "Cannot public memory map");
SYS_CloseFile(mapAddr);
return SCARD_F_INTERNAL_ERROR;
}
}
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
{
int j;
psContextMap[i].dwClientID = 0;
psContextMap[i].hContext = 0;
psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
psContextMap[i].mMutex = NULL;
for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
{
psContextMap[i].psChannelMap[j].hCard = 0;
psContextMap[i].psChannelMap[j].readerName = NULL;
}
}
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
{
if (psContextMap[i].dwClientID == 0)
break;
}
if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS)
{
return SCARD_E_NO_MEMORY;
}
return SCARD_S_SUCCESS;
}
static int SHMClientCommunicationTimeout()
{
static int baseTimeout = 12000; volatile int timeOut = baseTimeout;
return timeOut;
}