pcsc-lite 1.9.9
winscard_clnt.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2005
9 * Martin Paljak <martin@paljak.pri.ee>
10 * Copyright (C) 2002-2011
11 * Ludovic Rousseau <ludovic.rousseau@free.fr>
12 * Copyright (C) 2009
13 * Jean-Luc Giraud <jlgiraud@googlemail.com>
14 *
15Redistribution and use in source and binary forms, with or without
16modification, are permitted provided that the following conditions
17are met:
18
191. Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
212. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
243. The name of the author may not be used to endorse or promote products
25 derived from this software without specific prior written permission.
26
27THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
105#include "config.h"
106#include <stdlib.h>
107#include <string.h>
108#include <sys/types.h>
109#include <fcntl.h>
110#include <unistd.h>
111#include <sys/un.h>
112#include <errno.h>
113#include <stddef.h>
114#include <sys/time.h>
115#include <pthread.h>
116#include <sys/wait.h>
117#include <stdbool.h>
118
119#include "misc.h"
120#include "pcscd.h"
121#include "winscard.h"
122#include "debuglog.h"
123
124#include "readerfactory.h"
125#include "eventhandler.h"
126#include "sys_generic.h"
127#include "winscard_msg.h"
128#include "utils.h"
129
130/* Display, on stderr, a trace of the WinSCard calls with arguments and
131 * results */
132//#define DO_TRACE
133
134/* Profile the execution time of WinSCard calls */
135//#define DO_PROFILE
136
137
138static bool sharing_shall_block = true;
139
140#define COLOR_RED "\33[01;31m"
141#define COLOR_GREEN "\33[32m"
142#define COLOR_BLUE "\33[34m"
143#define COLOR_MAGENTA "\33[35m"
144#define COLOR_NORMAL "\33[0m"
145
146#ifdef DO_TRACE
147
148#include <stdio.h>
149#include <stdarg.h>
150
151static void trace(const char *func, const char direction, const char *fmt, ...)
152{
154
155 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
157
158 fprintf(stderr, COLOR_MAGENTA);
159 va_start(args, fmt);
161 va_end(args);
162
163 fprintf(stderr, COLOR_NORMAL "\n");
164}
165
166#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
167#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
168#else
169#define API_TRACE_IN(...)
170#define API_TRACE_OUT(...)
171#endif
172
173#ifdef DO_PROFILE
174
175#define PROFILE_FILE "/tmp/pcsc_profile"
176#include <stdio.h>
177#include <sys/time.h>
178
179/* we can profile a maximum of 5 simultaneous calls */
180#define MAX_THREADS 5
184bool profile_tty;
185
186#define PROFILE_START profile_start();
187#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
188
189static void profile_start(void)
190{
191 static bool initialized = false;
192 pthread_t t;
193 int i;
194
195 if (!initialized)
196 {
197 char filename[80];
198
199 initialized = true;
200 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
201 profile_fd = fopen(filename, "a+");
202 if (NULL == profile_fd)
203 {
204 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
206 exit(-1);
207 }
208 fprintf(profile_fd, "\nStart a new profile\n");
209
210 if (isatty(fileno(stderr)))
211 profile_tty = true;
212 else
213 profile_tty = false;
214 }
215
216 t = pthread_self();
217 for (i=0; i<MAX_THREADS; i++)
218 if (pthread_equal(0, threads[i]))
219 {
220 threads[i] = t;
221 break;
222 }
223
225} /* profile_start */
226
227static void profile_end(const char *f, LONG rv)
228{
230 long d;
231 pthread_t t;
232 int i;
233
235
236 t = pthread_self();
237 for (i=0; i<MAX_THREADS; i++)
238 if (pthread_equal(t, threads[i]))
239 break;
240
241 if (i>=MAX_THREADS)
242 {
243 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
244 return;
245 }
246
248
249 /* free this entry */
250 threads[i] = 0;
251
252 if (profile_tty)
253 {
254 if (rv != SCARD_S_SUCCESS)
256 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
257 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
258 f, d, rv, pcsc_stringify_error(rv));
259 else
260 fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
261 COLOR_NORMAL "\n", f, d);
262 }
263 fprintf(profile_fd, "%s %ld\n", f, d);
265} /* profile_end */
266
267#else
268#define PROFILE_START
269#define PROFILE_END(rv)
270#endif
271
277{
278 SCARDHANDLE hCard;
279 LPSTR readerName;
280};
281
282typedef struct _psChannelMap CHANNEL_MAP;
283
284static int CHANNEL_MAP_seeker(const void *el, const void *key)
285{
286 const CHANNEL_MAP * channelMap = el;
287
288 if ((el == NULL) || (key == NULL))
289 {
290 Log3(PCSC_LOG_CRITICAL,
291 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
292 el, key);
293 return 0;
294 }
295
296 if (channelMap->hCard == *(SCARDHANDLE *)key)
297 return 1;
298
299 return 0;
300}
301
321
322static list_t contextMapList;
323
324static int SCONTEXTMAP_seeker(const void *el, const void *key)
325{
326 const SCONTEXTMAP * contextMap = el;
327
328 if ((el == NULL) || (key == NULL))
329 {
330 Log3(PCSC_LOG_CRITICAL,
331 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
332 el, key);
333 return 0;
334 }
335
336 if (contextMap->hContext == *(SCARDCONTEXT *) key)
337 return 1;
338
339 return 0;
340}
341
345static short isExecuted = 0;
346
347
353
358
365
366
367static LONG SCardAddContext(SCARDCONTEXT, DWORD);
371static void SCardCleanContext(SCONTEXTMAP *);
372
373static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
374static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
375 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
376static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
377 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
378static void SCardRemoveHandle(SCARDHANDLE);
379
380static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
381 LPBYTE pbAttr, LPDWORD pcbAttrLen);
382
383static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
384static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
385static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
386
387/*
388 * Thread safety functions
389 */
396inline static void SCardLockThread(void)
397{
399}
400
406inline static void SCardUnlockThread(void)
407{
409}
410
430
431static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
432 /*@out@*/ LPSCARDCONTEXT);
433
469LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
470 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
471{
472 LONG rv;
473
474 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
475 PROFILE_START
476
477 /* Check if the server is running */
479 if (rv != SCARD_S_SUCCESS)
480 goto end;
481
486
487end:
488 PROFILE_END(rv)
489 API_TRACE_OUT("%ld", *phContext)
490
491 return rv;
492}
493
494#ifdef DESTRUCTOR
495DESTRUCTOR static void destructor(void)
496{
497 list_destroy(&contextMapList);
498}
499#endif
500
528static LONG SCardEstablishContextTH(DWORD dwScope,
529 /*@unused@*/ LPCVOID pvReserved1,
530 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
531{
532 LONG rv;
534 uint32_t dwClientID = 0;
535
538 if (phContext == NULL)
540 else
541 *phContext = 0;
542
543 /*
544 * Do this only once:
545 * - Initialize context list.
546 */
547 if (isExecuted == 0)
548 {
549 int lrv;
550
551 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
552 * Applications which load and unload the library may leak
553 * the list's internal structures. */
554 lrv = list_init(&contextMapList);
555 if (lrv < 0)
556 {
557 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
558 lrv);
559 return SCARD_E_NO_MEMORY;
560 }
561
562 lrv = list_attributes_seeker(&contextMapList,
563 SCONTEXTMAP_seeker);
564 if (lrv <0)
565 {
566 Log2(PCSC_LOG_CRITICAL,
567 "list_attributes_seeker failed with return value: %d", lrv);
568 list_destroy(&contextMapList);
569 return SCARD_E_NO_MEMORY;
570 }
571
572 if (getenv("PCSCLITE_NO_BLOCKING"))
573 {
574 Log1(PCSC_LOG_INFO, "Disable shared blocking");
575 sharing_shall_block = false;
576 }
577
578 isExecuted = 1;
579 }
580
581
582 /* Establishes a connection to the server */
583 if (ClientSetupSession(&dwClientID) != 0)
584 {
585 return SCARD_E_NO_SERVICE;
586 }
587
588 { /* exchange client/server protocol versions */
589 struct version_struct veStr;
590
594
595 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
596 &veStr);
597 if (rv != SCARD_S_SUCCESS)
598 goto cleanup;
599
600 /* Read a message from the server */
601 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
602 if (rv != SCARD_S_SUCCESS)
603 {
604 Log1(PCSC_LOG_CRITICAL,
605 "Your pcscd is too old and does not support CMD_VERSION");
606 goto cleanup;
607 }
608
609 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
610 veStr.major, veStr.minor);
611
612 if (veStr.rv != SCARD_S_SUCCESS)
613 {
614 rv = veStr.rv;
615 goto cleanup;
616 }
617 }
618
619again:
620 /*
621 * Try to establish an Application Context with the server
622 */
623 scEstablishStruct.dwScope = dwScope;
624 scEstablishStruct.hContext = 0;
626
628 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
629
630 if (rv != SCARD_S_SUCCESS)
631 goto cleanup;
632
633 /*
634 * Read the response from the server
635 */
637 dwClientID);
638
639 if (rv != SCARD_S_SUCCESS)
640 goto cleanup;
641
643 {
644 rv = scEstablishStruct.rv;
645 goto cleanup;
646 }
647
648 /* check we do not reuse an existing hContext */
650 /* we do not need to release the allocated context since
651 * SCardReleaseContext() does nothing on the server side */
652 goto again;
653
654 *phContext = scEstablishStruct.hContext;
655
656 /*
657 * Allocate the new hContext - if allocator full return an error
658 */
659 rv = SCardAddContext(*phContext, dwClientID);
660
661 return rv;
662
663cleanup:
664 ClientCloseSession(dwClientID);
665
666 return rv;
667}
668
690LONG SCardReleaseContext(SCARDCONTEXT hContext)
691{
692 LONG rv;
695
696 API_TRACE_IN("%ld", hContext)
697 PROFILE_START
698
699 /*
700 * Make sure this context has been opened
701 * and get currentContextMap
702 */
704 if (NULL == currentContextMap)
705 {
707 goto error;
708 }
709
710 scReleaseStruct.hContext = hContext;
712
714 currentContextMap->dwClientID,
715 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
716
717 if (rv != SCARD_S_SUCCESS)
718 goto end;
719
720 /*
721 * Read a message from the server
722 */
724 currentContextMap->dwClientID);
725
726 if (rv != SCARD_S_SUCCESS)
727 goto end;
728
729 rv = scReleaseStruct.rv;
730end:
732
733 /*
734 * Remove the local context from the stack
735 */
737 SCardRemoveContext(hContext);
739
740error:
741 PROFILE_END(rv)
742 API_TRACE_OUT("")
743
744 return rv;
745}
746
802LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
803 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
804 LPDWORD pdwActiveProtocol)
805{
806 LONG rv;
809
810 PROFILE_START
811 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
812
813 /*
814 * Check for NULL parameters
815 */
816 if (phCard == NULL || pdwActiveProtocol == NULL)
818 else
819 *phCard = 0;
820
821 if (szReader == NULL)
823
824 /*
825 * Check for uninitialized strings
826 */
827 if (strlen(szReader) > MAX_READERNAME)
829
830 /*
831 * Make sure this context has been opened
832 */
834 if (NULL == currentContextMap)
836
837 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
838 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
839 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
840
841 scConnectStruct.hContext = hContext;
842 scConnectStruct.dwShareMode = dwShareMode;
843 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
844 scConnectStruct.hCard = 0;
845 scConnectStruct.dwActiveProtocol = 0;
847
849 sizeof(scConnectStruct), (void *) &scConnectStruct);
850
851 if (rv != SCARD_S_SUCCESS)
852 goto end;
853
854 /*
855 * Read a message from the server
856 */
858 currentContextMap->dwClientID);
859
860 if (rv != SCARD_S_SUCCESS)
861 goto end;
862
863 *phCard = scConnectStruct.hCard;
864 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
865
867 {
868 /*
869 * Keep track of the handle locally
870 */
871 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
872 }
873 else
874 rv = scConnectStruct.rv;
875
876end:
878
879 PROFILE_END(rv)
880 API_TRACE_OUT("%d", *pdwActiveProtocol)
881
882 return rv;
883}
884
957LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
958 DWORD dwPreferredProtocols, DWORD dwInitialization,
959 LPDWORD pdwActiveProtocol)
960{
961 LONG rv;
965
966 PROFILE_START
967 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
968
969 if (pdwActiveProtocol == NULL)
971
972 /* Retry loop for blocking behaviour */
973retry:
974
975 /*
976 * Make sure this handle has been opened
977 */
978 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
979 &pChannelMap);
980 if (rv == -1)
982
983 scReconnectStruct.hCard = hCard;
984 scReconnectStruct.dwShareMode = dwShareMode;
985 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
986 scReconnectStruct.dwInitialization = dwInitialization;
987 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
989
991 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
992
993 if (rv != SCARD_S_SUCCESS)
994 goto end;
995
996 /*
997 * Read a message from the server
998 */
1000 currentContextMap->dwClientID);
1001
1002 if (rv != SCARD_S_SUCCESS)
1003 goto end;
1004
1005 rv = scReconnectStruct.rv;
1006
1007 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1008 {
1011 goto retry;
1012 }
1013
1014 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1015
1016end:
1018
1019 PROFILE_END(rv)
1020 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1021
1022 return rv;
1023}
1024
1056LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1057{
1058 LONG rv;
1062
1063 PROFILE_START
1064 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1065
1066 /*
1067 * Make sure this handle has been opened
1068 */
1069 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1070 &pChannelMap);
1071 if (rv == -1)
1072 {
1074 goto error;
1075 }
1076
1077 scDisconnectStruct.hCard = hCard;
1078 scDisconnectStruct.dwDisposition = dwDisposition;
1080
1082 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1083
1084 if (rv != SCARD_S_SUCCESS)
1085 goto end;
1086
1087 /*
1088 * Read a message from the server
1089 */
1091 currentContextMap->dwClientID);
1092
1093 if (rv != SCARD_S_SUCCESS)
1094 goto end;
1095
1097 SCardRemoveHandle(hCard);
1098 rv = scDisconnectStruct.rv;
1099
1100end:
1102
1103error:
1104 PROFILE_END(rv)
1105 API_TRACE_OUT("")
1106
1107 return rv;
1108}
1109
1146LONG SCardBeginTransaction(SCARDHANDLE hCard)
1147{
1148
1149 LONG rv;
1153
1154 PROFILE_START
1155 API_TRACE_IN("%ld", hCard)
1156
1157 /*
1158 * Query the server every so often until the sharing violation ends
1159 * and then hold the lock for yourself.
1160 */
1161
1162 for(;;)
1163 {
1164 /*
1165 * Make sure this handle has been opened
1166 */
1167 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1168 &pChannelMap);
1169 if (rv == -1)
1171
1172 scBeginStruct.hCard = hCard;
1174
1176 currentContextMap->dwClientID,
1177 sizeof(scBeginStruct), (void *) &scBeginStruct);
1178
1179 if (rv != SCARD_S_SUCCESS)
1180 break;
1181
1182 /*
1183 * Read a message from the server
1184 */
1186 currentContextMap->dwClientID);
1187
1188 if (rv != SCARD_S_SUCCESS)
1189 break;
1190
1191 rv = scBeginStruct.rv;
1192
1193 if (SCARD_E_SHARING_VIOLATION != rv)
1194 break;
1195
1198 }
1199
1201
1202 PROFILE_END(rv)
1203 API_TRACE_OUT("")
1204
1205 return rv;
1206}
1207
1247LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1248{
1249 LONG rv;
1250 struct end_struct scEndStruct;
1253
1254 PROFILE_START
1255 API_TRACE_IN("%ld", hCard)
1256
1257 /*
1258 * Make sure this handle has been opened
1259 */
1260 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1261 &pChannelMap);
1262 if (rv == -1)
1264
1265 scEndStruct.hCard = hCard;
1266 scEndStruct.dwDisposition = dwDisposition;
1268
1270 currentContextMap->dwClientID,
1271 sizeof(scEndStruct), (void *) &scEndStruct);
1272
1273 if (rv != SCARD_S_SUCCESS)
1274 goto end;
1275
1276 /*
1277 * Read a message from the server
1278 */
1279 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1280 currentContextMap->dwClientID);
1281
1282 if (rv != SCARD_S_SUCCESS)
1283 goto end;
1284
1285 rv = scEndStruct.rv;
1286
1287end:
1289
1290 PROFILE_END(rv)
1291 API_TRACE_OUT("")
1292
1293 return rv;
1294}
1295
1391LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1392 LPDWORD pcchReaderLen, LPDWORD pdwState,
1393 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1394{
1395 DWORD dwReaderLen, dwAtrLen;
1396 LONG rv;
1397 int i;
1401 char *r;
1402 char *bufReader = NULL;
1403 LPBYTE bufAtr = NULL;
1404 DWORD dummy = 0;
1405
1406 PROFILE_START
1407
1408 /* default output values */
1409 if (pdwState)
1410 *pdwState = 0;
1411
1412 if (pdwProtocol)
1413 *pdwProtocol = 0;
1414
1415 /* Check for NULL parameters */
1416 if (pcchReaderLen == NULL)
1418
1419 if (pcbAtrLen == NULL)
1420 pcbAtrLen = &dummy;
1421
1422 /* length passed from caller */
1425
1426 *pcchReaderLen = 0;
1427 *pcbAtrLen = 0;
1428
1429 /* Retry loop for blocking behaviour */
1430retry:
1431
1432 /*
1433 * Make sure this handle has been opened
1434 */
1435 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1436 &pChannelMap);
1437 if (rv == -1)
1439
1440 /* synchronize reader states with daemon */
1441 rv = getReaderStates(currentContextMap);
1442 if (rv != SCARD_S_SUCCESS)
1443 goto end;
1444
1445 r = pChannelMap->readerName;
1446 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1447 {
1448 /* by default r == NULL */
1449 if (r && strcmp(r, readerStates[i].readerName) == 0)
1450 break;
1451 }
1452
1454 {
1456 goto end;
1457 }
1458
1459 /* initialise the structure */
1460 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1461 scStatusStruct.hCard = hCard;
1462
1464 sizeof(scStatusStruct), (void *) &scStatusStruct);
1465
1466 if (rv != SCARD_S_SUCCESS)
1467 goto end;
1468
1469 /*
1470 * Read a message from the server
1471 */
1473 currentContextMap->dwClientID);
1474
1475 if (rv != SCARD_S_SUCCESS)
1476 goto end;
1477
1478 rv = scStatusStruct.rv;
1479
1480 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1481 {
1484 goto retry;
1485 }
1486
1488 {
1489 /*
1490 * An event must have occurred
1491 */
1492 goto end;
1493 }
1494
1495 /*
1496 * Now continue with the client side SCardStatus
1497 */
1498
1499 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1501
1502 if (pdwState)
1503 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1504
1505 if (pdwProtocol)
1507
1509 {
1511 if (NULL == szReaderName)
1512 {
1514 goto end;
1515 }
1517 if (NULL == bufReader)
1518 {
1519 rv = SCARD_E_NO_MEMORY;
1520 goto end;
1521 }
1522 *(char **)szReaderName = bufReader;
1523 }
1524 else
1526
1527 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1528 if (bufReader)
1529 {
1532
1534 }
1535
1537 {
1539 if (NULL == pbAtr)
1540 {
1542 goto end;
1543 }
1545 if (NULL == bufAtr)
1546 {
1547 rv = SCARD_E_NO_MEMORY;
1548 goto end;
1549 }
1550 *(LPBYTE *)pbAtr = bufAtr;
1551 }
1552 else
1553 bufAtr = pbAtr;
1554
1555 if (bufAtr)
1556 {
1557 if (*pcbAtrLen > dwAtrLen)
1559
1560 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1561 }
1562
1563end:
1565
1566 PROFILE_END(rv)
1567
1568 return rv;
1569}
1570
1678LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1680{
1683 long dwTime;
1684 DWORD dwBreakFlag = 0;
1685 unsigned int j;
1687 int currentReaderCount = 0;
1688 LONG rv = SCARD_S_SUCCESS;
1689
1690 PROFILE_START
1691 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1692#ifdef DO_TRACE
1693 for (j=0; j<cReaders; j++)
1694 {
1695 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1696 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1697 }
1698#endif
1699
1700 if ((rgReaderStates == NULL && cReaders > 0)
1702 {
1704 goto error;
1705 }
1706
1707 /* Check the integrity of the reader states structures */
1708 for (j = 0; j < cReaders; j++)
1709 {
1710 if (rgReaderStates[j].szReader == NULL)
1711 return SCARD_E_INVALID_VALUE;
1712 }
1713
1714 /* return if all readers are SCARD_STATE_IGNORE */
1715 if (cReaders > 0)
1716 {
1718
1719 for (j=0; j<cReaders; j++)
1720 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1722
1723 if (0 == nbNonIgnoredReaders)
1724 {
1725 rv = SCARD_S_SUCCESS;
1726 goto error;
1727 }
1728 }
1729 else
1730 {
1731 /* reader list is empty */
1732 rv = SCARD_S_SUCCESS;
1733 goto error;
1734 }
1735
1736 /*
1737 * Make sure this context has been opened
1738 */
1740 if (NULL == currentContextMap)
1741 {
1743 goto error;
1744 }
1745
1746 /* synchronize reader states with daemon */
1747 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1748 if (rv != SCARD_S_SUCCESS)
1749 goto end;
1750
1751 /* check all the readers are already known */
1752 for (j=0; j<cReaders; j++)
1753 {
1754 const char *readerName;
1755 int i;
1756
1757 readerName = rgReaderStates[j].szReader;
1758 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1759 {
1760 if (strcmp(readerName, readerStates[i].readerName) == 0)
1761 break;
1762 }
1763
1764 /* The requested reader name is not recognized */
1766 {
1767 /* PnP special reader? */
1768 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1769 {
1771 goto end;
1772 }
1773 }
1774 }
1775
1776 /* Clear the event state for all readers */
1777 for (j = 0; j < cReaders; j++)
1778 rgReaderStates[j].dwEventState = 0;
1779
1780 /* Now is where we start our event checking loop */
1781 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1782
1783 /* Get the initial reader count on the system */
1784 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1785 if (readerStates[j].readerName[0] != '\0')
1787
1788 /* catch possible sign extension problems from 32 to 64-bits integers */
1789 if ((DWORD)-1 == dwTimeout)
1791 if (INFINITE == dwTimeout)
1792 dwTime = 60*1000; /* "infinite" timeout */
1793 else
1794 dwTime = dwTimeout;
1795
1796 j = 0;
1797 do
1798 {
1800
1801 /* Ignore for IGNORED readers */
1802 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1803 {
1804 const char *readerName;
1805 int i;
1806
1807 /* Looks for correct readernames */
1808 readerName = currReader->szReader;
1809 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1810 {
1811 if (strcmp(readerName, readerStates[i].readerName) == 0)
1812 break;
1813 }
1814
1815 /* The requested reader name is not recognized */
1817 {
1818 /* PnP special reader? */
1819 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1820 {
1821 int k, newReaderCount = 0;
1822
1823 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1824 if (readerStates[k].readerName[0] != '\0')
1826
1828 {
1829 Log1(PCSC_LOG_INFO, "Reader list changed");
1831
1832 currReader->dwEventState |= SCARD_STATE_CHANGED;
1833 dwBreakFlag = 1;
1834 }
1835 }
1836 else
1837 {
1838 currReader->dwEventState =
1840 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1841 {
1842 currReader->dwEventState |= SCARD_STATE_CHANGED;
1843 /*
1844 * Spec says use SCARD_STATE_IGNORE but a removed USB
1845 * reader with eventState fed into currentState will
1846 * be ignored forever
1847 */
1848 dwBreakFlag = 1;
1849 }
1850 }
1851 }
1852 else
1853 {
1854 uint32_t readerState;
1855
1856 /* The reader has come back after being away */
1857 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1858 {
1859 currReader->dwEventState |= SCARD_STATE_CHANGED;
1860 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1861 Log0(PCSC_LOG_DEBUG);
1862 dwBreakFlag = 1;
1863 }
1864
1865 /* Set the reader status structure */
1867
1868 /* Now we check all the Reader States */
1869 readerState = rContext->readerState;
1870
1871 /* only if current state has an non null event counter */
1872 if (currReader->dwCurrentState & 0xFFFF0000)
1873 {
1874 unsigned int currentCounter;
1875
1876 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1877
1878 /* has the event counter changed since the last call? */
1879 if (rContext->eventCounter != currentCounter)
1880 {
1881 currReader->dwEventState |= SCARD_STATE_CHANGED;
1882 Log0(PCSC_LOG_DEBUG);
1883 dwBreakFlag = 1;
1884 }
1885 }
1886
1887 /* add an event counter in the upper word of dwEventState */
1888 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1889 | (rContext->eventCounter << 16));
1890
1891 /* Check if the reader is in the correct state */
1892 if (readerState & SCARD_UNKNOWN)
1893 {
1894 /* reader is in bad state */
1895 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1896 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1897 {
1898 /* App thinks reader is in good state and it is not */
1899 currReader->dwEventState |= SCARD_STATE_CHANGED;
1900 Log0(PCSC_LOG_DEBUG);
1901 dwBreakFlag = 1;
1902 }
1903 }
1904 else
1905 {
1906 /* App thinks reader in bad state but it is not */
1907 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1908 {
1909 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1910 currReader->dwEventState |= SCARD_STATE_CHANGED;
1911 Log0(PCSC_LOG_DEBUG);
1912 dwBreakFlag = 1;
1913 }
1914 }
1915
1916 /* Check for card presence in the reader */
1917 if (readerState & SCARD_PRESENT)
1918 {
1919#ifndef DISABLE_AUTO_POWER_ON
1920 /* card present but not yet powered up */
1921 if (0 == rContext->cardAtrLength)
1922 /* Allow the status thread to convey information */
1924#endif
1925
1926 currReader->cbAtr = rContext->cardAtrLength;
1927 memcpy(currReader->rgbAtr, rContext->cardAtr,
1928 currReader->cbAtr);
1929 }
1930 else
1931 currReader->cbAtr = 0;
1932
1933 /* Card is now absent */
1934 if (readerState & SCARD_ABSENT)
1935 {
1936 currReader->dwEventState |= SCARD_STATE_EMPTY;
1937 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1938 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1939 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1940 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1941 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1942 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1943 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1944 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1945
1946 /* After present the rest are assumed */
1947 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1948 {
1949 currReader->dwEventState |= SCARD_STATE_CHANGED;
1950 Log0(PCSC_LOG_DEBUG);
1951 dwBreakFlag = 1;
1952 }
1953 }
1954 /* Card is now present */
1955 else if (readerState & SCARD_PRESENT)
1956 {
1957 currReader->dwEventState |= SCARD_STATE_PRESENT;
1958 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1959 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1960 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1961 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1962 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1963 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1964
1965 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1966 {
1967 currReader->dwEventState |= SCARD_STATE_CHANGED;
1968 Log0(PCSC_LOG_DEBUG);
1969 dwBreakFlag = 1;
1970 }
1971
1972 if (readerState & SCARD_SWALLOWED)
1973 {
1974 currReader->dwEventState |= SCARD_STATE_MUTE;
1975 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1976 {
1977 currReader->dwEventState |= SCARD_STATE_CHANGED;
1978 Log0(PCSC_LOG_DEBUG);
1979 dwBreakFlag = 1;
1980 }
1981 }
1982 else
1983 {
1984 /* App thinks card is mute but it is not */
1985 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1986 {
1987 currReader->dwEventState |= SCARD_STATE_CHANGED;
1988 Log0(PCSC_LOG_DEBUG);
1989 dwBreakFlag = 1;
1990 }
1991 }
1992 }
1993
1994 /* Now figure out sharing modes */
1995 if (rContext->readerSharing == PCSCLITE_SHARING_EXCLUSIVE_CONTEXT)
1996 {
1997 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1998 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1999 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2000 {
2001 currReader->dwEventState |= SCARD_STATE_CHANGED;
2002 Log0(PCSC_LOG_DEBUG);
2003 dwBreakFlag = 1;
2004 }
2005 }
2006 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2007 {
2008 /* A card must be inserted for it to be INUSE */
2009 if (readerState & SCARD_PRESENT)
2010 {
2011 currReader->dwEventState |= SCARD_STATE_INUSE;
2012 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2013 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2014 {
2015 currReader->dwEventState |= SCARD_STATE_CHANGED;
2016 Log0(PCSC_LOG_DEBUG);
2017 dwBreakFlag = 1;
2018 }
2019 }
2020 }
2021 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2022 {
2023 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2024 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2025
2026 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2027 {
2028 currReader->dwEventState |= SCARD_STATE_CHANGED;
2029 Log0(PCSC_LOG_DEBUG);
2030 dwBreakFlag = 1;
2031 }
2032 else if (currReader-> dwCurrentState
2034 {
2035 currReader->dwEventState |= SCARD_STATE_CHANGED;
2036 Log0(PCSC_LOG_DEBUG);
2037 dwBreakFlag = 1;
2038 }
2039 }
2040
2041 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2042 {
2043 /*
2044 * Break out of the while .. loop and return status
2045 * once all the status's for all readers is met
2046 */
2047 currReader->dwEventState |= SCARD_STATE_CHANGED;
2048 Log0(PCSC_LOG_DEBUG);
2049 dwBreakFlag = 1;
2050 }
2051 } /* End of SCARD_STATE_UNKNOWN */
2052 } /* End of SCARD_STATE_IGNORE */
2053
2054 /* Counter and resetter */
2055 j++;
2056 if (j == cReaders)
2057 {
2058 /* go back to the first reader */
2059 j = 0;
2060
2061 /* Declare all the break conditions */
2062
2063 /* Break if UNAWARE is set and all readers have been checked */
2064 if (dwBreakFlag == 1)
2065 break;
2066
2067 /* Only sleep once for each cycle of reader checks. */
2068 {
2070 struct timeval before, after;
2071
2073
2075
2076 /* another thread can do SCardCancel() */
2077 currentContextMap->cancellable = true;
2078
2079 /*
2080 * Read a message from the server
2081 */
2084 currentContextMap->dwClientID, dwTime);
2085
2086 /* SCardCancel() will return immediately with success
2087 * because something changed on the daemon side. */
2088 currentContextMap->cancellable = false;
2089
2090 /* timeout */
2091 if (SCARD_E_TIMEOUT == rv)
2092 {
2093 /* ask server to remove us from the event list */
2094 rv = unregisterFromEvents(currentContextMap);
2095 }
2096
2097 if (rv != SCARD_S_SUCCESS)
2098 goto end;
2099
2100 /* an event occurs or SCardCancel() was called */
2102 {
2103 rv = waitStatusStruct.rv;
2104 goto end;
2105 }
2106
2107 /* synchronize reader states with daemon */
2108 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2109 if (rv != SCARD_S_SUCCESS)
2110 goto end;
2111
2112 if (INFINITE != dwTimeout)
2113 {
2114 long int diff;
2115
2117 diff = time_sub(&after, &before);
2118 dwTime -= diff/1000;
2119 }
2120 }
2121
2122 if (dwTimeout != INFINITE)
2123 {
2124 /* If time is greater than timeout and all readers have been
2125 * checked
2126 */
2127 if (dwTime <= 0)
2128 {
2129 rv = SCARD_E_TIMEOUT;
2130 goto end;
2131 }
2132 }
2133 }
2134 }
2135 while (1);
2136
2137end:
2138 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2139
2140 /* if SCardCancel() has been used then the client is already
2141 * unregistered */
2142 if (SCARD_E_CANCELLED != rv)
2143 (void)unregisterFromEvents(currentContextMap);
2144
2146
2147error:
2148 PROFILE_END(rv)
2149#ifdef DO_TRACE
2150 for (j=0; j<cReaders; j++)
2151 {
2152 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2153 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2154 }
2155#endif
2156
2157 return rv;
2158}
2159
2210LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2211 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2212 LPDWORD lpBytesReturned)
2213{
2214 LONG rv;
2218
2219 PROFILE_START
2220
2221 /* 0 bytes received by default */
2222 if (NULL != lpBytesReturned)
2223 *lpBytesReturned = 0;
2224
2225 /*
2226 * Make sure this handle has been opened
2227 */
2228 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2229 &pChannelMap);
2230 if (rv == -1)
2231 {
2232 PROFILE_END(SCARD_E_INVALID_HANDLE)
2234 }
2235
2236 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2237 {
2239 goto end;
2240 }
2241
2242 scControlStruct.hCard = hCard;
2243 scControlStruct.dwControlCode = dwControlCode;
2244 scControlStruct.cbSendLength = cbSendLength;
2245 scControlStruct.cbRecvLength = cbRecvLength;
2246 scControlStruct.dwBytesReturned = 0;
2247 scControlStruct.rv = 0;
2248
2251
2252 if (rv != SCARD_S_SUCCESS)
2253 goto end;
2254
2255 /* write the sent buffer */
2256 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2257 currentContextMap->dwClientID);
2258
2259 if (rv != SCARD_S_SUCCESS)
2260 goto end;
2261
2262 /*
2263 * Read a message from the server
2264 */
2266 currentContextMap->dwClientID);
2267
2268 if (rv != SCARD_S_SUCCESS)
2269 goto end;
2270
2272 {
2273 if (scControlStruct.dwBytesReturned > cbRecvLength)
2274 {
2275 if (NULL != lpBytesReturned)
2276 *lpBytesReturned = scControlStruct.dwBytesReturned;
2278 goto end;
2279 }
2280
2281 /* read the received buffer */
2282 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2283 currentContextMap->dwClientID);
2284
2285 if (rv != SCARD_S_SUCCESS)
2286 goto end;
2287
2288 }
2289
2290 if (NULL != lpBytesReturned)
2291 *lpBytesReturned = scControlStruct.dwBytesReturned;
2292
2293 rv = scControlStruct.rv;
2294
2295end:
2297
2298 PROFILE_END(rv)
2299
2300 return rv;
2301}
2302
2421LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2422 LPDWORD pcbAttrLen)
2423{
2424 LONG ret;
2425 unsigned char *buf = NULL;
2426
2427 PROFILE_START
2428
2429 if (NULL == pcbAttrLen)
2430 {
2432 goto end;
2433 }
2434
2436 {
2437 if (NULL == pbAttr)
2439
2441 buf = malloc(*pcbAttrLen);
2442 if (NULL == buf)
2443 {
2445 goto end;
2446 }
2447
2448 *(unsigned char **)pbAttr = buf;
2449 }
2450 else
2451 {
2452 buf = pbAttr;
2453
2454 /* if only get the length */
2455 if (NULL == pbAttr)
2456 /* use a reasonable size */
2458 }
2459
2460 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2461 pcbAttrLen);
2462
2463end:
2464 PROFILE_END(ret)
2465
2466 return ret;
2467}
2468
2504LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2505 DWORD cbAttrLen)
2506{
2507 LONG ret;
2508
2509 PROFILE_START
2510
2511 if (NULL == pbAttr || 0 == cbAttrLen)
2513
2514 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2515 &cbAttrLen);
2516
2517 PROFILE_END(ret)
2518
2519 return ret;
2520}
2521
2522static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2523 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2524{
2525 LONG rv;
2529
2530 /*
2531 * Make sure this handle has been opened
2532 */
2533 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2534 &pChannelMap);
2535 if (rv == -1)
2537
2539 {
2541 goto end;
2542 }
2543
2544 scGetSetStruct.hCard = hCard;
2545 scGetSetStruct.dwAttrId = dwAttrId;
2547 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2548 if (SCARD_SET_ATTRIB == command)
2549 {
2550 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2551 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2552 }
2553 else
2554 /* we can get up to the communication buffer size */
2555 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2556
2557 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2558 sizeof(scGetSetStruct), &scGetSetStruct);
2559
2560 if (rv != SCARD_S_SUCCESS)
2561 goto end;
2562
2563 /*
2564 * Read a message from the server
2565 */
2567 currentContextMap->dwClientID);
2568
2569 if (rv != SCARD_S_SUCCESS)
2570 goto end;
2571
2572 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2573 {
2574 /*
2575 * Copy and zero it so any secret information is not leaked
2576 */
2577 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2578 {
2579 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2580 * buffer overflow in the memcpy() below */
2581 DWORD correct_value = scGetSetStruct.cbAttrLen;
2582 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2584
2586 }
2587 else
2588 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2589
2590 if (pbAttr)
2591 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2592
2593 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2594 }
2595 rv = scGetSetStruct.rv;
2596
2597end:
2599
2600 return rv;
2601}
2602
2661LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2662 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2664 LPDWORD pcbRecvLength)
2665{
2666 LONG rv;
2670
2671 PROFILE_START
2672
2673 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2674 pcbRecvLength == NULL || pioSendPci == NULL)
2676
2677 /* Retry loop for blocking behaviour */
2678retry:
2679
2680 /*
2681 * Make sure this handle has been opened
2682 */
2683 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2684 &pChannelMap);
2685 if (rv == -1)
2686 {
2687 *pcbRecvLength = 0;
2688 PROFILE_END(SCARD_E_INVALID_HANDLE)
2690 }
2691
2692 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2693 {
2695 goto end;
2696 }
2697
2698 scTransmitStruct.hCard = hCard;
2699 scTransmitStruct.cbSendLength = cbSendLength;
2700 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2701 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2702 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2704
2705 if (pioRecvPci)
2706 {
2707 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2708 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2709 }
2710 else
2711 {
2712 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2713 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2714 }
2715
2717 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2718
2719 if (rv != SCARD_S_SUCCESS)
2720 goto end;
2721
2722 /* write the sent buffer */
2723 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2724 currentContextMap->dwClientID);
2725
2726 if (rv != SCARD_S_SUCCESS)
2727 goto end;
2728
2729 /*
2730 * Read a message from the server
2731 */
2733 currentContextMap->dwClientID);
2734
2735 if (rv != SCARD_S_SUCCESS)
2736 goto end;
2737
2739 {
2740 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2741 {
2742 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2744 goto end;
2745 }
2746
2747 /* read the received buffer */
2748 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2749 currentContextMap->dwClientID);
2750
2751 if (rv != SCARD_S_SUCCESS)
2752 goto end;
2753
2754 if (pioRecvPci)
2755 {
2756 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2757 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2758 }
2759 }
2760
2761 rv = scTransmitStruct.rv;
2762
2763 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2764 {
2767 goto retry;
2768 }
2769
2770 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2771
2772end:
2774
2775 PROFILE_END(rv)
2776
2777 return rv;
2778}
2779
2842LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2843 LPSTR mszReaders, LPDWORD pcchReaders)
2844{
2845 DWORD dwReadersLen = 0;
2846 int i;
2848 LONG rv = SCARD_S_SUCCESS;
2849 char *buf = NULL;
2850
2851 (void)mszGroups;
2852 PROFILE_START
2853 API_TRACE_IN("%ld", hContext)
2854
2855 /*
2856 * Check for NULL parameters
2857 */
2858 if (pcchReaders == NULL)
2860
2861 /*
2862 * Make sure this context has been opened
2863 */
2865 if (NULL == currentContextMap)
2866 {
2867 PROFILE_END(SCARD_E_INVALID_HANDLE)
2869 }
2870
2871 /* synchronize reader states with daemon */
2872 rv = getReaderStates(currentContextMap);
2873 if (rv != SCARD_S_SUCCESS)
2874 goto end;
2875
2876 dwReadersLen = 0;
2877 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2878 if (readerStates[i].readerName[0] != '\0')
2879 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2880
2881 /* for the last NULL byte */
2882 dwReadersLen += 1;
2883
2884 if (1 == dwReadersLen)
2885 {
2887 goto end;
2888 }
2889
2891 {
2892 if (NULL == mszReaders)
2893 {
2895 goto end;
2896 }
2898 if (NULL == buf)
2899 {
2900 rv = SCARD_E_NO_MEMORY;
2901 goto end;
2902 }
2903 *(char **)mszReaders = buf;
2904 }
2905 else
2906 {
2907 buf = mszReaders;
2908
2909 /* not enough place to store the reader names */
2910 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2911 {
2913 goto end;
2914 }
2915 }
2916
2917 if (mszReaders == NULL) /* text array not allocated */
2918 goto end;
2919
2920 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2921 {
2922 if (readerStates[i].readerName[0] != '\0')
2923 {
2924 /*
2925 * Build the multi-string
2926 */
2927 strcpy(buf, readerStates[i].readerName);
2928 buf += strlen(readerStates[i].readerName)+1;
2929 }
2930 }
2931 *buf = '\0'; /* Add the last null */
2932
2933end:
2934 /* set the reader names length */
2936
2938
2939 PROFILE_END(rv)
2940 API_TRACE_OUT("%d", *pcchReaders)
2941
2942 return rv;
2943}
2944
2958LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2959{
2960 LONG rv = SCARD_S_SUCCESS;
2961
2962 PROFILE_START
2963
2964 /*
2965 * Make sure this context has been opened
2966 */
2967 if (! SCardGetContextValidity(hContext))
2969
2970 free((void *)pvMem);
2971
2972 PROFILE_END(rv)
2973
2974 return rv;
2975}
2976
3028LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3029 LPDWORD pcchGroups)
3030{
3031 LONG rv = SCARD_S_SUCCESS;
3033 char *buf = NULL;
3034
3035 PROFILE_START
3036
3037 /* Multi-string with two trailing \0 */
3038 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3039 const unsigned int dwGroups = sizeof(ReaderGroup);
3040
3041 /*
3042 * Make sure this context has been opened
3043 */
3045 if (NULL == currentContextMap)
3047
3049 {
3050 if (NULL == mszGroups)
3051 {
3053 goto end;
3054 }
3055 buf = malloc(dwGroups);
3056 if (NULL == buf)
3057 {
3058 rv = SCARD_E_NO_MEMORY;
3059 goto end;
3060 }
3061 *(char **)mszGroups = buf;
3062 }
3063 else
3064 {
3065 buf = mszGroups;
3066
3067 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3068 {
3070 goto end;
3071 }
3072 }
3073
3074 if (buf)
3076
3077end:
3079
3081
3082 PROFILE_END(rv)
3083
3084 return rv;
3085}
3086
3118LONG SCardCancel(SCARDCONTEXT hContext)
3119{
3121 LONG rv = SCARD_S_SUCCESS;
3122 uint32_t dwClientID = 0;
3124 bool cancellable;
3125
3126 PROFILE_START
3127 API_TRACE_IN("%ld", hContext)
3128
3129 /*
3130 * Make sure this context has been opened
3131 */
3134
3135 if (NULL == currentContextMap)
3136 {
3139 goto error;
3140 }
3141 cancellable = currentContextMap->cancellable;
3143
3144 if (! cancellable)
3145 {
3146 rv = SCARD_S_SUCCESS;
3147 goto error;
3148 }
3149
3150 /* create a new connection to the server */
3151 if (ClientSetupSession(&dwClientID) != 0)
3152 {
3153 rv = SCARD_E_NO_SERVICE;
3154 goto error;
3155 }
3156
3157 scCancelStruct.hContext = hContext;
3159
3160 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3161 sizeof(scCancelStruct), (void *) &scCancelStruct);
3162
3163 if (rv != SCARD_S_SUCCESS)
3164 goto end;
3165
3166 /*
3167 * Read a message from the server
3168 */
3169 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3170
3171 if (rv != SCARD_S_SUCCESS)
3172 goto end;
3173
3174 rv = scCancelStruct.rv;
3175end:
3176 ClientCloseSession(dwClientID);
3177
3178error:
3179 PROFILE_END(rv)
3180 API_TRACE_OUT("")
3181
3182 return rv;
3183}
3184
3208LONG SCardIsValidContext(SCARDCONTEXT hContext)
3209{
3210 LONG rv;
3211
3212 PROFILE_START
3213 API_TRACE_IN("%ld", hContext)
3214
3215 rv = SCARD_S_SUCCESS;
3216
3217 /*
3218 * Make sure this context has been opened
3219 */
3220 if (! SCardGetContextValidity(hContext))
3222
3223 PROFILE_END(rv)
3224 API_TRACE_OUT("")
3225
3226 return rv;
3227}
3228
3245static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3246{
3247 int lrv;
3249
3250 newContextMap = malloc(sizeof(SCONTEXTMAP));
3251 if (NULL == newContextMap)
3252 return SCARD_E_NO_MEMORY;
3253
3254 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3255 newContextMap->hContext = hContext;
3256 newContextMap->dwClientID = dwClientID;
3257 newContextMap->cancellable = false;
3258
3260
3261 lrv = list_init(&newContextMap->channelMapList);
3262 if (lrv < 0)
3263 {
3264 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3265 goto error;
3266 }
3267
3268 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3269 CHANNEL_MAP_seeker);
3270 if (lrv <0)
3271 {
3272 Log2(PCSC_LOG_CRITICAL,
3273 "list_attributes_seeker failed with return value: %d", lrv);
3274 list_destroy(&newContextMap->channelMapList);
3275 goto error;
3276 }
3277
3278 lrv = list_append(&contextMapList, newContextMap);
3279 if (lrv < 0)
3280 {
3281 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3282 lrv);
3283 list_destroy(&newContextMap->channelMapList);
3284 goto error;
3285 }
3286
3287 return SCARD_S_SUCCESS;
3288
3289error:
3290
3293
3294 return SCARD_E_NO_MEMORY;
3295}
3296
3314{
3316
3319
3320 /* lock the context (if available) */
3321 if (NULL != currentContextMap)
3323
3325
3326 return currentContextMap;
3327}
3328
3342{
3343 return list_seek(&contextMapList, &hContext);
3344}
3345
3353{
3356
3357 if (NULL != currentContextMap)
3358 SCardCleanContext(currentContextMap);
3359}
3360
3361static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3362{
3363 int list_index, lrv;
3364 int listSize;
3366
3367 targetContextMap->hContext = 0;
3369 targetContextMap->dwClientID = 0;
3371
3372 listSize = list_size(&targetContextMap->channelMapList);
3374 {
3375 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3376 list_index);
3377 if (NULL == currentChannelMap)
3378 {
3379 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3380 list_index);
3381 continue;
3382 }
3383 else
3384 {
3385 free(currentChannelMap->readerName);
3387 }
3388
3389 }
3390 list_destroy(&targetContextMap->channelMapList);
3391
3392 lrv = list_delete(&contextMapList, targetContextMap);
3393 if (lrv < 0)
3394 {
3395 Log2(PCSC_LOG_CRITICAL,
3396 "list_delete failed with return value: %d", lrv);
3397 }
3398
3400
3401 return;
3402}
3403
3404/*
3405 * Functions for managing hCard values returned from SCardConnect.
3406 */
3407
3408static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3409 LPCSTR readerName)
3410{
3412 int lrv = -1;
3413
3414 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3415 if (NULL == newChannelMap)
3416 return SCARD_E_NO_MEMORY;
3417
3418 newChannelMap->hCard = hCard;
3419 newChannelMap->readerName = strdup(readerName);
3420
3421 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3422 if (lrv < 0)
3423 {
3424 free(newChannelMap->readerName);
3426 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3427 lrv);
3428 return SCARD_E_NO_MEMORY;
3429 }
3430
3431 return SCARD_S_SUCCESS;
3432}
3433
3434static void SCardRemoveHandle(SCARDHANDLE hCard)
3435{
3438 int lrv;
3439 LONG rv;
3440
3441 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3443 if (rv == -1)
3444 return;
3445
3446 free(currentChannelMap->readerName);
3447
3448 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3449 if (lrv < 0)
3450 {
3451 Log2(PCSC_LOG_CRITICAL,
3452 "list_delete failed with return value: %d", lrv);
3453 }
3454
3456
3457 return;
3458}
3459
3460static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3462{
3463 LONG rv;
3464
3465 if (0 == hCard)
3466 return -1;
3467
3469 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3471
3472 if (SCARD_S_SUCCESS == rv)
3473 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3474
3476
3477 return rv;
3478}
3479
3480static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3482{
3483 int listSize;
3484 int list_index;
3487
3488 /* Best to get the caller a crash early if we fail unsafely */
3491
3492 listSize = list_size(&contextMapList);
3493
3495 {
3496 currentContextMap = list_get_at(&contextMapList, list_index);
3497 if (currentContextMap == NULL)
3498 {
3499 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3500 list_index);
3501 continue;
3502 }
3503 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3504 &hCard);
3505 if (currentChannelMap != NULL)
3506 {
3509 return SCARD_S_SUCCESS;
3510 }
3511 }
3512
3513 return -1;
3514}
3515
3524{
3525 LONG rv;
3526 struct stat statBuffer;
3527 char *socketName;
3528
3529 socketName = getSocketName();
3530 rv = stat(socketName, &statBuffer);
3531
3532 if (rv != 0)
3533 {
3534 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3536 return SCARD_E_NO_SERVICE;
3537 }
3538
3539 return SCARD_S_SUCCESS;
3540}
3541
3542static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3543{
3544 int32_t dwClientID = currentContextMap->dwClientID;
3545 LONG rv;
3546
3547 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3548 if (rv != SCARD_S_SUCCESS)
3549 return rv;
3550
3551 /* Read a message from the server */
3552 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3553 if (rv != SCARD_S_SUCCESS)
3554 return rv;
3555
3556 return SCARD_S_SUCCESS;
3557}
3558
3559static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3560{
3561 int32_t dwClientID = currentContextMap->dwClientID;
3562 LONG rv;
3563
3564 /* Get current reader states from server and register on event list */
3566 0, NULL);
3567 if (rv != SCARD_S_SUCCESS)
3568 return rv;
3569
3570 /* Read a message from the server */
3571 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3572 return rv;
3573}
3574
3575static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3576{
3577 int32_t dwClientID = currentContextMap->dwClientID;
3578 LONG rv;
3580
3581 /* ask server to remove us from the event list */
3583 dwClientID, 0, NULL);
3584 if (rv != SCARD_S_SUCCESS)
3585 return rv;
3586
3587 /* This message can be the response to
3588 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3589 * cancel notification.
3590 * The server side ensures, that no more messages will be sent to
3591 * the client. */
3592
3594 dwClientID);
3595 if (rv != SCARD_S_SUCCESS)
3596 return rv;
3597
3598 /* if we received a cancel event the return value will be set
3599 * accordingly */
3600 rv = waitStatusStruct.rv;
3601
3602 return rv;
3603}
3604
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition pcscd.h:53
@ POWER_STATE_POWERED
powered
Definition pcscd.h:64
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition pcscd.h:54
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition pcsclite.h:266
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:260
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition pcsclite.h:242
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:259
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition pcsclite.h:241
#define SCARD_STATE_INUSE
Shared Mode.
Definition pcsclite.h:274
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:233
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition pcsclite.h:269
#define SCARD_STATE_PRESENT
Card inserted.
Definition pcsclite.h:271
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:257
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:268
#define INFINITE
Infinite timeout.
Definition pcsclite.h:279
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:270
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition pcsclite.h:243
#define SCARD_STATE_MUTE
Unresponsive card.
Definition pcsclite.h:275
#define SCARD_STATE_CHANGED
State has changed.
Definition pcsclite.h:267
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition pcsclite.h:246
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:297
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition pcsclite.h:298
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition pcsclite.h:273
#define SCARD_STATE_UNAWARE
App wants status.
Definition pcsclite.h:265
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition pcsclite.h:284
This keeps track of a list of currently available reader structures.
Protocol Control Information (PCI)
Definition pcsclite.h:80
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
bool cancellable
We are in a cancellable call.
contained in SCARD_BEGIN_TRANSACTION Messages.
contained in SCARD_CANCEL Messages.
contained in SCARD_CONNECT Messages.
contained in SCARD_CONTROL Messages.
contained in SCARD_DISCONNECT Messages.
contained in SCARD_END_TRANSACTION Messages.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
contained in SCARD_GET_ATTRIB and Messages.
list object
Definition simclist.h:181
Define an exported public reader state structure so each application gets instant notification of cha...
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
uint32_t eventCounter
number of card events
uint32_t readerState
SCARD_* bit field.
uint32_t cardAtrLength
ATR length.
contained in SCARD_RECONNECT Messages.
Information contained in SCARD_RELEASE_CONTEXT Messages.
contained in SCARD_STATUS Messages.
contained in SCARD_TRANSMIT Messages.
Information transmitted in CMD_VERSION Messages.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition sys_unix.c:80
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition utils.c:138
This handles smart card reader communications.
static short isExecuted
Make sure the initialization code is executed only once.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
@ SCARD_DISCONNECT
used by SCardDisconnect()
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
@ CMD_GET_READERS_STATE
get the readers state
@ SCARD_CONTROL
used by SCardControl()
@ CMD_VERSION
get the client/server protocol version
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
@ SCARD_RECONNECT
used by SCardReconnect()
@ SCARD_STATUS
used by SCardStatus()
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
@ SCARD_TRANSMIT
used by SCardTransmit()
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
@ SCARD_CANCEL
used by SCardCancel()
@ SCARD_CONNECT
used by SCardConnect()
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()