pcsc-lite
1.8.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-2011 00009 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00010 * Copyright (C) 2009 00011 * Jean-Luc Giraud <jlgiraud@googlemail.com> 00012 * 00013 * $Id: winscard_svc.c 5864 2011-07-09 11:37:48Z 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=%p, key=%p", 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 @%p", 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 #ifdef USE_USB 00356 /* wait until all readers are ready */ 00357 RFWaitForReaderInit(); 00358 #endif 00359 00360 /* dump the readers state */ 00361 ret = MessageSend(readerStates, sizeof(readerStates), filedes); 00362 } 00363 break; 00364 00365 case CMD_WAIT_READER_STATE_CHANGE: 00366 { 00367 struct wait_reader_state_change waStr; 00368 00369 READ_BODY(waStr) 00370 00371 /* add the client fd to the list */ 00372 EHRegisterClientForEvent(filedes); 00373 00374 /* We do not send anything here. 00375 * Either the client will timeout or the server will 00376 * answer if an event occurs */ 00377 } 00378 break; 00379 00380 case CMD_STOP_WAITING_READER_STATE_CHANGE: 00381 { 00382 struct wait_reader_state_change waStr; 00383 00384 READ_BODY(waStr) 00385 00386 /* add the client fd to the list */ 00387 waStr.rv = EHUnregisterClientForEvent(filedes); 00388 00389 WRITE_BODY(waStr) 00390 } 00391 break; 00392 00393 case SCARD_ESTABLISH_CONTEXT: 00394 { 00395 struct establish_struct esStr; 00396 SCARDCONTEXT hContext; 00397 00398 READ_BODY(esStr) 00399 00400 hContext = esStr.hContext; 00401 esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0, 00402 &hContext); 00403 esStr.hContext = hContext; 00404 00405 if (esStr.rv == SCARD_S_SUCCESS) 00406 esStr.rv = MSGAddContext(esStr.hContext, threadContext); 00407 00408 WRITE_BODY(esStr) 00409 } 00410 break; 00411 00412 case SCARD_RELEASE_CONTEXT: 00413 { 00414 struct release_struct reStr; 00415 00416 READ_BODY(reStr) 00417 00418 reStr.rv = SCardReleaseContext(reStr.hContext); 00419 00420 if (reStr.rv == SCARD_S_SUCCESS) 00421 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext); 00422 00423 WRITE_BODY(reStr) 00424 } 00425 break; 00426 00427 case SCARD_CONNECT: 00428 { 00429 struct connect_struct coStr; 00430 SCARDHANDLE hCard; 00431 DWORD dwActiveProtocol; 00432 00433 READ_BODY(coStr) 00434 00435 hCard = coStr.hCard; 00436 dwActiveProtocol = coStr.dwActiveProtocol; 00437 00438 coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, 00439 coStr.dwShareMode, coStr.dwPreferredProtocols, 00440 &hCard, &dwActiveProtocol); 00441 00442 coStr.hCard = hCard; 00443 coStr.dwActiveProtocol = dwActiveProtocol; 00444 00445 if (coStr.rv == SCARD_S_SUCCESS) 00446 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard, 00447 threadContext); 00448 00449 WRITE_BODY(coStr) 00450 } 00451 break; 00452 00453 case SCARD_RECONNECT: 00454 { 00455 struct reconnect_struct rcStr; 00456 DWORD dwActiveProtocol; 00457 00458 READ_BODY(rcStr) 00459 00460 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext)) 00461 goto exit; 00462 00463 rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode, 00464 rcStr.dwPreferredProtocols, rcStr.dwInitialization, 00465 &dwActiveProtocol); 00466 rcStr.dwActiveProtocol = dwActiveProtocol; 00467 00468 WRITE_BODY(rcStr) 00469 } 00470 break; 00471 00472 case SCARD_DISCONNECT: 00473 { 00474 struct disconnect_struct diStr; 00475 00476 READ_BODY(diStr) 00477 00478 if (MSGCheckHandleAssociation(diStr.hCard, threadContext)) 00479 goto exit; 00480 00481 diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition); 00482 00483 if (SCARD_S_SUCCESS == diStr.rv) 00484 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext); 00485 00486 WRITE_BODY(diStr) 00487 } 00488 break; 00489 00490 case SCARD_BEGIN_TRANSACTION: 00491 { 00492 struct begin_struct beStr; 00493 00494 READ_BODY(beStr) 00495 00496 if (MSGCheckHandleAssociation(beStr.hCard, threadContext)) 00497 goto exit; 00498 00499 beStr.rv = SCardBeginTransaction(beStr.hCard); 00500 00501 WRITE_BODY(beStr) 00502 } 00503 break; 00504 00505 case SCARD_END_TRANSACTION: 00506 { 00507 struct end_struct enStr; 00508 00509 READ_BODY(enStr) 00510 00511 if (MSGCheckHandleAssociation(enStr.hCard, threadContext)) 00512 goto exit; 00513 00514 enStr.rv = SCardEndTransaction(enStr.hCard, 00515 enStr.dwDisposition); 00516 00517 WRITE_BODY(enStr) 00518 } 00519 break; 00520 00521 case SCARD_CANCEL: 00522 { 00523 struct cancel_struct caStr; 00524 SCONTEXT * psTargetContext = NULL; 00525 READ_BODY(caStr) 00526 00527 /* find the client */ 00528 (void)pthread_mutex_lock(&contextsList_lock); 00529 psTargetContext = (SCONTEXT *) list_seek(&contextsList, 00530 &(caStr.hContext)); 00531 (void)pthread_mutex_unlock(&contextsList_lock); 00532 if (psTargetContext != NULL) 00533 { 00534 uint32_t fd = psTargetContext->dwClientID; 00535 caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED); 00536 } 00537 else 00538 caStr.rv = SCARD_E_INVALID_HANDLE; 00539 00540 WRITE_BODY(caStr) 00541 } 00542 break; 00543 00544 case SCARD_STATUS: 00545 { 00546 struct status_struct stStr; 00547 00548 READ_BODY(stStr) 00549 00550 if (MSGCheckHandleAssociation(stStr.hCard, threadContext)) 00551 goto exit; 00552 00553 /* only hCard and return value are used by the client */ 00554 stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL, 00555 NULL, 0, NULL); 00556 00557 WRITE_BODY(stStr) 00558 } 00559 break; 00560 00561 case SCARD_TRANSMIT: 00562 { 00563 struct transmit_struct trStr; 00564 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00565 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00566 SCARD_IO_REQUEST ioSendPci; 00567 SCARD_IO_REQUEST ioRecvPci; 00568 DWORD cbRecvLength; 00569 00570 READ_BODY(trStr) 00571 00572 if (MSGCheckHandleAssociation(trStr.hCard, threadContext)) 00573 goto exit; 00574 00575 /* avoids buffer overflow */ 00576 if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer)) 00577 || (trStr.cbSendLength > sizeof(pbSendBuffer))) 00578 goto buffer_overflow; 00579 00580 /* read sent buffer */ 00581 ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes); 00582 if (ret != SCARD_S_SUCCESS) 00583 { 00584 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00585 goto exit; 00586 } 00587 00588 ioSendPci.dwProtocol = trStr.ioSendPciProtocol; 00589 ioSendPci.cbPciLength = trStr.ioSendPciLength; 00590 ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol; 00591 ioRecvPci.cbPciLength = trStr.ioRecvPciLength; 00592 cbRecvLength = trStr.pcbRecvLength; 00593 00594 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci, 00595 pbSendBuffer, trStr.cbSendLength, &ioRecvPci, 00596 pbRecvBuffer, &cbRecvLength); 00597 00598 trStr.ioSendPciProtocol = ioSendPci.dwProtocol; 00599 trStr.ioSendPciLength = ioSendPci.cbPciLength; 00600 trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol; 00601 trStr.ioRecvPciLength = ioRecvPci.cbPciLength; 00602 trStr.pcbRecvLength = cbRecvLength; 00603 00604 WRITE_BODY(trStr) 00605 00606 /* write received buffer */ 00607 if (SCARD_S_SUCCESS == trStr.rv) 00608 ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes); 00609 } 00610 break; 00611 00612 case SCARD_CONTROL: 00613 { 00614 struct control_struct ctStr; 00615 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00616 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; 00617 DWORD dwBytesReturned; 00618 00619 READ_BODY(ctStr) 00620 00621 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext)) 00622 goto exit; 00623 00624 /* avoids buffer overflow */ 00625 if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer)) 00626 || (ctStr.cbSendLength > sizeof(pbSendBuffer))) 00627 { 00628 goto buffer_overflow; 00629 } 00630 00631 /* read sent buffer */ 00632 ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes); 00633 if (ret != SCARD_S_SUCCESS) 00634 { 00635 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00636 goto exit; 00637 } 00638 00639 dwBytesReturned = ctStr.dwBytesReturned; 00640 00641 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode, 00642 pbSendBuffer, ctStr.cbSendLength, 00643 pbRecvBuffer, ctStr.cbRecvLength, 00644 &dwBytesReturned); 00645 00646 ctStr.dwBytesReturned = dwBytesReturned; 00647 00648 WRITE_BODY(ctStr) 00649 00650 /* write received buffer */ 00651 if (SCARD_S_SUCCESS == ctStr.rv) 00652 ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes); 00653 } 00654 break; 00655 00656 case SCARD_GET_ATTRIB: 00657 { 00658 struct getset_struct gsStr; 00659 DWORD cbAttrLen; 00660 00661 READ_BODY(gsStr) 00662 00663 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) 00664 goto exit; 00665 00666 /* avoids buffer overflow */ 00667 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) 00668 goto buffer_overflow; 00669 00670 cbAttrLen = gsStr.cbAttrLen; 00671 00672 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId, 00673 gsStr.pbAttr, &cbAttrLen); 00674 00675 gsStr.cbAttrLen = cbAttrLen; 00676 00677 WRITE_BODY(gsStr) 00678 } 00679 break; 00680 00681 case SCARD_SET_ATTRIB: 00682 { 00683 struct getset_struct gsStr; 00684 00685 READ_BODY(gsStr) 00686 00687 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) 00688 goto exit; 00689 00690 /* avoids buffer overflow */ 00691 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) 00692 goto buffer_overflow; 00693 00694 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId, 00695 gsStr.pbAttr, gsStr.cbAttrLen); 00696 00697 WRITE_BODY(gsStr) 00698 } 00699 break; 00700 00701 default: 00702 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command); 00703 goto exit; 00704 } 00705 00706 /* MessageSend() failed */ 00707 if (ret != SCARD_S_SUCCESS) 00708 { 00709 /* Clean up the dead client */ 00710 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); 00711 goto exit; 00712 } 00713 } 00714 00715 buffer_overflow: 00716 Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes); 00717 goto exit; 00718 wrong_length: 00719 Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes); 00720 exit: 00721 (void)close(filedes); 00722 (void)MSGCleanupClient(threadContext); 00723 (void)pthread_exit((LPVOID) NULL); 00724 } 00725 00726 LONG MSGSignalClient(uint32_t filedes, LONG rv) 00727 { 00728 uint32_t ret; 00729 struct wait_reader_state_change waStr; 00730 00731 Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes); 00732 00733 waStr.rv = rv; 00734 WRITE_BODY_WITH_COMMAND("SIGNAL", waStr) 00735 00736 return ret; 00737 } /* MSGSignalClient */ 00738 00739 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) 00740 { 00741 threadContext->hContext = hContext; 00742 return SCARD_S_SUCCESS; 00743 } 00744 00745 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) 00746 { 00747 LONG rv; 00748 int lrv; 00749 00750 if (threadContext->hContext != hContext) 00751 return SCARD_E_INVALID_VALUE; 00752 00753 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00754 while (list_size(&(threadContext->cardsList)) != 0) 00755 { 00756 READER_CONTEXT * rContext = NULL; 00757 SCARDHANDLE hCard, hLockId; 00758 void *ptr; 00759 00760 /* 00761 * Disconnect each of these just in case 00762 */ 00763 ptr = list_get_at(&(threadContext->cardsList), 0); 00764 if (NULL == ptr) 00765 { 00766 Log1(PCSC_LOG_CRITICAL, "list_get_at failed"); 00767 continue; 00768 } 00769 hCard = *(int32_t *)ptr; 00770 00771 /* 00772 * Unlock the sharing 00773 */ 00774 rv = RFReaderInfoById(hCard, &rContext); 00775 if (rv != SCARD_S_SUCCESS) 00776 { 00777 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00778 return rv; 00779 } 00780 00781 hLockId = rContext->hLockId; 00782 rContext->hLockId = 0; 00783 00784 if (hCard != hLockId) 00785 { 00786 /* 00787 * if the card is locked by someone else we do not reset it 00788 * and simulate a card removal 00789 */ 00790 rv = SCARD_W_REMOVED_CARD; 00791 } 00792 else 00793 { 00794 /* 00795 * We will use SCardStatus to see if the card has been 00796 * reset there is no need to reset each time 00797 * Disconnect is called 00798 */ 00799 rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL); 00800 } 00801 00802 if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD) 00803 (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD); 00804 else 00805 (void)SCardDisconnect(hCard, SCARD_RESET_CARD); 00806 00807 /* Remove entry from the list */ 00808 lrv = list_delete_at(&(threadContext->cardsList), 0); 00809 if (lrv < 0) 00810 Log2(PCSC_LOG_CRITICAL, 00811 "list_delete_at failed with return value: %d", lrv); 00812 } 00813 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00814 list_destroy(&(threadContext->cardsList)); 00815 00816 /* We only mark the context as no longer in use. 00817 * The memory is freed in MSGCleanupCLient() */ 00818 threadContext->hContext = 0; 00819 00820 return SCARD_S_SUCCESS; 00821 } 00822 00823 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, 00824 SCONTEXT * threadContext) 00825 { 00826 if (threadContext->hContext == hContext) 00827 { 00828 /* 00829 * Find an empty spot to put the hCard value 00830 */ 00831 int listLength, lrv; 00832 00833 listLength = list_size(&(threadContext->cardsList)); 00834 if (listLength >= contextMaxCardHandles) 00835 { 00836 Log4(PCSC_LOG_DEBUG, 00837 "Too many card handles for thread context @%p: %d (max is %d)" 00838 "Restart pcscd with --max-card-handle-per-thread value", 00839 threadContext, listLength, contextMaxCardHandles); 00840 return SCARD_E_NO_MEMORY; 00841 } 00842 00843 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00844 lrv = list_append(&(threadContext->cardsList), &hCard); 00845 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00846 if (lrv < 0) 00847 { 00848 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d", 00849 lrv); 00850 return SCARD_E_NO_MEMORY; 00851 } 00852 return SCARD_S_SUCCESS; 00853 } 00854 00855 return SCARD_E_INVALID_VALUE; 00856 } 00857 00858 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext) 00859 { 00860 int lrv; 00861 00862 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00863 lrv = list_delete(&(threadContext->cardsList), &hCard); 00864 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00865 if (lrv < 0) 00866 { 00867 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv); 00868 return SCARD_E_INVALID_VALUE; 00869 } 00870 00871 return SCARD_S_SUCCESS; 00872 } 00873 00874 00875 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, 00876 SCONTEXT * threadContext) 00877 { 00878 int list_index = 0; 00879 00880 if (0 == threadContext->hContext) 00881 { 00882 /* the handle is no more valid. After SCardReleaseContext() for 00883 * example */ 00884 Log1(PCSC_LOG_CRITICAL, "Invalidated handle"); 00885 return -1; 00886 } 00887 00888 (void)pthread_mutex_lock(&threadContext->cardsList_lock); 00889 list_index = list_locate(&(threadContext->cardsList), &hCard); 00890 (void)pthread_mutex_unlock(&threadContext->cardsList_lock); 00891 if (list_index >= 0) 00892 return 0; 00893 00894 /* Must be a rogue client, debug log and sleep a couple of seconds */ 00895 Log1(PCSC_LOG_ERROR, "Client failed to authenticate"); 00896 (void)SYS_Sleep(2); 00897 00898 return -1; 00899 } 00900 00901 00902 /* Should be called just prior to exiting the thread as it de-allocates 00903 * the thread memory strucutres 00904 */ 00905 static LONG MSGCleanupClient(SCONTEXT * threadContext) 00906 { 00907 int lrv; 00908 int listSize; 00909 00910 if (threadContext->hContext != 0) 00911 { 00912 (void)SCardReleaseContext(threadContext->hContext); 00913 (void)MSGRemoveContext(threadContext->hContext, threadContext); 00914 } 00915 00916 Log3(PCSC_LOG_DEBUG, 00917 "Thread is stopping: dwClientID=%d, threadContext @%p", 00918 threadContext->dwClientID, threadContext); 00919 00920 /* Clear the struct to ensure that we detect 00921 * access to de-allocated memory 00922 * Hopefully the compiler won't optimise it out */ 00923 memset((void*) threadContext, 0, sizeof(SCONTEXT)); 00924 Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext); 00925 00926 (void)pthread_mutex_lock(&contextsList_lock); 00927 lrv = list_delete(&contextsList, threadContext); 00928 listSize = list_size(&contextsList); 00929 (void)pthread_mutex_unlock(&contextsList_lock); 00930 if (lrv < 0) 00931 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv); 00932 00933 free(threadContext); 00934 00935 /* start a suicide alarm */ 00936 if (AutoExit && (listSize < 1)) 00937 { 00938 Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds", 00939 TIME_BEFORE_SUICIDE); 00940 alarm(TIME_BEFORE_SUICIDE); 00941 } 00942 00943 return 0; 00944 }