pcsc-lite  1.7.4
winscard_clnt.c
Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 1999-2004
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2003-2004
00007  *  Damien Sauveron <damien.sauveron@labri.fr>
00008  * Copyright (C) 2005
00009  *  Martin Paljak <martin@paljak.pri.ee>
00010  * Copyright (C) 2002-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 5797 2011-06-16 08:58:37Z 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 const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) };
00349 PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) };
00351 PCSC_API const 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 #ifdef ENABLE_AUTOSTART
00448     int daemon_launched = FALSE;
00449     int retries = 0;
00450 #endif
00451 
00452     API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
00453     PROFILE_START
00454 
00455 again:
00456     /* Check if the server is running */
00457     rv = SCardCheckDaemonAvailability();
00458     if (SCARD_E_INVALID_HANDLE == rv)
00459         /* we reconnected to a daemon or we got called from a forked child */
00460         rv = SCardCheckDaemonAvailability();
00461 
00462 #ifdef ENABLE_AUTOSTART
00463     if (SCARD_E_NO_SERVICE == rv)
00464     {
00465 launch:
00466         if (daemon_launched)
00467         {
00468             retries++;
00469             if (retries < 50)   /* 50 x 100ms = 5 seconds */
00470             {
00471                 /* give some more time to the server to start */
00472                 SYS_USleep(100*1000);   /* 100 ms */
00473                 goto again;
00474             }
00475 
00476             /* the server failed to start (in time) */
00477             goto end;
00478         }
00479         else
00480         {
00481             int pid;
00482 
00483             pid = fork();
00484 
00485             if (pid < 0)
00486             {
00487                 Log2(PCSC_LOG_CRITICAL, "fork failed: %s", strerror(errno));
00488                 rv = SCARD_F_INTERNAL_ERROR;
00489                 goto end;
00490             }
00491 
00492             if (0 == pid)
00493             {
00494                 int i, max;
00495                 char *param = getenv("PCSCLITE_PCSCD_ARGS");
00496 
00497                 /* close all file handles except stdin, stdout and
00498                  * stderr so that pcscd does not confiscate ressources
00499                  * allocated by the application */
00500                 max = sysconf(_SC_OPEN_MAX);
00501                 if (-1 == max)
00502                     max = 1024;
00503                 for (i=3; i<max; i++)
00504                     (void)close(i);
00505 
00506                 /* son process */
00507                 execl(PCSCD_BINARY, "pcscd", "--auto-exit", param,
00508                     (char *)NULL);
00509                 Log2(PCSC_LOG_CRITICAL, "exec " PCSCD_BINARY " failed: %s",
00510                     strerror(errno));
00511                 exit(1);
00512             }
00513 
00514             /* father process */
00515             daemon_launched = TRUE;
00516 
00517             if (waitpid(pid, NULL, 0) < 0)
00518                 Log2(PCSC_LOG_CRITICAL, "waitpid failed: %s", strerror(errno));
00519 
00520             goto again;
00521         }
00522     }
00523 #endif
00524 
00525     if (rv != SCARD_S_SUCCESS)
00526         goto end;
00527 
00528     (void)SCardLockThread();
00529     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00530         pvReserved2, phContext);
00531     (void)SCardUnlockThread();
00532 
00533 #ifdef ENABLE_AUTOSTART
00534     /* SCardEstablishContextTH may fail if the previous pcscd crashed
00535      * without cleaning /var/run/pcscd/pcscd.comm */
00536     if (SCARD_E_NO_SERVICE == rv)
00537     {
00538         retries++;
00539         if (retries <= 1)
00540             goto launch;
00541     }
00542 #endif
00543 
00544 end:
00545     PROFILE_END(rv)
00546     API_TRACE_OUT("%ld", *phContext)
00547 
00548     return rv;
00549 }
00550 
00577 static LONG SCardEstablishContextTH(DWORD dwScope,
00578     /*@unused@*/ LPCVOID pvReserved1,
00579     /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00580 {
00581     LONG rv;
00582     struct establish_struct scEstablishStruct;
00583     uint32_t dwClientID = 0;
00584 
00585     (void)pvReserved1;
00586     (void)pvReserved2;
00587     if (phContext == NULL)
00588         return SCARD_E_INVALID_PARAMETER;
00589     else
00590         *phContext = 0;
00591 
00592     /*
00593      * Do this only once:
00594      * - Initialize context list.
00595      */
00596     if (isExecuted == 0)
00597     {
00598         int lrv;
00599 
00600         /* NOTE: The list will never be freed (No API call exists to
00601          * "close all contexts".
00602          * Applications which load and unload the library will leak
00603          * the list's internal structures. */
00604         lrv = list_init(&contextMapList);
00605         if (lrv < 0)
00606         {
00607             Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
00608                 lrv);
00609             return SCARD_E_NO_MEMORY;
00610         }
00611 
00612         lrv = list_attributes_seeker(&contextMapList,
00613                 SCONTEXTMAP_seeker);
00614         if (lrv <0)
00615         {
00616             Log2(PCSC_LOG_CRITICAL,
00617                 "list_attributes_seeker failed with return value: %d", lrv);
00618             list_destroy(&contextMapList);
00619             return SCARD_E_NO_MEMORY;
00620         }
00621 
00622         if (getenv("PCSCLITE_NO_BLOCKING"))
00623         {
00624             Log1(PCSC_LOG_INFO, "Disable shared blocking");
00625             sharing_shall_block = FALSE;
00626         }
00627 
00628         isExecuted = 1;
00629     }
00630 
00631 
00632     /* Establishes a connection to the server */
00633     if (ClientSetupSession(&dwClientID) != 0)
00634     {
00635         return SCARD_E_NO_SERVICE;
00636     }
00637 
00638     {   /* exchange client/server protocol versions */
00639         struct version_struct veStr;
00640 
00641         veStr.major = PROTOCOL_VERSION_MAJOR;
00642         veStr.minor = PROTOCOL_VERSION_MINOR;
00643         veStr.rv = SCARD_S_SUCCESS;
00644 
00645         rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
00646             &veStr);
00647         if (rv != SCARD_S_SUCCESS)
00648             return rv;
00649 
00650         /* Read a message from the server */
00651         rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
00652         if (rv != SCARD_S_SUCCESS)
00653         {
00654             Log1(PCSC_LOG_CRITICAL,
00655                 "Your pcscd is too old and does not support CMD_VERSION");
00656             return SCARD_F_COMM_ERROR;
00657         }
00658 
00659         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00660             veStr.major, veStr.minor);
00661 
00662         if (veStr.rv != SCARD_S_SUCCESS)
00663             return veStr.rv;
00664     }
00665 
00666 again:
00667     /*
00668      * Try to establish an Application Context with the server
00669      */
00670     scEstablishStruct.dwScope = dwScope;
00671     scEstablishStruct.hContext = 0;
00672     scEstablishStruct.rv = SCARD_S_SUCCESS;
00673 
00674     rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
00675         sizeof(scEstablishStruct), (void *) &scEstablishStruct);
00676 
00677     if (rv != SCARD_S_SUCCESS)
00678         return rv;
00679 
00680     /*
00681      * Read the response from the server
00682      */
00683     rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
00684         dwClientID);
00685 
00686     if (rv != SCARD_S_SUCCESS)
00687         return rv;
00688 
00689     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00690         return scEstablishStruct.rv;
00691 
00692     /* check we do not reuse an existing hContext */
00693     if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
00694         /* we do not need to release the allocated context since
00695          * SCardReleaseContext() does nothing on the server side */
00696         goto again;
00697 
00698     *phContext = scEstablishStruct.hContext;
00699 
00700     /*
00701      * Allocate the new hContext - if allocator full return an error
00702      */
00703     rv = SCardAddContext(*phContext, dwClientID);
00704 
00705     return rv;
00706 }
00707 
00729 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00730 {
00731     LONG rv;
00732     struct release_struct scReleaseStruct;
00733     SCONTEXTMAP * currentContextMap;
00734 
00735     API_TRACE_IN("%ld", hContext)
00736     PROFILE_START
00737 
00738     CHECK_SAME_PROCESS
00739 
00740     /*
00741      * Make sure this context has been opened
00742      * and get currentContextMap
00743      */
00744     currentContextMap = SCardGetContext(hContext);
00745     if (NULL == currentContextMap)
00746     {
00747         rv = SCARD_E_INVALID_HANDLE;
00748         goto error;
00749     }
00750 
00751     (void)pthread_mutex_lock(currentContextMap->mMutex);
00752 
00753     /* check the context is still opened */
00754     currentContextMap = SCardGetContext(hContext);
00755     if (NULL == currentContextMap)
00756         /* the context is now invalid
00757          * -> another thread may have called SCardReleaseContext
00758          * -> so the mMutex has been unlocked */
00759     {
00760         rv = SCARD_E_INVALID_HANDLE;
00761         goto error;
00762     }
00763 
00764     scReleaseStruct.hContext = hContext;
00765     scReleaseStruct.rv = SCARD_S_SUCCESS;
00766 
00767     rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
00768         currentContextMap->dwClientID,
00769         sizeof(scReleaseStruct), (void *) &scReleaseStruct);
00770 
00771     if (rv != SCARD_S_SUCCESS)
00772         goto end;
00773 
00774     /*
00775      * Read a message from the server
00776      */
00777     rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
00778         currentContextMap->dwClientID);
00779 
00780     if (rv != SCARD_S_SUCCESS)
00781         goto end;
00782 
00783     rv = scReleaseStruct.rv;
00784 end:
00785     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00786 
00787     /*
00788      * Remove the local context from the stack
00789      */
00790     (void)SCardLockThread();
00791     (void)SCardRemoveContext(hContext);
00792     (void)SCardUnlockThread();
00793 
00794 error:
00795     PROFILE_END(rv)
00796     API_TRACE_OUT("")
00797 
00798     return rv;
00799 }
00800 
00857 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00858     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00859     LPDWORD pdwActiveProtocol)
00860 {
00861     LONG rv;
00862     struct connect_struct scConnectStruct;
00863     SCONTEXTMAP * currentContextMap;
00864 
00865     PROFILE_START
00866     API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
00867 
00868     /*
00869      * Check for NULL parameters
00870      */
00871     if (phCard == NULL || pdwActiveProtocol == NULL)
00872         return SCARD_E_INVALID_PARAMETER;
00873     else
00874         *phCard = 0;
00875 
00876     if (szReader == NULL)
00877         return SCARD_E_UNKNOWN_READER;
00878 
00879     /*
00880      * Check for uninitialized strings
00881      */
00882     if (strlen(szReader) > MAX_READERNAME)
00883         return SCARD_E_INVALID_VALUE;
00884 
00885     CHECK_SAME_PROCESS
00886 
00887     /*
00888      * Make sure this context has been opened
00889      */
00890     currentContextMap = SCardGetContext(hContext);
00891     if (NULL == currentContextMap)
00892         return SCARD_E_INVALID_HANDLE;
00893 
00894     (void)pthread_mutex_lock(currentContextMap->mMutex);
00895 
00896     /* check the context is still opened */
00897     currentContextMap = SCardGetContext(hContext);
00898     if (NULL == currentContextMap)
00899         /* the context is now invalid
00900          * -> another thread may have called SCardReleaseContext
00901          * -> so the mMutex has been unlocked */
00902         return SCARD_E_INVALID_HANDLE;
00903 
00904     strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
00905 
00906     scConnectStruct.hContext = hContext;
00907     scConnectStruct.dwShareMode = dwShareMode;
00908     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00909     scConnectStruct.hCard = 0;
00910     scConnectStruct.dwActiveProtocol = 0;
00911     scConnectStruct.rv = SCARD_S_SUCCESS;
00912 
00913     rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
00914         sizeof(scConnectStruct), (void *) &scConnectStruct);
00915 
00916     if (rv != SCARD_S_SUCCESS)
00917         goto end;
00918 
00919     /*
00920      * Read a message from the server
00921      */
00922     rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
00923         currentContextMap->dwClientID);
00924 
00925     if (rv != SCARD_S_SUCCESS)
00926         goto end;
00927 
00928     *phCard = scConnectStruct.hCard;
00929     *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
00930 
00931     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00932     {
00933         /*
00934          * Keep track of the handle locally
00935          */
00936         rv = SCardAddHandle(*phCard, currentContextMap, szReader);
00937     }
00938     else
00939         rv = scConnectStruct.rv;
00940 
00941 end:
00942     (void)pthread_mutex_unlock(currentContextMap->mMutex);
00943 
00944     PROFILE_END(rv)
00945     API_TRACE_OUT("%d", *pdwActiveProtocol)
00946 
00947     return rv;
00948 }
00949 
01023 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
01024     DWORD dwPreferredProtocols, DWORD dwInitialization,
01025     LPDWORD pdwActiveProtocol)
01026 {
01027     LONG rv;
01028     struct reconnect_struct scReconnectStruct;
01029     SCONTEXTMAP * currentContextMap;
01030     CHANNEL_MAP * pChannelMap;
01031 
01032     PROFILE_START
01033 
01034     if (pdwActiveProtocol == NULL)
01035         return SCARD_E_INVALID_PARAMETER;
01036 
01037     CHECK_SAME_PROCESS
01038 
01039     /*
01040      * Make sure this handle has been opened
01041      */
01042     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01043         &pChannelMap);
01044     if (rv == -1)
01045         return SCARD_E_INVALID_HANDLE;
01046 
01047     (void)pthread_mutex_lock(currentContextMap->mMutex);
01048 
01049     /* check the handle is still valid */
01050     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01051         &pChannelMap);
01052     if (rv == -1)
01053         /* the handle is now invalid
01054          * -> another thread may have called SCardReleaseContext
01055          * -> so the mMutex has been unlocked */
01056         return SCARD_E_INVALID_HANDLE;
01057 
01058     /* Retry loop for blocking behaviour */
01059 retry:
01060 
01061     scReconnectStruct.hCard = hCard;
01062     scReconnectStruct.dwShareMode = dwShareMode;
01063     scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
01064     scReconnectStruct.dwInitialization = dwInitialization;
01065     scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
01066     scReconnectStruct.rv = SCARD_S_SUCCESS;
01067 
01068     rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
01069         sizeof(scReconnectStruct), (void *) &scReconnectStruct);
01070 
01071     if (rv != SCARD_S_SUCCESS)
01072         goto end;
01073 
01074     /*
01075      * Read a message from the server
01076      */
01077     rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
01078         currentContextMap->dwClientID);
01079 
01080     if (rv != SCARD_S_SUCCESS)
01081         goto end;
01082 
01083     rv = scReconnectStruct.rv;
01084 
01085     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01086     {
01087         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01088         goto retry;
01089     }
01090 
01091     *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
01092 
01093 end:
01094     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01095 
01096     PROFILE_END(rv)
01097 
01098     return rv;
01099 }
01100 
01132 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01133 {
01134     LONG rv;
01135     struct disconnect_struct scDisconnectStruct;
01136     SCONTEXTMAP * currentContextMap;
01137     CHANNEL_MAP * pChannelMap;
01138 
01139     PROFILE_START
01140     API_TRACE_IN("%ld %ld", hCard, dwDisposition)
01141 
01142     CHECK_SAME_PROCESS
01143 
01144     /*
01145      * Make sure this handle has been opened
01146      */
01147     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01148         &pChannelMap);
01149     if (rv == -1)
01150     {
01151         rv = SCARD_E_INVALID_HANDLE;
01152         goto error;
01153     }
01154 
01155     (void)pthread_mutex_lock(currentContextMap->mMutex);
01156 
01157     /* check the handle is still valid */
01158     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01159         &pChannelMap);
01160     if (rv == -1)
01161         /* the handle is now invalid
01162          * -> another thread may have called SCardReleaseContext
01163          * -> so the mMutex has been unlocked */
01164     {
01165         rv = SCARD_E_INVALID_HANDLE;
01166         goto error;
01167     }
01168 
01169     scDisconnectStruct.hCard = hCard;
01170     scDisconnectStruct.dwDisposition = dwDisposition;
01171     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01172 
01173     rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
01174         sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
01175 
01176     if (rv != SCARD_S_SUCCESS)
01177         goto end;
01178 
01179     /*
01180      * Read a message from the server
01181      */
01182     rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
01183         currentContextMap->dwClientID);
01184 
01185     if (rv != SCARD_S_SUCCESS)
01186         goto end;
01187 
01188     if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
01189         (void)SCardRemoveHandle(hCard);
01190     rv = scDisconnectStruct.rv;
01191 
01192 end:
01193     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01194 
01195 error:
01196     PROFILE_END(rv)
01197     API_TRACE_OUT("")
01198 
01199     return rv;
01200 }
01201 
01237 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01238 {
01239 
01240     LONG rv;
01241     struct begin_struct scBeginStruct;
01242     SCONTEXTMAP * currentContextMap;
01243     CHANNEL_MAP * pChannelMap;
01244 
01245     PROFILE_START
01246 
01247     CHECK_SAME_PROCESS
01248 
01249     /*
01250      * Make sure this handle has been opened
01251      */
01252     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01253         &pChannelMap);
01254     if (rv == -1)
01255         return SCARD_E_INVALID_HANDLE;
01256 
01257     (void)pthread_mutex_lock(currentContextMap->mMutex);
01258 
01259     /* check the handle is still valid */
01260     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01261         &pChannelMap);
01262     if (rv == -1)
01263         /* the handle is now invalid
01264          * -> another thread may have called SCardReleaseContext
01265          * -> so the mMutex has been unlocked */
01266         return SCARD_E_INVALID_HANDLE;
01267 
01268     scBeginStruct.hCard = hCard;
01269     scBeginStruct.rv = SCARD_S_SUCCESS;
01270 
01271     /*
01272      * Query the server every so often until the sharing violation ends
01273      * and then hold the lock for yourself.
01274      */
01275 
01276     do
01277     {
01278         rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
01279             currentContextMap->dwClientID,
01280             sizeof(scBeginStruct), (void *) &scBeginStruct);
01281 
01282         if (rv != SCARD_S_SUCCESS)
01283             goto end;
01284 
01285         /*
01286          * Read a message from the server
01287          */
01288         rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
01289             currentContextMap->dwClientID);
01290 
01291         if (rv != SCARD_S_SUCCESS)
01292             goto end;
01293 
01294         rv = scBeginStruct.rv;
01295     }
01296     while (SCARD_E_SHARING_VIOLATION == rv);
01297 
01298 end:
01299     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01300 
01301     PROFILE_END(rv)
01302 
01303     return rv;
01304 }
01305 
01346 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01347 {
01348     LONG rv;
01349     struct end_struct scEndStruct;
01350     int randnum;
01351     SCONTEXTMAP * currentContextMap;
01352     CHANNEL_MAP * pChannelMap;
01353 
01354     PROFILE_START
01355 
01356     CHECK_SAME_PROCESS
01357 
01358     /*
01359      * Make sure this handle has been opened
01360      */
01361     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01362         &pChannelMap);
01363     if (rv == -1)
01364         return SCARD_E_INVALID_HANDLE;
01365 
01366     (void)pthread_mutex_lock(currentContextMap->mMutex);
01367 
01368     /* check the handle is still valid */
01369     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01370         &pChannelMap);
01371     if (rv == -1)
01372         /* the handle is now invalid
01373          * -> another thread may have called SCardReleaseContext
01374          * -> so the mMutex has been unlocked */
01375         return SCARD_E_INVALID_HANDLE;
01376 
01377     scEndStruct.hCard = hCard;
01378     scEndStruct.dwDisposition = dwDisposition;
01379     scEndStruct.rv = SCARD_S_SUCCESS;
01380 
01381     rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
01382         currentContextMap->dwClientID,
01383         sizeof(scEndStruct), (void *) &scEndStruct);
01384 
01385     if (rv != SCARD_S_SUCCESS)
01386         goto end;
01387 
01388     /*
01389      * Read a message from the server
01390      */
01391     rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
01392         currentContextMap->dwClientID);
01393 
01394     if (rv != SCARD_S_SUCCESS)
01395         goto end;
01396 
01397     /*
01398      * This helps prevent starvation
01399      */
01400     randnum = SYS_RandomInt(1000, 10000);
01401     (void)SYS_USleep(randnum);
01402     rv = scEndStruct.rv;
01403 
01404 end:
01405     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01406 
01407     PROFILE_END(rv)
01408 
01409     return rv;
01410 }
01411 
01507 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
01508     LPDWORD pcchReaderLen, LPDWORD pdwState,
01509     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01510 {
01511     DWORD dwReaderLen, dwAtrLen;
01512     LONG rv;
01513     int i;
01514     struct status_struct scStatusStruct;
01515     SCONTEXTMAP * currentContextMap;
01516     CHANNEL_MAP * pChannelMap;
01517     char *r;
01518     char *bufReader = NULL;
01519     LPBYTE bufAtr = NULL;
01520     DWORD dummy = 0;
01521 
01522     PROFILE_START
01523 
01524     /* default output values */
01525     if (pdwState)
01526         *pdwState = 0;
01527 
01528     if (pdwProtocol)
01529         *pdwProtocol = 0;
01530 
01531     /* Check for NULL parameters */
01532     if (pcchReaderLen == NULL)
01533         pcchReaderLen = &dummy;
01534 
01535     if (pcbAtrLen == NULL)
01536         pcbAtrLen = &dummy;
01537 
01538     /* length passed from caller */
01539     dwReaderLen = *pcchReaderLen;
01540     dwAtrLen = *pcbAtrLen;
01541 
01542     *pcchReaderLen = 0;
01543     *pcbAtrLen = 0;
01544 
01545     CHECK_SAME_PROCESS
01546 
01547     /*
01548      * Make sure this handle has been opened
01549      */
01550     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01551         &pChannelMap);
01552     if (rv == -1)
01553         return SCARD_E_INVALID_HANDLE;
01554 
01555     (void)pthread_mutex_lock(currentContextMap->mMutex);
01556 
01557     /* check the handle is still valid */
01558     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
01559         &pChannelMap);
01560     if (rv == -1)
01561         /* the handle is now invalid
01562          * -> another thread may have called SCardReleaseContext
01563          * -> so the mMutex has been unlocked */
01564         return SCARD_E_INVALID_HANDLE;
01565 
01566     /* synchronize reader states with daemon */
01567     rv = getReaderStates(currentContextMap);
01568     if (rv != SCARD_S_SUCCESS)
01569         goto end;
01570 
01571     r = pChannelMap->readerName;
01572     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01573     {
01574         /* by default r == NULL */
01575         if (r && strcmp(r, readerStates[i].readerName) == 0)
01576             break;
01577     }
01578 
01579     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01580     {
01581         rv = SCARD_E_READER_UNAVAILABLE;
01582         goto end;
01583     }
01584 
01585     /* Retry loop for blocking behaviour */
01586 retry:
01587 
01588     /* initialise the structure */
01589     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01590     scStatusStruct.hCard = hCard;
01591 
01592     rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
01593         sizeof(scStatusStruct), (void *) &scStatusStruct);
01594 
01595     if (rv != SCARD_S_SUCCESS)
01596         goto end;
01597 
01598     /*
01599      * Read a message from the server
01600      */
01601     rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
01602         currentContextMap->dwClientID);
01603 
01604     if (rv != SCARD_S_SUCCESS)
01605         goto end;
01606 
01607     rv = scStatusStruct.rv;
01608 
01609     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
01610     {
01611         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
01612         goto retry;
01613     }
01614 
01615     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01616     {
01617         /*
01618          * An event must have occurred
01619          */
01620         goto end;
01621     }
01622 
01623     /*
01624      * Now continue with the client side SCardStatus
01625      */
01626 
01627     *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
01628     *pcbAtrLen = readerStates[i].cardAtrLength;
01629 
01630     if (pdwState)
01631         *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
01632 
01633     if (pdwProtocol)
01634         *pdwProtocol = readerStates[i].cardProtocol;
01635 
01636     if (SCARD_AUTOALLOCATE == dwReaderLen)
01637     {
01638         dwReaderLen = *pcchReaderLen;
01639         bufReader = malloc(dwReaderLen);
01640         if (NULL == bufReader)
01641         {
01642             rv = SCARD_E_NO_MEMORY;
01643             goto end;
01644         }
01645         if (NULL == mszReaderName)
01646         {
01647             rv = SCARD_E_INVALID_PARAMETER;
01648             goto end;
01649         }
01650         *(char **)mszReaderName = bufReader;
01651     }
01652     else
01653         bufReader = mszReaderName;
01654 
01655     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01656     if (bufReader)
01657     {
01658         if (*pcchReaderLen > dwReaderLen)
01659             rv = SCARD_E_INSUFFICIENT_BUFFER;
01660 
01661         strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
01662     }
01663 
01664     if (SCARD_AUTOALLOCATE == dwAtrLen)
01665     {
01666         dwAtrLen = *pcbAtrLen;
01667         bufAtr = malloc(dwAtrLen);
01668         if (NULL == bufAtr)
01669         {
01670             rv = SCARD_E_NO_MEMORY;
01671             goto end;
01672         }
01673         if (NULL == pbAtr)
01674         {
01675             rv = SCARD_E_INVALID_PARAMETER;
01676             goto end;
01677         }
01678         *(LPBYTE *)pbAtr = bufAtr;
01679     }
01680     else
01681         bufAtr = pbAtr;
01682 
01683     if (bufAtr)
01684     {
01685         if (*pcbAtrLen > dwAtrLen)
01686             rv = SCARD_E_INSUFFICIENT_BUFFER;
01687 
01688         memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
01689     }
01690 
01691 end:
01692     (void)pthread_mutex_unlock(currentContextMap->mMutex);
01693 
01694     PROFILE_END(rv)
01695 
01696     return rv;
01697 }
01698 
01795 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01796     SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
01797 {
01798     SCARD_READERSTATE *currReader;
01799     READER_STATE *rContext;
01800     long dwTime;
01801     DWORD dwBreakFlag = 0;
01802     unsigned int j;
01803     SCONTEXTMAP * currentContextMap;
01804     int currentReaderCount = 0;
01805     LONG rv = SCARD_S_SUCCESS;
01806 
01807     PROFILE_START
01808     API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
01809 #ifdef DO_TRACE
01810     for (j=0; j<cReaders; j++)
01811     {
01812         API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
01813             rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
01814     }
01815 #endif
01816 
01817     if ((rgReaderStates == NULL && cReaders > 0)
01818         || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
01819     {
01820         rv = SCARD_E_INVALID_PARAMETER;
01821         goto error;
01822     }
01823 
01824     /* Check the integrity of the reader states structures */
01825     for (j = 0; j < cReaders; j++)
01826     {
01827         if (rgReaderStates[j].szReader == NULL)
01828             return SCARD_E_INVALID_VALUE;
01829     }
01830 
01831     /* return if all readers are SCARD_STATE_IGNORE */
01832     if (cReaders > 0)
01833     {
01834         int nbNonIgnoredReaders = cReaders;
01835 
01836         for (j=0; j<cReaders; j++)
01837             if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
01838                 nbNonIgnoredReaders--;
01839 
01840         if (0 == nbNonIgnoredReaders)
01841         {
01842             rv = SCARD_S_SUCCESS;
01843             goto error;
01844         }
01845     }
01846     else
01847     {
01848         /* reader list is empty */
01849         rv = SCARD_S_SUCCESS;
01850         goto error;
01851     }
01852 
01853     CHECK_SAME_PROCESS
01854 
01855     /*
01856      * Make sure this context has been opened
01857      */
01858     currentContextMap = SCardGetContext(hContext);
01859     if (NULL == currentContextMap)
01860     {
01861         rv = SCARD_E_INVALID_HANDLE;
01862         goto error;
01863     }
01864 
01865     (void)pthread_mutex_lock(currentContextMap->mMutex);
01866 
01867     /* check the context is still opened */
01868     currentContextMap = SCardGetContext(hContext);
01869     if (NULL == currentContextMap)
01870         /* the context is now invalid
01871          * -> another thread may have called SCardReleaseContext
01872          * -> so the mMutex has been unlocked */
01873     {
01874         rv = SCARD_E_INVALID_HANDLE;
01875         goto error;
01876     }
01877 
01878     /* synchronize reader states with daemon */
01879     rv = getReaderStates(currentContextMap);
01880     if (rv != SCARD_S_SUCCESS)
01881         goto end;
01882 
01883     /* Clear the event state for all readers */
01884     for (j = 0; j < cReaders; j++)
01885         rgReaderStates[j].dwEventState = 0;
01886 
01887     /* Now is where we start our event checking loop */
01888     Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
01889 
01890     /* Get the initial reader count on the system */
01891     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
01892         if (readerStates[j].readerName[0] != '\0')
01893             currentReaderCount++;
01894 
01895     /* catch possible sign extension problems from 32 to 64-bits integers */
01896     if ((DWORD)-1 == dwTimeout)
01897         dwTimeout = INFINITE;
01898     if (INFINITE == dwTimeout)
01899         dwTime = 60*1000;   /* "infinite" timeout */
01900     else
01901         dwTime = dwTimeout;
01902 
01903     j = 0;
01904     do
01905     {
01906         currReader = &rgReaderStates[j];
01907 
01908         /* Ignore for IGNORED readers */
01909         if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
01910         {
01911             const char *readerName;
01912             int i;
01913 
01914             /* Looks for correct readernames */
01915             readerName = currReader->szReader;
01916             for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01917             {
01918                 if (strcmp(readerName, readerStates[i].readerName) == 0)
01919                     break;
01920             }
01921 
01922             /* The requested reader name is not recognized */
01923             if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01924             {
01925                 /* PnP special reader? */
01926                 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
01927                 {
01928                     int k, newReaderCount = 0;
01929 
01930                     for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
01931                         if (readerStates[k].readerName[0] != '\0')
01932                             newReaderCount++;
01933 
01934                     if (newReaderCount != currentReaderCount)
01935                     {
01936                         Log1(PCSC_LOG_INFO, "Reader list changed");
01937                         currentReaderCount = newReaderCount;
01938 
01939                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01940                         dwBreakFlag = 1;
01941                     }
01942                 }
01943                 else
01944                 {
01945                     currReader->dwEventState =
01946                         SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE;
01947                     if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
01948                     {
01949                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01950                         /*
01951                          * Spec says use SCARD_STATE_IGNORE but a removed USB
01952                          * reader with eventState fed into currentState will
01953                          * be ignored forever
01954                          */
01955                         dwBreakFlag = 1;
01956                     }
01957                 }
01958             }
01959             else
01960             {
01961                 uint32_t readerState;
01962 
01963                 /* The reader has come back after being away */
01964                 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
01965                 {
01966                     currReader->dwEventState |= SCARD_STATE_CHANGED;
01967                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
01968                     Log0(PCSC_LOG_DEBUG);
01969                     dwBreakFlag = 1;
01970                 }
01971 
01972                 /* Set the reader status structure */
01973                 rContext = &readerStates[i];
01974 
01975                 /* Now we check all the Reader States */
01976                 readerState = rContext->readerState;
01977 
01978                 /* only if current state has an non null event counter */
01979                 if (currReader->dwCurrentState & 0xFFFF0000)
01980                 {
01981                     unsigned int currentCounter;
01982 
01983                     currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
01984 
01985                     /* has the event counter changed since the last call? */
01986                     if (rContext->eventCounter != currentCounter)
01987                     {
01988                         currReader->dwEventState |= SCARD_STATE_CHANGED;
01989                         Log0(PCSC_LOG_DEBUG);
01990                         dwBreakFlag = 1;
01991                     }
01992                 }
01993 
01994                 /* add an event counter in the upper word of dwEventState */
01995                 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
01996                     | (rContext->eventCounter << 16));
01997 
01998                 /* Check if the reader is in the correct state */
01999                 if (readerState & SCARD_UNKNOWN)
02000                 {
02001                     /* reader is in bad state */
02002                     currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
02003                     if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
02004                     {
02005                         /* App thinks reader is in good state and it is not */
02006                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02007                         Log0(PCSC_LOG_DEBUG);
02008                         dwBreakFlag = 1;
02009                     }
02010                 }
02011                 else
02012                 {
02013                     /* App thinks reader in bad state but it is not */
02014                     if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
02015                     {
02016                         currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02017                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02018                         Log0(PCSC_LOG_DEBUG);
02019                         dwBreakFlag = 1;
02020                     }
02021                 }
02022 
02023                 /* Check for card presence in the reader */
02024                 if (readerState & SCARD_PRESENT)
02025                 {
02026                     /* card present but not yet powered up */
02027                     if (0 == rContext->cardAtrLength)
02028                         /* Allow the status thread to convey information */
02029                         (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
02030 
02031                     currReader->cbAtr = rContext->cardAtrLength;
02032                     memcpy(currReader->rgbAtr, rContext->cardAtr,
02033                         currReader->cbAtr);
02034                 }
02035                 else
02036                     currReader->cbAtr = 0;
02037 
02038                 /* Card is now absent */
02039                 if (readerState & SCARD_ABSENT)
02040                 {
02041                     currReader->dwEventState |= SCARD_STATE_EMPTY;
02042                     currReader->dwEventState &= ~SCARD_STATE_PRESENT;
02043                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02044                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02045                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02046                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02047                     currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
02048                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02049                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02050 
02051                     /* After present the rest are assumed */
02052                     if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
02053                     {
02054                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02055                         Log0(PCSC_LOG_DEBUG);
02056                         dwBreakFlag = 1;
02057                     }
02058                 }
02059                 /* Card is now present */
02060                 else if (readerState & SCARD_PRESENT)
02061                 {
02062                     currReader->dwEventState |= SCARD_STATE_PRESENT;
02063                     currReader->dwEventState &= ~SCARD_STATE_EMPTY;
02064                     currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
02065                     currReader->dwEventState &= ~SCARD_STATE_IGNORE;
02066                     currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
02067                     currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
02068                     currReader->dwEventState &= ~SCARD_STATE_MUTE;
02069 
02070                     if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
02071                     {
02072                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02073                         Log0(PCSC_LOG_DEBUG);
02074                         dwBreakFlag = 1;
02075                     }
02076 
02077                     if (readerState & SCARD_SWALLOWED)
02078                     {
02079                         currReader->dwEventState |= SCARD_STATE_MUTE;
02080                         if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
02081                         {
02082                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02083                             Log0(PCSC_LOG_DEBUG);
02084                             dwBreakFlag = 1;
02085                         }
02086                     }
02087                     else
02088                     {
02089                         /* App thinks card is mute but it is not */
02090                         if (currReader->dwCurrentState & SCARD_STATE_MUTE)
02091                         {
02092                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02093                             Log0(PCSC_LOG_DEBUG);
02094                             dwBreakFlag = 1;
02095                         }
02096                     }
02097                 }
02098 
02099                 /* Now figure out sharing modes */
02100                 if (rContext->readerSharing == PCSCLITE_SHARING_EXCLUSIVE_CONTEXT)
02101                 {
02102                     currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
02103                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02104                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02105                     {
02106                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02107                         Log0(PCSC_LOG_DEBUG);
02108                         dwBreakFlag = 1;
02109                     }
02110                 }
02111                 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
02112                 {
02113                     /* A card must be inserted for it to be INUSE */
02114                     if (readerState & SCARD_PRESENT)
02115                     {
02116                         currReader->dwEventState |= SCARD_STATE_INUSE;
02117                         currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02118                         if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
02119                         {
02120                             currReader->dwEventState |= SCARD_STATE_CHANGED;
02121                             Log0(PCSC_LOG_DEBUG);
02122                             dwBreakFlag = 1;
02123                         }
02124                     }
02125                 }
02126                 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
02127                 {
02128                     currReader->dwEventState &= ~SCARD_STATE_INUSE;
02129                     currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
02130 
02131                     if (currReader->dwCurrentState & SCARD_STATE_INUSE)
02132                     {
02133                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02134                         Log0(PCSC_LOG_DEBUG);
02135                         dwBreakFlag = 1;
02136                     }
02137                     else if (currReader-> dwCurrentState
02138                         & SCARD_STATE_EXCLUSIVE)
02139                     {
02140                         currReader->dwEventState |= SCARD_STATE_CHANGED;
02141                         Log0(PCSC_LOG_DEBUG);
02142                         dwBreakFlag = 1;
02143                     }
02144                 }
02145 
02146                 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
02147                 {
02148                     /*
02149                      * Break out of the while .. loop and return status
02150                      * once all the status's for all readers is met
02151                      */
02152                     currReader->dwEventState |= SCARD_STATE_CHANGED;
02153                     Log0(PCSC_LOG_DEBUG);
02154                     dwBreakFlag = 1;
02155                 }
02156             }   /* End of SCARD_STATE_UNKNOWN */
02157         }   /* End of SCARD_STATE_IGNORE */
02158 
02159         /* Counter and resetter */
02160         j++;
02161         if (j == cReaders)
02162         {
02163             /* go back to the first reader */
02164             j = 0;
02165 
02166             /* Declare all the break conditions */
02167 
02168             /* Break if UNAWARE is set and all readers have been checked */
02169             if (dwBreakFlag == 1)
02170                 break;
02171 
02172             /* Only sleep once for each cycle of reader checks. */
02173             {
02174                 struct wait_reader_state_change waitStatusStruct;
02175                 struct timeval before, after;
02176 
02177                 gettimeofday(&before, NULL);
02178 
02179                 waitStatusStruct.timeOut = dwTime;
02180                 waitStatusStruct.rv = SCARD_S_SUCCESS;
02181 
02182                 /* another thread can do SCardCancel() */
02183                 currentContextMap->cancellable = TRUE;
02184 
02185                 rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
02186                     currentContextMap->dwClientID,
02187                     sizeof(waitStatusStruct), &waitStatusStruct);
02188 
02189                 if (rv != SCARD_S_SUCCESS)
02190                     goto end;
02191 
02192                 /*
02193                  * Read a message from the server
02194                  */
02195                 rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
02196                     &waitStatusStruct, sizeof(waitStatusStruct),
02197                     currentContextMap->dwClientID, dwTime);
02198 
02199                 /* another thread can do SCardCancel() */
02200                 currentContextMap->cancellable = FALSE;
02201 
02202                 /* timeout */
02203                 if (SCARD_E_TIMEOUT == rv)
02204                 {
02205                     /* ask server to remove us from the event list */
02206                     rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
02207                         currentContextMap->dwClientID,
02208                         sizeof(waitStatusStruct), &waitStatusStruct);
02209 
02210                     if (rv != SCARD_S_SUCCESS)
02211                         goto end;
02212 
02213                     /* Read a message from the server */
02214                     rv = MessageReceive(&waitStatusStruct,
02215                         sizeof(waitStatusStruct),
02216                         currentContextMap->dwClientID);
02217 
02218                     if (rv != SCARD_S_SUCCESS)
02219                         goto end;
02220                 }
02221 
02222                 if (rv != SCARD_S_SUCCESS)
02223                     goto end;
02224 
02225                 /* an event occurs or SCardCancel() was called */
02226                 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
02227                 {
02228                     rv = waitStatusStruct.rv;
02229                     goto end;
02230                 }
02231 
02232                 /* synchronize reader states with daemon */
02233                 rv = getReaderStates(currentContextMap);
02234                 if (rv != SCARD_S_SUCCESS)
02235                     goto end;
02236 
02237                 if (INFINITE != dwTimeout)
02238                 {
02239                     long int diff;
02240 
02241                     gettimeofday(&after, NULL);
02242                     diff = time_sub(&after, &before);
02243                     dwTime -= diff/1000;
02244                 }
02245             }
02246 
02247             if (dwTimeout != INFINITE)
02248             {
02249                 /* If time is greater than timeout and all readers have been
02250                  * checked
02251                  */
02252                 if (dwTime <= 0)
02253                 {
02254                     rv = SCARD_E_TIMEOUT;
02255                     goto end;
02256                 }
02257             }
02258         }
02259     }
02260     while (1);
02261 
02262 end:
02263     Log1(PCSC_LOG_DEBUG, "Event Loop End");
02264 
02265     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02266 
02267 error:
02268     PROFILE_END(rv)
02269 #ifdef DO_TRACE
02270     for (j=0; j<cReaders; j++)
02271     {
02272         API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
02273             rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
02274     }
02275 #endif
02276 
02277     return rv;
02278 }
02279 
02333 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
02334     DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
02335     LPDWORD lpBytesReturned)
02336 {
02337     LONG rv;
02338     struct control_struct scControlStruct;
02339     SCONTEXTMAP * currentContextMap;
02340     CHANNEL_MAP * pChannelMap;
02341 
02342     PROFILE_START
02343 
02344     /* 0 bytes received by default */
02345     if (NULL != lpBytesReturned)
02346         *lpBytesReturned = 0;
02347 
02348     CHECK_SAME_PROCESS
02349 
02350     /*
02351      * Make sure this handle has been opened
02352      */
02353     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02354         &pChannelMap);
02355     if (rv == -1)
02356     {
02357         PROFILE_END(SCARD_E_INVALID_HANDLE)
02358         return SCARD_E_INVALID_HANDLE;
02359     }
02360 
02361     (void)pthread_mutex_lock(currentContextMap->mMutex);
02362 
02363     /* check the handle is still valid */
02364     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02365         &pChannelMap);
02366     if (rv == -1)
02367         /* the handle is now invalid
02368          * -> another thread may have called SCardReleaseContext
02369          * -> so the mMutex has been unlocked */
02370         return SCARD_E_INVALID_HANDLE;
02371 
02372     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02373         || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02374     {
02375         rv = SCARD_E_INSUFFICIENT_BUFFER;
02376         goto end;
02377     }
02378 
02379     scControlStruct.hCard = hCard;
02380     scControlStruct.dwControlCode = dwControlCode;
02381     scControlStruct.cbSendLength = cbSendLength;
02382     scControlStruct.cbRecvLength = cbRecvLength;
02383     scControlStruct.dwBytesReturned = 0;
02384     scControlStruct.rv = 0;
02385 
02386     rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
02387         sizeof(scControlStruct), &scControlStruct);
02388 
02389     if (rv != SCARD_S_SUCCESS)
02390         goto end;
02391 
02392     /* write the sent buffer */
02393     rv = MessageSend((char *)pbSendBuffer, cbSendLength,
02394         currentContextMap->dwClientID);
02395 
02396     if (rv != SCARD_S_SUCCESS)
02397         goto end;
02398 
02399     /*
02400      * Read a message from the server
02401      */
02402     rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
02403         currentContextMap->dwClientID);
02404 
02405     if (rv != SCARD_S_SUCCESS)
02406         goto end;
02407 
02408     if (SCARD_S_SUCCESS == scControlStruct.rv)
02409     {
02410         /* read the received buffer */
02411         rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
02412             currentContextMap->dwClientID);
02413 
02414         if (rv != SCARD_S_SUCCESS)
02415             goto end;
02416 
02417     }
02418 
02419     if (NULL != lpBytesReturned)
02420         *lpBytesReturned = scControlStruct.dwBytesReturned;
02421 
02422     rv = scControlStruct.rv;
02423 
02424 end:
02425     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02426 
02427     PROFILE_END(rv)
02428 
02429     return rv;
02430 }
02431 
02536 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
02537     LPDWORD pcbAttrLen)
02538 {
02539     LONG ret;
02540     unsigned char *buf = NULL;
02541 
02542     PROFILE_START
02543 
02544     if (NULL == pcbAttrLen)
02545     {
02546         ret = SCARD_E_INVALID_PARAMETER;
02547         goto end;
02548     }
02549 
02550     if (SCARD_AUTOALLOCATE == *pcbAttrLen)
02551     {
02552         if (NULL == pbAttr)
02553             return SCARD_E_INVALID_PARAMETER;
02554 
02555         *pcbAttrLen = MAX_BUFFER_SIZE;
02556         buf = malloc(*pcbAttrLen);
02557         if (NULL == buf)
02558         {
02559             ret = SCARD_E_NO_MEMORY;
02560             goto end;
02561         }
02562 
02563         *(unsigned char **)pbAttr = buf;
02564     }
02565     else
02566     {
02567         buf = pbAttr;
02568 
02569         /* if only get the length */
02570         if (NULL == pbAttr)
02571             /* use a reasonable size */
02572             *pcbAttrLen = MAX_BUFFER_SIZE;
02573     }
02574 
02575     ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
02576         pcbAttrLen);
02577 
02578 end:
02579     PROFILE_END(ret)
02580 
02581     return ret;
02582 }
02583 
02619 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
02620     DWORD cbAttrLen)
02621 {
02622     LONG ret;
02623 
02624     PROFILE_START
02625 
02626     if (NULL == pbAttr || 0 == cbAttrLen)
02627         return SCARD_E_INVALID_PARAMETER;
02628 
02629     ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
02630         &cbAttrLen);
02631 
02632     PROFILE_END(ret)
02633 
02634     return ret;
02635 }
02636 
02637 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
02638     LPBYTE pbAttr, LPDWORD pcbAttrLen)
02639 {
02640     LONG rv;
02641     struct getset_struct scGetSetStruct;
02642     SCONTEXTMAP * currentContextMap;
02643     CHANNEL_MAP * pChannelMap;
02644 
02645     CHECK_SAME_PROCESS
02646 
02647     /*
02648      * Make sure this handle has been opened
02649      */
02650     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02651         &pChannelMap);
02652     if (rv == -1)
02653         return SCARD_E_INVALID_HANDLE;
02654 
02655     (void)pthread_mutex_lock(currentContextMap->mMutex);
02656 
02657     /* check the handle is still valid */
02658     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02659         &pChannelMap);
02660     if (rv == -1)
02661         /* the handle is now invalid
02662          * -> another thread may have called SCardReleaseContext
02663          * -> so the mMutex has been unlocked */
02664         return SCARD_E_INVALID_HANDLE;
02665 
02666     if (*pcbAttrLen > MAX_BUFFER_SIZE)
02667     {
02668         rv = SCARD_E_INSUFFICIENT_BUFFER;
02669         goto end;
02670     }
02671 
02672     scGetSetStruct.hCard = hCard;
02673     scGetSetStruct.dwAttrId = dwAttrId;
02674     scGetSetStruct.cbAttrLen = *pcbAttrLen;
02675     scGetSetStruct.rv = SCARD_E_NO_SERVICE;
02676     memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
02677     if (SCARD_SET_ATTRIB == command)
02678         memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
02679 
02680     rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
02681         sizeof(scGetSetStruct), &scGetSetStruct);
02682 
02683     if (rv != SCARD_S_SUCCESS)
02684         goto end;
02685 
02686     /*
02687      * Read a message from the server
02688      */
02689     rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
02690         currentContextMap->dwClientID);
02691 
02692     if (rv != SCARD_S_SUCCESS)
02693         goto end;
02694 
02695     if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
02696     {
02697         /*
02698          * Copy and zero it so any secret information is not leaked
02699          */
02700         if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
02701         {
02702             scGetSetStruct.cbAttrLen = *pcbAttrLen;
02703             scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
02704         }
02705         else
02706             *pcbAttrLen = scGetSetStruct.cbAttrLen;
02707 
02708         if (pbAttr)
02709             memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
02710 
02711         memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
02712     }
02713     rv = scGetSetStruct.rv;
02714 
02715 end:
02716     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02717 
02718     return rv;
02719 }
02720 
02779 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
02780     LPCBYTE pbSendBuffer, DWORD cbSendLength,
02781     SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
02782     LPDWORD pcbRecvLength)
02783 {
02784     LONG rv;
02785     SCONTEXTMAP * currentContextMap;
02786     CHANNEL_MAP * pChannelMap;
02787     struct transmit_struct scTransmitStruct;
02788 
02789     PROFILE_START
02790 
02791     if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
02792             pcbRecvLength == NULL || pioSendPci == NULL)
02793         return SCARD_E_INVALID_PARAMETER;
02794 
02795     CHECK_SAME_PROCESS
02796 
02797     /*
02798      * Make sure this handle has been opened
02799      */
02800     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02801         &pChannelMap);
02802     if (rv == -1)
02803     {
02804         *pcbRecvLength = 0;
02805         PROFILE_END(SCARD_E_INVALID_HANDLE)
02806         return SCARD_E_INVALID_HANDLE;
02807     }
02808 
02809     (void)pthread_mutex_lock(currentContextMap->mMutex);
02810 
02811     /* check the handle is still valid */
02812     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
02813         &pChannelMap);
02814     if (rv == -1)
02815         /* the handle is now invalid
02816          * -> another thread may have called SCardReleaseContext
02817          * -> so the mMutex has been unlocked */
02818         return SCARD_E_INVALID_HANDLE;
02819 
02820     if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
02821         || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
02822     {
02823         rv = SCARD_E_INSUFFICIENT_BUFFER;
02824         goto end;
02825     }
02826 
02827     /* Retry loop for blocking behaviour */
02828 retry:
02829 
02830     scTransmitStruct.hCard = hCard;
02831     scTransmitStruct.cbSendLength = cbSendLength;
02832     scTransmitStruct.pcbRecvLength = *pcbRecvLength;
02833     scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
02834     scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
02835     scTransmitStruct.rv = SCARD_S_SUCCESS;
02836 
02837     if (pioRecvPci)
02838     {
02839         scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
02840         scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
02841     }
02842     else
02843     {
02844         scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
02845         scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
02846     }
02847 
02848     rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
02849         sizeof(scTransmitStruct), (void *) &scTransmitStruct);
02850 
02851     if (rv != SCARD_S_SUCCESS)
02852         goto end;
02853 
02854     /* write the sent buffer */
02855     rv = MessageSend((void *)pbSendBuffer, cbSendLength,
02856         currentContextMap->dwClientID);
02857 
02858     if (rv != SCARD_S_SUCCESS)
02859         goto end;
02860 
02861     /*
02862      * Read a message from the server
02863      */
02864     rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
02865         currentContextMap->dwClientID);
02866 
02867     if (rv != SCARD_S_SUCCESS)
02868         goto end;
02869 
02870     if (SCARD_S_SUCCESS == scTransmitStruct.rv)
02871     {
02872         /* read the received buffer */
02873         rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
02874             currentContextMap->dwClientID);
02875 
02876         if (rv != SCARD_S_SUCCESS)
02877             goto end;
02878 
02879         if (pioRecvPci)
02880         {
02881             pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
02882             pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
02883         }
02884     }
02885 
02886     rv = scTransmitStruct.rv;
02887 
02888     if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
02889     {
02890         (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
02891         goto retry;
02892     }
02893 
02894     *pcbRecvLength = scTransmitStruct.pcbRecvLength;
02895 
02896 end:
02897     (void)pthread_mutex_unlock(currentContextMap->mMutex);
02898 
02899     PROFILE_END(rv)
02900 
02901     return rv;
02902 }
02903 
02954 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
02955     LPSTR mszReaders, LPDWORD pcchReaders)
02956 {
02957     DWORD dwReadersLen = 0;
02958     int i;
02959     SCONTEXTMAP * currentContextMap;
02960     LONG rv = SCARD_S_SUCCESS;
02961     char *buf = NULL;
02962 
02963     (void)mszGroups;
02964     PROFILE_START
02965     API_TRACE_IN("%ld", hContext)
02966 
02967     /*
02968      * Check for NULL parameters
02969      */
02970     if (pcchReaders == NULL)
02971         return SCARD_E_INVALID_PARAMETER;
02972 
02973     CHECK_SAME_PROCESS
02974 
02975     /*
02976      * Make sure this context has been opened
02977      */
02978     currentContextMap = SCardGetContext(hContext);
02979     if (NULL == currentContextMap)
02980     {
02981         PROFILE_END(SCARD_E_INVALID_HANDLE)
02982         return SCARD_E_INVALID_HANDLE;
02983     }
02984 
02985     (void)pthread_mutex_lock(currentContextMap->mMutex);
02986 
02987     /* check the context is still opened */
02988     currentContextMap = SCardGetContext(hContext);
02989     if (NULL == currentContextMap)
02990         /* the context is now invalid
02991          * -> another thread may have called SCardReleaseContext
02992          * -> so the mMutex has been unlocked */
02993         return SCARD_E_INVALID_HANDLE;
02994 
02995     /* synchronize reader states with daemon */
02996     rv = getReaderStates(currentContextMap);
02997     if (rv != SCARD_S_SUCCESS)
02998         goto end;
02999 
03000     dwReadersLen = 0;
03001     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03002         if (readerStates[i].readerName[0] != '\0')
03003             dwReadersLen += strlen(readerStates[i].readerName) + 1;
03004 
03005     /* for the last NULL byte */
03006     dwReadersLen += 1;
03007 
03008     if (1 == dwReadersLen)
03009     {
03010         rv = SCARD_E_NO_READERS_AVAILABLE;
03011         goto end;
03012     }
03013 
03014     if (SCARD_AUTOALLOCATE == *pcchReaders)
03015     {
03016         buf = malloc(dwReadersLen);
03017         if (NULL == buf)
03018         {
03019             rv = SCARD_E_NO_MEMORY;
03020             goto end;
03021         }
03022         if (NULL == mszReaders)
03023         {
03024             rv = SCARD_E_INVALID_PARAMETER;
03025             goto end;
03026         }
03027         *(char **)mszReaders = buf;
03028     }
03029     else
03030     {
03031         buf = mszReaders;
03032 
03033         /* not enough place to store the reader names */
03034         if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
03035         {
03036             rv = SCARD_E_INSUFFICIENT_BUFFER;
03037             goto end;
03038         }
03039     }
03040 
03041     if (mszReaders == NULL) /* text array not allocated */
03042         goto end;
03043 
03044     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
03045     {
03046         if (readerStates[i].readerName[0] != '\0')
03047         {
03048             /*
03049              * Build the multi-string
03050              */
03051             strcpy(buf, readerStates[i].readerName);
03052             buf += strlen(readerStates[i].readerName)+1;
03053         }
03054     }
03055     *buf = '\0';    /* Add the last null */
03056 
03057 end:
03058     /* set the reader names length */
03059     *pcchReaders = dwReadersLen;
03060 
03061     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03062 
03063     PROFILE_END(rv)
03064     API_TRACE_OUT("%d", *pcchReaders)
03065 
03066     return rv;
03067 }
03068 
03082 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
03083 {
03084     LONG rv = SCARD_S_SUCCESS;
03085     SCONTEXTMAP * currentContextMap;
03086 
03087     PROFILE_START
03088 
03089     CHECK_SAME_PROCESS
03090 
03091     /*
03092      * Make sure this context has been opened
03093      */
03094     currentContextMap = SCardGetContext(hContext);
03095     if (NULL == currentContextMap)
03096         return SCARD_E_INVALID_HANDLE;
03097 
03098     free((void *)pvMem);
03099 
03100     PROFILE_END(rv)
03101 
03102     return rv;
03103 }
03104 
03156 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
03157     LPDWORD pcchGroups)
03158 {
03159     LONG rv = SCARD_S_SUCCESS;
03160     SCONTEXTMAP * currentContextMap;
03161     char *buf = NULL;
03162 
03163     PROFILE_START
03164 
03165     /* Multi-string with two trailing \0 */
03166     const char ReaderGroup[] = "SCard$DefaultReaders\0";
03167     const unsigned int dwGroups = sizeof(ReaderGroup);
03168 
03169     CHECK_SAME_PROCESS
03170 
03171     /*
03172      * Make sure this context has been opened
03173      */
03174     currentContextMap = SCardGetContext(hContext);
03175     if (NULL == currentContextMap)
03176         return SCARD_E_INVALID_HANDLE;
03177 
03178     (void)pthread_mutex_lock(currentContextMap->mMutex);
03179 
03180     /* check the context is still opened */
03181     currentContextMap = SCardGetContext(hContext);
03182     if (NULL == currentContextMap)
03183         /* the context is now invalid
03184          * -> another thread may have called SCardReleaseContext
03185          * -> so the mMutex has been unlocked */
03186         return SCARD_E_INVALID_HANDLE;
03187 
03188     if (SCARD_AUTOALLOCATE == *pcchGroups)
03189     {
03190         buf = malloc(dwGroups);
03191         if (NULL == buf)
03192         {
03193             rv = SCARD_E_NO_MEMORY;
03194             goto end;
03195         }
03196         if (NULL == mszGroups)
03197         {
03198             rv = SCARD_E_INVALID_PARAMETER;
03199             goto end;
03200         }
03201         *(char **)mszGroups = buf;
03202     }
03203     else
03204     {
03205         buf = mszGroups;
03206 
03207         if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
03208         {
03209             rv = SCARD_E_INSUFFICIENT_BUFFER;
03210             goto end;
03211         }
03212     }
03213 
03214     if (buf)
03215         memcpy(buf, ReaderGroup, dwGroups);
03216 
03217 end:
03218     *pcchGroups = dwGroups;
03219 
03220     (void)pthread_mutex_unlock(currentContextMap->mMutex);
03221 
03222     PROFILE_END(rv)
03223 
03224     return rv;
03225 }
03226 
03256 LONG SCardCancel(SCARDCONTEXT hContext)
03257 {
03258     SCONTEXTMAP * currentContextMap;
03259     LONG rv = SCARD_S_SUCCESS;
03260     uint32_t dwClientID = 0;
03261     struct cancel_struct scCancelStruct;
03262 
03263     PROFILE_START
03264     API_TRACE_IN("%ld", hContext)
03265 
03266     /*
03267      * Make sure this context has been opened
03268      */
03269     currentContextMap = SCardGetContext(hContext);
03270     if (NULL == currentContextMap)
03271     {
03272         rv = SCARD_E_INVALID_HANDLE;
03273         goto error;
03274     }
03275 
03276     if (! currentContextMap->cancellable)
03277     {
03278         rv = SCARD_S_SUCCESS;
03279         goto error;
03280     }
03281 
03282     /* create a new connection to the server */
03283     if (ClientSetupSession(&dwClientID) != 0)
03284     {
03285         rv = SCARD_E_NO_SERVICE;
03286         goto error;
03287     }
03288 
03289     scCancelStruct.hContext = hContext;
03290     scCancelStruct.rv = SCARD_S_SUCCESS;
03291 
03292     rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
03293         sizeof(scCancelStruct), (void *) &scCancelStruct);
03294 
03295     if (rv != SCARD_S_SUCCESS)
03296         goto end;
03297 
03298     /*
03299      * Read a message from the server
03300      */
03301     rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
03302 
03303     if (rv != SCARD_S_SUCCESS)
03304         goto end;
03305 
03306     rv = scCancelStruct.rv;
03307 end:
03308     ClientCloseSession(dwClientID);
03309 
03310 error:
03311     PROFILE_END(rv)
03312     API_TRACE_OUT("")
03313 
03314     return rv;
03315 }
03316 
03340 LONG SCardIsValidContext(SCARDCONTEXT hContext)
03341 {
03342     LONG rv;
03343     SCONTEXTMAP * currentContextMap;
03344 
03345     PROFILE_START
03346     API_TRACE_IN("%ld", hContext)
03347 
03348     rv = SCARD_S_SUCCESS;
03349 
03350     /* Check if the _same_ server is running */
03351     CHECK_SAME_PROCESS
03352 
03353     /*
03354      * Make sure this context has been opened
03355      */
03356     currentContextMap = SCardGetContext(hContext);
03357     if (currentContextMap == NULL)
03358         rv = SCARD_E_INVALID_HANDLE;
03359 
03360     PROFILE_END(rv)
03361     API_TRACE_OUT("")
03362 
03363     return rv;
03364 }
03365 
03382 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
03383 {
03384     int lrv;
03385     SCONTEXTMAP * newContextMap;
03386 
03387     newContextMap = malloc(sizeof(SCONTEXTMAP));
03388     if (NULL == newContextMap)
03389         return SCARD_E_NO_MEMORY;
03390 
03391     Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%X", newContextMap);
03392     newContextMap->hContext = hContext;
03393     newContextMap->dwClientID = dwClientID;
03394     newContextMap->cancellable = FALSE;
03395 
03396     newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
03397     if (NULL == newContextMap->mMutex)
03398     {
03399         Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%X", newContextMap);
03400         free(newContextMap);
03401         return SCARD_E_NO_MEMORY;
03402     }
03403     (void)pthread_mutex_init(newContextMap->mMutex, NULL);
03404 
03405     lrv = list_init(&(newContextMap->channelMapList));
03406     if (lrv < 0)
03407     {
03408         Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
03409         goto error;
03410     }
03411 
03412     lrv = list_attributes_seeker(&(newContextMap->channelMapList),
03413         CHANNEL_MAP_seeker);
03414     if (lrv <0)
03415     {
03416         Log2(PCSC_LOG_CRITICAL,
03417             "list_attributes_seeker failed with return value: %d", lrv);
03418         list_destroy(&(newContextMap->channelMapList));
03419         goto error;
03420     }
03421 
03422     lrv = list_append(&contextMapList, newContextMap);
03423     if (lrv < 0)
03424     {
03425         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
03426             lrv);
03427         list_destroy(&(newContextMap->channelMapList));
03428         goto error;
03429     }
03430 
03431     return SCARD_S_SUCCESS;
03432 
03433 error:
03434 
03435     (void)pthread_mutex_destroy(newContextMap->mMutex);
03436     free(newContextMap->mMutex);
03437     free(newContextMap);
03438 
03439     return SCARD_E_NO_MEMORY;
03440 }
03441 
03454 static SCONTEXTMAP * SCardGetContext(SCARDCONTEXT hContext)
03455 {
03456     SCONTEXTMAP * currentContextMap;
03457 
03458     (void)SCardLockThread();
03459     currentContextMap = SCardGetContextTH(hContext);
03460     (void)SCardUnlockThread();
03461 
03462     return currentContextMap;
03463 }
03464 
03477 static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext)
03478 {
03479     return list_seek(&contextMapList, &hContext);
03480 }
03481 
03491 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
03492 {
03493     SCONTEXTMAP * currentContextMap;
03494     currentContextMap = SCardGetContextTH(hContext);
03495 
03496     if (NULL == currentContextMap)
03497         return SCARD_E_INVALID_HANDLE;
03498     else
03499         return SCardCleanContext(currentContextMap);
03500 }
03501 
03502 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
03503 {
03504     int list_index, lrv;
03505     int listSize;
03506     CHANNEL_MAP * currentChannelMap;
03507 
03508     targetContextMap->hContext = 0;
03509     (void)ClientCloseSession(targetContextMap->dwClientID);
03510     targetContextMap->dwClientID = 0;
03511     (void)pthread_mutex_destroy(targetContextMap->mMutex);
03512     free(targetContextMap->mMutex);
03513     targetContextMap->mMutex = NULL;
03514 
03515     listSize = list_size(&(targetContextMap->channelMapList));
03516     for (list_index = 0; list_index < listSize; list_index++)
03517     {
03518         currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
03519             list_index);
03520         if (NULL == currentChannelMap)
03521         {
03522             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03523                 list_index);
03524             continue;
03525         }
03526         else
03527         {
03528             free(currentChannelMap->readerName);
03529             free(currentChannelMap);
03530         }
03531 
03532     }
03533     list_destroy(&(targetContextMap->channelMapList));
03534 
03535     lrv = list_delete(&contextMapList, targetContextMap);
03536     if (lrv < 0)
03537     {
03538         Log2(PCSC_LOG_CRITICAL,
03539             "list_delete failed with return value: %d", lrv);
03540     }
03541 
03542     free(targetContextMap);
03543 
03544     return SCARD_S_SUCCESS;
03545 }
03546 
03547 /*
03548  * Functions for managing hCard values returned from SCardConnect.
03549  */
03550 
03551 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
03552     LPCSTR readerName)
03553 {
03554     CHANNEL_MAP * newChannelMap;
03555     int lrv = -1;
03556 
03557     newChannelMap = malloc(sizeof(CHANNEL_MAP));
03558     if (NULL == newChannelMap)
03559         return SCARD_E_NO_MEMORY;
03560 
03561     newChannelMap->hCard = hCard;
03562     newChannelMap->readerName = strdup(readerName);
03563 
03564     lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
03565     if (lrv < 0)
03566     {
03567         free(newChannelMap->readerName);
03568         free(newChannelMap);
03569         Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
03570             lrv);
03571         return SCARD_E_NO_MEMORY;
03572     }
03573 
03574     return SCARD_S_SUCCESS;
03575 }
03576 
03577 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
03578 {
03579     SCONTEXTMAP * currentContextMap;
03580     CHANNEL_MAP * currentChannelMap;
03581     int lrv;
03582     LONG rv;
03583 
03584     rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
03585         &currentChannelMap);
03586     if (rv == -1)
03587         return SCARD_E_INVALID_HANDLE;
03588 
03589     free(currentChannelMap->readerName);
03590 
03591     lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
03592     if (lrv < 0)
03593     {
03594         Log2(PCSC_LOG_CRITICAL,
03595             "list_delete failed with return value: %d", lrv);
03596     }
03597 
03598     free(currentChannelMap);
03599 
03600     return SCARD_S_SUCCESS;
03601 }
03602 
03603 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
03604     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03605 {
03606     LONG rv;
03607 
03608     if (0 == hCard)
03609         return -1;
03610 
03611     (void)SCardLockThread();
03612     rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
03613         targetChannelMap);
03614     (void)SCardUnlockThread();
03615 
03616     return rv;
03617 }
03618 
03619 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
03620     SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
03621 {
03622     int listSize;
03623     int list_index;
03624     SCONTEXTMAP * currentContextMap;
03625     CHANNEL_MAP * currentChannelMap;
03626 
03627     /* Best to get the caller a crash early if we fail unsafely */
03628     *targetContextMap = NULL;
03629     *targetChannelMap = NULL;
03630 
03631     listSize = list_size(&contextMapList);
03632 
03633     for (list_index = 0; list_index < listSize; list_index++)
03634     {
03635         currentContextMap = list_get_at(&contextMapList, list_index);
03636         if (currentContextMap == NULL)
03637         {
03638             Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
03639                 list_index);
03640             continue;
03641         }
03642         currentChannelMap = list_seek(&(currentContextMap->channelMapList),
03643             &hCard);
03644         if (currentChannelMap != NULL)
03645         {
03646             *targetContextMap = currentContextMap;
03647             *targetChannelMap = currentChannelMap;
03648             return SCARD_S_SUCCESS;
03649         }
03650     }
03651 
03652     return -1;
03653 }
03654 
03666 LONG SCardCheckDaemonAvailability(void)
03667 {
03668     LONG rv;
03669     struct stat statBuffer;
03670     char *socketName;
03671 
03672     socketName = getSocketName();
03673     rv = stat(socketName, &statBuffer);
03674 
03675     if (rv != 0)
03676     {
03677         Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
03678             socketName, strerror(errno));
03679         return SCARD_E_NO_SERVICE;
03680     }
03681 
03682     return SCARD_S_SUCCESS;
03683 }
03684 
03685 #ifdef DO_CHECK_SAME_PROCESS
03686 static LONG SCardInvalidateHandles(void)
03687 {
03688     /* invalid all handles */
03689     (void)SCardLockThread();
03690 
03691     while (list_size(&contextMapList) != 0)
03692     {
03693         SCONTEXTMAP * currentContextMap;
03694 
03695         currentContextMap = list_get_at(&contextMapList, 0);
03696         if (currentContextMap != NULL)
03697             (void)SCardCleanContext(currentContextMap);
03698         else
03699             Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
03700     }
03701 
03702     (void)SCardUnlockThread();
03703 
03704     return SCARD_E_INVALID_HANDLE;
03705 }
03706 
03707 static LONG SCardCheckSameProcess(void)
03708 {
03709     /* after fork() need to restart */
03710     if ((client_pid && client_pid != getpid()))
03711     {
03712         Log1(PCSC_LOG_INFO, "Client forked");
03713         return SCardInvalidateHandles();
03714     }
03715 
03716     client_pid = getpid();
03717 
03718     return SCARD_S_SUCCESS;
03719 }
03720 #endif
03721 
03722 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
03723 {
03724     int32_t dwClientID = currentContextMap->dwClientID;
03725     LONG rv;
03726 
03727     rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
03728     if (rv != SCARD_S_SUCCESS)
03729         return rv;
03730 
03731     /* Read a message from the server */
03732     rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
03733     if (rv != SCARD_S_SUCCESS)
03734         return rv;
03735 
03736     return SCARD_S_SUCCESS;
03737 }
03738