pcsc-lite  1.8.3
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-2011
00011  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00012  * Copyright (C) 2009
00013  *  Jean-Luc Giraud <jlgiraud@googlemail.com>
00014  *
00015  * $Id: winscard_clnt.c 6105 2011-11-14 10:19:44Z rousseau $
00016  */
00017 
00084 #include "config.h"
00085 #include <stdlib.h>
00086 #include <string.h>
00087 #include <sys/types.h>
00088 #include <fcntl.h>
00089 #include <unistd.h>
00090 #include <sys/un.h>
00091 #include <errno.h>
00092 #include <stddef.h>
00093 #include <sys/time.h>
00094 #include <pthread.h>
00095 #include <sys/wait.h>
00096 
00097 #include "misc.h"
00098 #include "pcscd.h"
00099 #include "winscard.h"
00100 #include "debuglog.h"
00101 #include "strlcpycat.h"
00102 
00103 #include "readerfactory.h"
00104 #include "eventhandler.h"
00105 #include "sys_generic.h"
00106 #include "winscard_msg.h"
00107 #include "utils.h"
00108 
00109 /* Display, on stderr, a trace of the WinSCard calls with arguments and
00110  * results */
00111 #undef DO_TRACE
00112 
00113 /* Profile the execution time of WinSCard calls */
00114 #undef DO_PROFILE
00115 
00116 
00118 #define SCARD_PROTOCOL_ANY_OLD  0x1000
00119 
00120 #ifndef TRUE
00121 #define TRUE 1
00122 #define FALSE 0
00123 #endif
00124 
00125 static char sharing_shall_block = TRUE;
00126 
00127 #define COLOR_RED "\33[01;31m"
00128 #define COLOR_GREEN "\33[32m"
00129 #define COLOR_BLUE "\33[34m"
00130 #define COLOR_MAGENTA "\33[35m"
00131 #define COLOR_NORMAL "\33[0m"
00132 
00133 #ifdef DO_TRACE
00134 
00135 #include <stdio.h>
00136 #include <stdarg.h>
00137 
00138 static void trace(const char *func, const char direction, const char *fmt, ...)
00139 {
00140     va_list args;
00141 
00142     fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
00143         direction, pthread_self(), func);
00144 
00145     fprintf(stderr, COLOR_MAGENTA);
00146     va_start(args, fmt);
00147     vfprintf(stderr, fmt, args);
00148     va_end(args);
00149 
00150     fprintf(stderr, COLOR_NORMAL "\n");
00151 }
00152 
00153 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
00154 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
00155 #else
00156 #define API_TRACE_IN(...)
00157 #define API_TRACE_OUT(...)
00158 #endif
00159 
00160 #ifdef DO_PROFILE
00161 
00162 #define PROFILE_FILE "/tmp/pcsc_profile"
00163 #include <stdio.h>
00164 #include <sys/time.h>
00165 
00166 /* we can profile a maximum of 5 simultaneous calls */
00167 #define MAX_THREADS 5
00168 pthread_t threads[MAX_THREADS];
00169 struct timeval profile_time_start[MAX_THREADS];
00170 FILE *profile_fd;
00171 char profile_tty;
00172 
00173 #define PROFILE_START profile_start();
00174 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
00175 
00176 static void profile_start(void)
00177 {
00178     static char initialized = FALSE;
00179     pthread_t t;
00180     int i;
00181 
00182     if (!initialized)
00183     {
00184         char filename[80];
00185 
00186         initialized = TRUE;
00187         sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
00188         profile_fd = fopen(filename, "a+");
00189         if (NULL == profile_fd)
00190         {
00191             fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
00192                 PROFILE_FILE, strerror(errno));
00193             exit(-1);
00194         }
00195         fprintf(profile_fd, "\nStart a new profile\n");
00196 
00197         if (isatty(fileno(stderr)))
00198             profile_tty = TRUE;
00199         else
00200             profile_tty = FALSE;
00201     }
00202 
00203     t = pthread_self();
00204     for (i=0; i<MAX_THREADS; i++)
00205         if (pthread_equal(0, threads[i]))
00206         {
00207             threads[i] = t;
00208             break;
00209         }
00210 
00211     gettimeofday(&profile_time_start[i], NULL);
00212 } /* profile_start */
00213 
00214 static void profile_end(const char *f, LONG rv)
00215 {
00216     struct timeval profile_time_end;
00217     long d;
00218     pthread_t t;
00219     int i;
00220 
00221     gettimeofday(&profile_time_end, NULL);
00222 
00223     t = pthread_self();
00224     for (i=0; i<MAX_THREADS; i++)
00225         if (pthread_equal(t, threads[i]))
00226             break;
00227 
00228     if (i>=MAX_THREADS)
00229     {
00230         fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
00231         return;
00232     }
00233 
00234     d = time_sub(&profile_time_end, &profile_time_start[i]);
00235 
00236     /* free this entry */
00237     threads[i] = 0;
00238 
00239     if (profile_tty)
00240     {
00241         if (rv != SCARD_S_SUCCESS)
00242             fprintf(stderr,
00243                 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
00244                 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
00245                 f, d, rv, pcsc_stringify_error(rv));
00246         else
00247             fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
00248                 COLOR_NORMAL "\n", f, d);
00249     }
00250     fprintf(profile_fd, "%s %ld\n", f, d);
00251     fflush(profile_fd);
00252 } /* profile_end */
00253 
00254 #else
00255 #define PROFILE_START
00256 #define PROFILE_END(rv)
00257 #endif
00258 
00263 struct _psChannelMap
00264 {
00265     SCARDHANDLE hCard;
00266     LPSTR readerName;
00267 };
00268 
00269 typedef struct _psChannelMap CHANNEL_MAP;
00270 
00271 static int CHANNEL_MAP_seeker(const void *el, const void *key)
00272 {
00273     const CHANNEL_MAP * channelMap = el;
00274 
00275     if ((el == NULL) || (key == NULL))
00276     {
00277         Log3(PCSC_LOG_CRITICAL,
00278             "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
00279             el, key);
00280         return 0;
00281     }
00282 
00283     if (channelMap->hCard == *(SCARDHANDLE *)key)
00284         return 1;
00285 
00286     return 0;
00287 }
00288 
00294 struct _psContextMap
00295 {
00296     DWORD dwClientID;               
00297     SCARDCONTEXT hContext;          
00298     pthread_mutex_t * mMutex;       
00299     list_t channelMapList;
00300     char cancellable;               
00301 };
00302 typedef struct _psContextMap SCONTEXTMAP;
00303 
00304 static list_t contextMapList;
00305 
00306 static int SCONTEXTMAP_seeker(const void *el, const void *key)
00307 {
00308     const SCONTEXTMAP * contextMap = el;
00309 
00310     if ((el == NULL) || (key == NULL))
00311     {
00312         Log3(PCSC_LOG_CRITICAL,
00313             "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
00314             el, key);
00315         return 0;
00316     }
00317 
00318     if (contextMap->hContext == *(SCARDCONTEXT *) key)
00319         return 1;
00320 
00321     return 0;
00322 }
00323 
00327 static short isExecuted = 0;
00328 
00329 
00334 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
00335 
00339 static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
00340 
00342 PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) };
00344 PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) };
00346 PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };
00347 
00348 
00349 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
00350 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT);
00351 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT);
00352 static LONG SCardRemoveContext(SCARDCONTEXT);
00353 static LONG SCardCleanContext(SCONTEXTMAP *);
00354 
00355 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
00356 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE,
00357     /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
00358 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
00359     /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
00360 static LONG SCardRemoveHandle(SCARDHANDLE);
00361 
00362 static void SCardInvalidateHandles(void);
00363 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
00364     LPBYTE pbAttr, LPDWORD pcbAttrLen);
00365 
00366 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
00367 
00368 /*
00369  * Thread safety functions
00370  */
00377 inline static LONG SCardLockThread(void)
00378 {
00379     return pthread_mutex_lock(&clientMutex);
00380 }
00381 
00387 inline static LONG SCardUnlockThread(void)
00388 {
00389     return pthread_mutex_unlock(&clientMutex);
00390 }
00391 
00392 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
00393     /*@out@*/ LPSCARDCONTEXT);
00394 
00428 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
00429     LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00430 {
00431     LONG rv;
00432     static int first_time = TRUE;
00433 
00434     API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
00435     PROFILE_START
00436 
00437     /* Some setup for the first execution */
00438     if (first_time)
00439     {
00440         first_time = FALSE;
00441 
00442         /* Invalidate all the handles in the son after a fork */
00443         pthread_atfork(NULL, NULL, SCardInvalidateHandles);
00444     }
00445 
00446     /* Check if the server is running */
00447     rv = SCardCheckDaemonAvailability();
00448     if (SCARD_E_INVALID_HANDLE == rv)
00449         /* we reconnected to a daemon or we got called from a forked child */
00450         rv = SCardCheckDaemonAvailability();
00451 
00452     if (rv != SCARD_S_SUCCESS)
00453         goto end;
00454 
00455     (void)SCardLockThread();
00456     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00457         pvReserved2, phContext);
00458     (void)SCardUnlockThread();
00459 
00460 end:
00461     PROFILE_END(rv)
00462     API_TRACE_OUT("%ld", *phContext)
00463 
00464     return rv;
00465 }
00466 
00493 static LONG SCardEstablishContextTH(DWORD dwScope,
00494     /*@unused@*/ LPCVOID pvReserved1,
00495     /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00496 {
00497     LONG rv;
00498     struct establish_struct scEstablishStruct;
00499     uint32_t dwClientID = 0;
00500 
00501     (void)pvReserved1;
00502     (void)pvReserved2;
00503     if (phContext == NULL)
00504         return SCARD_E_INVALID_PARAMETER;
00505     else
00506         *phContext = 0;
00507 
00508     /*
00509      * Do this only once:
00510      * - Initialize context list.
00511      */
00512     if (isExecuted == 0)
00513     {
00514         int lrv;
00515 
00516         /* NOTE: The list will never be freed (No API call exists to
00517          * "close all contexts".
00518          * Applications which load and unload the library will leak
00519          * the list's internal structures. */
00520         lrv = list_init(&contextMapList);
00521         if (lrv < 0)
00522         {
00523             Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
00524                 lrv);
00525             return SCARD_E_NO_MEMORY;
00526         }
00527 
00528         lrv = list_attributes_seeker(&contextMapList,
00529                 SCONTEXTMAP_seeker);
00530         if (lrv <0)
00531         {
00532             Log2(PCSC_LOG_CRITICAL,
00533                 "list_attributes_seeker failed with return value: %d", lrv);
00534             list_destroy(&contextMapList);
00535             return SCARD_E_NO_MEMORY;
00536         }
00537 
00538         if (getenv("PCSCLITE_NO_BLOCKING"))
00539         {
00540             Log1(PCSC_LOG_INFO, "Disable shared blocking");
00541             sharing_shall_block = FALSE;
00542         }
00543 
00544         isExecuted = 1;
00545     }
00546 
00547 
00548     /* Establishes a connection to the server */
00549     if (ClientSetupSession(&dwClientID) != 0)
00550     {
00551         return SCARD_E_NO_SERVICE;
00552     }
00553 
00554     {   /* exchange client/server protocol versions */
00555         struct version_struct veStr;
00556 
00557         veStr.major = PROTOCOL_VERSION_MAJOR;
00558         veStr.minor = PROTOCOL_VERSION_MINOR;
00559         veStr.rv = SCARD_S_SUCCESS;
00560 
00561         rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
00562             &veStr);
00563         if (rv != SCARD_S_SUCCESS)
00564             return rv;
00565 
00566         /* Read a message from the server */
00567         rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
00568         if (rv != SCARD_S_SUCCESS)
00569         {
00570             Log1(PCSC_LOG_CRITICAL,
00571                 "Your pcscd is too old and does not support CMD_VERSION");
00572             return SCARD_F_COMM_ERROR;
00573         }
00574 
00575         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00576             veStr.major, veStr.minor);
00577 
00578         if (veStr.rv != SCARD_S_SUCCESS)
00579             return veStr.rv;
00580     }
00581 
00582 again:
00583     /*
00584      * Try to establish an Application Context with the server
00585      */
00586     scEstablishStruct.dwScope = dwScope;
00587     scEstablishStruct.hContext = 0;
00588     scEstablishStruct.rv = SCARD_S_SUCCESS;
00589 
00590     rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
00591         sizeof(scEstablishStruct), (void *) &scEstablishStruct);
00592 
00593     if (rv != SCARD_S_SUCCESS)
00594         return rv;
00595 
00596     /*
00597      * Read the response from the server
00598      */
00599     rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
00600         dwClientID);
00601 
00602     if (rv != SCARD_S_SUCCESS)
00603         return rv;
00604 
00605     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00606         return scEstablishStruct.rv;
00607 
00608     /* check we do not reuse an existing hContext */
00609     if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
00610         /* we do not need to release the allocated context since
00611          * SCardReleaseContext() does nothing on the server side */
00612         goto again;
00613 
00614     *phContext = scEstablishStruct.hContext;
00615 
00616     /*
00617      * Allocate the new hContext - if allocator full return an error
00618      */
00619     rv = SCardAddContext(*phContext, dwClientID);
00620 
00621     return rv;
00622 }
00623 
00645 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00646 {
00647     LONG rv;
00648     struct release_struct scReleaseStruct;
00649     SCONTEXTMAP * currentContextMap;
00650 
00651     API_TRACE_IN("%ld", hContext)
00652     PROFILE_START
00653 
00654     /*
00655      * Make sure this context has been opened
00656      * and get currentContextMap
00657      */
00658     currentContextMap = SCardGetContext(hContext);
00659     if (NULL == currentContextMap)
00660     {
00661         rv = SCARD_E_INVALID_HANDLE;
00662         goto error;
00663     }
00664 
00665     (void)pthread_mutex_lock(currentContextMap->mMutex);
00666 
00667     /* check the context is still opened */
00668     currentContextMap = SCardGetContext(hContext);
00669     if (NULL == currentContextMap)
00670         /* the context is now invalid
00671          * -> another thread may have called SCardReleaseContext
00672          * -> so the mMutex has been unlocked */
00673     {
00674         rv = SCARD_E_INVALID_HANDLE;
00675         goto error;
00676     }
00677 
00678     scReleaseStruct.hContext = hContext;
00679     scReleaseStruct.rv = SCARD_S_SUCCESS;
00680 
00681     rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
00682         currentContextMap->dwClientID,
00683         sizeof(scReleaseStruct), (void *) &scReleaseStruct);
00684 
00685     if (rv != SCARD_S_SUCCESS)
00686         goto end;
00687 
00688     /*
00689      * Read a message from the server
00690      */
00691     rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
00692         currentContextMap->dwClientID);
00693 
00694     if (rv != SCARD_S_SUCCESS)
00695         goto end;
00696 
00697     rv = scReleaseStruct.rv;
00698 end:
00699     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00700 
00701     /*
00702      * Remove the local context from the stack
00703      */
00704     (void)SCardLockThread();
00705     (void)SCardRemoveContext(hContext);
00706     (void)SCardUnlockThread();
00707 
00708 error:
00709     PROFILE_END(rv)
00710     API_TRACE_OUT("")
00711 
00712     return rv;
00713 }
00714 
00771 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00772     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00773     LPDWORD pdwActiveProtocol)
00774 {
00775     LONG rv;
00776     struct connect_struct scConnectStruct;
00777     SCONTEXTMAP * currentContextMap;
00778 
00779     PROFILE_START
00780     API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
00781 
00782     /*
00783      * Check for NULL parameters
00784      */
00785     if (phCard == NULL || pdwActiveProtocol == NULL)
00786         return SCARD_E_INVALID_PARAMETER;
00787     else
00788         *phCard = 0;
00789 
00790     if (szReader == NULL)
00791         return SCARD_E_UNKNOWN_READER;
00792 
00793     /*
00794      * Check for uninitialized strings
00795      */
00796     if (strlen(szReader) > MAX_READERNAME)
00797         return SCARD_E_INVALID_VALUE;
00798 
00799     /*
00800      * Make sure this context has been opened
00801      */
00802     currentContextMap = SCardGetContext(hContext);
00803     if (NULL == currentContextMap)
00804         return SCARD_E_INVALID_HANDLE;
00805 
00806     (void)pthread_mutex_lock(currentContextMap->mMutex);
00807 
00808     /* check the context is still opened */
00809     currentContextMap = SCardGetContext(hContext);
00810     if (NULL == currentContextMap)
00811         /* the context is now invalid
00812          * -> another thread may have called SCardReleaseContext
00813          * -> so the mMutex has been unlocked */
00814         return SCARD_E_INVALID_HANDLE;
00815 
00816     strlcpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
00817 
00818     scConnectStruct.hContext = hContext;
00819     scConnectStruct.dwShareMode = dwShareMode;
00820     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00821     scConnectStruct.hCard = 0;
00822     scConnectStruct.dwActiveProtocol = 0;
00823     scConnectStruct.rv = SCARD_S_SUCCESS;
00824 
00825     rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
00826         sizeof(scConnectStruct), (void *) &scConnectStruct);
00827 
00828     if (rv != SCARD_S_SUCCESS)
00829         goto end;
00830 
00831     /*
00832      * Read a message from the server
00833      */
00834     rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
00835         currentContextMap->dwClientID);
00836 
00837     if (rv != SCARD_S_SUCCESS)
00838         goto end;
00839 
00840     *phCard = scConnectStruct.hCard;
00841     *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
00842 
00843     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00844     {
00845         /*
00846          * Keep track of the handle locally
00847          */
00848         rv = SCardAddHandle(*phCard, currentContextMap, szReader);
00849     }
00850     else
00851         rv = scConnectStruct.rv;
00852 
00853 end:
00854     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00855 
00856     PROFILE_END(rv)
00857     API_TRACE_OUT("%d", *pdwActiveProtocol)
00858 
00859     return rv;
00860 }
00861 
00935 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
00936     DWORD dwPreferredProtocols, DWORD dwInitialization,
00937     LPDWORD pdwActiveProtocol)
00938 {
00939     LONG rv;
00940     struct reconnect_struct scReconnectStruct;
00941     SCONTEXTMAP * currentContextMap;
00942     CHANNEL_MAP * pChannelMap;
00943 
00944     PROFILE_START
00945 
00946     if (pdwActiveProtocol == NULL)
00947         return SCARD_E_INVALID_PARAMETER;
00948 
00949     /*
00950      * Make sure this handle has been opened
00951      */
00952     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
00953         &pChannelMap);
00954     if (rv == -1)
00955         return SCARD_E_INVALID_HANDLE;
00956 
00957     (void)pthread_mutex_lock(currentContextMap->mMutex);
00958 
00959     /* check the handle is still valid */
00960     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
00961         &pChannelMap);
00962     if (rv == -1)
00963         /* the handle is now invalid
00964          * -> another thread may have called SCardReleaseContext
00965          * -> so the mMutex has been unlocked */
00966         return SCARD_E_INVALID_HANDLE;
00967 
00968     /* Retry loop for blocking behaviour */
00969 retry:
00970 
00971     scReconnectStruct.hCard = hCard;
00972     scReconnectStruct.dwShareMode = dwShareMode;
00973     scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00974     scReconnectStruct.dwInitialization = dwInitialization;
00975     scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
00976     scReconnectStruct.rv = SCARD_S_SUCCESS;
00977 
00978     rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
00979         sizeof(scReconnectStruct), (void *) &scReconnectStruct);
00980 
00981     if (rv != SCARD_S_SUCCESS)
00982         goto end;
00983 
00984     /*
00985      * Read a message from the server
00986      */
00987     rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
00988         currentContextMap->dwClientID);
00989 
00990     if (rv != SCARD_S_SUCCESS)
00991         goto end;
00992 
00993     rv = scReconnectStruct.rv;
00994 
00995     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
00996     {
00997         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
00998         goto retry;
00999     }
01000 
01001     *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
01002 
01003 end:
01004     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01005 
01006     PROFILE_END(rv)
01007 
01008     return rv;
01009 }
01010 
01042 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01043 {
01044     LONG rv;
01045     struct disconnect_struct scDisconnectStruct;
01046     SCONTEXTMAP * currentContextMap;
01047     CHANNEL_MAP * pChannelMap;
01048 
01049     PROFILE_START
01050     API_TRACE_IN("%ld %ld", hCard, dwDisposition)
01051 
01052     /*
01053      * Make sure this handle has been opened
01054      */
01055     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01056         &pChannelMap);
01057     if (rv == -1)
01058     {
01059         rv = SCARD_E_INVALID_HANDLE;
01060         goto error;
01061     }
01062 
01063     (void)pthread_mutex_lock(currentContextMap->mMutex);
01064 
01065     /* check the handle is still valid */
01066     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01067         &pChannelMap);
01068     if (rv == -1)
01069         /* the handle is now invalid
01070          * -> another thread may have called SCardReleaseContext
01071          * -> so the mMutex has been unlocked */
01072     {
01073         rv = SCARD_E_INVALID_HANDLE;
01074         goto error;
01075     }
01076 
01077     scDisconnectStruct.hCard = hCard;
01078     scDisconnectStruct.dwDisposition = dwDisposition;
01079     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01080 
01081     rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
01082         sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
01083 
01084     if (rv != SCARD_S_SUCCESS)
01085         goto end;
01086 
01087     /*
01088      * Read a message from the server
01089      */
01090     rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
01091         currentContextMap->dwClientID);
01092 
01093     if (rv != SCARD_S_SUCCESS)
01094         goto end;
01095 
01096     if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
01097         (void)SCardRemoveHandle(hCard);
01098     rv = scDisconnectStruct.rv;
01099 
01100 end:
01101     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01102 
01103 error:
01104     PROFILE_END(rv)
01105     API_TRACE_OUT("")
01106 
01107     return rv;
01108 }
01109 
01145 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01146 {
01147 
01148     LONG rv;
01149     struct begin_struct scBeginStruct;
01150     SCONTEXTMAP * currentContextMap;
01151     CHANNEL_MAP * pChannelMap;
01152 
01153     PROFILE_START
01154 
01155     /*
01156      * Make sure this handle has been opened
01157      */
01158     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01159         &pChannelMap);
01160     if (rv == -1)
01161         return SCARD_E_INVALID_HANDLE;
01162 
01163     (void)pthread_mutex_lock(currentContextMap->mMutex);
01164 
01165     /* check the handle is still valid */
01166     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01167         &pChannelMap);
01168     if (rv == -1)
01169         /* the handle is now invalid
01170          * -> another thread may have called SCardReleaseContext
01171          * -> so the mMutex has been unlocked */
01172         return SCARD_E_INVALID_HANDLE;
01173 
01174     scBeginStruct.hCard = hCard;
01175     scBeginStruct.rv = SCARD_S_SUCCESS;
01176 
01177     /*
01178      * Query the server every so often until the sharing violation ends
01179      * and then hold the lock for yourself.
01180      */
01181 
01182     do
01183     {
01184         rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
01185             currentContextMap->dwClientID,
01186             sizeof(scBeginStruct), (void *) &scBeginStruct);
01187 
01188         if (rv != SCARD_S_SUCCESS)
01189             goto end;
01190 
01191         /*
01192          * Read a message from the server
01193          */
01194         rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
01195             currentContextMap->dwClientID);
01196 
01197         if (rv != SCARD_S_SUCCESS)
01198             goto end;
01199 
01200         rv = scBeginStruct.rv;
01201     }
01202     while (SCARD_E_SHARING_VIOLATION == rv);
01203 
01204 end:
01205     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01206 
01207     PROFILE_END(rv)
01208 
01209     return rv;
01210 }
01211 
01252 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01253 {
01254     LONG rv;
01255     struct end_struct scEndStruct;
01256     int randnum;
01257     SCONTEXTMAP * currentContextMap;
01258     CHANNEL_MAP * pChannelMap;
01259 
01260     PROFILE_START
01261 
01262     /*
01263      * Make sure this handle has been opened
01264      */
01265     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01266         &pChannelMap);
01267     if (rv == -1)
01268         return SCARD_E_INVALID_HANDLE;
01269 
01270     (void)pthread_mutex_lock(currentContextMap->mMutex);
01271 
01272     /* check the handle is still valid */
01273     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01274         &pChannelMap);
01275     if (rv == -1)
01276         /* the handle is now invalid
01277          * -> another thread may have called SCardReleaseContext
01278          * -> so the mMutex has been unlocked */
01279         return SCARD_E_INVALID_HANDLE;
01280 
01281     scEndStruct.hCard = hCard;
01282     scEndStruct.dwDisposition = dwDisposition;
01283     scEndStruct.rv = SCARD_S_SUCCESS;
01284 
01285     rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
01286         currentContextMap->dwClientID,
01287         sizeof(scEndStruct), (void *) &scEndStruct);
01288 
01289     if (rv != SCARD_S_SUCCESS)
01290         goto end;
01291 
01292     /*
01293      * Read a message from the server
01294      */
01295     rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
01296         currentContextMap->dwClientID);
01297 
01298     if (rv != SCARD_S_SUCCESS)
01299         goto end;
01300 
01301     /*
01302      * This helps prevent starvation
01303      */
01304     randnum = SYS_RandomInt(1000, 10000);
01305     (void)SYS_USleep(randnum);
01306     rv = scEndStruct.rv;
01307 
01308 end:
01309     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01310 
01311     PROFILE_END(rv)
01312 
01313     return rv;
01314 }
01315 
01411 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
01412     LPDWORD pcchReaderLen, LPDWORD pdwState,
01413     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01414 {
01415     DWORD dwReaderLen, dwAtrLen;
01416     LONG rv;
01417     int i;
01418     struct status_struct scStatusStruct;
01419     SCONTEXTMAP * currentContextMap;
01420     CHANNEL_MAP * pChannelMap;
01421     char *r;
01422     char *bufReader = NULL;
01423     LPBYTE bufAtr = NULL;
01424     DWORD dummy = 0;
01425 
01426     PROFILE_START
01427 
01428     /* default output values */
01429     if (pdwState)
01430         *pdwState = 0;
01431 
01432     if (pdwProtocol)
01433         *pdwProtocol = 0;
01434 
01435     /* Check for NULL parameters */
01436     if (pcchReaderLen == NULL)
01437         pcchReaderLen = &dummy;
01438 
01439     if (pcbAtrLen == NULL)
01440         pcbAtrLen = &dummy;
01441 
01442     /* length passed from caller */
01443     dwReaderLen = *pcchReaderLen;
01444     dwAtrLen = *pcbAtrLen;
01445 
01446     *pcchReaderLen = 0;
01447     *pcbAtrLen = 0;
01448 
01449     /*
01450      * Make sure this handle has been opened
01451      */
01452     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01453         &pChannelMap);
01454     if (rv == -1)
01455         return SCARD_E_INVALID_HANDLE;
01456 
01457     (void)pthread_mutex_lock(currentContextMap->mMutex);
01458 
01459     /* check the handle is still valid */
01460     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01461         &pChannelMap);
01462     if (rv == -1)
01463         /* the handle is now invalid
01464          * -> another thread may have called SCardReleaseContext
01465          * -> so the mMutex has been unlocked */
01466         return SCARD_E_INVALID_HANDLE;
01467 
01468     /* synchronize reader states with daemon */
01469     rv = getReaderStates(currentContextMap);
01470     if (rv != SCARD_S_SUCCESS)
01471         goto end;
01472 
01473     r = pChannelMap->readerName;
01474     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01475     {
01476         /* by default r == NULL */
01477         if (r && strcmp(r, readerStates[i].readerName) == 0)
01478             break;
01479     }
01480 
01481     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01482     {
01483         rv = SCARD_E_READER_UNAVAILABLE;
01484         goto end;
01485     }
01486 
01487     /* Retry loop for blocking behaviour */
01488 retry:
01489 
01490     /* initialise the structure */
01491     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01492     scStatusStruct.hCard = hCard;
01493 
01494     rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
01495         sizeof(scStatusStruct), (void *) &scStatusStruct);
01496 
01497     if (rv != SCARD_S_SUCCESS)
01498         goto end;
01499 
01500     /*
01501      * Read a message from the server
01502      */
01503     rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
01504         currentContextMap->dwClientID);
01505 
01506     if (rv != SCARD_S_SUCCESS)
01507         goto end;
01508 
01509     rv = scStatusStruct.rv;
01510 
01511     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01512     {
01513         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01514         goto retry;
01515     }
01516 
01517     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01518     {
01519         /*
01520          * An event must have occurred
01521          */
01522         goto end;
01523     }
01524 
01525     /*
01526      * Now continue with the client side SCardStatus
01527      */
01528 
01529     *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
01530     *pcbAtrLen = readerStates[i].cardAtrLength;
01531 
01532     if (pdwState)
01533         *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
01534 
01535     if (pdwProtocol)
01536         *pdwProtocol = readerStates[i].cardProtocol;
01537 
01538     if (SCARD_AUTOALLOCATE == dwReaderLen)
01539     {
01540         dwReaderLen = *pcchReaderLen;
01541         bufReader = malloc(dwReaderLen);
01542         if (NULL == bufReader)
01543         {
01544             rv = SCARD_E_NO_MEMORY;
01545             goto end;
01546         }
01547         if (NULL == mszReaderName)
01548         {
01549             rv = SCARD_E_INVALID_PARAMETER;
01550             goto end;
01551         }
01552         *(char **)mszReaderName = bufReader;
01553     }
01554     else
01555         bufReader = mszReaderName;
01556 
01557     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01558     if (bufReader)
01559     {
01560         if (*pcchReaderLen > dwReaderLen)
01561             rv = SCARD_E_INSUFFICIENT_BUFFER;
01562 
01563         strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
01564     }
01565 
01566     if (SCARD_AUTOALLOCATE == dwAtrLen)
01567     {
01568         dwAtrLen = *pcbAtrLen;
01569         bufAtr = malloc(dwAtrLen);
01570         if (NULL == bufAtr)
01571         {
01572             rv = SCARD_E_NO_MEMORY;
01573             goto end;
01574         }
01575         if (NULL == pbAtr)
01576         {
01577             rv = SCARD_E_INVALID_PARAMETER;
01578             goto end;
01579         }
01580         *(LPBYTE *)pbAtr = bufAtr;
01581     }
01582     else
01583         bufAtr = pbAtr;
01584 
01585     if (bufAtr)
01586     {
01587         if (*pcbAtrLen > dwAtrLen)
01588             rv = SCARD_E_INSUFFICIENT_BUFFER;
01589 
01590         memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
01591     }
01592 
01593 end:
01594     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01595 
01596     PROFILE_END(rv)
01597 
01598     return rv;
01599 }
01600 
01694 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01695     SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
01696 {
01697     SCARD_READERSTATE *currReader;
01698     READER_STATE *rContext;
01699     long dwTime;
01700     DWORD dwBreakFlag = 0;
01701     unsigned int j;
01702     SCONTEXTMAP * currentContextMap;
01703     int currentReaderCount = 0;
01704     LONG rv = SCARD_S_SUCCESS;
01705 
01706     PROFILE_START
01707     API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
01708 #ifdef DO_TRACE
01709     for (j=0; j<cReaders; j++)
01710     {
01711         API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
01712             rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
01713     }
01714 #endif
01715 
01716     if ((rgReaderStates == NULL && cReaders > 0)
01717         || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
01718     {
01719         rv = SCARD_E_INVALID_PARAMETER;
01720         goto error;
01721     }
01722 
01723     /* Check the integrity of the reader states structures */
01724     for (j = 0; j < cReaders; j++)
01725     {
01726         if (rgReaderStates[j].szReader == NULL)
01727             return SCARD_E_INVALID_VALUE;
01728     }
01729 
01730     /* return if all readers are SCARD_STATE_IGNORE */
01731     if (cReaders > 0)
01732     {
01733         int nbNonIgnoredReaders = cReaders;
01734 
01735         for (j=0; j<cReaders; j++)
01736             if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
01737                 nbNonIgnoredReaders--;
01738 
01739         if (0 == nbNonIgnoredReaders)
01740         {
01741             rv = SCARD_S_SUCCESS;
01742             goto error;
01743         }
01744     }
01745     else
01746     {
01747         /* reader list is empty */
01748         rv = SCARD_S_SUCCESS;
01749         goto error;
01750     }
01751 
01752     /*
01753      * Make sure this context has been opened
01754      */
01755     currentContextMap = SCardGetContext(hContext);
01756     if (NULL == currentContextMap)
01757     {
01758         rv = SCARD_E_INVALID_HANDLE;
01759         goto error;
01760     }
01761 
01762     (void)pthread_mutex_lock(currentContextMap->mMutex);
01763 
01764     /* check the context is still opened */
01765     currentContextMap = SCardGetContext(hContext);
01766     if (NULL == currentContextMap)
01767         /* the context is now invalid
01768          * -> another thread may have called SCardReleaseContext
01769          * -> so the mMutex has been unlocked */
01770     {
01771         rv = SCARD_E_INVALID_HANDLE;
01772         goto error;
01773     }
01774 
01775     /* synchronize reader states with daemon */
01776     rv = getReaderStates(currentContextMap);
01777     if (rv != SCARD_S_SUCCESS)
01778         goto end;
01779 
01780     /* check all the readers are already known */
01781     for (j=0; j<cReaders; j++)
01782     {
01783         const char *readerName;
01784         int i;
01785 
01786         readerName = rgReaderStates[j].szReader;
01787         for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01788         {
01789             if (strcmp(readerName, readerStates[i].readerName) == 0)
01790                 break;
01791         }
01792 
01793         /* The requested reader name is not recognized */
01794         if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01795         {
01796             /* PnP special reader? */
01797             if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
01798             {
01799                 rv = SCARD_E_UNKNOWN_READER;
01800                 goto end;
01801             }
01802         }
01803     }
01804 
01805     /* Clear the event state for all readers */
01806     for (j = 0; j < cReaders; j++)
01807         rgReaderStates[j].dwEventState = 0;
01808 
01809     /* Now is where we start our event checking loop */
01810     Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
01811 
01812     /* Get the initial reader count on the system */
01813     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
01814         if (readerStates[j].readerName[0] != '\0')
01815             currentReaderCount++;
01816 
01817     /* catch possible sign extension problems from 32 to 64-bits integers */
01818     if ((DWORD)-1 == dwTimeout)
01819         dwTimeout = INFINITE;
01820     if (INFINITE == dwTimeout)
01821         dwTime = 60*1000;   /* "infinite" timeout */
01822     else
01823         dwTime = dwTimeout;
01824 
01825     j = 0;
01826     do
01827     {
01828         currReader = &rgReaderStates[j];
01829 
01830         /* Ignore for IGNORED readers */
01831         if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
01832         {
01833             const char *readerName;
01834             int i;
01835 
01836             /* Looks for correct readernames */
01837             readerName = currReader->szReader;
01838             for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01839             {
01840                 if (strcmp(readerName, readerStates[i].readerName) == 0)
01841                     break;
01842             }
01843 
01844             /* The requested reader name is not recognized */
01845             if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01846             {
01847                 /* PnP special reader? */
01848                 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
01849                 {
01850                     int k, newReaderCount = 0;
01851 
01852                     for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
01853                         if (readerStates[k].readerName[0] != '\0')
01854                             newReaderCount++;
01855 
01856                     if (newReaderCount != currentReaderCount)
01857                     {
01858                         Log1(PCSC_LOG_INFO, "Reader list changed");
01859                         currentReaderCount = newReaderCount;
01860 
01861                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01862                         dwBreakFlag = 1;
01863                     }
01864                 }
01865                 else
01866                 {
01867                     currReader->dwEventState =
01868                         SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE;
01869                     if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
01870                     {
01871                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01872                         /*
01873                          * Spec says use SCARD_STATE_IGNORE but a removed USB
01874                          * reader with eventState fed into currentState will
01875                          * be ignored forever
01876                          */
01877                         dwBreakFlag = 1;
01878                     }
01879                 }
01880             }
01881             else
01882             {
01883                 uint32_t readerState;
01884 
01885                 /* The reader has come back after being away */
01886                 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
01887                 {
01888                     currReader->dwEventState |= SCARD_STATE_CHANGED;
01889                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01890                     Log0(PCSC_LOG_DEBUG);
01891                     dwBreakFlag = 1;
01892                 }
01893 
01894                 /* Set the reader status structure */
01895                 rContext = &readerStates[i];
01896 
01897                 /* Now we check all the Reader States */
01898                 readerState = rContext->readerState;
01899 
01900                 /* only if current state has an non null event counter */
01901                 if (currReader->dwCurrentState & 0xFFFF0000)
01902                 {
01903                     unsigned int currentCounter;
01904 
01905                     currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
01906 
01907                     /* has the event counter changed since the last call? */
01908                     if (rContext->eventCounter != currentCounter)
01909                     {
01910                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01911                         Log0(PCSC_LOG_DEBUG);
01912                         dwBreakFlag = 1;
01913                     }
01914                 }
01915 
01916                 /* add an event counter in the upper word of dwEventState */
01917                 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
01918                     | (rContext->eventCounter << 16));
01919 
01920                 /* Check if the reader is in the correct state */
01921                 if (readerState & SCARD_UNKNOWN)
01922                 {
01923                     /* reader is in bad state */
01924                     currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
01925                     if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
01926                     {
01927                         /* App thinks reader is in good state and it is not */
01928                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01929                         Log0(PCSC_LOG_DEBUG);
01930                         dwBreakFlag = 1;
01931                     }
01932                 }
01933                 else
01934                 {
01935                     /* App thinks reader in bad state but it is not */
01936                     if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
01937                     {
01938                         currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
01939                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01940                         Log0(PCSC_LOG_DEBUG);
01941                         dwBreakFlag = 1;
01942                     }
01943                 }
01944 
01945                 /* Check for card presence in the reader */
01946                 if (readerState & SCARD_PRESENT)
01947                 {
01948                     /* card present but not yet powered up */
01949                     if (0 == rContext->cardAtrLength)
01950                         /* Allow the status thread to convey information */
01951                         (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
01952 
01953                     currReader->cbAtr = rContext->cardAtrLength;
01954                     memcpy(currReader->rgbAtr, rContext->cardAtr,
01955                         currReader->cbAtr);
01956                 }
01957                 else
01958                     currReader->cbAtr = 0;
01959 
01960                 /* Card is now absent */
01961                 if (readerState & SCARD_ABSENT)
01962                 {
01963                     currReader->dwEventState |= SCARD_STATE_EMPTY;
01964                     currReader->dwEventState &= ~SCARD_STATE_PRESENT;
01965                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
01966                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
01967                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01968                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
01969                     currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
01970                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
01971                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
01972 
01973                     /* After present the rest are assumed */
01974                     if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
01975                     {
01976                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01977                         Log0(PCSC_LOG_DEBUG);
01978                         dwBreakFlag = 1;
01979                     }
01980                 }
01981                 /* Card is now present */
01982                 else if (readerState & SCARD_PRESENT)
01983                 {
01984                     currReader->dwEventState |= SCARD_STATE_PRESENT;
01985                     currReader->dwEventState &= ~SCARD_STATE_EMPTY;
01986                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
01987                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
01988                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01989                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
01990                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
01991 
01992                     if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
01993                     {
01994                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01995                         Log0(PCSC_LOG_DEBUG);
01996                         dwBreakFlag = 1;
01997                     }
01998 
01999                     if (readerState & SCARD_SWALLOWED)
02000                     {
02001                         currReader->dwEventState |= SCARD_STATE_MUTE;
02002                         if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
02003                         {
02004                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02005                             Log0(PCSC_LOG_DEBUG);
02006                             dwBreakFlag = 1;
02007                         }
02008                     }
02009                     else
02010                     {
02011                         /* App thinks card is mute but it is not */
02012                         if (currReader->dwCurrentState & SCARD_STATE_MUTE)
02013                         {
02014                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02015                             Log0(PCSC_LOG_DEBUG);
02016                             dwBreakFlag = 1;
02017                         }
02018                     }
02019                 }
02020 
02021                 /* Now figure out sharing modes */
02022                 if (rContext->readerSharing == PCSCLITE_SHARING_EXCLUSIVE_CONTEXT)
02023                 {
02024                     currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
02025                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02026                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02027                     {
02028                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02029                         Log0(PCSC_LOG_DEBUG);
02030                         dwBreakFlag = 1;
02031                     }
02032                 }
02033                 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
02034                 {
02035                     /* A card must be inserted for it to be INUSE */
02036                     if (readerState & SCARD_PRESENT)
02037                     {
02038                         currReader->dwEventState |= SCARD_STATE_INUSE;
02039                         currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02040                         if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
02041                         {
02042                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02043                             Log0(PCSC_LOG_DEBUG);
02044                             dwBreakFlag = 1;
02045                         }
02046                     }
02047                 }
02048                 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
02049                 {
02050                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02051                     currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02052 
02053                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02054                     {
02055                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02056                         Log0(PCSC_LOG_DEBUG);
02057                         dwBreakFlag = 1;
02058                     }
02059                     else if (currReader-> dwCurrentState
02060                         & SCARD_STATE_EXCLUSIVE)
02061                     {
02062                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02063                         Log0(PCSC_LOG_DEBUG);
02064                         dwBreakFlag = 1;
02065                     }
02066                 }
02067 
02068                 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
02069                 {
02070                     /*
02071                      * Break out of the while .. loop and return status
02072                      * once all the status's for all readers is met
02073                      */
02074                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02075                     Log0(PCSC_LOG_DEBUG);
02076                     dwBreakFlag = 1;
02077                 }
02078             }   /* End of SCARD_STATE_UNKNOWN */
02079         }   /* End of SCARD_STATE_IGNORE */
02080 
02081         /* Counter and resetter */
02082         j++;
02083         if (j == cReaders)
02084         {
02085             /* go back to the first reader */
02086             j = 0;
02087 
02088             /* Declare all the break conditions */
02089 
02090             /* Break if UNAWARE is set and all readers have been checked */
02091             if (dwBreakFlag == 1)
02092                 break;
02093 
02094             /* Only sleep once for each cycle of reader checks. */
02095             {
02096                 struct wait_reader_state_change waitStatusStruct;
02097                 struct timeval before, after;
02098 
02099                 gettimeofday(&before, NULL);
02100 
02101                 waitStatusStruct.timeOut = dwTime;
02102                 waitStatusStruct.rv = SCARD_S_SUCCESS;
02103 
02104                 /* another thread can do SCardCancel() */
02105                 currentContextMap->cancellable = TRUE;
02106 
02107                 rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
02108                     currentContextMap->dwClientID,
02109                     sizeof(waitStatusStruct), &waitStatusStruct);
02110 
02111                 if (rv != SCARD_S_SUCCESS)
02112                     goto end;
02113 
02114                 /*
02115                  * Read a message from the server
02116                  */
02117                 rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
02118                     &waitStatusStruct, sizeof(waitStatusStruct),
02119                     currentContextMap->dwClientID, dwTime);
02120 
02121                 /* another thread can do SCardCancel() */
02122                 currentContextMap->cancellable = FALSE;
02123 
02124                 /* timeout */
02125                 if (SCARD_E_TIMEOUT == rv)
02126                 {
02127                     /* ask server to remove us from the event list */
02128                     rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
02129                         currentContextMap->dwClientID,
02130                         sizeof(waitStatusStruct), &waitStatusStruct);
02131 
02132                     if (rv != SCARD_S_SUCCESS)
02133                         goto end;
02134 
02135                     /* Read a message from the server */
02136                     rv = MessageReceive(&waitStatusStruct,
02137                         sizeof(waitStatusStruct),
02138                         currentContextMap->dwClientID);
02139 
02140                     if (rv != SCARD_S_SUCCESS)
02141                         goto end;
02142                 }
02143 
02144                 if (rv != SCARD_S_SUCCESS)
02145                     goto end;
02146 
02147                 /* an event occurs or SCardCancel() was called */
02148                 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
02149                 {
02150                     rv = waitStatusStruct.rv;
02151                     goto end;
02152                 }
02153 
02154                 /* synchronize reader states with daemon */
02155                 rv = getReaderStates(currentContextMap);
02156                 if (rv != SCARD_S_SUCCESS)
02157                     goto end;
02158 
02159                 if (INFINITE != dwTimeout)
02160                 {
02161                     long int diff;
02162 
02163                     gettimeofday(&after, NULL);
02164                     diff = time_sub(&after, &before);
02165                     dwTime -= diff/1000;
02166                 }
02167             }
02168 
02169             if (dwTimeout != INFINITE)
02170             {
02171                 /* If time is greater than timeout and all readers have been
02172                  * checked
02173                  */
02174                 if (dwTime <= 0)
02175                 {
02176                     rv = SCARD_E_TIMEOUT;
02177                     goto end;
02178                 }
02179             }
02180         }
02181     }
02182     while (1);
02183 
02184 end:
02185     Log1(PCSC_LOG_DEBUG, "Event Loop End");
02186 
02187     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02188 
02189 error:
02190     PROFILE_END(rv)
02191 #ifdef DO_TRACE
02192     for (j=0; j<cReaders; j++)
02193     {
02194         API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
02195             rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
02196     }
02197 #endif
02198 
02199     return rv;
02200 }
02201 
02252 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
02253     DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
02254     LPDWORD lpBytesReturned)
02255 {
02256     LONG rv;
02257     struct control_struct scControlStruct;
02258     SCONTEXTMAP * currentContextMap;
02259     CHANNEL_MAP * pChannelMap;
02260 
02261     PROFILE_START
02262 
02263     /* 0 bytes received by default */
02264     if (NULL != lpBytesReturned)
02265         *lpBytesReturned = 0;
02266 
02267     /*
02268      * Make sure this handle has been opened
02269      */
02270     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02271         &pChannelMap);
02272     if (rv == -1)
02273     {
02274         PROFILE_END(SCARD_E_INVALID_HANDLE)
02275         return SCARD_E_INVALID_HANDLE;
02276     }
02277 
02278     (void)pthread_mutex_lock(currentContextMap->mMutex);
02279 
02280     /* check the handle is still valid */
02281     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02282         &pChannelMap);
02283     if (rv == -1)
02284         /* the handle is now invalid
02285          * -> another thread may have called SCardReleaseContext
02286          * -> so the mMutex has been unlocked */
02287         return SCARD_E_INVALID_HANDLE;
02288 
02289     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02290         || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02291     {
02292         rv = SCARD_E_INSUFFICIENT_BUFFER;
02293         goto end;
02294     }
02295 
02296     scControlStruct.hCard = hCard;
02297     scControlStruct.dwControlCode = dwControlCode;
02298     scControlStruct.cbSendLength = cbSendLength;
02299     scControlStruct.cbRecvLength = cbRecvLength;
02300     scControlStruct.dwBytesReturned = 0;
02301     scControlStruct.rv = 0;
02302 
02303     rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
02304         sizeof(scControlStruct), &scControlStruct);
02305 
02306     if (rv != SCARD_S_SUCCESS)
02307         goto end;
02308 
02309     /* write the sent buffer */
02310     rv = MessageSend((char *)pbSendBuffer, cbSendLength,
02311         currentContextMap->dwClientID);
02312 
02313     if (rv != SCARD_S_SUCCESS)
02314         goto end;
02315 
02316     /*
02317      * Read a message from the server
02318      */
02319     rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
02320         currentContextMap->dwClientID);
02321 
02322     if (rv != SCARD_S_SUCCESS)
02323         goto end;
02324 
02325     if (SCARD_S_SUCCESS == scControlStruct.rv)
02326     {
02327         /* read the received buffer */
02328         rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
02329             currentContextMap->dwClientID);
02330 
02331         if (rv != SCARD_S_SUCCESS)
02332             goto end;
02333 
02334     }
02335 
02336     if (NULL != lpBytesReturned)
02337         *lpBytesReturned = scControlStruct.dwBytesReturned;
02338 
02339     rv = scControlStruct.rv;
02340 
02341 end:
02342     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02343 
02344     PROFILE_END(rv)
02345 
02346     return rv;
02347 }
02348 
02453 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
02454     LPDWORD pcbAttrLen)
02455 {
02456     LONG ret;
02457     unsigned char *buf = NULL;
02458 
02459     PROFILE_START
02460 
02461     if (NULL == pcbAttrLen)
02462     {
02463         ret = SCARD_E_INVALID_PARAMETER;
02464         goto end;
02465     }
02466 
02467     if (SCARD_AUTOALLOCATE == *pcbAttrLen)
02468     {
02469         if (NULL == pbAttr)
02470             return SCARD_E_INVALID_PARAMETER;
02471 
02472         *pcbAttrLen = MAX_BUFFER_SIZE;
02473         buf = malloc(*pcbAttrLen);
02474         if (NULL == buf)
02475         {
02476             ret = SCARD_E_NO_MEMORY;
02477             goto end;
02478         }
02479 
02480         *(unsigned char **)pbAttr = buf;
02481     }
02482     else
02483     {
02484         buf = pbAttr;
02485 
02486         /* if only get the length */
02487         if (NULL == pbAttr)
02488             /* use a reasonable size */
02489             *pcbAttrLen = MAX_BUFFER_SIZE;
02490     }
02491 
02492     ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
02493         pcbAttrLen);
02494 
02495 end:
02496     PROFILE_END(ret)
02497 
02498     return ret;
02499 }
02500 
02536 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
02537     DWORD cbAttrLen)
02538 {
02539     LONG ret;
02540 
02541     PROFILE_START
02542 
02543     if (NULL == pbAttr || 0 == cbAttrLen)
02544         return SCARD_E_INVALID_PARAMETER;
02545 
02546     ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
02547         &cbAttrLen);
02548 
02549     PROFILE_END(ret)
02550 
02551     return ret;
02552 }
02553 
02554 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
02555     LPBYTE pbAttr, LPDWORD pcbAttrLen)
02556 {
02557     LONG rv;
02558     struct getset_struct scGetSetStruct;
02559     SCONTEXTMAP * currentContextMap;
02560     CHANNEL_MAP * pChannelMap;
02561 
02562     /*
02563      * Make sure this handle has been opened
02564      */
02565     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02566         &pChannelMap);
02567     if (rv == -1)
02568         return SCARD_E_INVALID_HANDLE;
02569 
02570     (void)pthread_mutex_lock(currentContextMap->mMutex);
02571 
02572     /* check the handle is still valid */
02573     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02574         &pChannelMap);
02575     if (rv == -1)
02576         /* the handle is now invalid
02577          * -> another thread may have called SCardReleaseContext
02578          * -> so the mMutex has been unlocked */
02579         return SCARD_E_INVALID_HANDLE;
02580 
02581     if (*pcbAttrLen > MAX_BUFFER_SIZE)
02582     {
02583         rv = SCARD_E_INSUFFICIENT_BUFFER;
02584         goto end;
02585     }
02586 
02587     scGetSetStruct.hCard = hCard;
02588     scGetSetStruct.dwAttrId = dwAttrId;
02589     scGetSetStruct.cbAttrLen = *pcbAttrLen;
02590     scGetSetStruct.rv = SCARD_E_NO_SERVICE;
02591     memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
02592     if (SCARD_SET_ATTRIB == command)
02593         memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
02594 
02595     rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
02596         sizeof(scGetSetStruct), &scGetSetStruct);
02597 
02598     if (rv != SCARD_S_SUCCESS)
02599         goto end;
02600 
02601     /*
02602      * Read a message from the server
02603      */
02604     rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
02605         currentContextMap->dwClientID);
02606 
02607     if (rv != SCARD_S_SUCCESS)
02608         goto end;
02609 
02610     if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
02611     {
02612         /*
02613          * Copy and zero it so any secret information is not leaked
02614          */
02615         if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
02616         {
02617             scGetSetStruct.cbAttrLen = *pcbAttrLen;
02618             scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
02619         }
02620         else
02621             *pcbAttrLen = scGetSetStruct.cbAttrLen;
02622 
02623         if (pbAttr)
02624             memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
02625 
02626         memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
02627     }
02628     rv = scGetSetStruct.rv;
02629 
02630 end:
02631     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02632 
02633     return rv;
02634 }
02635 
02694 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
02695     LPCBYTE pbSendBuffer, DWORD cbSendLength,
02696     SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
02697     LPDWORD pcbRecvLength)
02698 {
02699     LONG rv;
02700     SCONTEXTMAP * currentContextMap;
02701     CHANNEL_MAP * pChannelMap;
02702     struct transmit_struct scTransmitStruct;
02703 
02704     PROFILE_START
02705 
02706     if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
02707             pcbRecvLength == NULL || pioSendPci == NULL)
02708         return SCARD_E_INVALID_PARAMETER;
02709 
02710     /*
02711      * Make sure this handle has been opened
02712      */
02713     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02714         &pChannelMap);
02715     if (rv == -1)
02716     {
02717         *pcbRecvLength = 0;
02718         PROFILE_END(SCARD_E_INVALID_HANDLE)
02719         return SCARD_E_INVALID_HANDLE;
02720     }
02721 
02722     (void)pthread_mutex_lock(currentContextMap->mMutex);
02723 
02724     /* check the handle is still valid */
02725     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02726         &pChannelMap);
02727     if (rv == -1)
02728         /* the handle is now invalid
02729          * -> another thread may have called SCardReleaseContext
02730          * -> so the mMutex has been unlocked */
02731         return SCARD_E_INVALID_HANDLE;
02732 
02733     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02734         || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02735     {
02736         rv = SCARD_E_INSUFFICIENT_BUFFER;
02737         goto end;
02738     }
02739 
02740     /* Retry loop for blocking behaviour */
02741 retry:
02742 
02743     scTransmitStruct.hCard = hCard;
02744     scTransmitStruct.cbSendLength = cbSendLength;
02745     scTransmitStruct.pcbRecvLength = *pcbRecvLength;
02746     scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
02747     scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
02748     scTransmitStruct.rv = SCARD_S_SUCCESS;
02749 
02750     if (pioRecvPci)
02751     {
02752         scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
02753         scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
02754     }
02755     else
02756     {
02757         scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
02758         scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
02759     }
02760 
02761     rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
02762         sizeof(scTransmitStruct), (void *) &scTransmitStruct);
02763 
02764     if (rv != SCARD_S_SUCCESS)
02765         goto end;
02766 
02767     /* write the sent buffer */
02768     rv = MessageSend((void *)pbSendBuffer, cbSendLength,
02769         currentContextMap->dwClientID);
02770 
02771     if (rv != SCARD_S_SUCCESS)
02772         goto end;
02773 
02774     /*
02775      * Read a message from the server
02776      */
02777     rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
02778         currentContextMap->dwClientID);
02779 
02780     if (rv != SCARD_S_SUCCESS)
02781         goto end;
02782 
02783     if (SCARD_S_SUCCESS == scTransmitStruct.rv)
02784     {
02785         /* read the received buffer */
02786         rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
02787             currentContextMap->dwClientID);
02788 
02789         if (rv != SCARD_S_SUCCESS)
02790             goto end;
02791 
02792         if (pioRecvPci)
02793         {
02794             pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
02795             pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
02796         }
02797     }
02798 
02799     rv = scTransmitStruct.rv;
02800 
02801     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
02802     {
02803         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
02804         goto retry;
02805     }
02806 
02807     *pcbRecvLength = scTransmitStruct.pcbRecvLength;
02808 
02809 end:
02810     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02811 
02812     PROFILE_END(rv)
02813 
02814     return rv;
02815 }
02816 
02867 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
02868     LPSTR mszReaders, LPDWORD pcchReaders)
02869 {
02870     DWORD dwReadersLen = 0;
02871     int i;
02872     SCONTEXTMAP * currentContextMap;
02873     LONG rv = SCARD_S_SUCCESS;
02874     char *buf = NULL;
02875 
02876     (void)mszGroups;
02877     PROFILE_START
02878     API_TRACE_IN("%ld", hContext)
02879 
02880     /*
02881      * Check for NULL parameters
02882      */
02883     if (pcchReaders == NULL)
02884         return SCARD_E_INVALID_PARAMETER;
02885 
02886     /*
02887      * Make sure this context has been opened
02888      */
02889     currentContextMap = SCardGetContext(hContext);
02890     if (NULL == currentContextMap)
02891     {
02892         PROFILE_END(SCARD_E_INVALID_HANDLE)
02893         return SCARD_E_INVALID_HANDLE;
02894     }
02895 
02896     (void)pthread_mutex_lock(currentContextMap->mMutex);
02897 
02898     /* check the context is still opened */
02899     currentContextMap = SCardGetContext(hContext);
02900     if (NULL == currentContextMap)
02901         /* the context is now invalid
02902          * -> another thread may have called SCardReleaseContext
02903          * -> so the mMutex has been unlocked */
02904         return SCARD_E_INVALID_HANDLE;
02905 
02906     /* synchronize reader states with daemon */
02907     rv = getReaderStates(currentContextMap);
02908     if (rv != SCARD_S_SUCCESS)
02909         goto end;
02910 
02911     dwReadersLen = 0;
02912     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
02913         if (readerStates[i].readerName[0] != '\0')
02914             dwReadersLen += strlen(readerStates[i].readerName) + 1;
02915 
02916     /* for the last NULL byte */
02917     dwReadersLen += 1;
02918 
02919     if (1 == dwReadersLen)
02920     {
02921         rv = SCARD_E_NO_READERS_AVAILABLE;
02922         goto end;
02923     }
02924 
02925     if (SCARD_AUTOALLOCATE == *pcchReaders)
02926     {
02927         buf = malloc(dwReadersLen);
02928         if (NULL == buf)
02929         {
02930             rv = SCARD_E_NO_MEMORY;
02931             goto end;
02932         }
02933         if (NULL == mszReaders)
02934         {
02935             rv = SCARD_E_INVALID_PARAMETER;
02936             goto end;
02937         }
02938         *(char **)mszReaders = buf;
02939     }
02940     else
02941     {
02942         buf = mszReaders;
02943 
02944         /* not enough place to store the reader names */
02945         if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
02946         {
02947             rv = SCARD_E_INSUFFICIENT_BUFFER;
02948             goto end;
02949         }
02950     }
02951 
02952     if (mszReaders == NULL) /* text array not allocated */
02953         goto end;
02954 
02955     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
02956     {
02957         if (readerStates[i].readerName[0] != '\0')
02958         {
02959             /*
02960              * Build the multi-string
02961              */
02962             strcpy(buf, readerStates[i].readerName);
02963             buf += strlen(readerStates[i].readerName)+1;
02964         }
02965     }
02966     *buf = '\0';    /* Add the last null */
02967 
02968 end:
02969     /* set the reader names length */
02970     *pcchReaders = dwReadersLen;
02971 
02972     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02973 
02974     PROFILE_END(rv)
02975     API_TRACE_OUT("%d", *pcchReaders)
02976 
02977     return rv;
02978 }
02979 
02993 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
02994 {
02995     LONG rv = SCARD_S_SUCCESS;
02996     SCONTEXTMAP * currentContextMap;
02997 
02998     PROFILE_START
02999 
03000     /*
03001      * Make sure this context has been opened
03002      */
03003     currentContextMap = SCardGetContext(hContext);
03004     if (NULL == currentContextMap)
03005         return SCARD_E_INVALID_HANDLE;
03006 
03007     free((void *)pvMem);
03008 
03009     PROFILE_END(rv)
03010 
03011     return rv;
03012 }
03013 
03065 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
03066     LPDWORD pcchGroups)
03067 {
03068     LONG rv = SCARD_S_SUCCESS;
03069     SCONTEXTMAP * currentContextMap;
03070     char *buf = NULL;
03071 
03072     PROFILE_START
03073 
03074     /* Multi-string with two trailing \0 */
03075     const char ReaderGroup[] = "SCard$DefaultReaders\0";
03076     const unsigned int dwGroups = sizeof(ReaderGroup);
03077 
03078     /*
03079      * Make sure this context has been opened
03080      */
03081     currentContextMap = SCardGetContext(hContext);
03082     if (NULL == currentContextMap)
03083         return SCARD_E_INVALID_HANDLE;
03084 
03085     (void)pthread_mutex_lock(currentContextMap->mMutex);
03086 
03087     /* check the context is still opened */
03088     currentContextMap = SCardGetContext(hContext);
03089     if (NULL == currentContextMap)
03090         /* the context is now invalid
03091          * -> another thread may have called SCardReleaseContext
03092          * -> so the mMutex has been unlocked */
03093         return SCARD_E_INVALID_HANDLE;
03094 
03095     if (SCARD_AUTOALLOCATE == *pcchGroups)
03096     {
03097         buf = malloc(dwGroups);
03098         if (NULL == buf)
03099         {
03100             rv = SCARD_E_NO_MEMORY;
03101             goto end;
03102         }
03103         if (NULL == mszGroups)
03104         {
03105             rv = SCARD_E_INVALID_PARAMETER;
03106             goto end;
03107         }
03108         *(char **)mszGroups = buf;
03109     }
03110     else
03111     {
03112         buf = mszGroups;
03113 
03114         if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
03115         {
03116             rv = SCARD_E_INSUFFICIENT_BUFFER;
03117             goto end;
03118         }
03119     }
03120 
03121     if (buf)
03122         memcpy(buf, ReaderGroup, dwGroups);
03123 
03124 end:
03125     *pcchGroups = dwGroups;
03126 
03127     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03128 
03129     PROFILE_END(rv)
03130 
03131     return rv;
03132 }
03133 
03163 LONG SCardCancel(SCARDCONTEXT hContext)
03164 {
03165     SCONTEXTMAP * currentContextMap;
03166     LONG rv = SCARD_S_SUCCESS;
03167     uint32_t dwClientID = 0;
03168     struct cancel_struct scCancelStruct;
03169 
03170     PROFILE_START
03171     API_TRACE_IN("%ld", hContext)
03172 
03173     /*
03174      * Make sure this context has been opened
03175      */
03176     currentContextMap = SCardGetContext(hContext);
03177     if (NULL == currentContextMap)
03178     {
03179         rv = SCARD_E_INVALID_HANDLE;
03180         goto error;
03181     }
03182 
03183     if (! currentContextMap->cancellable)
03184     {
03185         rv = SCARD_S_SUCCESS;
03186         goto error;
03187     }
03188 
03189     /* create a new connection to the server */
03190     if (ClientSetupSession(&dwClientID) != 0)
03191     {
03192         rv = SCARD_E_NO_SERVICE;
03193         goto error;
03194     }
03195 
03196     scCancelStruct.hContext = hContext;
03197     scCancelStruct.rv = SCARD_S_SUCCESS;
03198 
03199     rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
03200         sizeof(scCancelStruct), (void *) &scCancelStruct);
03201 
03202     if (rv != SCARD_S_SUCCESS)
03203         goto end;
03204 
03205     /*
03206      * Read a message from the server
03207      */
03208     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
03209 
03210     if (rv != SCARD_S_SUCCESS)
03211         goto end;
03212 
03213     rv = scCancelStruct.rv;
03214 end:
03215     ClientCloseSession(dwClientID);
03216 
03217 error:
03218     PROFILE_END(rv)
03219     API_TRACE_OUT("")
03220 
03221     return rv;
03222 }
03223 
03247 LONG SCardIsValidContext(SCARDCONTEXT hContext)
03248 {
03249     LONG rv;
03250     SCONTEXTMAP * currentContextMap;
03251 
03252     PROFILE_START
03253     API_TRACE_IN("%ld", hContext)
03254 
03255     rv = SCARD_S_SUCCESS;
03256 
03257     /*
03258      * Make sure this context has been opened
03259      */
03260     currentContextMap = SCardGetContext(hContext);
03261     if (currentContextMap == NULL)
03262         rv = SCARD_E_INVALID_HANDLE;
03263 
03264     PROFILE_END(rv)
03265     API_TRACE_OUT("")
03266 
03267     return rv;
03268 }
03269 
03286 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
03287 {
03288     int lrv;
03289     SCONTEXTMAP * newContextMap;
03290 
03291     newContextMap = malloc(sizeof(SCONTEXTMAP));
03292     if (NULL == newContextMap)
03293         return SCARD_E_NO_MEMORY;
03294 
03295     Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
03296     newContextMap->hContext = hContext;
03297     newContextMap->dwClientID = dwClientID;
03298     newContextMap->cancellable = FALSE;
03299 
03300     newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
03301     if (NULL == newContextMap->mMutex)
03302     {
03303         Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%p", newContextMap);
03304         free(newContextMap);
03305         return SCARD_E_NO_MEMORY;
03306     }
03307     (void)pthread_mutex_init(newContextMap->mMutex, NULL);
03308 
03309     lrv = list_init(&(newContextMap->channelMapList));
03310     if (lrv < 0)
03311     {
03312         Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
03313         goto error;
03314     }
03315 
03316     lrv = list_attributes_seeker(&(newContextMap->channelMapList),
03317         CHANNEL_MAP_seeker);
03318     if (lrv <0)
03319     {
03320         Log2(PCSC_LOG_CRITICAL,
03321             "list_attributes_seeker failed with return value: %d", lrv);
03322         list_destroy(&(newContextMap->channelMapList));
03323         goto error;
03324     }
03325 
03326     lrv = list_append(&contextMapList, newContextMap);
03327     if (lrv < 0)
03328     {
03329         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
03330             lrv);
03331         list_destroy(&(newContextMap->channelMapList));
03332         goto error;
03333     }
03334 
03335     return SCARD_S_SUCCESS;
03336 
03337 error:
03338 
03339     (void)pthread_mutex_destroy(newContextMap->mMutex);
03340     free(newContextMap->mMutex);
03341     free(newContextMap);
03342 
03343     return SCARD_E_NO_MEMORY;
03344 }
03345 
03358 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT hContext)
03359 {
03360     SCONTEXTMAP * currentContextMap;
03361 
03362     (void)SCardLockThread();
03363     currentContextMap = SCardGetContextTH(hContext);
03364     (void)SCardUnlockThread();
03365 
03366     return currentContextMap;
03367 }
03368 
03381 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext)
03382 {
03383     return list_seek(&contextMapList, &hContext);
03384 }
03385 
03395 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
03396 {
03397     SCONTEXTMAP * currentContextMap;
03398     currentContextMap = SCardGetContextTH(hContext);
03399 
03400     if (NULL == currentContextMap)
03401         return SCARD_E_INVALID_HANDLE;
03402     else
03403         return SCardCleanContext(currentContextMap);
03404 }
03405 
03406 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
03407 {
03408     int list_index, lrv;
03409     int listSize;
03410     CHANNEL_MAP * currentChannelMap;
03411 
03412     targetContextMap->hContext = 0;
03413     (void)ClientCloseSession(targetContextMap->dwClientID);
03414     targetContextMap->dwClientID = 0;
03415     (void)pthread_mutex_destroy(targetContextMap->mMutex);
03416     free(targetContextMap->mMutex);
03417     targetContextMap->mMutex = NULL;
03418 
03419     listSize = list_size(&(targetContextMap->channelMapList));
03420     for (list_index = 0; list_index < listSize; list_index++)
03421     {
03422         currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
03423             list_index);
03424         if (NULL == currentChannelMap)
03425         {
03426             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03427                 list_index);
03428             continue;
03429         }
03430         else
03431         {
03432             free(currentChannelMap->readerName);
03433             free(currentChannelMap);
03434         }
03435 
03436     }
03437     list_destroy(&(targetContextMap->channelMapList));
03438 
03439     lrv = list_delete(&contextMapList, targetContextMap);
03440     if (lrv < 0)
03441     {
03442         Log2(PCSC_LOG_CRITICAL,
03443             "list_delete failed with return value: %d", lrv);
03444     }
03445 
03446     free(targetContextMap);
03447 
03448     return SCARD_S_SUCCESS;
03449 }
03450 
03451 /*
03452  * Functions for managing hCard values returned from SCardConnect.
03453  */
03454 
03455 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
03456     LPCSTR readerName)
03457 {
03458     CHANNEL_MAP * newChannelMap;
03459     int lrv = -1;
03460 
03461     newChannelMap = malloc(sizeof(CHANNEL_MAP));
03462     if (NULL == newChannelMap)
03463         return SCARD_E_NO_MEMORY;
03464 
03465     newChannelMap->hCard = hCard;
03466     newChannelMap->readerName = strdup(readerName);
03467 
03468     lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
03469     if (lrv < 0)
03470     {
03471         free(newChannelMap->readerName);
03472         free(newChannelMap);
03473         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
03474             lrv);
03475         return SCARD_E_NO_MEMORY;
03476     }
03477 
03478     return SCARD_S_SUCCESS;
03479 }
03480 
03481 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
03482 {
03483     SCONTEXTMAP * currentContextMap;
03484     CHANNEL_MAP * currentChannelMap;
03485     int lrv;
03486     LONG rv;
03487 
03488     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
03489         &currentChannelMap);
03490     if (rv == -1)
03491         return SCARD_E_INVALID_HANDLE;
03492 
03493     free(currentChannelMap->readerName);
03494 
03495     lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
03496     if (lrv < 0)
03497     {
03498         Log2(PCSC_LOG_CRITICAL,
03499             "list_delete failed with return value: %d", lrv);
03500     }
03501 
03502     free(currentChannelMap);
03503 
03504     return SCARD_S_SUCCESS;
03505 }
03506 
03507 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
03508     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03509 {
03510     LONG rv;
03511 
03512     if (0 == hCard)
03513         return -1;
03514 
03515     (void)SCardLockThread();
03516     rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
03517         targetChannelMap);
03518     (void)SCardUnlockThread();
03519 
03520     return rv;
03521 }
03522 
03523 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
03524     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03525 {
03526     int listSize;
03527     int list_index;
03528     SCONTEXTMAP * currentContextMap;
03529     CHANNEL_MAP * currentChannelMap;
03530 
03531     /* Best to get the caller a crash early if we fail unsafely */
03532     *targetContextMap = NULL;
03533     *targetChannelMap = NULL;
03534 
03535     listSize = list_size(&contextMapList);
03536 
03537     for (list_index = 0; list_index < listSize; list_index++)
03538     {
03539         currentContextMap = list_get_at(&contextMapList, list_index);
03540         if (currentContextMap == NULL)
03541         {
03542             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03543                 list_index);
03544             continue;
03545         }
03546         currentChannelMap = list_seek(&(currentContextMap->channelMapList),
03547             &hCard);
03548         if (currentChannelMap != NULL)
03549         {
03550             *targetContextMap = currentContextMap;
03551             *targetChannelMap = currentChannelMap;
03552             return SCARD_S_SUCCESS;
03553         }
03554     }
03555 
03556     return -1;
03557 }
03558 
03570 LONG SCardCheckDaemonAvailability(void)
03571 {
03572     LONG rv;
03573     struct stat statBuffer;
03574     char *socketName;
03575 
03576     socketName = getSocketName();
03577     rv = stat(socketName, &statBuffer);
03578 
03579     if (rv != 0)
03580     {
03581         Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
03582             socketName, strerror(errno));
03583         return SCARD_E_NO_SERVICE;
03584     }
03585 
03586     return SCARD_S_SUCCESS;
03587 }
03588 
03589 static void SCardInvalidateHandles(void)
03590 {
03591     /* invalid all handles */
03592     (void)SCardLockThread();
03593 
03594     while (list_size(&contextMapList) != 0)
03595     {
03596         SCONTEXTMAP * currentContextMap;
03597 
03598         currentContextMap = list_get_at(&contextMapList, 0);
03599         if (currentContextMap != NULL)
03600             (void)SCardCleanContext(currentContextMap);
03601         else
03602             Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
03603     }
03604 
03605     (void)SCardUnlockThread();
03606 }
03607 
03608 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
03609 {
03610     int32_t dwClientID = currentContextMap->dwClientID;
03611     LONG rv;
03612 
03613     rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
03614     if (rv != SCARD_S_SUCCESS)
03615         return rv;
03616 
03617     /* Read a message from the server */
03618     rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
03619     if (rv != SCARD_S_SUCCESS)
03620         return rv;
03621 
03622     return SCARD_S_SUCCESS;
03623 }
03624