pcsc-lite 1.6.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-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 }