/* * MUSCLE SmartCard Development ( http://www.linuxnet.com ) * * Copyright (C) 2002 * David Corcoran * Najam Siddiqui * Copyright (C) 2005 * Ludovic Rousseau * * $Id: winscard_scf.c 2151 2006-09-06 20:02:47Z rousseau $ */ /** * @file * @brief This provides PC/SC to SCF shimming. */ #include "config.h" #include #include #include #include #include #include #include #include #include "pcsclite.h" #include "winscard.h" #include "debug.h" #include "thread_generic.h" #include "readerfactory.h" #include "eventhandler.h" #include "sys_generic.h" #define TRUE 1 #define FALSE 0 #undef PCSCLITE_MAX_READERS_CONTEXTS #define PCSCLITE_MAX_READERS_CONTEXTS 2 /* Global session to manage Readers, Card events. */ static SCF_Session_t g_hSession = NULL; /* Have to define this because they are defined in pcsclite.h as externs */ SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; static struct _psTransmitMap { BYTE Buffer[266]; int isResponseCached; LONG bufferLength; } psTransmitMap[PCSCLITE_MAX_APPLICATION_CONTEXTS]; /* Channel Map to manage Card Connections. */ static struct _psChannelMap { SCARDHANDLE PCSC_hCard; SCARDCONTEXT hContext; SCF_Session_t hSession; SCF_Terminal_t hTerminal; SCF_Card_t SCF_hCard; short haveLock; short isReset; int ReaderIndice; } psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXTS]; /* Context Map to manage contexts and sessions. */ static struct _psContextMap { SCARDCONTEXT hContext; SCF_Session_t hSession; DWORD contextBlockStatus; } psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS]; /* Reader Map to handle Status and GetStatusChange. */ static struct _psReaderMap { SCF_Terminal_t hTerminal; LPSTR ReaderName; short SharedRefCount; DWORD dwCurrentState; BYTE bAtr[MAX_ATR_SIZE]; DWORD dwAtrLength; SCF_ListenerHandle_t lHandle; } psReaderMap[PCSCLITE_MAX_READERS_CONTEXTS]; static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER; /* * Mutex for the Smardcard Event Handling, different from client Mutex * because event reporting from the ocfserver is done using a single thread, * so to get lock on the clientMutex may affect the performance of the ocf server. */ static PCSCLITE_MUTEX EventMutex = PTHREAD_MUTEX_INITIALIZER; static PCSCLITE_MUTEX SCFInitMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t EventCondition = PTHREAD_COND_INITIALIZER; static char PCSC_Initialized = 0; static LONG isOCFServerRunning(void); LONG SCardLockThread(void); LONG SCardUnlockThread(void); LONG SCardEventLock(void); LONG SCardEventUnlock(void); static LONG PCSC_SCF_Initialize(void); static void EventCallback(SCF_Event_t eventType, SCF_Terminal_t hTerm, void *cbdata); static LONG PCSC_SCF_getATR(SCF_Card_t hCard, LPBYTE pcbAtr, LPDWORD pcbAtrLen); static LONG ConvertStatus(SCF_Status_t status); static LONG SCardGetReaderIndice(LPCSTR ReaderName); static LONG getNewContext(SCARDCONTEXT * phContext); static LONG SCardAddContext(SCARDCONTEXT hContext, SCF_Session_t hSession); static SCF_Session_t getSessionForContext(SCARDCONTEXT hContext); static LONG SCardRemoveContext(SCARDCONTEXT hContext); static LONG SCardGetContextIndice(SCARDCONTEXT hContext); static LONG getNewHandle(SCARDCONTEXT hContext, LPCSTR szReader, SCARDHANDLE * phCard, DWORD); static LONG getCardForHandle(SCARDHANDLE PSCS_hCard, SCF_Card_t * SCF_hCard); static LONG SCardRemoveHandle(SCARDHANDLE hCard); static LONG SCardAddHandle(SCARDHANDLE PCSC_hCard, SCARDCONTEXT hContext, SCF_Session_t hSession, SCF_Terminal_t hTerminal, SCF_Card_t SCF_hCard, int, DWORD); static LONG SCardGetHandleIndice(SCARDHANDLE hCard); static LONG isActiveContextPresent(void); static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) { LONG rv = 0; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; rv = PCSC_SCF_Initialize(); if (SCARD_S_SUCCESS != rv) return rv; if (NULL == phContext) return SCARD_E_INVALID_PARAMETER; else *phContext = 0; if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL && dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL) { *phContext = 0; return SCARD_E_INVALID_VALUE; } rv = getNewContext(phContext); return rv; } LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) { long rv; SCardLockThread(); rv = SCardEstablishContextTH(dwScope, pvReserved1, pvReserved2, phContext); SCardUnlockThread(); return rv; } static LONG SCardReleaseContextTH(SCARDCONTEXT hContext) { LONG rv; /* Zero out everything */ if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; rv = 0; /* Remove the local context from the stack */ rv = SCardRemoveContext(hContext); return rv; } LONG SCardReleaseContext(SCARDCONTEXT hContext) { long rv; SCardLockThread(); rv = SCardReleaseContextTH(hContext); SCardUnlockThread(); return rv; } static LONG SCardListReadersTH(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders) { static int first_time = 1; int i = 0; static DWORD dwReadersLen = 0; LONG retIndice = 0; char *tempPtr; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Check for NULL parameters */ if (pcchReaders == NULL) { return SCARD_E_INVALID_PARAMETER; } /*Check for Context validity */ retIndice = SCardGetContextIndice(hContext); if (0 > retIndice) return SCARD_E_INVALID_HANDLE; /*Calculate the the buffer length reuired only once. */ if (first_time) { for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (NULL != psReaderMap[i].ReaderName) dwReadersLen += strlen(psReaderMap[i].ReaderName) + 1; } dwReadersLen++; first_time = 0; } /*There are no readers available */ if (1 >= dwReadersLen) return SCARD_E_READER_UNAVAILABLE; if (mszReaders == NULL) { *pcchReaders = dwReadersLen; return SCARD_S_SUCCESS; } else if (*pcchReaders == 0) { *pcchReaders = dwReadersLen; return SCARD_S_SUCCESS; } else if (*pcchReaders < dwReadersLen) { *pcchReaders = dwReadersLen; return SCARD_E_INSUFFICIENT_BUFFER; } tempPtr = mszReaders; for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (NULL != psReaderMap[i].ReaderName) { memcpy(tempPtr, psReaderMap[i].ReaderName, strlen(psReaderMap[i].ReaderName) + 1); tempPtr += (strlen(psReaderMap[i].ReaderName) + 1); } } /*the extra NULL character as per the PCSC specs. */ tempPtr[0] = '\0'; *pcchReaders = dwReadersLen; return SCARD_S_SUCCESS; } LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders) { long rv; SCardLockThread(); rv = SCardListReadersTH(hContext, mszGroups, mszReaders, pcchReaders); SCardUnlockThread(); return rv; } /* by najam */ static LONG SCardConnectTH(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) { LONG rv; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Zero out everything */ rv = 0; /* Check for NULL parameters */ if (phCard == NULL || pdwActiveProtocol == NULL) return SCARD_E_INVALID_PARAMETER; else *phCard = 0; /* Make sure this context has been opened */ if (SCardGetContextIndice(hContext) == -1) return SCARD_E_INVALID_HANDLE; if (szReader == NULL) return SCARD_E_UNKNOWN_READER; /* Check for uninitialized strings */ 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)) { return SCARD_E_INVALID_VALUE; } if ((SCARD_SHARE_SHARED != dwShareMode) && (SCARD_SHARE_EXCLUSIVE != dwShareMode) && (SCARD_SHARE_DIRECT != dwShareMode)) { return SCARD_E_INVALID_VALUE; } /* TODO Which Protocols have to be supported */ /* Ignoring protocols for now */ /* Make sure this handle has been opened */ rv = getNewHandle(hContext, szReader, phCard, dwShareMode); if (SCARD_S_SUCCESS != rv) return rv; *pdwActiveProtocol = SCARD_PROTOCOL_T0; return SCARD_S_SUCCESS; } LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) { long rv; SCardLockThread(); rv = SCardConnectTH(hContext, szReader, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); SCardUnlockThread(); return rv; } static LONG SCardDisconnectTH(SCARDHANDLE hCard, DWORD dwDisposition) { long rv; LONG retIndice = 0; SCF_Status_t status; /*check ocfserver availibility */ if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; if (dwDisposition != SCARD_LEAVE_CARD && dwDisposition != SCARD_RESET_CARD && dwDisposition != SCARD_UNPOWER_CARD && dwDisposition != SCARD_EJECT_CARD) { return SCARD_E_INVALID_VALUE; } /*CHECK HANDLE VALIDITY */ retIndice = SCardGetHandleIndice(hCard); if ((retIndice == -1) || (NULL == psChannelMap[retIndice].SCF_hCard)) return SCARD_E_INVALID_HANDLE; /* TODO Take Care of the Disposition... */ /* Resetting the card for SCARD_RESET_CARD | SCARD_UNPOWER_CARD | SCARD_EJECT_CARD */ if (SCARD_LEAVE_CARD != dwDisposition) { /*must acquire the lock to reset card */ status = SCF_Card_lock(psChannelMap[retIndice].SCF_hCard, 0); if ((SCF_STATUS_SUCCESS == status) || (SCF_STATUS_DOUBLELOCK == status)) { status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard); SCF_Card_unlock(psChannelMap[retIndice].SCF_hCard); /*a usleep here will allow the RESET_EVENT to be reported and the Maps to be updated */ SYS_USleep(10); } } rv = SCardRemoveHandle(hCard); return rv; } static LONG SCardReconnectTH(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol) { SCARDCONTEXT hContext; LPSTR ReaderName; SCARDHANDLE tempHandle; LONG rv; int retIndice = 0; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; if (pdwActiveProtocol == NULL) return SCARD_E_INVALID_PARAMETER; if (dwInitialization != SCARD_LEAVE_CARD && dwInitialization != SCARD_RESET_CARD && dwInitialization != SCARD_UNPOWER_CARD && dwInitialization != SCARD_EJECT_CARD) { return SCARD_E_INVALID_VALUE; } retIndice = SCardGetHandleIndice(hCard); if (-1 == retIndice) return SCARD_E_INVALID_HANDLE; hContext = psChannelMap[retIndice].hContext; ReaderName = psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName; SCardDisconnectTH(hCard, dwInitialization); /* get a new handle */ rv = SCardConnectTH(hContext, ReaderName, dwShareMode, dwPreferredProtocols, &tempHandle, pdwActiveProtocol); if (SCARD_S_SUCCESS != rv) return rv; retIndice = SCardGetHandleIndice(tempHandle); if (-1 == retIndice) return SCARD_E_NO_MEMORY; /*set PCSC hCard to old Handle */ SCardEventLock(); psChannelMap[retIndice].PCSC_hCard = hCard; SCardEventUnlock(); return SCARD_S_SUCCESS; } LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol) { long rv; SCardLockThread(); rv = SCardReconnectTH(hCard, dwShareMode, dwPreferredProtocols, dwInitialization, pdwActiveProtocol); SCardUnlockThread(); return rv; } LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) { long rv; SCardLockThread(); rv = SCardDisconnectTH(hCard, dwDisposition); SCardUnlockThread(); return rv; } LONG SCardBeginTransaction(SCARDHANDLE hCard) { LONG rv; SCF_Card_t SCF_hCard; SCF_Status_t status; /* Zero out everything */ rv = 0; SCardLockThread(); if (SCARD_S_SUCCESS != isOCFServerRunning()) { SCardUnlockThread(); return SCARD_E_NO_SERVICE; } rv = getCardForHandle(hCard, &SCF_hCard); if (SCARD_S_SUCCESS != rv) { SCardUnlockThread(); return rv; } SCardUnlockThread(); status = SCF_Card_lock(SCF_hCard, SCF_TIMEOUT_MAX); if (SCF_STATUS_DOUBLELOCK == status) return SCARD_S_SUCCESS; rv = ConvertStatus(status); return rv; } static LONG SCardEndTransactionTH(SCARDHANDLE hCard, DWORD dwDisposition) { LONG rv; LONG retIndice = 0; SCF_Card_t SCF_hCard; SCF_Status_t status; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Zero out everything */ rv = 0; if (dwDisposition != SCARD_LEAVE_CARD && dwDisposition != SCARD_RESET_CARD && dwDisposition != SCARD_UNPOWER_CARD && dwDisposition != SCARD_EJECT_CARD) { return SCARD_E_INVALID_VALUE; } retIndice = SCardGetHandleIndice(hCard); if (retIndice == -1) return SCARD_E_INVALID_HANDLE; rv = getCardForHandle(hCard, &SCF_hCard); if (rv != SCARD_S_SUCCESS) return rv; /* TODO Take Care of the Disposition... */ if (SCARD_LEAVE_CARD != dwDisposition) { status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard); if (SCF_STATUS_SUCCESS == status) { /* reset the isReset for this card */ SYS_USleep(10); SCardEventLock(); psChannelMap[retIndice].isReset = 0; SCardEventUnlock(); } } status = SCF_Card_unlock(SCF_hCard); return ConvertStatus(status); } LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) { long rv; SCardLockThread(); rv = SCardEndTransactionTH(hCard, dwDisposition); SCardUnlockThread(); return rv; } static LONG SCardCancelTransactionTH(SCARDHANDLE hCard) { if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* TODO */ return SCARD_S_SUCCESS; } LONG SCardCancelTransaction(SCARDHANDLE hCard) { long rv; SCardLockThread(); rv = SCardCancelTransactionTH(hCard); SCardUnlockThread(); return rv; } static LONG SCardStatusTH(SCARDHANDLE hCard, LPSTR mszReaderNames, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) { LONG retIndice, rv; int i; DWORD dwReaderLen; SCF_Card_t SCF_hCard; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Zero out everything */ retIndice = 0; dwReaderLen = 0; rv = 0; i = 0; /* Check for NULL parameters */ if (pcchReaderLen == NULL || pdwState == NULL || pdwProtocol == NULL || pcbAtrLen == NULL) { return SCARD_E_INVALID_PARAMETER; } retIndice = SCardGetHandleIndice(hCard); rv = getCardForHandle(hCard, &SCF_hCard); if (SCARD_S_SUCCESS != rv) return rv; dwReaderLen = strlen(psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName); if (mszReaderNames == NULL) { *pcchReaderLen = dwReaderLen; *pcbAtrLen = 0; *pdwState = 0; *pdwProtocol = 0; return SCARD_S_SUCCESS; } if (*pcchReaderLen == 0) { *pcchReaderLen = dwReaderLen; *pcbAtrLen = 0; *pdwState = 0; *pdwProtocol = 0; return SCARD_S_SUCCESS; } if (*pcchReaderLen < dwReaderLen) { *pcchReaderLen = dwReaderLen; *pcbAtrLen = 0; *pdwState = 0; *pdwProtocol = 0; return SCARD_E_INSUFFICIENT_BUFFER; } *pcchReaderLen = dwReaderLen; strcpy(mszReaderNames, psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName); *pdwProtocol = SCARD_PROTOCOL_T0; SCardEventLock(); if (!(psReaderMap[psChannelMap[retIndice].ReaderIndice]. dwCurrentState & SCARD_STATE_PRESENT)) { *pdwState = SCARD_ABSENT; SCardEventUnlock(); return SCARD_S_SUCCESS; } *pdwState = SCARD_NEGOTIABLE | SCARD_POWERED | SCARD_PRESENT; rv = PCSC_SCF_getATR(SCF_hCard, pbAtr, pcbAtrLen); if (SCARD_S_SUCCESS == rv) { /*referesh the Atr in the reader Map */ psReaderMap[psChannelMap[retIndice].ReaderIndice].dwAtrLength = *pcbAtrLen; memcpy(psReaderMap[psChannelMap[retIndice].ReaderIndice].bAtr, pbAtr, *pcbAtrLen); } SCardEventUnlock(); return SCARD_S_SUCCESS; } LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) { long rv; SCardLockThread(); rv = SCardStatusTH(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen); SCardUnlockThread(); return rv; } LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders) { LONG rv, retIndice, readerIndice; PSCARD_READERSTATE_A currReader; PREADER_STATE rContext; LPSTR lpcReaderName; DWORD dwTime; DWORD dwState; DWORD dwBreakFlag; int i, j; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Zero out everything */ rv = 0; rContext = 0; lpcReaderName = 0; dwTime = 0; j = 0; dwState = 0; i = 0; currReader = 0; retIndice = 0; readerIndice = 0; dwBreakFlag = 0; if (rgReaderStates == NULL && cReaders > 0) return SCARD_E_INVALID_PARAMETER; if (cReaders < 0) return SCARD_E_INVALID_VALUE; /* change by najam */ SCardLockThread(); retIndice = SCardGetContextIndice(hContext); /* change by najam */ SCardUnlockThread(); if (retIndice == -1) return SCARD_E_INVALID_HANDLE; /* Application is waiting for a reader - return the first available reader */ if (cReaders == 0) { for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (psReaderMap[i].ReaderName) return SCARD_S_SUCCESS; } return SCARD_E_READER_UNAVAILABLE; } else if (cReaders > PCSCLITE_MAX_READERS_CONTEXTS) { return SCARD_E_INVALID_VALUE; } /* Check the integrity of the reader states structures */ for (j = 0; j < cReaders; j++) { currReader = &rgReaderStates[j]; if (currReader->szReader == NULL) { return SCARD_E_INVALID_VALUE; } } /* End of search for readers */ /* Clear the event state for all readers */ for (j = 0; j < cReaders; j++) { currReader = &rgReaderStates[j]; currReader->dwEventState = 0; } /* Now is where we start our event checking loop */ psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_BLOCKING; j = 0; do { SYS_USleep(10); if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; currReader = &rgReaderStates[j]; /************ Look for IGNORED readers ****************************/ if (currReader->dwCurrentState & SCARD_STATE_IGNORE) { currReader->dwEventState = SCARD_STATE_IGNORE; } else { /************ Looks for correct readernames *********************/ lpcReaderName = (char *) currReader->szReader; readerIndice = SCardGetReaderIndice(lpcReaderName); /* The requested reader name is not recognized */ if (0 > readerIndice) { if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN) { currReader->dwEventState = SCARD_STATE_UNKNOWN; } else { currReader->dwEventState = SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED; /* Spec says use SCARD_STATE_IGNORE but a removed USB reader with eventState fed into currentState will be ignored forever */ dwBreakFlag = 1; } } else { /* The reader has come back after being away */ if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN) { currReader->dwEventState |= SCARD_STATE_CHANGED; currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; dwBreakFlag = 1; } /*****************************************************************/ SCardEventLock(); /* Now we check all the Reader States */ dwState = psReaderMap[readerIndice].dwCurrentState; /*********** Check if the reader is in the correct state ********/ if (dwState & SCARD_STATE_UNKNOWN) { /* App thinks reader is in bad state and it is */ if (currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE) { currReader->dwEventState = SCARD_STATE_UNAVAILABLE; } else { /* App thinks reader is in good state and it is not */ currReader->dwEventState = SCARD_STATE_CHANGED | SCARD_STATE_UNAVAILABLE; dwBreakFlag = 1; } } else { /* App thinks reader in bad state but it is not */ if (currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE) { currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; currReader->dwEventState |= SCARD_STATE_CHANGED; dwBreakFlag = 1; } } /********** Check for card presence in the reader **************/ if (dwState & SCARD_STATE_PRESENT) { currReader->cbAtr = psReaderMap[readerIndice].dwAtrLength; memcpy(currReader->rgbAtr, psReaderMap[readerIndice].bAtr, currReader->cbAtr); } else { currReader->cbAtr = 0; } /* Card is now absent */ if (dwState & SCARD_STATE_EMPTY) { 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; /* After present the rest are assumed */ 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; } /* Card is now present */ } else if (dwState & SCARD_STATE_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; } /* TODO */ if (0 && 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 { /* App thinks card is mute but it is not */ if (currReader->dwCurrentState & SCARD_STATE_MUTE) { currReader->dwEventState |= SCARD_STATE_CHANGED; dwBreakFlag = 1; } } } if (-1 == psReaderMap[readerIndice].SharedRefCount) { currReader->dwEventState |= SCARD_STATE_EXCLUSIVE; currReader->dwEventState &= ~SCARD_STATE_INUSE; if (!currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE) { currReader->dwEventState |= SCARD_STATE_CHANGED; dwBreakFlag = 1; } } else if (psReaderMap[readerIndice].SharedRefCount >= 1) { /* A card must be inserted for it to be INUSE */ if (dwState & SCARD_STATE_PRESENT) { currReader->dwEventState |= SCARD_STATE_INUSE; currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE; if (!currReader->dwCurrentState & SCARD_STATE_INUSE) { currReader->dwEventState |= SCARD_STATE_CHANGED; dwBreakFlag = 1; } } } SCardEventUnlock(); if (currReader->dwCurrentState == SCARD_STATE_UNAWARE) { /* Break out of the while .. loop and return status once all the status's for all readers is met */ dwBreakFlag = 1; } SYS_USleep(PCSCLITE_STATUS_WAIT); } /* End of SCARD_STATE_UNKNOWN */ } /* End of SCARD_STATE_IGNORE */ /* Counter and resetter */ j = j + 1; if (j == cReaders) j = 0; if (dwTimeout != INFINITE && dwTimeout != 0) { dwTime += PCSCLITE_STATUS_WAIT; /* If time is greater than timeout and all readers have been checked */ if ((dwTime >= (dwTimeout * 1000)) && (j == 0)) { return SCARD_E_TIMEOUT; } } /* Declare all the break conditions */ /* TODO think about this */ if (psContextMap[retIndice].contextBlockStatus == BLOCK_STATUS_RESUME) break; /* Break if UNAWARE is set and all readers have been checked */ if ((dwBreakFlag == 1) && (j == 0)) break; /* * Solve the problem of never exiting the loop when a smartcard is * already inserted in the reader, thus blocking the application * (patch proposed by Serge Koganovitsch) */ if ((dwTimeout == 0) && (j == 0)) break; } while (1); /* end of do */ if (psContextMap[retIndice].contextBlockStatus == BLOCK_STATUS_RESUME) { return SCARD_E_CANCELLED; } return SCARD_S_SUCCESS; } LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned) { /* TODO */ return SCARD_S_SUCCESS; } static LONG SCardTransmitTH(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) { BYTE Buffer[MAX_BUFFER_SIZE]; LONG rv = 0; SCF_Card_t SCF_hCard; SCF_Status_t status; LONG retIndice; LONG localRecvLen = MAX_BUFFER_SIZE; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; if (pbSendBuffer == NULL || pbRecvBuffer == NULL || pcbRecvLength == NULL || pioSendPci == NULL) { return SCARD_E_INVALID_PARAMETER; } rv = getCardForHandle(hCard, &SCF_hCard); if (rv != SCARD_S_SUCCESS) return rv; if ((cbSendLength > MAX_BUFFER_SIZE) || (*pcbRecvLength < 2)) return SCARD_E_INSUFFICIENT_BUFFER; /* TODO which protocols to support */ /* if(pioSendPci && pioSendPci->dwProtocol) { */ retIndice = SCardGetHandleIndice(hCard); if ((pbSendBuffer[1] == 0xC0) && psTransmitMap[retIndice].isResponseCached) { if (*pcbRecvLength < psTransmitMap[retIndice].bufferLength) { *pcbRecvLength = psTransmitMap[retIndice].bufferLength; return SCARD_E_INSUFFICIENT_BUFFER; } *pcbRecvLength = psTransmitMap[retIndice].bufferLength; memcpy(pbRecvBuffer, psTransmitMap[retIndice].Buffer, psTransmitMap[retIndice].bufferLength); if (pioRecvPci && pioSendPci) pioRecvPci->dwProtocol = pioSendPci->dwProtocol; return SCARD_S_SUCCESS; } else { psTransmitMap[retIndice].isResponseCached = 0; } status = SCF_Card_exchangeAPDU(SCF_hCard, (const uint8_t *) pbSendBuffer, (size_t) cbSendLength, (uint8_t *) Buffer, (size_t *) & localRecvLen); if ((cbSendLength > 5) && (localRecvLen > 2)) { if (SCF_STATUS_SUCCESS == status) { *pcbRecvLength = 2; pbRecvBuffer[0] = 0x61; pbRecvBuffer[1] = localRecvLen - 2; psTransmitMap[retIndice].isResponseCached = TRUE; psTransmitMap[retIndice].bufferLength = localRecvLen; memcpy(psTransmitMap[retIndice].Buffer, Buffer, psTransmitMap[retIndice].bufferLength); if (pioRecvPci && pioSendPci) pioRecvPci->dwProtocol = pioSendPci->dwProtocol; return SCARD_S_SUCCESS; } } else { if (SCF_STATUS_SUCCESS == status) { if (*pcbRecvLength < localRecvLen) { *pcbRecvLength = localRecvLen; return SCARD_E_INSUFFICIENT_BUFFER; } *pcbRecvLength = localRecvLen; memcpy(pbRecvBuffer, Buffer, *pcbRecvLength); } } /* TODO fill the received Pci ... */ /* For now just filling the send pci protocol. */ if (pioRecvPci && pioSendPci) pioRecvPci->dwProtocol = pioSendPci->dwProtocol; rv = ConvertStatus(status); return rv; } LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) { long rv; SCardLockThread(); rv = SCardTransmitTH(hCard, pioSendPci, pbSendBuffer, cbSendLength, pioRecvPci, pbRecvBuffer, pcbRecvLength); SCardUnlockThread(); return rv; } static LONG SCardListReaderGroupsTH(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups) { LONG rv = SCARD_S_SUCCESS; const char ReaderGroup[] = "SCard$DefaultReaders"; const int dwGroups = strlen(ReaderGroup) + 2; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; /* Make sure this context has been opened */ if (SCardGetContextIndice(hContext) == -1) { return SCARD_E_INVALID_HANDLE; } if (mszGroups) { if (*pcchGroups < dwGroups) rv = SCARD_E_INSUFFICIENT_BUFFER; else { memset(mszGroups, 0, dwGroups); memcpy(mszGroups, ReaderGroup, strlen(ReaderGroup)); } } *pcchGroups = dwGroups; return rv; } LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups) { long rv; SCardLockThread(); rv = SCardListReaderGroupsTH(hContext, mszGroups, pcchGroups); SCardUnlockThread(); return rv; } static LONG SCardCancelTH(SCARDCONTEXT hContext) { LONG hContextIndice; if (SCARD_S_SUCCESS != isOCFServerRunning()) return SCARD_E_NO_SERVICE; hContextIndice = SCardGetContextIndice(hContext); if (hContextIndice == -1) return SCARD_E_INVALID_HANDLE; /* Set the block status for this Context so blocking calls will complete */ psContextMap[hContextIndice].contextBlockStatus = BLOCK_STATUS_RESUME; return SCARD_S_SUCCESS; } LONG SCardCancel(SCARDCONTEXT hContext) { long rv; SCardLockThread(); rv = SCardCancelTH(hContext); SCardUnlockThread(); return rv; } LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen) { return SCARD_E_NOT_TRANSACTED; } LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen) { return SCARD_E_NOT_TRANSACTED; } static LONG SCardGetHandleIndice(SCARDHANDLE hCard) { int i = 0; static int LastIndex = 0; if (hCard == 0) return -1; if (psChannelMap[LastIndex].PCSC_hCard == hCard) return LastIndex; for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) { if (hCard == psChannelMap[i].PCSC_hCard) return i; } return -1; } static LONG SCardGetReaderIndice(LPCSTR ReaderName) { int i = 0; if (NULL == ReaderName) return -1; for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if ((NULL != psReaderMap[i].ReaderName) && (strncmp(psReaderMap[i].ReaderName, ReaderName, strlen(psReaderMap[i].ReaderName)) == 0)) { return i; } } return -1; } static LONG SCardAddHandle(SCARDHANDLE PCSC_hCard, SCARDCONTEXT hContext, SCF_Session_t hSession, SCF_Terminal_t hTerminal, SCF_Card_t SCF_hCard, int ReaderIndice, DWORD dwShareMode) { int i = 0; for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) { if (psChannelMap[i].PCSC_hCard == 0) { psChannelMap[i].PCSC_hCard = PCSC_hCard; psChannelMap[i].hContext = hContext; psChannelMap[i].hSession = hSession; psChannelMap[i].hTerminal = hTerminal; psChannelMap[i].SCF_hCard = SCF_hCard; psChannelMap[i].ReaderIndice = ReaderIndice; SCardEventLock(); if (SCARD_SHARE_EXCLUSIVE == dwShareMode) { psChannelMap[i].haveLock = TRUE; psReaderMap[ReaderIndice].SharedRefCount = -1; } else { psReaderMap[ReaderIndice].SharedRefCount++; psReaderMap[ReaderIndice].dwCurrentState |= SCARD_STATE_INUSE; } PCSC_SCF_getATR(SCF_hCard, psReaderMap[ReaderIndice].bAtr, &psReaderMap[ReaderIndice].dwAtrLength); SCardEventUnlock(); return SCARD_S_SUCCESS; } } return SCARD_E_NO_MEMORY; } static LONG PCSC_SCF_getATR(SCF_Card_t hCard, LPBYTE pcbAtr, LPDWORD pcbAtrLen) { SCF_Status_t status; struct SCF_BinaryData_t *pAtr; status = SCF_Card_getInfo(hCard, "atr", &pAtr); if (SCF_STATUS_SUCCESS != status) return SCARD_F_COMM_ERROR; if ((NULL == pcbAtr) || (NULL == pcbAtrLen) || (MAX_ATR_SIZE < pAtr->length)) { if (NULL != pcbAtrLen) *pcbAtrLen = pAtr->length; SCF_Card_freeInfo(hCard, pAtr); return SCARD_E_INSUFFICIENT_BUFFER; } *pcbAtrLen = pAtr->length; memcpy(pcbAtr, pAtr->data, pAtr->length); SCF_Card_freeInfo(hCard, pAtr); return SCARD_S_SUCCESS; } static LONG SCardRemoveHandle(SCARDHANDLE hCard) { LONG retIndice = 0; retIndice = SCardGetHandleIndice(hCard); if (retIndice == -1) { return SCARD_E_INVALID_HANDLE; } SCardEventLock(); SCF_Session_close(psChannelMap[retIndice].hSession); psChannelMap[retIndice].PCSC_hCard = 0; psChannelMap[retIndice].hContext = 0; psChannelMap[retIndice].hSession = NULL; psChannelMap[retIndice].hTerminal = NULL; psChannelMap[retIndice].SCF_hCard = NULL; psChannelMap[retIndice].isReset = 0; if (psChannelMap[retIndice].haveLock) { psChannelMap[retIndice].haveLock = FALSE; psReaderMap[psChannelMap[retIndice].ReaderIndice].SharedRefCount = 0; } else { psReaderMap[psChannelMap[retIndice].ReaderIndice].SharedRefCount--; if (0 >= psReaderMap[psChannelMap[retIndice].ReaderIndice].SharedRefCount) { psReaderMap[psChannelMap[retIndice].ReaderIndice].SharedRefCount = 0; psReaderMap[psChannelMap[retIndice].ReaderIndice]. dwCurrentState &= (~(SCARD_STATE_EXCLUSIVE | SCARD_STATE_INUSE)); } } psChannelMap[retIndice].ReaderIndice = 0; SCardEventUnlock(); return SCARD_S_SUCCESS; } static LONG getCardForHandle(SCARDHANDLE PCSC_hCard, SCF_Card_t * SCF_hCard) { int retIndice = 0; retIndice = SCardGetHandleIndice(PCSC_hCard); if (0 > retIndice) return SCARD_E_INVALID_HANDLE; *SCF_hCard = psChannelMap[retIndice].SCF_hCard; if (NULL == *SCF_hCard) return SCARD_E_INVALID_HANDLE; SCardEventLock(); if (psChannelMap[retIndice].isReset) { SCardEventUnlock(); return SCARD_W_RESET_CARD; } SCardEventUnlock(); return SCARD_S_SUCCESS; } static LONG getNewHandle(SCARDCONTEXT hContext, LPCSTR szReader, SCARDHANDLE * phCard, DWORD dwShareMode) { long rv = 0, ReaderIndice; SCF_Status_t status; SCF_Session_t hSession; SCF_Terminal_t hTerminal; SCF_Card_t SCF_hCard; ReaderIndice = SCardGetReaderIndice(szReader); if (-1 == ReaderIndice) return SCARD_E_UNKNOWN_READER; SCardEventLock(); if ((psReaderMap[ReaderIndice].SharedRefCount == -1) || ((SCARD_SHARE_EXCLUSIVE == dwShareMode) && psReaderMap[ReaderIndice].SharedRefCount)) { SCardEventUnlock(); return SCARD_E_SHARING_VIOLATION; } SCardEventUnlock(); status = SCF_Session_getSession(&hSession); if (SCF_STATUS_SUCCESS != status) { return ConvertStatus(status); } status = SCF_Session_getTerminal(hSession, szReader, &hTerminal); if (SCF_STATUS_SUCCESS != status) { SCF_Session_close(hSession); return ConvertStatus(status); } status = SCF_Terminal_getCard(hTerminal, &SCF_hCard); if (SCF_STATUS_SUCCESS != status) { SCF_Session_close(hSession); return ConvertStatus(status); } if (SCARD_SHARE_EXCLUSIVE == dwShareMode) { status = SCF_Card_lock(SCF_hCard, 0); if (status != SCF_STATUS_SUCCESS) { SCF_Session_close(hSession); return SCARD_E_SHARING_VIOLATION; } } while (1) { *phCard = (PCSCLITE_SVC_IDENTITY + SYS_RandomInt(1, 65535)); if (SCardGetHandleIndice(*phCard) == -1) break; } rv = SCardAddHandle(*phCard, hContext, hSession, hTerminal, SCF_hCard, ReaderIndice, dwShareMode); if (SCARD_S_SUCCESS != rv) { SCF_Session_close(hSession); return rv; } return SCARD_S_SUCCESS; } /* Function Managing Terminals for Sessions */ /* Functions for managing instances of SCardEstablishContext These functions keep track of Context handles and associate the blocking variable contextBlockStatus to an hContext */ static LONG getNewContext(SCARDCONTEXT * phContext) { LONG rv; SCF_Session_t hSession = NULL; SCF_Status_t status; status = SCF_Session_getSession(&hSession); if (status != SCF_STATUS_SUCCESS) return SCARD_E_NO_SERVICE; while (1) { *phContext = (PCSCLITE_SVC_IDENTITY + SYS_RandomInt(1, 65535)); if (-1 == SCardGetContextIndice(*phContext)) break; } rv = SCardAddContext(*phContext, hSession); if (SCARD_S_SUCCESS != rv) { SCF_Session_close(hSession); } return rv; } static LONG SCardAddContext(SCARDCONTEXT hContext, SCF_Session_t hSession) { int i; for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) { if (psContextMap[i].hContext == 0) { psContextMap[i].hContext = hContext; psContextMap[i].hSession = hSession; psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; return SCARD_S_SUCCESS; } } return SCARD_E_NO_MEMORY; } static LONG SCardGetContextIndice(SCARDCONTEXT hContext) { int i; /* Find this context and return it's spot in the array */ for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) { if ((hContext == psContextMap[i].hContext) && (hContext != 0)) { return i; } } return -1; } static LONG SCardRemoveContext(SCARDCONTEXT hContext) { LONG retIndice; int i = 0; retIndice = 0; retIndice = SCardGetContextIndice(hContext); if (retIndice == -1) { return SCARD_E_INVALID_HANDLE; } else { /* Free all handles for this context. */ for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) { if (psChannelMap[i].hContext == hContext) { SCardRemoveHandle(psChannelMap[i].PCSC_hCard); } } SCF_Session_close(psContextMap[retIndice].hSession); psContextMap[retIndice].hContext = 0; psContextMap[retIndice].hSession = NULL; psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_RESUME; } return SCARD_S_SUCCESS; } static SCF_Session_t getSessionForContext(SCARDCONTEXT hContext) { LONG retIndice; retIndice = 0; retIndice = SCardGetContextIndice(hContext); if (retIndice == -1) return NULL; return (psContextMap[retIndice].hSession); } /* This function locks a mutex so another thread must wait to use this function */ LONG SCardLockThread(void) { return SYS_MutexLock(&clientMutex); } LONG SCardEventLock(void) { return SYS_MutexLock(&EventMutex); } /* This function unlocks a mutex so another thread may use the client library */ LONG SCardUnlockThread(void) { return SYS_MutexUnLock(&clientMutex); } LONG SCardEventUnlock(void) { return SYS_MutexUnLock(&EventMutex); } static LONG isActiveContextPresent(void) { long fActiveContext = FALSE; int i; for (i=0; i