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  *  Damien Sauveron <damien.sauveron@labri.fr>
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * $Id: winscard_clnt.c 2915 2008-04-28 09:28:05Z rousseau $
00010  */
00011 
00021 #include "config.h"
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <sys/types.h>
00025 #include <fcntl.h>
00026 #include <unistd.h>
00027 #include <sys/un.h>
00028 #include <errno.h>
00029 #include <stddef.h>
00030 
00031 #include "misc.h"
00032 #include "pcscd.h"
00033 #include "winscard.h"
00034 #include "debug.h"
00035 #include "thread_generic.h"
00036 #include "strlcpycat.h"
00037 
00038 #include "readerfactory.h"
00039 #include "eventhandler.h"
00040 #include "sys_generic.h"
00041 #include "winscard_msg.h"
00042 #include "utils.h"
00043 
00045 #define SCARD_PROTOCOL_ANY_OLD  0x1000
00046 
00047 #ifndef TRUE
00048 #define TRUE 1
00049 #define FALSE 0
00050 #endif
00051 
00052 #undef DO_PROFILE
00053 #ifdef DO_PROFILE
00054 
00055 #define PROFILE_FILE "/tmp/pcsc_profile"
00056 #include <stdio.h>
00057 #include <sys/time.h>
00058 
00059 struct timeval profile_time_start;
00060 FILE *fd;
00061 char profile_tty;
00062 char fct_name[100];
00063 
00064 #define PROFILE_START profile_start(__FUNCTION__);
00065 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
00066 
00067 static void profile_start(const char *f)
00068 {
00069     static char initialized = FALSE;
00070 
00071     if (!initialized)
00072     {
00073         char filename[80];
00074 
00075         initialized = TRUE;
00076         sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
00077         fd = fopen(filename, "a+");
00078         if (NULL == fd)
00079         {
00080             fprintf(stderr, "\33[01;31mCan't open %s: %s\33[0m\n",
00081                 PROFILE_FILE, strerror(errno));
00082             exit(-1);
00083         }
00084         fprintf(fd, "\nStart a new profile\n");
00085 
00086         if (isatty(fileno(stderr)))
00087             profile_tty = TRUE;
00088         else
00089             profile_tty = FALSE;
00090     }
00091 
00092     /* PROFILE_END was not called before? */
00093     if (profile_tty && fct_name[0])
00094         printf("\33[01;34m WARNING: %s starts before %s finishes\33[0m\n",
00095             f, fct_name);
00096 
00097     strlcpy(fct_name, f, sizeof(fct_name));
00098 
00099     gettimeofday(&profile_time_start, NULL);
00100 } /* profile_start */
00101 
00102 /* r = a - b */
00103 static long int time_sub(struct timeval *a, struct timeval *b)
00104 {
00105     struct timeval r;
00106     r.tv_sec = a -> tv_sec - b -> tv_sec;
00107     r.tv_usec = a -> tv_usec - b -> tv_usec;
00108     if (r.tv_usec < 0)
00109     {
00110         r.tv_sec--;
00111         r.tv_usec += 1000000;
00112     }
00113 
00114     return r.tv_sec * 1000000 + r.tv_usec;
00115 } /* time_sub */
00116 
00117 
00118 static void profile_end(const char *f, LONG rv)
00119 {
00120     struct timeval profile_time_end;
00121     long d;
00122 
00123     gettimeofday(&profile_time_end, NULL);
00124     d = time_sub(&profile_time_end, &profile_time_start);
00125 
00126     if (profile_tty)
00127     {
00128         if (fct_name[0])
00129         {
00130             if (strncmp(fct_name, f, sizeof(fct_name)))
00131                 printf("\33[01;34m WARNING: %s ends before %s\33[0m\n",
00132                         f, fct_name);
00133         }
00134         else
00135             printf("\33[01;34m WARNING: %s ends but we lost its start\33[0m\n",
00136                 f);
00137 
00138         /* allow to detect missing PROFILE_END calls */
00139         fct_name[0] = '\0';
00140 
00141         if (rv != SCARD_S_SUCCESS)
00142             fprintf(stderr,
00143                 "\33[01;31mRESULT %s \33[35m%ld \33[34m0x%08lX %s\33[0m\n",
00144                 f, d, rv, pcsc_stringify_error(rv));
00145         else
00146             fprintf(stderr, "\33[01;31mRESULT %s \33[35m%ld\33[0m\n", f, d);
00147     }
00148     fprintf(fd, "%s %ld\n", f, d);
00149     fflush(fd);
00150 } /* profile_end */
00151 
00152 #else
00153 #define PROFILE_START
00154 #define PROFILE_END(rv)
00155 #endif
00156 
00161 struct _psChannelMap
00162 {
00163     SCARDHANDLE hCard;
00164     LPSTR readerName;
00165 };
00166 
00167 typedef struct _psChannelMap CHANNEL_MAP, *PCHANNEL_MAP;
00168 
00174 static struct _psContextMap
00175 {
00176     DWORD dwClientID;               
00177     SCARDCONTEXT hContext;          
00178     DWORD contextBlockStatus;
00179     PCSCLITE_MUTEX_T mMutex;        
00180     CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
00181 } psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS];
00182 
00186 static short isExecuted = 0;
00187 
00188 
00192 static time_t daemon_ctime = 0;
00193 static pid_t daemon_pid = 0;
00198 static pid_t client_pid = 0;
00199 
00205 static int mapAddr = 0;
00206 
00211 static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;
00212 
00219 static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
00220 
00221 PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
00222 PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
00223 PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
00224 
00225 
00226 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
00227 static LONG SCardGetContextIndice(SCARDCONTEXT);
00228 static LONG SCardGetContextIndiceTH(SCARDCONTEXT);
00229 static LONG SCardRemoveContext(SCARDCONTEXT);
00230 static LONG SCardCleanContext(LONG indice);
00231 
00232 static LONG SCardAddHandle(SCARDHANDLE, DWORD, LPCSTR);
00233 static LONG SCardGetIndicesFromHandle(SCARDHANDLE, PDWORD, PDWORD);
00234 static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE, PDWORD, PDWORD);
00235 static LONG SCardRemoveHandle(SCARDHANDLE);
00236 
00237 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
00238     LPBYTE pbAttr, LPDWORD pcbAttrLen);
00239 
00240 void DESTRUCTOR SCardUnload(void);
00241 
00242 /*
00243  * Thread safety functions
00244  */
00251 inline static LONG SCardLockThread(void)
00252 {
00253     return SYS_MutexLock(&clientMutex);
00254 }
00255 
00261 inline static LONG SCardUnlockThread(void)
00262 {
00263     return SYS_MutexUnLock(&clientMutex);
00264 }
00265 
00266 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
00267 
00302 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
00303     LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00304 {
00305     LONG rv;
00306 
00307     PROFILE_START
00308 
00309     /* Check if the server is running */
00310     rv = SCardCheckDaemonAvailability();
00311     if (SCARD_E_INVALID_HANDLE == rv)
00312         /* we reconnected to a daemon or we got called from a forked child */
00313         rv = SCardCheckDaemonAvailability();
00314 
00315     if (rv != SCARD_S_SUCCESS)
00316         return rv;
00317 
00318     SCardLockThread();
00319     rv = SCardEstablishContextTH(dwScope, pvReserved1,
00320         pvReserved2, phContext);
00321     SCardUnlockThread();
00322 
00323     PROFILE_END(rv)
00324 
00325     return rv;
00326 }
00327 
00354 static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1,
00355     LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00356 {
00357     LONG rv;
00358     int i;
00359     establish_struct scEstablishStruct;
00360     sharedSegmentMsg msgStruct;
00361     uint32_t dwClientID = 0;
00362 
00363     if (phContext == NULL)
00364         return SCARD_E_INVALID_PARAMETER;
00365     else
00366         *phContext = 0;
00367 
00368     /*
00369      * Do this only once:
00370      * - Initialize debug of need.
00371      * - Set up the memory mapped structures for reader states.
00372      * - Allocate each reader structure.
00373      * - Initialize context struct.
00374      */
00375     if (isExecuted == 0)
00376     {
00377         int pageSize;
00378 
00379         /*
00380          * Do any system initilization here
00381          */
00382         SYS_Initialize();
00383 
00384         /*
00385          * Set up the memory mapped reader stats structures
00386          */
00387         mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0);
00388         if (mapAddr < 0)
00389         {
00390             Log3(PCSC_LOG_CRITICAL, "Cannot open public shared file %s: %s",
00391                 PCSCLITE_PUBSHM_FILE, strerror(errno));
00392             return SCARD_E_NO_SERVICE;
00393         }
00394 
00395         /* close on exec so that child processes do not inherits the file
00396          * descriptor. The child process will call SCardEstablishContext()
00397          * if needed. */
00398         fcntl(mapAddr, F_SETFD, FD_CLOEXEC);
00399 
00400         pageSize = SYS_GetPageSize();
00401 
00402         /*
00403          * Allocate each reader structure in the memory map
00404          */
00405         for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00406         {
00407             readerStates[i] =
00408                 (PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE),
00409                 mapAddr, (i * pageSize));
00410             if (readerStates[i] == NULL)
00411             {
00412                 Log2(PCSC_LOG_CRITICAL, "Cannot public memory map: %s",
00413                     strerror(errno));
00414                 SYS_CloseFile(mapAddr); /* Close the memory map file */
00415                 return SCARD_F_INTERNAL_ERROR;
00416             }
00417         }
00418 
00419         /*
00420          * Initializes the application contexts and all channels for each one
00421          */
00422         for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
00423         {
00424             int j;
00425 
00426             /*
00427              * Initially set the context struct to zero
00428              */
00429             psContextMap[i].dwClientID = 0;
00430             psContextMap[i].hContext = 0;
00431             psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
00432             psContextMap[i].mMutex = NULL;
00433 
00434             for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
00435             {
00436                 /*
00437                  * Initially set the hcard structs to zero
00438                  */
00439                 psContextMap[i].psChannelMap[j].hCard = 0;
00440                 psContextMap[i].psChannelMap[j].readerName = NULL;
00441             }
00442         }
00443 
00444     }
00445 
00446     /*
00447      * Is there a free slot for this connection ?
00448      */
00449 
00450     for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
00451     {
00452         if (psContextMap[i].dwClientID == 0)
00453             break;
00454     }
00455 
00456     if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS)
00457     {
00458         return SCARD_E_NO_MEMORY;
00459     }
00460 
00461     /* Establishes a connection to the server */
00462     if (SHMClientSetupSession(&dwClientID) != 0)
00463     {
00464         SYS_CloseFile(mapAddr);
00465         return SCARD_E_NO_SERVICE;
00466     }
00467 
00468     {   /* exchange client/server protocol versions */
00469         version_struct *veStr;
00470 
00471         memset(&msgStruct, 0, sizeof(msgStruct));
00472         msgStruct.mtype = CMD_VERSION;
00473         msgStruct.user_id = SYS_GetUID();
00474         msgStruct.group_id = SYS_GetGID();
00475         msgStruct.command = 0;
00476         msgStruct.date = time(NULL);
00477 
00478         veStr = (version_struct *) msgStruct.data;
00479         veStr->major = PROTOCOL_VERSION_MAJOR;
00480         veStr->minor = PROTOCOL_VERSION_MINOR;
00481 
00482         if (-1 == SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID,
00483             PCSCLITE_MCLIENT_ATTEMPTS))
00484             return SCARD_E_NO_SERVICE;
00485 
00486         /*
00487          * Read a message from the server
00488          */
00489         if (-1 == SHMMessageReceive(&msgStruct, sizeof(msgStruct), dwClientID,
00490             PCSCLITE_CLIENT_ATTEMPTS))
00491         {
00492             Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION");
00493             return SCARD_F_COMM_ERROR;
00494         }
00495 
00496         Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
00497             veStr->major, veStr->minor);
00498 
00499         if (veStr->rv != SCARD_S_SUCCESS)
00500             return veStr->rv;
00501 
00502         isExecuted = 1;
00503     }
00504 
00505 
00506     if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
00507         dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL)
00508     {
00509         return SCARD_E_INVALID_VALUE;
00510     }
00511 
00512     /*
00513      * Try to establish an Application Context with the server
00514      */
00515     scEstablishStruct.dwScope = dwScope;
00516     scEstablishStruct.phContext = 0;
00517     scEstablishStruct.rv = SCARD_S_SUCCESS;
00518 
00519     rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID,
00520         sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS,
00521         (void *) &scEstablishStruct);
00522 
00523     if (rv == -1)
00524         return SCARD_E_NO_SERVICE;
00525 
00526     /*
00527      * Read the response from the server
00528      */
00529     rv = SHMClientRead(&msgStruct, dwClientID, PCSCLITE_CLIENT_ATTEMPTS);
00530 
00531     if (rv == -1)
00532         return SCARD_F_COMM_ERROR;
00533 
00534     memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct));
00535 
00536     if (scEstablishStruct.rv != SCARD_S_SUCCESS)
00537         return scEstablishStruct.rv;
00538 
00539     *phContext = scEstablishStruct.phContext;
00540 
00541     /*
00542      * Allocate the new hContext - if allocator full return an error
00543      */
00544     rv = SCardAddContext(*phContext, dwClientID);
00545 
00546     return rv;
00547 }
00548 
00571 LONG SCardReleaseContext(SCARDCONTEXT hContext)
00572 {
00573     LONG rv;
00574     release_struct scReleaseStruct;
00575     sharedSegmentMsg msgStruct;
00576     LONG dwContextIndex;
00577 
00578     PROFILE_START
00579 
00580     /*
00581      * Make sure this context has been opened    
00582      * and get dwContextIndex
00583      */      
00584     dwContextIndex = SCardGetContextIndice(hContext);    
00585     if (dwContextIndex == -1)    
00586         return SCARD_E_INVALID_HANDLE;
00587 
00588     rv = SCardCheckDaemonAvailability();
00589     if (rv != SCARD_S_SUCCESS)
00590     {
00591         /*
00592          * Remove the local context from the stack
00593          */
00594         SCardLockThread();
00595         SCardRemoveContext(hContext);
00596         SCardUnlockThread();
00597 
00598         return rv;
00599     }
00600 
00601     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
00602 
00603     scReleaseStruct.hContext = hContext;
00604     scReleaseStruct.rv = SCARD_S_SUCCESS;
00605 
00606     rv = WrapSHMWrite(SCARD_RELEASE_CONTEXT,
00607         psContextMap[dwContextIndex].dwClientID,
00608         sizeof(scReleaseStruct),
00609         PCSCLITE_MCLIENT_ATTEMPTS, (void *) &scReleaseStruct);
00610 
00611     if (rv == -1)
00612     {
00613         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00614         return SCARD_E_NO_SERVICE;
00615     }
00616 
00617     /*
00618      * Read a message from the server
00619      */
00620     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
00621         PCSCLITE_CLIENT_ATTEMPTS);
00622     memcpy(&scReleaseStruct, &msgStruct.data, sizeof(scReleaseStruct));
00623 
00624     if (rv == -1)
00625     {
00626         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00627         return SCARD_F_COMM_ERROR;
00628     }
00629 
00630     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00631 
00632     /*
00633      * Remove the local context from the stack
00634      */
00635     SCardLockThread();
00636     SCardRemoveContext(hContext);
00637     SCardUnlockThread();
00638 
00639     PROFILE_END(scReleaseStruct.rv)
00640 
00641     return scReleaseStruct.rv;
00642 }
00643 
00657 LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout)
00658 {
00659     /*
00660      * Deprecated
00661      */
00662 
00663     return SCARD_S_SUCCESS;
00664 }
00665 
00718 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
00719     DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
00720     LPDWORD pdwActiveProtocol)
00721 {
00722     LONG rv;
00723     connect_struct scConnectStruct;
00724     sharedSegmentMsg msgStruct;
00725     LONG dwContextIndex;
00726 
00727     PROFILE_START
00728 
00729     /*
00730      * Check for NULL parameters
00731      */
00732     if (phCard == NULL || pdwActiveProtocol == NULL)
00733         return SCARD_E_INVALID_PARAMETER;
00734     else
00735         *phCard = 0;
00736 
00737     if (szReader == NULL)
00738         return SCARD_E_UNKNOWN_READER;
00739 
00740     /*
00741      * Check for uninitialized strings
00742      */
00743     if (strlen(szReader) > MAX_READERNAME)
00744         return SCARD_E_INVALID_VALUE;
00745 
00746     if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
00747         !(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
00748         !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
00749         !(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
00750     {
00751         return SCARD_E_INVALID_VALUE;
00752     }
00753 
00754     rv = SCardCheckDaemonAvailability();
00755     if (rv != SCARD_S_SUCCESS)
00756         return rv;
00757 
00758     /*
00759      * Make sure this context has been opened
00760      */
00761     dwContextIndex = SCardGetContextIndice(hContext);
00762     if (dwContextIndex == -1)
00763         return SCARD_E_INVALID_HANDLE;
00764 
00765     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
00766 
00767     strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
00768 
00769     scConnectStruct.hContext = hContext;
00770     scConnectStruct.dwShareMode = dwShareMode;
00771     scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00772     scConnectStruct.phCard = 0;
00773     scConnectStruct.pdwActiveProtocol = 0;
00774     scConnectStruct.rv = SCARD_S_SUCCESS;
00775 
00776     rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID,
00777         sizeof(scConnectStruct),
00778         PCSCLITE_CLIENT_ATTEMPTS, (void *) &scConnectStruct);
00779 
00780     if (rv == -1)
00781     {
00782         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00783         return SCARD_E_NO_SERVICE;
00784     }
00785 
00786     /*
00787      * Read a message from the server
00788      */
00789     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
00790         PCSCLITE_CLIENT_ATTEMPTS);
00791 
00792     memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct));
00793 
00794     if (rv == -1)
00795     {
00796         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00797         return SCARD_F_COMM_ERROR;
00798     }
00799 
00800     *phCard = scConnectStruct.phCard;
00801     *pdwActiveProtocol = scConnectStruct.pdwActiveProtocol;
00802 
00803     if (scConnectStruct.rv == SCARD_S_SUCCESS)
00804     {
00805         /*
00806          * Keep track of the handle locally
00807          */
00808         rv = SCardAddHandle(*phCard, dwContextIndex, szReader);
00809         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00810 
00811         PROFILE_END(rv)
00812 
00813         return rv;
00814     }
00815 
00816     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00817 
00818     PROFILE_END(scConnectStruct.rv)
00819 
00820     return scConnectStruct.rv;
00821 }
00822 
00888 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
00889     DWORD dwPreferredProtocols, DWORD dwInitialization,
00890     LPDWORD pdwActiveProtocol)
00891 {
00892     LONG rv;
00893     reconnect_struct scReconnectStruct;
00894     sharedSegmentMsg msgStruct;
00895     int i;
00896     DWORD dwContextIndex, dwChannelIndex;
00897 
00898     PROFILE_START
00899 
00900     if (dwInitialization != SCARD_LEAVE_CARD &&
00901         dwInitialization != SCARD_RESET_CARD &&
00902         dwInitialization != SCARD_UNPOWER_CARD &&
00903         dwInitialization != SCARD_EJECT_CARD)
00904     {
00905         return SCARD_E_INVALID_VALUE;
00906     }
00907 
00908     if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
00909         !(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
00910         !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
00911         !(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
00912     {
00913         return SCARD_E_INVALID_VALUE;
00914     }
00915 
00916     if (pdwActiveProtocol == NULL)
00917         return SCARD_E_INVALID_PARAMETER;
00918 
00919     rv = SCardCheckDaemonAvailability();
00920     if (rv != SCARD_S_SUCCESS)
00921         return rv;
00922 
00923     /*
00924      * Make sure this handle has been opened
00925      */
00926     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
00927 
00928     if (rv == -1)
00929         return SCARD_E_INVALID_HANDLE;
00930 
00931     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
00932 
00933 
00934     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00935     {
00936         char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
00937 
00938         /* by default r == NULL */
00939         if (r && strcmp(r, (readerStates[i])->readerName) == 0)
00940             break;
00941     }
00942 
00943     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
00944     {
00945         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00946         return SCARD_E_READER_UNAVAILABLE;
00947     }
00948 
00949     do
00950     {
00951         scReconnectStruct.hCard = hCard;
00952         scReconnectStruct.dwShareMode = dwShareMode;
00953         scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
00954         scReconnectStruct.dwInitialization = dwInitialization;
00955         scReconnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
00956         scReconnectStruct.rv = SCARD_S_SUCCESS;
00957 
00958         rv = WrapSHMWrite(SCARD_RECONNECT, psContextMap[dwContextIndex].dwClientID,
00959             sizeof(scReconnectStruct),
00960             PCSCLITE_CLIENT_ATTEMPTS, (void *) &scReconnectStruct);
00961 
00962         if (rv == -1)
00963         {
00964             SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00965             return SCARD_E_NO_SERVICE;
00966         }
00967 
00968         /*
00969          * Read a message from the server
00970          */
00971         rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
00972             PCSCLITE_CLIENT_ATTEMPTS);
00973 
00974         memcpy(&scReconnectStruct, &msgStruct.data, sizeof(scReconnectStruct));
00975 
00976         if (rv == -1)
00977         {
00978             SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00979             return SCARD_F_COMM_ERROR;
00980         }
00981     } while (SCARD_E_SHARING_VIOLATION == scReconnectStruct.rv);
00982 
00983     *pdwActiveProtocol = scReconnectStruct.pdwActiveProtocol;
00984 
00985     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
00986 
00987     PROFILE_END(scReconnectStruct.rv)
00988 
00989     return scReconnectStruct.rv;
00990 }
00991 
01023 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
01024 {
01025     LONG rv;
01026     disconnect_struct scDisconnectStruct;
01027     sharedSegmentMsg msgStruct;
01028     DWORD dwContextIndex, dwChannelIndex;
01029 
01030     PROFILE_START
01031 
01032     if (dwDisposition != SCARD_LEAVE_CARD &&
01033         dwDisposition != SCARD_RESET_CARD &&
01034         dwDisposition != SCARD_UNPOWER_CARD &&
01035         dwDisposition != SCARD_EJECT_CARD)
01036     {
01037         return SCARD_E_INVALID_VALUE;
01038     }
01039 
01040     rv = SCardCheckDaemonAvailability();
01041     if (rv != SCARD_S_SUCCESS)
01042         return rv;
01043 
01044     /*
01045      * Make sure this handle has been opened
01046      */
01047     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
01048 
01049     if (rv == -1)
01050         return SCARD_E_INVALID_HANDLE;
01051 
01052     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01053 
01054     scDisconnectStruct.hCard = hCard;
01055     scDisconnectStruct.dwDisposition = dwDisposition;
01056     scDisconnectStruct.rv = SCARD_S_SUCCESS;
01057 
01058     rv = WrapSHMWrite(SCARD_DISCONNECT, psContextMap[dwContextIndex].dwClientID,
01059         sizeof(scDisconnectStruct),
01060         PCSCLITE_CLIENT_ATTEMPTS, (void *) &scDisconnectStruct);
01061 
01062     if (rv == -1)
01063     {
01064         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01065         return SCARD_E_NO_SERVICE;
01066     }
01067 
01068     /*
01069      * Read a message from the server
01070      */
01071     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
01072         PCSCLITE_CLIENT_ATTEMPTS);
01073 
01074     memcpy(&scDisconnectStruct, &msgStruct.data,
01075         sizeof(scDisconnectStruct));
01076 
01077     if (rv == -1)
01078     {
01079         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01080         return SCARD_F_COMM_ERROR;
01081     }
01082 
01083     SCardRemoveHandle(hCard);
01084 
01085     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01086 
01087     PROFILE_END(scDisconnectStruct.rv)
01088 
01089     return scDisconnectStruct.rv;
01090 }
01091 
01127 LONG SCardBeginTransaction(SCARDHANDLE hCard)
01128 {
01129 
01130     LONG rv;
01131     begin_struct scBeginStruct;
01132     int i;
01133     sharedSegmentMsg msgStruct;
01134     DWORD dwContextIndex, dwChannelIndex;
01135 
01136     PROFILE_START
01137 
01138     rv = SCardCheckDaemonAvailability();
01139     if (rv != SCARD_S_SUCCESS)
01140         return rv;
01141 
01142     /*
01143      * Make sure this handle has been opened
01144      */
01145     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
01146 
01147     if (rv == -1)
01148         return SCARD_E_INVALID_HANDLE;
01149 
01150     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01151 
01152     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01153     {
01154         char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
01155 
01156         /* by default r == NULL */
01157         if (r && strcmp(r, (readerStates[i])->readerName) == 0)
01158             break;
01159     }
01160 
01161     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01162     {
01163         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01164         return SCARD_E_READER_UNAVAILABLE;
01165     }
01166 
01167     scBeginStruct.hCard = hCard;
01168     scBeginStruct.rv = SCARD_S_SUCCESS;
01169 
01170     /*
01171      * Query the server every so often until the sharing violation ends
01172      * and then hold the lock for yourself.
01173      */
01174 
01175     do
01176     {
01177         rv = WrapSHMWrite(SCARD_BEGIN_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
01178             sizeof(scBeginStruct),
01179             PCSCLITE_CLIENT_ATTEMPTS, (void *) &scBeginStruct);
01180 
01181         if (rv == -1)
01182         {
01183 
01184             SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01185             return SCARD_E_NO_SERVICE;
01186         }
01187 
01188         /*
01189          * Read a message from the server
01190          */
01191         rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
01192             PCSCLITE_CLIENT_ATTEMPTS);
01193 
01194         memcpy(&scBeginStruct, &msgStruct.data, sizeof(scBeginStruct));
01195 
01196         if (rv == -1)
01197         {
01198 
01199             SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01200             return SCARD_F_COMM_ERROR;
01201         }
01202 
01203     }
01204     while (scBeginStruct.rv == SCARD_E_SHARING_VIOLATION);
01205 
01206     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01207 
01208     PROFILE_END(scBeginStruct.rv);
01209 
01210     return scBeginStruct.rv;
01211 }
01212 
01253 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
01254 {
01255     LONG rv;
01256     end_struct scEndStruct;
01257     sharedSegmentMsg msgStruct;
01258     int randnum, i;
01259     DWORD dwContextIndex, dwChannelIndex;
01260 
01261     PROFILE_START
01262 
01263     /*
01264      * Zero out everything
01265      */
01266     randnum = 0;
01267 
01268     if (dwDisposition != SCARD_LEAVE_CARD &&
01269         dwDisposition != SCARD_RESET_CARD &&
01270         dwDisposition != SCARD_UNPOWER_CARD &&
01271         dwDisposition != SCARD_EJECT_CARD)
01272     {
01273         return SCARD_E_INVALID_VALUE;
01274     }
01275 
01276     rv = SCardCheckDaemonAvailability();
01277     if (rv != SCARD_S_SUCCESS)
01278         return rv;
01279 
01280     /*
01281      * Make sure this handle has been opened
01282      */
01283     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
01284 
01285     if (rv == -1)
01286         return SCARD_E_INVALID_HANDLE;
01287 
01288     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01289 
01290     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01291     {
01292         char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
01293 
01294         /* by default r == NULL */
01295         if (r && strcmp(r, (readerStates[i])->readerName) == 0)
01296             break;
01297     }
01298 
01299     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01300     {
01301         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01302         return SCARD_E_READER_UNAVAILABLE;
01303     }
01304 
01305     scEndStruct.hCard = hCard;
01306     scEndStruct.dwDisposition = dwDisposition;
01307     scEndStruct.rv = SCARD_S_SUCCESS;
01308 
01309     rv = WrapSHMWrite(SCARD_END_TRANSACTION,
01310         psContextMap[dwContextIndex].dwClientID,
01311         sizeof(scEndStruct),
01312         PCSCLITE_CLIENT_ATTEMPTS, (void *) &scEndStruct);
01313 
01314     if (rv == -1)
01315     {
01316         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01317         return SCARD_E_NO_SERVICE;
01318     }
01319 
01320     /*
01321      * Read a message from the server
01322      */
01323     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
01324         PCSCLITE_CLIENT_ATTEMPTS);
01325 
01326     memcpy(&scEndStruct, &msgStruct.data, sizeof(scEndStruct));
01327 
01328     if (rv == -1)
01329     {
01330         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01331         return SCARD_F_COMM_ERROR;
01332     }
01333 
01334     /*
01335      * This helps prevent starvation
01336      */
01337     randnum = SYS_RandomInt(1000, 10000);
01338     SYS_USleep(randnum);
01339 
01340     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01341 
01342     PROFILE_END(scEndStruct.rv)
01343 
01344     return scEndStruct.rv;
01345 }
01346 
01353 LONG SCardCancelTransaction(SCARDHANDLE hCard)
01354 {
01355     LONG rv;
01356     cancel_struct scCancelStruct;
01357     sharedSegmentMsg msgStruct;
01358     int i;
01359     DWORD dwContextIndex, dwChannelIndex;
01360 
01361     PROFILE_START
01362 
01363     rv = SCardCheckDaemonAvailability();
01364     if (rv != SCARD_S_SUCCESS)
01365         return rv;
01366 
01367     /*
01368      * Make sure this handle has been opened
01369      */
01370     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
01371 
01372     if (rv == -1)
01373         return SCARD_E_INVALID_HANDLE;
01374 
01375     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01376 
01377     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01378     {
01379         char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
01380 
01381         /* by default r == NULL */
01382         if (r && strcmp(r, (readerStates[i])->readerName) == 0)
01383             break;
01384     }
01385 
01386     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01387     {
01388         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01389         return SCARD_E_READER_UNAVAILABLE;
01390     }
01391 
01392     scCancelStruct.hCard = hCard;
01393 
01394     rv = WrapSHMWrite(SCARD_CANCEL_TRANSACTION,
01395         psContextMap[dwContextIndex].dwClientID,
01396         sizeof(scCancelStruct),
01397         PCSCLITE_CLIENT_ATTEMPTS, (void *) &scCancelStruct);
01398 
01399     if (rv == -1)
01400     {
01401         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01402         return SCARD_E_NO_SERVICE;
01403     }
01404 
01405     /*
01406      * Read a message from the server
01407      */
01408     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
01409         PCSCLITE_CLIENT_ATTEMPTS);
01410 
01411     memcpy(&scCancelStruct, &msgStruct.data, sizeof(scCancelStruct));
01412 
01413     if (rv == -1)
01414     {
01415         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01416         return SCARD_F_COMM_ERROR;
01417     }
01418 
01419     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01420 
01421     PROFILE_END(scCancelStruct.rv)
01422 
01423     return scCancelStruct.rv;
01424 }
01425 
01487 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames,
01488     LPDWORD pcchReaderLen, LPDWORD pdwState,
01489     LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
01490 {
01491     DWORD dwReaderLen, dwAtrLen;
01492     LONG rv;
01493     int i;
01494     status_struct scStatusStruct;
01495     sharedSegmentMsg msgStruct;
01496     DWORD dwContextIndex, dwChannelIndex;
01497     char *r;
01498 
01499     PROFILE_START
01500 
01501     /*
01502      * Check for NULL parameters
01503      */
01504 
01505     if (pcchReaderLen == NULL || pcbAtrLen == NULL)
01506         return SCARD_E_INVALID_PARAMETER;
01507 
01508     /* length passed from caller */
01509     dwReaderLen = *pcchReaderLen;
01510     dwAtrLen = *pcbAtrLen;
01511 
01512     /* default output values */
01513     if (pdwState)
01514         *pdwState = 0;
01515 
01516     if (pdwProtocol)
01517         *pdwProtocol = 0;
01518 
01519     *pcchReaderLen = 0;
01520     *pcbAtrLen = 0;
01521 
01522     rv = SCardCheckDaemonAvailability();
01523     if (rv != SCARD_S_SUCCESS)
01524         return rv;
01525 
01526     /*
01527      * Make sure this handle has been opened
01528      */
01529     rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
01530 
01531     if (rv == -1)
01532         return SCARD_E_INVALID_HANDLE;
01533 
01534     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01535 
01536     r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
01537     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
01538     {
01539         /* by default r == NULL */
01540         if (r && strcmp(r, (readerStates[i])->readerName) == 0)
01541             break;
01542     }
01543 
01544     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
01545     {
01546         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01547         return SCARD_E_READER_UNAVAILABLE;
01548     }
01549 
01550     /* initialise the structure */
01551     memset(&scStatusStruct, 0, sizeof(scStatusStruct));
01552     scStatusStruct.hCard = hCard;
01553 
01554     /* those sizes need to be initialised */
01555     scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
01556     scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
01557 
01558     rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID,
01559         sizeof(scStatusStruct),
01560         PCSCLITE_CLIENT_ATTEMPTS, (void *) &scStatusStruct);
01561 
01562     if (rv == -1)
01563     {
01564         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01565         return SCARD_E_NO_SERVICE;
01566     }
01567 
01568     /*
01569      * Read a message from the server
01570      */
01571     rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,
01572         PCSCLITE_CLIENT_ATTEMPTS);
01573 
01574     memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct));
01575 
01576     if (rv == -1)
01577     {
01578         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01579         return SCARD_F_COMM_ERROR;
01580     }
01581 
01582     rv = scStatusStruct.rv;
01583     if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
01584     {
01585         /*
01586          * An event must have occurred
01587          */
01588         SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01589         return rv;
01590     }
01591 
01592     /*
01593      * Now continue with the client side SCardStatus
01594      */
01595 
01596     *pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1;
01597     *pcbAtrLen = (readerStates[i])->cardAtrLength;
01598 
01599     if (pdwState)
01600         *pdwState = (readerStates[i])->readerState;
01601 
01602     if (pdwProtocol)
01603         *pdwProtocol = (readerStates[i])->cardProtocol;
01604 
01605     /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
01606     if (mszReaderNames)
01607     {
01608         if (*pcchReaderLen > dwReaderLen)
01609             rv = SCARD_E_INSUFFICIENT_BUFFER;
01610 
01611         strncpy(mszReaderNames,
01612             psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,
01613             dwReaderLen);
01614     }
01615 
01616     if (pbAtr)
01617     {
01618         if (*pcbAtrLen > dwAtrLen)
01619             rv = SCARD_E_INSUFFICIENT_BUFFER;
01620 
01621         memcpy(pbAtr, (readerStates[i])->cardAtr,
01622             min(*pcbAtrLen, dwAtrLen));
01623     }
01624 
01625     SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
01626 
01627     PROFILE_END(rv)
01628 
01629     return rv;
01630 }
01631 
01719 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
01720     LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
01721 {
01722     PSCARD_READERSTATE_A currReader;
01723     PREADER_STATE rContext;
01724     DWORD dwTime = 0;
01725     DWORD dwState;
01726     DWORD dwBreakFlag = 0;
01727     int j;
01728     LONG dwContextIndex;
01729     int currentReaderCount = 0;
01730     LONG rv;
01731 
01732     PROFILE_START
01733 
01734     if (rgReaderStates == NULL && cReaders > 0)
01735         return SCARD_E_INVALID_PARAMETER;
01736 
01737     rv = SCardCheckDaemonAvailability();
01738     if (rv != SCARD_S_SUCCESS)
01739         return rv;
01740 
01741     /*
01742      * Make sure this context has been opened
01743      */
01744 
01745     dwContextIndex = SCardGetContextIndice(hContext);
01746     if (dwContextIndex == -1)
01747         return SCARD_E_INVALID_HANDLE;
01748 
01749     SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
01750 
01751     /*
01752      * Application is waiting for a reader - return the first available
01753      * reader
01754      */
01755 
01756     if (cReaders == 0)
01757