/* Log PC/SC arguments Copyright (C) 2011-2013 Ludovic Rousseau This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include #define DEBUG /* function prototypes */ #define p_SCardEstablishContext(fct) LONG(fct)(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) #define p_SCardReleaseContext(fct) LONG(fct)(SCARDCONTEXT hContext) #define p_SCardIsValidContext(fct) LONG(fct) (SCARDCONTEXT hContext) #define p_SCardConnect(fct) LONG(fct) (SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) #define p_SCardReconnect(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol) #define p_SCardDisconnect(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwDisposition) #define p_SCardBeginTransaction(fct) LONG(fct) (SCARDHANDLE hCard) #define p_SCardEndTransaction(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwDisposition) #define p_SCardStatus(fct) LONG(fct) (SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) #define p_SCardGetStatusChange(fct) LONG(fct) (SCARDCONTEXT hContext, DWORD dwTimeout, LPSCARD_READERSTATE rgReaderStates, DWORD cReaders) #define p_SCardControl(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned) #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) #define p_SCardListReaderGroups(fct) LONG(fct) (SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups) #define p_SCardListReaders(fct) LONG(fct) (SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders) #define p_SCardFreeMemory(fct) LONG(fct) (SCARDCONTEXT hContext, LPCVOID pvMem) #define p_SCardCancel(fct) LONG(fct) (SCARDCONTEXT hContext) #define p_SCardGetAttrib(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen) #define p_SCardSetAttrib(fct) LONG(fct) (SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen) #define p_pcsc_stringify_error(fct) const char *(fct)(const LONG pcscError) /* fake function to just return en error code */ static LONG internal_error(void) { return SCARD_F_INTERNAL_ERROR; } static const char * internal_stringify_error(void) { return "No spy pcsc_stringify_error() function"; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" /* contains pointers to real functions */ static struct { p_SCardEstablishContext(*SCardEstablishContext); p_SCardReleaseContext(*SCardReleaseContext); p_SCardIsValidContext(*SCardIsValidContext); p_SCardConnect(*SCardConnect); p_SCardReconnect(*SCardReconnect); p_SCardDisconnect(*SCardDisconnect); p_SCardBeginTransaction(*SCardBeginTransaction); p_SCardEndTransaction(*SCardEndTransaction); p_SCardStatus(*SCardStatus); p_SCardGetStatusChange(*SCardGetStatusChange); p_SCardControl(*SCardControl); p_SCardTransmit(*SCardTransmit); p_SCardListReaderGroups(*SCardListReaderGroups); p_SCardListReaders(*SCardListReaders); p_SCardFreeMemory(*SCardFreeMemory); p_SCardCancel(*SCardCancel); p_SCardGetAttrib(*SCardGetAttrib); p_SCardSetAttrib(*SCardSetAttrib); p_pcsc_stringify_error(*pcsc_stringify_error); } spy = { /* initialized with the fake internal_error() function */ .SCardEstablishContext = (p_SCardEstablishContext(*))internal_error, .SCardReleaseContext = (p_SCardReleaseContext(*))internal_error, .SCardIsValidContext = (p_SCardIsValidContext(*))internal_error, .SCardConnect = (p_SCardConnect(*))internal_error, .SCardReconnect = (p_SCardReconnect(*))internal_error, .SCardDisconnect = (p_SCardDisconnect(*))internal_error, .SCardBeginTransaction = (p_SCardBeginTransaction(*))internal_error, .SCardEndTransaction = (p_SCardEndTransaction(*))internal_error, .SCardStatus = (p_SCardStatus(*))internal_error, .SCardGetStatusChange = (p_SCardGetStatusChange(*))internal_error, .SCardControl = (p_SCardControl(*))internal_error, .SCardTransmit = (p_SCardTransmit(*))internal_error, .SCardListReaderGroups = (p_SCardListReaderGroups(*))internal_error, .SCardListReaders = (p_SCardListReaders(*))internal_error, .SCardFreeMemory = (p_SCardFreeMemory(*))internal_error, .SCardCancel = (p_SCardCancel(*))internal_error, .SCardGetAttrib = (p_SCardGetAttrib(*))internal_error, .SCardSetAttrib = (p_SCardSetAttrib(*))internal_error, .pcsc_stringify_error = (p_pcsc_stringify_error(*))internal_stringify_error }; #pragma GCC diagnostic pop #define LOG log_line("%s:%d", __FILE__, __LINE__) static int Log_fd = -1; static void *Lib_handle = NULL; static pthread_mutex_t Log_fd_mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef DEBUG static void log_line(const char *fmt, ...) { va_list args; va_start(args, fmt); vprintf(fmt, args); printf("\n"); va_end(args); } #else static void log_line(const char *fmt, ...) { } #endif static void spy_line_direct(char *line) { char threadid[30]; ssize_t r; /* spying disabled */ if (Log_fd < 0) return; snprintf(threadid, sizeof threadid, "%lX@", pthread_self()); pthread_mutex_lock(&Log_fd_mutex); r = write(Log_fd, threadid, strlen(threadid)); r = write(Log_fd, line, strlen(line)); r = write(Log_fd, "\n", 1); (void)r; pthread_mutex_unlock(&Log_fd_mutex); } static void spy_line(const char *fmt, ...) { va_list args; char line[256]; int size; char threadid[30]; ssize_t r; /* spying disabled */ if (Log_fd < 0) return; va_start(args, fmt); size = vsnprintf(line, sizeof line, fmt, args); va_end(args); if ((size_t)size >= sizeof line) { printf("libpcsc-spy: Buffer is too small!\n"); return; } snprintf(threadid, sizeof threadid, "%lX@", pthread_self()); pthread_mutex_lock(&Log_fd_mutex); r = write(Log_fd, threadid, strlen(threadid)); r = write(Log_fd, line, size); r = write(Log_fd, "\n", 1); (void)r; pthread_mutex_unlock(&Log_fd_mutex); } static void spy_enter(const char *fname) { struct timeval profile_time; gettimeofday(&profile_time, NULL); spy_line(">|%ld|%ld|%s", profile_time.tv_sec, profile_time.tv_usec, fname); } static void spy_quit(const char *fname, LONG rv) { struct timeval profile_time; gettimeofday(&profile_time, NULL); spy_line("<|%ld|%ld|%s|%s|0x%08lX", profile_time.tv_sec, profile_time.tv_usec, fname, spy.pcsc_stringify_error(rv), rv); } #define Enter() spy_enter(__FUNCTION__) #define Quit() spy_quit(__FUNCTION__, rv) static void spy_long(long arg) { spy_line("0x%08lX", arg); } static void spy_ptr_long(LONG *arg) { if (arg) spy_line("0x%08lX", *arg); else spy_line("NULL"); } static void spy_ptr_ulong(ULONG *arg) { if (arg) spy_line("0x%08lX", *arg); else spy_line("NULL"); } static void spy_pvoid(const void *ptr) { spy_line("%p", ptr); } static void spy_buffer(const unsigned char *buffer, size_t length) { spy_long(length); if (NULL == buffer) spy_line("NULL"); else { /* "78 79 7A" */ char log_buffer[length * 3 +1], *p; size_t i; p = log_buffer; log_buffer[0] = '\0'; for (i=0; idwProtocol); spy_long(pioSendPci->cbPciLength); spy_buffer(pbSendBuffer, cbSendLength); rv = spy.SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength, pioRecvPci, pbRecvBuffer, pcbRecvLength); spy_long(pioRecvPci->dwProtocol); spy_long(pioRecvPci->cbPciLength); if (pcbRecvLength) spy_buffer(pbRecvBuffer, *pcbRecvLength); else spy_buffer(NULL, 0); Quit(); return rv; } PCSC_API p_SCardListReaderGroups(SCardListReaderGroups) { LONG rv; int autoallocate = 0; if (pcchGroups) autoallocate = *pcchGroups == SCARD_AUTOALLOCATE; Enter(); spy_long(hContext); spy_ptr_ulong(pcchGroups); rv = spy.SCardListReaderGroups(hContext, mszGroups, pcchGroups); if (SCARD_S_SUCCESS == rv) spy_n_str(mszGroups, pcchGroups, autoallocate); else spy_n_str(NULL, pcchGroups, 0); Quit(); return rv; } PCSC_API p_SCardListReaders(SCardListReaders) { LONG rv; int autoallocate = 0; if (pcchReaders) autoallocate = *pcchReaders == SCARD_AUTOALLOCATE; Enter(); spy_long(hContext); spy_str(mszGroups); rv = spy.SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders); if (SCARD_S_SUCCESS == rv) spy_n_str(mszReaders, pcchReaders, autoallocate); else spy_n_str(NULL, pcchReaders, 0); Quit(); return rv; } PCSC_API p_SCardFreeMemory(SCardFreeMemory) { LONG rv; Enter(); spy_long(hContext); spy_pvoid(pvMem); rv = spy.SCardFreeMemory(hContext, pvMem); Quit(); return rv; } PCSC_API p_SCardCancel(SCardCancel) { LONG rv; Enter(); spy_long(hContext); rv = spy.SCardCancel(hContext); Quit(); return rv; } PCSC_API p_SCardGetAttrib(SCardGetAttrib) { LONG rv; int autoallocate = 0; if (pcbAttrLen) autoallocate = *pcbAttrLen == SCARD_AUTOALLOCATE; Enter(); spy_long(hCard); spy_long(dwAttrId); rv = spy.SCardGetAttrib(hCard, dwAttrId, pbAttr, pcbAttrLen); if (NULL == pcbAttrLen) spy_buffer(NULL, 0); else { LPBYTE buffer; if (autoallocate) buffer = *(LPBYTE *)pbAttr; else buffer = pbAttr; spy_buffer(buffer, *pcbAttrLen); } Quit(); return rv; } PCSC_API p_SCardSetAttrib(SCardSetAttrib) { LONG rv; Enter(); spy_long(hCard); spy_long(dwAttrId); spy_buffer(pbAttr, cbAttrLen); rv = spy.SCardSetAttrib(hCard, dwAttrId, pbAttr, cbAttrLen); Quit(); return rv; } PCSC_API p_pcsc_stringify_error(pcsc_stringify_error) { return spy.pcsc_stringify_error(pcscError); } PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) }; PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) }; PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };