pcsc-lite 2.3.0
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
337
338/* exported functions */
339PCSC_API LONG SCardEstablishContext(DWORD dwScope,
340 LPCVOID pvReserved1,
341 LPCVOID pvReserved2,
342 LPSCARDCONTEXT phContext)
343{
344 LONG rv;
345 static int init = 0;
346
347 if (!init)
348 {
349 const char *home;
350 char log_pipe[128];
351
352 init = 1;
353
354 /* load the real library */
355 rv = load_lib();
356 if (rv != SCARD_S_SUCCESS)
357 return rv;
358
359 /* check if we can log */
360 home = SYS_GetEnv("HOME");
361 if (NULL == home)
362 home = "/tmp";
363
364 snprintf(log_pipe, sizeof log_pipe, "%s/pcsc-spy", home);
365 Log_fd = open(log_pipe, O_WRONLY);
366 if (Log_fd < 0)
367 {
368 log_line("open %s failed: %s", log_pipe, strerror(errno));
369 }
370 }
371
372 Enter();
373 spy_long(dwScope);
374 rv = spy.SCardEstablishContext(dwScope, pvReserved1, pvReserved2,
375 phContext);
376 spy_ptr_long(phContext);
377 Quit();
378 return rv;
379}
380
381PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
382{
383 LONG rv;
384
385 Enter();
386 spy_long(hContext);
387 rv = spy.SCardReleaseContext(hContext);
388 Quit();
389 return rv;
390}
391
392PCSC_API LONG SCardIsValidContext(SCARDCONTEXT hContext)
393{
394 LONG rv;
395
396 Enter();
397 spy_long(hContext);
398 rv = spy.SCardIsValidContext(hContext);
399 Quit();
400 return rv;
401}
402
403PCSC_API LONG SCardConnect(SCARDCONTEXT hContext,
404 LPCSTR szReader,
405 DWORD dwShareMode,
406 DWORD dwPreferredProtocols,
407 LPSCARDHANDLE phCard,
408 LPDWORD pdwActiveProtocol)
409{
410 LONG rv;
411
412 Enter();
413 spy_long(hContext);
414 spy_str(szReader);
415 spy_long(dwShareMode);
416 spy_long(dwPreferredProtocols);
417 spy_ptr_long(phCard);
418 spy_ptr_ulong(pdwActiveProtocol);
419 rv = spy.SCardConnect(hContext, szReader, dwShareMode,
420 dwPreferredProtocols, phCard, pdwActiveProtocol);
421 spy_ptr_long(phCard);
422 spy_ptr_ulong(pdwActiveProtocol);
423 Quit();
424 return rv;
425}
426
427PCSC_API LONG SCardReconnect(SCARDHANDLE hCard,
428 DWORD dwShareMode,
429 DWORD dwPreferredProtocols,
430 DWORD dwInitialization,
431 LPDWORD pdwActiveProtocol)
432{
433 LONG rv;
434
435 Enter();
436 spy_long(hCard);
437 spy_long(dwShareMode);
438 spy_long(dwPreferredProtocols);
439 spy_long(dwInitialization);
440 rv = spy.SCardReconnect(hCard, dwShareMode, dwPreferredProtocols,
441 dwInitialization, pdwActiveProtocol);
442 spy_ptr_ulong(pdwActiveProtocol);
443 Quit();
444 return rv;
445}
446
447PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard,
448 DWORD dwDisposition)
449{
450 LONG rv;
451
452 Enter();
453 spy_long(hCard);
454 spy_long(dwDisposition);
455 rv = spy.SCardDisconnect(hCard, dwDisposition);
456 Quit();
457 return rv;
458}
459
460PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
461{
462 LONG rv;
463
464 Enter();
465 spy_long(hCard);
466 rv = spy.SCardBeginTransaction(hCard);
467 Quit();
468 return rv;
469}
470
471PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard,
472 DWORD dwDisposition)
473{
474 LONG rv;
475
476 Enter();
477 spy_long(hCard);
478 spy_long(dwDisposition);
479 rv = spy.SCardEndTransaction(hCard, dwDisposition);
480 Quit();
481 return rv;
482}
483
484PCSC_API LONG SCardStatus(SCARDHANDLE hCard,
485 LPSTR mszReaderName,
486 LPDWORD pcchReaderLen,
487 LPDWORD pdwState,
488 LPDWORD pdwProtocol,
489 LPBYTE pbAtr,
490 LPDWORD pcbAtrLen)
491{
492 LONG rv;
493 int autoallocate_ReaderName = 0, autoallocate_Atr = 0;
494
495 if (pcchReaderLen)
496 autoallocate_ReaderName = *pcchReaderLen == SCARD_AUTOALLOCATE;
497
498 if (pcbAtrLen)
499 autoallocate_Atr = *pcbAtrLen == SCARD_AUTOALLOCATE;
500
501 Enter();
502 spy_long(hCard);
503 spy_ptr_ulong(pcchReaderLen);
504 spy_ptr_ulong(pcbAtrLen);
505 rv = spy.SCardStatus(hCard, mszReaderName, pcchReaderLen, pdwState,
506 pdwProtocol, pbAtr, pcbAtrLen);
507 spy_n_str(mszReaderName, pcchReaderLen, autoallocate_ReaderName);
508 spy_ptr_ulong(pdwState);
509 spy_ptr_ulong(pdwProtocol);
510 if (NULL == pcbAtrLen)
511 spy_line("NULL");
512 else
513 {
514 LPBYTE buffer;
515
516 if (autoallocate_Atr)
517 buffer = *(LPBYTE *)pbAtr;
518 else
519 buffer = pbAtr;
520
521 spy_buffer(buffer, *pcbAtrLen);
522 }
523 Quit();
524 return rv;
525}
526
527PCSC_API LONG SCardGetStatusChange(SCARDCONTEXT hContext,
528 DWORD dwTimeout,
529 SCARD_READERSTATE *rgReaderStates,
530 DWORD cReaders)
531{
532 LONG rv;
533
534 Enter();
535 spy_long(hContext);
536 spy_long(dwTimeout);
537 spy_long(cReaders);
538 spy_readerstate(rgReaderStates, cReaders);
539 rv = spy.SCardGetStatusChange(hContext, dwTimeout, rgReaderStates,
540 cReaders);
541 spy_readerstate(rgReaderStates, cReaders);
542 Quit();
543 return rv;
544}
545
546PCSC_API LONG SCardControl(SCARDHANDLE hCard,
547 DWORD dwControlCode,
548 LPCVOID pbSendBuffer,
549 DWORD cbSendLength,
550 LPVOID pbRecvBuffer,
551 DWORD cbRecvLength,
552 LPDWORD lpBytesReturned)
553{
554 LONG rv;
555
556 Enter();
557 spy_long(hCard);
558 spy_long(dwControlCode);
559 spy_buffer(pbSendBuffer, cbSendLength);
560 rv = spy.SCardControl(hCard, dwControlCode, pbSendBuffer, cbSendLength,
561 pbRecvBuffer, cbRecvLength, lpBytesReturned);
562 if (lpBytesReturned)
563 {
564 if (SCARD_S_SUCCESS == rv)
565 spy_buffer(pbRecvBuffer, *lpBytesReturned);
566 else
567 spy_buffer(NULL, *lpBytesReturned);
568 }
569 else
570 spy_buffer(NULL, 0);
571 Quit();
572 return rv;
573}
574
575PCSC_API LONG SCardTransmit(SCARDHANDLE hCard,
576 const SCARD_IO_REQUEST *pioSendPci,
577 LPCBYTE pbSendBuffer,
578 DWORD cbSendLength,
579 SCARD_IO_REQUEST *pioRecvPci,
580 LPBYTE pbRecvBuffer,
581 LPDWORD pcbRecvLength)
582{
583 LONG rv;
584
585 Enter();
586 spy_long(hCard);
587 if (pioSendPci)
588 {
589 spy_long(pioSendPci->dwProtocol);
590 spy_long(pioSendPci->cbPciLength);
591 }
592 else
593 {
594 spy_long(-1);
595 spy_long(-1);
596 }
597 spy_buffer(pbSendBuffer, cbSendLength);
598 rv = spy.SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength,
599 pioRecvPci, pbRecvBuffer, pcbRecvLength);
600 if (pioRecvPci)
601 {
602 spy_long(pioRecvPci->dwProtocol);
603 spy_long(pioRecvPci->cbPciLength);
604 }
605 else
606 {
607 spy_long(-1);
608 spy_long(-1);
609 }
610 if (pcbRecvLength)
611 {
612 if (SCARD_S_SUCCESS == rv)
613 spy_buffer(pbRecvBuffer, *pcbRecvLength);
614 else
615 spy_buffer(NULL, *pcbRecvLength);
616 }
617 else
618 spy_buffer(NULL, 0);
619 Quit();
620 return rv;
621}
622
623PCSC_API LONG SCardListReaderGroups(SCARDCONTEXT hContext,
624 LPSTR mszGroups,
625 LPDWORD pcchGroups)
626{
627 LONG rv;
628 int autoallocate = 0;
629
630 if (pcchGroups)
631 autoallocate = *pcchGroups == SCARD_AUTOALLOCATE;
632
633 Enter();
634 spy_long(hContext);
635 spy_ptr_ulong(pcchGroups);
636 rv = spy.SCardListReaderGroups(hContext, mszGroups, pcchGroups);
637 if (SCARD_S_SUCCESS == rv)
638 spy_n_str(mszGroups, pcchGroups, autoallocate);
639 else
640 spy_n_str(NULL, pcchGroups, 0);
641 Quit();
642 return rv;
643}
644
645PCSC_API LONG SCardListReaders(SCARDCONTEXT hContext,
646 LPCSTR mszGroups,
647 LPSTR mszReaders,
648 LPDWORD pcchReaders)
649{
650 LONG rv;
651 int autoallocate = 0;
652
653 if (pcchReaders)
654 autoallocate = *pcchReaders == SCARD_AUTOALLOCATE;
655
656 Enter();
657 spy_long(hContext);
658 spy_str(mszGroups);
659 rv = spy.SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders);
660 if (SCARD_S_SUCCESS == rv)
661 spy_n_str(mszReaders, pcchReaders, autoallocate);
662 else
663 spy_n_str(NULL, pcchReaders, 0);
664 Quit();
665 return rv;
666}
667
668PCSC_API LONG SCardFreeMemory(SCARDCONTEXT hContext,
669 LPCVOID pvMem)
670{
671 LONG rv;
672
673 Enter();
674 spy_long(hContext);
675 spy_pvoid(pvMem);
676 rv = spy.SCardFreeMemory(hContext, pvMem);
677 Quit();
678 return rv;
679}
680
681PCSC_API LONG SCardCancel(SCARDCONTEXT hContext)
682{
683 LONG rv;
684
685 Enter();
686 spy_long(hContext);
687 rv = spy.SCardCancel(hContext);
688 Quit();
689 return rv;
690}
691
692PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard,
693 DWORD dwAttrId,
694 LPBYTE pbAttr,
695 LPDWORD pcbAttrLen)
696{
697 LONG rv;
698 int autoallocate = 0;
699
700 if (pcbAttrLen)
701 autoallocate = *pcbAttrLen == SCARD_AUTOALLOCATE;
702
703 Enter();
704 spy_long(hCard);
705 spy_long(dwAttrId);
706 rv = spy.SCardGetAttrib(hCard, dwAttrId, pbAttr, pcbAttrLen);
707 if (NULL == pcbAttrLen)
708 spy_buffer(NULL, 0);
709 else
710 if (rv != SCARD_S_SUCCESS)
711 spy_buffer(NULL, *pcbAttrLen);
712 else
713 {
714 LPBYTE buffer;
715
716 if (autoallocate)
717 buffer = *(LPBYTE *)pbAttr;
718 else
719 buffer = pbAttr;
720
721 spy_buffer(buffer, *pcbAttrLen);
722 }
723 Quit();
724 return rv;
725}
726
727PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard,
728 DWORD dwAttrId,
729 LPCBYTE pbAttr,
730 DWORD cbAttrLen)
731{
732 LONG rv;
733
734 Enter();
735 spy_long(hCard);
736 spy_long(dwAttrId);
737 spy_buffer(pbAttr, cbAttrLen);
738 rv = spy.SCardSetAttrib(hCard, dwAttrId, pbAttr, cbAttrLen);
739 Quit();
740 return rv;
741}
742
#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.