#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "wintypes.h"
#include "pcsclite.h"
#include "ifdhandler.h"
#include "debuglog.h"
#include "thread_generic.h"
#include "readerfactory.h"
#include "eventhandler.h"
#include "dyn_generic.h"
#include "sys_generic.h"
#include "ifdwrapper.h"
#include "prothandler.h"
#include "readerstate.h"
#include <security_utilities/debugging.h>
static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
void EHStatusHandlerThread(PREADER_CONTEXT);
LONG EHInitializeEventStructures(void)
{
int fd, i, pageSize;
fd = 0;
i = 0;
pageSize = 0;
fd = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDWR | O_CREAT , 00644);
if (fd < 0)
{
Log3(PCSC_LOG_CRITICAL, "Cannot create public shared file %s: %s",
PCSCLITE_PUBSHM_FILE, strerror(errno));
exit(1);
}
SYS_Chmod(PCSCLITE_PUBSHM_FILE,
S_IRGRP | S_IREAD | S_IWRITE | S_IROTH);
pageSize = SYS_GetPageSize();
int rx = ftruncate(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS);
if (rx)
Log3(PCSC_LOG_CRITICAL, "Cannot truncate public shared file %d: %s",
errno, strerror(errno));
SYS_SeekFile(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS);
SYS_WriteFile(fd, "", 1);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
readerStates[i] = (PREADER_STATE)
SYS_MemoryMap(sizeof(READER_STATE), fd, (i * pageSize));
if (readerStates[i] == MAP_FAILED)
{
Log3(PCSC_LOG_CRITICAL, "Cannot memory map public shared file %s: %s",
PCSCLITE_PUBSHM_FILE, strerror(errno));
exit(1);
}
memset((readerStates[i])->readerName, 0, MAX_READERNAME);
memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE);
(readerStates[i])->readerID = 0;
(readerStates[i])->readerState = 0;
(readerStates[i])->lockState = 0;
(readerStates[i])->readerSharing = 0;
(readerStates[i])->cardAtrLength = 0;
(readerStates[i])->cardProtocol = SCARD_PROTOCOL_UNSET; }
return SCARD_S_SUCCESS;
}
LONG EHDestroyEventHandler(PREADER_CONTEXT rContext)
{
if (NULL == rContext->readerState)
{
Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)");
return SCARD_S_SUCCESS;
}
PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
if ((rContext->pthThread == 0) || !rs || (rs->readerNameLength() == 0))
{
Log1(PCSC_LOG_INFO, "Thread already stomped.");
return SCARD_S_SUCCESS;
}
secdebug("pcscd", "EHDestroyEventHandler: pthThread: %p, reader name len: %ld",
rContext->pthThread, rs->readerNameLength());
rs->xreaderNameClear();
rs->xcardAtrClear();
rs->xreaderID(0);
rs->xreaderState(0);
rs->xlockState(0);
rs->sharing(0);
rs->xcardAtrLength(0);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
ReaderContextLock(rContext);
Log1(PCSC_LOG_INFO, "Stomping thread.");
int ix;
for (ix = 0; (ix < 100) && ReaderContextIsLocked(rContext); ++ix)
{
SYS_USleep(50000);
}
secdebug("pcscd", "EHDestroyEventHandler: post-stop dwLockId: %d", rContext->dwLockId);
rContext->pthThread = 0;
Log1(PCSC_LOG_INFO, "Thread stomped.");
return SCARD_S_SUCCESS;
}
LONG EHSpawnEventHandler(PREADER_CONTEXT rContext)
{
LONG rv;
DWORD dwStatus = 0;
int i;
UCHAR ucAtr[MAX_ATR_SIZE];
DWORD dwAtrLen = 0;
secdebug("pcscd", "EHSpawnEventHandler: rContext: 0x%p", rContext);
rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
return SCARD_F_UNKNOWN_ERROR;
}
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
PCSCD::SharedReaderState *rstmp = PCSCD::SharedReaderState::overlay(readerStates[i]);
if (rstmp->xreaderID() == 0)
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
return SCARD_F_INTERNAL_ERROR;
PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(readerStates[i]);
rContext->readerState = readerStates[i];
rs->xreaderName(rContext->lpcReader);
rs->xcardAtr(ucAtr, dwAtrLen);
rs->xreaderID(i + 100);
rs->xreaderState(dwStatus);
rs->sharing(rContext->dwContexts);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
rv = SYS_ThreadCreate(&rContext->pthThread, THREAD_ATTR_DETACHED,
(PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
secdebug("pcscd", "EHSpawnEventHandler after thread create: %d [%04X]", rv, rv);
if (rv == 1)
return SCARD_S_SUCCESS;
else
return SCARD_E_NO_MEMORY;
}
void EHStatusHandlerThread(PREADER_CONTEXT rContext)
{
LONG rv;
LPCSTR lpcReader;
DWORD dwStatus, dwReaderSharing;
DWORD dwCurrentState;
int pageSize = SYS_GetPageSize();
dwStatus = 0;
dwReaderSharing = 0;
dwCurrentState = 0;
secdebug("pcscd", "EHStatusHandlerThread: rContext: 0x%p", rContext);
lpcReader = rContext->lpcReader;
PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
DWORD tmpCardAtrLength = MAX_ATR_SIZE;
rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);
secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDStatusICC: %d [%04X]", rv, rv);
if (dwStatus & SCARD_PRESENT)
{
tmpCardAtrLength = MAX_ATR_SIZE;
rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDPowerICC: %d [%04X]", rv, rv);
if (rv == IFD_SUCCESS)
{
rs->xcardAtrLength(tmpCardAtrLength);
dwStatus |= SCARD_PRESENT;
dwStatus &= ~SCARD_ABSENT;
dwStatus |= SCARD_POWERED;
dwStatus |= SCARD_NEGOTIABLE;
dwStatus &= ~SCARD_SPECIFIC;
dwStatus &= ~SCARD_SWALLOWED;
dwStatus &= ~SCARD_UNKNOWN;
if (rs->xcardAtrLength() > 0)
{
LogXxd(PCSC_LOG_INFO, "Card ATR: ",
rs->xcardAtr(),
rs->xcardAtrLength());
}
else
Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
}
else
{
dwStatus |= SCARD_PRESENT;
dwStatus &= ~SCARD_ABSENT;
dwStatus |= SCARD_SWALLOWED;
dwStatus &= ~SCARD_POWERED;
dwStatus &= ~SCARD_NEGOTIABLE;
dwStatus &= ~SCARD_SPECIFIC;
dwStatus &= ~SCARD_UNKNOWN;
Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
}
dwCurrentState = SCARD_PRESENT;
}
else
{
dwStatus |= SCARD_ABSENT;
dwStatus &= ~SCARD_PRESENT;
dwStatus &= ~SCARD_POWERED;
dwStatus &= ~SCARD_NEGOTIABLE;
dwStatus &= ~SCARD_SPECIFIC;
dwStatus &= ~SCARD_SWALLOWED;
dwStatus &= ~SCARD_UNKNOWN;
rs->xcardAtrLength(0);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
dwCurrentState = SCARD_ABSENT;
}
rs->xreaderState(dwStatus);
dwReaderSharing = rContext->dwContexts;
rs->sharing(dwReaderSharing);
SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
while (1)
{
dwStatus = 0;
if (!rContext->vHandle)
{
secdebug("pcscd", "EHStatusHandlerThread: lost dynamic callbacks ??");
ReaderContextUnlock(rContext);
SYS_ThreadDetach(rContext->pthThread);
SYS_ThreadExit(0);
}
DWORD tmpCardAtrLength = MAX_ATR_SIZE;
rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);
if (rv != SCARD_S_SUCCESS)
{
Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
DWORD readerStateTmp = rs->xreaderState();
readerStateTmp &= ~SCARD_ABSENT;
readerStateTmp &= ~SCARD_PRESENT;
readerStateTmp &= ~SCARD_POWERED;
readerStateTmp &= ~SCARD_NEGOTIABLE;
readerStateTmp &= ~SCARD_SPECIFIC;
readerStateTmp &= ~SCARD_SWALLOWED;
readerStateTmp |= SCARD_UNKNOWN;
rs->xcardAtrLength(0);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
rs->xreaderState(readerStateTmp);
dwCurrentState = SCARD_UNKNOWN;
SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
}
if (dwStatus & SCARD_ABSENT)
{
if (dwCurrentState == SCARD_PRESENT ||
dwCurrentState == SCARD_UNKNOWN)
{
Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
RFSetReaderEventState(rContext, SCARD_REMOVED);
rs->xcardAtrLength(0);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
DWORD readerStateTmp = rs->xreaderState();
readerStateTmp |= SCARD_ABSENT;
readerStateTmp &= ~SCARD_UNKNOWN;
readerStateTmp &= ~SCARD_PRESENT;
readerStateTmp &= ~SCARD_POWERED;
readerStateTmp &= ~SCARD_NEGOTIABLE;
readerStateTmp &= ~SCARD_SWALLOWED;
readerStateTmp &= ~SCARD_SPECIFIC;
rs->xreaderState(readerStateTmp);
dwCurrentState = SCARD_ABSENT;
SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
}
}
else if (dwStatus & SCARD_PRESENT)
{
if (dwCurrentState == SCARD_ABSENT ||
dwCurrentState == SCARD_UNKNOWN)
{
SYS_USleep(PCSCLITE_STATUS_WAIT);
DWORD tmpCardAtrLength = MAX_ATR_SIZE;
rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);
rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
secdebug("pcscd", "EHStatusHandlerThread: power-and-reset call to IFDPowerICC: %d [%04X]", rv, rv);
DWORD readerStateTmp = rs->xreaderState();
if (rv == IFD_SUCCESS)
{
rs->xcardAtrLength(tmpCardAtrLength);
readerStateTmp |= SCARD_PRESENT;
readerStateTmp &= ~SCARD_ABSENT;
readerStateTmp |= SCARD_POWERED;
readerStateTmp |= SCARD_NEGOTIABLE;
readerStateTmp &= ~SCARD_SPECIFIC;
readerStateTmp &= ~SCARD_UNKNOWN;
readerStateTmp &= ~SCARD_SWALLOWED;
rs->xreaderState(readerStateTmp);
RFSetReaderEventState(rContext, SCARD_RESET);
}
else
{
readerStateTmp |= SCARD_PRESENT;
readerStateTmp &= ~SCARD_ABSENT;
readerStateTmp |= SCARD_SWALLOWED;
readerStateTmp &= ~SCARD_POWERED;
readerStateTmp &= ~SCARD_NEGOTIABLE;
readerStateTmp &= ~SCARD_SPECIFIC;
readerStateTmp &= ~SCARD_UNKNOWN;
rs->xreaderState(readerStateTmp);
rs->xcardAtrLength(0);
}
dwCurrentState = SCARD_PRESENT;
SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
if (rv == IFD_SUCCESS)
{
if (rs->xcardAtrLength() > 0)
LogXxd(PCSC_LOG_INFO, "Card ATR: ", rs->xcardAtr(), rs->xcardAtrLength());
else
Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
}
else
Log1(PCSC_LOG_ERROR,"Error powering up card.");
}
}
if (ReaderContextIsLocked(rContext))
{
secdebug("pcscd", "EHStatusHandlerThread: parent requested shutdown");
ReaderContextUnlock(rContext);
SYS_ThreadDetach(rContext->pthThread);
SYS_ThreadExit(0);
}
if (dwReaderSharing != (uint32_t)rContext->dwContexts)
{
dwReaderSharing = rContext->dwContexts;
rs->sharing(dwReaderSharing);
SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
}
SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
}
}
void EHSetSharingEvent(PREADER_CONTEXT rContext, DWORD dwValue)
{
PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
rs->xlockState(dwValue);
}