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