pcsc-lite 1.6.4
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 
00391     PROFILE_START
00392 
00393     /* Check if the server is running */
00394     rv = SCardCheckDaemonAvailability();
00395     if (SCARD_E_INVALID_HANDLE == rv)
00396         /* we reconnected to a daemon or we got called from a forked child */
00397         rv = SCardCheckDaemonAvailability();
00398 
00399     if (rv != SCARD_S_SUCCESS)
00400         goto end;
00401 
00402     (void)SCardLockThread();
00403     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00404         pvReserved2, phContext);
00405     (void)SCardUnlockThread();
00406 
00407 end:
00408     PROFILE_END(rv)
00409 
00410     return rv;
00411 }
00412 
00439 static LONG SCardEstablishContextTH(DWORD dwScope,
00440     /*@unused@*/ LPCVOID pvReserved1,
00441     /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00442 {
00443     LONG rv;
00444     struct establish_struct scEstablishStruct;
00445     uint32_t dwClientID = 0;
00446 
00447     (void)pvReserved1;
00448     (void)pvReserved2;
00449     if (phContext == NULL)
00450         return SCARD_E_INVALID_PARAMETER;
00451     else
00452         *phContext = 0;
00453 
00454     /*
00455      * Do this only once:
00456      * - Initialize context list.
00457      */
00458     if (isExecuted == 0)
00459     {
00460         int lrv;
00461 
00462         /* NOTE: The list will never be freed (No API call exists to
00463          * "close all contexts".
00464          * Applications which load and unload the library will leak
00465          * the list's internal structures. */
00466         lrv = list_init(&contextMapList);
00467         if (lrv < 0)
00468         {
00469             Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
00470             return SCARD_E_NO_MEMORY;
00471         }
00472 
00473         lrv = list_attributes_seeker(&contextMapList,
00474                 SCONTEXTMAP_seeker);
00475         if (lrv <0)
00476         {
00477             Log2(PCSC_LOG_CRITICAL,
00478                 "list_attributes_seeker failed with return value: %X", lrv);
00479             list_destroy(&contextMapList);
00480             return SCARD_E_NO_MEMORY;
00481         }
00482 
00483         if (getenv("PCSCLITE_NO_BLOCKING"))
00484         {
00485             Log1(PCSC_LOG_INFO, "Disable shared blocking");
00486             sharing_shall_block = FALSE;
00487         }
00488         
00489         isExecuted = 1;
00490     }
00491 
00492 
00493     /* Establishes a connection to the server */
00494     if (ClientSetupSession(&dwClientID) != 0)
00495     {
00496         return SCARD_E_NO_SERVICE;
00497     }
00498 
00499     {   /* exchange client/server protocol versions */
00500         struct version_struct veStr;
00501 
00502         veStr.major = PROTOCOL_VERSION_MAJOR;
00503         veStr.minor = PROTOCOL_VERSION_MINOR;
00504         veStr.rv = SCARD_S_SUCCESS;
00505 
00506         if (-1 == MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
00507             &veStr))
00508             return SCARD_E_NO_SERVICE;
00509 
00510         /* Read a message from the server */
00511         if (MessageReceive(&veStr, sizeof(veStr), dwClientID) < 0)
00512         {
00513             Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION");
00514             return SCARD_F_COMM_ERROR;
00515         }
00516 
00517         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00518             veStr.major, veStr.minor);
00519 
00520         if (veStr.rv != SCARD_S_SUCCESS)
00521             return veStr.rv;
00522     }
00523 
00524 again:
00525     /*
00526      * Try to establish an Application Context with the server
00527      */
00528     scEstablishStruct.dwScope = dwScope;
00529     scEstablishStruct.hContext = 0;
00530     scEstablishStruct.rv = SCARD_S_SUCCESS;
00531 
00532     rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
00533         sizeof(scEstablishStruct), (void *) &scEstablishStruct);
00534 
00535     if (rv == -1)
00536         return SCARD_E_NO_SERVICE;
00537 
00538     /*
00539      * Read the response from the server
00540      */
00541     rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct), dwClientID);
00542 
00543     if (rv < 0)
00544         return SCARD_F_COMM_ERROR;
00545 
00546     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00547         return scEstablishStruct.rv;
00548 
00549     /* check we do not reuse an existing hContext */
00550     if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
00551         /* we do not need to release the allocated context since
00552          * SCardReleaseContext() does nothing on the server side */
00553         goto again;
00554 
00555     *phContext = scEstablishStruct.hContext;
00556 
00557     /*
00558      * Allocate the new hContext - if allocator full return an error
00559      */
00560     rv = SCardAddContext(*phContext, dwClientID);
00561 
00562     return rv;
00563 }
00564 
00586 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00587 {
00588     LONG rv;
00589     struct release_struct scReleaseStruct;
00590     SCONTEXTMAP * currentContextMap;
00591 
00592     PROFILE_START
00593 
00594     CHECK_SAME_PROCESS
00595 
00596     /*
00597      * Make sure this context has been opened
00598      * and get currentContextMap
00599      */
00600     currentContextMap = SCardGetContext(hContext);
00601     if (NULL == currentContextMap)
00602     {
00603         PROFILE_END(SCARD_E_INVALID_HANDLE)
00604         return SCARD_E_INVALID_HANDLE;
00605     }
00606 
00607     (void)pthread_mutex_lock(currentContextMap->mMutex);
00608 
00609     /* check the context is still opened */
00610     currentContextMap = SCardGetContext(hContext);
00611     if (NULL == currentContextMap)
00612         /* the context is now invalid
00613          * -> another thread may have called SCardReleaseContext
00614          * -> so the mMutex has been unlocked */
00615         return SCARD_E_INVALID_HANDLE;
00616 
00617     scReleaseStruct.hContext = hContext;
00618     scReleaseStruct.rv = SCARD_S_SUCCESS;
00619 
00620     rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
00621         currentContextMap->dwClientID,
00622         sizeof(scReleaseStruct),
00623         (void *) &scReleaseStruct);
00624 
00625     if (rv == -1)
00626     {
00627         rv = SCARD_E_NO_SERVICE;
00628         goto end;
00629     }
00630 
00631     /*
00632      * Read a message from the server
00633      */
00634     rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
00635         currentContextMap->dwClientID);
00636 
00637     if (rv < 0)
00638     {
00639         rv = SCARD_F_COMM_ERROR;
00640         goto end;
00641     }
00642 
00643     rv = scReleaseStruct.rv;
00644 end:
00645     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00646 
00647     /*
00648      * Remove the local context from the stack
00649      */
00650     (void)SCardLockThread();
00651     (void)SCardRemoveContext(hContext);
00652     (void)SCardUnlockThread();
00653 
00654     PROFILE_END(rv)
00655 
00656     return rv;
00657 }
00658 
00674 LONG SCardSetTimeout(/*@unused@*/ SCARDCONTEXT hContext,
00675     /*@unused@*/ DWORD dwTimeout)
00676 {
00677     /*
00678      * Deprecated
00679      */
00680     (void)hContext;
00681     (void)dwTimeout;
00682     return SCARD_S_SUCCESS;
00683 }
00684 
00742 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00743     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00744     LPDWORD pdwActiveProtocol)
00745 {
00746     LONG rv;
00747     struct connect_struct scConnectStruct;
00748     SCONTEXTMAP * currentContextMap;
00749 
00750     PROFILE_START
00751 
00752     /*
00753      * Check for NULL parameters
00754      */
00755     if (phCard == NULL || pdwActiveProtocol == NULL)
00756         return SCARD_E_INVALID_PARAMETER;
00757     else
00758         *phCard = 0;
00759 
00760     if (szReader == NULL)
00761         return SCARD_E_UNKNOWN_READER;
00762 
00763     /*
00764      * Check for uninitialized strings
00765      */
00766     if (strlen(szReader) > MAX_READERNAME)
00767         return SCARD_E_INVALID_VALUE;
00768 
00769     CHECK_SAME_PROCESS
00770 
00771     /*
00772      * Make sure this context has been opened
00773      */
00774     currentContextMap = SCardGetContext(hContext);
00775     if (NULL == currentContextMap)
00776         return SCARD_E_INVALID_HANDLE;
00777 
00778     (void)pthread_mutex_lock(currentContextMap->mMutex);
00779 
00780     /* check the context is still opened */
00781     currentContextMap = SCardGetContext(hContext);
00782     if (NULL == currentContextMap)
00783         /* the context is now invalid
00784          * -> another thread may have called SCardReleaseContext
00785          * -> so the mMutex has been unlocked */
00786         return SCARD_E_INVALID_HANDLE;
00787 
00788     strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
00789 
00790     scConnectStruct.hContext = hContext;
00791     scConnectStruct.dwShareMode = dwShareMode;
00792     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00793     scConnectStruct.hCard = 0;
00794     scConnectStruct.dwActiveProtocol = 0;
00795     scConnectStruct.rv = SCARD_S_SUCCESS;
00796 
00797     rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
00798         sizeof(scConnectStruct),
00799         (void *) &scConnectStruct);
00800 
00801     if (rv == -1)
00802     {
00803         rv = SCARD_E_NO_SERVICE;
00804         goto end;
00805     }
00806 
00807     /*
00808      * Read a message from the server
00809      */
00810     rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
00811         currentContextMap->dwClientID);
00812 
00813     if (rv < 0)
00814     {
00815         rv = SCARD_F_COMM_ERROR;
00816         goto end;
00817     }
00818 
00819     *phCard = scConnectStruct.hCard;
00820     *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
00821 
00822     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00823     {
00824         /*
00825          * Keep track of the handle locally
00826          */
00827         rv = SCardAddHandle(*phCard, currentContextMap, szReader);
00828     }
00829     else
00830         rv = scConnectStruct.rv;
00831 
00832 end:
00833     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00834 
00835     PROFILE_END(rv)
00836 
00837     return rv;
00838 }
00839 
00913 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
00914     DWORD dwPreferredProtocols, DWORD dwInitialization,
00915     LPDWORD pdwActiveProtocol)
00916 {
00917     LONG rv;
00918     struct reconnect_struct scReconnectStruct;
00919     SCONTEXTMAP * currentContextMap;
00920     CHANNEL_MAP * pChannelMap;
00921 
00922     PROFILE_START
00923 
00924     if (pdwActiveProtocol == NULL)
00925         return SCARD_E_INVALID_PARAMETER;
00926 
00927     CHECK_SAME_PROCESS
00928 
00929     /*
00930      * Make sure this handle has been opened
00931      */
00932     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
00933         &pChannelMap);
00934     if (rv == -1)
00935         return SCARD_E_INVALID_HANDLE;
00936 
00937     (void)pthread_mutex_lock(currentContextMap->mMutex);
00938 
00939     /* check the handle is still valid */
00940     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
00941         &pChannelMap);
00942     if (rv == -1)
00943         /* the handle is now invalid
00944          * -> another thread may have called SCardReleaseContext
00945          * -> so the mMutex has been unlocked */
00946         return SCARD_E_INVALID_HANDLE;
00947 
00948     /* Retry loop for blocking behaviour */
00949 retry:
00950     
00951     scReconnectStruct.hCard = hCard;
00952     scReconnectStruct.dwShareMode = dwShareMode;
00953     scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00954     scReconnectStruct.dwInitialization = dwInitialization;
00955     scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
00956     scReconnectStruct.rv = SCARD_S_SUCCESS;
00957 
00958     rv = MessageSendWithHeader(SCARD_RECONNECT,
00959         currentContextMap->dwClientID,
00960         sizeof(scReconnectStruct),
00961         (void *) &scReconnectStruct);
00962 
00963     if (rv == -1)
00964     {
00965         rv = SCARD_E_NO_SERVICE;
00966         goto end;
00967     }
00968 
00969     /*
00970      * Read a message from the server
00971      */
00972     rv = MessageReceive(&scReconnectStruct,
00973         sizeof(scReconnectStruct),
00974         currentContextMap->dwClientID);
00975 
00976     if (rv < 0)
00977     {
00978         rv = SCARD_F_COMM_ERROR;
00979         goto end;
00980     }
00981 
00982     rv = scReconnectStruct.rv;
00983 
00984     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
00985     {
00986         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
00987         goto retry;
00988     }
00989     
00990     *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
00991 
00992 end:
00993     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00994 
00995     PROFILE_END(rv)
00996 
00997     return rv;
00998 }
00999 
01031 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01032 {
01033     LONG rv;
01034     struct disconnect_struct scDisconnectStruct;
01035     SCONTEXTMAP * currentContextMap;
01036     CHANNEL_MAP * pChannelMap;
01037 
01038     PROFILE_START
01039 
01040     CHECK_SAME_PROCESS
01041 
01042     /*
01043      * Make sure this handle has been opened
01044      */
01045     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01046         &pChannelMap);
01047     if (rv == -1)
01048         return SCARD_E_INVALID_HANDLE;
01049 
01050     (void)pthread_mutex_lock(currentContextMap->mMutex);
01051 
01052     /* check the handle is still valid */
01053     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01054         &pChannelMap);
01055     if (rv == -1)
01056         /* the handle is now invalid
01057          * -> another thread may have called SCardReleaseContext
01058          * -> so the mMutex has been unlocked */
01059         return SCARD_E_INVALID_HANDLE;
01060 
01061     scDisconnectStruct.hCard = hCard;
01062     scDisconnectStruct.dwDisposition = dwDisposition;
01063     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01064 
01065     rv = MessageSendWithHeader(SCARD_DISCONNECT,
01066         currentContextMap->dwClientID,
01067         sizeof(scDisconnectStruct),
01068         (void *) &scDisconnectStruct);
01069 
01070     if (rv == -1)
01071     {
01072         rv = SCARD_E_NO_SERVICE;
01073         goto end;
01074     }
01075 
01076     /*
01077      * Read a message from the server
01078      */
01079     rv = MessageReceive(&scDisconnectStruct,
01080         sizeof(scDisconnectStruct),
01081         currentContextMap->dwClientID);
01082 
01083     if (rv < 0)
01084     {
01085         rv = SCARD_F_COMM_ERROR;
01086         goto end;
01087     }
01088 
01089     (void)SCardRemoveHandle(hCard);
01090     rv = scDisconnectStruct.rv;
01091 
01092 end:
01093     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01094 
01095     PROFILE_END(rv)
01096 
01097     return rv;
01098 }
01099 
01135 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01136 {
01137 
01138     LONG rv;
01139     struct begin_struct scBeginStruct;
01140     SCONTEXTMAP * currentContextMap;
01141     CHANNEL_MAP * pChannelMap;
01142 
01143     PROFILE_START
01144 
01145     CHECK_SAME_PROCESS
01146 
01147     /*
01148      * Make sure this handle has been opened
01149      */
01150     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01151         &pChannelMap);
01152     if (rv == -1)
01153         return SCARD_E_INVALID_HANDLE;
01154 
01155     (void)pthread_mutex_lock(currentContextMap->mMutex);
01156 
01157     /* check the handle is still valid */
01158     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01159         &pChannelMap);
01160     if (rv == -1)
01161         /* the handle is now invalid
01162          * -> another thread may have called SCardReleaseContext
01163          * -> so the mMutex has been unlocked */
01164         return SCARD_E_INVALID_HANDLE;
01165 
01166     scBeginStruct.hCard = hCard;
01167     scBeginStruct.rv = SCARD_S_SUCCESS;
01168 
01169     /*
01170      * Query the server every so often until the sharing violation ends
01171      * and then hold the lock for yourself.
01172      */
01173 
01174     do
01175     {
01176         rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
01177             currentContextMap->dwClientID,
01178             sizeof(scBeginStruct),
01179             (void *) &scBeginStruct);
01180 
01181         if (rv == -1)
01182         {
01183             rv = SCARD_E_NO_SERVICE;
01184             goto end;
01185         }
01186 
01187         /*
01188          * Read a message from the server
01189          */
01190         rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
01191             currentContextMap->dwClientID);
01192 
01193         if (rv < 0)
01194         {
01195             rv = SCARD_F_COMM_ERROR;
01196             goto end;
01197         }
01198 
01199         rv = scBeginStruct.rv;
01200     }
01201     while (SCARD_E_SHARING_VIOLATION == rv);
01202 
01203 end:
01204     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01205 
01206     PROFILE_END(rv)
01207 
01208     return rv;
01209 }
01210 
01251 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01252 {
01253     LONG rv;
01254     struct end_struct scEndStruct;
01255     int randnum;
01256     SCONTEXTMAP * currentContextMap;
01257     CHANNEL_MAP * pChannelMap;
01258 
01259     PROFILE_START
01260 
01261     /*
01262      * Zero out everything
01263      */
01264     randnum = 0;
01265 
01266     CHECK_SAME_PROCESS
01267 
01268     /*
01269      * Make sure this handle has been opened
01270      */
01271     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01272         &pChannelMap);
01273     if (rv == -1)
01274         return SCARD_E_INVALID_HANDLE;
01275 
01276     (void)pthread_mutex_lock(currentContextMap->mMutex);
01277 
01278     /* check the handle is still valid */
01279     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01280         &pChannelMap);
01281     if (rv == -1)
01282         /* the handle is now invalid
01283          * -> another thread may have called SCardReleaseContext
01284          * -> so the mMutex has been unlocked */
01285         return SCARD_E_INVALID_HANDLE;
01286 
01287     scEndStruct.hCard = hCard;
01288     scEndStruct.dwDisposition = dwDisposition;
01289     scEndStruct.rv = SCARD_S_SUCCESS;
01290 
01291     rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
01292         currentContextMap->dwClientID,
01293         sizeof(scEndStruct),
01294         (void *) &scEndStruct);
01295 
01296     if (rv == -1)
01297     {
01298         rv = SCARD_E_NO_SERVICE;
01299         goto end;
01300     }
01301 
01302     /*
01303      * Read a message from the server
01304      */
01305     rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
01306         currentContextMap->dwClientID);
01307 
01308     if (rv < 0)
01309     {
01310         rv = SCARD_F_COMM_ERROR;
01311         goto end;
01312     }
01313 
01314     /*
01315      * This helps prevent starvation
01316      */
01317     randnum = SYS_RandomInt(1000, 10000);
01318     (void)SYS_USleep(randnum);
01319     rv = scEndStruct.rv;
01320 
01321 end:
01322     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01323 
01324     PROFILE_END(rv)
01325 
01326     return rv;
01327 }
01328 
01335 LONG SCardCancelTransaction(SCARDHANDLE hCard)
01336 {
01337     LONG rv;
01338     struct cancel_transaction_struct scCancelStruct;
01339     SCONTEXTMAP * currentContextMap;
01340     CHANNEL_MAP * pChannelMap;
01341 
01342     PROFILE_START
01343 
01344     CHECK_SAME_PROCESS
01345 
01346     /*
01347      * Make sure this handle has been opened
01348      */
01349     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01350         &pChannelMap);
01351     if (rv == -1)
01352         return SCARD_E_INVALID_HANDLE;
01353 
01354     (void)pthread_mutex_lock(currentContextMap->mMutex);
01355 
01356     /* check the handle is still valid */
01357     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01358         &pChannelMap);
01359     if (rv == -1)
01360         /* the handle is now invalid
01361          * -> another thread may have called SCardReleaseContext
01362          * -> so the mMutex has been unlocked */
01363         return SCARD_E_INVALID_HANDLE;
01364 
01365     scCancelStruct.hCard = hCard;
01366 
01367     rv = MessageSendWithHeader(SCARD_CANCEL_TRANSACTION,
01368         currentContextMap->dwClientID,
01369         sizeof(scCancelStruct), (void *) &scCancelStruct);
01370 
01371     if (rv == -1)
01372     {
01373         rv = SCARD_E_NO_SERVICE;
01374         goto end;
01375     }
01376 
01377     /*
01378      * Read a message from the server
01379      */
01380     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
01381         currentContextMap->dwClientID);
01382 
01383     if (rv < 0)
01384     {
01385         rv = SCARD_F_COMM_ERROR;
01386         goto end;
01387     }
01388     rv = scCancelStruct.rv;
01389 
01390 end:
01391     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01392 
01393     PROFILE_END(rv)
01394 
01395     return rv;
01396 }
01397 
01487 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
01488     LPDWORD pcchReaderLen, LPDWORD pdwState,
01489     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01490 {
01491     DWORD dwReaderLen, dwAtrLen;
01492     LONG rv;
01493     int i;
01494     struct status_struct scStatusStruct;
01495     SCONTEXTMAP * currentContextMap;
01496     CHANNEL_MAP * pChannelMap;
01497     char *r;
01498     char *bufReader = NULL;
01499     LPBYTE bufAtr = NULL;
01500     DWORD dummy;
01501 
01502     PROFILE_START
01503 
01504     /* default output values */
01505     if (pdwState)
01506         *pdwState = 0;
01507 
01508     if (pdwProtocol)
01509         *pdwProtocol = 0;
01510 
01511     /* Check for NULL parameters */
01512     if (pcchReaderLen == NULL)
01513         pcchReaderLen = &dummy;
01514 
01515     if (pcbAtrLen == NULL)
01516         pcbAtrLen = &dummy;
01517 
01518     /* length passed from caller */
01519     dwReaderLen = *pcchReaderLen;
01520     dwAtrLen = *pcbAtrLen;
01521 
01522     *pcchReaderLen = 0;
01523     *pcbAtrLen = 0;
01524 
01525     CHECK_SAME_PROCESS
01526 
01527     /*
01528      * Make sure this handle has been opened
01529      */
01530     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01531         &pChannelMap);
01532     if (rv == -1)
01533         return SCARD_E_INVALID_HANDLE;
01534 
01535     (void)pthread_mutex_lock(currentContextMap->mMutex);
01536 
01537     /* check the handle is still valid */
01538     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01539         &pChannelMap);
01540     if (rv == -1)
01541         /* the handle is now invalid
01542          * -> another thread may have called SCardReleaseContext
01543          * -> so the mMutex has been unlocked */
01544         return SCARD_E_INVALID_HANDLE;
01545 
01546     /* synchronize reader states with daemon */
01547     rv = getReaderStates(currentContextMap);
01548     if (rv != SCARD_S_SUCCESS)
01549         goto end;
01550 
01551     r = pChannelMap->readerName;
01552     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01553     {
01554         /* by default r == NULL */
01555         if (r && strcmp(r, readerStates[i].readerName) == 0)
01556             break;
01557     }
01558 
01559     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01560     {
01561         rv = SCARD_E_READER_UNAVAILABLE;
01562         goto end;
01563     }
01564 
01565     /* Retry loop for blocking behaviour */
01566 retry:
01567 
01568     /* initialise the structure */
01569     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01570     scStatusStruct.hCard = hCard;
01571 
01572     /* those sizes need to be initialised */
01573     scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
01574     scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
01575 
01576     rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
01577         sizeof(scStatusStruct),
01578         (void *) &scStatusStruct);
01579 
01580     if (rv == -1)
01581     {
01582         rv = SCARD_E_NO_SERVICE;
01583         goto end;
01584     }
01585 
01586     /*
01587      * Read a message from the server
01588      */
01589     rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
01590         currentContextMap->dwClientID);
01591 
01592     if (rv < 0)
01593     {
01594         rv = SCARD_F_COMM_ERROR;
01595         goto end;
01596     }
01597 
01598     rv = scStatusStruct.rv;
01599 
01600     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01601     {
01602         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01603         goto retry;
01604     }
01605     
01606     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01607     {
01608         /*
01609          * An event must have occurred
01610          */
01611         goto end;
01612     }
01613 
01614     /*
01615      * Now continue with the client side SCardStatus
01616      */
01617 
01618     *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
01619     *pcbAtrLen = readerStates[i].cardAtrLength;
01620 
01621     if (pdwState)
01622         *pdwState = readerStates[i].readerState;
01623 
01624     if (pdwProtocol)
01625         *pdwProtocol = readerStates[i].cardProtocol;
01626 
01627     if (SCARD_AUTOALLOCATE == dwReaderLen)
01628     {
01629         dwReaderLen = *pcchReaderLen;
01630         bufReader = malloc(dwReaderLen);
01631         if (NULL == bufReader)
01632         {
01633             rv = SCARD_E_NO_MEMORY;
01634             goto end;
01635         }
01636         if (NULL == mszReaderName)
01637         {
01638             rv = SCARD_E_INVALID_PARAMETER;
01639             goto end;
01640         }
01641         *(char **)mszReaderName = bufReader;
01642     }
01643     else
01644         bufReader = mszReaderName;
01645 
01646     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01647     if (bufReader)
01648     {
01649         if (*pcchReaderLen > dwReaderLen)
01650             rv = SCARD_E_INSUFFICIENT_BUFFER;
01651 
01652         strncpy(bufReader,
01653             pChannelMap->readerName,
01654             dwReaderLen);
01655     }
01656 
01657     if (SCARD_AUTOALLOCATE == dwAtrLen)
01658     {
01659         dwAtrLen = *pcbAtrLen;
01660         bufAtr = malloc(dwAtrLen);
01661         if (NULL == bufAtr)
01662         {
01663             rv = SCARD_E_NO_MEMORY;
01664             goto end;
01665         }
01666         if (NULL == pbAtr)
01667         {
01668             rv = SCARD_E_INVALID_PARAMETER;
01669             goto end;
01670         }
01671         *(LPBYTE *)pbAtr = bufAtr;
01672     }
01673     else
01674         bufAtr = pbAtr;
01675 
01676     if (bufAtr)
01677     {
01678         if (*pcbAtrLen > dwAtrLen)
01679             rv = SCARD_E_INSUFFICIENT_BUFFER;
01680 
01681         memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
01682     }
01683 
01684 end:
01685     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01686 
01687     PROFILE_END(rv)
01688 
01689     return rv;
01690 }
01691 
01786 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01787     SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
01788 {
01789     SCARD_READERSTATE *currReader;
01790     READER_STATE *rContext;
01791     long dwTime;
01792     DWORD dwState;
01793     DWORD dwBreakFlag = 0;
01794     unsigned int j;
01795     SCONTEXTMAP * currentContextMap;
01796     int currentReaderCount = 0;
01797     LONG rv = SCARD_S_SUCCESS;
01798 
01799     PROFILE_START
01800 
01801     if ((rgReaderStates == NULL && cReaders > 0)
01802         || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
01803         return SCARD_E_INVALID_PARAMETER;
01804 
01805     /* Check the integrity of the reader states structures */
01806     for (j = 0; j < cReaders; j++)
01807     {
01808         if (rgReaderStates[j].szReader == NULL)
01809             return SCARD_E_INVALID_VALUE;
01810     }
01811 
01812     /* return if all readers are SCARD_STATE_IGNORE */
01813     if (cReaders > 0)
01814     {
01815         int nbNonIgnoredReaders = cReaders;
01816 
01817         for (j=0; j<cReaders; j++)
01818             if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
01819                 nbNonIgnoredReaders--;
01820 
01821         if (0 == nbNonIgnoredReaders)
01822             return SCARD_S_SUCCESS;
01823     }
01824     else
01825         /* reader list is empty */
01826         return SCARD_S_SUCCESS;
01827 
01828     CHECK_SAME_PROCESS
01829 
01830     /*
01831      * Make sure this context has been opened
01832      */
01833     currentContextMap = SCardGetContext(hContext);
01834     if (NULL == currentContextMap)
01835         return SCARD_E_INVALID_HANDLE;
01836 
01837     (void)pthread_mutex_lock(currentContextMap->mMutex);
01838 
01839     /* check the context is still opened */
01840     currentContextMap = SCardGetContext(hContext);
01841     if (NULL == currentContextMap)
01842         /* the context is now invalid
01843          * -> another thread may have called SCardReleaseContext
01844          * -> so the mMutex has been unlocked */
01845         return SCARD_E_INVALID_HANDLE;
01846 
01847     /* synchronize reader states with daemon */
01848     rv = getReaderStates(currentContextMap);
01849     if (rv != SCARD_S_SUCCESS)
01850         goto end;
01851 
01852     /* Clear the event state for all readers */
01853     for (j = 0; j < cReaders; j++)
01854         rgReaderStates[j].dwEventState = 0;
01855 
01856     /* Now is where we start our event checking loop */
01857     Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
01858 
01859     /* Get the initial reader count on the system */
01860     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
01861         if (readerStates[j].readerID != 0)
01862             currentReaderCount++;
01863 
01864     if (INFINITE == dwTimeout)
01865         dwTime = 60*1000;   /* "infinite" timeout */
01866     else
01867         dwTime = dwTimeout;
01868 
01869     j = 0;
01870     do
01871     {
01872         currReader = &rgReaderStates[j];
01873 
01874         /* Ignore for IGNORED readers */
01875         if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
01876         {
01877             LPSTR lpcReaderName;
01878             int i;
01879 
01880       /************ Looks for correct readernames *********************/
01881 
01882             lpcReaderName = (char *) currReader->szReader;
01883 
01884             for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01885             {
01886                 if (strcmp(lpcReaderName, readerStates[i].readerName) == 0)
01887                     break;
01888             }
01889 
01890             /* The requested reader name is not recognized */
01891             if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01892             {
01893                 /* PnP special reader? */
01894                 if (strcasecmp(lpcReaderName, "\\\\?PnP?\\Notification") == 0)
01895                 {
01896                     int k, newReaderCount = 0;
01897 
01898                     for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
01899                         if (readerStates[k].readerID != 0)
01900                             newReaderCount++;
01901 
01902                     if (newReaderCount != currentReaderCount)
01903                     {
01904                         Log1(PCSC_LOG_INFO, "Reader list changed");
01905                         currentReaderCount = newReaderCount;
01906 
01907                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01908                         dwBreakFlag = 1;
01909                     }
01910                 }
01911                 else
01912                 {
01913                     currReader->dwEventState = SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE;
01914                     if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
01915                     {
01916                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01917                         /*
01918                          * Spec says use SCARD_STATE_IGNORE but a removed USB
01919                          * reader with eventState fed into currentState will
01920                          * be ignored forever
01921                          */
01922                         dwBreakFlag = 1;
01923                     }
01924                 }
01925             }
01926             else
01927             {
01928                 /* The reader has come back after being away */
01929                 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
01930                 {
01931                     currReader->dwEventState |= SCARD_STATE_CHANGED;
01932                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01933                     Log0(PCSC_LOG_DEBUG);
01934                     dwBreakFlag = 1;
01935                 }
01936 
01937     /*****************************************************************/
01938 
01939                 /* Set the reader status structure */
01940                 rContext = &readerStates[i];
01941 
01942                 /* Now we check all the Reader States */
01943                 dwState = rContext->readerState;
01944 
01945                 /* only if current state has an non null event counter */
01946                 if (currReader->dwCurrentState & 0xFFFF0000)
01947                 {
01948                     int currentCounter, stateCounter;
01949 
01950                     stateCounter = (dwState >> 16) & 0xFFFF;
01951                     currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
01952 
01953                     /* has the event counter changed since the last call? */
01954                     if (stateCounter != currentCounter)
01955                     {
01956                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01957                         Log0(PCSC_LOG_DEBUG);
01958                         dwBreakFlag = 1;
01959                     }
01960 
01961                     /* add an event counter in the upper word of dwEventState */
01962                     currReader->dwEventState =
01963                         ((currReader->dwEventState & 0xffff )
01964                         | (stateCounter << 16));
01965                 }
01966 
01967     /*********** Check if the reader is in the correct state ********/
01968                 if (dwState & SCARD_UNKNOWN)
01969                 {
01970                     /* reader is in bad state */
01971                     currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
01972                     if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
01973                     {
01974                         /* App thinks reader is in good state and it is not */
01975                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01976                         Log0(PCSC_LOG_DEBUG);
01977                         dwBreakFlag = 1;
01978                     }
01979                 }
01980                 else
01981                 {
01982                     /* App thinks reader in bad state but it is not */
01983                     if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
01984                     {
01985                         currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
01986                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01987                         Log0(PCSC_LOG_DEBUG);
01988                         dwBreakFlag = 1;
01989                     }
01990                 }
01991 
01992     /********** Check for card presence in the reader **************/
01993 
01994                 if (dwState & SCARD_PRESENT)
01995                 {
01996                     /* card present but not yet powered up */
01997                     if (0 == rContext->cardAtrLength)
01998                         /* Allow the status thread to convey information */
01999                         (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
02000 
02001                     currReader->cbAtr = rContext->cardAtrLength;
02002                     memcpy(currReader->rgbAtr, rContext->cardAtr,
02003                         currReader->cbAtr);
02004                 }
02005                 else
02006                     currReader->cbAtr = 0;
02007 
02008                 /* Card is now absent */
02009                 if (dwState & SCARD_ABSENT)
02010                 {
02011                     currReader->dwEventState |= SCARD_STATE_EMPTY;
02012                     currReader->dwEventState &= ~SCARD_STATE_PRESENT;
02013                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02014                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02015                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02016                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02017                     currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
02018                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02019                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02020 
02021                     /* After present the rest are assumed */
02022                     if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
02023                     {
02024                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02025                         Log0(PCSC_LOG_DEBUG);
02026                         dwBreakFlag = 1;
02027                     }
02028                 }
02029                 /* Card is now present */
02030                 else if (dwState & SCARD_PRESENT)
02031                 {
02032                     currReader->dwEventState |= SCARD_STATE_PRESENT;
02033                     currReader->dwEventState &= ~SCARD_STATE_EMPTY;
02034                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02035                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02036                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02037                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02038                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02039 
02040                     if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
02041                     {
02042                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02043                         Log0(PCSC_LOG_DEBUG);
02044                         dwBreakFlag = 1;
02045                     }
02046 
02047                     if (dwState & SCARD_SWALLOWED)
02048                     {
02049                         currReader->dwEventState |= SCARD_STATE_MUTE;
02050                         if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
02051                         {
02052                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02053                             Log0(PCSC_LOG_DEBUG);
02054                             dwBreakFlag = 1;
02055                         }
02056                     }
02057                     else
02058                     {
02059                         /* App thinks card is mute but it is not */
02060                         if (currReader->dwCurrentState & SCARD_STATE_MUTE)
02061                         {
02062                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02063                             Log0(PCSC_LOG_DEBUG);
02064                             dwBreakFlag = 1;
02065                         }
02066                     }
02067                 }
02068 
02069                 /* Now figure out sharing modes */
02070                 if (rContext->readerSharing == SCARD_EXCLUSIVE_CONTEXT)
02071                 {
02072                     currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
02073                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02074                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02075                     {
02076                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02077                         Log0(PCSC_LOG_DEBUG);
02078                         dwBreakFlag = 1;
02079                     }
02080                 }
02081                 else if (rContext->readerSharing >= SCARD_LAST_CONTEXT)
02082                 {
02083                     /* A card must be inserted for it to be INUSE */
02084                     if (dwState & SCARD_PRESENT)
02085                     {
02086                         currReader->dwEventState |= SCARD_STATE_INUSE;
02087                         currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02088                         if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
02089                         {
02090                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02091                             Log0(PCSC_LOG_DEBUG);
02092                             dwBreakFlag = 1;
02093                         }
02094                     }
02095                 }
02096                 else if (rContext->readerSharing == SCARD_NO_CONTEXT)
02097                 {
02098                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02099                     currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02100 
02101                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02102                     {
02103                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02104                         Log0(PCSC_LOG_DEBUG);
02105                         dwBreakFlag = 1;
02106                     }
02107                     else if (currReader-> dwCurrentState
02108                         & SCARD_STATE_EXCLUSIVE)
02109                     {
02110                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02111                         Log0(PCSC_LOG_DEBUG);
02112                         dwBreakFlag = 1;
02113                     }
02114                 }
02115 
02116                 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
02117                 {
02118                     /*
02119                      * Break out of the while .. loop and return status
02120                      * once all the status's for all readers is met
02121                      */
02122                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02123                     Log0(PCSC_LOG_DEBUG);
02124                     dwBreakFlag = 1;
02125                 }
02126             }   /* End of SCARD_STATE_UNKNOWN */
02127         }   /* End of SCARD_STATE_IGNORE */
02128 
02129         /* Counter and resetter */
02130         j++;
02131         if (j == cReaders)
02132         {
02133             /* go back to the first reader */
02134             j = 0;
02135 
02136             /* Declare all the break conditions */
02137 
02138             /* Break if UNAWARE is set and all readers have been checked */
02139             if (dwBreakFlag == 1)
02140                 break;
02141 
02142             /* Only sleep once for each cycle of reader checks. */
02143             {
02144                 struct wait_reader_state_change waitStatusStruct;
02145                 struct timeval before, after;
02146 
02147                 gettimeofday(&before, NULL);
02148 
02149                 waitStatusStruct.timeOut = dwTime;
02150                 waitStatusStruct.rv = SCARD_S_SUCCESS;
02151 
02152                 rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
02153                     currentContextMap->dwClientID,
02154                     sizeof(waitStatusStruct),
02155                     &waitStatusStruct);
02156 
02157                 if (rv == -1)
02158                 {
02159                     rv = SCARD_E_NO_SERVICE;
02160                     goto end;
02161                 }
02162 
02163                 /*
02164                  * Read a message from the server
02165                  */
02166                 rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
02167                     &waitStatusStruct, sizeof(waitStatusStruct),
02168                     currentContextMap->dwClientID, dwTime);
02169 
02170                 /* timeout */
02171                 if (-2 == rv)
02172                 {
02173                     /* ask server to remove us from the event list */
02174                     rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
02175                         currentContextMap->dwClientID,
02176                         sizeof(waitStatusStruct),
02177                         &waitStatusStruct);
02178 
02179                     if (rv == -1)
02180                     {
02181                         rv = SCARD_E_NO_SERVICE;
02182                         goto end;
02183                     }
02184 
02185                     /* Read a message from the server */
02186                     rv = MessageReceive(&waitStatusStruct,
02187                         sizeof(waitStatusStruct),
02188                         currentContextMap->dwClientID);
02189 
02190                     if (rv == -1)
02191                     {
02192                         rv = SCARD_E_NO_SERVICE;
02193                         goto end;
02194                     }
02195                 }
02196 
02197                 if (rv < 0)
02198                 {
02199                     rv = SCARD_E_NO_SERVICE;
02200                     goto end;
02201                 }
02202 
02203                 /* an event occurs or SCardCancel() was called */
02204                 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
02205                 {
02206                     rv = waitStatusStruct.rv;
02207                     goto end;
02208                 }
02209 
02210                 /* synchronize reader states with daemon */
02211                 rv = getReaderStates(currentContextMap);
02212                 if (rv != SCARD_S_SUCCESS)
02213                     goto end;
02214 
02215                 if (INFINITE != dwTimeout)
02216                 {
02217                     long int diff;
02218 
02219                     gettimeofday(&after, NULL);
02220                     diff = time_sub(&after, &before);
02221                     dwTime -= diff/1000;
02222                 }
02223             }
02224 
02225             if (dwTimeout != INFINITE)
02226             {
02227                 /* If time is greater than timeout and all readers have been
02228                  * checked
02229                  */
02230                 if (dwTime <= 0)
02231                 {
02232                     rv = SCARD_E_TIMEOUT;
02233                     goto end;
02234                 }
02235             }
02236         }
02237     }
02238     while (1);
02239 
02240 end:
02241     Log1(PCSC_LOG_DEBUG, "Event Loop End");
02242 
02243     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02244 
02245     PROFILE_END(rv)
02246 
02247     return rv;
02248 }
02249 
02303 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
02304     DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
02305     LPDWORD lpBytesReturned)
02306 {
02307     LONG rv;
02308     struct control_struct scControlStruct;
02309     SCONTEXTMAP * currentContextMap;
02310     CHANNEL_MAP * pChannelMap;
02311 
02312     PROFILE_START
02313 
02314     /* 0 bytes received by default */
02315     if (NULL != lpBytesReturned)
02316         *lpBytesReturned = 0;
02317 
02318     CHECK_SAME_PROCESS
02319 
02320     /*
02321      * Make sure this handle has been opened
02322      */
02323     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02324         &pChannelMap);
02325     if (rv == -1)
02326     {
02327         PROFILE_END(SCARD_E_INVALID_HANDLE)
02328         return SCARD_E_INVALID_HANDLE;
02329     }
02330 
02331     (void)pthread_mutex_lock(currentContextMap->mMutex);
02332 
02333     /* check the handle is still valid */
02334     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02335         &pChannelMap);
02336     if (rv == -1)
02337         /* the handle is now invalid
02338          * -> another thread may have called SCardReleaseContext
02339          * -> so the mMutex has been unlocked */
02340         return SCARD_E_INVALID_HANDLE;
02341 
02342     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02343         || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02344     {
02345         rv = SCARD_E_INSUFFICIENT_BUFFER;
02346         goto end;
02347     }
02348 
02349     scControlStruct.hCard = hCard;
02350     scControlStruct.dwControlCode = dwControlCode;
02351     scControlStruct.cbSendLength = cbSendLength;
02352     scControlStruct.cbRecvLength = cbRecvLength;
02353 
02354     rv = MessageSendWithHeader(SCARD_CONTROL,
02355         currentContextMap->dwClientID,
02356         sizeof(scControlStruct), &scControlStruct);
02357 
02358     if (rv == -1)
02359     {
02360         rv = SCARD_E_NO_SERVICE;
02361         goto end;
02362     }
02363 
02364     /* write the sent buffer */
02365     rv = MessageSend((char *)pbSendBuffer, cbSendLength,
02366         currentContextMap->dwClientID);
02367 
02368     if (rv == -1)
02369     {
02370         rv = SCARD_E_NO_SERVICE;
02371         goto end;
02372     }
02373 
02374     /*
02375      * Read a message from the server
02376      */
02377     rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
02378         currentContextMap->dwClientID);
02379 
02380     if (rv < 0)
02381     {
02382         rv = SCARD_F_COMM_ERROR;
02383         goto end;
02384     }
02385 
02386     if (SCARD_S_SUCCESS == scControlStruct.rv)
02387     {
02388         /* read the received buffer */
02389         rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
02390             currentContextMap->dwClientID);
02391 
02392         if (rv < 0)
02393         {
02394             rv = SCARD_E_NO_SERVICE;
02395             goto end;
02396         }
02397 
02398     }
02399 
02400     if (NULL != lpBytesReturned)
02401         *lpBytesReturned = scControlStruct.dwBytesReturned;
02402 
02403     rv = scControlStruct.rv;
02404 
02405 end:
02406     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02407 
02408     PROFILE_END(rv)
02409 
02410     return rv;
02411 }
02412 
02517 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
02518     LPDWORD pcbAttrLen)
02519 {
02520     LONG ret;
02521     unsigned char *buf = NULL;
02522 
02523     PROFILE_START
02524 
02525     if (NULL == pcbAttrLen)
02526         return SCARD_E_INVALID_PARAMETER;
02527 
02528     if (SCARD_AUTOALLOCATE == *pcbAttrLen)
02529     {
02530         if (NULL == pbAttr)
02531             return SCARD_E_INVALID_PARAMETER;
02532 
02533         *pcbAttrLen = MAX_BUFFER_SIZE;
02534         buf = malloc(*pcbAttrLen);
02535         if (NULL == buf)
02536             return SCARD_E_NO_MEMORY;
02537 
02538         *(unsigned char **)pbAttr = buf;
02539     }
02540     else
02541     {
02542         buf = pbAttr;
02543 
02544         /* if only get the length */
02545         if (NULL == pbAttr)
02546             /* use a reasonable size */
02547             *pcbAttrLen = MAX_BUFFER_SIZE;
02548     }
02549 
02550     ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
02551         pcbAttrLen);
02552 
02553     PROFILE_END(ret)
02554 
02555     return ret;
02556 }
02557 
02593 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
02594     DWORD cbAttrLen)
02595 {
02596     LONG ret;
02597 
02598     if (NULL == pbAttr || 0 == cbAttrLen)
02599         return SCARD_E_INVALID_PARAMETER;
02600 
02601     ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
02602         &cbAttrLen);
02603 
02604     return ret;
02605 }
02606 
02607 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
02608     LPBYTE pbAttr, LPDWORD pcbAttrLen)
02609 {
02610     LONG rv;
02611     struct getset_struct scGetSetStruct;
02612     SCONTEXTMAP * currentContextMap;
02613     CHANNEL_MAP * pChannelMap;
02614 
02615     CHECK_SAME_PROCESS
02616 
02617     /*
02618      * Make sure this handle has been opened
02619      */
02620     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02621         &pChannelMap);
02622     if (rv == -1)
02623         return SCARD_E_INVALID_HANDLE;
02624 
02625     (void)pthread_mutex_lock(currentContextMap->mMutex);
02626 
02627     /* check the handle is still valid */
02628     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02629         &pChannelMap);
02630     if (rv == -1)
02631         /* the handle is now invalid
02632          * -> another thread may have called SCardReleaseContext
02633          * -> so the mMutex has been unlocked */
02634         return SCARD_E_INVALID_HANDLE;
02635 
02636     if (*pcbAttrLen > MAX_BUFFER_SIZE)
02637     {
02638         rv = SCARD_E_INSUFFICIENT_BUFFER;
02639         goto end;
02640     }
02641 
02642     scGetSetStruct.hCard = hCard;
02643     scGetSetStruct.dwAttrId = dwAttrId;
02644     scGetSetStruct.cbAttrLen = *pcbAttrLen;
02645     scGetSetStruct.rv = SCARD_E_NO_SERVICE;
02646     memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
02647     if (SCARD_SET_ATTRIB == command)
02648         memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
02649 
02650     rv = MessageSendWithHeader(command,
02651         currentContextMap->dwClientID, sizeof(scGetSetStruct),
02652         &scGetSetStruct);
02653 
02654     if (rv == -1)
02655     {
02656         rv = SCARD_E_NO_SERVICE;
02657         goto end;
02658     }
02659 
02660     /*
02661      * Read a message from the server
02662      */
02663     rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
02664         currentContextMap->dwClientID);
02665 
02666     if (rv < 0)
02667     {
02668         rv = SCARD_F_COMM_ERROR;
02669         goto end;
02670     }
02671 
02672     if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
02673     {
02674         /*
02675          * Copy and zero it so any secret information is not leaked
02676          */
02677         if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
02678         {
02679             scGetSetStruct.cbAttrLen = *pcbAttrLen;
02680             scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
02681         }
02682         else
02683             *pcbAttrLen = scGetSetStruct.cbAttrLen;
02684 
02685         if (pbAttr)
02686             memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
02687 
02688         memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
02689     }
02690     rv = scGetSetStruct.rv;
02691 
02692 end:
02693     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02694 
02695     PROFILE_END(rv)
02696 
02697     return rv;
02698 }
02699 
02758 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
02759     LPCBYTE pbSendBuffer, DWORD cbSendLength,
02760     SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
02761     LPDWORD pcbRecvLength)
02762 {
02763     LONG rv;
02764     SCONTEXTMAP * currentContextMap;
02765     CHANNEL_MAP * pChannelMap;
02766     struct transmit_struct scTransmitStruct;
02767 
02768     PROFILE_START
02769 
02770     if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
02771             pcbRecvLength == NULL || pioSendPci == NULL)
02772         return SCARD_E_INVALID_PARAMETER;
02773 
02774     CHECK_SAME_PROCESS
02775 
02776     /*
02777      * Make sure this handle has been opened
02778      */
02779     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02780         &pChannelMap);
02781     if (rv == -1)
02782     {
02783         *pcbRecvLength = 0;
02784         PROFILE_END(SCARD_E_INVALID_HANDLE)
02785         return SCARD_E_INVALID_HANDLE;
02786     }
02787 
02788     (void)pthread_mutex_lock(currentContextMap->mMutex);
02789 
02790     /* check the handle is still valid */
02791     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02792         &pChannelMap);
02793     if (rv == -1)
02794         /* the handle is now invalid
02795          * -> another thread may have called SCardReleaseContext
02796          * -> so the mMutex has been unlocked */
02797         return SCARD_E_INVALID_HANDLE;
02798 
02799     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02800         || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02801     {
02802         rv = SCARD_E_INSUFFICIENT_BUFFER;
02803         goto end;
02804     }
02805 
02806     /* Retry loop for blocking behaviour */
02807 retry:
02808     
02809     scTransmitStruct.hCard = hCard;
02810     scTransmitStruct.cbSendLength = cbSendLength;
02811     scTransmitStruct.pcbRecvLength = *pcbRecvLength;
02812     scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
02813     scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
02814     scTransmitStruct.rv = SCARD_S_SUCCESS;
02815 
02816     if (pioRecvPci)
02817     {
02818         scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
02819         scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
02820     }
02821     else
02822     {
02823         scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
02824         scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
02825     }
02826 
02827     rv = MessageSendWithHeader(SCARD_TRANSMIT,
02828         currentContextMap->dwClientID, sizeof(scTransmitStruct),
02829         (void *) &scTransmitStruct);
02830 
02831     if (rv == -1)
02832     {
02833         rv = SCARD_E_NO_SERVICE;
02834         goto end;
02835     }
02836 
02837     /* write the sent buffer */
02838     rv = MessageSend((void *)pbSendBuffer, cbSendLength,
02839         currentContextMap->dwClientID);
02840 
02841     if (rv == -1)
02842     {
02843         rv = SCARD_E_NO_SERVICE;
02844         goto end;
02845     }
02846 
02847     /*
02848      * Read a message from the server
02849      */
02850     rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
02851         currentContextMap->dwClientID);
02852 
02853     if (rv < 0)
02854     {
02855         rv = SCARD_F_COMM_ERROR;
02856         goto end;
02857     }
02858 
02859     if (SCARD_S_SUCCESS == scTransmitStruct.rv)
02860     {
02861         /* read the received buffer */
02862         rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
02863             currentContextMap->dwClientID);
02864 
02865         if (rv < 0)
02866         {
02867             rv = SCARD_E_NO_SERVICE;
02868             goto end;
02869         }
02870 
02871         if (pioRecvPci)
02872         {
02873             pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
02874             pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
02875         }
02876     }
02877 
02878     rv = scTransmitStruct.rv;
02879 
02880     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
02881     {
02882         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
02883         goto retry;
02884     }
02885 
02886     *pcbRecvLength = scTransmitStruct.pcbRecvLength;
02887 
02888 end:
02889     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02890 
02891     PROFILE_END(rv)
02892 
02893     return rv;
02894 }
02895 
02946 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
02947     LPSTR mszReaders, LPDWORD pcchReaders)
02948 {
02949     DWORD dwReadersLen = 0;
02950     int i;
02951     SCONTEXTMAP * currentContextMap;
02952     LONG rv = SCARD_S_SUCCESS;
02953     char *buf = NULL;
02954 
02955     (void)mszGroups;
02956     PROFILE_START
02957 
02958     /*
02959      * Check for NULL parameters
02960      */
02961     if (pcchReaders == NULL)
02962         return SCARD_E_INVALID_PARAMETER;
02963 
02964     CHECK_SAME_PROCESS
02965 
02966     /*
02967      * Make sure this context has been opened
02968      */
02969     currentContextMap = SCardGetContext(hContext);
02970     if (NULL == currentContextMap)
02971     {
02972         PROFILE_END(SCARD_E_INVALID_HANDLE)
02973         return SCARD_E_INVALID_HANDLE;
02974     }
02975 
02976     (void)pthread_mutex_lock(currentContextMap->mMutex);
02977 
02978     /* check the context is still opened */
02979     currentContextMap = SCardGetContext(hContext);
02980     if (NULL == currentContextMap)
02981         /* the context is now invalid
02982          * -> another thread may have called SCardReleaseContext
02983          * -> so the mMutex has been unlocked */
02984         return SCARD_E_INVALID_HANDLE;
02985 
02986     /* synchronize reader states with daemon */
02987     rv = getReaderStates(currentContextMap);
02988     if (rv != SCARD_S_SUCCESS)
02989         goto end;
02990 
02991     dwReadersLen = 0;
02992     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
02993         if (readerStates[i].readerID != 0)
02994             dwReadersLen += strlen(readerStates[i].readerName) + 1;
02995 
02996     /* for the last NULL byte */
02997     dwReadersLen += 1;
02998 
02999     if (1 == dwReadersLen)
03000     {
03001         rv = SCARD_E_NO_READERS_AVAILABLE;
03002         goto end;
03003     }
03004 
03005     if (SCARD_AUTOALLOCATE == *pcchReaders)
03006     {
03007         buf = malloc(dwReadersLen);
03008         if (NULL == buf)
03009         {
03010             rv = SCARD_E_NO_MEMORY;
03011             goto end;
03012         }
03013         if (NULL == mszReaders)
03014         {
03015             rv = SCARD_E_INVALID_PARAMETER;
03016             goto end;
03017         }
03018         *(char **)mszReaders = buf;
03019     }
03020     else
03021     {
03022         buf = mszReaders;
03023 
03024         /* not enough place to store the reader names */
03025         if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
03026         {
03027             rv = SCARD_E_INSUFFICIENT_BUFFER;
03028             goto end;
03029         }
03030     }
03031 
03032     if (mszReaders == NULL) /* text array not allocated */
03033         goto end;
03034 
03035     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03036     {
03037         if (readerStates[i].readerID != 0)
03038         {
03039             /*
03040              * Build the multi-string
03041              */
03042             strcpy(buf, readerStates[i].readerName);
03043             buf += strlen(readerStates[i].readerName)+1;
03044         }
03045     }
03046     *buf = '\0';    /* Add the last null */
03047 
03048 end:
03049     /* set the reader names length */
03050     *pcchReaders = dwReadersLen;
03051 
03052     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03053 
03054     PROFILE_END(rv)
03055 
03056     return rv;
03057 }
03058 
03072 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
03073 {
03074     LONG rv = SCARD_S_SUCCESS;
03075     SCONTEXTMAP * currentContextMap;
03076 
03077     PROFILE_START
03078 
03079     CHECK_SAME_PROCESS
03080 
03081     /*
03082      * Make sure this context has been opened
03083      */
03084     currentContextMap = SCardGetContext(hContext);
03085     if (NULL == currentContextMap)
03086         return SCARD_E_INVALID_HANDLE;
03087 
03088     free((void *)pvMem);
03089 
03090     PROFILE_END(rv)
03091 
03092     return rv;
03093 }
03094 
03146 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
03147     LPDWORD pcchGroups)
03148 {
03149     LONG rv = SCARD_S_SUCCESS;
03150     SCONTEXTMAP * currentContextMap;
03151     char *buf = NULL;
03152 
03153     PROFILE_START
03154 
03155     /* Multi-string with two trailing \0 */
03156     const char ReaderGroup[] = "SCard$DefaultReaders\0";
03157     const unsigned int dwGroups = sizeof(ReaderGroup);
03158 
03159     CHECK_SAME_PROCESS
03160 
03161     /*
03162      * Make sure this context has been opened
03163      */
03164     currentContextMap = SCardGetContext(hContext);
03165     if (NULL == currentContextMap)
03166         return SCARD_E_INVALID_HANDLE;
03167 
03168     (void)pthread_mutex_lock(currentContextMap->mMutex);
03169 
03170     /* check the context is still opened */
03171     currentContextMap = SCardGetContext(hContext);
03172     if (NULL == currentContextMap)
03173         /* the context is now invalid
03174          * -> another thread may have called SCardReleaseContext
03175          * -> so the mMutex has been unlocked */
03176         return SCARD_E_INVALID_HANDLE;
03177 
03178     if (SCARD_AUTOALLOCATE == *pcchGroups)
03179     {
03180         buf = malloc(dwGroups);
03181         if (NULL == buf)
03182         {
03183             rv = SCARD_E_NO_MEMORY;
03184             goto end;
03185         }
03186         if (NULL == mszGroups)
03187         {
03188             rv = SCARD_E_INVALID_PARAMETER;
03189             goto end;
03190         }
03191         *(char **)mszGroups = buf;
03192     }
03193     else
03194     {
03195         buf = mszGroups;
03196 
03197         if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
03198         {
03199             rv = SCARD_E_INSUFFICIENT_BUFFER;
03200             goto end;
03201         }
03202     }
03203 
03204     if (buf)
03205         memcpy(buf, ReaderGroup, dwGroups);
03206 
03207 end:
03208     *pcchGroups = dwGroups;
03209 
03210     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03211 
03212     PROFILE_END(rv)
03213 
03214     return rv;
03215 }
03216 
03246 LONG SCardCancel(SCARDCONTEXT hContext)
03247 {
03248     SCONTEXTMAP * currentContextMap;
03249     LONG rv = SCARD_S_SUCCESS;
03250     uint32_t dwClientID = 0;
03251     struct cancel_struct scCancelStruct;
03252 
03253     PROFILE_START
03254 
03255     /*
03256      * Make sure this context has been opened
03257      */
03258     currentContextMap = SCardGetContext(hContext);
03259     if (NULL == currentContextMap)
03260         return SCARD_E_INVALID_HANDLE;
03261 
03262     /* create a new connection to the server */
03263     if (ClientSetupSession(&dwClientID) != 0)
03264     {
03265         rv = SCARD_E_NO_SERVICE;
03266         goto error;
03267     }
03268 
03269     scCancelStruct.hContext = hContext;
03270     scCancelStruct.rv = SCARD_S_SUCCESS;
03271 
03272     rv = MessageSendWithHeader(SCARD_CANCEL,
03273         dwClientID,
03274         sizeof(scCancelStruct), (void *) &scCancelStruct);
03275 
03276     if (rv == -1)
03277     {
03278         rv = SCARD_E_NO_SERVICE;
03279         goto end;
03280     }
03281 
03282     /*
03283      * Read a message from the server
03284      */
03285     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct),
03286         dwClientID);
03287 
03288     if (rv < 0)
03289     {
03290         rv = SCARD_F_COMM_ERROR;
03291         goto end;
03292     }
03293 
03294     rv = scCancelStruct.rv;
03295 end:
03296     ClientCloseSession(dwClientID);
03297 
03298 error:
03299     PROFILE_END(rv)
03300 
03301     return rv;
03302 }
03303 
03327 LONG SCardIsValidContext(SCARDCONTEXT hContext)
03328 {
03329     LONG rv;
03330     SCONTEXTMAP * currentContextMap;
03331 
03332     PROFILE_START
03333 
03334     rv = SCARD_S_SUCCESS;
03335 
03336     /* Check if the _same_ server is running */
03337     CHECK_SAME_PROCESS
03338 
03339     /*
03340      * Make sure this context has been opened
03341      */
03342     currentContextMap = SCardGetContext(hContext);
03343     if (currentContextMap == NULL)
03344         rv = SCARD_E_INVALID_HANDLE;
03345 
03346     PROFILE_END(rv)
03347 
03348     return rv;
03349 }
03350 
03367 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
03368 {
03369     int lrv;
03370     SCONTEXTMAP * newContextMap;
03371 
03372     newContextMap = malloc(sizeof(SCONTEXTMAP));
03373     if (NULL == newContextMap)
03374         return SCARD_E_NO_MEMORY;
03375 
03376     Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%X", newContextMap);
03377     newContextMap->hContext = hContext;
03378     newContextMap->dwClientID = dwClientID;
03379 
03380     newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
03381     if (NULL == newContextMap->mMutex)
03382     {
03383         Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%X", newContextMap);
03384         free(newContextMap);
03385         return SCARD_E_NO_MEMORY;
03386     }
03387     (void)pthread_mutex_init(newContextMap->mMutex, NULL);
03388 
03389     lrv = list_init(&(newContextMap->channelMapList));
03390     if (lrv < 0)
03391     {
03392         Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %X", lrv);
03393         goto error;
03394     }
03395 
03396     lrv = list_attributes_seeker(&(newContextMap->channelMapList),
03397         CHANNEL_MAP_seeker);
03398     if (lrv <0)
03399     {
03400         Log2(PCSC_LOG_CRITICAL,
03401             "list_attributes_seeker failed with return value: %X", lrv);
03402         list_destroy(&(newContextMap->channelMapList));
03403         goto error;
03404     }
03405 
03406     lrv = list_append(&contextMapList, newContextMap);
03407     if (lrv < 0)
03408     {
03409         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X",
03410             lrv);
03411         list_destroy(&(newContextMap->channelMapList));
03412         goto error;
03413     }
03414 
03415     return SCARD_S_SUCCESS;
03416 
03417 error:
03418 
03419     (void)pthread_mutex_destroy(newContextMap->mMutex);
03420     free(newContextMap->mMutex);
03421     free(newContextMap);
03422 
03423     return SCARD_E_NO_MEMORY;
03424 }
03425 
03438 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT hContext)
03439 {
03440     SCONTEXTMAP * currentContextMap;
03441 
03442     (void)SCardLockThread();
03443     currentContextMap = SCardGetContextTH(hContext);
03444     (void)SCardUnlockThread();
03445 
03446     return currentContextMap;
03447 }
03448 
03461 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext)
03462 {
03463     return list_seek(&contextMapList, &hContext);
03464 }
03465 
03475 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
03476 {
03477     SCONTEXTMAP * currentContextMap;
03478     currentContextMap = SCardGetContextTH(hContext);
03479 
03480     if (NULL == currentContextMap)
03481         return SCARD_E_INVALID_HANDLE;
03482     else
03483         return SCardCleanContext(currentContextMap);
03484 }
03485 
03486 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
03487 {
03488     int list_index, lrv;
03489     int listSize;
03490     CHANNEL_MAP * currentChannelMap;
03491 
03492     targetContextMap->hContext = 0;
03493     (void)ClientCloseSession(targetContextMap->dwClientID);
03494     targetContextMap->dwClientID = 0;
03495     (void)pthread_mutex_destroy(targetContextMap->mMutex);
03496     free(targetContextMap->mMutex);
03497     targetContextMap->mMutex = NULL;
03498 
03499     listSize = list_size(&(targetContextMap->channelMapList));
03500     for (list_index = 0; list_index < listSize; list_index++)
03501     {
03502         currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
03503             list_index);
03504         if (NULL == currentChannelMap)
03505         {
03506             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03507                 list_index);
03508             continue;
03509         }
03510         else
03511         {
03512             free(currentChannelMap->readerName);
03513             free(currentChannelMap);
03514         }
03515 
03516     }
03517     list_destroy(&(targetContextMap->channelMapList));
03518 
03519     lrv = list_delete(&contextMapList, targetContextMap);
03520     if (lrv < 0)
03521     {
03522         Log2(PCSC_LOG_CRITICAL,
03523             "list_delete failed with return value: %X", lrv);
03524     }
03525 
03526     free(targetContextMap);
03527 
03528     return SCARD_S_SUCCESS;
03529 }
03530 
03531 /*
03532  * Functions for managing hCard values returned from SCardConnect.
03533  */
03534 
03535 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
03536     LPCSTR readerName)
03537 {
03538     CHANNEL_MAP * newChannelMap;
03539     int lrv = -1;
03540 
03541     newChannelMap = malloc(sizeof(CHANNEL_MAP));
03542     if (NULL == newChannelMap)
03543         return SCARD_E_NO_MEMORY;
03544 
03545     newChannelMap->hCard = hCard;
03546     newChannelMap->readerName = strdup(readerName);
03547 
03548     lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
03549     if (lrv < 0)
03550     {
03551         free(newChannelMap->readerName);
03552         free(newChannelMap);
03553         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %X", lrv);
03554         return SCARD_E_NO_MEMORY;
03555     }
03556 
03557     return SCARD_S_SUCCESS;
03558 }
03559 
03560 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
03561 {
03562     SCONTEXTMAP * currentContextMap;
03563     CHANNEL_MAP * currentChannelMap;
03564     int lrv;
03565     LONG rv;
03566 
03567     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
03568         &currentChannelMap);
03569     if (rv == -1)
03570         return SCARD_E_INVALID_HANDLE;
03571 
03572     free(currentChannelMap->readerName);
03573 
03574     lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
03575     if (lrv < 0)
03576     {
03577         Log2(PCSC_LOG_CRITICAL,
03578             "list_delete failed with return value: %X", lrv);
03579     }
03580 
03581     free(currentChannelMap);
03582 
03583     return SCARD_S_SUCCESS;
03584 }
03585 
03586 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
03587     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03588 {
03589     LONG rv;
03590 
03591     if (0 == hCard)
03592         return -1;
03593 
03594     (void)SCardLockThread();
03595     rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap, targetChannelMap);
03596     (void)SCardUnlockThread();
03597 
03598     return rv;
03599 }
03600 
03601 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
03602     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03603 {
03604     int listSize;
03605     int list_index;
03606     SCONTEXTMAP * currentContextMap;
03607     CHANNEL_MAP * currentChannelMap;
03608 
03609     /* Best to get the caller a crash early if we fail unsafely */
03610     *targetContextMap = NULL;
03611     *targetChannelMap = NULL;
03612 
03613     listSize = list_size(&contextMapList);
03614 
03615     for (list_index = 0; list_index < listSize; list_index++)
03616     {
03617         currentContextMap = list_get_at(&contextMapList, list_index);
03618         if (currentContextMap == NULL)
03619         {
03620             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d", list_index);
03621             continue;
03622         }
03623         currentChannelMap = list_seek(&(currentContextMap->channelMapList),
03624             &hCard);
03625         if (currentChannelMap != NULL)
03626         {
03627             *targetContextMap = currentContextMap;
03628             *targetChannelMap = currentChannelMap;
03629             return SCARD_S_SUCCESS;
03630         }
03631     }
03632 
03633     return -1;
03634 }
03635 
03636 static LONG SCardInvalidateHandles(void)
03637 {
03638     /* invalid all handles */
03639     (void)SCardLockThread();
03640 
03641     while (list_size(&contextMapList) != 0)
03642     {
03643         SCONTEXTMAP * currentContextMap;
03644 
03645         currentContextMap = list_get_at(&contextMapList, 0);
03646         if (currentContextMap != NULL)
03647             (void)SCardCleanContext(currentContextMap);
03648         else
03649             Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
03650     }
03651 
03652     (void)SCardUnlockThread();
03653 
03654     /* reset pcscd status */
03655     daemon_ctime = 0;
03656     client_pid = 0;
03657 
03658     return SCARD_E_INVALID_HANDLE;
03659 }
03660 
03673 LONG SCardCheckDaemonAvailability(void)
03674 {
03675     LONG rv;
03676     struct stat statBuffer;
03677     int need_restart = 0;
03678 
03679     rv = stat(PCSCLITE_CSOCK_NAME, &statBuffer);
03680 
03681     if (rv != 0)
03682     {
03683         Log2(PCSC_LOG_INFO, "PCSC Not Running: " PCSCLITE_CSOCK_NAME ": %s",
03684             strerror(errno));
03685         return SCARD_E_NO_SERVICE;
03686     }
03687 
03688     /* when the _first_ reader is connected the ctime changes
03689      * I don't know why yet */
03690     if (daemon_ctime && statBuffer.st_ctime > daemon_ctime)
03691     {
03692         /* so we also check the daemon pid to be sure it is a new pcscd */
03693         if (GetDaemonPid() != daemon_pid)
03694         {
03695             Log1(PCSC_LOG_INFO, "PCSC restarted");
03696             need_restart = 1;
03697         }
03698     }
03699 
03700     /* after fork() need to restart */
03701     if (client_pid && client_pid != getpid())
03702     {
03703         Log1(PCSC_LOG_INFO, "Client forked");
03704         need_restart = 1;
03705     }
03706 
03707     if (need_restart)
03708         return SCardInvalidateHandles();
03709 
03710     daemon_ctime = statBuffer.st_ctime;
03711     daemon_pid = GetDaemonPid();
03712     client_pid = getpid();
03713 
03714     return SCARD_S_SUCCESS;
03715 }
03716 
03717 #ifdef DO_CHECK_SAME_PROCESS
03718 static LONG SCardCheckSameProcess(void)
03719 {
03720     /* after fork() need to restart */
03721     if ((client_pid && client_pid != getpid()))
03722     {
03723         Log1(PCSC_LOG_INFO, "Client forked");
03724         return SCardInvalidateHandles();
03725     }
03726 
03727     client_pid = getpid();
03728 
03729     return SCARD_S_SUCCESS;
03730 }
03731 #endif
03732 
03733 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
03734 {
03735     int32_t dwClientID = currentContextMap->dwClientID;
03736 
03737     if (-1 == MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL))
03738         return SCARD_E_NO_SERVICE;
03739 
03740     /* Read a message from the server */
03741     if (MessageReceive(&readerStates, sizeof(readerStates), dwClientID) < 0)
03742         return SCARD_F_COMM_ERROR;
03743 
03744     return SCARD_S_SUCCESS;
03745 }
03746