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