#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <fcntl.h>
#include "wintypes.h"
#include "pcsclite.h"
#include "ifdhandler.h"
#include "debuglog.h"
#include "thread_generic.h"
#include "readerfactory.h"
#include "dyn_generic.h"
#include "sys_generic.h"
#include "eventhandler.h"
#include "ifdwrapper.h"
#include "readerState.h"
#include <security_utilities/debugging.h>
#include <mach/machine.h>
#include <sys/sysctl.h>
static cpu_type_t architectureForPid(pid_t pid);
#ifndef PCSCLITE_HP_BASE_PORT
#define PCSCLITE_HP_BASE_PORT 0x200000
#endif
static LONG RFLoadReader(PREADER_CONTEXT);
static LONG RFUnBindFunctions(PREADER_CONTEXT);
static LONG RFUnloadReader(PREADER_CONTEXT);
static PREADER_CONTEXT sReadersContexts[PCSCLITE_MAX_READERS_CONTEXTS];
static DWORD dwNumReadersContexts = 0;
static DWORD lastLockID = 0;
static PCSCLITE_MUTEX_T sReadersContextsLock = NULL;
static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader,
DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice);
static void ReaderContextDestructor(PREADER_CONTEXT ctx);
static void ReaderContextFree(PREADER_CONTEXT ctx);
static void ReaderContextClear(PREADER_CONTEXT ctx);
static int ReaderContextInsert(PREADER_CONTEXT ctx);
static int ReaderContextRemove(PREADER_CONTEXT ctx);
static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort);
static int ReaderSlotCount(PREADER_CONTEXT ctx);
static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot);
static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index);
static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe);
static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader,
DWORD dwPort, LPCSTR lpcLibrary);
static int ReaderCheckArchitecture(LPCSTR lpcLibrary);
static cpu_type_t architectureForPid(pid_t pid);
static int architectureMatch(const char *name);
extern int DBUpdateReaders(char *readerconf);
LONG RFAllocateReaderSpace()
{
int i;
sReadersContextsLock = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
SYS_MutexInit(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
sReadersContexts[i] = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
return EHInitializeEventStructures();
}
LONG RFAddReader(LPSTR lpcReader, DWORD dwPort, LPSTR lpcLibrary, LPSTR lpcDevice)
{
int slotCount;
LONG rv = SCARD_E_NO_MEMORY;
int slot;
PREADER_CONTEXT baseContext = NULL;
if ((lpcReader == NULL) || (lpcLibrary == NULL) || (lpcDevice == NULL))
return SCARD_E_INVALID_VALUE;
if (strlen(lpcReader) >= MAX_READERNAME)
{
Log3(PCSC_LOG_ERROR, "Reader name too long: %d chars instead of max %d",
strlen(lpcReader), MAX_READERNAME);
return SCARD_E_INVALID_VALUE;
}
if (strlen(lpcLibrary) >= MAX_LIBNAME)
{
Log3(PCSC_LOG_ERROR, "Library name too long: %d chars instead of max %d",
strlen(lpcLibrary), MAX_LIBNAME);
return SCARD_E_INVALID_VALUE;
}
if (strlen(lpcDevice) >= MAX_DEVICENAME)
{
Log3(PCSC_LOG_ERROR, "Device name too long: %d chars instead of max %d",
strlen(lpcDevice), MAX_DEVICENAME);
return SCARD_E_INVALID_VALUE;
}
rv = ReaderContextCheckDuplicateReader(lpcReader, dwPort);
if (rv)
return rv;
rv = ReaderContextInsert(NULL);
if (rv != SCARD_S_SUCCESS)
return rv;
baseContext = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
rv = ReaderContextConstructor(baseContext, lpcReader, dwPort, lpcLibrary, lpcDevice);
if (rv != SCARD_S_SUCCESS)
goto xit;
rv = ReaderCheckForClone(baseContext, lpcReader, dwPort, lpcLibrary);
if (rv != SCARD_S_SUCCESS)
goto xit;
rv = ReaderCheckArchitecture(lpcLibrary);
if (rv != SCARD_S_SUCCESS)
goto xit;
rv = RFInitializeReader(baseContext);
if (rv != SCARD_S_SUCCESS)
goto xit;
rv = ReaderContextInsert(baseContext);
if (rv != SCARD_S_SUCCESS)
goto xit;
rv = EHSpawnEventHandler(baseContext);
if (rv != SCARD_S_SUCCESS)
goto xit;
slotCount = ReaderSlotCount(baseContext);
if (slotCount <= 1)
return SCARD_S_SUCCESS;
BOOL baseIsThreadSafe = ReaderDriverIsThreadSafe(baseContext, 1);
for (slot = 1; slot < slotCount; slot++)
{
rv = ReaderContextInsert(NULL);
if (rv != SCARD_S_SUCCESS)
{
rv = RFRemoveReader(lpcReader, dwPort);
return rv;
}
PREADER_CONTEXT ctxSlot = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
rv = ReaderContextConstructor(ctxSlot, lpcReader, dwPort, lpcLibrary, lpcDevice);
if (rv != SCARD_S_SUCCESS)
{
ReaderContextDestructor(ctxSlot);
free(ctxSlot);
return rv;
}
ReaderContextDuplicateSlot(baseContext, ctxSlot, slot, baseIsThreadSafe);
rv = RFInitializeReader(ctxSlot);
if (rv != SCARD_S_SUCCESS)
{
Log2(PCSC_LOG_ERROR, "%s init failed.", lpcReader);
ReaderContextDestructor(ctxSlot);
free(ctxSlot);
return rv;
}
rv = ReaderContextInsert(ctxSlot);
if (rv != SCARD_S_SUCCESS)
return rv;
rv = EHSpawnEventHandler(ctxSlot);
if (rv != SCARD_S_SUCCESS)
return rv;
EHSpawnEventHandler(ctxSlot);
}
xit:
if (rv != SCARD_S_SUCCESS)
{
Log3(PCSC_LOG_ERROR, "RFAddReader: %s init failed: %d", lpcReader, rv);
ReaderContextDestructor(baseContext);
free(baseContext);
}
return rv;
}
LONG RFRemoveReader(LPSTR lpcReader, DWORD dwPort)
{
LONG rv;
PREADER_CONTEXT tmpContext = NULL;
if (lpcReader == 0)
return SCARD_E_INVALID_VALUE;
secdebug("pcscd", "RFRemoveReader: removing %s", lpcReader);
while ((rv = RFReaderInfoNamePort(dwPort, lpcReader, &tmpContext)) == SCARD_S_SUCCESS)
{
rv = EHDestroyEventHandler(tmpContext);
rv = RFUnInitializeReader(tmpContext);
if (rv != SCARD_S_SUCCESS)
return rv;
ReaderContextRemove(tmpContext);
}
return SCARD_S_SUCCESS;
}
LONG RFSetReaderName(PREADER_CONTEXT rContext, LPCSTR readerName,
LPCSTR libraryName, DWORD dwPort, DWORD dwSlot)
{
LONG parent = -1;
DWORD valueLength;
int currentDigit = -1;
int supportedChannels = 0;
int usedDigits[PCSCLITE_MAX_READERS_CONTEXTS] = {0,};
int i;
if ((0 == dwSlot) && (dwNumReadersContexts != 0))
{
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (sReadersContexts[i] == NULL)
continue;
if ((sReadersContexts[i])->vHandle != 0)
{
if (strcmp((sReadersContexts[i])->lpcLibrary, libraryName) == 0)
{
UCHAR tagValue[1];
LONG ret;
valueLength = sizeof(tagValue);
ret = IFDGetCapabilities((sReadersContexts[i]),
TAG_IFD_SIMULTANEOUS_ACCESS,
&valueLength, tagValue);
if ((ret == IFD_SUCCESS) && (valueLength == 1) &&
(tagValue[0] > 1))
{
supportedChannels = tagValue[0];
Log2(PCSC_LOG_INFO,
"Support %d simultaneous readers", tagValue[0]);
}
else
supportedChannels = 1;
if (((((sReadersContexts[i])->dwPort & 0xFFFF0000) ==
PCSCLITE_HP_BASE_PORT)
&& ((sReadersContexts[i])->dwPort != dwPort))
|| (supportedChannels > 1))
{
char *lpcReader = sReadersContexts[i]->lpcReader;
parent = i;
currentDigit = strtol(lpcReader + strlen(lpcReader) - 5, NULL, 16);
usedDigits[currentDigit] = 1;
}
}
}
}
}
i = 0;
if (currentDigit != -1)
{
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (usedDigits[i] == 0)
break;
}
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
{
Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CONTEXTS);
return -2;
}
if (i >= supportedChannels)
{
Log3(PCSC_LOG_ERROR, "Driver %s does not support more than "
"%d reader(s). Maybe the driver should support "
"TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels);
return -2;
}
}
sprintf(rContext->lpcReader, "%s %02X %02X", readerName, i, dwSlot);
rContext->dwSlot = (i << 16) + dwSlot;
return parent;
}
LONG RFReaderInfo(LPSTR lpcReader, PREADER_CONTEXT * sReader)
{
int i;
LONG rv = SCARD_E_UNKNOWN_READER;
if (lpcReader == 0)
return SCARD_E_UNKNOWN_READER;
SYS_MutexLock(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
{
if (strcmp(lpcReader, (sReadersContexts[i])->lpcReader) == 0)
{
*sReader = sReadersContexts[i];
rv = SCARD_S_SUCCESS;
break;
}
}
}
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
LONG RFReaderInfoNamePort(DWORD dwPort, LPSTR lpcReader,
PREADER_CONTEXT * sReader)
{
int ix;
LONG rv = SCARD_E_INVALID_VALUE;
SYS_MutexLock(sReadersContextsLock);
for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
{
if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0) &&
ReaderNameMatchForIndex(dwPort, lpcReader, ix))
{
*sReader = sReadersContexts[ix];
rv = SCARD_S_SUCCESS;
break;
}
}
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
LONG RFReaderInfoById(DWORD dwIdentity, PREADER_CONTEXT * sReader)
{
int i;
LONG rv = SCARD_E_INVALID_VALUE;
dwIdentity = dwIdentity >> (sizeof(DWORD) / 2) * 8;
dwIdentity = dwIdentity << (sizeof(DWORD) / 2) * 8;
SYS_MutexLock(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if ((sReadersContexts[i]!=NULL) && (dwIdentity == (sReadersContexts[i])->dwIdentity))
{
*sReader = sReadersContexts[i];
rv = SCARD_S_SUCCESS;
break;
}
}
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
static LONG RFLoadReader(PREADER_CONTEXT rContext)
{
if (rContext->vHandle != 0)
{
Log1(PCSC_LOG_ERROR, "Warning library pointer not NULL");
return SCARD_S_SUCCESS;
}
return DYN_LoadLibrary(&rContext->vHandle, rContext->lpcLibrary);
}
LONG RFBindFunctions(PREADER_CONTEXT rContext)
{
int rv1, rv2, rv3;
void *f;
Log1(PCSC_LOG_INFO, "Binding driver functions");
rv1 = DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
rv2 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel");
rv3 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName");
if (rv1 != SCARD_S_SUCCESS && rv2 != SCARD_S_SUCCESS && rv3 != SCARD_S_SUCCESS)
{
Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
exit(1);
} else if (rv1 == SCARD_S_SUCCESS)
{
rContext->dwVersion = IFD_HVERSION_1_0;
} else if (rv3 == SCARD_S_SUCCESS)
{
rContext->dwVersion = IFD_HVERSION_3_0;
}
else
{
rContext->dwVersion = IFD_HVERSION_2_0;
}
if (rContext->dwVersion == IFD_HVERSION_1_0)
{
Log1(PCSC_LOG_INFO, "Loading IFD Handler 1.0");
#define GET_ADDRESS_OPTIONALv1(field, function, code) \
{ \
void *f1 = NULL; \
if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFD_" #function)) \
{ \
code \
} \
rContext->psFunctions.psFunctions_v1.pvf ## field = f1; \
}
#define GET_ADDRESSv1(field, function) \
GET_ADDRESS_OPTIONALv1(field, function, \
Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #function ); \
exit(1); )
DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
rContext->psFunctions.psFunctions_v1.pvfCreateChannel = f;
if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f,
"IO_Close_Channel"))
{
Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
exit(1);
}
rContext->psFunctions.psFunctions_v1.pvfCloseChannel = f;
GET_ADDRESSv1(GetCapabilities, Get_Capabilities)
GET_ADDRESSv1(SetCapabilities, Set_Capabilities)
GET_ADDRESSv1(PowerICC, Power_ICC)
GET_ADDRESSv1(TransmitToICC, Transmit_to_ICC)
GET_ADDRESSv1(ICCPresence, Is_ICC_Present)
GET_ADDRESS_OPTIONALv1(SetProtocolParameters, Set_Protocol_Parameters, )
}
else if (rContext->dwVersion == IFD_HVERSION_2_0)
{
#define GET_ADDRESS_OPTIONALv2(s, code) \
{ \
void *f1 = NULL; \
if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
{ \
code \
} \
rContext->psFunctions.psFunctions_v2.pvf ## s = f1; \
}
#define GET_ADDRESSv2(s) \
GET_ADDRESS_OPTIONALv2(s, \
Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
exit(1); )
Log1(PCSC_LOG_INFO, "Loading IFD Handler 2.0");
GET_ADDRESSv2(CreateChannel)
GET_ADDRESSv2(CloseChannel)
GET_ADDRESSv2(GetCapabilities)
GET_ADDRESSv2(SetCapabilities)
GET_ADDRESSv2(PowerICC)
GET_ADDRESSv2(TransmitToICC)
GET_ADDRESSv2(ICCPresence)
GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
GET_ADDRESSv2(Control)
}
else if (rContext->dwVersion == IFD_HVERSION_3_0)
{
#define GET_ADDRESS_OPTIONALv3(s, code) \
{ \
void *f1 = NULL; \
if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
{ \
code \
} \
rContext->psFunctions.psFunctions_v3.pvf ## s = f1; \
}
#define GET_ADDRESSv3(s) \
GET_ADDRESS_OPTIONALv3(s, \
Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
exit(1); )
Log1(PCSC_LOG_INFO, "Loading IFD Handler 3.0");
GET_ADDRESSv2(CreateChannel)
GET_ADDRESSv2(CloseChannel)
GET_ADDRESSv2(GetCapabilities)
GET_ADDRESSv2(SetCapabilities)
GET_ADDRESSv2(PowerICC)
GET_ADDRESSv2(TransmitToICC)
GET_ADDRESSv2(ICCPresence)
GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
GET_ADDRESSv3(CreateChannelByName)
GET_ADDRESSv3(Control)
}
else
{
Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0");
exit(1);
}
return SCARD_S_SUCCESS;
}
static LONG RFUnBindFunctions(PREADER_CONTEXT rContext)
{
Log1(PCSC_LOG_INFO, "Unbinding driver functions");
memset(&rContext->psFunctions, 0, sizeof(rContext->psFunctions));
return SCARD_S_SUCCESS;
}
static LONG RFUnloadReader(PREADER_CONTEXT rContext)
{
Log1(PCSC_LOG_INFO, "Unloading reader driver.");
if (*rContext->pdwFeeds == 1)
{
Log1(PCSC_LOG_INFO, "--- closing dynamic library");
DYN_CloseLibrary(&rContext->vHandle);
}
rContext->vHandle = 0;
return SCARD_S_SUCCESS;
}
LONG RFCheckSharing(DWORD hCard)
{
LONG rv;
PREADER_CONTEXT rContext = NULL;
rv = RFReaderInfoById(hCard, &rContext);
if (rv != SCARD_S_SUCCESS)
return rv;
if (rContext->dwLockId == 0 || rContext->dwLockId == hCard)
return SCARD_S_SUCCESS;
else
{
secdebug("pcscd", "RFCheckSharing: sharing violation, dwLockId: 0x%02X", rContext->dwLockId);
return SCARD_E_SHARING_VIOLATION;
}
}
LONG RFLockSharing(DWORD hCard)
{
PREADER_CONTEXT rContext = NULL;
RFReaderInfoById(hCard, &rContext);
if (RFCheckSharing(hCard) == SCARD_S_SUCCESS)
{
EHSetSharingEvent(rContext, 1);
rContext->dwLockId = hCard;
}
else
return SCARD_E_SHARING_VIOLATION;
return SCARD_S_SUCCESS;
}
LONG RFUnlockSharing(DWORD hCard)
{
PREADER_CONTEXT rContext = NULL;
LONG rv;
rv = RFReaderInfoById(hCard, &rContext);
if (rv != SCARD_S_SUCCESS)
return rv;
rv = RFCheckSharing(hCard);
if (rv != SCARD_S_SUCCESS)
return rv;
EHSetSharingEvent(rContext, 0);
rContext->dwLockId = 0;
return SCARD_S_SUCCESS;
}
LONG RFUnblockContext(SCARDCONTEXT hContext)
{
int i;
SYS_MutexLock(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
if (sReadersContexts[i])
(sReadersContexts[i])->dwBlockStatus = hContext;
SYS_MutexUnLock(sReadersContextsLock);
return SCARD_S_SUCCESS;
}
LONG RFUnblockReader(PREADER_CONTEXT rContext)
{
rContext->dwBlockStatus = BLOCK_STATUS_RESUME;
return SCARD_S_SUCCESS;
}
LONG RFInitializeReader(PREADER_CONTEXT rContext)
{
LONG rv;
Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s",
rContext->lpcReader, rContext->lpcLibrary);
rv = RFLoadReader(rContext);
if (rv != SCARD_S_SUCCESS)
{
Log2(PCSC_LOG_ERROR, "RFLoadReader failed: %X", rv);
return rv;
}
rv = RFBindFunctions(rContext);
if (rv != SCARD_S_SUCCESS)
{
Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: %X", rv);
RFUnloadReader(rContext);
return rv;
}
rv = IFDOpenIFD(rContext);
if (rv != IFD_SUCCESS)
{
Log3(PCSC_LOG_CRITICAL, "Open Port %X Failed (%s)",
rContext->dwPort, rContext->lpcDevice);
RFUnBindFunctions(rContext);
RFUnloadReader(rContext);
return SCARD_E_INVALID_TARGET;
}
return SCARD_S_SUCCESS;
}
LONG RFUnInitializeReader(PREADER_CONTEXT rContext)
{
Log2(PCSC_LOG_INFO, "Attempting shutdown of %s.",
rContext->lpcReader);
IFDCloseIFD(rContext);
RFUnBindFunctions(rContext);
RFUnloadReader(rContext);
return SCARD_S_SUCCESS;
}
SCARDHANDLE RFCreateReaderHandle(PREADER_CONTEXT rContext)
{
USHORT randHandle;
randHandle = SYS_Random(SYS_GetSeed(), 10, 65000);
while (1)
{
int i;
SYS_MutexLock(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
{
int j;
for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
{
if ((rContext->dwIdentity + randHandle) ==
(sReadersContexts[i])->psHandles[j].hCard)
{
randHandle = SYS_Random(randHandle, 10, 65000);
continue;
}
}
}
}
SYS_MutexUnLock(sReadersContextsLock);
if (i == PCSCLITE_MAX_READERS_CONTEXTS)
break;
}
return rContext->dwIdentity + randHandle;
}
LONG RFFindReaderHandle(SCARDHANDLE hCard)
{
int i;
LONG rv = SCARD_E_INVALID_HANDLE;
SYS_MutexLock(sReadersContextsLock);
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
{
int j;
for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
{
if (hCard == (sReadersContexts[i])->psHandles[j].hCard)
{
rv = SCARD_S_SUCCESS;
goto xit;
}
}
}
}
xit:
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
LONG RFDestroyReaderHandle(SCARDHANDLE hCard)
{
return SCARD_S_SUCCESS;
}
LONG RFAddReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
{
int i;
for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
{
if (rContext->psHandles[i].hCard == 0)
{
rContext->psHandles[i].hCard = hCard;
rContext->psHandles[i].dwEventStatus = 0;
break;
}
}
if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
return SCARD_E_INSUFFICIENT_BUFFER;
return SCARD_S_SUCCESS;
}
LONG RFRemoveReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
{
int i;
for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
{
if (rContext->psHandles[i].hCard == hCard)
{
rContext->psHandles[i].hCard = 0;
rContext->psHandles[i].dwEventStatus = 0;
break;
}
}
if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
return SCARD_E_INVALID_HANDLE;
return SCARD_S_SUCCESS;
}
LONG RFSetReaderEventState(PREADER_CONTEXT rContext, DWORD dwEvent)
{
int i;
for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
{
if (rContext->psHandles[i].hCard != 0)
rContext->psHandles[i].dwEventStatus = dwEvent;
}
return SCARD_S_SUCCESS;
}
LONG RFCheckReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
{
int i;
for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
{
if (rContext->psHandles[i].hCard == hCard)
{
if (rContext->psHandles[i].dwEventStatus == SCARD_REMOVED)
return SCARD_W_REMOVED_CARD;
else
{
if (rContext->psHandles[i].dwEventStatus == SCARD_RESET)
return SCARD_W_RESET_CARD;
else
{
if (rContext->psHandles[i].dwEventStatus == 0)
return SCARD_S_SUCCESS;
else
return SCARD_E_INVALID_VALUE;
}
}
}
}
return SCARD_E_INVALID_HANDLE;
}
LONG RFClearReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
{
int i;
for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
{
if (rContext->psHandles[i].hCard == hCard)
rContext->psHandles[i].dwEventStatus = 0;
}
if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
return SCARD_E_INVALID_HANDLE;
return SCARD_S_SUCCESS;
}
LONG RFCheckReaderStatus(PREADER_CONTEXT rContext)
{
LONG rx = 0;
rx = ((rContext == NULL) || (rContext->readerState == NULL) ||
(SharedReaderState_State(rContext->readerState) & SCARD_UNKNOWN))?SCARD_E_READER_UNAVAILABLE:SCARD_S_SUCCESS;
return rx;
}
void RFCleanupReaders(int shouldExit)
{
int i;
Log1(PCSC_LOG_INFO, "entering cleaning function");
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if ((sReadersContexts[i]!=NULL) && (sReadersContexts[i]->vHandle != 0))
{
LONG rv;
char lpcStripReader[MAX_READERNAME];
Log2(PCSC_LOG_INFO, "Stopping reader: %s",
sReadersContexts[i]->lpcReader);
strncpy(lpcStripReader, (sReadersContexts[i])->lpcReader,
sizeof(lpcStripReader));
lpcStripReader[strlen(lpcStripReader) - 6] = '\0';
rv = RFRemoveReader(lpcStripReader, sReadersContexts[i]->dwPort);
if (rv != SCARD_S_SUCCESS)
Log2(PCSC_LOG_ERROR, "RFRemoveReader error: 0x%08X", rv);
}
}
secdebug("pcscd", "RFCleanupReaders: exiting cleaning function");
if (shouldExit)
exit(0);
}
int RFStartSerialReaders(const char *readerconf)
{
return DBUpdateReaders((char *)readerconf);
}
void RFReCheckReaderConf(void)
{
}
void RFSuspendAllReaders()
{
int ix;
secdebug("pcscd", "RFSuspendAllReaders");
Log1(PCSC_LOG_DEBUG, "zzzzz zzzzz zzzzz zzzzz RFSuspendAllReaders zzzzz zzzzz zzzzz zzzzz ");
for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
{
if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0))
{
EHDestroyEventHandler(sReadersContexts[ix]);
IFDCloseIFD(sReadersContexts[ix]);
}
}
}
void RFAwakeAllReaders(void)
{
LONG rv = IFD_SUCCESS;
int i;
secdebug("pcscd", "RFAwakeAllReaders");
Log1(PCSC_LOG_DEBUG, "----- ----- ----- ----- RFAwakeAllReaders ----- ----- ----- ----- ");
for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
{
if (sReadersContexts[i]==NULL)
continue;
if ( ((sReadersContexts[i])->vHandle != 0) &&
((sReadersContexts[i])->pthThread == 0) )
{
int jx;
int alreadyInitializedFlag = 0;
for (jx=0; jx < i; jx++)
{
if (((sReadersContexts[jx])->vHandle == (sReadersContexts[i])->vHandle)&&
((sReadersContexts[jx])->dwPort == (sReadersContexts[i])->dwPort))
{
alreadyInitializedFlag = 1;
}
}
if (!alreadyInitializedFlag)
{
SYS_USleep(100000L); rv = IFDOpenIFD(sReadersContexts[i]);
}
RFSetReaderEventState(sReadersContexts[i], SCARD_RESET);
if (rv != IFD_SUCCESS)
{
Log3(PCSC_LOG_ERROR, "Open Port %X Failed (%s)",
(sReadersContexts[i])->dwPort, (sReadersContexts[i])->lpcDevice);
Log2(PCSC_LOG_ERROR, " with error 0x%08X", rv);
continue;
}
EHSpawnEventHandler(sReadersContexts[i]);
}
}
}
#pragma mark ---------- Context Share Lock Tracking ----------
void ReaderContextLock(PREADER_CONTEXT rContext)
{
if (rContext)
{
secdebug("pcscd", "===> ReaderContextLock [was: %02X]", rContext->dwLockId);
rContext->dwLockId = 0xFFFF;
lastLockID = -3; }
}
void ReaderContextUnlock(PREADER_CONTEXT rContext)
{
if (rContext)
{
secdebug("pcscd", "<=== ReaderContextUnlock [was: %02X]", rContext->dwLockId);
rContext->dwLockId = 0;
lastLockID = -2; }
}
int ReaderContextIsLocked(PREADER_CONTEXT rContext)
{
if (rContext)
{
if (rContext->dwLockId && (rContext->dwLockId != lastLockID)) {
lastLockID = rContext->dwLockId;
secdebug("pcscd", ".... ReaderContextLock state: %02X", rContext->dwLockId);
}
return (rContext->dwLockId == 0xFFFF)?1:0;
}
else
return 0;
}
#pragma mark ---------- Reader Context Management ----------
static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader,
DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice)
{
if (!ctx)
return SCARD_E_NO_MEMORY;
strlcpy(ctx->lpcLibrary, lpcLibrary, sizeof(ctx->lpcLibrary));
strlcpy(ctx->lpcDevice, lpcDevice, sizeof(ctx->lpcDevice));
ctx->dwPort = dwPort;
ctx->pdwFeeds = malloc(sizeof(DWORD));
*ctx->pdwFeeds = 1;
ctx->mMutex = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
SYS_MutexInit(ctx->mMutex);
ctx->pdwMutex = malloc(sizeof(DWORD));
*ctx->pdwMutex = 1;
return SCARD_S_SUCCESS;
}
static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader,
DWORD dwPort, LPCSTR lpcLibrary)
{
LONG parentNode = RFSetReaderName(ctx, lpcReader, lpcLibrary, dwPort, 0);
if (parentNode < -1)
return SCARD_E_NO_MEMORY;
if ((parentNode >= 0) && (parentNode < PCSCLITE_MAX_READERS_CONTEXTS)
&& sReadersContexts[parentNode])
{
SYS_MutexLock(sReadersContextsLock);
ctx->pdwFeeds = (sReadersContexts[parentNode])->pdwFeeds;
*ctx->pdwFeeds += 1;
ctx->vHandle = (sReadersContexts[parentNode])->vHandle;
ctx->mMutex = (sReadersContexts[parentNode])->mMutex;
ctx->pdwMutex = (sReadersContexts[parentNode])->pdwMutex;
SYS_MutexUnLock(sReadersContextsLock);
if (0 && ReaderDriverIsThreadSafe(sReadersContexts[parentNode], 0))
{
ctx->mMutex = 0;
ctx->pdwMutex = NULL;
}
else
*ctx->pdwMutex += 1;
}
return SCARD_S_SUCCESS;
}
static void ReaderContextDestructor(PREADER_CONTEXT ctx)
{
ReaderContextFree(ctx);
}
static void ReaderContextFree(PREADER_CONTEXT ctx)
{
if (!ctx)
return;
if (ctx->pdwMutex)
{
if (*ctx->pdwMutex == 1)
{
SYS_MutexDestroy(ctx->mMutex);
free(ctx->mMutex);
}
*ctx->pdwMutex -= 1;
}
if (ctx->pdwMutex && (*ctx->pdwMutex == 0))
{
free(ctx->pdwMutex);
ctx->pdwMutex = NULL;
}
if (ctx->pdwFeeds)
{
*ctx->pdwFeeds -= 1;
if (*ctx->pdwFeeds == 0)
{
free(ctx->pdwFeeds);
ctx->pdwFeeds = NULL;
}
}
ReaderContextClear(ctx);
}
static void ReaderContextClear(PREADER_CONTEXT ctx)
{
if (ctx)
memset(ctx, 0, sizeof(READER_CONTEXT));
}
static int ReaderContextInsert(PREADER_CONTEXT ctx)
{
int ix, rv = SCARD_E_NO_MEMORY;
SYS_MutexLock(sReadersContextsLock);
for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
{
if ((sReadersContexts[ix] == NULL) || (sReadersContexts[ix])->vHandle == 0)
{
if (ctx)
{
if (sReadersContexts[ix])
free(sReadersContexts[ix]);
sReadersContexts[ix] = ctx;
(sReadersContexts[ix])->dwIdentity = (ix + 1) << (sizeof(DWORD) / 2) * 8;
dwNumReadersContexts += 1;
}
rv = SCARD_S_SUCCESS;
break;
}
}
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
static int ReaderContextRemove(PREADER_CONTEXT ctx)
{
int ix, rv = SCARD_E_UNKNOWN_READER;
PREADER_CONTEXT ctxToRemove = NULL;
DWORD dwPort = ctx->dwPort;
LPSTR lpcReader = ctx->lpcReader;
SYS_MutexLock(sReadersContextsLock);
for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
{
if (!ReaderNameMatchForIndex(dwPort, lpcReader, ix))
continue;
ctxToRemove = sReadersContexts[ix];
sReadersContexts[ix] = NULL;
dwNumReadersContexts -= 1;
rv = SCARD_S_SUCCESS;
break;
}
SYS_MutexUnLock(sReadersContextsLock);
if (ctxToRemove)
{
ReaderContextDestructor(ctxToRemove);
free(ctxToRemove);
}
return rv;
}
static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort)
{
if (dwNumReadersContexts == 0)
return SCARD_S_SUCCESS;
int ix, rv = SCARD_S_SUCCESS;
SYS_MutexLock(sReadersContextsLock);
for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
{
if ((sReadersContexts[ix]==NULL) || ((sReadersContexts[ix])->vHandle == 0))
continue;
if (ReaderNameMatchForIndex(dwPort, lpcReader, ix))
{
Log1(PCSC_LOG_ERROR, "Duplicate reader found.");
rv = SCARD_E_DUPLICATE_READER;
break;
}
}
SYS_MutexUnLock(sReadersContextsLock);
return rv;
}
static int ReaderSlotCount(PREADER_CONTEXT ctx)
{
UCHAR ucGetData[1];
DWORD dwGetSize = sizeof(ucGetData);
int rv = IFDGetCapabilities(ctx, TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);
if (rv != IFD_SUCCESS || dwGetSize != 1 || ucGetData[0] == 0)
return 1;
if (rv == IFD_SUCCESS && dwGetSize == 1 && ucGetData[0] == 1)
return 1;
return (int)ucGetData[0];
}
static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot)
{
UCHAR ucThread[1];
DWORD dwGetSize = sizeof(ucThread);
int rv = IFDGetCapabilities(ctx, testSlot?TAG_IFD_SLOT_THREAD_SAFE:TAG_IFD_THREAD_SAFE,
&dwGetSize, ucThread);
if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
{
Log1(PCSC_LOG_INFO, "Driver is thread safe");
return 1;
}
else
{
Log1(PCSC_LOG_INFO, "Driver is not thread safe");
return 0;
}
}
static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index)
{
char lpcStripReader[MAX_READERNAME];
int tmplen;
if (sReadersContexts[index]==NULL)
return 0;
strncpy(lpcStripReader, (sReadersContexts[index])->lpcReader, sizeof(lpcStripReader));
tmplen = strlen(lpcStripReader);
lpcStripReader[tmplen - 6] = 0;
return ((strcmp(lpcReader, lpcStripReader) == 0) && (dwPort == (sReadersContexts[index])->dwPort))?1:0;
}
static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe)
{
int ix;
char *tmpReader = ctxSlot->lpcReader;
strlcpy(tmpReader, ctxBase->lpcReader, sizeof(ctxSlot->lpcReader));
sprintf(tmpReader + strlen(tmpReader) - 2, "%02X", slotNumber);
strlcpy(ctxSlot->lpcLibrary, ctxBase->lpcLibrary, sizeof(ctxSlot->lpcLibrary));
strlcpy(ctxSlot->lpcDevice, ctxBase->lpcDevice, sizeof(ctxSlot->lpcDevice));
ctxSlot->dwVersion = ctxBase->dwVersion;
ctxSlot->dwPort = ctxBase->dwPort;
ctxSlot->vHandle = ctxBase->vHandle;
ctxSlot->mMutex = ctxBase->mMutex;
ctxSlot->pdwMutex = ctxBase->pdwMutex;
ctxSlot->dwSlot = ctxBase->dwSlot + slotNumber;
ctxSlot->pdwFeeds = ctxBase->pdwFeeds;
*ctxSlot->pdwFeeds += 1;
ctxSlot->dwBlockStatus = 0;
ctxSlot->dwContexts = 0;
ctxSlot->dwLockId = 0;
ctxSlot->readerState = NULL;
ctxSlot->dwIdentity = (slotNumber + 1) << (sizeof(DWORD) / 2) * 8;
for (ix = 0; ix < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; ix++)
ctxSlot->psHandles[ix].hCard = 0;
if (!ctxSlot->pdwMutex)
ctxSlot->pdwMutex = malloc(sizeof(DWORD));
if (baseIsThreadSafe)
{
ctxSlot->mMutex = malloc(sizeof(PCSCLITE_MUTEX));
SYS_MutexInit(ctxSlot->mMutex);
*ctxSlot->pdwMutex = 1;
}
else
*ctxSlot->pdwMutex += 1;
}
#pragma mark ---------- 64 bit routines ----------
#include <spawn.h>
#include <err.h>
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFNumber.h>
#include <signal.h>
extern char **environ;
extern char **globalArgv;
static cpu_type_t architectureForPid(pid_t pid)
{
cpu_type_t cpuType = CPU_TYPE_ANY;
int mib[CTL_MAXNAME]={0,};
size_t len = CTL_MAXNAME;
if (sysctlnametomib("sysctl.proc_cputype", mib, &len) != -1)
{
mib[len] = pid;
len++;
size_t cputypelen = sizeof(cpuType);
if (sysctl(mib, len, &cpuType, &cputypelen, 0, 0) == -1)
{
cpuType = CPU_TYPE_ANY;
}
}
return cpuType;
}
static int ReaderCheckArchitecture(LPCSTR lpcLibrary)
{
#if MAX_OS_X_VERSION_MIN_REQUIRED <= MAX_OS_X_VERSION_10_5
cpu_type_t cputype = architectureForPid(getpid());
if (! (cputype & CPU_ARCH_ABI64))
return SCARD_S_SUCCESS;
if (architectureMatch(lpcLibrary))
return SCARD_S_SUCCESS;
pid_t pid = getpid();
Log2(PCSC_LOG_INFO, "Send respawn signal to pcscd (pid=%d)", pid);
if (kill(pid, SIGUSR2) < 0)
{
Log3(PCSC_LOG_CRITICAL, "Can't signal pcscd (pid=%d): %s",
pid, strerror(errno));
}
void *value_ptr;
pthread_exit(value_ptr);
return SCARD_E_SERVICE_STOPPED;
#else
return SCARD_S_SUCCESS;
#endif
}
static int architectureMatch(const char *name)
{
int rx = false;
const Boolean isDirectory = true;
cpu_type_t cputype;
CFArrayRef pluginArchitectures = NULL;
CFURLRef exurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8), kCFURLPOSIXPathStyle, isDirectory);
if (!exurl)
return false;
CFBundleRef theBundle = CFBundleCreate(kCFAllocatorDefault, exurl);
if (theBundle == NULL)
goto xit;
pluginArchitectures = CFBundleCopyExecutableArchitectures(theBundle);
if (pluginArchitectures == NULL)
goto xit;
cputype = architectureForPid(getpid());
int ix;
for (ix = CFArrayGetCount(pluginArchitectures); --ix >= 0; )
{
CFNumberRef cfarch = (CFNumberRef)CFArrayGetValueAtIndex(pluginArchitectures, ix);
UInt32 arch;
CFNumberGetValue(cfarch, kCFNumberSInt32Type, &arch);
if (cputype == arch)
{
rx = true;
break;
}
}
xit:
if (exurl)
CFRelease(exurl);
if (theBundle)
CFRelease(theBundle);
if (pluginArchitectures)
CFRelease(pluginArchitectures);
return rx;
}