pcsc-lite 2.3.3
libpcscspy.c
1/*
2 Log PC/SC arguments
3 Copyright (C) 2011-2024 Ludovic Rousseau
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <dlfcn.h>
20#include <stdio.h>
21#include <stdarg.h>
22#include <fcntl.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <string.h>
26#include <unistd.h>
27#include <sys/time.h>
28#include <pthread.h>
29
30#include "misc.h"
31#include <winscard.h>
32#include "sys_generic.h"
33
34#define DEBUG
35
36#define DLSYM_DECLARE(symbol) \
37 typeof(symbol)* symbol
38#define DLSYM_SET_VALUE(symbol) \
39 .symbol = (typeof(symbol)(*))internal_error
40
41/* fake function to just return en error code */
42static LONG internal_error(void)
43{
45}
46
47#pragma GCC diagnostic push
48#pragma GCC diagnostic ignored "-Wcast-function-type"
49/* contains pointers to real functions */
50static struct
51{
52 DLSYM_DECLARE(SCardEstablishContext);
53 DLSYM_DECLARE(SCardReleaseContext);
54 DLSYM_DECLARE(SCardIsValidContext);
55 DLSYM_DECLARE(SCardConnect);
56 DLSYM_DECLARE(SCardReconnect);
57 DLSYM_DECLARE(SCardDisconnect);
58 DLSYM_DECLARE(SCardBeginTransaction);
59 DLSYM_DECLARE(SCardEndTransaction);
60 DLSYM_DECLARE(SCardStatus);
61 DLSYM_DECLARE(SCardGetStatusChange);
62 DLSYM_DECLARE(SCardControl);
63 DLSYM_DECLARE(SCardTransmit);
64 DLSYM_DECLARE(SCardListReaderGroups);
65 DLSYM_DECLARE(SCardListReaders);
66 DLSYM_DECLARE(SCardFreeMemory);
67 DLSYM_DECLARE(SCardCancel);
68 DLSYM_DECLARE(SCardGetAttrib);
69 DLSYM_DECLARE(SCardSetAttrib);
70} spy = {
71 /* initialized with the fake internal_error() function */
72 DLSYM_SET_VALUE(SCardEstablishContext),
73 DLSYM_SET_VALUE(SCardReleaseContext),
74 DLSYM_SET_VALUE(SCardIsValidContext),
75 DLSYM_SET_VALUE(SCardConnect),
76 DLSYM_SET_VALUE(SCardReconnect),
77 DLSYM_SET_VALUE(SCardDisconnect),
78 DLSYM_SET_VALUE(SCardBeginTransaction),
79 DLSYM_SET_VALUE(SCardEndTransaction),
80 DLSYM_SET_VALUE(SCardStatus),
81 DLSYM_SET_VALUE(SCardGetStatusChange),
82 DLSYM_SET_VALUE(SCardControl),
83 DLSYM_SET_VALUE(SCardTransmit),
84 DLSYM_SET_VALUE(SCardListReaderGroups),
85 DLSYM_SET_VALUE(SCardListReaders),
86 DLSYM_SET_VALUE(SCardFreeMemory),
87 DLSYM_SET_VALUE(SCardCancel),
88 DLSYM_SET_VALUE(SCardGetAttrib),
89 DLSYM_SET_VALUE(SCardSetAttrib)
90};
91#pragma GCC diagnostic pop
92
93#define LOG log_line("%s:%d", __FILE__, __LINE__)
94
95static int Log_fd = -1;
96static void *Lib_handle = NULL;
97static pthread_mutex_t Log_fd_mutex = PTHREAD_MUTEX_INITIALIZER;
98
99#ifdef DEBUG
100static void log_line(const char *fmt, ...)
101{
102 va_list args;
103
104 va_start(args, fmt);
105 vfprintf(stderr, fmt, args);
106 fprintf(stderr, "\n");
107 va_end(args);
108}
109#else
110static void log_line(const char *fmt, ...)
111{
112}
113#endif
114
115static void spy_line_direct(char *line)
116{
117 char threadid[30];
118 ssize_t r;
119
120 /* spying disabled */
121 if (Log_fd < 0)
122 return;
123
124 snprintf(threadid, sizeof threadid, "%lX@", (unsigned long)pthread_self());
125 pthread_mutex_lock(&Log_fd_mutex);
126 r = write(Log_fd, threadid, strlen(threadid));
127 r = write(Log_fd, line, strlen(line));
128 r = write(Log_fd, "\n", 1);
129 (void)r;
130 pthread_mutex_unlock(&Log_fd_mutex);
131}
132
133static void spy_line(const char *fmt, ...)
134{
135 va_list args;
136 char line[256];
137 int size;
138 char threadid[30];
139 ssize_t r;
140
141 /* spying disabled */
142 if (Log_fd < 0)
143 return;
144
145 va_start(args, fmt);
146 size = vsnprintf(line, sizeof line, fmt, args);
147 va_end(args);
148 if ((size_t)size >= sizeof line)
149 {
150 printf("libpcsc-spy: Buffer is too small!\n");
151 return;
152 }
153 snprintf(threadid, sizeof threadid, "%lX@", (unsigned long)pthread_self());
154 pthread_mutex_lock(&Log_fd_mutex);
155 r = write(Log_fd, threadid, strlen(threadid));
156 r = write(Log_fd, line, size);
157 r = write(Log_fd, "\n", 1);
158 (void)r;
159 pthread_mutex_unlock(&Log_fd_mutex);
160}
161
162static void spy_enter(const char *fname)
163{
164 struct timeval profile_time;
165
166 gettimeofday(&profile_time, NULL);
167 spy_line(">|%ld|%ld|%s", profile_time.tv_sec, profile_time.tv_usec, fname);
168}
169
170static void spy_quit(const char *fname, LONG rv)
171{
172 struct timeval profile_time;
173
174 gettimeofday(&profile_time, NULL);
175 spy_line("<|%ld|%ld|%s|0x%08lX", profile_time.tv_sec,
176 profile_time.tv_usec, fname, rv);
177}
178
179#define Enter() spy_enter(__FUNCTION__)
180#define Quit() spy_quit(__FUNCTION__, rv)
181
182static void spy_long(long arg)
183{
184 spy_line("0x%08lX", arg);
185}
186
187static void spy_ptr_long(LONG *arg)
188{
189 if (arg)
190 spy_line("0x%08lX", *arg);
191 else
192 spy_line("NULL");
193}
194
195static void spy_ptr_ulong(ULONG *arg)
196{
197 if (arg)
198 spy_line("0x%08lX", *arg);
199 else
200 spy_line("NULL");
201}
202
203static void spy_pvoid(const void *ptr)
204{
205 spy_line("%p", ptr);
206}
207
208static void spy_buffer(const unsigned char *buffer, size_t length)
209{
210 spy_long(length);
211
212 if (NULL == buffer)
213 spy_line("NULL");
214 else
215 {
216 /* "78 79 7A" */
217 char log_buffer[length * 3 +1], *p;
218 size_t i;
219
220 p = log_buffer;
221 log_buffer[0] = '\0';
222 for (i=0; i<length; i++)
223 {
224 snprintf(p, 4, "%02X ", buffer[i]);
225 p += 3;
226 }
227 *p = '\0';
228
229 spy_line_direct(log_buffer);
230 }
231}
232
233static void spy_str(const char *str)
234{
235 spy_line("%s", str);
236}
237
238static void spy_n_str(const char *str, ULONG *len, int autoallocate)
239{
240 spy_ptr_ulong(len);
241 if (NULL == len)
242 {
243 spy_line("\"\"");
244 }
245 else
246 {
247 if (NULL == str)
248 {
249 spy_line("NULL");
250 }
251 else
252 {
253 const char *s = str;
254 unsigned int length = 0;
255
256 if (autoallocate)
257 s = *(char **)str;
258
259 do
260 {
261 spy_line("%s", s);
262 length += strlen(s)+1;
263 s += strlen(s)+1;
264 } while(length < *len);
265 }
266 }
267}
268
269
270static void spy_readerstate(SCARD_READERSTATE * rgReaderStates, int cReaders)
271{
272 int i;
273
274 for (i=0; i<cReaders; i++)
275 {
276 spy_str(rgReaderStates[i].szReader);
277 spy_long(rgReaderStates[i].dwCurrentState);
278 spy_long(rgReaderStates[i].dwEventState);
279 if (rgReaderStates[i].cbAtr <= MAX_ATR_SIZE)
280 spy_buffer(rgReaderStates[i].rgbAtr, rgReaderStates[i].cbAtr);
281 else
282 spy_buffer(NULL, rgReaderStates[i].cbAtr);
283 }
284}
285
286static LONG load_lib(void)
287{
288
289#define LIBPCSC "libpcsclite_real.so.1"
290
291 const char *lib;
292
293 lib = SYS_GetEnv("LIBPCSCLITE_SPY_DELEGATE");
294 if (NULL == lib)
295 lib = LIBPCSC;
296
297 /* load the normal library */
298 Lib_handle = dlopen(lib, RTLD_LAZY);
299 if (NULL == Lib_handle)
300 {
301 log_line("loading \"%s\" failed: %s", lib, dlerror());
303 }
304
305#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)
306
307 if (SCardEstablishContext == dlsym(Lib_handle, "SCardEstablishContext"))
308 {
309 log_line("Symbols dlsym error");
311 }
312
313 get_symbol(SCardEstablishContext);
314 get_symbol(SCardReleaseContext);
315 get_symbol(SCardIsValidContext);
316 get_symbol(SCardConnect);
317 get_symbol(SCardReconnect);
318 get_symbol(SCardDisconnect);
319 get_symbol(SCardBeginTransaction);
320 get_symbol(SCardEndTransaction);
321 get_symbol(SCardStatus);
322 get_symbol(SCardGetStatusChange);
323 get_symbol(SCardControl);
324 get_symbol(SCardTransmit);
325 get_symbol(SCardListReaderGroups);
326 get_symbol(SCardListReaders);
327 /* Mac OS X do not have SCardFreeMemory() */
328 if (dlsym(Lib_handle, "SCardFreeMemory"))
329 get_symbol(SCardFreeMemory);
330 get_symbol(SCardCancel);
331 get_symbol(SCardGetAttrib);
332 get_symbol(SCardSetAttrib);
333
334 return SCARD_S_SUCCESS;
335}
336
337static void init(void)
338{
339 const char *home;
340 char log_pipe[128];
341
342 /* load the real library */
343 if (load_lib() != SCARD_S_SUCCESS)
344 return;
345
346 /* check if we can log */
347 home = SYS_GetEnv("HOME");
348 if (NULL == home)
349 home = "/tmp";
350
351 snprintf(log_pipe, sizeof log_pipe, "%s/pcsc-spy", home);
352 Log_fd = open(log_pipe, O_WRONLY);
353 if (Log_fd < 0)
354 {
355 log_line("open %s failed: %s", log_pipe, strerror(errno));
356 }
357}
358
359/* exported functions */
360PCSC_API LONG SCardEstablishContext(DWORD dwScope,
361 LPCVOID pvReserved1,
362 LPCVOID pvReserved2,
363 LPSCARDCONTEXT phContext)
364{
365 LONG rv;
366 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
367
368 pthread_once(&once_control, init);
369
370 Enter();
371 spy_long(dwScope);
372 rv = spy.SCardEstablishContext(dwScope, pvReserved1, pvReserved2,
373 phContext);
374 spy_ptr_long(phContext);
375 Quit();
376 return rv;
377}
378
379PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
380{
381 LONG rv;
382
383 Enter();
384 spy_long(hContext);
385 rv = spy.SCardReleaseContext(hContext);
386 Quit();
387 return rv;
388}
389
390PCSC_API LONG SCardIsValidContext(SCARDCONTEXT hContext)
391{
392 LONG rv;
393
394 Enter();
395 spy_long(hContext);
396 rv = spy.SCardIsValidContext(hContext);
397 Quit();
398 return rv;
399}
400
401PCSC_API LONG SCardConnect(SCARDCONTEXT hContext,
402 LPCSTR szReader,
403 DWORD dwShareMode,
404 DWORD dwPreferredProtocols,
405 LPSCARDHANDLE phCard,
406 LPDWORD pdwActiveProtocol)
407{
408 LONG rv;
409
410 Enter();
411 spy_long(hContext);
412 spy_str(szReader);
413 spy_long(dwShareMode);
414 spy_long(dwPreferredProtocols);
415 spy_ptr_long(phCard);
416 spy_ptr_ulong(pdwActiveProtocol);
417 rv = spy.SCardConnect(hContext, szReader, dwShareMode,
418 dwPreferredProtocols, phCard, pdwActiveProtocol);
419 spy_ptr_long(phCard);
420 spy_ptr_ulong(pdwActiveProtocol);
421 Quit();
422 return rv;
423}
424
425PCSC_API LONG SCardReconnect(SCARDHANDLE hCard,
426 DWORD dwShareMode,
427 DWORD dwPreferredProtocols,
428 DWORD dwInitialization,
429 LPDWORD pdwActiveProtocol)
430{
431 LONG rv;
432
433 Enter();
434 spy_long(hCard);
435 spy_long(dwShareMode);
436 spy_long(dwPreferredProtocols);
437 spy_long(dwInitialization);
438 rv = spy.SCardReconnect(hCard, dwShareMode, dwPreferredProtocols,
439 dwInitialization, pdwActiveProtocol);
440 spy_ptr_ulong(pdwActiveProtocol);
441 Quit();
442 return rv;
443}
444
445PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard,
446 DWORD dwDisposition)
447{
448 LONG rv;
449
450 Enter();
451 spy_long(hCard);
452 spy_long(dwDisposition);
453 rv = spy.SCardDisconnect(hCard, dwDisposition);
454 Quit();
455 return rv;
456}
457
458PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
459{
460 LONG rv;
461
462 Enter();
463 spy_long(hCard);
464 rv = spy.SCardBeginTransaction(hCard);
465 Quit();
466 return rv;
467}
468
469PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard,
470 DWORD dwDisposition)
471{
472 LONG rv;
473
474 Enter();
475 spy_long(hCard);
476 spy_long(dwDisposition);
477 rv = spy.SCardEndTransaction(hCard, dwDisposition);
478 Quit();
479 return rv;
480}
481
482PCSC_API LONG SCardStatus(SCARDHANDLE hCard,
483 LPSTR mszReaderName,
484 LPDWORD pcchReaderLen,
485 LPDWORD pdwState,
486 LPDWORD pdwProtocol,
487 LPBYTE pbAtr,
488 LPDWORD pcbAtrLen)
489{
490 LONG rv;
491 int autoallocate_ReaderName = 0, autoallocate_Atr = 0;
492
493 if (pcchReaderLen)
494 autoallocate_ReaderName = *pcchReaderLen == SCARD_AUTOALLOCATE;
495
496 if (pcbAtrLen)
497 autoallocate_Atr = *pcbAtrLen == SCARD_AUTOALLOCATE;
498
499 Enter();
500 spy_long(hCard);
501 spy_ptr_ulong(pcchReaderLen);
502 spy_ptr_ulong(pcbAtrLen);
503 rv = spy.SCardStatus(hCard, mszReaderName, pcchReaderLen, pdwState,
504 pdwProtocol, pbAtr, pcbAtrLen);
505 spy_n_str(mszReaderName, pcchReaderLen, autoallocate_ReaderName);
506 spy_ptr_ulong(pdwState);
507 spy_ptr_ulong(pdwProtocol);
508 if (NULL == pcbAtrLen)
509 spy_line("NULL");
510 else
511 {
512 LPBYTE buffer;
513
514 if (autoallocate_Atr)
515 buffer = *(LPBYTE *)pbAtr;
516 else
517 buffer = pbAtr;
518
519 spy_buffer(buffer, *pcbAtrLen);
520 }
521 Quit();
522 return rv;
523}
524
525PCSC_API LONG SCardGetStatusChange(SCARDCONTEXT hContext,
526 DWORD dwTimeout,
527 SCARD_READERSTATE *rgReaderStates,
528 DWORD cReaders)
529{
530 LONG rv;
531
532 Enter();
533 spy_long(hContext);
534 spy_long(dwTimeout);
535 spy_long(cReaders);
536 spy_readerstate(rgReaderStates, cReaders);
537 rv = spy.SCardGetStatusChange(hContext, dwTimeout, rgReaderStates,
538 cReaders);
539 spy_readerstate(rgReaderStates, cReaders);
540 Quit();
541 return rv;
542}
543
544PCSC_API LONG SCardControl(SCARDHANDLE hCard,
545 DWORD dwControlCode,
546 LPCVOID pbSendBuffer,
547 DWORD cbSendLength,
548 LPVOID pbRecvBuffer,
549 DWORD cbRecvLength,
550 LPDWORD lpBytesReturned)
551{
552 LONG rv;
553
554 Enter();
555 spy_long(hCard);
556 spy_long(dwControlCode);
557 spy_buffer(pbSendBuffer, cbSendLength);
558 rv = spy.SCardControl(hCard, dwControlCode, pbSendBuffer, cbSendLength,
559 pbRecvBuffer, cbRecvLength, lpBytesReturned);
560 if (lpBytesReturned)
561 {
562 if (SCARD_S_SUCCESS == rv)
563 spy_buffer(pbRecvBuffer, *lpBytesReturned);
564 else
565 spy_buffer(NULL, *lpBytesReturned);
566 }
567 else
568 spy_buffer(NULL, 0);
569 Quit();
570 return rv;
571}
572
573PCSC_API LONG SCardTransmit(SCARDHANDLE hCard,
574 const SCARD_IO_REQUEST *pioSendPci,
575 LPCBYTE pbSendBuffer,
576 DWORD cbSendLength,
577 SCARD_IO_REQUEST *pioRecvPci,
578 LPBYTE pbRecvBuffer,
579 LPDWORD pcbRecvLength)
580{
581 LONG rv;
582
583 Enter();
584 spy_long(hCard);
585 if (pioSendPci)
586 {
587 spy_long(pioSendPci->dwProtocol);
588 spy_long(pioSendPci->cbPciLength);
589 }
590 else
591 {
592 spy_long(-1);
593 spy_long(-1);
594 }
595 spy_buffer(pbSendBuffer, cbSendLength);
596 rv = spy.SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength,
597 pioRecvPci, pbRecvBuffer, pcbRecvLength);
598 if (pioRecvPci)
599 {
600 spy_long(pioRecvPci->dwProtocol);
601 spy_long(pioRecvPci->cbPciLength);
602 }
603 else
604 {
605 spy_long(-1);
606 spy_long(-1);
607 }
608 if (pcbRecvLength)
609 {
610 if (SCARD_S_SUCCESS == rv)
611 spy_buffer(pbRecvBuffer, *pcbRecvLength);
612 else
613 spy_buffer(NULL, *pcbRecvLength);
614 }
615 else
616 spy_buffer(NULL, 0);
617 Quit();
618 return rv;
619}
620
621PCSC_API LONG SCardListReaderGroups(SCARDCONTEXT hContext,
622 LPSTR mszGroups,
623 LPDWORD pcchGroups)
624{
625 LONG rv;
626 int autoallocate = 0;
627
628 if (pcchGroups)
629 autoallocate = *pcchGroups == SCARD_AUTOALLOCATE;
630
631 Enter();
632 spy_long(hContext);
633 spy_ptr_ulong(pcchGroups);
634 rv = spy.SCardListReaderGroups(hContext, mszGroups, pcchGroups);
635 if (SCARD_S_SUCCESS == rv)
636 spy_n_str(mszGroups, pcchGroups, autoallocate);
637 else
638 spy_n_str(NULL, pcchGroups, 0);
639 Quit();
640 return rv;
641}
642
643PCSC_API LONG SCardListReaders(SCARDCONTEXT hContext,
644 LPCSTR mszGroups,
645 LPSTR mszReaders,
646 LPDWORD pcchReaders)
647{
648 LONG rv;
649 int autoallocate = 0;
650
651 if (pcchReaders)
652 autoallocate = *pcchReaders == SCARD_AUTOALLOCATE;
653
654 Enter();
655 spy_long(hContext);
656 spy_str(mszGroups);
657 rv = spy.SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders);
658 if (SCARD_S_SUCCESS == rv)
659 spy_n_str(mszReaders, pcchReaders, autoallocate);
660 else
661 spy_n_str(NULL, pcchReaders, 0);
662 Quit();
663 return rv;
664}
665
666PCSC_API LONG SCardFreeMemory(SCARDCONTEXT hContext,
667 LPCVOID pvMem)
668{
669 LONG rv;
670
671 Enter();
672 spy_long(hContext);
673 spy_pvoid(pvMem);
674 rv = spy.SCardFreeMemory(hContext, pvMem);
675 Quit();
676 return rv;
677}
678
679PCSC_API LONG SCardCancel(SCARDCONTEXT hContext)
680{
681 LONG rv;
682
683 Enter();
684 spy_long(hContext);
685 rv = spy.SCardCancel(hContext);
686 Quit();
687 return rv;
688}
689
690PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard,
691 DWORD dwAttrId,
692 LPBYTE pbAttr,
693 LPDWORD pcbAttrLen)
694{
695 LONG rv;
696 int autoallocate = 0;
697
698 if (pcbAttrLen)
699 autoallocate = *pcbAttrLen == SCARD_AUTOALLOCATE;
700
701 Enter();
702 spy_long(hCard);
703 spy_long(dwAttrId);
704 rv = spy.SCardGetAttrib(hCard, dwAttrId, pbAttr, pcbAttrLen);
705 if (NULL == pcbAttrLen)
706 spy_buffer(NULL, 0);
707 else
708 if (rv != SCARD_S_SUCCESS)
709 spy_buffer(NULL, *pcbAttrLen);
710 else
711 {
712 LPBYTE buffer;
713
714 if (autoallocate)
715 buffer = *(LPBYTE *)pbAttr;
716 else
717 buffer = pbAttr;
718
719 spy_buffer(buffer, *pcbAttrLen);
720 }
721 Quit();
722 return rv;
723}
724
725PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard,
726 DWORD dwAttrId,
727 LPCBYTE pbAttr,
728 DWORD cbAttrLen)
729{
730 LONG rv;
731
732 Enter();
733 spy_long(hCard);
734 spy_long(dwAttrId);
735 spy_buffer(pbAttr, cbAttrLen);
736 rv = spy.SCardSetAttrib(hCard, dwAttrId, pbAttr, cbAttrLen);
737 Quit();
738 return rv;
739}
740
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
#define SCARD_S_SUCCESS
No error was encountered.
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
#define MAX_ATR_SIZE
Maximum ATR size.
LONG SCARDHANDLE
hCard returned by SCardConnect()
Protocol Control Information (PCI)
unsigned long dwProtocol
Protocol identifier.
unsigned long cbPciLength
Protocol Control Inf Length.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168
This handles smart card reader communications.