winscard_clnt.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 1999-2004
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2003-2004
00007  *  Damien Sauveron <damien.sauveron@labri.fr>
00008  * Copyright (C) 2005
00009  *  Martin Paljak <martin@paljak.pri.ee>
00010  * Copyright (C) 2002-2009
00011  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00012  * Copyright (C) 2009
00013  *  Jean-Luc Giraud <jlgiraud@googlemail.com>
00014  *
00015  * $Id: winscard_clnt.c 4952 2010-05-18 13:42:25Z rousseau $
00016  */
00017 
00078 #include "config.h"
00079 #include <stdlib.h>
00080 #include <string.h>
00081 #include <sys/types.h>
00082 #include <fcntl.h>
00083 #include <unistd.h>
00084 #include <sys/un.h>
00085 #include <errno.h>
00086 #include <stddef.h>
00087 #include <sys/time.h>
00088 #include <pthread.h>
00089 #include <sys/wait.h>
00090 
00091 #include "misc.h"
00092 #include "pcscd.h"
00093 #include "winscard.h"
00094 #include "debuglog.h"
00095 #include "strlcpycat.h"
00096 
00097 #include "readerfactory.h"
00098 #include "eventhandler.h"
00099 #include "sys_generic.h"
00100 #include "winscard_msg.h"
00101 #include "utils.h"
00102 
00104 #define SCARD_PROTOCOL_ANY_OLD  0x1000
00105 
00106 #ifndef TRUE
00107 #define TRUE 1
00108 #define FALSE 0
00109 #endif
00110 
00111 static char sharing_shall_block = TRUE;
00112 
00113 #undef DO_PROFILE
00114 #ifdef DO_PROFILE
00115 
00116 #define PROFILE_FILE "/tmp/pcsc_profile"
00117 #include <stdio.h>
00118 #include <sys/time.h>
00119 
00120 struct timeval profile_time_start;
00121 FILE *profile_fd;
00122 char profile_tty;
00123 char fct_name[100];
00124 
00125 #define PROFILE_START profile_start(__FUNCTION__);
00126 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
00127 
00128 static void profile_start(const char *f)
00129 {
00130     static char initialized = FALSE;
00131 
00132     if (!initialized)
00133     {
00134         char filename[80];
00135 
00136         initialized = TRUE;
00137         sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
00138         profile_fd = fopen(filename, "a+");
00139         if (NULL == profile_fd)
00140         {
00141             fprintf(stderr, "\33[01;31mCan't open %s: %s\33[0m\n",
00142                 PROFILE_FILE, strerror(errno));
00143             exit(-1);
00144         }
00145         fprintf(profile_fd, "\nStart a new profile\n");
00146 
00147         if (isatty(fileno(stderr)))
00148             profile_tty = TRUE;
00149         else
00150             profile_tty = FALSE;
00151     }
00152 
00153     /* PROFILE_END was not called before? */
00154     if (profile_tty && fct_name[0])
00155         printf("\33[01;34m WARNING: %s starts before %s finishes\33[0m\n",
00156             f, fct_name);
00157 
00158     strlcpy(fct_name, f, sizeof(fct_name));
00159 
00160     gettimeofday(&profile_time_start, NULL);
00161 } /* profile_start */
00162 
00163 static void profile_end(const char *f, LONG rv)
00164 {
00165     struct timeval profile_time_end;
00166     long d;
00167 
00168     gettimeofday(&profile_time_end, NULL);
00169     d = time_sub(&profile_time_end, &profile_time_start);
00170 
00171     if (profile_tty)
00172     {
00173         if (fct_name[0])
00174         {
00175             if (strncmp(fct_name, f, sizeof(fct_name)))
00176                 printf("\33[01;34m WARNING: %s ends before %s\33[0m\n",
00177                         f, fct_name);
00178         }
00179         else
00180             printf("\33[01;34m WARNING: %s ends but we lost its start\33[0m\n",
00181                 f);
00182 
00183         /* allow to detect missing PROFILE_END calls */
00184         fct_name[0] = '\0';
00185 
00186         if (rv != SCARD_S_SUCCESS)
00187             fprintf(stderr,
00188                 "\33[01;31mRESULT %s \33[35m%ld \33[34m0x%08lX %s\33[0m\n",
00189                 f, d, rv, pcsc_stringify_error(rv));
00190         else
00191             fprintf(stderr, "\33[01;31mRESULT %s \33[35m%ld\33[0m\n", f, d);
00192     }
00193     fprintf(profile_fd, "%s %ld\n", f, d);
00194     fflush(profile_fd);
00195 } /* profile_end */
00196 
00197 #else
00198 #define PROFILE_START
00199 #define PROFILE_END(rv)
00200 #endif
00201 
00206 struct _psChannelMap
00207 {
00208     SCARDHANDLE hCard;
00209     LPSTR readerName;
00210 };
00211 
00212 typedef struct _psChannelMap CHANNEL_MAP;
00213 
00214 static int CHANNEL_MAP_seeker(const void *el, const void *key)
00215 {
00216     const CHANNEL_MAP * channelMap = el;
00217 
00218     if ((el == NULL) || (key == NULL))
00219     {
00220         Log3(PCSC_LOG_CRITICAL,
00221             "CHANNEL_MAP_seeker called with NULL pointer: el=%X, key=%X",
00222             el, key);
00223     }
00224 
00225     if (channelMap->hCard == *(SCARDHANDLE *)key)
00226         return 1;
00227 
00228     return 0;
00229 }
00230 
00236 struct _psContextMap
00237 {
00238     DWORD dwClientID;               
00239     SCARDCONTEXT hContext;          
00240     pthread_mutex_t * mMutex;       
00241     list_t channelMapList;
00242 };
00243 typedef struct _psContextMap SCONTEXTMAP;
00244 
00245 static list_t contextMapList;
00246 
00247 static int SCONTEXTMAP_seeker(const void *el, const void *key)
00248 {
00249     const SCONTEXTMAP * contextMap = el;
00250 
00251     if ((el == NULL) || (key == NULL))
00252     {
00253         Log3(PCSC_LOG_CRITICAL,
00254             "SCONTEXTMAP_seeker called with NULL pointer: el=%X, key=%X",
00255             el, key);
00256     }
00257 
00258     if (contextMap->hContext == *(SCARDCONTEXT *) key)
00259         return 1;
00260 
00261     return 0;
00262 }
00263 
00267 static short isExecuted = 0;
00268 
00269 
00273 static time_t daemon_ctime = 0;
00274 static pid_t daemon_pid = 0;
00279 static pid_t client_pid = 0;
00280 
00285 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
00286 
00290 static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
00291 
00293 PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) };
00295 PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) };
00297 PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };
00298 
00299 
00300 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
00301 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT);
00302 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT);
00303 static LONG SCardRemoveContext(SCARDCONTEXT);
00304 static LONG SCardCleanContext(SCONTEXTMAP *);
00305 
00306 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
00307 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE, /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
00308 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE, /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
00309 static LONG SCardRemoveHandle(SCARDHANDLE);
00310 
00311 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
00312     LPBYTE pbAttr, LPDWORD pcbAttrLen);
00313 
00314 #ifdef DO_CHECK_SAME_PROCESS
00315 static LONG SCardCheckSameProcess(void);
00316 #define CHECK_SAME_PROCESS \
00317     rv = SCardCheckSameProcess(); \
00318     if (rv != SCARD_S_SUCCESS) \
00319         return rv;
00320 #else
00321 #define CHECK_SAME_PROCESS
00322 #endif
00323 
00324 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
00325 
00326 /*
00327  * Thread safety functions
00328  */
00335 inline static LONG SCardLockThread(void)
00336 {
00337     return pthread_mutex_lock(&clientMutex);
00338 }
00339 
00345 inline static LONG SCardUnlockThread(void)
00346 {
00347     return pthread_mutex_unlock(&clientMutex);
00348 }
00349 
00350 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
00351     /*@out@*/ LPSCARDCONTEXT);
00352 
00386 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
00387     LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00388 {
00389     LONG rv;
00390     int daemon_launched = FALSE;
00391     int retries = 0;
00392 
00393     PROFILE_START
00394 
00395 again:
00396     /* Check if the server is running */
00397     rv = SCardCheckDaemonAvailability();
00398     if (SCARD_E_INVALID_HANDLE == rv)
00399         /* we reconnected to a daemon or we got called from a forked child */
00400         rv = SCardCheckDaemonAvailability();
00401 
00402     if (SCARD_E_NO_SERVICE == rv)
00403     {
00404 launch:
00405         if (daemon_launched)
00406         {
00407             retries++;
00408             if (retries < 50)   /* 50 x 100ms = 5 seconds */
00409             {
00410                 /* give some more time to the server to start */
00411                 SYS_USleep(100*1000);   /* 100 ms */
00412                 goto again;
00413             }
00414 
00415             /* the server failed to start (in time) */
00416             goto end;
00417         }
00418         else
00419         {
00420             int pid;
00421 
00422             pid = fork();
00423 
00424             if (pid < 0)
00425             {
00426                 Log2(PCSC_LOG_CRITICAL, "fork failed: %s", strerror(errno));
00427                 rv = SCARD_F_INTERNAL_ERROR;
00428                 goto end;
00429             }
00430 
00431             if (0 == pid)
00432             {
00433                 int ret;
00434                 char *param = getenv("PCSCLITE_PCSCD_ARGS");
00435 
00436                 /* son process */
00437                 ret = execl(PCSCD_BINARY, "pcscd", "--auto-exit", param,
00438                     (char *)NULL);
00439                 Log2(PCSC_LOG_CRITICAL, "exec " PCSCD_BINARY " failed: %s",
00440                     strerror(errno));
00441                 exit(1);
00442             }
00443 
00444             /* father process */
00445             daemon_launched = TRUE;
00446 
00447             if (waitpid(pid, NULL, 0) < 0)
00448                 Log2(PCSC_LOG_CRITICAL, "waitpid failed: %s", strerror(errno));
00449 
00450             goto again;
00451         }
00452     }
00453 
00454     if (rv != SCARD_S_SUCCESS)
00455         goto end;
00456 
00457     (void)SCardLockThread();
00458     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00459         pvReserved2, phContext);
00460     (void)SCardUnlockThread();
00461 
00462     /* SCardEstablishContextTH may fail if the previous pcscd crashed
00463      * without cleaning /var/run/pcscd/pcscd.comm */
00464     if (SCARD_E_NO_SERVICE == rv)
00465     {
00466         retries++;
00467         if (retries <= 1)
00468             goto launch;
00469     }
00470 
00471 end:
00472     PROFILE_END(rv)
00473 
00474     return rv;
00475 }
00476 
00503 static LONG SCardEstablishContextTH(DWORD dwScope,
00504     /*@unused@*/ LPCVOID pvReserved1,
00505     /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00506 {
00507     LONG rv;
00508     struct establish_struct scEstablishStruct;
00509     uint32_t dwClientID = 0;
00510 
00511     (void)pvReserved1;
00512     (void)pvReserved2;
00513     if (phContext == NULL)
00514         return SCARD_E_INVALID_PARAMETER;
00515     else
00516         *phContext = 0;
00517 
00518     /*
00519      * Do this only once:
00520      * - Initialize context list.
00521      */
00522     if (isExecuted == 0)
00523     {
00524         int lrv;
00525 
00526         /* NOTE: The list will never be freed (No API call exists to
00527          * "close all contexts".
00528          * Applications which load and unload the library will leak
00529          * the list's internal structures. */
00530         lrv = list_init(&contextMapList);
00531         if (lrv < 0)
00532         {
00533             Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
00534             return SCARD_E_NO_MEMORY;
00535         }
00536 
00537         lrv = list_attributes_seeker(&contextMapList,
00538                 SCONTEXTMAP_seeker);
00539         if (lrv <0)
00540         {
00541             Log2(PCSC_LOG_CRITICAL,
00542                 "list_attributes_seeker failed with return value: %X", lrv);
00543             list_destroy(&contextMapList);
00544             return SCARD_E_NO_MEMORY;
00545         }
00546 
00547         if (getenv("PCSCLITE_NO_BLOCKING"))
00548         {
00549             Log1(PCSC_LOG_INFO, "Disable shared blocking");
00550             sharing_shall_block = FALSE;
00551         }
00552         
00553         isExecuted = 1;
00554     }
00555 
00556 
00557     /* Establishes a connection to the server */
00558     if (ClientSetupSession(&dwClientID) != 0)
00559     {
00560         return SCARD_E_NO_SERVICE;
00561     }
00562 
00563     {   /* exchange client/server protocol versions */
00564         struct version_struct veStr;
00565 
00566         veStr.major = PROTOCOL_VERSION_MAJOR;
00567         veStr.minor = PROTOCOL_VERSION_MINOR;
00568         veStr.rv = SCARD_S_SUCCESS;
00569 
00570         if (-1 == MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
00571             &veStr))
00572             return SCARD_E_NO_SERVICE;
00573 
00574         /* Read a message from the server */
00575         if (MessageReceive(&veStr, sizeof(veStr), dwClientID) < 0)
00576         {
00577             Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION");
00578             return SCARD_F_COMM_ERROR;
00579         }
00580 
00581         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00582             veStr.major, veStr.minor);
00583 
00584         if (veStr.rv != SCARD_S_SUCCESS)
00585             return veStr.rv;
00586     }
00587 
00588 again:
00589     /*
00590      * Try to establish an Application Context with the server
00591      */
00592     scEstablishStruct.dwScope = dwScope;
00593     scEstablishStruct.hContext = 0;
00594     scEstablishStruct.rv = SCARD_S_SUCCESS;
00595 
00596     rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
00597         sizeof(scEstablishStruct), (void *) &scEstablishStruct);
00598 
00599     if (rv == -1)
00600         return SCARD_E_NO_SERVICE;
00601 
00602     /*
00603      * Read the response from the server
00604      */
00605     rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct), dwClientID);
00606 
00607     if (rv < 0)
00608         return SCARD_F_COMM_ERROR;
00609 
00610     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00611         return scEstablishStruct.rv;
00612 
00613     /* check we do not reuse an existing hContext */
00614     if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
00615         /* we do not need to release the allocated context since
00616          * SCardReleaseContext() does nothing on the server side */
00617         goto again;
00618 
00619     *phContext = scEstablishStruct.hContext;
00620 
00621     /*
00622      * Allocate the new hContext - if allocator full return an error
00623      */
00624     rv = SCardAddContext(*phContext, dwClientID);
00625 
00626     return rv;
00627 }
00628 
00650 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00651 {
00652     LONG rv;
00653     struct release_struct scReleaseStruct;
00654     SCONTEXTMAP * currentContextMap;
00655 
00656     PROFILE_START
00657 
00658     CHECK_SAME_PROCESS
00659 
00660     /*
00661      * Make sure this context has been opened
00662      * and get currentContextMap
00663      */
00664     currentContextMap = SCardGetContext(hContext);
00665     if (NULL == currentContextMap)
00666     {
00667         PROFILE_END(SCARD_E_INVALID_HANDLE)
00668         return SCARD_E_INVALID_HANDLE;
00669     }
00670 
00671     (void)pthread_mutex_lock(currentContextMap->mMutex);
00672 
00673     /* check the context is still opened */
00674     currentContextMap = SCardGetContext(hContext);
00675     if (NULL == currentContextMap)
00676         /* the context is now invalid
00677          * -> another thread may have called SCardReleaseContext
00678          * -> so the mMutex has been unlocked */
00679         return SCARD_E_INVALID_HANDLE;
00680 
00681     scReleaseStruct.hContext = hContext;
00682     scReleaseStruct.rv = SCARD_S_SUCCESS;
00683 
00684     rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
00685         currentContextMap->dwClientID,
00686         sizeof(scReleaseStruct),
00687         (void *) &scReleaseStruct);
00688 
00689     if (rv == -1)
00690     {
00691         rv = SCARD_E_NO_SERVICE;
00692         goto end;
00693     }
00694 
00695     /*
00696      * Read a message from the server
00697      */
00698     rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
00699         currentContextMap->dwClientID);
00700 
00701     if (rv < 0)
00702     {
00703         rv = SCARD_F_COMM_ERROR;
00704         goto end;
00705     }
00706 
00707     rv = scReleaseStruct.rv;
00708 end:
00709     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00710 
00711     /*
00712      * Remove the local context from the stack
00713      */
00714     (void)SCardLockThread();
00715     (void)SCardRemoveContext(hContext);
00716     (void)SCardUnlockThread();
00717 
00718     PROFILE_END(rv)
00719 
00720     return rv;
00721 }
00722 
00738 LONG SCardSetTimeout(/*@unused@*/ SCARDCONTEXT hContext,
00739     /*@unused@*/ DWORD dwTimeout)
00740 {
00741     /*
00742      * Deprecated
00743      */
00744     (void)hContext;
00745     (void)dwTimeout;
00746     return SCARD_S_SUCCESS;
00747 }
00748 
00806 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00807     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00808     LPDWORD pdwActiveProtocol)
00809 {
00810     LONG rv;
00811     struct connect_struct scConnectStruct;
00812     SCONTEXTMAP * currentContextMap;
00813 
00814     PROFILE_START
00815 
00816     /*
00817      * Check for NULL parameters
00818      */
00819     if (phCard == NULL || pdwActiveProtocol == NULL)
00820         return SCARD_E_INVALID_PARAMETER;
00821     else
00822         *phCard = 0;
00823 
00824     if (szReader == NULL)
00825         return SCARD_E_UNKNOWN_READER;
00826 
00827     /*
00828      * Check for uninitialized strings
00829      */
00830     if (strlen(szReader) > MAX_READERNAME)
00831         return SCARD_E_INVALID_VALUE;
00832 
00833     CHECK_SAME_PROCESS
00834 
00835     /*
00836      * Make sure this context has been opened
00837      */
00838     currentContextMap = SCardGetContext(hContext);
00839     if (NULL == currentContextMap)
00840         return SCARD_E_INVALID_HANDLE;
00841 
00842     (void)pthread_mutex_lock(currentContextMap->mMutex);
00843 
00844     /* check the context is still opened */
00845     currentContextMap = SCardGetContext(hContext);
00846     if (NULL == currentContextMap)
00847         /* the context is now invalid
00848          * -> another thread may have called SCardReleaseContext
00849          * -> so the mMutex has been unlocked */
00850         return SCARD_E_INVALID_HANDLE;
00851 
00852     strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
00853 
00854     scConnectStruct.hContext = hContext;
00855     scConnectStruct.dwShareMode = dwShareMode;
00856     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00857     scConnectStruct.hCard = 0;
00858     scConnectStruct.dwActiveProtocol = 0;
00859     scConnectStruct.rv = SCARD_S_SUCCESS;
00860 
00861     rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
00862         sizeof(scConnectStruct),
00863         (void *) &scConnectStruct);
00864 
00865     if (rv == -1)
00866     {
00867         rv = SCARD_E_NO_SERVICE;
00868         goto end;
00869     }
00870 
00871     /*
00872      * Read a message from the server
00873      */
00874     rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
00875         currentContextMap->dwClientID);
00876 
00877     if (rv < 0)
00878     {
00879         rv = SCARD_F_COMM_ERROR;
00880         goto end;
00881     }
00882 
00883     *phCard = scConnectStruct.hCard;
00884     *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
00885 
00886     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00887     {
00888         /*
00889          * Keep track of the handle locally
00890          */
00891         rv = SCardAddHandle(*phCard, currentContextMap, szReader);
00892     }
00893     else
00894         rv = scConnectStruct.rv;
00895 
00896 end:
00897     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00898 
00899     PROFILE_END(rv)
00900 
00901     return rv;
00902 }
00903 
00977 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
00978     DWORD dwPreferredProtocols, DWORD dwInitialization,
00979     LPDWORD pdwActiveProtocol)
00980 {
00981     LONG rv;
00982     struct reconnect_struct scReconnectStruct;
00983     SCONTEXTMAP * currentContextMap;
00984     CHANNEL_MAP * pChannelMap;
00985 
00986     PROFILE_START
00987 
00988     if (pdwActiveProtocol == NULL)
00989         return SCARD_E_INVALID_PARAMETER;
00990 
00991     CHECK_SAME_PROCESS
00992 
00993     /*
00994      * Make sure this handle has been opened
00995      */
00996     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
00997         &pChannelMap);
00998     if (rv == -1)
00999         return SCARD_E_INVALID_HANDLE;
01000 
01001     (void)pthread_mutex_lock(currentContextMap->mMutex);
01002 
01003     /* check the handle is still valid */
01004     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01005         &pChannelMap);
01006     if (rv == -1)
01007         /* the handle is now invalid
01008          * -> another thread may have called SCardReleaseContext
01009          * -> so the mMutex has been unlocked */
01010         return SCARD_E_INVALID_HANDLE;
01011 
01012     /* Retry loop for blocking behaviour */
01013 retry:
01014     
01015     scReconnectStruct.hCard = hCard;
01016     scReconnectStruct.dwShareMode = dwShareMode;
01017     scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
01018     scReconnectStruct.dwInitialization = dwInitialization;
01019     scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
01020     scReconnectStruct.rv = SCARD_S_SUCCESS;
01021 
01022     rv = MessageSendWithHeader(SCARD_RECONNECT,
01023         currentContextMap->dwClientID,
01024         sizeof(scReconnectStruct),
01025         (void *) &scReconnectStruct);
01026 
01027     if (rv == -1)
01028     {
01029         rv = SCARD_E_NO_SERVICE;
01030         goto end;
01031     }
01032 
01033     /*
01034      * Read a message from the server
01035      */
01036     rv = MessageReceive(&scReconnectStruct,
01037         sizeof(scReconnectStruct),
01038         currentContextMap->dwClientID);
01039 
01040     if (rv < 0)
01041     {
01042         rv = SCARD_F_COMM_ERROR;
01043         goto end;
01044     }
01045 
01046     rv = scReconnectStruct.rv;
01047 
01048     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01049     {
01050         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01051         goto retry;
01052     }
01053     
01054     *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
01055 
01056 end:
01057     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01058 
01059     PROFILE_END(rv)
01060 
01061     return rv;
01062 }
01063 
01095 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01096 {
01097     LONG rv;
01098     struct disconnect_struct scDisconnectStruct;
01099     SCONTEXTMAP * currentContextMap;
01100     CHANNEL_MAP * pChannelMap;
01101 
01102     PROFILE_START
01103 
01104     CHECK_SAME_PROCESS
01105 
01106     /*
01107      * Make sure this handle has been opened
01108      */
01109     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01110         &pChannelMap);
01111     if (rv == -1)
01112         return SCARD_E_INVALID_HANDLE;
01113 
01114     (void)pthread_mutex_lock(currentContextMap->mMutex);
01115 
01116     /* check the handle is still valid */
01117     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01118         &pChannelMap);
01119     if (rv == -1)
01120         /* the handle is now invalid
01121          * -> another thread may have called SCardReleaseContext
01122          * -> so the mMutex has been unlocked */
01123         return SCARD_E_INVALID_HANDLE;
01124 
01125     scDisconnectStruct.hCard = hCard;
01126     scDisconnectStruct.dwDisposition = dwDisposition;
01127     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01128 
01129     rv = MessageSendWithHeader(SCARD_DISCONNECT,
01130         currentContextMap->dwClientID,
01131         sizeof(scDisconnectStruct),
01132         (void *) &scDisconnectStruct);
01133 
01134     if (rv == -1)
01135     {
01136         rv = SCARD_E_NO_SERVICE;
01137         goto end;
01138     }
01139 
01140     /*
01141      * Read a message from the server
01142      */
01143     rv = MessageReceive(&scDisconnectStruct,
01144         sizeof(scDisconnectStruct),
01145         currentContextMap->dwClientID);
01146 
01147     if (rv < 0)
01148     {
01149         rv = SCARD_F_COMM_ERROR;
01150         goto end;
01151     }
01152 
01153     (void)SCardRemoveHandle(hCard);
01154     rv = scDisconnectStruct.rv;
01155 
01156 end:
01157     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01158 
01159     PROFILE_END(rv)
01160 
01161     return rv;
01162 }
01163 
01199 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01200 {
01201 
01202     LONG rv;
01203     struct begin_struct scBeginStruct;
01204     SCONTEXTMAP * currentContextMap;
01205     CHANNEL_MAP * pChannelMap;
01206 
01207     PROFILE_START
01208 
01209     CHECK_SAME_PROCESS
01210 
01211     /*
01212      * Make sure this handle has been opened
01213      */
01214     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01215         &pChannelMap);
01216     if (rv == -1)
01217         return SCARD_E_INVALID_HANDLE;
01218 
01219     (void)pthread_mutex_lock(currentContextMap->mMutex);
01220 
01221     /* check the handle is still valid */
01222     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01223         &pChannelMap);
01224     if (rv == -1)
01225         /* the handle is now invalid
01226          * -> another thread may have called SCardReleaseContext
01227          * -> so the mMutex has been unlocked */
01228         return SCARD_E_INVALID_HANDLE;
01229 
01230     scBeginStruct.hCard = hCard;
01231     scBeginStruct.rv = SCARD_S_SUCCESS;
01232 
01233     /*
01234      * Query the server every so often until the sharing violation ends
01235      * and then hold the lock for yourself.
01236      */
01237 
01238     do
01239     {
01240         rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
01241             currentContextMap->dwClientID,
01242             sizeof(scBeginStruct),
01243             (void *) &scBeginStruct);
01244 
01245         if (rv == -1)
01246         {
01247             rv = SCARD_E_NO_SERVICE;
01248             goto end;
01249         }
01250 
01251         /*
01252          * Read a message from the server
01253          */
01254         rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
01255             currentContextMap->dwClientID);
01256 
01257         if (rv < 0)
01258         {
01259             rv = SCARD_F_COMM_ERROR;
01260             goto end;
01261         }
01262 
01263         rv = scBeginStruct.rv;
01264     }
01265     while (SCARD_E_SHARING_VIOLATION == rv);
01266 
01267 end:
01268     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01269 
01270     PROFILE_END(rv);
01271 
01272     return rv;
01273 }
01274 
01315 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01316 {
01317     LONG rv;
01318     struct end_struct scEndStruct;
01319     int randnum;
01320     SCONTEXTMAP * currentContextMap;
01321     CHANNEL_MAP * pChannelMap;
01322 
01323     PROFILE_START
01324 
01325     /*
01326      * Zero out everything
01327      */
01328     randnum = 0;
01329 
01330     CHECK_SAME_PROCESS
01331 
01332     /*
01333      * Make sure this handle has been opened
01334      */
01335     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01336         &pChannelMap);
01337     if (rv == -1)
01338         return SCARD_E_INVALID_HANDLE;
01339 
01340     (void)pthread_mutex_lock(currentContextMap->mMutex);
01341 
01342     /* check the handle is still valid */
01343     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01344         &pChannelMap);
01345     if (rv == -1)
01346         /* the handle is now invalid
01347          * -> another thread may have called SCardReleaseContext
01348          * -> so the mMutex has been unlocked */
01349         return SCARD_E_INVALID_HANDLE;
01350 
01351     scEndStruct.hCard = hCard;
01352     scEndStruct.dwDisposition = dwDisposition;
01353     scEndStruct.rv = SCARD_S_SUCCESS;
01354 
01355     rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
01356         currentContextMap->dwClientID,
01357         sizeof(scEndStruct),
01358         (void *) &scEndStruct);
01359 
01360     if (rv == -1)
01361     {
01362         rv = SCARD_E_NO_SERVICE;
01363         goto end;
01364     }
01365 
01366     /*
01367      * Read a message from the server
01368      */
01369     rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
01370         currentContextMap->dwClientID);
01371 
01372     if (rv < 0)
01373     {
01374         rv = SCARD_F_COMM_ERROR;
01375         goto end;
01376     }
01377 
01378     /*
01379      * This helps prevent starvation
01380      */
01381     randnum = SYS_RandomInt(1000, 10000);
01382     (void)SYS_USleep(randnum);
01383     rv = scEndStruct.rv;
01384 
01385 end:
01386     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01387 
01388     PROFILE_END(rv)
01389 
01390     return rv;
01391 }
01392 
01399 LONG SCardCancelTransaction(SCARDHANDLE hCard)
01400 {
01401     LONG rv;
01402     struct cancel_transaction_struct scCancelStruct;
01403     SCONTEXTMAP * currentContextMap;
01404     CHANNEL_MAP * pChannelMap;
01405 
01406     PROFILE_START
01407 
01408     CHECK_SAME_PROCESS
01409 
01410     /*
01411      * Make sure this handle has been opened
01412      */
01413     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01414         &pChannelMap);
01415     if (rv == -1)
01416         return SCARD_E_INVALID_HANDLE;
01417 
01418     (void)pthread_mutex_lock(currentContextMap->mMutex);
01419 
01420     /* check the handle is still valid */
01421     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01422         &pChannelMap);
01423     if (rv == -1)
01424         /* the handle is now invalid
01425          * -> another thread may have called SCardReleaseContext
01426          * -> so the mMutex has been unlocked */
01427         return SCARD_E_INVALID_HANDLE;
01428 
01429     scCancelStruct.hCard = hCard;
01430 
01431     rv = MessageSendWithHeader(SCARD_CANCEL_TRANSACTION,
01432         currentContextMap->dwClientID,
01433         sizeof(scCancelStruct), (void *) &scCancelStruct);
01434 
01435     if (rv == -1)
01436     {
01437         rv = SCARD_E_NO_SERVICE;
01438         goto end;
01439     }
01440 
01441     /*
01442      * Read a message from the server
01443      */
01444     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
01445         currentContextMap->dwClientID);
01446 
01447     if (rv < 0)
01448     {
01449         rv = SCARD_F_COMM_ERROR;
01450         goto end;
01451     }
01452     rv = scCancelStruct.rv;
01453 
01454 end:
01455     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01456 
01457     PROFILE_END(rv)
01458 
01459     return rv;
01460 }
01461 
01551 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
01552     LPDWORD pcchReaderLen, LPDWORD pdwState,
01553     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01554 {
01555     DWORD dwReaderLen, dwAtrLen;
01556     LONG rv;
01557     int i;
01558     struct status_struct scStatusStruct;
01559     SCONTEXTMAP * currentContextMap;
01560     CHANNEL_MAP * pChannelMap;
01561     char *r;
01562     char *bufReader = NULL;
01563     LPBYTE bufAtr = NULL;
01564     DWORD dummy;
01565 
01566     PROFILE_START
01567 
01568     /* default output values */
01569     if (pdwState)
01570         *pdwState = 0;
01571 
01572     if (pdwProtocol)
01573         *pdwProtocol = 0;
01574 
01575     /* Check for NULL parameters */
01576     if (pcchReaderLen == NULL)
01577         pcchReaderLen = &dummy;
01578 
01579     if (pcbAtrLen == NULL)
01580         pcbAtrLen = &dummy;
01581 
01582     /* length passed from caller */
01583     dwReaderLen = *pcchReaderLen;
01584     dwAtrLen = *pcbAtrLen;
01585 
01586     *pcchReaderLen = 0;
01587     *pcbAtrLen = 0;
01588 
01589     CHECK_SAME_PROCESS
01590 
01591     /*
01592      * Make sure this handle has been opened
01593      */
01594     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01595         &pChannelMap);
01596     if (rv == -1)
01597         return SCARD_E_INVALID_HANDLE;
01598 
01599     (void)pthread_mutex_lock(currentContextMap->mMutex);
01600 
01601     /* check the handle is still valid */
01602     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01603         &pChannelMap);
01604     if (rv == -1)
01605         /* the handle is now invalid
01606          * -> another thread may have called SCardReleaseContext
01607          * -> so the mMutex has been unlocked */
01608         return SCARD_E_INVALID_HANDLE;
01609 
01610     /* synchronize reader states with daemon */
01611     rv = getReaderStates(currentContextMap);
01612     if (rv != SCARD_S_SUCCESS)
01613         goto end;
01614 
01615     r = pChannelMap->readerName;
01616     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01617     {
01618         /* by default r == NULL */
01619         if (r && strcmp(r, readerStates[i].readerName) == 0)
01620             break;
01621     }
01622 
01623     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01624     {
01625         rv = SCARD_E_READER_UNAVAILABLE;
01626         goto end;
01627     }
01628 
01629     /* Retry loop for blocking behaviour */
01630 retry:
01631 
01632     /* initialise the structure */
01633     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01634     scStatusStruct.hCard = hCard;
01635 
01636     /* those sizes need to be initialised */
01637     scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
01638     scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
01639 
01640     rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
01641         sizeof(scStatusStruct),
01642         (void *) &scStatusStruct);
01643 
01644     if (rv == -1)
01645     {
01646         rv = SCARD_E_NO_SERVICE;
01647         goto end;
01648     }
01649 
01650     /*
01651      * Read a message from the server
01652      */
01653     rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
01654         currentContextMap->dwClientID);
01655 
01656     if (rv < 0)
01657     {
01658         rv = SCARD_F_COMM_ERROR;
01659         goto end;
01660     }
01661 
01662     rv = scStatusStruct.rv;
01663 
01664     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01665     {
01666         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01667         goto retry;
01668     }
01669     
01670     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01671     {
01672         /*
01673          * An event must have occurred
01674          */
01675         goto end;
01676     }
01677 
01678     /*
01679      * Now continue with the client side SCardStatus
01680      */
01681 
01682     *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
01683     *pcbAtrLen = readerStates[i].cardAtrLength;
01684 
01685     if (pdwState)
01686         *pdwState = readerStates[i].readerState;
01687 
01688     if (pdwProtocol)
01689         *pdwProtocol = readerStates[i].cardProtocol;
01690 
01691     if (SCARD_AUTOALLOCATE == dwReaderLen)
01692     {
01693         dwReaderLen = *pcchReaderLen;
01694         bufReader = malloc(dwReaderLen);
01695         if (NULL == bufReader)
01696         {
01697             rv = SCARD_E_NO_MEMORY;
01698             goto end;
01699         }
01700         if (NULL == mszReaderName)
01701         {
01702             rv = SCARD_E_INVALID_PARAMETER;
01703             goto end;
01704         }
01705         *(char **)mszReaderName = bufReader;
01706     }
01707     else
01708         bufReader = mszReaderName;
01709 
01710     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01711     if (bufReader)
01712     {
01713         if (*pcchReaderLen > dwReaderLen)
01714             rv = SCARD_E_INSUFFICIENT_BUFFER;
01715 
01716         strncpy(bufReader,
01717             pChannelMap->readerName,
01718             dwReaderLen);
01719     }
01720 
01721     if (SCARD_AUTOALLOCATE == dwAtrLen)
01722     {
01723         dwAtrLen = *pcbAtrLen;
01724         bufAtr = malloc(dwAtrLen);
01725         if (NULL == bufAtr)
01726         {
01727             rv = SCARD_E_NO_MEMORY;
01728             goto end;
01729         }
01730         if (NULL == pbAtr)
01731         {
01732             rv = SCARD_E_INVALID_PARAMETER;
01733             goto end;
01734         }
01735         *(LPBYTE *)pbAtr = bufAtr;
01736     }
01737     else
01738         bufAtr = pbAtr;
01739 
01740     if (bufAtr)
01741     {
01742         if (*pcbAtrLen > dwAtrLen)
01743             rv = SCARD_E_INSUFFICIENT_BUFFER;
01744 
01745         memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
01746     }
01747 
01748 end:
01749     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01750 
01751     PROFILE_END(rv)
01752 
01753     return rv;
01754 }
01755 
01850 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01851     LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
01852 {
01853     PSCARD_READERSTATE_A currReader;
01854     READER_STATE *rContext;
01855     long dwTime;
01856     DWORD dwState;
01857     DWORD dwBreakFlag = 0;
01858     unsigned int j;
01859     SCONTEXTMAP * currentContextMap;
01860     int currentReaderCount = 0;
01861     LONG rv = SCARD_S_SUCCESS;
01862 
01863     PROFILE_START
01864 
01865     if ((rgReaderStates == NULL && cReaders > 0)
01866         || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
01867         return SCARD_E_INVALID_PARAMETER;
01868 
01869     /* Check the integrity of the reader states structures */
01870     for (j = 0; j < cReaders; j++)
01871     {
01872         if (rgReaderStates[j].szReader == NULL)
01873             return SCARD_E_INVALID_VALUE;
01874     }
01875 
01876     /* return if all readers are SCARD_STATE_IGNORE */
01877     if (cReaders > 0)
01878     {
01879         int nbNonIgnoredReaders = cReaders;
01880 
01881         for (j=0; j<cReaders; j++)
01882             if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
01883                 nbNonIgnoredReaders--;
01884 
01885         if (0 == nbNonIgnoredReaders)
01886             return SCARD_S_SUCCESS;
01887     }
01888     else
01889         /* reader list is empty */
01890         return SCARD_S_SUCCESS;
01891 
01892     CHECK_SAME_PROCESS
01893 
01894     /*
01895      * Make sure this context has been opened
01896      */
01897     currentContextMap = SCardGetContext(hContext);
01898     if (NULL == currentContextMap)
01899         return SCARD_E_INVALID_HANDLE;
01900 
01901     (void)pthread_mutex_lock(currentContextMap->mMutex);
01902 
01903     /* check the context is still opened */
01904     currentContextMap = SCardGetContext(hContext);
01905     if (NULL == currentContextMap)
01906         /* the context is now invalid
01907          * -> another thread may have called SCardReleaseContext
01908          * -> so the mMutex has been unlocked */
01909         return SCARD_E_INVALID_HANDLE;
01910 
01911     /* synchronize reader states with daemon */
01912     rv = getReaderStates(currentContextMap);
01913     if (rv != SCARD_S_SUCCESS)
01914         goto end;
01915 
01916     /* Clear the event state for all readers */
01917     for (j = 0; j < cReaders; j++)
01918         rgReaderStates[j].dwEventState = 0;
01919 
01920     /* Now is where we start our event checking loop */
01921     Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
01922 
01923     /* Get the initial reader count on the system */
01924     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
01925         if (readerStates[j].readerID != 0)
01926             currentReaderCount++;
01927 
01928     if (INFINITE == dwTimeout)
01929         dwTime = 60*1000;   /* "infinite" timeout */
01930     else
01931         dwTime = dwTimeout;
01932 
01933     j = 0;
01934     do
01935     {
01936         currReader = &rgReaderStates[j];
01937 
01938         /* Ignore for IGNORED readers */
01939         if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
01940         {
01941             LPSTR lpcReaderName;
01942             int i;
01943 
01944       /************ Looks for correct readernames *********************/
01945 
01946             lpcReaderName = (char *) currReader->szReader;
01947 
01948             for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01949             {
01950                 if (strcmp(lpcReaderName, readerStates[i].readerName) == 0)
01951                     break;
01952             }
01953 
01954             /* The requested reader name is not recognized */
01955             if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01956             {
01957                 /* PnP special reader? */
01958                 if (strcasecmp(lpcReaderName, "\\\\?PnP?\\Notification") == 0)
01959                 {
01960                     int k, newReaderCount = 0;
01961 
01962                     for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
01963                         if (readerStates[k].readerID != 0)
01964                             newReaderCount++;
01965 
01966                     if (newReaderCount != currentReaderCount)
01967                     {
01968                         Log1(PCSC_LOG_INFO, "Reader list changed");
01969                         currentReaderCount = newReaderCount;
01970 
01971                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01972                         dwBreakFlag = 1;
01973                     }
01974                 }
01975                 else
01976                 {
01977                     currReader->dwEventState = SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE;
01978                     if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
01979                     {
01980                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01981                         /*
01982                          * Spec says use SCARD_STATE_IGNORE but a removed USB
01983                          * reader with eventState fed into currentState will
01984                          * be ignored forever
01985                          */
01986                         dwBreakFlag = 1;
01987                     }
01988                 }
01989             }
01990             else
01991             {
01992                 /* The reader has come back after being away */
01993                 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
01994                 {
01995                     currReader->dwEventState |= SCARD_STATE_CHANGED;
01996                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01997                     Log0(PCSC_LOG_DEBUG);
01998                     dwBreakFlag = 1;
01999                 }
02000 
02001     /*****************************************************************/
02002 
02003                 /* Set the reader status structure */
02004                 rContext = &readerStates[i];
02005 
02006                 /* Now we check all the Reader States */
02007                 dwState = rContext->readerState;
02008 
02009                 /* only if current state has an non null event counter */
02010                 if (currReader->dwCurrentState & 0xFFFF0000)
02011                 {
02012                     int currentCounter, stateCounter;
02013 
02014                     stateCounter = (dwState >> 16) & 0xFFFF;
02015                     currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
02016 
02017                     /* has the event counter changed since the last call? */
02018                     if (stateCounter != currentCounter)
02019                     {
02020                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02021                         Log0(PCSC_LOG_DEBUG);
02022                         dwBreakFlag = 1;
02023                     }
02024 
02025                     /* add an event counter in the upper word of dwEventState */
02026                     currReader->dwEventState =
02027                         ((currReader->dwEventState & 0xffff )
02028                         | (stateCounter << 16));
02029                 }
02030 
02031     /*********** Check if the reader is in the correct state ********/
02032                 if (dwState & SCARD_UNKNOWN)
02033                 {
02034                     /* reader is in bad state */
02035                     currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
02036                     if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
02037                     {
02038                         /* App thinks reader is in good state and it is not */
02039                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02040                         Log0(PCSC_LOG_DEBUG);
02041                         dwBreakFlag = 1;
02042                     }
02043                 }
02044                 else
02045                 {
02046                     /* App thinks reader in bad state but it is not */
02047                     if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
02048                     {
02049                         currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02050                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02051                         Log0(PCSC_LOG_DEBUG);
02052                         dwBreakFlag = 1;
02053                     }
02054                 }
02055 
02056     /********** Check for card presence in the reader **************/
02057 
02058                 if (dwState & SCARD_PRESENT)
02059                 {
02060                     /* card present but not yet powered up */
02061                     if (0 == rContext->cardAtrLength)
02062                         /* Allow the status thread to convey information */
02063                         (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
02064 
02065                     currReader->cbAtr = rContext->cardAtrLength;
02066                     memcpy(currReader->rgbAtr, rContext->cardAtr,
02067                         currReader->cbAtr);
02068                 }
02069                 else
02070                     currReader->cbAtr = 0;
02071 
02072                 /* Card is now absent */
02073                 if (dwState & SCARD_ABSENT)
02074                 {
02075                     currReader->dwEventState |= SCARD_STATE_EMPTY;
02076                     currReader->dwEventState &= ~SCARD_STATE_PRESENT;
02077                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02078                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02079                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02080                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02081                     currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
02082                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02083                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02084 
02085                     /* After present the rest are assumed */
02086                     if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
02087                     {
02088                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02089                         Log0(PCSC_LOG_DEBUG);
02090                         dwBreakFlag = 1;
02091                     }
02092                 }
02093                 /* Card is now present */
02094                 else if (dwState & SCARD_PRESENT)
02095                 {
02096                     currReader->dwEventState |= SCARD_STATE_PRESENT;
02097                     currReader->dwEventState &= ~SCARD_STATE_EMPTY;
02098                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02099                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02100                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02101                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02102                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02103 
02104                     if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
02105                     {
02106                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02107                         Log0(PCSC_LOG_DEBUG);
02108                         dwBreakFlag = 1;
02109                     }
02110 
02111                     if (dwState & SCARD_SWALLOWED)
02112                     {
02113                         currReader->dwEventState |= SCARD_STATE_MUTE;
02114                         if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
02115                         {
02116                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02117                             Log0(PCSC_LOG_DEBUG);
02118                             dwBreakFlag = 1;
02119                         }
02120                     }
02121                     else
02122                     {
02123                         /* App thinks card is mute but it is not */
02124                         if (currReader->dwCurrentState & SCARD_STATE_MUTE)
02125                         {
02126                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02127                             Log0(PCSC_LOG_DEBUG);
02128                             dwBreakFlag = 1;
02129                         }
02130                     }
02131                 }
02132 
02133                 /* Now figure out sharing modes */
02134                 if (rContext->readerSharing == SCARD_EXCLUSIVE_CONTEXT)
02135                 {
02136                     currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
02137                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02138                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02139                     {
02140                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02141                         Log0(PCSC_LOG_DEBUG);
02142                         dwBreakFlag = 1;
02143                     }
02144                 }
02145                 else if (rContext->readerSharing >= SCARD_LAST_CONTEXT)
02146                 {
02147                     /* A card must be inserted for it to be INUSE */
02148                     if (dwState & SCARD_PRESENT)
02149                     {
02150                         currReader->dwEventState |= SCARD_STATE_INUSE;
02151                         currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02152                         if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
02153                         {
02154                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02155                             Log0(PCSC_LOG_DEBUG);
02156                             dwBreakFlag = 1;
02157                         }
02158                     }
02159                 }
02160                 else if (rContext->readerSharing == SCARD_NO_CONTEXT)
02161                 {
02162                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02163                     currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02164 
02165                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02166                     {
02167                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02168                         Log0(PCSC_LOG_DEBUG);
02169                         dwBreakFlag = 1;
02170                     }
02171                     else if (currReader-> dwCurrentState
02172                         & SCARD_STATE_EXCLUSIVE)
02173                     {
02174                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02175                         Log0(PCSC_LOG_DEBUG);
02176                         dwBreakFlag = 1;
02177                     }
02178                 }
02179 
02180                 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
02181                 {
02182                     /*
02183                      * Break out of the while .. loop and return status
02184                      * once all the status's for all readers is met
02185                      */
02186                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02187                     Log0(PCSC_LOG_DEBUG);
02188                     dwBreakFlag = 1;
02189                 }
02190             }   /* End of SCARD_STATE_UNKNOWN */
02191         }   /* End of SCARD_STATE_IGNORE */
02192 
02193         /* Counter and resetter */
02194         j++;
02195         if (j == cReaders)
02196         {
02197             /* go back to the first reader */
02198             j = 0;
02199 
02200             /* Declare all the break conditions */
02201 
02202             /* Break if UNAWARE is set and all readers have been checked */
02203             if (dwBreakFlag == 1)
02204                 break;
02205 
02206             /* Only sleep once for each cycle of reader checks. */
02207             {
02208                 struct wait_reader_state_change waitStatusStruct;
02209                 struct timeval before, after;
02210 
02211                 gettimeofday(&before, NULL);
02212 
02213                 waitStatusStruct.timeOut = dwTime;
02214                 waitStatusStruct.rv = SCARD_S_SUCCESS;
02215 
02216                 rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
02217                     currentContextMap->dwClientID,
02218                     sizeof(waitStatusStruct),
02219                     &waitStatusStruct);
02220 
02221                 if (rv == -1)
02222                 {
02223                     rv = SCARD_E_NO_SERVICE;
02224                     goto end;
02225                 }
02226 
02227                 /*
02228                  * Read a message from the server
02229                  */
02230                 rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
02231                     &waitStatusStruct, sizeof(waitStatusStruct),
02232                     currentContextMap->dwClientID, dwTime);
02233 
02234                 /* timeout */
02235                 if (-2 == rv)
02236                 {
02237                     /* ask server to remove us from the event list */
02238                     rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
02239                         currentContextMap->dwClientID,
02240                         sizeof(waitStatusStruct),
02241                         &waitStatusStruct);
02242 
02243                     if (rv == -1)
02244                     {
02245                         rv = SCARD_E_NO_SERVICE;
02246                         goto end;
02247                     }
02248 
02249                     /* Read a message from the server */
02250                     rv = MessageReceive(&waitStatusStruct,
02251                         sizeof(waitStatusStruct),
02252                         currentContextMap->dwClientID);
02253 
02254                     if (rv == -1)
02255                     {
02256                         rv = SCARD_E_NO_SERVICE;
02257                         goto end;
02258                     }
02259                 }
02260 
02261                 if (rv < 0)
02262                 {
02263                     rv = SCARD_E_NO_SERVICE;
02264                     goto end;
02265                 }
02266 
02267                 /* an event occurs or SCardCancel() was called */
02268                 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
02269                 {
02270                     rv = waitStatusStruct.rv;
02271                     goto end;
02272                 }
02273 
02274                 /* synchronize reader states with daemon */
02275                 rv = getReaderStates(currentContextMap);
02276                 if (rv != SCARD_S_SUCCESS)
02277                     goto end;
02278 
02279                 if (INFINITE != dwTimeout)
02280                 {
02281                     long int diff;
02282 
02283                     gettimeofday(&after, NULL);
02284                     diff = time_sub(&after, &before);
02285                     dwTime -= diff/1000;
02286                 }
02287             }
02288 
02289             if (dwTimeout != INFINITE)
02290             {
02291                 /* If time is greater than timeout and all readers have been
02292                  * checked
02293                  */
02294                 if (dwTime <= 0)
02295                 {
02296                     rv = SCARD_E_TIMEOUT;
02297                     goto end;
02298                 }
02299             }
02300         }
02301     }
02302     while (1);
02303 
02304 end:
02305     Log1(PCSC_LOG_DEBUG, "Event Loop End");
02306 
02307     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02308 
02309     PROFILE_END(rv)
02310 
02311     return rv;
02312 }
02313 
02367 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
02368     DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
02369     LPDWORD lpBytesReturned)
02370 {
02371     LONG rv;
02372     struct control_struct scControlStruct;
02373     SCONTEXTMAP * currentContextMap;
02374     CHANNEL_MAP * pChannelMap;
02375 
02376     PROFILE_START
02377 
02378     /* 0 bytes received by default */
02379     if (NULL != lpBytesReturned)
02380         *lpBytesReturned = 0;
02381 
02382     CHECK_SAME_PROCESS
02383 
02384     /*
02385      * Make sure this handle has been opened
02386      */
02387     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02388         &pChannelMap);
02389     if (rv == -1)
02390     {
02391         PROFILE_END(SCARD_E_INVALID_HANDLE)
02392         return SCARD_E_INVALID_HANDLE;
02393     }
02394 
02395     (void)pthread_mutex_lock(currentContextMap->mMutex);
02396 
02397     /* check the handle is still valid */
02398     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02399         &pChannelMap);
02400     if (rv == -1)
02401         /* the handle is now invalid
02402          * -> another thread may have called SCardReleaseContext
02403          * -> so the mMutex has been unlocked */
02404         return SCARD_E_INVALID_HANDLE;
02405 
02406     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02407         || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02408     {
02409         rv = SCARD_E_INSUFFICIENT_BUFFER;
02410         goto end;
02411     }
02412 
02413     scControlStruct.hCard = hCard;
02414     scControlStruct.dwControlCode = dwControlCode;
02415     scControlStruct.cbSendLength = cbSendLength;
02416     scControlStruct.cbRecvLength = cbRecvLength;
02417 
02418     rv = MessageSendWithHeader(SCARD_CONTROL,
02419         currentContextMap->dwClientID,
02420         sizeof(scControlStruct), &scControlStruct);
02421 
02422     if (rv == -1)
02423     {
02424         rv = SCARD_E_NO_SERVICE;
02425         goto end;
02426     }
02427 
02428     /* write the sent buffer */
02429     rv = MessageSend((char *)pbSendBuffer, cbSendLength,
02430         currentContextMap->dwClientID);
02431 
02432     if (rv == -1)
02433     {
02434         rv = SCARD_E_NO_SERVICE;
02435         goto end;
02436     }
02437 
02438     /*
02439      * Read a message from the server
02440      */
02441     rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
02442         currentContextMap->dwClientID);
02443 
02444     if (rv < 0)
02445     {
02446         rv = SCARD_F_COMM_ERROR;
02447         goto end;
02448     }
02449 
02450     if (SCARD_S_SUCCESS == scControlStruct.rv)
02451     {
02452         /* read the received buffer */
02453         rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
02454             currentContextMap->dwClientID);
02455 
02456         if (rv < 0)
02457         {
02458             rv = SCARD_E_NO_SERVICE;
02459             goto end;
02460         }
02461 
02462     }
02463 
02464     if (NULL != lpBytesReturned)
02465         *lpBytesReturned = scControlStruct.dwBytesReturned;
02466 
02467     rv = scControlStruct.rv;
02468 
02469 end:
02470     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02471 
02472     PROFILE_END(rv)
02473 
02474     return rv;
02475 }
02476 
02581 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
02582     LPDWORD pcbAttrLen)
02583 {
02584     LONG ret;
02585     unsigned char *buf = NULL;
02586 
02587     PROFILE_START
02588 
02589     if (NULL == pcbAttrLen)
02590         return SCARD_E_INVALID_PARAMETER;
02591 
02592     if (SCARD_AUTOALLOCATE == *pcbAttrLen)
02593     {
02594         if (NULL == pbAttr)
02595             return SCARD_E_INVALID_PARAMETER;
02596 
02597         *pcbAttrLen = MAX_BUFFER_SIZE;
02598         buf = malloc(*pcbAttrLen);
02599         if (NULL == buf)
02600             return SCARD_E_NO_MEMORY;
02601 
02602         *(unsigned char **)pbAttr = buf;
02603     }
02604     else
02605     {
02606         buf = pbAttr;
02607 
02608         /* if only get the length */
02609         if (NULL == pbAttr)
02610             /* use a reasonable size */
02611             *pcbAttrLen = MAX_BUFFER_SIZE;
02612     }
02613 
02614     ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
02615         pcbAttrLen);
02616 
02617     PROFILE_END(ret)
02618 
02619     return ret;
02620 }
02621 
02657 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
02658     DWORD cbAttrLen)
02659 {
02660     LONG ret;
02661 
02662     PROFILE_START
02663 
02664     if (NULL == pbAttr || 0 == cbAttrLen)
02665         return SCARD_E_INVALID_PARAMETER;
02666 
02667     ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
02668         &cbAttrLen);
02669 
02670     PROFILE_END(ret)
02671 
02672     return ret;
02673 }
02674 
02675 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
02676     LPBYTE pbAttr, LPDWORD pcbAttrLen)
02677 {
02678     LONG rv;
02679     struct getset_struct scGetSetStruct;
02680     SCONTEXTMAP * currentContextMap;
02681     CHANNEL_MAP * pChannelMap;
02682 
02683     CHECK_SAME_PROCESS
02684 
02685     /*
02686      * Make sure this handle has been opened
02687      */
02688     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02689         &pChannelMap);
02690     if (rv == -1)
02691         return SCARD_E_INVALID_HANDLE;
02692 
02693     (void)pthread_mutex_lock(currentContextMap->mMutex);
02694 
02695     /* check the handle is still valid */
02696     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02697         &pChannelMap);
02698     if (rv == -1)
02699         /* the handle is now invalid
02700          * -> another thread may have called SCardReleaseContext
02701          * -> so the mMutex has been unlocked */
02702         return SCARD_E_INVALID_HANDLE;
02703 
02704     if (*pcbAttrLen > MAX_BUFFER_SIZE)
02705     {
02706         rv = SCARD_E_INSUFFICIENT_BUFFER;
02707         goto end;
02708     }
02709 
02710     scGetSetStruct.hCard = hCard;
02711     scGetSetStruct.dwAttrId = dwAttrId;
02712     scGetSetStruct.cbAttrLen = *pcbAttrLen;
02713     scGetSetStruct.rv = SCARD_E_NO_SERVICE;
02714     memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
02715     if (SCARD_SET_ATTRIB == command)
02716         memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
02717 
02718     rv = MessageSendWithHeader(command,
02719         currentContextMap->dwClientID, sizeof(scGetSetStruct),
02720         &scGetSetStruct);
02721 
02722     if (rv == -1)
02723     {
02724         rv = SCARD_E_NO_SERVICE;
02725         goto end;
02726     }
02727 
02728     /*
02729      * Read a message from the server
02730      */
02731     rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
02732         currentContextMap->dwClientID);
02733 
02734     if (rv < 0)
02735     {
02736         rv = SCARD_F_COMM_ERROR;
02737         goto end;
02738     }
02739 
02740     if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
02741     {
02742         /*
02743          * Copy and zero it so any secret information is not leaked
02744          */
02745         if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
02746         {
02747             scGetSetStruct.cbAttrLen = *pcbAttrLen;
02748             scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
02749         }
02750         else
02751             *pcbAttrLen = scGetSetStruct.cbAttrLen;
02752 
02753         if (pbAttr)
02754             memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
02755 
02756         memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
02757     }
02758     rv = scGetSetStruct.rv;
02759 
02760 end:
02761     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02762 
02763     return rv;
02764 }
02765 
02824 LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
02825     LPCBYTE pbSendBuffer, DWORD cbSendLength,
02826     LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
02827     LPDWORD pcbRecvLength)
02828 {
02829     LONG rv;
02830     SCONTEXTMAP * currentContextMap;
02831     CHANNEL_MAP * pChannelMap;
02832     struct transmit_struct scTransmitStruct;
02833 
02834     PROFILE_START
02835 
02836     if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
02837             pcbRecvLength == NULL || pioSendPci == NULL)
02838         return SCARD_E_INVALID_PARAMETER;
02839 
02840     CHECK_SAME_PROCESS
02841 
02842     /*
02843      * Make sure this handle has been opened
02844      */
02845     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02846         &pChannelMap);
02847     if (rv == -1)
02848     {
02849         *pcbRecvLength = 0;
02850         PROFILE_END(SCARD_E_INVALID_HANDLE)
02851         return SCARD_E_INVALID_HANDLE;
02852     }
02853 
02854     (void)pthread_mutex_lock(currentContextMap->mMutex);
02855 
02856     /* check the handle is still valid */
02857     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02858         &pChannelMap);
02859     if (rv == -1)
02860         /* the handle is now invalid
02861          * -> another thread may have called SCardReleaseContext
02862          * -> so the mMutex has been unlocked */
02863         return SCARD_E_INVALID_HANDLE;
02864 
02865     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02866         || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02867     {
02868         rv = SCARD_E_INSUFFICIENT_BUFFER;
02869         goto end;
02870     }
02871 
02872     /* Retry loop for blocking behaviour */
02873 retry:
02874     
02875     scTransmitStruct.hCard = hCard;
02876     scTransmitStruct.cbSendLength = cbSendLength;
02877     scTransmitStruct.pcbRecvLength = *pcbRecvLength;
02878     scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
02879     scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
02880     scTransmitStruct.rv = SCARD_S_SUCCESS;
02881 
02882     if (pioRecvPci)
02883     {
02884         scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
02885         scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
02886     }
02887     else
02888     {
02889         scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
02890         scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
02891     }
02892 
02893     rv = MessageSendWithHeader(SCARD_TRANSMIT,
02894         currentContextMap->dwClientID, sizeof(scTransmitStruct),
02895         (void *) &scTransmitStruct);
02896 
02897     if (rv == -1)
02898     {
02899         rv = SCARD_E_NO_SERVICE;
02900         goto end;
02901     }
02902 
02903     /* write the sent buffer */
02904     rv = MessageSend((void *)pbSendBuffer, cbSendLength,
02905         currentContextMap->dwClientID);
02906 
02907     if (rv == -1)
02908     {
02909         rv = SCARD_E_NO_SERVICE;
02910         goto end;
02911     }
02912 
02913     /*
02914      * Read a message from the server
02915      */
02916     rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
02917         currentContextMap->dwClientID);
02918 
02919     if (rv < 0)
02920     {
02921         rv = SCARD_F_COMM_ERROR;
02922         goto end;
02923     }
02924 
02925     if (SCARD_S_SUCCESS == scTransmitStruct.rv)
02926     {
02927         /* read the received buffer */
02928         rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
02929             currentContextMap->dwClientID);
02930 
02931         if (rv < 0)
02932         {
02933             rv = SCARD_E_NO_SERVICE;
02934             goto end;
02935         }
02936 
02937         if (pioRecvPci)
02938         {
02939             pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
02940             pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
02941         }
02942     }
02943 
02944     rv = scTransmitStruct.rv;
02945 
02946     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
02947     {
02948         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
02949         goto retry;
02950     }
02951 
02952     *pcbRecvLength = scTransmitStruct.pcbRecvLength;
02953 
02954 end:
02955     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02956 
02957     PROFILE_END(rv)
02958 
02959     return rv;
02960 }
02961 
03012 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
03013     LPSTR mszReaders, LPDWORD pcchReaders)
03014 {
03015     DWORD dwReadersLen = 0;
03016     int i;
03017     SCONTEXTMAP * currentContextMap;
03018     LONG rv = SCARD_S_SUCCESS;
03019     char *buf = NULL;
03020 
03021     (void)mszGroups;
03022     PROFILE_START
03023 
03024     /*
03025      * Check for NULL parameters
03026      */
03027     if (pcchReaders == NULL)
03028         return SCARD_E_INVALID_PARAMETER;
03029 
03030     CHECK_SAME_PROCESS
03031 
03032     /*
03033      * Make sure this context has been opened
03034      */
03035     currentContextMap = SCardGetContext(hContext);
03036     if (NULL == currentContextMap)
03037     {
03038         PROFILE_END(SCARD_E_INVALID_HANDLE)
03039         return SCARD_E_INVALID_HANDLE;
03040     }
03041 
03042     (void)pthread_mutex_lock(currentContextMap->mMutex);
03043 
03044     /* check the context is still opened */
03045     currentContextMap = SCardGetContext(hContext);
03046     if (NULL == currentContextMap)
03047         /* the context is now invalid
03048          * -> another thread may have called SCardReleaseContext
03049          * -> so the mMutex has been unlocked */
03050         return SCARD_E_INVALID_HANDLE;
03051 
03052     /* synchronize reader states with daemon */
03053     rv = getReaderStates(currentContextMap);
03054     if (rv != SCARD_S_SUCCESS)
03055         goto end;
03056 
03057     dwReadersLen = 0;
03058     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03059         if (readerStates[i].readerID != 0)
03060             dwReadersLen += strlen(readerStates[i].readerName) + 1;
03061 
03062     /* for the last NULL byte */
03063     dwReadersLen += 1;
03064 
03065     if (1 == dwReadersLen)
03066     {
03067         rv = SCARD_E_NO_READERS_AVAILABLE;
03068         goto end;
03069     }
03070 
03071     if (SCARD_AUTOALLOCATE == *pcchReaders)
03072     {
03073         buf = malloc(dwReadersLen);
03074         if (NULL == buf)
03075         {
03076             rv = SCARD_E_NO_MEMORY;
03077             goto end;
03078         }
03079         if (NULL == mszReaders)
03080         {
03081             rv = SCARD_E_INVALID_PARAMETER;
03082             goto end;
03083         }
03084         *(char **)mszReaders = buf;
03085     }
03086     else
03087     {
03088         buf = mszReaders;
03089 
03090         /* not enough place to store the reader names */
03091         if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
03092         {
03093             rv = SCARD_E_INSUFFICIENT_BUFFER;
03094             goto end;
03095         }
03096     }
03097 
03098     if (mszReaders == NULL) /* text array not allocated */
03099         goto end;
03100 
03101     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03102     {
03103         if (readerStates[i].readerID != 0)
03104         {
03105             /*
03106              * Build the multi-string
03107              */
03108             strcpy(buf, readerStates[i].readerName);
03109             buf += strlen(readerStates[i].readerName)+1;
03110         }
03111     }
03112     *buf = '\0';    /* Add the last null */
03113 
03114 end:
03115     /* set the reader names length */
03116     *pcchReaders = dwReadersLen;
03117 
03118     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03119 
03120     PROFILE_END(rv)
03121 
03122     return rv;
03123 }
03124 
03138 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
03139 {
03140     LONG rv = SCARD_S_SUCCESS;
03141     SCONTEXTMAP * currentContextMap;
03142 
03143     PROFILE_START
03144 
03145     CHECK_SAME_PROCESS
03146 
03147     /*
03148      * Make sure this context has been opened
03149      */
03150     currentContextMap = SCardGetContext(hContext);
03151     if (NULL == currentContextMap)
03152         return SCARD_E_INVALID_HANDLE;
03153 
03154     free((void *)pvMem);
03155 
03156     PROFILE_END(rv)
03157 
03158     return rv;
03159 }
03160 
03212 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
03213     LPDWORD pcchGroups)
03214 {
03215     LONG rv = SCARD_S_SUCCESS;
03216     SCONTEXTMAP * currentContextMap;
03217     char *buf = NULL;
03218 
03219     PROFILE_START
03220 
03221     /* Multi-string with two trailing \0 */
03222     const char ReaderGroup[] = "SCard$DefaultReaders\0";
03223     const unsigned int dwGroups = sizeof(ReaderGroup);
03224 
03225     CHECK_SAME_PROCESS
03226 
03227     /*
03228      * Make sure this context has been opened
03229      */
03230     currentContextMap = SCardGetContext(hContext);
03231     if (NULL == currentContextMap)
03232         return SCARD_E_INVALID_HANDLE;
03233 
03234     (void)pthread_mutex_lock(currentContextMap->mMutex);
03235 
03236     /* check the context is still opened */
03237     currentContextMap = SCardGetContext(hContext);
03238     if (NULL == currentContextMap)
03239         /* the context is now invalid
03240          * -> another thread may have called SCardReleaseContext
03241          * -> so the mMutex has been unlocked */
03242         return SCARD_E_INVALID_HANDLE;
03243 
03244     if (SCARD_AUTOALLOCATE == *pcchGroups)
03245     {
03246         buf = malloc(dwGroups);
03247         if (NULL == buf)
03248         {
03249             rv = SCARD_E_NO_MEMORY;
03250             goto end;
03251         }
03252         if (NULL == mszGroups)
03253         {
03254             rv = SCARD_E_INVALID_PARAMETER;
03255             goto end;
03256         }
03257         *(char **)mszGroups = buf;
03258     }
03259     else
03260     {
03261         buf = mszGroups;
03262 
03263         if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
03264         {
03265             rv = SCARD_E_INSUFFICIENT_BUFFER;
03266             goto end;
03267         }
03268     }
03269 
03270     if (buf)
03271         memcpy(buf, ReaderGroup, dwGroups);
03272 
03273 end:
03274     *pcchGroups = dwGroups;
03275 
03276     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03277 
03278     PROFILE_END(rv)
03279 
03280     return rv;
03281 }
03282 
03312 LONG SCardCancel(SCARDCONTEXT hContext)
03313 {
03314     SCONTEXTMAP * currentContextMap;
03315     LONG rv = SCARD_S_SUCCESS;
03316     uint32_t dwClientID = 0;
03317     struct cancel_struct scCancelStruct;
03318 
03319     PROFILE_START
03320 
03321     /*
03322      * Make sure this context has been opened
03323      */
03324     currentContextMap = SCardGetContext(hContext);
03325     if (NULL == currentContextMap)
03326         return SCARD_E_INVALID_HANDLE;
03327 
03328     /* create a new connection to the server */
03329     if (ClientSetupSession(&dwClientID) != 0)
03330     {
03331         rv = SCARD_E_NO_SERVICE;
03332         goto error;
03333     }
03334 
03335     scCancelStruct.hContext = hContext;
03336     scCancelStruct.rv = SCARD_S_SUCCESS;
03337 
03338     rv = MessageSendWithHeader(SCARD_CANCEL,
03339         dwClientID,
03340         sizeof(scCancelStruct), (void *) &scCancelStruct);
03341 
03342     if (rv == -1)
03343     {
03344         rv = SCARD_E_NO_SERVICE;
03345         goto end;
03346     }
03347 
03348     /*
03349      * Read a message from the server
03350      */
03351     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
03352         dwClientID);
03353 
03354     if (rv < 0)
03355     {
03356         rv = SCARD_F_COMM_ERROR;
03357         goto end;
03358     }
03359 
03360     rv = scCancelStruct.rv;
03361 end:
03362     ClientCloseSession(dwClientID);
03363 
03364 error:
03365     PROFILE_END(rv)
03366 
03367     return rv;
03368 }
03369 
03393 LONG SCardIsValidContext(SCARDCONTEXT hContext)
03394 {
03395     LONG rv;
03396     SCONTEXTMAP * currentContextMap;
03397 
03398     PROFILE_START
03399 
03400     rv = SCARD_S_SUCCESS;
03401 
03402     /* Check if the _same_ server is running */
03403     CHECK_SAME_PROCESS
03404 
03405     /*
03406      * Make sure this context has been opened
03407      */
03408     currentContextMap = SCardGetContext(hContext);
03409     if (currentContextMap == NULL)
03410         rv = SCARD_E_INVALID_HANDLE;
03411 
03412     PROFILE_END(rv)
03413 
03414     return rv;
03415 }
03416 
03433 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
03434 {
03435     int lrv;
03436     SCONTEXTMAP * newContextMap;
03437 
03438     newContextMap = malloc(sizeof(SCONTEXTMAP));
03439     if (NULL == newContextMap)
03440         return SCARD_E_NO_MEMORY;
03441 
03442     Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%X", newContextMap);
03443     newContextMap->hContext = hContext;
03444     newContextMap->dwClientID = dwClientID;
03445 
03446     newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
03447     if (NULL == newContextMap->mMutex)
03448     {
03449         Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%X", newContextMap);
03450         free(newContextMap);
03451         return SCARD_E_NO_MEMORY;
03452     }
03453     (void)pthread_mutex_init(newContextMap->mMutex, NULL);
03454 
03455     lrv = list_init(&(newContextMap->channelMapList));
03456     if (lrv < 0)
03457     {
03458         Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
03459         goto error;
03460     }
03461 
03462     lrv = list_attributes_seeker(&(newContextMap->channelMapList),
03463         CHANNEL_MAP_seeker);
03464     if (lrv <0)
03465     {
03466         Log2(PCSC_LOG_CRITICAL,
03467             "list_attributes_seeker failed with return value: %X", lrv);
03468         list_destroy(&(newContextMap->channelMapList));
03469         goto error;
03470     }
03471 
03472     lrv = list_append(&contextMapList, newContextMap);
03473     if (lrv < 0)
03474     {
03475         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X",
03476             lrv);
03477         list_destroy(&(newContextMap->channelMapList));
03478         goto error;
03479     }
03480 
03481     return SCARD_S_SUCCESS;
03482 
03483 error:
03484 
03485     (void)pthread_mutex_destroy(newContextMap->mMutex);
03486     free(newContextMap->mMutex);
03487     free(newContextMap);
03488 
03489     return SCARD_E_NO_MEMORY;
03490 }
03491 
03504 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT hContext)
03505 {
03506     SCONTEXTMAP * currentContextMap;
03507 
03508     (void)SCardLockThread();
03509     currentContextMap = SCardGetContextTH(hContext);
03510     (void)SCardUnlockThread();
03511 
03512     return currentContextMap;
03513 }
03514 
03527 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext)
03528 {
03529     return list_seek(&contextMapList, &hContext);
03530 }
03531 
03541 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
03542 {
03543     SCONTEXTMAP * currentContextMap;
03544     currentContextMap = SCardGetContextTH(hContext);
03545 
03546     if (NULL == currentContextMap)
03547         return SCARD_E_INVALID_HANDLE;
03548     else
03549         return SCardCleanContext(currentContextMap);
03550 }
03551 
03552 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
03553 {
03554     int list_index, lrv;
03555     int listSize;
03556     CHANNEL_MAP * currentChannelMap;
03557 
03558     targetContextMap->hContext = 0;
03559     (void)ClientCloseSession(targetContextMap->dwClientID);
03560     targetContextMap->dwClientID = 0;
03561     (void)pthread_mutex_destroy(targetContextMap->mMutex);
03562     free(targetContextMap->mMutex);
03563     targetContextMap->mMutex = NULL;
03564 
03565     listSize = list_size(&(targetContextMap->channelMapList));
03566     for (list_index = 0; list_index < listSize; list_index++)
03567     {
03568         currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
03569             list_index);
03570         if (NULL == currentChannelMap)
03571         {
03572             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03573                 list_index);
03574             continue;
03575         }
03576         else
03577         {
03578             free(currentChannelMap->readerName);
03579             free(currentChannelMap);
03580         }
03581 
03582     }
03583     list_destroy(&(targetContextMap->channelMapList));
03584 
03585     lrv = list_delete(&contextMapList, targetContextMap);
03586     if (lrv < 0)
03587     {
03588         Log2(PCSC_LOG_CRITICAL,
03589             "list_delete failed with return value: %X", lrv);
03590     }
03591 
03592     free(targetContextMap);
03593 
03594     return SCARD_S_SUCCESS;
03595 }
03596 
03597 /*
03598  * Functions for managing hCard values returned from SCardConnect.
03599  */
03600 
03601 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
03602     LPCSTR readerName)
03603 {
03604     CHANNEL_MAP * newChannelMap;
03605     int lrv = -1;
03606 
03607     newChannelMap = malloc(sizeof(CHANNEL_MAP));
03608     if (NULL == newChannelMap)
03609         return SCARD_E_NO_MEMORY;
03610 
03611     newChannelMap->hCard = hCard;
03612     newChannelMap->readerName = strdup(readerName);
03613 
03614     lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
03615     if (lrv < 0)
03616     {
03617         free(newChannelMap->readerName);
03618         free(newChannelMap);
03619         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X", lrv);
03620         return SCARD_E_NO_MEMORY;
03621     }
03622 
03623     return SCARD_S_SUCCESS;
03624 }
03625 
03626 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
03627 {
03628     SCONTEXTMAP * currentContextMap;
03629     CHANNEL_MAP * currentChannelMap;
03630     int lrv;
03631     LONG rv;
03632 
03633     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
03634         &currentChannelMap);
03635     if (rv == -1)
03636         return SCARD_E_INVALID_HANDLE;
03637 
03638     free(currentChannelMap->readerName);
03639 
03640     lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
03641     if (lrv < 0)
03642     {
03643         Log2(PCSC_LOG_CRITICAL,
03644             "list_delete failed with return value: %X", lrv);
03645     }
03646 
03647     free(currentChannelMap);
03648 
03649     return SCARD_S_SUCCESS;
03650 }
03651 
03652 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
03653     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03654 {
03655     LONG rv;
03656 
03657     if (0 == hCard)
03658         return -1;
03659 
03660     (void)SCardLockThread();
03661     rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap, targetChannelMap);
03662     (void)SCardUnlockThread();
03663 
03664     return rv;
03665 }
03666 
03667 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
03668     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03669 {
03670     int listSize;
03671     int list_index;
03672     SCONTEXTMAP * currentContextMap;
03673     CHANNEL_MAP * currentChannelMap;
03674 
03675     /* Best to get the caller a crash early if we fail unsafely */
03676     *targetContextMap = NULL;
03677     *targetChannelMap = NULL;
03678 
03679     listSize = list_size(&contextMapList);
03680 
03681     for (list_index = 0; list_index < listSize; list_index++)
03682     {
03683         currentContextMap = list_get_at(&contextMapList, list_index);
03684         if (currentContextMap == NULL)
03685         {
03686             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d", list_index);
03687             continue;
03688         }
03689         currentChannelMap = list_seek(&(currentContextMap->channelMapList),
03690             &hCard);
03691         if (currentChannelMap != NULL)
03692         {
03693             *targetContextMap = currentContextMap;
03694             *targetChannelMap = currentChannelMap;
03695             return SCARD_S_SUCCESS;
03696         }
03697     }
03698 
03699     return -1;
03700 }
03701 
03702 static LONG SCardInvalidateHandles(void)
03703 {
03704     /* invalid all handles */
03705     (void)SCardLockThread();
03706 
03707     while (list_size(&contextMapList) != 0)
03708     {
03709         SCONTEXTMAP * currentContextMap;
03710 
03711         currentContextMap = list_get_at(&contextMapList, 0);
03712         if (currentContextMap != NULL)
03713             (void)SCardCleanContext(currentContextMap);
03714         else
03715             Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
03716     }
03717 
03718     (void)SCardUnlockThread();
03719 
03720     /* reset pcscd status */
03721     daemon_ctime = 0;
03722     client_pid = 0;
03723 
03724     return SCARD_E_INVALID_HANDLE;
03725 }
03726 
03739 LONG SCardCheckDaemonAvailability(void)
03740 {
03741     LONG rv;
03742     struct stat statBuffer;
03743     int need_restart = 0;
03744 
03745     rv = stat(PCSCLITE_CSOCK_NAME, &statBuffer);
03746 
03747     if (rv != 0)
03748     {
03749         Log2(PCSC_LOG_INFO, "PCSC Not Running: " PCSCLITE_CSOCK_NAME ": %s",
03750             strerror(errno));
03751         return SCARD_E_NO_SERVICE;
03752     }
03753 
03754     /* when the _first_ reader is connected the ctime changes
03755      * I don't know why yet */
03756     if (daemon_ctime && statBuffer.st_ctime > daemon_ctime)
03757     {
03758         /* so we also check the daemon pid to be sure it is a new pcscd */
03759         if (GetDaemonPid() != daemon_pid)
03760         {
03761             Log1(PCSC_LOG_INFO, "PCSC restarted");
03762             need_restart = 1;
03763         }
03764     }
03765 
03766     /* after fork() need to restart */
03767     if (client_pid && client_pid != getpid())
03768     {
03769         Log1(PCSC_LOG_INFO, "Client forked");
03770         need_restart = 1;
03771     }
03772 
03773     if (need_restart)
03774         return SCardInvalidateHandles();
03775 
03776     daemon_ctime = statBuffer.st_ctime;
03777     daemon_pid = GetDaemonPid();
03778     client_pid = getpid();
03779 
03780     return SCARD_S_SUCCESS;
03781 }
03782 
03783 #ifdef DO_CHECK_SAME_PROCESS
03784 static LONG SCardCheckSameProcess(void)
03785 {
03786     /* after fork() need to restart */
03787     if ((client_pid && client_pid != getpid()))
03788     {
03789         Log1(PCSC_LOG_INFO, "Client forked");
03790         return SCardInvalidateHandles();
03791     }
03792 
03793     client_pid = getpid();
03794 
03795     return SCARD_S_SUCCESS;
03796 }
03797 #endif
03798 
03799 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
03800 {
03801     int32_t dwClientID = currentContextMap->dwClientID;
03802 
03803     if (-1 == MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL))
03804         return SCARD_E_NO_SERVICE;
03805 
03806     /* Read a message from the server */
03807     if (MessageReceive(&readerStates, sizeof(readerStates), dwClientID) < 0)
03808         return SCARD_F_COMM_ERROR;
03809 
03810     return SCARD_S_SUCCESS;
03811 }
03812