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