pcsc-lite  1.7.4
winscard_svc.c
Go to the documentation of this file.
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 5765 2011-05-22 11:33:09Z 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 #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 @%X: %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 @%X",
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 @%X", 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 }