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