pcsc-lite 1.7.2
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2004 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 2003-2004 00007 * Damien Sauveron <damien.sauveron@labri.fr> 00008 * Copyright (C) 2002-2010 00009 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00010 * Copyright (C) 2009 00011 * Jean-Luc Giraud <jlgiraud@googlemail.com> 00012 * 00013 * $Id: winscard_svc.c 5539 2011-01-20 09:35:38Z rousseau $ 00014 */ 00015 00026 #include "config.h" 00027 #include <time.h> 00028 #include <stdio.h> 00029 #include <string.h> 00030 #include <stddef.h> 00031 #include <stdlib.h> 00032 #include <unistd.h> 00033 #include <pthread.h> 00034 00035 #include "pcscd.h" 00036 #include "winscard.h" 00037 #include "debuglog.h" 00038 #include "winscard_msg.h" 00039 #include "winscard_svc.h" 00040 #include "sys_generic.h" 00041 #include "utils.h" 00042 #include "readerfactory.h" 00043 #include "eventhandler.h" 00044 #include "simclist.h" 00045 00052 extern char AutoExit; 00053 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS; 00054 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES; 00055 00056 static list_t contextsList; 00057 pthread_mutex_t contextsList_lock; 00059 struct _psContext 00060 { 00061 int32_t hContext; 00062 list_t cardsList; 00063 pthread_mutex_t cardsList_lock; 00064 uint32_t dwClientID; 00065 pthread_t pthThread; 00066 }; 00067 typedef struct _psContext SCONTEXT; 00068 00069 static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *); 00070 static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *); 00071 static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *); 00072 static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *); 00073 static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *); 00074 static LONG MSGCleanupClient(SCONTEXT *); 00075 00076 static void ContextThread(LPVOID pdwIndex); 00077 00078 extern READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; 00079 00080 static int contextsListhContext_seeker(const void *el, const void *key) 00081 { 00082 const SCONTEXT * currentContext = (SCONTEXT *)el; 00083 00084 if ((el == NULL) || (key == NULL)) 00085 { 00086 Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%X, key=%X", 00087 el, key); 00088 return 0; 00089 } 00090 00091 if (currentContext->hContext == *(int32_t *)key) 00092 return 1; 00093 return 0; 00094 } 00095 00096 LONG ContextsInitialize(int customMaxThreadCounter, 00097 int customMaxThreadCardHandles) 00098 { 00099 int lrv = 0; 00100 00101 if (customMaxThreadCounter != 0) 00102 contextMaxThreadCounter = customMaxThreadCounter; 00103 00104 if (customMaxThreadCardHandles != 0) 00105 contextMaxCardHandles = customMaxThreadCardHandles; 00106 00107 lrv = list_init(&contextsList); 00108 if (lrv < 0) 00109 { 00110 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); 00111 return -1; 00112 } 00113 lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker); 00114 if (lrv < 0) 00115 { 00116 Log2(PCSC_LOG_CRITICAL, 00117 "list_attributes_seeker failed with return value: %d", lrv); 00118 return -1; 00119 } 00120 00121 (void)pthread_mutex_init(&contextsList_lock, NULL); 00122 00123 return 1; 00124 } 00125 00126 void ContextsDeinitialize(void) 00127 { 00128 int listSize; 00129 listSize = list_size(&contextsList); 00130 Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize); 00131 /* This is currently a no-op. It should terminate the threads properly. */ 00132 } 00133 00144 LONG CreateContextThread(uint32_t *pdwClientID) 00145 { 00146 int rv; 00147 int lrv; 00148 int listSize; 00149 SCONTEXT * newContext = NULL; 00150 00151 (void)pthread_mutex_lock(&contextsList_lock); 00152 listSize = list_size(&contextsList); 00153 (void)pthread_mutex_unlock(&contextsList_lock); 00154 00155 if (listSize >= contextMaxThreadCounter) 00156 { 00157 Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize); 00158 goto error; 00159 } 00160 00161 /* Create the context for this thread. */ 00162 newContext = malloc(sizeof(*newContext)); 00163 if (NULL == newContext) 00164 { 00165 Log1(PCSC_LOG_CRITICAL, "Could not allocate new context"); 00166 goto error; 00167 } 00168 memset(newContext, 0, sizeof(*newContext)); 00169 00170 newContext->dwClientID = *pdwClientID; 00171 00172 /* Initialise the list of card contexts */ 00173 lrv = list_init(&(newContext->cardsList)); 00174 if (lrv < 0) 00175 { 00176 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); 00177 goto error; 00178 } 00179 00180 /* request to store copies, and provide the metric function */ 00181 list_attributes_copy(&(newContext->cardsList), list_meter_int32_t, 1); 00182 00183 /* Adding a comparator 00184 * The stored type is SCARDHANDLE (long) but has only 32 bits 00185 * usefull even on a 64-bit CPU since the API between pcscd and 00186 * libpcscliter uses "int32_t hCard;" 00187 */ 00188 lrv = list_attributes_comparator(&(newContext->cardsList), 00189 list_comparator_int32_t); 00190 if (lrv != 0) 00191 { 00192 Log2(PCSC_LOG_CRITICAL, 00193 "list_attributes_comparator failed with return value: %d", lrv); 00194 list_destroy(&(newContext->cardsList)); 00195 goto error; 00196 } 00197 00198 (void)pthread_mutex_init(&newContext->cardsList_lock, NULL); 00199 00200 (void)pthread_mutex_lock(&contextsList_lock); 00201 lrv = list_append(&contextsList, newContext); 00202 (void)pthread_mutex_unlock(&contextsList_lock); 00203 if (lrv < 0) 00204 { 00205 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d", 00206 lrv); 00207 list_destroy(&(newContext->cardsList)); 00208 goto error; 00209 } 00210 00211 rv = ThreadCreate(&(newContext->pthThread), THREAD_ATTR_DETACHED, 00212 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext); 00213 if (rv) 00214 { 00215 int lrv2; 00216 00217 Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv)); 00218 (void)pthread_mutex_lock(&contextsList_lock); 00219 lrv2 = list_delete(&contextsList, newContext); 00220 (void)pthread_mutex_unlock(&contextsList_lock); 00221 if (lrv2 < 0) 00222 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2); 00223 list_destroy(&(newContext->cardsList)); 00224 goto error; 00225 } 00226 00227 /* disable any suicide alarm */ 00228 if (AutoExit) 00229 alarm(0); 00230 00231 return SCARD_S_SUCCESS; 00232 00233 error: 00234 if (newContext) 00235 free(newContext); 00236 (void)close(*pdwClientID); 00237 return SCARD_E_NO_MEMORY; 00238 } 00239 00240 /* 00241 * A list of local functions used to keep track of clients and their 00242 * connections 00243 */ 00244 00253 #ifndef NO_LOG 00254 static const char *CommandsText[] = { 00255 "NULL", 00256 "ESTABLISH_CONTEXT", /* 0x01 */ 00257 "RELEASE_CONTEXT", 00258 "LIST_READERS", 00259 "CONNECT", 00260 "RECONNECT", /* 0x05 */ 00261 "DISCONNECT", 00262 "BEGIN_TRANSACTION", 00263 "END_TRANSACTION", 00264 "TRANSMIT", 00265 "CONTROL", /* 0x0A */ 00266 "STATUS", 00267 "GET_STATUS_CHANGE", 00268 "CANCEL", 00269 "CANCEL_TRANSACTION", 00270 "GET_ATTRIB", /* 0x0F */ 00271 "SET_ATTRIB", 00272 "CMD_VERSION", 00273 "CMD_GET_READERS_STATE", 00274 "CMD_WAIT_READER_STATE_CHANGE", 00275 "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */ 00276 "NULL" 00277 }; 00278 #endif 00279 00280 #define READ_BODY(v) \ 00281 if (header.size != sizeof(v)) { goto wrong_length; } \ 00282 ret = MessageReceive(&v, sizeof(v), filedes); \ 00283 if (ret != SCARD_S_SUCCESS) { Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); goto exit; } 00284 00285 #define WRITE_BODY(v) \ 00286 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v) 00287 #define WRITE_BODY_WITH_COMMAND(command, v) \ 00288 Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \ 00289 ret = MessageSend(&v, sizeof(v), filedes); 00290 00291 static void ContextThread(LPVOID newContext) 00292 { 00293 SCONTEXT * threadContext = (SCONTEXT *) newContext; 00294 int32_t filedes = threadContext->dwClientID; 00295 00296 Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%X", 00297 threadContext->dwClientID, threadContext); 00298 00299 while (1) 00300 { 00301 struct rxHeader header; 00302 int32_t ret = MessageReceive(&header, sizeof(header), filedes); 00303 00304 if (ret != SCARD_S_SUCCESS) 00305 { 00306 /* Clean up the dead client */ 00307 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00308 EHTryToUnregisterClientForEvent(filedes); 00309 goto exit; 00310 } 00311 00312 if ((header.command > CMD_ENUM_FIRST) 00313 && (header.command < CMD_ENUM_LAST)) 00314 Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d", 00315 CommandsText[header.command], filedes); 00316 00317 switch (header.command) 00318 { 00319 /* pcsc-lite client/server protocol version */ 00320 case CMD_VERSION: 00321 { 00322 struct version_struct veStr; 00323 00324 READ_BODY(veStr) 00325 00326 Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d", 00327 veStr.major, veStr.minor); 00328 00329 veStr.rv = SCARD_S_SUCCESS; 00330 00331 /* client and server use different protocol */ 00332 if ((veStr.major != PROTOCOL_VERSION_MAJOR) 00333 || (veStr.minor != PROTOCOL_VERSION_MINOR)) 00334 { 00335 Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d", 00336 veStr.major, veStr.minor); 00337 Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d", 00338 PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR); 00339 veStr.rv = SCARD_E_NO_SERVICE; 00340 } 00341 00342 /* set the server protocol version */ 00343 veStr.major = PROTOCOL_VERSION_MAJOR; 00344 veStr.minor = PROTOCOL_VERSION_MINOR; 00345 00346 /* send back the response */ 00347 WRITE_BODY(veStr) 00348 } 00349 break; 00350 00351 case CMD_GET_READERS_STATE: 00352 { 00353 /* nothing to read */ 00354 00355 /* wait until all readers are ready */ 00356 RFWaitForReaderInit(); 00357 00358 /* dump the readers state */ 00359 ret = MessageSend(readerStates, sizeof(readerStates), filedes); 00360 } 00361 break; 00362 00363 case CMD_WAIT_READER_STATE_CHANGE: 00364 { 00365 struct wait_reader_state_change waStr; 00366 00367 READ_BODY(waStr) 00368 00369 /* add the client fd to the list */ 00370 EHRegisterClientForEvent(filedes); 00371 00372 /* We do not send anything here. 00373 * Either the client will timeout or the server will 00374 * answer if an event occurs */ 00375 } 00376 break; 00377 00378 case CMD_STOP_WAITING_READER_STATE_CHANGE: 00379 { 00380 struct wait_reader_state_change waStr; 00381 00382 READ_BODY(waStr) 00383 00384 /* add the client fd to the list */ 00385 waStr.rv = EHUnregisterClientForEvent(filedes); 00386 00387 WRITE_BODY(waStr) 00388 } 00389 break; 00390 00391 case SCARD_ESTABLISH_CONTEXT: 00392 { 00393 struct establish_struct esStr; 00394 SCARDCONTEXT hContext; 00395 00396 READ_BODY(esStr) 00397 00398 hContext = esStr.hContext; 00399 esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0, 00400 &hContext); 00401 esStr.hContext = hContext; 00402 00403 if (esStr.rv == SCARD_S_SUCCESS) 00404 esStr.rv = MSGAddContext(esStr.hContext, threadContext); 00405 00406 WRITE_BODY(esStr) 00407 } 00408 break; 00409 00410 case SCARD_RELEASE_CONTEXT: 00411 { 00412 struct release_struct reStr; 00413 00414 READ_BODY(reStr) 00415 00416 reStr.rv = SCardReleaseContext(reStr.hContext); 00417 00418 if (reStr.rv == SCARD_S_SUCCESS) 00419 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext); 00420 00421 WRITE_BODY(reStr) 00422 } 00423 break; 00424 00425 case SCARD_CONNECT: 00426 { 00427 struct connect_struct coStr; 00428 SCARDHANDLE hCard; 00429 DWORD dwActiveProtocol; 00430 00431 READ_BODY(coStr) 00432 00433 hCard = coStr.hCard; 00434 dwActiveProtocol = coStr.dwActiveProtocol; 00435 00436 coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, 00437 coStr.dwShareMode, coStr.dwPreferredProtocols, 00438 &hCard, &dwActiveProtocol); 00439 00440 coStr.hCard = hCard; 00441 coStr.dwActiveProtocol = dwActiveProtocol; 00442 00443 if (coStr.rv == SCARD_S_SUCCESS) 00444 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard, 00445 threadContext); 00446 00447 WRITE_BODY(coStr) 00448 } 00449 break; 00450 00451 case SCARD_RECONNECT: 00452 { 00453 struct reconnect_struct rcStr; 00454 DWORD dwActiveProtocol; 00455 00456 READ_BODY(rcStr) 00457 00458 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext)) 00459 goto exit; 00460 00461 rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode, 00462 rcStr.dwPreferredProtocols, rcStr.dwInitialization, 00463 &dwActiveProtocol); 00464 rcStr.dwActiveProtocol = dwActiveProtocol; 00465 00466 WRITE_BODY(rcStr) 00467 } 00468 break; 00469 00470 case SCARD_DISCONNECT: 00471 { 00472 struct disconnect_struct diStr; 00473 00474 READ_BODY(diStr) 00475 00476 if (MSGCheckHandleAssociation(diStr.hCard, threadContext)) 00477 goto exit; 00478 00479 diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition); 00480 00481 if (SCARD_S_SUCCESS == diStr.rv) 00482 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext); 00483 00484 WRITE_BODY(diStr) 00485 } 00486 break; 00487 00488 case SCARD_BEGIN_TRANSACTION: 00489 { 00490 struct begin_struct beStr; 00491 00492 READ_BODY(beStr) 00493 00494 if (MSGCheckHandleAssociation(beStr.hCard, threadContext)) 00495 goto exit; 00496 00497 beStr.rv = SCardBeginTransaction(beStr.hCard); 00498 00499 WRITE_BODY(beStr) 00500 } 00501 break; 00502 00503 case SCARD_END_TRANSACTION: 00504 { 00505 struct end_struct enStr; 00506 00507 READ_BODY(enStr) 00508 00509 if (MSGCheckHandleAssociation(enStr.hCard, threadContext)) 00510 goto exit; 00511 00512 enStr.rv = SCardEndTransaction(enStr.hCard, 00513 enStr.dwDisposition); 00514 00515 WRITE_BODY(enStr) 00516 } 00517 break; 00518 00519 case SCARD_CANCEL: 00520 { 00521 struct cancel_struct caStr; 00522 SCONTEXT * psTargetContext = NULL; 00523 READ_BODY(caStr) 00524 00525 /* find the client */ 00526 (void)pthread_mutex_lock(&contextsList_lock); 00527 psTargetContext = (SCONTEXT *) list_seek(&contextsList, 00528 &(caStr.hContext)); 00529 (void)pthread_mutex_unlock(&contextsList_lock); 00530 if (psTargetContext != NULL) 00531 { 00532 uint32_t fd = psTargetContext->dwClientID; 00533 caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED); 00534 } 00535 else 00536 caStr.rv = SCARD_E_INVALID_HANDLE; 00537 00538 WRITE_BODY(caStr) 00539 } 00540 break; 00541 00542 case SCARD_STATUS: 00543 { 00544 struct status_struct stStr; 00545 00546 READ_BODY(stStr) 00547 00548 if (MSGCheckHandleAssociation(stStr.hCard, threadContext)) 00549 goto exit; 00550 00551 /* only hCard and return value are used by the client */ 00552 stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL, 00553 NULL, 0, NULL); 00554 00555 WRITE_BODY(stStr) 00556 } 00557 break; 00558 00559 case SCARD_TRANSMIT: 00560 { 00561 struct transmit_struct trStr; 00562 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00563 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00564 SCARD_IO_REQUEST ioSendPci; 00565 SCARD_IO_REQUEST ioRecvPci; 00566 DWORD cbRecvLength; 00567 00568 READ_BODY(trStr) 00569 00570 if (MSGCheckHandleAssociation(trStr.hCard, threadContext)) 00571 goto exit; 00572 00573 /* avoids buffer overflow */ 00574 if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer)) 00575 || (trStr.cbSendLength > sizeof(pbSendBuffer))) 00576 goto buffer_overflow; 00577 00578 /* read sent buffer */ 00579 ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes); 00580 if (ret != SCARD_S_SUCCESS) 00581 { 00582 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00583 goto exit; 00584 } 00585 00586 ioSendPci.dwProtocol = trStr.ioSendPciProtocol; 00587 ioSendPci.cbPciLength = trStr.ioSendPciLength; 00588 ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol; 00589 ioRecvPci.cbPciLength = trStr.ioRecvPciLength; 00590 cbRecvLength = trStr.pcbRecvLength; 00591 00592 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci, 00593 pbSendBuffer, trStr.cbSendLength, &ioRecvPci, 00594 pbRecvBuffer, &cbRecvLength); 00595 00596 trStr.ioSendPciProtocol = ioSendPci.dwProtocol; 00597 trStr.ioSendPciLength = ioSendPci.cbPciLength; 00598 trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol; 00599 trStr.ioRecvPciLength = ioRecvPci.cbPciLength; 00600 trStr.pcbRecvLength = cbRecvLength; 00601 00602 WRITE_BODY(trStr) 00603 00604 /* write received buffer */ 00605 if (SCARD_S_SUCCESS == trStr.rv) 00606 ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes); 00607 } 00608 break; 00609 00610 case SCARD_CONTROL: 00611 { 00612 struct control_struct ctStr; 00613 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00614 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00615 DWORD dwBytesReturned; 00616 00617 READ_BODY(ctStr) 00618 00619 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext)) 00620 goto exit; 00621 00622 /* avoids buffer overflow */ 00623 if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer)) 00624 || (ctStr.cbSendLength > sizeof(pbSendBuffer))) 00625 { 00626 goto buffer_overflow; 00627 } 00628 00629 /* read sent buffer */ 00630 ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes); 00631 if (ret != SCARD_S_SUCCESS) 00632 { 00633 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00634 goto exit; 00635 } 00636 00637 dwBytesReturned = ctStr.dwBytesReturned; 00638 00639 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode, 00640 pbSendBuffer, ctStr.cbSendLength, 00641 pbRecvBuffer, ctStr.cbRecvLength, 00642 &dwBytesReturned); 00643 00644 ctStr.dwBytesReturned = dwBytesReturned; 00645 00646 WRITE_BODY(ctStr) 00647 00648 /* write received buffer */ 00649 if (SCARD_S_SUCCESS == ctStr.rv) 00650 ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes); 00651 } 00652 break; 00653 00654 case SCARD_GET_ATTRIB: 00655 { 00656 struct getset_struct gsStr; 00657 DWORD cbAttrLen; 00658 00659 READ_BODY(gsStr) 00660 00661 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) 00662 goto exit; 00663 00664 /* avoids buffer overflow */ 00665 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) 00666 goto buffer_overflow; 00667 00668 cbAttrLen = gsStr.cbAttrLen; 00669 00670 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId, 00671 gsStr.pbAttr, &cbAttrLen); 00672 00673 gsStr.cbAttrLen = cbAttrLen; 00674 00675 WRITE_BODY(gsStr) 00676 } 00677 break; 00678 00679 case SCARD_SET_ATTRIB: 00680 { 00681 struct getset_struct gsStr; 00682 00683 READ_BODY(gsStr) 00684 00685 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) 00686 goto exit; 00687 00688 /* avoids buffer overflow */ 00689 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) 00690 goto buffer_overflow; 00691 00692 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId, 00693 gsStr.pbAttr, gsStr.cbAttrLen); 00694 00695 WRITE_BODY(gsStr) 00696 } 00697 break; 00698 00699 default: 00700 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command); 00701 goto exit; 00702 } 00703 00704 /* MessageSend() failed */ 00705 if (ret != SCARD_S_SUCCESS) 00706 { 00707 /* Clean up the dead client */ 00708 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00709 goto exit; 00710 } 00711 } 00712 00713 buffer_overflow: 00714 Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes); 00715 goto exit; 00716 wrong_length: 00717 Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes); 00718 exit: 00719 (void)close(filedes); 00720 (void)MSGCleanupClient(threadContext); 00721 (void)pthread_exit((LPVOID) NULL); 00722 } 00723 00724 LONG MSGSignalClient(uint32_t filedes, LONG rv) 00725 { 00726 uint32_t ret; 00727 struct wait_reader_state_change waStr; 00728 00729 Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes); 00730 00731 waStr.rv = rv; 00732 WRITE_BODY_WITH_COMMAND("SIGNAL", waStr) 00733 00734 return ret; 00735 } /* MSGSignalClient */ 00736 00737 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) 00738 { 00739 threadContext->hContext = hContext; 00740 return SCARD_S_SUCCESS; 00741 } 00742 00743 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) 00744 { 00745 LONG rv; 00746 int lrv; 00747 00748 if (threadContext->hContext != hContext) 00749 return SCARD_E_INVALID_VALUE; 00750 00751 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00752 while (list_size(&(threadContext->cardsList)) != 0) 00753 { 00754 READER_CONTEXT * rContext = NULL; 00755 SCARDHANDLE hCard, hLockId; 00756 void *ptr; 00757 00758 /* 00759 * Disconnect each of these just in case 00760 */ 00761 ptr = list_get_at(&(threadContext->cardsList), 0); 00762 if (NULL == ptr) 00763 { 00764 Log1(PCSC_LOG_CRITICAL, "list_get_at failed"); 00765 continue; 00766 } 00767 hCard = *(int32_t *)ptr; 00768 00769 /* 00770 * Unlock the sharing 00771 */ 00772 rv = RFReaderInfoById(hCard, &rContext); 00773 if (rv != SCARD_S_SUCCESS) 00774 { 00775 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00776 return rv; 00777 } 00778 00779 hLockId = rContext->hLockId; 00780 rContext->hLockId = 0; 00781 00782 if (hCard != hLockId) 00783 { 00784 /* 00785 * if the card is locked by someone else we do not reset it 00786 * and simulate a card removal 00787 */ 00788 rv = SCARD_W_REMOVED_CARD; 00789 } 00790 else 00791 { 00792 /* 00793 * We will use SCardStatus to see if the card has been 00794 * reset there is no need to reset each time 00795 * Disconnect is called 00796 */ 00797 rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL); 00798 } 00799 00800 if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD) 00801 (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD); 00802 else 00803 (void)SCardDisconnect(hCard, SCARD_RESET_CARD); 00804 00805 /* Remove entry from the list */ 00806 lrv = list_delete_at(&(threadContext->cardsList), 0); 00807 if (lrv < 0) 00808 Log2(PCSC_LOG_CRITICAL, 00809 "list_delete_at failed with return value: %d", lrv); 00810 } 00811 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00812 list_destroy(&(threadContext->cardsList)); 00813 00814 /* We only mark the context as no longer in use. 00815 * The memory is freed in MSGCleanupCLient() */ 00816 threadContext->hContext = 0; 00817 00818 return SCARD_S_SUCCESS; 00819 } 00820 00821 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, 00822 SCONTEXT * threadContext) 00823 { 00824 if (threadContext->hContext == hContext) 00825 { 00826 /* 00827 * Find an empty spot to put the hCard value 00828 */ 00829 int listLength, lrv; 00830 00831 listLength = list_size(&(threadContext->cardsList)); 00832 if (listLength >= contextMaxCardHandles) 00833 { 00834 Log4(PCSC_LOG_DEBUG, 00835 "Too many card handles for thread context @%X: %d (max is %d)" 00836 "Restart pcscd with --max-card-handle-per-thread value", 00837 threadContext, listLength, contextMaxCardHandles); 00838 return SCARD_E_NO_MEMORY; 00839 } 00840 00841 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00842 lrv = list_append(&(threadContext->cardsList), &hCard); 00843 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00844 if (lrv < 0) 00845 { 00846 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d", 00847 lrv); 00848 return SCARD_E_NO_MEMORY; 00849 } 00850 return SCARD_S_SUCCESS; 00851 } 00852 00853 return SCARD_E_INVALID_VALUE; 00854 } 00855 00856 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext) 00857 { 00858 int lrv; 00859 00860 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00861 lrv = list_delete(&(threadContext->cardsList), &hCard); 00862 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00863 if (lrv < 0) 00864 { 00865 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv); 00866 return SCARD_E_INVALID_VALUE; 00867 } 00868 00869 return SCARD_S_SUCCESS; 00870 } 00871 00872 00873 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, 00874 SCONTEXT * threadContext) 00875 { 00876 int list_index = 0; 00877 00878 if (0 == threadContext->hContext) 00879 { 00880 /* the handle is no more valid. After SCardReleaseContext() for 00881 * example */ 00882 Log1(PCSC_LOG_CRITICAL, "Invalidated handle"); 00883 return -1; 00884 } 00885 00886 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00887 list_index = list_locate(&(threadContext->cardsList), &hCard); 00888 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00889 if (list_index >= 0) 00890 return 0; 00891 00892 /* Must be a rogue client, debug log and sleep a couple of seconds */ 00893 Log1(PCSC_LOG_ERROR, "Client failed to authenticate"); 00894 (void)SYS_Sleep(2); 00895 00896 return -1; 00897 } 00898 00899 00900 /* Should be called just prior to exiting the thread as it de-allocates 00901 * the thread memory strucutres 00902 */ 00903 static LONG MSGCleanupClient(SCONTEXT * threadContext) 00904 { 00905 int lrv; 00906 int listSize; 00907 00908 if (threadContext->hContext != 0) 00909 { 00910 (void)SCardReleaseContext(threadContext->hContext); 00911 (void)MSGRemoveContext(threadContext->hContext, threadContext); 00912 } 00913 00914 Log3(PCSC_LOG_DEBUG, 00915 "Thread is stopping: dwClientID=%d, threadContext @%X", 00916 threadContext->dwClientID, threadContext); 00917 00918 /* Clear the struct to ensure that we detect 00919 * access to de-allocated memory 00920 * Hopefully the compiler won't optimise it out */ 00921 memset((void*) threadContext, 0, sizeof(SCONTEXT)); 00922 Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%X", threadContext); 00923 00924 (void)pthread_mutex_lock(&contextsList_lock); 00925 lrv = list_delete(&contextsList, threadContext); 00926 listSize = list_size(&contextsList); 00927 (void)pthread_mutex_unlock(&contextsList_lock); 00928 if (lrv < 0) 00929 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv); 00930 00931 free(threadContext); 00932 00933 /* start a suicide alarm */ 00934 if (AutoExit && (listSize < 1)) 00935 { 00936 Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds", 00937 TIME_BEFORE_SUICIDE); 00938 alarm(TIME_BEFORE_SUICIDE); 00939 } 00940 00941 return 0; 00942 }