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