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