LONG RFAddReader(const char *readerNameLong, int port, const char *library, const char *device) { DWORD dwContext = 0, dwGetSize; UCHAR ucGetData[1], ucThread[1]; LONG rv, parentNode; int i, j; int lrv = 0; char *readerName = NULL; if ((readerNameLong == NULL) || (library == NULL) || (device == NULL)) return SCARD_E_INVALID_VALUE; #ifdef FILTER_NAMES const char *ro_filter = getenv("PCSCLITE_FILTER_IGNORE_READER_NAMES"); if (ro_filter) { char *filter, *next; /* get a RW copy of the env string */ filter = alloca(strlen(ro_filter)+1); strcpy(filter, ro_filter); while (filter) { /* ':' is the separator */ next = strchr(filter, ':'); if (next) { /* NUL terminate the current pattern */ *next = '\0'; } /* if filter is non empty and found in the reader name */ if (*filter && strstr(readerNameLong, filter)) { Log3(PCSC_LOG_ERROR, "Reader name \"%s\" contains \"%s\": ignored", readerNameLong, filter); return SCARD_E_READER_UNAVAILABLE; } if (next) /* next pattern */ filter = next+1; else /* end */ filter = NULL; } } #endif /* allocate memory that is automatically freed */ readerName = alloca(strlen(readerNameLong)+1); strcpy(readerName, readerNameLong); /* Reader name too long? also count " 00 00"*/ if (strlen(readerName) > MAX_READERNAME - sizeof(" 00 00")) { Log3(PCSC_LOG_ERROR, "Reader name too long: %zd chars instead of max %zd. Truncating!", strlen(readerName), MAX_READERNAME - sizeof(" 00 00")); readerName[MAX_READERNAME - sizeof(" 00 00")] = '\0'; } /* Same name, same port, same device - duplicate reader cannot be used */ if (dwNumReadersContexts != 0) { for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle != 0) { char lpcStripReader[MAX_READERNAME]; int tmplen; /* get the reader name without the reader and slot numbers */ strncpy(lpcStripReader, sReadersContexts[i]->readerState->readerName, sizeof(lpcStripReader)); tmplen = strlen(lpcStripReader); lpcStripReader[tmplen - 6] = 0; if ((strcmp(readerName, lpcStripReader) == 0) && (port == sReadersContexts[i]->port) && (strcmp(device, sReadersContexts[i]->device) == 0)) { Log1(PCSC_LOG_ERROR, "Duplicate reader found."); return SCARD_E_DUPLICATE_READER; } } } } /* We must find an empty slot to put the reader structure */ for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle == 0) { dwContext = i; break; } } if (i == PCSCLITE_MAX_READERS_CONTEXTS) { /* No more spots left return */ return SCARD_E_NO_MEMORY; } /* Check and set the readername to see if it must be enumerated */ parentNode = RFSetReaderName(sReadersContexts[dwContext], readerName, library, port); if (parentNode < -1) return SCARD_E_NO_MEMORY; sReadersContexts[dwContext]->library = strdup(library); sReadersContexts[dwContext]->device = strdup(device); sReadersContexts[dwContext]->version = 0; sReadersContexts[dwContext]->port = port; sReadersContexts[dwContext]->mMutex = NULL; sReadersContexts[dwContext]->contexts = 0; sReadersContexts[dwContext]->pthThread = 0; sReadersContexts[dwContext]->hLockId = 0; sReadersContexts[dwContext]->LockCount = 0; sReadersContexts[dwContext]->vHandle = NULL; sReadersContexts[dwContext]->pFeeds = NULL; sReadersContexts[dwContext]->pMutex = NULL; sReadersContexts[dwContext]->pthCardEvent = NULL; lrv = list_init(&sReadersContexts[dwContext]->handlesList); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } lrv = list_attributes_seeker(&sReadersContexts[dwContext]->handlesList, RDR_CLIHANDLES_seeker); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_attributes_seeker failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } (void)pthread_mutex_init(&sReadersContexts[dwContext]->handlesList_lock, NULL); (void)pthread_mutex_init(&sReadersContexts[dwContext]->powerState_lock, NULL); sReadersContexts[dwContext]->powerState = POWER_STATE_UNPOWERED; /* reference count */ (void)pthread_mutex_init(&sReadersContexts[dwContext]->reference_lock, NULL); sReadersContexts[dwContext]->reference = 1; /* If a clone to this reader exists take some values from that clone */ if (parentNode >= 0 && parentNode < PCSCLITE_MAX_READERS_CONTEXTS) { sReadersContexts[dwContext]->pFeeds = sReadersContexts[parentNode]->pFeeds; *(sReadersContexts[dwContext])->pFeeds += 1; sReadersContexts[dwContext]->vHandle = sReadersContexts[parentNode]->vHandle; sReadersContexts[dwContext]->mMutex = sReadersContexts[parentNode]->mMutex; sReadersContexts[dwContext]->pMutex = sReadersContexts[parentNode]->pMutex; /* Call on the parent driver to see if it is thread safe */ dwGetSize = sizeof(ucThread); rv = IFDGetCapabilities(sReadersContexts[parentNode], TAG_IFD_THREAD_SAFE, &dwGetSize, ucThread); if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1) { Log1(PCSC_LOG_INFO, "Driver is thread safe"); sReadersContexts[dwContext]->mMutex = NULL; sReadersContexts[dwContext]->pMutex = NULL; } else *(sReadersContexts[dwContext])->pMutex += 1; } if (sReadersContexts[dwContext]->pFeeds == NULL) { sReadersContexts[dwContext]->pFeeds = malloc(sizeof(int)); /* Initialize pFeeds to 1, otherwise multiple cloned readers will cause pcscd to crash when RFUnloadReader unloads the driver library and there are still devices attached using it --mikeg*/ *(sReadersContexts[dwContext])->pFeeds = 1; } if (sReadersContexts[dwContext]->mMutex == 0) { sReadersContexts[dwContext]->mMutex = malloc(sizeof(pthread_mutex_t)); (void)pthread_mutex_init(sReadersContexts[dwContext]->mMutex, NULL); } if (sReadersContexts[dwContext]->pMutex == NULL) { sReadersContexts[dwContext]->pMutex = malloc(sizeof(int)); *(sReadersContexts[dwContext])->pMutex = 1; } dwNumReadersContexts += 1; rv = RFInitializeReader(sReadersContexts[dwContext]); if (rv != SCARD_S_SUCCESS) { /* Cannot connect to reader. Exit gracefully */ Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } /* asynchronous card movement? */ { RESPONSECODE (*fct)(DWORD, int) = NULL; dwGetSize = sizeof(fct); rv = IFDGetCapabilities(sReadersContexts[dwContext], TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct); if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct))) { Log1(PCSC_LOG_INFO, "Using the pcscd polling thread"); } else { sReadersContexts[dwContext]->pthCardEvent = fct; Log1(PCSC_LOG_INFO, "Using the reader polling thread"); } rv = EHSpawnEventHandler(sReadersContexts[dwContext]); if (rv != SCARD_S_SUCCESS) { Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } } /* Call on the driver to see if there are multiple slots */ dwGetSize = sizeof(ucGetData); rv = IFDGetCapabilities((sReadersContexts[dwContext]), TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData); int nbSlots = ucGetData[0]; if (rv != IFD_SUCCESS || dwGetSize != 1 || nbSlots == 0) /* Reader does not have this defined. Must be a single slot * reader so we can just return SCARD_S_SUCCESS. */ return SCARD_S_SUCCESS; if (1 == nbSlots) /* Reader has only one slot */ return SCARD_S_SUCCESS; /* * Check the number of slots and create a different * structure for each one accordingly */ /* Initialize the rest of the slots */ for (j = 1; j < nbSlots; j++) { char *tmpReader = NULL; DWORD dwContextB = 0; RESPONSECODE (*fct)(DWORD, int) = NULL; /* We must find an empty spot to put the reader structure */ for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { if (sReadersContexts[i]->vHandle == 0) { dwContextB = i; break; } } if (i == PCSCLITE_MAX_READERS_CONTEXTS) { /* No more slot left return */ RFRemoveReader(readerName, port); return SCARD_E_NO_MEMORY; } /* Copy the previous reader name and increment the slot number */ tmpReader = sReadersContexts[dwContextB]->readerState->readerName; memcpy(tmpReader, sReadersContexts[dwContext]->readerState->readerName, sizeof(sReadersContexts[dwContextB]->readerState->readerName)); snprintf(tmpReader + strlen(tmpReader) - 2, 3, "%02X", j); sReadersContexts[dwContextB]->library = sReadersContexts[dwContext]->library; sReadersContexts[dwContextB]->device = sReadersContexts[dwContext]->device; sReadersContexts[dwContextB]->version = sReadersContexts[dwContext]->version; sReadersContexts[dwContextB]->port = sReadersContexts[dwContext]->port; sReadersContexts[dwContextB]->vHandle = sReadersContexts[dwContext]->vHandle; sReadersContexts[dwContextB]->mMutex = sReadersContexts[dwContext]->mMutex; sReadersContexts[dwContextB]->pMutex = sReadersContexts[dwContext]->pMutex; sReadersContexts[dwContextB]->slot = sReadersContexts[dwContext]->slot + j; sReadersContexts[dwContextB]->pthCardEvent = NULL; /* * Added by Dave - slots did not have a pFeeds * parameter so it was by luck they were working */ sReadersContexts[dwContextB]->pFeeds = sReadersContexts[dwContext]->pFeeds; /* Added by Dave for multiple slots */ *(sReadersContexts[dwContextB])->pFeeds += 1; sReadersContexts[dwContextB]->contexts = 0; sReadersContexts[dwContextB]->hLockId = 0; sReadersContexts[dwContextB]->LockCount = 0; lrv = list_init(&sReadersContexts[dwContextB]->handlesList); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } lrv = list_attributes_seeker(&sReadersContexts[dwContextB]->handlesList, RDR_CLIHANDLES_seeker); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_attributes_seeker failed with return value: %d", lrv); return SCARD_E_NO_MEMORY; } (void)pthread_mutex_init(&sReadersContexts[dwContextB]->handlesList_lock, NULL); (void)pthread_mutex_init(&sReadersContexts[dwContextB]->powerState_lock, NULL); sReadersContexts[dwContextB]->powerState = POWER_STATE_UNPOWERED; /* reference count */ (void)pthread_mutex_init(&sReadersContexts[dwContextB]->reference_lock, NULL); sReadersContexts[dwContextB]->reference = 1; /* Call on the parent driver to see if the slots are thread safe */ dwGetSize = sizeof(ucThread); rv = IFDGetCapabilities((sReadersContexts[dwContext]), TAG_IFD_SLOT_THREAD_SAFE, &dwGetSize, ucThread); if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1) { Log1(PCSC_LOG_INFO, "Driver is slot thread safe"); sReadersContexts[dwContextB]->library = strdup(sReadersContexts[dwContext]->library); sReadersContexts[dwContextB]->device = strdup(sReadersContexts[dwContext]->device); sReadersContexts[dwContextB]->mMutex = malloc(sizeof(pthread_mutex_t)); (void)pthread_mutex_init(sReadersContexts[dwContextB]->mMutex, NULL); sReadersContexts[dwContextB]->pMutex = malloc(sizeof(int)); *(sReadersContexts[dwContextB])->pMutex = 1; } else *(sReadersContexts[dwContextB])->pMutex += 1; dwNumReadersContexts += 1; rv = RFInitializeReader(sReadersContexts[dwContextB]); if (rv != SCARD_S_SUCCESS) { /* Cannot connect to slot. Exit gracefully */ (void)RFRemoveReader(readerName, port); return rv; } /* asynchronous card movement? */ dwGetSize = sizeof(fct); rv = IFDGetCapabilities((sReadersContexts[dwContextB]), TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct); if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct))) { Log1(PCSC_LOG_INFO, "Using the pcscd polling thread"); } else { sReadersContexts[dwContextB]->pthCardEvent = fct; Log1(PCSC_LOG_INFO, "Using the reader polling thread"); } rv = EHSpawnEventHandler(sReadersContexts[dwContextB]); if (rv != SCARD_S_SUCCESS) { Log2(PCSC_LOG_ERROR, "%s init failed.", readerName); (void)RFRemoveReader(readerName, port); return rv; } } return SCARD_S_SUCCESS; }
LONG EHDestroyEventHandler(READER_CONTEXT * rContext) { int rv; DWORD dwGetSize; UCHAR ucGetData[1]; if ('\0' == rContext->readerState->readerName[0]) { Log1(PCSC_LOG_INFO, "Thread already stomped."); return SCARD_S_SUCCESS; } /* * Set the thread to 0 to exit thread */ rContext->hLockId = 0xFFFF; Log1(PCSC_LOG_INFO, "Stomping thread."); /* kill the "polling" thread */ dwGetSize = sizeof(ucGetData); rv = IFDGetCapabilities(rContext, TAG_IFD_POLLING_THREAD_KILLABLE, &dwGetSize, ucGetData); #ifdef HAVE_PTHREAD_CANCEL if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0]) { Log1(PCSC_LOG_INFO, "Killing polling thread"); (void)pthread_cancel(rContext->pthThread); } else #endif { /* ask to stop the "polling" thread */ RESPONSECODE (*fct)(DWORD) = NULL; dwGetSize = sizeof(fct); rv = IFDGetCapabilities(rContext, TAG_IFD_STOP_POLLING_THREAD, &dwGetSize, (PUCHAR)&fct); if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct))) { Log1(PCSC_LOG_INFO, "Request stoping of polling thread"); fct(rContext->slot); } else Log1(PCSC_LOG_INFO, "Waiting polling thread"); } /* wait for the thread to finish */ rv = pthread_join(rContext->pthThread, NULL); if (rv) Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv)); /* Zero the thread */ rContext->pthThread = 0; Log1(PCSC_LOG_INFO, "Thread stomped."); return SCARD_S_SUCCESS; }