pcsc-lite 1.5.5
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2000 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 2004-2008 00007 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00008 * 00009 * $Id: eventhandler.c 3305 2009-02-06 08:54:05Z rousseau $ 00010 */ 00011 00018 #include "config.h" 00019 #include <sys/types.h> 00020 #include <sys/stat.h> 00021 #include <errno.h> 00022 #include <fcntl.h> 00023 #include <string.h> 00024 #include <stdlib.h> 00025 00026 #include "misc.h" 00027 #include "pcscd.h" 00028 #include "ifdhandler.h" 00029 #include "debuglog.h" 00030 #include "thread_generic.h" 00031 #include "readerfactory.h" 00032 #include "eventhandler.h" 00033 #include "dyn_generic.h" 00034 #include "sys_generic.h" 00035 #include "ifdwrapper.h" 00036 #include "prothandler.h" 00037 #include "strlcpycat.h" 00038 #include "utils.h" 00039 00040 static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; 00041 00042 static void EHStatusHandlerThread(PREADER_CONTEXT); 00043 00044 LONG EHInitializeEventStructures(void) 00045 { 00046 int fd, i, pageSize; 00047 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 00048 00049 fd = 0; 00050 i = 0; 00051 pageSize = 0; 00052 00053 (void)SYS_RemoveFile(PCSCLITE_PUBSHM_FILE); 00054 00055 fd = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDWR | O_CREAT, mode); 00056 if (fd < 0) 00057 { 00058 Log3(PCSC_LOG_CRITICAL, "Cannot create public shared file %s: %s", 00059 PCSCLITE_PUBSHM_FILE, strerror(errno)); 00060 exit(1); 00061 } 00062 00063 /* set correct mode even is umask is too restictive */ 00064 (void)SYS_Chmod(PCSCLITE_PUBSHM_FILE, mode); 00065 00066 pageSize = SYS_GetPageSize(); 00067 00068 /* 00069 * Jump to end of file space and allocate zero's 00070 */ 00071 (void)SYS_SeekFile(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS); 00072 (void)SYS_WriteFile(fd, "", 1); 00073 00074 /* 00075 * Allocate each reader structure 00076 */ 00077 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00078 { 00079 readerStates[i] = (PREADER_STATE) 00080 SYS_MemoryMap(sizeof(READER_STATE), fd, (i * pageSize)); 00081 if (readerStates[i] == MAP_FAILED) 00082 { 00083 Log3(PCSC_LOG_CRITICAL, "Cannot memory map public shared file %s: %s", 00084 PCSCLITE_PUBSHM_FILE, strerror(errno)); 00085 exit(1); 00086 } 00087 00088 /* 00089 * Zero out each value in the struct 00090 */ 00091 memset((readerStates[i])->readerName, 0, MAX_READERNAME); 00092 memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE); 00093 (readerStates[i])->readerID = 0; 00094 (readerStates[i])->readerState = 0; 00095 (readerStates[i])->readerSharing = 0; 00096 (readerStates[i])->cardAtrLength = 0; 00097 (readerStates[i])->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00098 } 00099 00100 return SCARD_S_SUCCESS; 00101 } 00102 00103 LONG EHDestroyEventHandler(PREADER_CONTEXT rContext) 00104 { 00105 int rv; 00106 DWORD dwGetSize; 00107 UCHAR ucGetData[1]; 00108 00109 if (NULL == rContext->readerState) 00110 { 00111 Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)"); 00112 return SCARD_S_SUCCESS; 00113 } 00114 00115 if ('\0' == rContext->readerState->readerName[0]) 00116 { 00117 Log1(PCSC_LOG_INFO, "Thread already stomped."); 00118 return SCARD_S_SUCCESS; 00119 } 00120 00121 /* 00122 * Set the thread to 0 to exit thread 00123 */ 00124 rContext->dwLockId = 0xFFFF; 00125 00126 Log1(PCSC_LOG_INFO, "Stomping thread."); 00127 00128 /* kill the "polling" thread */ 00129 dwGetSize = sizeof(ucGetData); 00130 rv = IFDGetCapabilities(rContext, TAG_IFD_POLLING_THREAD_KILLABLE, 00131 &dwGetSize, ucGetData); 00132 00133 if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0]) 00134 { 00135 Log1(PCSC_LOG_INFO, "Killing polling thread"); 00136 (void)SYS_ThreadCancel(rContext->pthThread); 00137 } 00138 else 00139 Log1(PCSC_LOG_INFO, "Waiting polling thread"); 00140 00141 /* wait for the thread to finish */ 00142 rv = SYS_ThreadJoin(rContext->pthThread, NULL); 00143 if (rv) 00144 Log2(PCSC_LOG_ERROR, "SYS_ThreadJoin failed: %s", strerror(rv)); 00145 00146 /* 00147 * Zero out the public status struct to allow it to be recycled and 00148 * used again 00149 */ 00150 memset(rContext->readerState->readerName, 0, 00151 sizeof(rContext->readerState->readerName)); 00152 memset(rContext->readerState->cardAtr, 0, 00153 sizeof(rContext->readerState->cardAtr)); 00154 rContext->readerState->readerID = 0; 00155 rContext->readerState->readerState = 0; 00156 rContext->readerState->readerSharing = 0; 00157 rContext->readerState->cardAtrLength = 0; 00158 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00159 00160 /* Zero the thread */ 00161 rContext->pthThread = 0; 00162 00163 Log1(PCSC_LOG_INFO, "Thread stomped."); 00164 00165 return SCARD_S_SUCCESS; 00166 } 00167 00168 LONG EHSpawnEventHandler(PREADER_CONTEXT rContext, 00169 RESPONSECODE (*card_event)(DWORD)) 00170 { 00171 LONG rv; 00172 DWORD dwStatus = 0; 00173 int i; 00174 UCHAR ucAtr[MAX_ATR_SIZE]; 00175 DWORD dwAtrLen = 0; 00176 00177 rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen); 00178 if (rv != SCARD_S_SUCCESS) 00179 { 00180 Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader); 00181 return SCARD_F_UNKNOWN_ERROR; 00182 } 00183 00184 /* 00185 * Find an empty reader slot and insert the new reader 00186 */ 00187 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 00188 { 00189 if ((readerStates[i])->readerID == 0) 00190 break; 00191 } 00192 00193 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 00194 return SCARD_F_INTERNAL_ERROR; 00195 00196 /* 00197 * Set all the attributes to this reader 00198 */ 00199 rContext->readerState = readerStates[i]; 00200 (void)strlcpy(rContext->readerState->readerName, rContext->lpcReader, 00201 sizeof(rContext->readerState->readerName)); 00202 memcpy(rContext->readerState->cardAtr, ucAtr, dwAtrLen); 00203 rContext->readerState->readerID = i + 100; 00204 rContext->readerState->readerState = dwStatus; 00205 rContext->readerState->readerSharing = rContext->dwContexts; 00206 rContext->readerState->cardAtrLength = dwAtrLen; 00207 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00208 00209 rContext->pthCardEvent = card_event; 00210 rv = SYS_ThreadCreate(&rContext->pthThread, 0, 00211 (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext); 00212 if (rv) 00213 { 00214 Log2(PCSC_LOG_ERROR, "SYS_ThreadCreate failed: %s", strerror(rv)); 00215 return SCARD_E_NO_MEMORY; 00216 } 00217 else 00218 return SCARD_S_SUCCESS; 00219 } 00220 00221 static void incrementEventCounter(struct pubReaderStatesList *readerState) 00222 { 00223 int counter; 00224 00225 counter = (readerState -> readerState >> 16) & 0xFFFF; 00226 counter++; 00227 readerState -> readerState = (readerState -> readerState & 0xFFFF) 00228 + (counter << 16); 00229 } 00230 00231 static void EHStatusHandlerThread(PREADER_CONTEXT rContext) 00232 { 00233 LONG rv; 00234 LPCSTR lpcReader; 00235 DWORD dwStatus, dwReaderSharing; 00236 DWORD dwCurrentState; 00237 DWORD dwAtrLen; 00238 00239 /* 00240 * Zero out everything 00241 */ 00242 dwStatus = 0; 00243 dwReaderSharing = 0; 00244 dwCurrentState = 0; 00245 00246 lpcReader = rContext->lpcReader; 00247 00248 dwAtrLen = rContext->readerState->cardAtrLength; 00249 rv = IFDStatusICC(rContext, &dwStatus, rContext->readerState->cardAtr, 00250 &dwAtrLen); 00251 rContext->readerState->cardAtrLength = dwAtrLen; 00252 00253 if (dwStatus & SCARD_PRESENT) 00254 { 00255 dwAtrLen = MAX_ATR_SIZE; 00256 rv = IFDPowerICC(rContext, IFD_POWER_UP, 00257 rContext->readerState->cardAtr, 00258 &dwAtrLen); 00259 rContext->readerState->cardAtrLength = dwAtrLen; 00260 00261 /* the protocol is unset after a power on */ 00262 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00263 00264 if (rv == IFD_SUCCESS) 00265 { 00266 dwStatus |= SCARD_PRESENT; 00267 dwStatus &= ~SCARD_ABSENT; 00268 dwStatus |= SCARD_POWERED; 00269 dwStatus |= SCARD_NEGOTIABLE; 00270 dwStatus &= ~SCARD_SPECIFIC; 00271 dwStatus &= ~SCARD_SWALLOWED; 00272 dwStatus &= ~SCARD_UNKNOWN; 00273 00274 if (rContext->readerState->cardAtrLength > 0) 00275 { 00276 LogXxd(PCSC_LOG_INFO, "Card ATR: ", 00277 rContext->readerState->cardAtr, 00278 rContext->readerState->cardAtrLength); 00279 } 00280 else 00281 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)"); 00282 } 00283 else 00284 { 00285 dwStatus |= SCARD_PRESENT; 00286 dwStatus &= ~SCARD_ABSENT; 00287 dwStatus |= SCARD_SWALLOWED; 00288 dwStatus &= ~SCARD_POWERED; 00289 dwStatus &= ~SCARD_NEGOTIABLE; 00290 dwStatus &= ~SCARD_SPECIFIC; 00291 dwStatus &= ~SCARD_UNKNOWN; 00292 Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv); 00293 } 00294 00295 dwCurrentState = SCARD_PRESENT; 00296 } 00297 else 00298 { 00299 dwStatus |= SCARD_ABSENT; 00300 dwStatus &= ~SCARD_PRESENT; 00301 dwStatus &= ~SCARD_POWERED; 00302 dwStatus &= ~SCARD_NEGOTIABLE; 00303 dwStatus &= ~SCARD_SPECIFIC; 00304 dwStatus &= ~SCARD_SWALLOWED; 00305 dwStatus &= ~SCARD_UNKNOWN; 00306 rContext->readerState->cardAtrLength = 0; 00307 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00308 00309 dwCurrentState = SCARD_ABSENT; 00310 } 00311 00312 /* 00313 * Set all the public attributes to this reader 00314 */ 00315 rContext->readerState->readerState = dwStatus; 00316 rContext->readerState->readerSharing = dwReaderSharing = 00317 rContext->dwContexts; 00318 00319 (void)StatSynchronize(rContext->readerState); 00320 00321 while (1) 00322 { 00323 dwStatus = 0; 00324 00325 dwAtrLen = rContext->readerState->cardAtrLength; 00326 rv = IFDStatusICC(rContext, &dwStatus, 00327 rContext->readerState->cardAtr, 00328 &dwAtrLen); 00329 rContext->readerState->cardAtrLength = dwAtrLen; 00330 00331 if (rv != SCARD_S_SUCCESS) 00332 { 00333 Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader); 00334 00335 /* 00336 * Set error status on this reader while errors occur 00337 */ 00338 rContext->readerState->readerState &= ~SCARD_ABSENT; 00339 rContext->readerState->readerState &= ~SCARD_PRESENT; 00340 rContext->readerState->readerState &= ~SCARD_POWERED; 00341 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE; 00342 rContext->readerState->readerState &= ~SCARD_SPECIFIC; 00343 rContext->readerState->readerState &= ~SCARD_SWALLOWED; 00344 rContext->readerState->readerState |= SCARD_UNKNOWN; 00345 rContext->readerState->cardAtrLength = 0; 00346 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00347 00348 dwCurrentState = SCARD_UNKNOWN; 00349 00350 (void)StatSynchronize(rContext->readerState); 00351 } 00352 00353 if (dwStatus & SCARD_ABSENT) 00354 { 00355 if (dwCurrentState == SCARD_PRESENT || 00356 dwCurrentState == SCARD_UNKNOWN) 00357 { 00358 /* 00359 * Change the status structure 00360 */ 00361 Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader); 00362 /* 00363 * Notify the card has been removed 00364 */ 00365 (void)RFSetReaderEventState(rContext, SCARD_REMOVED); 00366 00367 rContext->readerState->cardAtrLength = 0; 00368 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00369 rContext->readerState->readerState |= SCARD_ABSENT; 00370 rContext->readerState->readerState &= ~SCARD_UNKNOWN; 00371 rContext->readerState->readerState &= ~SCARD_PRESENT; 00372 rContext->readerState->readerState &= ~SCARD_POWERED; 00373 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE; 00374 rContext->readerState->readerState &= ~SCARD_SWALLOWED; 00375 rContext->readerState->readerState &= ~SCARD_SPECIFIC; 00376 dwCurrentState = SCARD_ABSENT; 00377 00378 incrementEventCounter(rContext->readerState); 00379 00380 (void)StatSynchronize(rContext->readerState); 00381 } 00382 00383 } 00384 else if (dwStatus & SCARD_PRESENT) 00385 { 00386 if (dwCurrentState == SCARD_ABSENT || 00387 dwCurrentState == SCARD_UNKNOWN) 00388 { 00389 /* 00390 * Power and reset the card 00391 */ 00392 dwAtrLen = MAX_ATR_SIZE; 00393 rv = IFDPowerICC(rContext, IFD_POWER_UP, 00394 rContext->readerState->cardAtr, 00395 &dwAtrLen); 00396 rContext->readerState->cardAtrLength = dwAtrLen; 00397 00398 /* the protocol is unset after a power on */ 00399 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; 00400 00401 if (rv == IFD_SUCCESS) 00402 { 00403 rContext->readerState->readerState |= SCARD_PRESENT; 00404 rContext->readerState->readerState &= ~SCARD_ABSENT; 00405 rContext->readerState->readerState |= SCARD_POWERED; 00406 rContext->readerState->readerState |= SCARD_NEGOTIABLE; 00407 rContext->readerState->readerState &= ~SCARD_SPECIFIC; 00408 rContext->readerState->readerState &= ~SCARD_UNKNOWN; 00409 rContext->readerState->readerState &= ~SCARD_SWALLOWED; 00410 } 00411 else 00412 { 00413 rContext->readerState->readerState |= SCARD_PRESENT; 00414 rContext->readerState->readerState &= ~SCARD_ABSENT; 00415 rContext->readerState->readerState |= SCARD_SWALLOWED; 00416 rContext->readerState->readerState &= ~SCARD_POWERED; 00417 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE; 00418 rContext->readerState->readerState &= ~SCARD_SPECIFIC; 00419 rContext->readerState->readerState &= ~SCARD_UNKNOWN; 00420 rContext->readerState->cardAtrLength = 0; 00421 } 00422 00423 dwCurrentState = SCARD_PRESENT; 00424 00425 incrementEventCounter(rContext->readerState); 00426 00427 (void)StatSynchronize(rContext->readerState); 00428 00429 Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader); 00430 00431 if (rv == IFD_SUCCESS) 00432 { 00433 if (rContext->readerState->cardAtrLength > 0) 00434 { 00435 LogXxd(PCSC_LOG_INFO, "Card ATR: ", 00436 rContext->readerState->cardAtr, 00437 rContext->readerState->cardAtrLength); 00438 } 00439 else 00440 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)"); 00441 } 00442 else 00443 Log1(PCSC_LOG_ERROR,"Error powering up card."); 00444 } 00445 } 00446 00447 /* 00448 * Sharing may change w/o an event pass it on 00449 */ 00450 if (dwReaderSharing != rContext->dwContexts) 00451 { 00452 dwReaderSharing = rContext->dwContexts; 00453 rContext->readerState->readerSharing = dwReaderSharing; 00454 (void)StatSynchronize(rContext->readerState); 00455 } 00456 00457 if (rContext->pthCardEvent) 00458 { 00459 int ret; 00460 00461 ret = rContext->pthCardEvent(rContext->dwSlot); 00462 if (IFD_NO_SUCH_DEVICE == ret) 00463 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE); 00464 } 00465 else 00466 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE); 00467 00468 if (rContext->dwLockId == 0xFFFF) 00469 { 00470 /* 00471 * Exit and notify the caller 00472 */ 00473 (void)StatSynchronize(rContext->readerState); 00474 Log1(PCSC_LOG_INFO, "Die"); 00475 rContext->dwLockId = 0; 00476 (void)SYS_ThreadExit(NULL); 00477 } 00478 } 00479 } 00480