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