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