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-2009
00009  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00010  * Copyright (C) 2009
00011  *  Jean-Luc Giraud <jlgiraud@googlemail.com>
00012  *
00013  * $Id: winscard_svc.c 4967 2010-05-29 11:28:16Z 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(SCARD_S_SUCCESS == v.rv ? PCSC_LOG_DEBUG : PCSC_LOG_ERROR, "%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                 LONG rv;
00474 
00475                 READ_BODY(diStr)
00476 
00477                 rv = MSGCheckHandleAssociation(diStr.hCard, threadContext);
00478                 if (0 == rv)
00479                 {
00480                     diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
00481 
00482                     if (SCARD_S_SUCCESS == diStr.rv)
00483                         diStr.rv =
00484                             MSGRemoveHandle(diStr.hCard, threadContext);
00485                 }
00486 
00487                 WRITE_BODY(diStr)
00488             }
00489             break;
00490 
00491             case SCARD_BEGIN_TRANSACTION:
00492             {
00493                 struct begin_struct beStr;
00494                 LONG rv;
00495 
00496                 READ_BODY(beStr)
00497 
00498                 rv = MSGCheckHandleAssociation(beStr.hCard, threadContext);
00499                 if (0 == rv)
00500                     beStr.rv = SCardBeginTransaction(beStr.hCard);
00501 
00502                 WRITE_BODY(beStr)
00503             }
00504             break;
00505 
00506             case SCARD_END_TRANSACTION:
00507             {
00508                 struct end_struct enStr;
00509                 LONG rv;
00510 
00511                 READ_BODY(enStr)
00512 
00513                 rv = MSGCheckHandleAssociation(enStr.hCard, threadContext);
00514                 if (0 == rv)
00515                     enStr.rv =
00516                         SCardEndTransaction(enStr.hCard, enStr.dwDisposition);
00517 
00518                 WRITE_BODY(enStr)
00519             }
00520             break;
00521 
00522             case SCARD_CANCEL_TRANSACTION:
00523             {
00524                 struct cancel_transaction_struct caStr;
00525                 LONG rv;
00526 
00527                 READ_BODY(caStr)
00528 
00529                 rv = MSGCheckHandleAssociation(caStr.hCard, threadContext);
00530                 if (0 == rv)
00531                     caStr.rv = SCardCancelTransaction(caStr.hCard);
00532 
00533                 WRITE_BODY(caStr)
00534             }
00535             break;
00536 
00537             case SCARD_CANCEL:
00538             {
00539                 struct cancel_struct caStr;
00540                 SCONTEXT * psTargetContext = NULL;
00541                 READ_BODY(caStr)
00542 
00543                 /* find the client */
00544                 (void)pthread_mutex_lock(&contextsList_lock);
00545                 psTargetContext = (SCONTEXT *) list_seek(&contextsList,
00546                     &(caStr.hContext));
00547                 (void)pthread_mutex_unlock(&contextsList_lock);
00548                 if (psTargetContext != NULL)
00549                 {
00550                     uint32_t fd = psTargetContext->dwClientID;
00551                     caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
00552                 }
00553                 else
00554                     caStr.rv = SCARD_E_INVALID_HANDLE;
00555 
00556                 WRITE_BODY(caStr)
00557             }
00558             break;
00559 
00560             case SCARD_STATUS:
00561             {
00562                 struct status_struct stStr;
00563                 LONG rv;
00564 
00565                 READ_BODY(stStr)
00566 
00567                 rv = MSGCheckHandleAssociation(stStr.hCard, threadContext);
00568                 if (0 == rv)
00569                 {
00570                     DWORD cchReaderLen;
00571                     DWORD dwState;
00572                     DWORD dwProtocol;
00573                     DWORD cbAtrLen;
00574 
00575                     cchReaderLen = stStr.pcchReaderLen;
00576                     dwState = stStr.dwState;
00577                     dwProtocol = stStr.dwProtocol;
00578                     cbAtrLen = stStr.pcbAtrLen;
00579 
00580                     /* avoids buffer overflow */
00581                     if ((cchReaderLen > sizeof(stStr.mszReaderNames))
00582                         || (cbAtrLen > sizeof(stStr.pbAtr)))
00583                     {
00584                         stStr.rv = SCARD_E_INSUFFICIENT_BUFFER ;
00585                     }
00586                     else
00587                     {
00588                         stStr.rv = SCardStatus(stStr.hCard,
00589                             stStr.mszReaderNames,
00590                             &cchReaderLen, &dwState,
00591                             &dwProtocol, stStr.pbAtr, &cbAtrLen);
00592 
00593                         stStr.pcchReaderLen = cchReaderLen;
00594                         stStr.dwState = dwState;
00595                         stStr.dwProtocol = dwProtocol;
00596                         stStr.pcbAtrLen = cbAtrLen;
00597                     }
00598                 }
00599 
00600                 WRITE_BODY(stStr)
00601             }
00602             break;
00603 
00604             case SCARD_TRANSMIT:
00605             {
00606                 struct transmit_struct trStr;
00607                 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00608                 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00609                 SCARD_IO_REQUEST ioSendPci;
00610                 SCARD_IO_REQUEST ioRecvPci;
00611                 DWORD cbRecvLength;
00612 
00613                 READ_BODY(trStr)
00614 
00615                 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
00616                     goto exit;
00617 
00618                 /* avoids buffer overflow */
00619                 if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
00620                     || (trStr.cbSendLength > sizeof(pbSendBuffer)))
00621                     goto exit;
00622 
00623                 /* read sent buffer */
00624                 ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
00625                 if (ret < 0)
00626                 {
00627                     Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
00628                     goto exit;
00629                 }
00630 
00631                 ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
00632                 ioSendPci.cbPciLength = trStr.ioSendPciLength;
00633                 ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
00634                 ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
00635                 cbRecvLength = trStr.pcbRecvLength;
00636 
00637                 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
00638                     pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
00639                     pbRecvBuffer, &cbRecvLength);
00640 
00641                 trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
00642                 trStr.ioSendPciLength = ioSendPci.cbPciLength;
00643                 trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
00644                 trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
00645                 trStr.pcbRecvLength = cbRecvLength;
00646 
00647                 WRITE_BODY(trStr)
00648 
00649                 /* write received buffer */
00650                 if (SCARD_S_SUCCESS == trStr.rv)
00651                     ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
00652             }
00653             break;
00654 
00655             case SCARD_CONTROL:
00656             {
00657                 struct control_struct ctStr;
00658                 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00659                 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00660                 DWORD dwBytesReturned;
00661 
00662                 READ_BODY(ctStr)
00663 
00664                 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
00665                     goto exit;
00666 
00667                 /* avoids buffer overflow */
00668                 if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
00669                     || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
00670                 {
00671                     goto exit;
00672                 }
00673 
00674                 /* read sent buffer */
00675                 ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
00676                 if (ret < 0)
00677                 {
00678                     Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
00679                     goto exit;
00680                 }
00681 
00682                 dwBytesReturned = ctStr.dwBytesReturned;
00683 
00684                 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
00685                     pbSendBuffer, ctStr.cbSendLength,
00686                     pbRecvBuffer, ctStr.cbRecvLength,
00687                     &dwBytesReturned);
00688 
00689                 ctStr.dwBytesReturned = dwBytesReturned;
00690 
00691                 WRITE_BODY(ctStr)
00692 
00693                 /* write received buffer */
00694                 if (SCARD_S_SUCCESS == ctStr.rv)
00695                     ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
00696             }
00697             break;
00698 
00699             case SCARD_GET_ATTRIB:
00700             {
00701                 struct getset_struct gsStr;
00702                 DWORD cbAttrLen;
00703 
00704                 READ_BODY(gsStr)
00705 
00706                 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
00707                     goto exit;
00708 
00709                 /* avoids buffer overflow */
00710                 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
00711                     goto buffer_overflow;
00712 
00713                 cbAttrLen = gsStr.cbAttrLen;
00714 
00715                 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
00716                         gsStr.pbAttr, &cbAttrLen);
00717 
00718                 gsStr.cbAttrLen = cbAttrLen;
00719 
00720                 WRITE_BODY(gsStr)
00721             }
00722             break;
00723 
00724             case SCARD_SET_ATTRIB:
00725             {
00726                 struct getset_struct gsStr;
00727 
00728                 READ_BODY(gsStr)
00729 
00730                 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
00731                     goto buffer_overflow;
00732 
00733                 /* avoids buffer overflow */
00734                 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
00735                     goto buffer_overflow;
00736 
00737                 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
00738                     gsStr.pbAttr, gsStr.cbAttrLen);
00739 
00740                 WRITE_BODY(gsStr)
00741             }
00742             break;
00743 
00744             default:
00745                 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
00746                 goto exit;
00747         }
00748 
00749         /* MessageSend() failed */
00750         if (-1 == ret)
00751         {
00752             /* Clean up the dead client */
00753             Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
00754             goto exit;
00755         }
00756     }
00757 
00758 buffer_overflow:
00759     Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
00760     goto exit;
00761 wrong_length:
00762     Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
00763 exit:
00764     (void)close(filedes);
00765     (void)MSGCleanupClient(threadContext);
00766     (void)pthread_exit((LPVOID) NULL);
00767 }
00768 
00769 LONG MSGSignalClient(uint32_t filedes, LONG rv)
00770 {
00771     uint32_t ret;
00772     struct wait_reader_state_change waStr;
00773 
00774     Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
00775 
00776     waStr.rv = rv;
00777     WRITE_BODY_WITH_COMMAND("SIGNAL", waStr)
00778 
00779     return ret;
00780 } /* MSGSignalClient */
00781 
00782 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
00783 {
00784     threadContext->hContext = hContext;
00785     return SCARD_S_SUCCESS;
00786 }
00787 
00788 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
00789 {
00790     LONG rv;
00791     int lrv;
00792 
00793     if (threadContext->hContext != hContext)
00794         return SCARD_E_INVALID_VALUE;
00795 
00796     (void)pthread_mutex_lock(&threadContext->cardsList_lock);
00797     while (list_size(&(threadContext->cardsList)) != 0)
00798     {
00799         READER_CONTEXT * rContext = NULL;
00800         SCARDHANDLE hCard, hLockId;
00801         void *ptr;
00802 
00803         /*
00804          * Disconnect each of these just in case
00805          */
00806         ptr = list_get_at(&(threadContext->cardsList), 0);
00807         if (NULL == ptr)
00808         {
00809             Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
00810             continue;
00811         }
00812         hCard = *(int32_t *)ptr;
00813 
00814         /*
00815          * Unlock the sharing
00816          */
00817         rv = RFReaderInfoById(hCard, &rContext);
00818         if (rv != SCARD_S_SUCCESS)
00819         {
00820             (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
00821             return rv;
00822         }
00823 
00824         hLockId = rContext->hLockId;
00825         rContext->hLockId = 0;
00826 
00827         if (hCard != hLockId)
00828         {
00829             /*
00830              * if the card is locked by someone else we do not reset it
00831              * and simulate a card removal
00832              */
00833             rv = SCARD_W_REMOVED_CARD;
00834         }
00835         else
00836         {
00837             /*
00838              * We will use SCardStatus to see if the card has been
00839              * reset there is no need to reset each time
00840              * Disconnect is called
00841              */
00842             rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
00843         }
00844 
00845         if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
00846             (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
00847         else
00848             (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
00849 
00850         /* Remove entry from the list */
00851         lrv = list_delete_at(&(threadContext->cardsList), 0);
00852         if (lrv < 0)
00853             Log2(PCSC_LOG_CRITICAL,
00854                 "list_delete_at failed with return value: %X", lrv);
00855     }
00856     (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
00857     list_destroy(&(threadContext->cardsList));
00858 
00859     /* We only mark the context as no longer in use.
00860      * The memory is freed in MSGCleanupCLient() */
00861     threadContext->hContext = 0;
00862 
00863     return SCARD_S_SUCCESS;
00864 }
00865 
00866 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
00867     SCONTEXT * threadContext)
00868 {
00869     if (threadContext->hContext == hContext)
00870     {
00871         /*
00872          * Find an empty spot to put the hCard value
00873          */
00874         int listLength, lrv;
00875 
00876         listLength = list_size(&(threadContext->cardsList));
00877         if (listLength >= contextMaxCardHandles)
00878         {
00879             Log4(PCSC_LOG_DEBUG, "Too many card handles for thread context @%X: %d (max is %d)"
00880                 "Restart pcscd with --max-card-handle-per-thread value",
00881                 threadContext, listLength, contextMaxCardHandles);
00882             return SCARD_E_NO_MEMORY;
00883         }
00884 
00885         (void)pthread_mutex_lock(&threadContext->cardsList_lock);
00886         lrv = list_append(&(threadContext->cardsList), &hCard);
00887         (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
00888         if (lrv < 0)
00889         {
00890             Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X",
00891                 lrv);
00892             return SCARD_E_NO_MEMORY;
00893         }
00894         return SCARD_S_SUCCESS;
00895     }
00896 
00897     return SCARD_E_INVALID_VALUE;
00898 }
00899 
00900 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
00901 {
00902     int lrv;
00903 
00904     (void)pthread_mutex_lock(&threadContext->cardsList_lock);
00905     lrv = list_delete(&(threadContext->cardsList), &hCard);
00906     (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
00907     if (lrv < 0)
00908     {
00909         Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %X", lrv);
00910         return SCARD_E_INVALID_VALUE;
00911     }
00912 
00913     return SCARD_S_SUCCESS;
00914 }
00915 
00916 
00917 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, SCONTEXT * threadContext)
00918 {
00919     int list_index = 0;
00920     (void)pthread_mutex_lock(&threadContext->cardsList_lock);
00921     list_index = list_locate(&(threadContext->cardsList), &hCard);
00922     (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
00923     if (list_index >= 0)
00924         return 0;
00925 
00926     /* Must be a rogue client, debug log and sleep a couple of seconds */
00927     Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
00928     (void)SYS_Sleep(2);
00929 
00930     return -1;
00931 }
00932 
00933 
00934 /* Should be called just prior to exiting the thread as it de-allocates
00935  * the thread memory strucutres
00936  */
00937 static LONG MSGCleanupClient(SCONTEXT * threadContext)
00938 {
00939     int lrv;
00940     int listSize;
00941 
00942     if (threadContext->hContext != 0)
00943     {
00944         (void)SCardReleaseContext(threadContext->hContext);
00945         (void)MSGRemoveContext(threadContext->hContext, threadContext);
00946     }
00947 
00948     Log3(PCSC_LOG_DEBUG,
00949         "Thread is stopping: dwClientID=%d, threadContext @%X",
00950         threadContext->dwClientID, threadContext);
00951 
00952     /* Clear the struct to ensure that we detect
00953      * access to de-allocated memory
00954      * Hopefully the compiler won't optimise it out */
00955     memset((void*) threadContext, 0, sizeof(SCONTEXT));
00956     Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%X", threadContext);
00957 
00958     (void)pthread_mutex_lock(&contextsList_lock);
00959     lrv = list_delete(&contextsList, threadContext);
00960     listSize = list_size(&contextsList);
00961     (void)pthread_mutex_unlock(&contextsList_lock);
00962     if (lrv < 0)
00963         Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
00964 
00965     free(threadContext);
00966 
00967     /* start a suicide alarm */
00968     if (AutoExit && (listSize < 1))
00969     {
00970         Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
00971             TIME_BEFORE_SUICIDE);
00972         alarm(TIME_BEFORE_SUICIDE);
00973     }
00974 
00975     return 0;
00976 }