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-2010
00011  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00012  * Copyright (C) 2009
00013  *  Jean-Luc Giraud <jlgiraud@googlemail.com>
00014  *
00015  * $Id: winscard_clnt.c 5126 2010-08-13 12:41:29Z 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, i, max;
00434                 char *param = getenv("PCSCLITE_PCSCD_ARGS");
00435 
00436                 /* close all file handles except stdin, stdout and
00437                  * stderr so that pcscd does not confiscate ressources
00438                  * allocated by the application */
00439                 max = sysconf(_SC_OPEN_MAX);
00440                 if (-1 == max)
00441                     max = 1024;
00442                 for (i=3; i<max; i++)
00443                     (void)close(i);
00444 
00445                 /* son process */
00446                 ret = execl(PCSCD_BINARY, "pcscd", "--auto-exit", param,
00447                     (char *)NULL);
00448                 Log2(PCSC_LOG_CRITICAL, "exec " PCSCD_BINARY " failed: %s",
00449                     strerror(errno));
00450                 exit(1);
00451             }
00452 
00453             /* father process */
00454             daemon_launched = TRUE;
00455 
00456             if (waitpid(pid, NULL, 0) < 0)
00457                 Log2(PCSC_LOG_CRITICAL, "waitpid failed: %s", strerror(errno));
00458 
00459             goto again;
00460         }
00461     }
00462 
00463     if (rv != SCARD_S_SUCCESS)
00464         goto end;
00465 
00466     (void)SCardLockThread();
00467     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00468         pvReserved2, phContext);
00469     (void)SCardUnlockThread();
00470 
00471     /* SCardEstablishContextTH may fail if the previous pcscd crashed
00472      * without cleaning /var/run/pcscd/pcscd.comm */
00473     if (SCARD_E_NO_SERVICE == rv)
00474     {
00475         retries++;
00476         if (retries <= 1)
00477             goto launch;
00478     }
00479 
00480 end:
00481     PROFILE_END(rv)
00482 
00483     return rv;
00484 }
00485 
00512 static LONG SCardEstablishContextTH(DWORD dwScope,
00513     /*@unused@*/ LPCVOID pvReserved1,
00514     /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00515 {
00516     LONG rv;
00517     struct establish_struct scEstablishStruct;
00518     uint32_t dwClientID = 0;
00519 
00520     (void)pvReserved1;
00521     (void)pvReserved2;
00522     if (phContext == NULL)
00523         return SCARD_E_INVALID_PARAMETER;
00524     else
00525         *phContext = 0;
00526 
00527     /*
00528      * Do this only once:
00529      * - Initialize context list.
00530      */
00531     if (isExecuted == 0)
00532     {
00533         int lrv;
00534 
00535         /* NOTE: The list will never be freed (No API call exists to
00536          * "close all contexts".
00537          * Applications which load and unload the library will leak
00538          * the list's internal structures. */
00539         lrv = list_init(&contextMapList);
00540         if (lrv < 0)
00541         {
00542             Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
00543             return SCARD_E_NO_MEMORY;
00544         }
00545 
00546         lrv = list_attributes_seeker(&contextMapList,
00547                 SCONTEXTMAP_seeker);
00548         if (lrv <0)
00549         {
00550             Log2(PCSC_LOG_CRITICAL,
00551                 "list_attributes_seeker failed with return value: %X", lrv);
00552             list_destroy(&contextMapList);
00553             return SCARD_E_NO_MEMORY;
00554         }
00555 
00556         if (getenv("PCSCLITE_NO_BLOCKING"))
00557         {
00558             Log1(PCSC_LOG_INFO, "Disable shared blocking");
00559             sharing_shall_block = FALSE;
00560         }
00561         
00562         isExecuted = 1;
00563     }
00564 
00565 
00566     /* Establishes a connection to the server */
00567     if (ClientSetupSession(&dwClientID) != 0)
00568     {
00569         return SCARD_E_NO_SERVICE;
00570     }
00571 
00572     {   /* exchange client/server protocol versions */
00573         struct version_struct veStr;
00574 
00575         veStr.major = PROTOCOL_VERSION_MAJOR;
00576         veStr.minor = PROTOCOL_VERSION_MINOR;
00577         veStr.rv = SCARD_S_SUCCESS;
00578 
00579         if (-1 == MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
00580             &veStr))
00581             return SCARD_E_NO_SERVICE;
00582 
00583         /* Read a message from the server */
00584         if (MessageReceive(&veStr, sizeof(veStr), dwClientID) < 0)
00585         {
00586             Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION");
00587             return SCARD_F_COMM_ERROR;
00588         }
00589 
00590         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00591             veStr.major, veStr.minor);
00592 
00593         if (veStr.rv != SCARD_S_SUCCESS)
00594             return veStr.rv;
00595     }
00596 
00597 again:
00598     /*
00599      * Try to establish an Application Context with the server
00600      */
00601     scEstablishStruct.dwScope = dwScope;
00602     scEstablishStruct.hContext = 0;
00603     scEstablishStruct.rv = SCARD_S_SUCCESS;
00604 
00605     rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
00606         sizeof(scEstablishStruct), (void *) &scEstablishStruct);
00607 
00608     if (rv == -1)
00609         return SCARD_E_NO_SERVICE;
00610 
00611     /*
00612      * Read the response from the server
00613      */
00614     rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct), dwClientID);
00615 
00616     if (rv < 0)
00617         return SCARD_F_COMM_ERROR;
00618 
00619     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00620         return scEstablishStruct.rv;
00621 
00622     /* check we do not reuse an existing hContext */
00623     if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
00624         /* we do not need to release the allocated context since
00625          * SCardReleaseContext() does nothing on the server side */
00626         goto again;
00627 
00628     *phContext = scEstablishStruct.hContext;
00629 
00630     /*
00631      * Allocate the new hContext - if allocator full return an error
00632      */
00633     rv = SCardAddContext(*phContext, dwClientID);
00634 
00635     return rv;
00636 }
00637 
00659 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00660 {
00661     LONG rv;
00662     struct release_struct scReleaseStruct;
00663     SCONTEXTMAP * currentContextMap;
00664 
00665     PROFILE_START
00666 
00667     CHECK_SAME_PROCESS
00668 
00669     /*
00670      * Make sure this context has been opened
00671      * and get currentContextMap
00672      */
00673     currentContextMap = SCardGetContext(hContext);
00674     if (NULL == currentContextMap)
00675     {
00676         PROFILE_END(SCARD_E_INVALID_HANDLE)
00677         return SCARD_E_INVALID_HANDLE;
00678     }
00679 
00680     (void)pthread_mutex_lock(currentContextMap->mMutex);
00681 
00682     /* check the context is still opened */
00683     currentContextMap = SCardGetContext(hContext);
00684     if (NULL == currentContextMap)
00685         /* the context is now invalid
00686          * -> another thread may have called SCardReleaseContext
00687          * -> so the mMutex has been unlocked */
00688         return SCARD_E_INVALID_HANDLE;
00689 
00690     scReleaseStruct.hContext = hContext;
00691     scReleaseStruct.rv = SCARD_S_SUCCESS;
00692 
00693     rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
00694         currentContextMap->dwClientID,
00695         sizeof(scReleaseStruct),
00696         (void *) &scReleaseStruct);
00697 
00698     if (rv == -1)
00699     {
00700         rv = SCARD_E_NO_SERVICE;
00701         goto end;
00702     }
00703 
00704     /*
00705      * Read a message from the server
00706      */
00707     rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
00708         currentContextMap->dwClientID);
00709 
00710     if (rv < 0)
00711     {
00712         rv = SCARD_F_COMM_ERROR;
00713         goto end;
00714     }
00715 
00716     rv = scReleaseStruct.rv;
00717 end:
00718     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00719 
00720     /*
00721      * Remove the local context from the stack
00722      */
00723     (void)SCardLockThread();
00724     (void)SCardRemoveContext(hContext);
00725     (void)SCardUnlockThread();
00726 
00727     PROFILE_END(rv)
00728 
00729     return rv;
00730 }
00731 
00747 LONG SCardSetTimeout(/*@unused@*/ SCARDCONTEXT hContext,
00748     /*@unused@*/ DWORD dwTimeout)
00749 {
00750     /*
00751      * Deprecated
00752      */
00753     (void)hContext;
00754     (void)dwTimeout;
00755     return SCARD_S_SUCCESS;
00756 }
00757 
00815 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00816     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00817     LPDWORD pdwActiveProtocol)
00818 {
00819     LONG rv;
00820     struct connect_struct scConnectStruct;
00821     SCONTEXTMAP * currentContextMap;
00822 
00823     PROFILE_START
00824 
00825     /*
00826      * Check for NULL parameters
00827      */
00828     if (phCard == NULL || pdwActiveProtocol == NULL)
00829         return SCARD_E_INVALID_PARAMETER;
00830     else
00831         *phCard = 0;
00832 
00833     if (szReader == NULL)
00834         return SCARD_E_UNKNOWN_READER;
00835 
00836     /*
00837      * Check for uninitialized strings
00838      */
00839     if (strlen(szReader) > MAX_READERNAME)
00840         return SCARD_E_INVALID_VALUE;
00841 
00842     CHECK_SAME_PROCESS
00843 
00844     /*
00845      * Make sure this context has been opened
00846      */
00847     currentContextMap = SCardGetContext(hContext);
00848     if (NULL == currentContextMap)
00849         return SCARD_E_INVALID_HANDLE;
00850 
00851     (void)pthread_mutex_lock(currentContextMap->mMutex);
00852 
00853     /* check the context is still opened */
00854     currentContextMap = SCardGetContext(hContext);
00855     if (NULL == currentContextMap)
00856         /* the context is now invalid
00857          * -> another thread may have called SCardReleaseContext
00858          * -> so the mMutex has been unlocked */
00859         return SCARD_E_INVALID_HANDLE;
00860 
00861     strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
00862 
00863     scConnectStruct.hContext = hContext;
00864     scConnectStruct.dwShareMode = dwShareMode;
00865     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00866     scConnectStruct.hCard = 0;
00867     scConnectStruct.dwActiveProtocol = 0;
00868     scConnectStruct.rv = SCARD_S_SUCCESS;
00869 
00870     rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
00871         sizeof(scConnectStruct),
00872         (void *) &scConnectStruct);
00873 
00874     if (rv == -1)
00875     {
00876         rv = SCARD_E_NO_SERVICE;
00877         goto end;
00878     }
00879 
00880     /*
00881      * Read a message from the server
00882      */
00883     rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
00884         currentContextMap->dwClientID);
00885 
00886     if (rv < 0)
00887     {
00888         rv = SCARD_F_COMM_ERROR;
00889         goto end;
00890     }
00891 
00892     *phCard = scConnectStruct.hCard;
00893     *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
00894 
00895     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00896     {
00897         /*
00898          * Keep track of the handle locally
00899          */
00900         rv = SCardAddHandle(*phCard, currentContextMap, szReader);
00901     }
00902     else
00903         rv = scConnectStruct.rv;
00904 
00905 end:
00906     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00907 
00908     PROFILE_END(rv)
00909 
00910     return rv;
00911 }
00912 
00986 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
00987     DWORD dwPreferredProtocols, DWORD dwInitialization,
00988     LPDWORD pdwActiveProtocol)
00989 {
00990     LONG rv;
00991     struct reconnect_struct scReconnectStruct;
00992     SCONTEXTMAP * currentContextMap;
00993     CHANNEL_MAP * pChannelMap;
00994 
00995     PROFILE_START
00996 
00997     if (pdwActiveProtocol == NULL)
00998         return SCARD_E_INVALID_PARAMETER;
00999 
01000     CHECK_SAME_PROCESS
01001 
01002     /*
01003      * Make sure this handle has been opened
01004      */
01005     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01006         &pChannelMap);
01007     if (rv == -1)
01008         return SCARD_E_INVALID_HANDLE;
01009 
01010     (void)pthread_mutex_lock(currentContextMap->mMutex);
01011 
01012     /* check the handle is still valid */
01013     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01014         &pChannelMap);
01015     if (rv == -1)
01016         /* the handle is now invalid
01017          * -> another thread may have called SCardReleaseContext
01018          * -> so the mMutex has been unlocked */
01019         return SCARD_E_INVALID_HANDLE;
01020 
01021     /* Retry loop for blocking behaviour */
01022 retry:
01023     
01024     scReconnectStruct.hCard = hCard;
01025     scReconnectStruct.dwShareMode = dwShareMode;
01026     scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
01027     scReconnectStruct.dwInitialization = dwInitialization;
01028     scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
01029     scReconnectStruct.rv = SCARD_S_SUCCESS;
01030 
01031     rv = MessageSendWithHeader(SCARD_RECONNECT,
01032         currentContextMap->dwClientID,
01033         sizeof(scReconnectStruct),
01034         (void *) &scReconnectStruct);
01035 
01036     if (rv == -1)
01037     {
01038         rv = SCARD_E_NO_SERVICE;
01039         goto end;
01040     }
01041 
01042     /*
01043      * Read a message from the server
01044      */
01045     rv = MessageReceive(&scReconnectStruct,
01046         sizeof(scReconnectStruct),
01047         currentContextMap->dwClientID);
01048 
01049     if (rv < 0)
01050     {
01051         rv = SCARD_F_COMM_ERROR;
01052         goto end;
01053     }
01054 
01055     rv = scReconnectStruct.rv;
01056 
01057     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01058     {
01059         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01060         goto retry;
01061     }
01062     
01063     *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
01064 
01065 end:
01066     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01067 
01068     PROFILE_END(rv)
01069 
01070     return rv;
01071 }
01072 
01104 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01105 {
01106     LONG rv;
01107     struct disconnect_struct scDisconnectStruct;
01108     SCONTEXTMAP * currentContextMap;
01109     CHANNEL_MAP * pChannelMap;
01110 
01111     PROFILE_START
01112 
01113     CHECK_SAME_PROCESS
01114 
01115     /*
01116      * Make sure this handle has been opened
01117      */
01118     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01119         &pChannelMap);
01120     if (rv == -1)
01121         return SCARD_E_INVALID_HANDLE;
01122 
01123     (void)pthread_mutex_lock(currentContextMap->mMutex);
01124 
01125     /* check the handle is still valid */
01126     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01127         &pChannelMap);
01128     if (rv == -1)
01129         /* the handle is now invalid
01130          * -> another thread may have called SCardReleaseContext
01131          * -> so the mMutex has been unlocked */
01132         return SCARD_E_INVALID_HANDLE;
01133 
01134     scDisconnectStruct.hCard = hCard;
01135     scDisconnectStruct.dwDisposition = dwDisposition;
01136     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01137 
01138     rv = MessageSendWithHeader(SCARD_DISCONNECT,
01139         currentContextMap->dwClientID,
01140         sizeof(scDisconnectStruct),
01141         (void *) &scDisconnectStruct);
01142 
01143     if (rv == -1)
01144     {
01145         rv = SCARD_E_NO_SERVICE;
01146         goto end;
01147     }
01148 
01149     /*
01150      * Read a message from the server
01151      */
01152     rv = MessageReceive(&scDisconnectStruct,
01153         sizeof(scDisconnectStruct),
01154         currentContextMap->dwClientID);
01155 
01156     if (rv < 0)
01157     {
01158         rv = SCARD_F_COMM_ERROR;
01159         goto end;
01160     }
01161 
01162     (void)SCardRemoveHandle(hCard);
01163     rv = scDisconnectStruct.rv;
01164 
01165 end:
01166     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01167 
01168     PROFILE_END(rv)
01169 
01170     return rv;
01171 }
01172 
01208 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01209 {
01210 
01211     LONG rv;
01212     struct begin_struct scBeginStruct;
01213     SCONTEXTMAP * currentContextMap;
01214     CHANNEL_MAP * pChannelMap;
01215 
01216     PROFILE_START
01217 
01218     CHECK_SAME_PROCESS
01219 
01220     /*
01221      * Make sure this handle has been opened
01222      */
01223     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01224         &pChannelMap);
01225     if (rv == -1)
01226         return SCARD_E_INVALID_HANDLE;
01227 
01228     (void)pthread_mutex_lock(currentContextMap->mMutex);
01229 
01230     /* check the handle is still valid */
01231     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01232         &pChannelMap);
01233     if (rv == -1)
01234         /* the handle is now invalid
01235          * -> another thread may have called SCardReleaseContext
01236          * -> so the mMutex has been unlocked */
01237         return SCARD_E_INVALID_HANDLE;
01238 
01239     scBeginStruct.hCard = hCard;
01240     scBeginStruct.rv = SCARD_S_SUCCESS;
01241 
01242     /*
01243      * Query the server every so often until the sharing violation ends
01244      * and then hold the lock for yourself.
01245      */
01246 
01247     do
01248     {
01249         rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
01250             currentContextMap->dwClientID,
01251             sizeof(scBeginStruct),
01252             (void *) &scBeginStruct);
01253 
01254         if (rv == -1)
01255         {
01256             rv = SCARD_E_NO_SERVICE;
01257             goto end;
01258         }
01259 
01260         /*
01261          * Read a message from the server
01262          */
01263         rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
01264             currentContextMap->dwClientID);
01265 
01266         if (rv < 0)
01267         {
01268             rv = SCARD_F_COMM_ERROR;
01269             goto end;
01270         }
01271 
01272         rv = scBeginStruct.rv;
01273     }
01274     while (SCARD_E_SHARING_VIOLATION == rv);
01275 
01276 end:
01277     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01278 
01279     PROFILE_END(rv)
01280 
01281     return rv;
01282 }
01283 
01324 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01325 {
01326     LONG rv;
01327     struct end_struct scEndStruct;
01328     int randnum;
01329     SCONTEXTMAP * currentContextMap;
01330     CHANNEL_MAP * pChannelMap;
01331 
01332     PROFILE_START
01333 
01334     /*
01335      * Zero out everything
01336      */
01337     randnum = 0;
01338 
01339     CHECK_SAME_PROCESS
01340 
01341     /*
01342      * Make sure this handle has been opened
01343      */
01344     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01345         &pChannelMap);
01346     if (rv == -1)
01347         return SCARD_E_INVALID_HANDLE;
01348 
01349     (void)pthread_mutex_lock(currentContextMap->mMutex);
01350 
01351     /* check the handle is still valid */
01352     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01353         &pChannelMap);
01354     if (rv == -1)
01355         /* the handle is now invalid
01356          * -> another thread may have called SCardReleaseContext
01357          * -> so the mMutex has been unlocked */
01358         return SCARD_E_INVALID_HANDLE;
01359 
01360     scEndStruct.hCard = hCard;
01361     scEndStruct.dwDisposition = dwDisposition;
01362     scEndStruct.rv = SCARD_S_SUCCESS;
01363 
01364     rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
01365         currentContextMap->dwClientID,
01366         sizeof(scEndStruct),
01367         (void *) &scEndStruct);
01368 
01369     if (rv == -1)
01370     {
01371         rv = SCARD_E_NO_SERVICE;
01372         goto end;
01373     }
01374 
01375     /*
01376      * Read a message from the server
01377      */
01378     rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
01379         currentContextMap->dwClientID);
01380 
01381     if (rv < 0)
01382     {
01383         rv = SCARD_F_COMM_ERROR;
01384         goto end;
01385     }
01386 
01387     /*
01388      * This helps prevent starvation
01389      */
01390     randnum = SYS_RandomInt(1000, 10000);
01391     (void)SYS_USleep(randnum);
01392     rv = scEndStruct.rv;
01393 
01394 end:
01395     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01396 
01397     PROFILE_END(rv)
01398 
01399     return rv;
01400 }
01401 
01408 LONG SCardCancelTransaction(SCARDHANDLE hCard)
01409 {
01410     LONG rv;
01411     struct cancel_transaction_struct scCancelStruct;
01412     SCONTEXTMAP * currentContextMap;
01413     CHANNEL_MAP * pChannelMap;
01414 
01415     PROFILE_START
01416 
01417     CHECK_SAME_PROCESS
01418 
01419     /*
01420      * Make sure this handle has been opened
01421      */
01422     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01423         &pChannelMap);
01424     if (rv == -1)
01425         return SCARD_E_INVALID_HANDLE;
01426 
01427     (void)pthread_mutex_lock(currentContextMap->mMutex);
01428 
01429     /* check the handle is still valid */
01430     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01431         &pChannelMap);
01432     if (rv == -1)
01433         /* the handle is now invalid
01434          * -> another thread may have called SCardReleaseContext
01435          * -> so the mMutex has been unlocked */
01436         return SCARD_E_INVALID_HANDLE;
01437 
01438     scCancelStruct.hCard = hCard;
01439 
01440     rv = MessageSendWithHeader(SCARD_CANCEL_TRANSACTION,
01441         currentContextMap->dwClientID,
01442         sizeof(scCancelStruct), (void *) &scCancelStruct);
01443 
01444     if (rv == -1)
01445     {
01446         rv = SCARD_E_NO_SERVICE;
01447         goto end;
01448     }
01449 
01450     /*
01451      * Read a message from the server
01452      */
01453     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
01454         currentContextMap->dwClientID);
01455 
01456     if (rv < 0)
01457     {
01458         rv = SCARD_F_COMM_ERROR;
01459         goto end;
01460     }
01461     rv = scCancelStruct.rv;
01462 
01463 end:
01464     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01465 
01466     PROFILE_END(rv)
01467 
01468     return rv;
01469 }
01470 
01560 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
01561     LPDWORD pcchReaderLen, LPDWORD pdwState,
01562     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01563 {
01564     DWORD dwReaderLen, dwAtrLen;
01565     LONG rv;
01566     int i;
01567     struct status_struct scStatusStruct;
01568     SCONTEXTMAP * currentContextMap;
01569     CHANNEL_MAP * pChannelMap;
01570     char *r;
01571     char *bufReader = NULL;
01572     LPBYTE bufAtr = NULL;
01573     DWORD dummy;
01574 
01575     PROFILE_START
01576 
01577     /* default output values */
01578     if (pdwState)
01579         *pdwState = 0;
01580 
01581     if (pdwProtocol)
01582         *pdwProtocol = 0;
01583 
01584     /* Check for NULL parameters */
01585     if (pcchReaderLen == NULL)
01586         pcchReaderLen = &dummy;
01587 
01588     if (pcbAtrLen == NULL)
01589         pcbAtrLen = &dummy;
01590 
01591     /* length passed from caller */
01592     dwReaderLen = *pcchReaderLen;
01593     dwAtrLen = *pcbAtrLen;
01594 
01595     *pcchReaderLen = 0;
01596     *pcbAtrLen = 0;
01597 
01598     CHECK_SAME_PROCESS
01599 
01600     /*
01601      * Make sure this handle has been opened
01602      */
01603     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01604         &pChannelMap);
01605     if (rv == -1)
01606         return SCARD_E_INVALID_HANDLE;
01607 
01608     (void)pthread_mutex_lock(currentContextMap->mMutex);
01609 
01610     /* check the handle is still valid */
01611     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01612         &pChannelMap);
01613     if (rv == -1)
01614         /* the handle is now invalid
01615          * -> another thread may have called SCardReleaseContext
01616          * -> so the mMutex has been unlocked */
01617         return SCARD_E_INVALID_HANDLE;
01618 
01619     /* synchronize reader states with daemon */
01620     rv = getReaderStates(currentContextMap);
01621     if (rv != SCARD_S_SUCCESS)
01622         goto end;
01623 
01624     r = pChannelMap->readerName;
01625     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01626     {
01627         /* by default r == NULL */
01628         if (r && strcmp(r, readerStates[i].readerName) == 0)
01629             break;
01630     }
01631 
01632     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01633     {
01634         rv = SCARD_E_READER_UNAVAILABLE;
01635         goto end;
01636     }
01637 
01638     /* Retry loop for blocking behaviour */
01639 retry:
01640 
01641     /* initialise the structure */
01642     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01643     scStatusStruct.hCard = hCard;
01644 
01645     /* those sizes need to be initialised */
01646     scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
01647     scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
01648 
01649     rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
01650         sizeof(scStatusStruct),
01651         (void *) &scStatusStruct);
01652 
01653     if (rv == -1)
01654     {
01655         rv = SCARD_E_NO_SERVICE;
01656         goto end;
01657     }
01658 
01659     /*
01660      * Read a message from the server
01661      */
01662     rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
01663         currentContextMap->dwClientID);
01664 
01665     if (rv < 0)
01666     {
01667         rv = SCARD_F_COMM_ERROR;
01668         goto end;
01669     }
01670 
01671     rv = scStatusStruct.rv;
01672 
01673     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01674     {
01675         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01676         goto retry;
01677     }
01678     
01679     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01680     {
01681         /*
01682          * An event must have occurred
01683          */
01684         goto end;
01685     }
01686 
01687     /*
01688      * Now continue with the client side SCardStatus
01689      */
01690 
01691     *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
01692     *pcbAtrLen = readerStates[i].cardAtrLength;
01693 
01694     if (pdwState)
01695         *pdwState = readerStates[i].readerState;
01696 
01697     if (pdwProtocol)
01698         *pdwProtocol = readerStates[i].cardProtocol;
01699 
01700     if (SCARD_AUTOALLOCATE == dwReaderLen)
01701     {
01702         dwReaderLen = *pcchReaderLen;
01703         bufReader = malloc(dwReaderLen);
01704         if (NULL == bufReader)
01705         {
01706             rv = SCARD_E_NO_MEMORY;
01707             goto end;
01708         }
01709         if (NULL == mszReaderName)
01710         {
01711             rv = SCARD_E_INVALID_PARAMETER;
01712             goto end;
01713         }
01714         *(char **)mszReaderName = bufReader;
01715     }
01716     else
01717         bufReader = mszReaderName;
01718 
01719     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01720     if (bufReader)
01721     {
01722         if (*pcchReaderLen > dwReaderLen)
01723             rv = SCARD_E_INSUFFICIENT_BUFFER;
01724 
01725         strncpy(bufReader,
01726             pChannelMap->readerName,
01727             dwReaderLen);
01728     }
01729 
01730     if (SCARD_AUTOALLOCATE == dwAtrLen)
01731     {
01732         dwAtrLen = *pcbAtrLen;
01733         bufAtr = malloc(dwAtrLen);
01734         if (NULL == bufAtr)
01735         {
01736             rv = SCARD_E_NO_MEMORY;
01737             goto end;
01738         }
01739         if (NULL == pbAtr)
01740         {
01741             rv = SCARD_E_INVALID_PARAMETER;
01742             goto end;
01743         }
01744         *(LPBYTE *)pbAtr = bufAtr;
01745     }
01746     else
01747         bufAtr = pbAtr;
01748 
01749     if (bufAtr)
01750     {
01751         if (*pcbAtrLen > dwAtrLen)
01752             rv = SCARD_E_INSUFFICIENT_BUFFER;
01753 
01754         memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
01755     }
01756 
01757 end:
01758     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01759 
01760     PROFILE_END(rv)
01761 
01762     return rv;
01763 }
01764 
01859 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01860     SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
01861 {
01862     SCARD_READERSTATE *currReader;
01863     READER_STATE *rContext;
01864     long dwTime;
01865     DWORD dwState;
01866     DWORD dwBreakFlag = 0;
01867     unsigned int j;
01868     SCONTEXTMAP * currentContextMap;
01869     int currentReaderCount = 0;
01870     LONG rv = SCARD_S_SUCCESS;
01871 
01872     PROFILE_START
01873 
01874     if ((rgReaderStates == NULL && cReaders > 0)
01875         || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
01876         return SCARD_E_INVALID_PARAMETER;
01877 
01878     /* Check the integrity of the reader states structures */
01879     for (j = 0; j < cReaders; j++)
01880     {
01881         if (rgReaderStates[j].szReader == NULL)
01882             return SCARD_E_INVALID_VALUE;
01883     }
01884 
01885     /* return if all readers are SCARD_STATE_IGNORE */
01886     if (cReaders > 0)
01887     {
01888         int nbNonIgnoredReaders = cReaders;
01889 
01890         for (j=0; j<cReaders; j++)
01891             if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
01892                 nbNonIgnoredReaders--;
01893 
01894         if (0 == nbNonIgnoredReaders)
01895             return SCARD_S_SUCCESS;
01896     }
01897     else
01898         /* reader list is empty */
01899         return SCARD_S_SUCCESS;
01900 
01901     CHECK_SAME_PROCESS
01902 
01903     /*
01904      * Make sure this context has been opened
01905      */
01906     currentContextMap = SCardGetContext(hContext);
01907     if (NULL == currentContextMap)
01908         return SCARD_E_INVALID_HANDLE;
01909 
01910     (void)pthread_mutex_lock(currentContextMap->mMutex);
01911 
01912     /* check the context is still opened */
01913     currentContextMap = SCardGetContext(hContext);
01914     if (NULL == currentContextMap)
01915         /* the context is now invalid
01916          * -> another thread may have called SCardReleaseContext
01917          * -> so the mMutex has been unlocked */
01918         return SCARD_E_INVALID_HANDLE;
01919 
01920     /* synchronize reader states with daemon */
01921     rv = getReaderStates(currentContextMap);
01922     if (rv != SCARD_S_SUCCESS)
01923         goto end;
01924 
01925     /* Clear the event state for all readers */
01926     for (j = 0; j < cReaders; j++)
01927         rgReaderStates[j].dwEventState = 0;
01928 
01929     /* Now is where we start our event checking loop */
01930     Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
01931 
01932     /* Get the initial reader count on the system */
01933     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
01934         if (readerStates[j].readerID != 0)
01935             currentReaderCount++;
01936 
01937     if (INFINITE == dwTimeout)
01938         dwTime = 60*1000;   /* "infinite" timeout */
01939     else
01940         dwTime = dwTimeout;
01941 
01942     j = 0;
01943     do
01944     {
01945         currReader = &rgReaderStates[j];
01946 
01947         /* Ignore for IGNORED readers */
01948         if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
01949         {
01950             LPSTR lpcReaderName;
01951             int i;
01952 
01953       /************ Looks for correct readernames *********************/
01954 
01955             lpcReaderName = (char *) currReader->szReader;
01956 
01957             for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01958             {
01959                 if (strcmp(lpcReaderName, readerStates[i].readerName) == 0)
01960                     break;
01961             }
01962 
01963             /* The requested reader name is not recognized */
01964             if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01965             {
01966                 /* PnP special reader? */
01967                 if (strcasecmp(lpcReaderName, "\\\\?PnP?\\Notification") == 0)
01968                 {
01969                     int k, newReaderCount = 0;
01970 
01971                     for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
01972                         if (readerStates[k].readerID != 0)
01973                             newReaderCount++;
01974 
01975                     if (newReaderCount != currentReaderCount)
01976                     {
01977                         Log1(PCSC_LOG_INFO, "Reader list changed");
01978                         currentReaderCount = newReaderCount;
01979 
01980                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01981                         dwBreakFlag = 1;
01982                     }
01983                 }
01984                 else
01985                 {
01986                     currReader->dwEventState = SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE;
01987                     if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
01988                     {
01989                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01990                         /*
01991                          * Spec says use SCARD_STATE_IGNORE but a removed USB
01992                          * reader with eventState fed into currentState will
01993                          * be ignored forever
01994                          */
01995                         dwBreakFlag = 1;
01996                     }
01997                 }
01998             }
01999             else
02000             {
02001                 /* The reader has come back after being away */
02002                 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
02003                 {
02004                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02005                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02006                     Log0(PCSC_LOG_DEBUG);
02007                     dwBreakFlag = 1;
02008                 }
02009 
02010     /*****************************************************************/
02011 
02012                 /* Set the reader status structure */
02013                 rContext = &readerStates[i];
02014 
02015                 /* Now we check all the Reader States */
02016                 dwState = rContext->readerState;
02017 
02018                 /* only if current state has an non null event counter */
02019                 if (currReader->dwCurrentState & 0xFFFF0000)
02020                 {
02021                     int currentCounter, stateCounter;
02022 
02023                     stateCounter = (dwState >> 16) & 0xFFFF;
02024                     currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
02025 
02026                     /* has the event counter changed since the last call? */
02027                     if (stateCounter != currentCounter)
02028                     {
02029                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02030                         Log0(PCSC_LOG_DEBUG);
02031                         dwBreakFlag = 1;
02032                     }
02033 
02034                     /* add an event counter in the upper word of dwEventState */
02035                     currReader->dwEventState =
02036                         ((currReader->dwEventState & 0xffff )
02037                         | (stateCounter << 16));
02038                 }
02039 
02040     /*********** Check if the reader is in the correct state ********/
02041                 if (dwState & SCARD_UNKNOWN)
02042                 {
02043                     /* reader is in bad state */
02044                     currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
02045                     if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
02046                     {
02047                         /* App thinks reader is in good state and it is not */
02048                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02049                         Log0(PCSC_LOG_DEBUG);
02050                         dwBreakFlag = 1;
02051                     }
02052                 }
02053                 else
02054                 {
02055                     /* App thinks reader in bad state but it is not */
02056                     if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
02057                     {
02058                         currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02059                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02060                         Log0(PCSC_LOG_DEBUG);
02061                         dwBreakFlag = 1;
02062                     }
02063                 }
02064 
02065     /********** Check for card presence in the reader **************/
02066 
02067                 if (dwState & SCARD_PRESENT)
02068                 {
02069                     /* card present but not yet powered up */
02070                     if (0 == rContext->cardAtrLength)
02071                         /* Allow the status thread to convey information */
02072                         (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
02073 
02074                     currReader->cbAtr = rContext->cardAtrLength;
02075                     memcpy(currReader->rgbAtr, rContext->cardAtr,
02076                         currReader->cbAtr);
02077                 }
02078                 else
02079                     currReader->cbAtr = 0;
02080 
02081                 /* Card is now absent */
02082                 if (dwState & SCARD_ABSENT)
02083                 {
02084                     currReader->dwEventState |= SCARD_STATE_EMPTY;
02085                     currReader->dwEventState &= ~SCARD_STATE_PRESENT;
02086                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02087                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02088                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02089                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02090                     currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
02091                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02092                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02093 
02094                     /* After present the rest are assumed */
02095                     if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
02096                     {
02097                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02098                         Log0(PCSC_LOG_DEBUG);
02099                         dwBreakFlag = 1;
02100                     }
02101                 }
02102                 /* Card is now present */
02103                 else if (dwState & SCARD_PRESENT)
02104                 {
02105                     currReader->dwEventState |= SCARD_STATE_PRESENT;
02106                     currReader->dwEventState &= ~SCARD_STATE_EMPTY;
02107                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02108                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02109                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02110                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02111                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02112 
02113                     if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
02114                     {
02115                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02116                         Log0(PCSC_LOG_DEBUG);
02117                         dwBreakFlag = 1;
02118                     }
02119 
02120                     if (dwState & SCARD_SWALLOWED)
02121                     {
02122                         currReader->dwEventState |= SCARD_STATE_MUTE;
02123                         if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
02124                         {
02125                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02126                             Log0(PCSC_LOG_DEBUG);
02127                             dwBreakFlag = 1;
02128                         }
02129                     }
02130                     else
02131                     {
02132                         /* App thinks card is mute but it is not */
02133                         if (currReader->dwCurrentState & SCARD_STATE_MUTE)
02134                         {
02135                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02136                             Log0(PCSC_LOG_DEBUG);
02137                             dwBreakFlag = 1;
02138                         }
02139                     }
02140                 }
02141 
02142                 /* Now figure out sharing modes */
02143                 if (rContext->readerSharing == SCARD_EXCLUSIVE_CONTEXT)
02144                 {
02145                     currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
02146                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02147                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02148                     {
02149                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02150                         Log0(PCSC_LOG_DEBUG);
02151                         dwBreakFlag = 1;
02152                     }
02153                 }
02154                 else if (rContext->readerSharing >= SCARD_LAST_CONTEXT)
02155                 {
02156                     /* A card must be inserted for it to be INUSE */
02157                     if (dwState & SCARD_PRESENT)
02158                     {
02159                         currReader->dwEventState |= SCARD_STATE_INUSE;
02160                         currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02161                         if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
02162                         {
02163                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02164                             Log0(PCSC_LOG_DEBUG);
02165                             dwBreakFlag = 1;
02166                         }
02167                     }
02168                 }
02169                 else if (rContext->readerSharing == SCARD_NO_CONTEXT)
02170                 {
02171                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02172                     currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02173 
02174                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02175                     {
02176                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02177                         Log0(PCSC_LOG_DEBUG);
02178                         dwBreakFlag = 1;
02179                     }
02180                     else if (currReader-> dwCurrentState
02181                         & SCARD_STATE_EXCLUSIVE)
02182                     {
02183                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02184                         Log0(PCSC_LOG_DEBUG);
02185                         dwBreakFlag = 1;
02186                     }
02187                 }
02188 
02189                 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
02190                 {
02191                     /*
02192                      * Break out of the while .. loop and return status
02193                      * once all the status's for all readers is met
02194                      */
02195                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02196                     Log0(PCSC_LOG_DEBUG);
02197                     dwBreakFlag = 1;
02198                 }
02199             }   /* End of SCARD_STATE_UNKNOWN */
02200         }   /* End of SCARD_STATE_IGNORE */
02201 
02202         /* Counter and resetter */
02203         j++;
02204         if (j == cReaders)
02205         {
02206             /* go back to the first reader */
02207             j = 0;
02208 
02209             /* Declare all the break conditions */
02210 
02211             /* Break if UNAWARE is set and all readers have been checked */
02212             if (dwBreakFlag == 1)
02213                 break;
02214 
02215             /* Only sleep once for each cycle of reader checks. */
02216             {
02217                 struct wait_reader_state_change waitStatusStruct;
02218                 struct timeval before, after;
02219 
02220                 gettimeofday(&before, NULL);
02221 
02222                 waitStatusStruct.timeOut = dwTime;
02223                 waitStatusStruct.rv = SCARD_S_SUCCESS;
02224 
02225                 rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
02226                     currentContextMap->dwClientID,
02227                     sizeof(waitStatusStruct),
02228                     &waitStatusStruct);
02229 
02230                 if (rv == -1)
02231                 {
02232                     rv = SCARD_E_NO_SERVICE;
02233                     goto end;
02234                 }
02235 
02236                 /*
02237                  * Read a message from the server
02238                  */
02239                 rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
02240                     &waitStatusStruct, sizeof(waitStatusStruct),
02241                     currentContextMap->dwClientID, dwTime);
02242 
02243                 /* timeout */
02244                 if (-2 == rv)
02245                 {
02246                     /* ask server to remove us from the event list */
02247                     rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
02248                         currentContextMap->dwClientID,
02249                         sizeof(waitStatusStruct),
02250                         &waitStatusStruct);
02251 
02252                     if (rv == -1)
02253                     {
02254                         rv = SCARD_E_NO_SERVICE;
02255                         goto end;
02256                     }
02257 
02258                     /* Read a message from the server */
02259                     rv = MessageReceive(&waitStatusStruct,
02260                         sizeof(waitStatusStruct),
02261                         currentContextMap->dwClientID);
02262 
02263                     if (rv == -1)
02264                     {
02265                         rv = SCARD_E_NO_SERVICE;
02266                         goto end;
02267                     }
02268                 }
02269 
02270                 if (rv < 0)
02271                 {
02272                     rv = SCARD_E_NO_SERVICE;
02273                     goto end;
02274                 }
02275 
02276                 /* an event occurs or SCardCancel() was called */
02277                 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
02278                 {
02279                     rv = waitStatusStruct.rv;
02280                     goto end;
02281                 }
02282 
02283                 /* synchronize reader states with daemon */
02284                 rv = getReaderStates(currentContextMap);
02285                 if (rv != SCARD_S_SUCCESS)
02286                     goto end;
02287 
02288                 if (INFINITE != dwTimeout)
02289                 {
02290                     long int diff;
02291 
02292                     gettimeofday(&after, NULL);
02293                     diff = time_sub(&after, &before);
02294                     dwTime -= diff/1000;
02295                 }
02296             }
02297 
02298             if (dwTimeout != INFINITE)
02299             {
02300                 /* If time is greater than timeout and all readers have been
02301                  * checked
02302                  */
02303                 if (dwTime <= 0)
02304                 {
02305                     rv = SCARD_E_TIMEOUT;
02306                     goto end;
02307                 }
02308             }
02309         }
02310     }
02311     while (1);
02312 
02313 end:
02314     Log1(PCSC_LOG_DEBUG, "Event Loop End");
02315 
02316     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02317 
02318     PROFILE_END(rv)
02319 
02320     return rv;
02321 }
02322 
02376 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
02377     DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
02378     LPDWORD lpBytesReturned)
02379 {
02380     LONG rv;
02381     struct control_struct scControlStruct;
02382     SCONTEXTMAP * currentContextMap;
02383     CHANNEL_MAP * pChannelMap;
02384 
02385     PROFILE_START
02386 
02387     /* 0 bytes received by default */
02388     if (NULL != lpBytesReturned)
02389         *lpBytesReturned = 0;
02390 
02391     CHECK_SAME_PROCESS
02392 
02393     /*
02394      * Make sure this handle has been opened
02395      */
02396     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02397         &pChannelMap);
02398     if (rv == -1)
02399     {
02400         PROFILE_END(SCARD_E_INVALID_HANDLE)
02401         return SCARD_E_INVALID_HANDLE;
02402     }
02403 
02404     (void)pthread_mutex_lock(currentContextMap->mMutex);
02405 
02406     /* check the handle is still valid */
02407     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02408         &pChannelMap);
02409     if (rv == -1)
02410         /* the handle is now invalid
02411          * -> another thread may have called SCardReleaseContext
02412          * -> so the mMutex has been unlocked */
02413         return SCARD_E_INVALID_HANDLE;
02414 
02415     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02416         || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02417     {
02418         rv = SCARD_E_INSUFFICIENT_BUFFER;
02419         goto end;
02420     }
02421 
02422     scControlStruct.hCard = hCard;
02423     scControlStruct.dwControlCode = dwControlCode;
02424     scControlStruct.cbSendLength = cbSendLength;
02425     scControlStruct.cbRecvLength = cbRecvLength;
02426 
02427     rv = MessageSendWithHeader(SCARD_CONTROL,
02428         currentContextMap->dwClientID,
02429         sizeof(scControlStruct), &scControlStruct);
02430 
02431     if (rv == -1)
02432     {
02433         rv = SCARD_E_NO_SERVICE;
02434         goto end;
02435     }
02436 
02437     /* write the sent buffer */
02438     rv = MessageSend((char *)pbSendBuffer, cbSendLength,
02439         currentContextMap->dwClientID);
02440 
02441     if (rv == -1)
02442     {
02443         rv = SCARD_E_NO_SERVICE;
02444         goto end;
02445     }
02446 
02447     /*
02448      * Read a message from the server
02449      */
02450     rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
02451         currentContextMap->dwClientID);
02452 
02453     if (rv < 0)
02454     {
02455         rv = SCARD_F_COMM_ERROR;
02456         goto end;
02457     }
02458 
02459     if (SCARD_S_SUCCESS == scControlStruct.rv)
02460     {
02461         /* read the received buffer */
02462         rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
02463             currentContextMap->dwClientID);
02464 
02465         if (rv < 0)
02466         {
02467             rv = SCARD_E_NO_SERVICE;
02468             goto end;
02469         }
02470 
02471     }
02472 
02473     if (NULL != lpBytesReturned)
02474         *lpBytesReturned = scControlStruct.dwBytesReturned;
02475 
02476     rv = scControlStruct.rv;
02477 
02478 end:
02479     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02480 
02481     PROFILE_END(rv)
02482 
02483     return rv;
02484 }
02485 
02590 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
02591     LPDWORD pcbAttrLen)
02592 {
02593     LONG ret;
02594     unsigned char *buf = NULL;
02595 
02596     PROFILE_START
02597 
02598     if (NULL == pcbAttrLen)
02599         return SCARD_E_INVALID_PARAMETER;
02600 
02601     if (SCARD_AUTOALLOCATE == *pcbAttrLen)
02602     {
02603         if (NULL == pbAttr)
02604             return SCARD_E_INVALID_PARAMETER;
02605 
02606         *pcbAttrLen = MAX_BUFFER_SIZE;
02607         buf = malloc(*pcbAttrLen);
02608         if (NULL == buf)
02609             return SCARD_E_NO_MEMORY;
02610 
02611         *(unsigned char **)pbAttr = buf;
02612     }
02613     else
02614     {
02615         buf = pbAttr;
02616 
02617         /* if only get the length */
02618         if (NULL == pbAttr)
02619             /* use a reasonable size */
02620             *pcbAttrLen = MAX_BUFFER_SIZE;
02621     }
02622 
02623     ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
02624         pcbAttrLen);
02625 
02626     PROFILE_END(ret)
02627 
02628     return ret;
02629 }
02630 
02666 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
02667     DWORD cbAttrLen)
02668 {
02669     LONG ret;
02670 
02671     if (NULL == pbAttr || 0 == cbAttrLen)
02672         return SCARD_E_INVALID_PARAMETER;
02673 
02674     ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
02675         &cbAttrLen);
02676 
02677     return ret;
02678 }
02679 
02680 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
02681     LPBYTE pbAttr, LPDWORD pcbAttrLen)
02682 {
02683     LONG rv;
02684     struct getset_struct scGetSetStruct;
02685     SCONTEXTMAP * currentContextMap;
02686     CHANNEL_MAP * pChannelMap;
02687 
02688     CHECK_SAME_PROCESS
02689 
02690     /*
02691      * Make sure this handle has been opened
02692      */
02693     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02694         &pChannelMap);
02695     if (rv == -1)
02696         return SCARD_E_INVALID_HANDLE;
02697 
02698     (void)pthread_mutex_lock(currentContextMap->mMutex);
02699 
02700     /* check the handle is still valid */
02701     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02702         &pChannelMap);
02703     if (rv == -1)
02704         /* the handle is now invalid
02705          * -> another thread may have called SCardReleaseContext
02706          * -> so the mMutex has been unlocked */
02707         return SCARD_E_INVALID_HANDLE;
02708 
02709     if (*pcbAttrLen > MAX_BUFFER_SIZE)
02710     {
02711         rv = SCARD_E_INSUFFICIENT_BUFFER;
02712         goto end;
02713     }
02714 
02715     scGetSetStruct.hCard = hCard;
02716     scGetSetStruct.dwAttrId = dwAttrId;
02717     scGetSetStruct.cbAttrLen = *pcbAttrLen;
02718     scGetSetStruct.rv = SCARD_E_NO_SERVICE;
02719     memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
02720     if (SCARD_SET_ATTRIB == command)
02721         memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
02722 
02723     rv = MessageSendWithHeader(command,
02724         currentContextMap->dwClientID, sizeof(scGetSetStruct),
02725         &scGetSetStruct);
02726 
02727     if (rv == -1)
02728     {
02729         rv = SCARD_E_NO_SERVICE;
02730         goto end;
02731     }
02732 
02733     /*
02734      * Read a message from the server
02735      */
02736     rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
02737         currentContextMap->dwClientID);
02738 
02739     if (rv < 0)
02740     {
02741         rv = SCARD_F_COMM_ERROR;
02742         goto end;
02743     }
02744 
02745     if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
02746     {
02747         /*
02748          * Copy and zero it so any secret information is not leaked
02749          */
02750         if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
02751         {
02752             scGetSetStruct.cbAttrLen = *pcbAttrLen;
02753             scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
02754         }
02755         else
02756             *pcbAttrLen = scGetSetStruct.cbAttrLen;
02757 
02758         if (pbAttr)
02759             memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
02760 
02761         memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
02762     }
02763     rv = scGetSetStruct.rv;
02764 
02765 end:
02766     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02767 
02768     PROFILE_END(rv)
02769 
02770     return rv;
02771 }
02772 
02831 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
02832     LPCBYTE pbSendBuffer, DWORD cbSendLength,
02833     SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
02834     LPDWORD pcbRecvLength)
02835 {
02836     LONG rv;
02837     SCONTEXTMAP * currentContextMap;
02838     CHANNEL_MAP * pChannelMap;
02839     struct transmit_struct scTransmitStruct;
02840 
02841     PROFILE_START
02842 
02843     if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
02844             pcbRecvLength == NULL || pioSendPci == NULL)
02845         return SCARD_E_INVALID_PARAMETER;
02846 
02847     CHECK_SAME_PROCESS
02848 
02849     /*
02850      * Make sure this handle has been opened
02851      */
02852     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02853         &pChannelMap);
02854     if (rv == -1)
02855     {
02856         *pcbRecvLength = 0;
02857         PROFILE_END(SCARD_E_INVALID_HANDLE)
02858         return SCARD_E_INVALID_HANDLE;
02859     }
02860 
02861     (void)pthread_mutex_lock(currentContextMap->mMutex);
02862 
02863     /* check the handle is still valid */
02864     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02865         &pChannelMap);
02866     if (rv == -1)
02867         /* the handle is now invalid
02868          * -> another thread may have called SCardReleaseContext
02869          * -> so the mMutex has been unlocked */
02870         return SCARD_E_INVALID_HANDLE;
02871 
02872     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02873         || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02874     {
02875         rv = SCARD_E_INSUFFICIENT_BUFFER;
02876         goto end;
02877     }
02878 
02879     /* Retry loop for blocking behaviour */
02880 retry:
02881     
02882     scTransmitStruct.hCard = hCard;
02883     scTransmitStruct.cbSendLength = cbSendLength;
02884     scTransmitStruct.pcbRecvLength = *pcbRecvLength;
02885     scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
02886     scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
02887     scTransmitStruct.rv = SCARD_S_SUCCESS;
02888 
02889     if (pioRecvPci)
02890     {
02891         scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
02892         scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
02893     }
02894     else
02895     {
02896         scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
02897         scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
02898     }
02899 
02900     rv = MessageSendWithHeader(SCARD_TRANSMIT,
02901         currentContextMap->dwClientID, sizeof(scTransmitStruct),
02902         (void *) &scTransmitStruct);
02903 
02904     if (rv == -1)
02905     {
02906         rv = SCARD_E_NO_SERVICE;
02907         goto end;
02908     }
02909 
02910     /* write the sent buffer */
02911     rv = MessageSend((void *)pbSendBuffer, cbSendLength,
02912         currentContextMap->dwClientID);
02913 
02914     if (rv == -1)
02915     {
02916         rv = SCARD_E_NO_SERVICE;
02917         goto end;
02918     }
02919 
02920     /*
02921      * Read a message from the server
02922      */
02923     rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
02924         currentContextMap->dwClientID);
02925 
02926     if (rv < 0)
02927     {
02928         rv = SCARD_F_COMM_ERROR;
02929         goto end;
02930     }
02931 
02932     if (SCARD_S_SUCCESS == scTransmitStruct.rv)
02933     {
02934         /* read the received buffer */
02935         rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
02936             currentContextMap->dwClientID);
02937 
02938         if (rv < 0)
02939         {
02940             rv = SCARD_E_NO_SERVICE;
02941             goto end;
02942         }
02943 
02944         if (pioRecvPci)
02945         {
02946             pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
02947             pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
02948         }
02949     }
02950 
02951     rv = scTransmitStruct.rv;
02952 
02953     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
02954     {
02955         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
02956         goto retry;
02957     }
02958 
02959     *pcbRecvLength = scTransmitStruct.pcbRecvLength;
02960 
02961 end:
02962     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02963 
02964     PROFILE_END(rv)
02965 
02966     return rv;
02967 }
02968 
03019 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
03020     LPSTR mszReaders, LPDWORD pcchReaders)
03021 {
03022     DWORD dwReadersLen = 0;
03023     int i;
03024     SCONTEXTMAP * currentContextMap;
03025     LONG rv = SCARD_S_SUCCESS;
03026     char *buf = NULL;
03027 
03028     (void)mszGroups;
03029     PROFILE_START
03030 
03031     /*
03032      * Check for NULL parameters
03033      */
03034     if (pcchReaders == NULL)
03035         return SCARD_E_INVALID_PARAMETER;
03036 
03037     CHECK_SAME_PROCESS
03038 
03039     /*
03040      * Make sure this context has been opened
03041      */
03042     currentContextMap = SCardGetContext(hContext);
03043     if (NULL == currentContextMap)
03044     {
03045         PROFILE_END(SCARD_E_INVALID_HANDLE)
03046         return SCARD_E_INVALID_HANDLE;
03047     }
03048 
03049     (void)pthread_mutex_lock(currentContextMap->mMutex);
03050 
03051     /* check the context is still opened */
03052     currentContextMap = SCardGetContext(hContext);
03053     if (NULL == currentContextMap)
03054         /* the context is now invalid
03055          * -> another thread may have called SCardReleaseContext
03056          * -> so the mMutex has been unlocked */
03057         return SCARD_E_INVALID_HANDLE;
03058 
03059     /* synchronize reader states with daemon */
03060     rv = getReaderStates(currentContextMap);
03061     if (rv != SCARD_S_SUCCESS)
03062         goto end;
03063 
03064     dwReadersLen = 0;
03065     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03066         if (readerStates[i].readerID != 0)
03067             dwReadersLen += strlen(readerStates[i].readerName) + 1;
03068 
03069     /* for the last NULL byte */
03070     dwReadersLen += 1;
03071 
03072     if (1 == dwReadersLen)
03073     {
03074         rv = SCARD_E_NO_READERS_AVAILABLE;
03075         goto end;
03076     }
03077 
03078     if (SCARD_AUTOALLOCATE == *pcchReaders)
03079     {
03080         buf = malloc(dwReadersLen);
03081         if (NULL == buf)
03082         {
03083             rv = SCARD_E_NO_MEMORY;
03084             goto end;
03085         }
03086         if (NULL == mszReaders)
03087         {
03088             rv = SCARD_E_INVALID_PARAMETER;
03089             goto end;
03090         }
03091         *(char **)mszReaders = buf;
03092     }
03093     else
03094     {
03095         buf = mszReaders;
03096 
03097         /* not enough place to store the reader names */
03098         if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
03099         {
03100             rv = SCARD_E_INSUFFICIENT_BUFFER;
03101             goto end;
03102         }
03103     }
03104 
03105     if (mszReaders == NULL) /* text array not allocated */
03106         goto end;
03107 
03108     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03109     {
03110         if (readerStates[i].readerID != 0)
03111         {
03112             /*
03113              * Build the multi-string
03114              */
03115             strcpy(buf, readerStates[i].readerName);
03116             buf += strlen(readerStates[i].readerName)+1;
03117         }
03118     }
03119     *buf = '\0';    /* Add the last null */
03120 
03121 end:
03122     /* set the reader names length */
03123     *pcchReaders = dwReadersLen;
03124 
03125     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03126 
03127     PROFILE_END(rv)
03128 
03129     return rv;
03130 }
03131 
03145 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
03146 {
03147     LONG rv = SCARD_S_SUCCESS;
03148     SCONTEXTMAP * currentContextMap;
03149 
03150     PROFILE_START
03151 
03152     CHECK_SAME_PROCESS
03153 
03154     /*
03155      * Make sure this context has been opened
03156      */
03157     currentContextMap = SCardGetContext(hContext);
03158     if (NULL == currentContextMap)
03159         return SCARD_E_INVALID_HANDLE;
03160 
03161     free((void *)pvMem);
03162 
03163     PROFILE_END(rv)
03164 
03165     return rv;
03166 }
03167 
03219 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
03220     LPDWORD pcchGroups)
03221 {
03222     LONG rv = SCARD_S_SUCCESS;
03223     SCONTEXTMAP * currentContextMap;
03224     char *buf = NULL;
03225 
03226     PROFILE_START
03227 
03228     /* Multi-string with two trailing \0 */
03229     const char ReaderGroup[] = "SCard$DefaultReaders\0";
03230     const unsigned int dwGroups = sizeof(ReaderGroup);
03231 
03232     CHECK_SAME_PROCESS
03233 
03234     /*
03235      * Make sure this context has been opened
03236      */
03237     currentContextMap = SCardGetContext(hContext);
03238     if (NULL == currentContextMap)
03239         return SCARD_E_INVALID_HANDLE;
03240 
03241     (void)pthread_mutex_lock(currentContextMap->mMutex);
03242 
03243     /* check the context is still opened */
03244     currentContextMap = SCardGetContext(hContext);
03245     if (NULL == currentContextMap)
03246         /* the context is now invalid
03247          * -> another thread may have called SCardReleaseContext
03248          * -> so the mMutex has been unlocked */
03249         return SCARD_E_INVALID_HANDLE;
03250 
03251     if (SCARD_AUTOALLOCATE == *pcchGroups)
03252     {
03253         buf = malloc(dwGroups);
03254         if (NULL == buf)
03255         {
03256             rv = SCARD_E_NO_MEMORY;
03257             goto end;
03258         }
03259         if (NULL == mszGroups)
03260         {
03261             rv = SCARD_E_INVALID_PARAMETER;
03262             goto end;
03263         }
03264         *(char **)mszGroups = buf;
03265     }
03266     else
03267     {
03268         buf = mszGroups;
03269 
03270         if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
03271         {
03272             rv = SCARD_E_INSUFFICIENT_BUFFER;
03273             goto end;
03274         }
03275     }
03276 
03277     if (buf)
03278         memcpy(buf, ReaderGroup, dwGroups);
03279 
03280 end:
03281     *pcchGroups = dwGroups;
03282 
03283     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03284 
03285     PROFILE_END(rv)
03286 
03287     return rv;
03288 }
03289 
03319 LONG SCardCancel(SCARDCONTEXT hContext)
03320 {
03321     SCONTEXTMAP * currentContextMap;
03322     LONG rv = SCARD_S_SUCCESS;
03323     uint32_t dwClientID = 0;
03324     struct cancel_struct scCancelStruct;
03325 
03326     PROFILE_START
03327 
03328     /*
03329      * Make sure this context has been opened
03330      */
03331     currentContextMap = SCardGetContext(hContext);
03332     if (NULL == currentContextMap)
03333         return SCARD_E_INVALID_HANDLE;
03334 
03335     /* create a new connection to the server */
03336     if (ClientSetupSession(&dwClientID) != 0)
03337     {
03338         rv = SCARD_E_NO_SERVICE;
03339         goto error;
03340     }
03341 
03342     scCancelStruct.hContext = hContext;
03343     scCancelStruct.rv = SCARD_S_SUCCESS;
03344 
03345     rv = MessageSendWithHeader(SCARD_CANCEL,
03346         dwClientID,
03347         sizeof(scCancelStruct), (void *) &scCancelStruct);
03348 
03349     if (rv == -1)
03350     {
03351         rv = SCARD_E_NO_SERVICE;
03352         goto end;
03353     }
03354 
03355     /*
03356      * Read a message from the server
03357      */
03358     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
03359         dwClientID);
03360 
03361     if (rv < 0)
03362     {
03363         rv = SCARD_F_COMM_ERROR;
03364         goto end;
03365     }
03366 
03367     rv = scCancelStruct.rv;
03368 end:
03369     ClientCloseSession(dwClientID);
03370 
03371 error:
03372     PROFILE_END(rv)
03373 
03374     return rv;
03375 }
03376 
03400 LONG SCardIsValidContext(SCARDCONTEXT hContext)
03401 {
03402     LONG rv;
03403     SCONTEXTMAP * currentContextMap;
03404 
03405     PROFILE_START
03406 
03407     rv = SCARD_S_SUCCESS;
03408 
03409     /* Check if the _same_ server is running */
03410     CHECK_SAME_PROCESS
03411 
03412     /*
03413      * Make sure this context has been opened
03414      */
03415     currentContextMap = SCardGetContext(hContext);
03416     if (currentContextMap == NULL)
03417         rv = SCARD_E_INVALID_HANDLE;
03418 
03419     PROFILE_END(rv)
03420 
03421     return rv;
03422 }
03423 
03440 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
03441 {
03442     int lrv;
03443     SCONTEXTMAP * newContextMap;
03444 
03445     newContextMap = malloc(sizeof(SCONTEXTMAP));
03446     if (NULL == newContextMap)
03447         return SCARD_E_NO_MEMORY;
03448 
03449     Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%X", newContextMap);
03450     newContextMap->hContext = hContext;
03451     newContextMap->dwClientID = dwClientID;
03452 
03453     newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
03454     if (NULL == newContextMap->mMutex)
03455     {
03456         Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%X", newContextMap);
03457         free(newContextMap);
03458         return SCARD_E_NO_MEMORY;
03459     }
03460     (void)pthread_mutex_init(newContextMap->mMutex, NULL);
03461 
03462     lrv = list_init(&(newContextMap->channelMapList));
03463     if (lrv < 0)
03464     {
03465         Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
03466         goto error;
03467     }
03468 
03469     lrv = list_attributes_seeker(&(newContextMap->channelMapList),
03470         CHANNEL_MAP_seeker);
03471     if (lrv <0)
03472     {
03473         Log2(PCSC_LOG_CRITICAL,
03474             "list_attributes_seeker failed with return value: %X", lrv);
03475         list_destroy(&(newContextMap->channelMapList));
03476         goto error;
03477     }
03478 
03479     lrv = list_append(&contextMapList, newContextMap);
03480     if (lrv < 0)
03481     {
03482         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X",
03483             lrv);
03484         list_destroy(&(newContextMap->channelMapList));
03485         goto error;
03486     }
03487 
03488     return SCARD_S_SUCCESS;
03489 
03490 error:
03491 
03492     (void)pthread_mutex_destroy(newContextMap->mMutex);
03493     free(newContextMap->mMutex);
03494     free(newContextMap);
03495 
03496     return SCARD_E_NO_MEMORY;
03497 }
03498 
03511 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT hContext)
03512 {
03513     SCONTEXTMAP * currentContextMap;
03514 
03515     (void)SCardLockThread();
03516     currentContextMap = SCardGetContextTH(hContext);
03517     (void)SCardUnlockThread();
03518 
03519     return currentContextMap;
03520 }
03521 
03534 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext)
03535 {
03536     return list_seek(&contextMapList, &hContext);
03537 }
03538 
03548 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
03549 {
03550     SCONTEXTMAP * currentContextMap;
03551     currentContextMap = SCardGetContextTH(hContext);
03552 
03553     if (NULL == currentContextMap)
03554         return SCARD_E_INVALID_HANDLE;
03555     else
03556         return SCardCleanContext(currentContextMap);
03557 }
03558 
03559 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
03560 {
03561     int list_index, lrv;
03562     int listSize;
03563     CHANNEL_MAP * currentChannelMap;
03564 
03565     targetContextMap->hContext = 0;
03566     (void)ClientCloseSession(targetContextMap->dwClientID);
03567     targetContextMap->dwClientID = 0;
03568     (void)pthread_mutex_destroy(targetContextMap->mMutex);
03569     free(targetContextMap->mMutex);
03570     targetContextMap->mMutex = NULL;
03571 
03572     listSize = list_size(&(targetContextMap->channelMapList));
03573     for (list_index = 0; list_index < listSize; list_index++)
03574     {
03575         currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
03576             list_index);
03577         if (NULL == currentChannelMap)
03578         {
03579             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03580                 list_index);
03581             continue;
03582         }
03583         else
03584         {
03585             free(currentChannelMap->readerName);
03586             free(currentChannelMap);
03587         }
03588 
03589     }
03590     list_destroy(&(targetContextMap->channelMapList));
03591 
03592     lrv = list_delete(&contextMapList, targetContextMap);
03593     if (lrv < 0)
03594     {
03595         Log2(PCSC_LOG_CRITICAL,
03596             "list_delete failed with return value: %X", lrv);
03597     }
03598 
03599     free(targetContextMap);
03600 
03601     return SCARD_S_SUCCESS;
03602 }
03603 
03604 /*
03605  * Functions for managing hCard values returned from SCardConnect.
03606  */
03607 
03608 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
03609     LPCSTR readerName)
03610 {
03611     CHANNEL_MAP * newChannelMap;
03612     int lrv = -1;
03613 
03614     newChannelMap = malloc(sizeof(CHANNEL_MAP));
03615     if (NULL == newChannelMap)
03616         return SCARD_E_NO_MEMORY;
03617 
03618     newChannelMap->hCard = hCard;
03619     newChannelMap->readerName = strdup(readerName);
03620 
03621     lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
03622     if (lrv < 0)
03623     {
03624         free(newChannelMap->readerName);
03625         free(newChannelMap);
03626         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X", lrv);
03627         return SCARD_E_NO_MEMORY;
03628     }
03629 
03630     return SCARD_S_SUCCESS;
03631 }
03632 
03633 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
03634 {
03635     SCONTEXTMAP * currentContextMap;
03636     CHANNEL_MAP * currentChannelMap;
03637     int lrv;
03638     LONG rv;
03639 
03640     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
03641         &currentChannelMap);
03642     if (rv == -1)
03643         return SCARD_E_INVALID_HANDLE;
03644 
03645     free(currentChannelMap->readerName);
03646 
03647     lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
03648     if (lrv < 0)
03649     {
03650         Log2(PCSC_LOG_CRITICAL,
03651             "list_delete failed with return value: %X", lrv);
03652     }
03653 
03654     free(currentChannelMap);
03655 
03656     return SCARD_S_SUCCESS;
03657 }
03658 
03659 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
03660     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03661 {
03662     LONG rv;
03663 
03664     if (0 == hCard)
03665         return -1;
03666 
03667     (void)SCardLockThread();
03668     rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap, targetChannelMap);
03669     (void)SCardUnlockThread();
03670 
03671     return rv;
03672 }
03673 
03674 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
03675     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03676 {
03677     int listSize;
03678     int list_index;
03679     SCONTEXTMAP * currentContextMap;
03680     CHANNEL_MAP * currentChannelMap;
03681 
03682     /* Best to get the caller a crash early if we fail unsafely */
03683     *targetContextMap = NULL;
03684     *targetChannelMap = NULL;
03685 
03686     listSize = list_size(&contextMapList);
03687 
03688     for (list_index = 0; list_index < listSize; list_index++)
03689     {
03690         currentContextMap = list_get_at(&contextMapList, list_index);
03691         if (currentContextMap == NULL)
03692         {
03693             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d", list_index);
03694             continue;
03695         }
03696         currentChannelMap = list_seek(&(currentContextMap->channelMapList),
03697             &hCard);
03698         if (currentChannelMap != NULL)
03699         {
03700             *targetContextMap = currentContextMap;
03701             *targetChannelMap = currentChannelMap;
03702             return SCARD_S_SUCCESS;
03703         }
03704     }
03705 
03706     return -1;
03707 }
03708 
03709 static LONG SCardInvalidateHandles(void)
03710 {
03711     /* invalid all handles */
03712     (void)SCardLockThread();
03713 
03714     while (list_size(&contextMapList) != 0)
03715     {
03716         SCONTEXTMAP * currentContextMap;
03717 
03718         currentContextMap = list_get_at(&contextMapList, 0);
03719         if (currentContextMap != NULL)
03720             (void)SCardCleanContext(currentContextMap);
03721         else
03722             Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
03723     }
03724 
03725     (void)SCardUnlockThread();
03726 
03727     /* reset pcscd status */
03728     daemon_ctime = 0;
03729     client_pid = 0;
03730 
03731     return SCARD_E_INVALID_HANDLE;
03732 }
03733 
03746 LONG SCardCheckDaemonAvailability(void)
03747 {
03748     LONG rv;
03749     struct stat statBuffer;
03750     int need_restart = 0;
03751 
03752     rv = stat(PCSCLITE_CSOCK_NAME, &statBuffer);
03753 
03754     if (rv != 0)
03755     {
03756         Log2(PCSC_LOG_INFO, "PCSC Not Running: " PCSCLITE_CSOCK_NAME ": %s",
03757             strerror(errno));
03758         return SCARD_E_NO_SERVICE;
03759     }
03760 
03761     /* when the _first_ reader is connected the ctime changes
03762      * I don't know why yet */
03763     if (daemon_ctime && statBuffer.st_ctime > daemon_ctime)
03764     {
03765         /* so we also check the daemon pid to be sure it is a new pcscd */
03766         if (GetDaemonPid() != daemon_pid)
03767         {
03768             Log1(PCSC_LOG_INFO, "PCSC restarted");
03769             need_restart = 1;
03770         }
03771     }
03772 
03773     /* after fork() need to restart */
03774     if (client_pid && client_pid != getpid())
03775     {
03776         Log1(PCSC_LOG_INFO, "Client forked");
03777         need_restart = 1;
03778     }
03779 
03780     if (need_restart)
03781         return SCardInvalidateHandles();
03782 
03783     daemon_ctime = statBuffer.st_ctime;
03784     daemon_pid = GetDaemonPid();
03785     client_pid = getpid();
03786 
03787     return SCARD_S_SUCCESS;
03788 }
03789 
03790 #ifdef DO_CHECK_SAME_PROCESS
03791 static LONG SCardCheckSameProcess(void)
03792 {
03793     /* after fork() need to restart */
03794     if ((client_pid && client_pid != getpid()))
03795     {
03796         Log1(PCSC_LOG_INFO, "Client forked");
03797         return SCardInvalidateHandles();
03798     }
03799 
03800     client_pid = getpid();
03801 
03802     return SCARD_S_SUCCESS;
03803 }
03804 #endif
03805 
03806 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
03807 {
03808     int32_t dwClientID = currentContextMap->dwClientID;
03809 
03810     if (-1 == MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL))
03811         return SCARD_E_NO_SERVICE;
03812 
03813     /* Read a message from the server */
03814     if (MessageReceive(&readerStates, sizeof(readerStates), dwClientID) < 0)
03815         return SCARD_F_COMM_ERROR;
03816 
03817     return SCARD_S_SUCCESS;
03818 }
03819