pcsc-lite  1.8.3
libpcscspy.c
00001 /*
00002     Log PC/SC arguments
00003     Copyright (C) 2001  Ludovic Rousseau
00004 
00005     This program is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 /* $Id: libpcscspy.c 6234 2012-02-28 14:38:13Z rousseau $ */
00020 
00021 #include <dlfcn.h>
00022 #include <stdio.h>
00023 #include <stdarg.h>
00024 #include <fcntl.h>
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <sys/time.h>
00030 #include <pthread.h>
00031 
00032 #include "misc.h"
00033 #include <winscard.h>
00034 
00035 #define DEBUG
00036 
00037 #ifdef __APPLE__
00038 #define SCardControl SCardControl132
00039 
00040 PCSC_API int32_t SCardControl132(SCARDHANDLE hCard, uint32_t dwControlCode,
00041         const void *pbSendBuffer, uint32_t cbSendLength,
00042         void *pbRecvBuffer, uint32_t cbRecvLength, uint32_t *lpBytesReturned);
00043 #endif
00044 
00045 /* function prototypes */
00046 
00047 #define p_SCardEstablishContext(fct) LONG(fct)(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
00048 
00049 #define p_SCardReleaseContext(fct) LONG(fct)(SCARDCONTEXT hContext)
00050 
00051 #define p_SCardIsValidContext(fct) LONG(fct) (SCARDCONTEXT hContext)
00052 
00053 #define p_SCardConnect(fct) LONG(fct) (SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
00054 
00055 #define p_SCardReconnect(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
00056 
00057 #define p_SCardDisconnect(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwDisposition)
00058 
00059 #define p_SCardBeginTransaction(fct) LONG(fct) (SCARDHANDLE hCard)
00060 
00061 #define p_SCardEndTransaction(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwDisposition)
00062 
00063 #define p_SCardStatus(fct) LONG(fct) (SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
00064 
00065 #define p_SCardGetStatusChange(fct) LONG(fct) (SCARDCONTEXT hContext, DWORD dwTimeout, LPSCARD_READERSTATE rgReaderStates, DWORD cReaders)
00066 
00067 #define p_SCardControl(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
00068 
00069 #define p_SCardTransmit(fct) LONG(fct) (SCARDHANDLE hCard, const SCARD_IO_REQUEST * pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST * pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
00070 
00071 #define p_SCardListReaderGroups(fct) LONG(fct) (SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
00072 
00073 #define p_SCardListReaders(fct) LONG(fct) (SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
00074 
00075 #define p_SCardFreeMemory(fct) LONG(fct) (SCARDCONTEXT hContext, LPCVOID pvMem)
00076 
00077 #define p_SCardCancel(fct) LONG(fct) (SCARDCONTEXT hContext)
00078 
00079 #define p_SCardGetAttrib(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
00080 
00081 #define p_SCardSetAttrib(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
00082 
00083 #define p_pcsc_stringify_error(fct) char *(fct)(const LONG pcscError)
00084 
00085 /* fake function to just return en error code */
00086 static LONG internal_error(void)
00087 {
00088     return SCARD_F_INTERNAL_ERROR;
00089 }
00090 
00091 static const char * internal_stringify_error(void)
00092 {
00093     return "No spy pcsc_stringify_error() function";
00094 }
00095 
00096 /* contains pointers to real functions */
00097 static struct
00098 {
00099     p_SCardEstablishContext(*SCardEstablishContext);
00100     p_SCardReleaseContext(*SCardReleaseContext);
00101     p_SCardIsValidContext(*SCardIsValidContext);
00102     p_SCardConnect(*SCardConnect);
00103     p_SCardReconnect(*SCardReconnect);
00104     p_SCardDisconnect(*SCardDisconnect);
00105     p_SCardBeginTransaction(*SCardBeginTransaction);
00106     p_SCardEndTransaction(*SCardEndTransaction);
00107     p_SCardStatus(*SCardStatus);
00108     p_SCardGetStatusChange(*SCardGetStatusChange);
00109     p_SCardControl(*SCardControl);
00110     p_SCardTransmit(*SCardTransmit);
00111     p_SCardListReaderGroups(*SCardListReaderGroups);
00112     p_SCardListReaders(*SCardListReaders);
00113     p_SCardFreeMemory(*SCardFreeMemory);
00114     p_SCardCancel(*SCardCancel);
00115     p_SCardGetAttrib(*SCardGetAttrib);
00116     p_SCardSetAttrib(*SCardSetAttrib);
00117     p_pcsc_stringify_error(*pcsc_stringify_error);
00118 } spy = {
00119     /* initialized with the fake internal_error() function */
00120     .SCardEstablishContext = (p_SCardEstablishContext(*))internal_error,
00121     .SCardReleaseContext = (p_SCardReleaseContext(*))internal_error,
00122     .SCardIsValidContext = (p_SCardIsValidContext(*))internal_error,
00123     .SCardConnect = (p_SCardConnect(*))internal_error,
00124     .SCardReconnect = (p_SCardReconnect(*))internal_error,
00125     .SCardDisconnect = (p_SCardDisconnect(*))internal_error,
00126     .SCardBeginTransaction = (p_SCardBeginTransaction(*))internal_error,
00127     .SCardEndTransaction = (p_SCardEndTransaction(*))internal_error,
00128     .SCardStatus = (p_SCardStatus(*))internal_error,
00129     .SCardGetStatusChange = (p_SCardGetStatusChange(*))internal_error,
00130     .SCardControl = (p_SCardControl(*))internal_error,
00131     .SCardTransmit = (p_SCardTransmit(*))internal_error,
00132     .SCardListReaderGroups = (p_SCardListReaderGroups(*))internal_error,
00133     .SCardListReaders = (p_SCardListReaders(*))internal_error,
00134     .SCardFreeMemory = (p_SCardFreeMemory(*))internal_error,
00135     .SCardCancel = (p_SCardCancel(*))internal_error,
00136     .SCardGetAttrib = (p_SCardGetAttrib(*))internal_error,
00137     .SCardSetAttrib = (p_SCardSetAttrib(*))internal_error,
00138     .pcsc_stringify_error = (p_pcsc_stringify_error(*))internal_stringify_error
00139 };
00140 
00141 #define LOG log_line("%s:%d", __FILE__, __LINE__)
00142 
00143 static int Log_fd = -1;
00144 static void *Lib_handle = NULL;
00145 static pthread_mutex_t Log_fd_mutex = PTHREAD_MUTEX_INITIALIZER;
00146 
00147 #ifdef DEBUG
00148 static void log_line(const char *fmt, ...)
00149 {
00150     va_list args;
00151 
00152     va_start(args, fmt);
00153     vprintf(fmt, args);
00154     printf("\n");
00155     va_end(args);
00156 }
00157 #else
00158 static void log_line(const char *fmt, ...)
00159 {
00160 }
00161 #endif
00162 
00163 static void spy_line_direct(char *line)
00164 {
00165     char threadid[30];
00166 
00167     /* spying disabled */
00168     if (Log_fd < 0)
00169         return;
00170 
00171     snprintf(threadid, sizeof threadid, "%lX@", pthread_self());
00172     pthread_mutex_lock(&Log_fd_mutex);
00173     write(Log_fd, threadid, strlen(threadid));
00174     write(Log_fd, line, strlen(line));
00175     write(Log_fd, "\n", 1);
00176     pthread_mutex_unlock(&Log_fd_mutex);
00177 }
00178 
00179 static void spy_line(const char *fmt, ...)
00180 {
00181     va_list args;
00182     char line[256];
00183     int size;
00184     char threadid[30];
00185 
00186     /* spying disabled */
00187     if (Log_fd < 0)
00188         return;
00189 
00190     va_start(args, fmt);
00191     size = vsnprintf(line, sizeof line, fmt, args);
00192     if ((size_t)size >= sizeof line)
00193     {
00194         printf("libpcsc-spy: Buffer is too small!\n");
00195         return;
00196     }
00197     snprintf(threadid, sizeof threadid, "%lX@", pthread_self());
00198     pthread_mutex_lock(&Log_fd_mutex);
00199     write(Log_fd, threadid, strlen(threadid));
00200     write(Log_fd, line, size);
00201     write(Log_fd, "\n", 1);
00202     pthread_mutex_unlock(&Log_fd_mutex);
00203     va_end(args);
00204 }
00205 
00206 static void spy_enter(const char *fname)
00207 {
00208     struct timeval profile_time;
00209 
00210     gettimeofday(&profile_time, NULL);
00211     spy_line(">|%d|%d|%s", profile_time.tv_sec, profile_time.tv_usec, fname);
00212 }
00213 
00214 static void spy_quit(const char *fname, LONG rv)
00215 {
00216     struct timeval profile_time;
00217 
00218     gettimeofday(&profile_time, NULL);
00219     spy_line("<|%d|%d|%s|%s|0x%08X", profile_time.tv_sec,
00220         profile_time.tv_usec, fname, spy.pcsc_stringify_error(rv), rv);
00221 }
00222 
00223 #define Enter() spy_enter(__FUNCTION__)
00224 #define Quit() spy_quit(__FUNCTION__, rv)
00225 
00226 static void spy_long(long arg)
00227 {
00228     spy_line("0x%08lX", arg);
00229 }
00230 
00231 static void spy_ptr_long(LONG *arg)
00232 {
00233     if (arg)
00234         spy_line("0x%08lX", *arg);
00235     else
00236         spy_line("NULL");
00237 }
00238 
00239 static void spy_ptr_ulong(ULONG *arg)
00240 {
00241     if (arg)
00242         spy_line("0x%08lX", *arg);
00243     else
00244         spy_line("NULL");
00245 }
00246 
00247 static void spy_pvoid(const void *ptr)
00248 {
00249     spy_line("%p", ptr);
00250 }
00251 
00252 static void spy_buffer(const unsigned char *buffer, size_t length)
00253 {
00254     spy_long(length);
00255 
00256     if (NULL == buffer)
00257         spy_line("NULL");
00258     else
00259     {
00260         /* "78 79 7A" */
00261         char log_buffer[length * 3 +1], *p;
00262         size_t i;
00263 
00264         p = log_buffer;
00265         log_buffer[0] = '\0';
00266         for (i=0; i<length; i++)
00267         {
00268             snprintf(p, 4, "%02X ", buffer[i]);
00269             p += 3;
00270         }
00271         *p = '\0';
00272 
00273         spy_line_direct(log_buffer);
00274     }
00275 }
00276 
00277 static void spy_str(const char *str)
00278 {
00279     spy_line("%s", str);
00280 }
00281 
00282 static void spy_n_str(const char *str, ULONG *len, int autoallocate)
00283 {
00284     spy_ptr_ulong(len);
00285     if (NULL == len)
00286     {
00287         spy_line("\"\"");
00288     }
00289     else
00290     {
00291         if (NULL == str)
00292         {
00293             spy_line("NULL");
00294         }
00295         else
00296         {
00297             const char *s = str;
00298             unsigned int length = 0;
00299 
00300             if (autoallocate)
00301                 s = *(char **)str;
00302 
00303             do
00304             {
00305                 spy_line("%s", s);
00306                 length += strlen(s)+1;
00307                 s += strlen(s)+1;
00308             } while(length < *len);
00309         }
00310     }
00311 }
00312 
00313 
00314 static void spy_readerstate(SCARD_READERSTATE * rgReaderStates, int cReaders)
00315 {
00316     int i;
00317 
00318     for (i=0; i<cReaders; i++)
00319     {
00320         spy_str(rgReaderStates[i].szReader);
00321         spy_long(rgReaderStates[i].dwCurrentState);
00322         spy_long(rgReaderStates[i].dwEventState);
00323         if (rgReaderStates[i].cbAtr <= MAX_ATR_SIZE)
00324             spy_buffer(rgReaderStates[i].rgbAtr, rgReaderStates[i].cbAtr);
00325         else
00326             spy_buffer(NULL, rgReaderStates[i].cbAtr);
00327     }
00328 }
00329 
00330 static LONG load_lib(void)
00331 {
00332 
00333 #ifdef __APPLE__
00334 /* We should be able to directly use this
00335  * #define LIBPCSC_NOSPY "/System/Library/Frameworks/PCSC.framework/PCSC"
00336  * but for a yet unknown reason the dlsym() returns symbols from the spy
00337  * library and not from the framework.
00338  * Just copying the framework in /tmp does solve the problem.
00339  */
00340 #define LIBPCSC_NOSPY "/tmp/PCSC"
00341 #define LIBPCSC "/tmp/PCSC"
00342 #else
00343 #define LIBPCSC_NOSPY "libpcsclite_nospy.so.1"
00344 #define LIBPCSC "libpcsclite.so.1"
00345 #endif
00346 
00347     /* first try to load the NOSPY library
00348      * this is used for programs doing an explicit dlopen like
00349      * Perl and Python wrappers */
00350     Lib_handle = dlopen(LIBPCSC_NOSPY, RTLD_LAZY);
00351     if (NULL == Lib_handle)
00352     {
00353         log_line("%s", dlerror());
00354 
00355         /* load the normal library */
00356         Lib_handle = dlopen(LIBPCSC, RTLD_LAZY);
00357         if (NULL == Lib_handle)
00358         {
00359             log_line("%s", dlerror());
00360             return SCARD_F_INTERNAL_ERROR;
00361         }
00362     }
00363 
00364 #define get_symbol(s) do { spy.s = dlsym(Lib_handle, #s); if (NULL == spy.s) { log_line("%s", dlerror()); return SCARD_F_INTERNAL_ERROR; } } while (0)
00365 
00366     if (SCardEstablishContext == dlsym(Lib_handle, "SCardEstablishContext"))
00367     {
00368         log_line("Symbols dlsym error");
00369         return SCARD_F_INTERNAL_ERROR;
00370     }
00371 
00372     get_symbol(SCardEstablishContext);
00373     get_symbol(SCardReleaseContext);
00374     get_symbol(SCardIsValidContext);
00375     get_symbol(SCardConnect);
00376     get_symbol(SCardReconnect);
00377     get_symbol(SCardDisconnect);
00378     get_symbol(SCardBeginTransaction);
00379     get_symbol(SCardEndTransaction);
00380     get_symbol(SCardStatus);
00381     get_symbol(SCardGetStatusChange);
00382     get_symbol(SCardControl);
00383     get_symbol(SCardTransmit);
00384     get_symbol(SCardListReaderGroups);
00385     get_symbol(SCardListReaders);
00386     /* Mac OS X do not have SCardFreeMemory() */
00387     if (dlsym(Lib_handle, "SCardFreeMemory"))
00388         get_symbol(SCardFreeMemory);
00389     get_symbol(SCardCancel);
00390     get_symbol(SCardGetAttrib);
00391     get_symbol(SCardSetAttrib);
00392     get_symbol(pcsc_stringify_error);
00393 
00394     return SCARD_S_SUCCESS;
00395 }
00396 
00397 
00398 /* exported functions */
00399 PCSC_API p_SCardEstablishContext(SCardEstablishContext)
00400 {
00401     LONG rv;
00402     static int init = 0;
00403 
00404     if (!init)
00405     {
00406         const char *home;
00407         char log_pipe[128];
00408 
00409         init = 1;
00410 
00411         /* load the real library */
00412         rv = load_lib();
00413         if (rv != SCARD_S_SUCCESS)
00414             return rv;
00415 
00416         /* check if we can log */
00417         home = getenv("HOME");
00418         if (NULL == home)
00419             home = "/tmp";
00420 
00421         snprintf(log_pipe, sizeof log_pipe, "%s/pcsc-spy", home);
00422         Log_fd = open(log_pipe, O_WRONLY);
00423         if (Log_fd < 0)
00424         {
00425             log_line("open %s failed: %s", log_pipe, strerror(errno));
00426         }
00427     }
00428 
00429     Enter();
00430     spy_long(dwScope);
00431     rv = spy.SCardEstablishContext(dwScope, pvReserved1, pvReserved2,
00432         phContext);
00433     spy_ptr_long(phContext);
00434     Quit();
00435     return rv;
00436 }
00437 
00438 PCSC_API p_SCardReleaseContext(SCardReleaseContext)
00439 {
00440     LONG rv;
00441 
00442     Enter();
00443     spy_long(hContext);
00444     rv = spy.SCardReleaseContext(hContext);
00445     Quit();
00446     return rv;
00447 }
00448 
00449 PCSC_API p_SCardIsValidContext(SCardIsValidContext)
00450 {
00451     LONG rv;
00452 
00453     Enter();
00454     spy_long(hContext);
00455     rv = spy.SCardIsValidContext(hContext);
00456     Quit();
00457     return rv;
00458 }
00459 
00460 PCSC_API p_SCardConnect(SCardConnect)
00461 {
00462     LONG rv;
00463 
00464     Enter();
00465     spy_long(hContext);
00466     spy_str(szReader);
00467     spy_long(dwShareMode);
00468     spy_long(dwPreferredProtocols);
00469     spy_ptr_long(phCard);
00470     spy_ptr_ulong(pdwActiveProtocol);
00471     rv = spy.SCardConnect(hContext, szReader, dwShareMode,
00472         dwPreferredProtocols, phCard, pdwActiveProtocol);
00473     spy_ptr_long(phCard);
00474     spy_ptr_ulong(pdwActiveProtocol);
00475     Quit();
00476     return rv;
00477 }
00478 
00479 PCSC_API p_SCardReconnect(SCardReconnect)
00480 {
00481     LONG rv;
00482 
00483     Enter();
00484     spy_long(hCard);
00485     spy_long(dwShareMode);
00486     spy_long(dwPreferredProtocols);
00487     spy_long(dwInitialization);
00488     rv = spy.SCardReconnect(hCard, dwShareMode, dwPreferredProtocols,
00489         dwInitialization, pdwActiveProtocol);
00490     spy_ptr_ulong(pdwActiveProtocol);
00491     Quit();
00492     return rv;
00493 }
00494 
00495 PCSC_API p_SCardDisconnect(SCardDisconnect)
00496 {
00497     LONG rv;
00498 
00499     Enter();
00500     spy_long(hCard);
00501     spy_long(dwDisposition);
00502     rv = spy.SCardDisconnect(hCard, dwDisposition);
00503     Quit();
00504     return rv;
00505 }
00506 
00507 PCSC_API p_SCardBeginTransaction(SCardBeginTransaction)
00508 {
00509     LONG rv;
00510 
00511     Enter();
00512     spy_long(hCard);
00513     rv = spy.SCardBeginTransaction(hCard);
00514     Quit();
00515     return rv;
00516 }
00517 
00518 PCSC_API p_SCardEndTransaction(SCardEndTransaction)
00519 {
00520     LONG rv;
00521 
00522     Enter();
00523     spy_long(hCard);
00524     spy_long(dwDisposition);
00525     rv = spy.SCardEndTransaction(hCard, dwDisposition);
00526     Quit();
00527     return rv;
00528 }
00529 
00530 PCSC_API p_SCardStatus(SCardStatus)
00531 {
00532     LONG rv;
00533     int autoallocate_ReaderName = 0, autoallocate_Atr = 0;
00534 
00535     if (pcchReaderLen)
00536         autoallocate_ReaderName = *pcchReaderLen == SCARD_AUTOALLOCATE;
00537 
00538     if (pcbAtrLen)
00539         autoallocate_Atr = *pcbAtrLen == SCARD_AUTOALLOCATE;
00540 
00541     Enter();
00542     spy_long(hCard);
00543     spy_ptr_ulong(pcchReaderLen);
00544     spy_ptr_ulong(pcbAtrLen);
00545     rv = spy.SCardStatus(hCard, mszReaderName, pcchReaderLen, pdwState,
00546         pdwProtocol, pbAtr, pcbAtrLen);
00547     spy_n_str(mszReaderName, pcchReaderLen, autoallocate_ReaderName);
00548     spy_ptr_ulong(pdwState);
00549     spy_ptr_ulong(pdwProtocol);
00550     if (NULL == pcbAtrLen)
00551         spy_line("NULL");
00552     else
00553     {
00554         if (autoallocate_Atr)
00555         {
00556             const unsigned char *b = *(unsigned char **)pbAtr;
00557 
00558             spy_buffer(b, *pcbAtrLen);
00559         }
00560         else
00561             spy_buffer(pbAtr, *pcbAtrLen);
00562     }
00563     Quit();
00564     return rv;
00565 }
00566 
00567 PCSC_API p_SCardGetStatusChange(SCardGetStatusChange)
00568 {
00569     LONG rv;
00570 
00571     Enter();
00572     spy_long(hContext);
00573     spy_long(dwTimeout);
00574     spy_long(cReaders);
00575     spy_readerstate(rgReaderStates, cReaders);
00576     rv = spy.SCardGetStatusChange(hContext, dwTimeout, rgReaderStates,
00577         cReaders);
00578     spy_readerstate(rgReaderStates, cReaders);
00579     Quit();
00580     return rv;
00581 }
00582 
00583 PCSC_API p_SCardControl(SCardControl)
00584 {
00585     LONG rv;
00586 
00587     Enter();
00588     spy_long(hCard);
00589     spy_long(dwControlCode);
00590     spy_buffer(pbSendBuffer, cbSendLength);
00591     rv = spy.SCardControl(hCard, dwControlCode, pbSendBuffer, cbSendLength,
00592         pbRecvBuffer, cbRecvLength, lpBytesReturned);
00593     if (lpBytesReturned)
00594         spy_buffer(pbRecvBuffer, *lpBytesReturned);
00595     else
00596         spy_buffer(NULL, 0);
00597     Quit();
00598     return rv;
00599 }
00600 
00601 PCSC_API p_SCardTransmit(SCardTransmit)
00602 {
00603     LONG rv;
00604 
00605     Enter();
00606     spy_long(hCard);
00607     spy_buffer(pbSendBuffer, cbSendLength);
00608     rv = spy.SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength,
00609         pioRecvPci, pbRecvBuffer, pcbRecvLength);
00610     if (pcbRecvLength)
00611         spy_buffer(pbRecvBuffer, *pcbRecvLength);
00612     else
00613         spy_buffer(NULL, 0);
00614     Quit();
00615     return rv;
00616 }
00617 
00618 PCSC_API p_SCardListReaderGroups(SCardListReaderGroups)
00619 {
00620     LONG rv;
00621     int autoallocate = 0;
00622 
00623     if (pcchGroups)
00624         autoallocate = *pcchGroups == SCARD_AUTOALLOCATE;
00625 
00626     Enter();
00627     spy_long(hContext);
00628     spy_ptr_ulong(pcchGroups);
00629     rv = spy.SCardListReaderGroups(hContext, mszGroups, pcchGroups);
00630     spy_n_str(mszGroups, pcchGroups, autoallocate);
00631     Quit();
00632     return rv;
00633 }
00634 
00635 PCSC_API p_SCardListReaders(SCardListReaders)
00636 {
00637     LONG rv;
00638     int autoallocate = 0;
00639 
00640     if (pcchReaders)
00641         autoallocate = *pcchReaders == SCARD_AUTOALLOCATE;
00642 
00643     Enter();
00644     spy_long(hContext);
00645     spy_str(mszGroups);
00646     rv = spy.SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders);
00647     spy_n_str(mszReaders, pcchReaders, autoallocate);
00648     Quit();
00649     return rv;
00650 }
00651 
00652 PCSC_API p_SCardFreeMemory(SCardFreeMemory)
00653 {
00654     LONG rv;
00655 
00656     Enter();
00657     spy_long(hContext);
00658     spy_pvoid(pvMem);
00659     rv = spy.SCardFreeMemory(hContext, pvMem);
00660     Quit();
00661     return rv;
00662 }
00663 
00664 PCSC_API p_SCardCancel(SCardCancel)
00665 {
00666     LONG rv;
00667 
00668     Enter();
00669     spy_long(hContext);
00670     rv = spy.SCardCancel(hContext);
00671     Quit();
00672     return rv;
00673 }
00674 
00675 PCSC_API p_SCardGetAttrib(SCardGetAttrib)
00676 {
00677     LONG rv;
00678     int autoallocate = 0;
00679 
00680     if (pcbAttrLen)
00681         autoallocate = *pcbAttrLen == SCARD_AUTOALLOCATE;
00682 
00683     Enter();
00684     spy_long(hCard);
00685     spy_long(dwAttrId);
00686     rv = spy.SCardGetAttrib(hCard, dwAttrId, pbAttr, pcbAttrLen);
00687     if (NULL == pcbAttrLen)
00688         spy_buffer(NULL, 0);
00689     else
00690     {
00691         const unsigned char *s = pbAttr;
00692 
00693         if (autoallocate)
00694             s = *(unsigned char **)pbAttr;
00695 
00696         spy_buffer(s, *pcbAttrLen);
00697     }
00698     Quit();
00699     return rv;
00700 }
00701 
00702 PCSC_API p_SCardSetAttrib(SCardSetAttrib)
00703 {
00704     LONG rv;
00705 
00706     Enter();
00707     spy_long(hCard);
00708     spy_long(dwAttrId);
00709     spy_buffer(pbAttr, cbAttrLen);
00710     rv = spy.SCardSetAttrib(hCard, dwAttrId, pbAttr, cbAttrLen);
00711     Quit();
00712     return rv;
00713 }
00714 
00715 PCSC_API p_pcsc_stringify_error(pcsc_stringify_error)
00716 {
00717     return spy.pcsc_stringify_error(pcscError);
00718 }
00719 
00720 PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) };
00721 PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) };
00722 PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };