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.
Definition pcsclite.h:109
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:234
#define MAX_ATR_SIZE
Maximum ATR size.
Definition pcsclite.h:59
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
Protocol Control Information (PCI)
Definition pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition pcsclite.h:82
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.