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