pcsc-lite 2.2.1
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-2024
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{
153 va_list args;
154
155 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
156 direction, pthread_self(), func);
157
158 fprintf(stderr, COLOR_MAGENTA);
159 va_start(args, fmt);
160 vfprintf(stderr, fmt, args);
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
181pthread_t threads[MAX_THREADS];
182struct timeval profile_time_start[MAX_THREADS];
183FILE *profile_fd;
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",
205 PROFILE_FILE, strerror(errno));
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
224 gettimeofday(&profile_time_start[i], NULL);
225} /* profile_start */
226
227static void profile_end(const char *f, LONG rv)
228{
229 struct timeval profile_time_end;
230 long d;
231 pthread_t t;
232 int i;
233
234 gettimeofday(&profile_time_end, NULL);
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
247 d = time_sub(&profile_time_end, &profile_time_start[i]);
248
249 /* free this entry */
250 threads[i] = 0;
251
252 if (profile_tty)
253 {
254 if (rv != SCARD_S_SUCCESS)
255 fprintf(stderr,
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);
264 fflush(profile_fd);
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
308{
311 pthread_mutex_t mMutex;
312 list_t channelMapList;
314};
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 bool isExecuted = false;
346static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
347
348
353static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
354
359static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
360
361
362static LONG SCardAddContext(SCARDCONTEXT, DWORD);
366static void SCardCleanContext(SCONTEXTMAP *);
367
368static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
369static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
370 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
371static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
372 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
373static void SCardRemoveHandle(SCARDHANDLE);
374
375static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
376 LPBYTE pbAttr, LPDWORD pcbAttrLen);
377
378static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
379static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
380static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
381
382/*
383 * Thread safety functions
384 */
391inline static void SCardLockThread(void)
392{
393 pthread_mutex_lock(&clientMutex);
394}
395
401inline static void SCardUnlockThread(void)
402{
403 pthread_mutex_unlock(&clientMutex);
404}
405
416{
417 SCONTEXTMAP * currentContextMap;
418
420 currentContextMap = SCardGetContextTH(hContext);
422
423 return currentContextMap != NULL;
424}
425
426static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
427 /*@out@*/ LPSCARDCONTEXT);
428
464LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
465 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
466{
467 LONG rv;
468
469 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
470 PROFILE_START
471
472 /* Check if the server is running */
474 if (rv != SCARD_S_SUCCESS)
475 goto end;
476
478 rv = SCardEstablishContextTH(dwScope, pvReserved1,
479 pvReserved2, phContext);
481
482end:
483 PROFILE_END(rv)
484 API_TRACE_OUT("%ld", *phContext)
485
486 return rv;
487}
488
489#ifdef DESTRUCTOR
490DESTRUCTOR static void destructor(void)
491{
492 list_destroy(&contextMapList);
493}
494#endif
495
496/*
497 * Do this only once:
498 * - Initialize context list.
499 */
500static void init_lib(void)
501{
502 int lrv;
503
504 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
505 * Applications which load and unload the library may leak
506 * the list's internal structures. */
507 lrv = list_init(&contextMapList);
508 if (lrv < 0)
509 {
510 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
511 lrv);
512 return;
513 }
514
515 lrv = list_attributes_seeker(&contextMapList,
516 SCONTEXTMAP_seeker);
517 if (lrv <0)
518 {
519 Log2(PCSC_LOG_CRITICAL,
520 "list_attributes_seeker failed with return value: %d", lrv);
521 list_destroy(&contextMapList);
522 return;
523 }
524
525 if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
526 {
527 Log1(PCSC_LOG_INFO, "Disable shared blocking");
528 sharing_shall_block = false;
529 }
530
531 isExecuted = true;
532}
533
561static LONG SCardEstablishContextTH(DWORD dwScope,
562 /*@unused@*/ LPCVOID pvReserved1,
563 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
564{
565 LONG rv;
566 struct establish_struct scEstablishStruct;
567 uint32_t dwClientID = 0;
568
569 (void)pvReserved1;
570 (void)pvReserved2;
571 if (phContext == NULL)
573 else
574 *phContext = 0;
575
576 pthread_once(&init_lib_control, init_lib);
577 if (!isExecuted)
578 return SCARD_E_NO_MEMORY;
579
580 /* Establishes a connection to the server */
581 if (ClientSetupSession(&dwClientID) != 0)
582 {
583 return SCARD_E_NO_SERVICE;
584 }
585
586 { /* exchange client/server protocol versions */
587 struct version_struct veStr;
588
591 veStr.rv = SCARD_S_SUCCESS;
592
593 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
594 &veStr);
595 if (rv != SCARD_S_SUCCESS)
596 goto cleanup;
597
598 /* Read a message from the server */
599 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
600 if (rv != SCARD_S_SUCCESS)
601 {
602 Log1(PCSC_LOG_CRITICAL,
603 "Your pcscd is too old and does not support CMD_VERSION");
604 goto cleanup;
605 }
606
607 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
608 veStr.major, veStr.minor);
609
610 if (veStr.rv != SCARD_S_SUCCESS)
611 {
612 rv = veStr.rv;
613 goto cleanup;
614 }
615 }
616
617again:
618 /*
619 * Try to establish an Application Context with the server
620 */
621 scEstablishStruct.dwScope = dwScope;
622 scEstablishStruct.hContext = 0;
623 scEstablishStruct.rv = SCARD_S_SUCCESS;
624
626 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
627
628 if (rv != SCARD_S_SUCCESS)
629 goto cleanup;
630
631 /*
632 * Read the response from the server
633 */
634 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
635 dwClientID);
636
637 if (rv != SCARD_S_SUCCESS)
638 goto cleanup;
639
640 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
641 {
642 rv = scEstablishStruct.rv;
643 goto cleanup;
644 }
645
646 /* check we do not reuse an existing hContext */
647 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
648 /* we do not need to release the allocated context since
649 * SCardReleaseContext() does nothing on the server side */
650 goto again;
651
652 *phContext = scEstablishStruct.hContext;
653
654 /*
655 * Allocate the new hContext - if allocator full return an error
656 */
657 rv = SCardAddContext(*phContext, dwClientID);
658
659 return rv;
660
661cleanup:
662 ClientCloseSession(dwClientID);
663
664 return rv;
665}
666
689{
690 LONG rv;
691 struct release_struct scReleaseStruct;
692 SCONTEXTMAP * currentContextMap;
693
694 API_TRACE_IN("%ld", hContext)
695 PROFILE_START
696
697 /*
698 * Make sure this context has been opened
699 * and get currentContextMap
700 */
701 currentContextMap = SCardGetAndLockContext(hContext);
702 if (NULL == currentContextMap)
703 {
705 goto error;
706 }
707
708 scReleaseStruct.hContext = hContext;
709 scReleaseStruct.rv = SCARD_S_SUCCESS;
710
712 currentContextMap->dwClientID,
713 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
714
715 if (rv != SCARD_S_SUCCESS)
716 goto end;
717
718 /*
719 * Read a message from the server
720 */
721 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
722 currentContextMap->dwClientID);
723
724 if (rv != SCARD_S_SUCCESS)
725 goto end;
726
727 rv = scReleaseStruct.rv;
728end:
729 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
730
731 /*
732 * Remove the local context from the stack
733 */
735 SCardRemoveContext(hContext);
737
738error:
739 PROFILE_END(rv)
740 API_TRACE_OUT("")
741
742 return rv;
743}
744
800LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
801 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
802 LPDWORD pdwActiveProtocol)
803{
804 LONG rv;
805 struct connect_struct scConnectStruct;
806 SCONTEXTMAP * currentContextMap;
807
808 PROFILE_START
809 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
810
811 /*
812 * Check for NULL parameters
813 */
814 if (phCard == NULL || pdwActiveProtocol == NULL)
816 else
817 *phCard = 0;
818
819 if (szReader == NULL)
821
822 /*
823 * Check for uninitialized strings
824 */
825 if (strlen(szReader) > MAX_READERNAME)
827
828 /*
829 * Make sure this context has been opened
830 */
831 currentContextMap = SCardGetAndLockContext(hContext);
832 if (NULL == currentContextMap)
834
835 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
836 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
837 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
838
839 scConnectStruct.hContext = hContext;
840 scConnectStruct.dwShareMode = dwShareMode;
841 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
842 scConnectStruct.hCard = 0;
843 scConnectStruct.dwActiveProtocol = 0;
844 scConnectStruct.rv = SCARD_S_SUCCESS;
845
846 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
847 sizeof(scConnectStruct), (void *) &scConnectStruct);
848
849 if (rv != SCARD_S_SUCCESS)
850 goto end;
851
852 /*
853 * Read a message from the server
854 */
855 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
856 currentContextMap->dwClientID);
857
858 if (rv != SCARD_S_SUCCESS)
859 goto end;
860
861 *phCard = scConnectStruct.hCard;
862 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
863
864 if (scConnectStruct.rv == SCARD_S_SUCCESS)
865 {
866 /*
867 * Keep track of the handle locally
868 */
869 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
870 }
871 else
872 rv = scConnectStruct.rv;
873
874end:
875 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
876
877 PROFILE_END(rv)
878 API_TRACE_OUT("%d", *pdwActiveProtocol)
879
880 return rv;
881}
882
955LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
956 DWORD dwPreferredProtocols, DWORD dwInitialization,
957 LPDWORD pdwActiveProtocol)
958{
959 LONG rv;
960 struct reconnect_struct scReconnectStruct;
961 SCONTEXTMAP * currentContextMap;
962 CHANNEL_MAP * pChannelMap;
963
964 PROFILE_START
965 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
966
967 if (pdwActiveProtocol == NULL)
969
970 /* Retry loop for blocking behaviour */
971retry:
972
973 /*
974 * Make sure this handle has been opened
975 */
976 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
977 &pChannelMap);
978 if (rv == -1)
980
981 scReconnectStruct.hCard = hCard;
982 scReconnectStruct.dwShareMode = dwShareMode;
983 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
984 scReconnectStruct.dwInitialization = dwInitialization;
985 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
986 scReconnectStruct.rv = SCARD_S_SUCCESS;
987
988 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
989 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
990
991 if (rv != SCARD_S_SUCCESS)
992 goto end;
993
994 /*
995 * Read a message from the server
996 */
997 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
998 currentContextMap->dwClientID);
999
1000 if (rv != SCARD_S_SUCCESS)
1001 goto end;
1002
1003 rv = scReconnectStruct.rv;
1004
1005 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1006 {
1007 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1008 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1009 goto retry;
1010 }
1011
1012 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1013
1014end:
1015 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1016
1017 PROFILE_END(rv)
1018 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1019
1020 return rv;
1021}
1022
1054LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1055{
1056 LONG rv;
1057 struct disconnect_struct scDisconnectStruct;
1058 SCONTEXTMAP * currentContextMap;
1059 CHANNEL_MAP * pChannelMap;
1060
1061 PROFILE_START
1062 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1063
1064 /*
1065 * Make sure this handle has been opened
1066 */
1067 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1068 &pChannelMap);
1069 if (rv == -1)
1070 {
1072 goto error;
1073 }
1074
1075 scDisconnectStruct.hCard = hCard;
1076 scDisconnectStruct.dwDisposition = dwDisposition;
1077 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1078
1079 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1080 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1081
1082 if (rv != SCARD_S_SUCCESS)
1083 goto end;
1084
1085 /*
1086 * Read a message from the server
1087 */
1088 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1089 currentContextMap->dwClientID);
1090
1091 if (rv != SCARD_S_SUCCESS)
1092 goto end;
1093
1094 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1095 SCardRemoveHandle(hCard);
1096 rv = scDisconnectStruct.rv;
1097
1098end:
1099 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1100
1101error:
1102 PROFILE_END(rv)
1103 API_TRACE_OUT("")
1104
1105 return rv;
1106}
1107
1145{
1146
1147 LONG rv;
1148 struct begin_struct scBeginStruct;
1149 SCONTEXTMAP * currentContextMap;
1150 CHANNEL_MAP * pChannelMap;
1151
1152 PROFILE_START
1153 API_TRACE_IN("%ld", hCard)
1154
1155 /*
1156 * Query the server every so often until the sharing violation ends
1157 * and then hold the lock for yourself.
1158 */
1159
1160 for(;;)
1161 {
1162 /*
1163 * Make sure this handle has been opened
1164 */
1165 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1166 &pChannelMap);
1167 if (rv == -1)
1169
1170 scBeginStruct.hCard = hCard;
1171 scBeginStruct.rv = SCARD_S_SUCCESS;
1172
1174 currentContextMap->dwClientID,
1175 sizeof(scBeginStruct), (void *) &scBeginStruct);
1176
1177 if (rv != SCARD_S_SUCCESS)
1178 break;
1179
1180 /*
1181 * Read a message from the server
1182 */
1183 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1184 currentContextMap->dwClientID);
1185
1186 if (rv != SCARD_S_SUCCESS)
1187 break;
1188
1189 rv = scBeginStruct.rv;
1190
1191 if (SCARD_E_SHARING_VIOLATION != rv)
1192 break;
1193
1194 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1195 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1196 }
1197
1198 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1199
1200 PROFILE_END(rv)
1201 API_TRACE_OUT("")
1202
1203 return rv;
1204}
1205
1245LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1246{
1247 LONG rv;
1248 struct end_struct scEndStruct;
1249 SCONTEXTMAP * currentContextMap;
1250 CHANNEL_MAP * pChannelMap;
1251
1252 PROFILE_START
1253 API_TRACE_IN("%ld", hCard)
1254
1255 /*
1256 * Make sure this handle has been opened
1257 */
1258 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1259 &pChannelMap);
1260 if (rv == -1)
1262
1263 scEndStruct.hCard = hCard;
1264 scEndStruct.dwDisposition = dwDisposition;
1265 scEndStruct.rv = SCARD_S_SUCCESS;
1266
1268 currentContextMap->dwClientID,
1269 sizeof(scEndStruct), (void *) &scEndStruct);
1270
1271 if (rv != SCARD_S_SUCCESS)
1272 goto end;
1273
1274 /*
1275 * Read a message from the server
1276 */
1277 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1278 currentContextMap->dwClientID);
1279
1280 if (rv != SCARD_S_SUCCESS)
1281 goto end;
1282
1283 rv = scEndStruct.rv;
1284
1285end:
1286 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1287
1288 PROFILE_END(rv)
1289 API_TRACE_OUT("")
1290
1291 return rv;
1292}
1293
1389LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1390 LPDWORD pcchReaderLen, LPDWORD pdwState,
1391 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1392{
1393 DWORD dwReaderLen, dwAtrLen;
1394 LONG rv;
1395 int i;
1396 struct status_struct scStatusStruct;
1397 SCONTEXTMAP * currentContextMap;
1398 CHANNEL_MAP * pChannelMap;
1399 char *r;
1400 char *bufReader = NULL;
1401 LPBYTE bufAtr = NULL;
1402 DWORD dummy = 0;
1403
1404 PROFILE_START
1405
1406 /* default output values */
1407 if (pdwState)
1408 *pdwState = 0;
1409
1410 if (pdwProtocol)
1411 *pdwProtocol = 0;
1412
1413 /* Check for NULL parameters */
1414 if (pcchReaderLen == NULL)
1415 pcchReaderLen = &dummy;
1416
1417 if (pcbAtrLen == NULL)
1418 pcbAtrLen = &dummy;
1419
1420 /* length passed from caller */
1421 dwReaderLen = *pcchReaderLen;
1422 dwAtrLen = *pcbAtrLen;
1423
1424 *pcchReaderLen = 0;
1425 *pcbAtrLen = 0;
1426
1427 /* Retry loop for blocking behaviour */
1428retry:
1429
1430 /*
1431 * Make sure this handle has been opened
1432 */
1433 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1434 &pChannelMap);
1435 if (rv == -1)
1437
1438 /* lock access to readerStates[] */
1439 (void)pthread_mutex_lock(&readerStatesMutex);
1440
1441 /* synchronize reader states with daemon */
1442 rv = getReaderStates(currentContextMap);
1443 if (rv != SCARD_S_SUCCESS)
1444 goto end;
1445
1446 r = pChannelMap->readerName;
1447 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1448 {
1449 /* by default r == NULL */
1450 if (r && strcmp(r, readerStates[i].readerName) == 0)
1451 break;
1452 }
1453
1455 {
1457 goto end;
1458 }
1459
1460 /* initialise the structure */
1461 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1462 scStatusStruct.hCard = hCard;
1463
1464 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1465 sizeof(scStatusStruct), (void *) &scStatusStruct);
1466
1467 if (rv != SCARD_S_SUCCESS)
1468 goto end;
1469
1470 /*
1471 * Read a message from the server
1472 */
1473 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1474 currentContextMap->dwClientID);
1475
1476 if (rv != SCARD_S_SUCCESS)
1477 goto end;
1478
1479 rv = scStatusStruct.rv;
1480
1481 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1482 {
1483 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1484 (void)pthread_mutex_unlock(&readerStatesMutex);
1485 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1486 goto retry;
1487 }
1488
1490 {
1491 /*
1492 * An event must have occurred
1493 */
1494 goto end;
1495 }
1496
1497 /*
1498 * Now continue with the client side SCardStatus
1499 */
1500
1501 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1502 *pcbAtrLen = readerStates[i].cardAtrLength;
1503
1504 if (pdwState)
1505 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1506
1507 if (pdwProtocol)
1508 *pdwProtocol = readerStates[i].cardProtocol;
1509
1510 if (SCARD_AUTOALLOCATE == dwReaderLen)
1511 {
1512 dwReaderLen = *pcchReaderLen;
1513 if (NULL == szReaderName)
1514 {
1516 goto end;
1517 }
1518 bufReader = malloc(dwReaderLen);
1519 if (NULL == bufReader)
1520 {
1521 rv = SCARD_E_NO_MEMORY;
1522 goto end;
1523 }
1524 *(char **)szReaderName = bufReader;
1525 }
1526 else
1527 bufReader = szReaderName;
1528
1529 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1530 if (bufReader)
1531 {
1532 if (*pcchReaderLen > dwReaderLen)
1534
1535 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1536 }
1537
1538 if (SCARD_AUTOALLOCATE == dwAtrLen)
1539 {
1540 dwAtrLen = *pcbAtrLen;
1541 if (NULL == pbAtr)
1542 {
1544 goto end;
1545 }
1546 bufAtr = malloc(dwAtrLen);
1547 if (NULL == bufAtr)
1548 {
1549 rv = SCARD_E_NO_MEMORY;
1550 goto end;
1551 }
1552 *(LPBYTE *)pbAtr = bufAtr;
1553 }
1554 else
1555 bufAtr = pbAtr;
1556
1557 if (bufAtr)
1558 {
1559 if (*pcbAtrLen > dwAtrLen)
1561
1562 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1563 }
1564
1565end:
1566 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1567 (void)pthread_mutex_unlock(&readerStatesMutex);
1568
1569 PROFILE_END(rv)
1570
1571 return rv;
1572}
1573
1681LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1682 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1683{
1684 SCARD_READERSTATE *currReader;
1685 READER_STATE *rContext;
1686 long dwTime;
1687 DWORD dwBreakFlag = 0;
1688 unsigned int j;
1689 SCONTEXTMAP * currentContextMap;
1690 int currentReaderCount = 0;
1691 LONG rv = SCARD_S_SUCCESS;
1692
1693 PROFILE_START
1694 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1695#ifdef DO_TRACE
1696 for (j=0; j<cReaders; j++)
1697 {
1698 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1699 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1700 }
1701#endif
1702
1703 if ((rgReaderStates == NULL && cReaders > 0)
1704 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1705 {
1707 goto error;
1708 }
1709
1710 /* Check the integrity of the reader states structures */
1711 for (j = 0; j < cReaders; j++)
1712 {
1713 if (rgReaderStates[j].szReader == NULL)
1714 return SCARD_E_INVALID_VALUE;
1715 }
1716
1717 /* return if all readers are SCARD_STATE_IGNORE */
1718 if (cReaders > 0)
1719 {
1720 int nbNonIgnoredReaders = cReaders;
1721
1722 for (j=0; j<cReaders; j++)
1723 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1724 nbNonIgnoredReaders--;
1725
1726 if (0 == nbNonIgnoredReaders)
1727 {
1728 rv = SCARD_S_SUCCESS;
1729 goto error;
1730 }
1731 }
1732 else
1733 {
1734 /* reader list is empty */
1735 rv = SCARD_S_SUCCESS;
1736 goto error;
1737 }
1738
1739 /*
1740 * Make sure this context has been opened
1741 */
1742 currentContextMap = SCardGetAndLockContext(hContext);
1743 if (NULL == currentContextMap)
1744 {
1746 goto error;
1747 }
1748
1749 /* lock access to readerStates[] */
1750 (void)pthread_mutex_lock(&readerStatesMutex);
1751
1752 /* synchronize reader states with daemon */
1753 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1754
1755 if (rv != SCARD_S_SUCCESS)
1756 {
1757 (void)pthread_mutex_unlock(&readerStatesMutex);
1758 goto end;
1759 }
1760
1761 /* check all the readers are already known */
1762 for (j=0; j<cReaders; j++)
1763 {
1764 const char *readerName;
1765 int i;
1766
1767 readerName = rgReaderStates[j].szReader;
1768 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1769 {
1770 if (strcmp(readerName, readerStates[i].readerName) == 0)
1771 break;
1772 }
1773
1774 /* The requested reader name is not recognized */
1776 {
1777 /* PnP special reader? */
1778 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1779 {
1781 (void)pthread_mutex_unlock(&readerStatesMutex);
1782 goto end;
1783 }
1784 }
1785 }
1786 (void)pthread_mutex_unlock(&readerStatesMutex);
1787
1788 /* Clear the event state for all readers */
1789 for (j = 0; j < cReaders; j++)
1790 rgReaderStates[j].dwEventState = 0;
1791
1792 /* Now is where we start our event checking loop */
1793 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1794
1795 /* Get the initial reader count on the system */
1796 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1797 if (readerStates[j].readerName[0] != '\0')
1798 currentReaderCount++;
1799
1800 /* catch possible sign extension problems from 32 to 64-bits integers */
1801 if ((DWORD)-1 == dwTimeout)
1802 dwTimeout = INFINITE;
1803 if (INFINITE == dwTimeout)
1804 dwTime = 60*1000; /* "infinite" timeout */
1805 else
1806 dwTime = dwTimeout;
1807
1808 j = 0;
1809 do
1810 {
1811 currReader = &rgReaderStates[j];
1812
1813 /* Ignore for IGNORED readers */
1814 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1815 {
1816 const char *readerName;
1817 int i;
1818
1819 /* lock access to readerStates[] */
1820 (void)pthread_mutex_lock(&readerStatesMutex);
1821
1822 /* Looks for correct readernames */
1823 readerName = currReader->szReader;
1824 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1825 {
1826 if (strcmp(readerName, readerStates[i].readerName) == 0)
1827 break;
1828 }
1829
1830 /* The requested reader name is not recognized */
1832 {
1833 /* PnP special reader? */
1834 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1835 {
1836 int k, newReaderCount = 0;
1837
1838 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1839 if (readerStates[k].readerName[0] != '\0')
1840 newReaderCount++;
1841
1842 if (newReaderCount != currentReaderCount)
1843 {
1844 Log1(PCSC_LOG_INFO, "Reader list changed");
1845 currentReaderCount = newReaderCount;
1846
1847 currReader->dwEventState |= SCARD_STATE_CHANGED;
1848 dwBreakFlag = 1;
1849 }
1850 }
1851 else
1852 {
1853 currReader->dwEventState =
1855 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1856 {
1857 currReader->dwEventState |= SCARD_STATE_CHANGED;
1858 /*
1859 * Spec says use SCARD_STATE_IGNORE but a removed USB
1860 * reader with eventState fed into currentState will
1861 * be ignored forever
1862 */
1863 dwBreakFlag = 1;
1864 }
1865 }
1866 }
1867 else
1868 {
1869 uint32_t readerState;
1870
1871 /* The reader has come back after being away */
1872 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1873 {
1874 currReader->dwEventState |= SCARD_STATE_CHANGED;
1875 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1876 Log0(PCSC_LOG_DEBUG);
1877 dwBreakFlag = 1;
1878 }
1879
1880 /* Set the reader status structure */
1881 rContext = &readerStates[i];
1882
1883 /* Now we check all the Reader States */
1884 readerState = rContext->readerState;
1885
1886 /* only if current state has an non null event counter */
1887 if (currReader->dwCurrentState & 0xFFFF0000)
1888 {
1889 unsigned int currentCounter;
1890
1891 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1892
1893 /* has the event counter changed since the last call? */
1894 if (rContext->eventCounter != currentCounter)
1895 {
1896 currReader->dwEventState |= SCARD_STATE_CHANGED;
1897 Log0(PCSC_LOG_DEBUG);
1898 dwBreakFlag = 1;
1899 }
1900 }
1901
1902 /* add an event counter in the upper word of dwEventState */
1903 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1904 | (rContext->eventCounter << 16));
1905
1906 /* Check if the reader is in the correct state */
1907 if (readerState & SCARD_UNKNOWN)
1908 {
1909 /* reader is in bad state */
1910 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1911 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1912 {
1913 /* App thinks reader is in good state and it is not */
1914 currReader->dwEventState |= SCARD_STATE_CHANGED;
1915 Log0(PCSC_LOG_DEBUG);
1916 dwBreakFlag = 1;
1917 }
1918 }
1919 else
1920 {
1921 /* App thinks reader in bad state but it is not */
1922 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1923 {
1924 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1925 currReader->dwEventState |= SCARD_STATE_CHANGED;
1926 Log0(PCSC_LOG_DEBUG);
1927 dwBreakFlag = 1;
1928 }
1929 }
1930
1931 /* Check for card presence in the reader */
1932 if (readerState & SCARD_PRESENT)
1933 {
1934#ifndef DISABLE_AUTO_POWER_ON
1935 /* card present but not yet powered up */
1936 if (0 == rContext->cardAtrLength)
1937 /* Allow the status thread to convey information */
1938 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1939#endif
1940
1941 currReader->cbAtr = rContext->cardAtrLength;
1942 memcpy(currReader->rgbAtr, rContext->cardAtr,
1943 currReader->cbAtr);
1944 }
1945 else
1946 currReader->cbAtr = 0;
1947
1948 /* Card is now absent */
1949 if (readerState & SCARD_ABSENT)
1950 {
1951 currReader->dwEventState |= SCARD_STATE_EMPTY;
1952 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1953 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1954 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1955 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1956 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1957 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1958 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1959 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1960
1961 /* After present the rest are assumed */
1962 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1963 {
1964 currReader->dwEventState |= SCARD_STATE_CHANGED;
1965 Log0(PCSC_LOG_DEBUG);
1966 dwBreakFlag = 1;
1967 }
1968 }
1969 /* Card is now present */
1970 else if (readerState & SCARD_PRESENT)
1971 {
1972 currReader->dwEventState |= SCARD_STATE_PRESENT;
1973 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1974 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1975 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1976 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1977 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1978 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1979
1980 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1981 {
1982 currReader->dwEventState |= SCARD_STATE_CHANGED;
1983 Log0(PCSC_LOG_DEBUG);
1984 dwBreakFlag = 1;
1985 }
1986
1987 if (readerState & SCARD_SWALLOWED)
1988 {
1989 currReader->dwEventState |= SCARD_STATE_MUTE;
1990 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1991 {
1992 currReader->dwEventState |= SCARD_STATE_CHANGED;
1993 Log0(PCSC_LOG_DEBUG);
1994 dwBreakFlag = 1;
1995 }
1996 }
1997 else
1998 {
1999 /* App thinks card is mute but it is not */
2000 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2001 {
2002 currReader->dwEventState |= SCARD_STATE_CHANGED;
2003 Log0(PCSC_LOG_DEBUG);
2004 dwBreakFlag = 1;
2005 }
2006 }
2007 }
2008
2009 /* Now figure out sharing modes */
2011 {
2012 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2013 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2014 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2015 {
2016 currReader->dwEventState |= SCARD_STATE_CHANGED;
2017 Log0(PCSC_LOG_DEBUG);
2018 dwBreakFlag = 1;
2019 }
2020 }
2021 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2022 {
2023 /* A card must be inserted for it to be INUSE */
2024 if (readerState & SCARD_PRESENT)
2025 {
2026 currReader->dwEventState |= SCARD_STATE_INUSE;
2027 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2028 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2029 {
2030 currReader->dwEventState |= SCARD_STATE_CHANGED;
2031 Log0(PCSC_LOG_DEBUG);
2032 dwBreakFlag = 1;
2033 }
2034 }
2035 }
2036 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2037 {
2038 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2039 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2040
2041 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2042 {
2043 currReader->dwEventState |= SCARD_STATE_CHANGED;
2044 Log0(PCSC_LOG_DEBUG);
2045 dwBreakFlag = 1;
2046 }
2047 else if (currReader-> dwCurrentState
2049 {
2050 currReader->dwEventState |= SCARD_STATE_CHANGED;
2051 Log0(PCSC_LOG_DEBUG);
2052 dwBreakFlag = 1;
2053 }
2054 }
2055
2056 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2057 {
2058 /*
2059 * Break out of the while .. loop and return status
2060 * once all the status's for all readers is met
2061 */
2062 currReader->dwEventState |= SCARD_STATE_CHANGED;
2063 Log0(PCSC_LOG_DEBUG);
2064 dwBreakFlag = 1;
2065 }
2066 } /* End of SCARD_STATE_UNKNOWN */
2067
2068 (void)pthread_mutex_unlock(&readerStatesMutex);
2069 } /* End of SCARD_STATE_IGNORE */
2070
2071 /* Counter and resetter */
2072 j++;
2073 if (j == cReaders)
2074 {
2075 /* go back to the first reader */
2076 j = 0;
2077
2078 /* Declare all the break conditions */
2079
2080 /* Break if UNAWARE is set and all readers have been checked */
2081 if (dwBreakFlag == 1)
2082 break;
2083
2084 /* Only sleep once for each cycle of reader checks. */
2085 {
2086 struct wait_reader_state_change waitStatusStruct = {0};
2087 struct timeval before, after;
2088
2089 gettimeofday(&before, NULL);
2090
2091 waitStatusStruct.rv = SCARD_S_SUCCESS;
2092
2093 /* another thread can do SCardCancel() */
2094 currentContextMap->cancellable = true;
2095
2096 /*
2097 * Read a message from the server
2098 */
2100 &waitStatusStruct, sizeof(waitStatusStruct),
2101 currentContextMap->dwClientID, dwTime);
2102
2103 /* SCardCancel() will return immediately with success
2104 * because something changed on the daemon side. */
2105 currentContextMap->cancellable = false;
2106
2107 /* timeout */
2108 if (SCARD_E_TIMEOUT == rv)
2109 {
2110 /* ask server to remove us from the event list */
2111 rv = unregisterFromEvents(currentContextMap);
2112 }
2113
2114 if (rv != SCARD_S_SUCCESS)
2115 goto end;
2116
2117 /* an event occurs or SCardCancel() was called */
2118 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2119 {
2120 rv = waitStatusStruct.rv;
2121 goto end;
2122 }
2123
2124 /* synchronize reader states with daemon */
2125 (void)pthread_mutex_lock(&readerStatesMutex);
2126 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2127 (void)pthread_mutex_unlock(&readerStatesMutex);
2128 if (rv != SCARD_S_SUCCESS)
2129 goto end;
2130
2131 if (INFINITE != dwTimeout)
2132 {
2133 long int diff;
2134
2135 gettimeofday(&after, NULL);
2136 diff = time_sub(&after, &before);
2137 dwTime -= diff/1000;
2138 }
2139 }
2140
2141 if (dwTimeout != INFINITE)
2142 {
2143 /* If time is greater than timeout and all readers have been
2144 * checked
2145 */
2146 if (dwTime <= 0)
2147 {
2148 rv = SCARD_E_TIMEOUT;
2149 goto end;
2150 }
2151 }
2152 }
2153 }
2154 while (1);
2155
2156end:
2157 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2158
2159 /* if SCardCancel() has been used then the client is already
2160 * unregistered */
2161 if (SCARD_E_CANCELLED != rv)
2162 (void)unregisterFromEvents(currentContextMap);
2163
2164 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2165
2166error:
2167 PROFILE_END(rv)
2168#ifdef DO_TRACE
2169 for (j=0; j<cReaders; j++)
2170 {
2171 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2172 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2173 }
2174#endif
2175
2176 return rv;
2177}
2178
2229LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2230 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2231 LPDWORD lpBytesReturned)
2232{
2233 LONG rv;
2234 struct control_struct scControlStruct;
2235 SCONTEXTMAP * currentContextMap;
2236 CHANNEL_MAP * pChannelMap;
2237
2238 PROFILE_START
2239
2240 /* 0 bytes received by default */
2241 if (NULL != lpBytesReturned)
2242 *lpBytesReturned = 0;
2243
2244 /*
2245 * Make sure this handle has been opened
2246 */
2247 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2248 &pChannelMap);
2249 if (rv == -1)
2250 {
2251 PROFILE_END(SCARD_E_INVALID_HANDLE)
2253 }
2254
2255 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2256 {
2258 goto end;
2259 }
2260
2261 scControlStruct.hCard = hCard;
2262 scControlStruct.dwControlCode = dwControlCode;
2263 scControlStruct.cbSendLength = cbSendLength;
2264 scControlStruct.cbRecvLength = cbRecvLength;
2265 scControlStruct.dwBytesReturned = 0;
2266 scControlStruct.rv = 0;
2267
2268 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2269 sizeof(scControlStruct), &scControlStruct);
2270
2271 if (rv != SCARD_S_SUCCESS)
2272 goto end;
2273
2274 /* write the sent buffer */
2275 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2276 currentContextMap->dwClientID);
2277
2278 if (rv != SCARD_S_SUCCESS)
2279 goto end;
2280
2281 /*
2282 * Read a message from the server
2283 */
2284 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2285 currentContextMap->dwClientID);
2286
2287 if (rv != SCARD_S_SUCCESS)
2288 goto end;
2289
2290 if (SCARD_S_SUCCESS == scControlStruct.rv)
2291 {
2292 if (scControlStruct.dwBytesReturned > cbRecvLength)
2293 {
2294 if (NULL != lpBytesReturned)
2295 *lpBytesReturned = scControlStruct.dwBytesReturned;
2297 goto end;
2298 }
2299
2300 /* read the received buffer */
2301 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2302 currentContextMap->dwClientID);
2303
2304 if (rv != SCARD_S_SUCCESS)
2305 goto end;
2306
2307 }
2308
2309 if (NULL != lpBytesReturned)
2310 *lpBytesReturned = scControlStruct.dwBytesReturned;
2311
2312 rv = scControlStruct.rv;
2313
2314end:
2315 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2316
2317 PROFILE_END(rv)
2318
2319 return rv;
2320}
2321
2440LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2441 LPDWORD pcbAttrLen)
2442{
2443 LONG ret;
2444 unsigned char *buf = NULL;
2445
2446 PROFILE_START
2447
2448 if (NULL == pcbAttrLen)
2449 {
2451 goto end;
2452 }
2453
2454 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2455 {
2456 if (NULL == pbAttr)
2458
2459 *pcbAttrLen = MAX_BUFFER_SIZE;
2460 buf = malloc(*pcbAttrLen);
2461 if (NULL == buf)
2462 {
2463 ret = SCARD_E_NO_MEMORY;
2464 goto end;
2465 }
2466
2467 *(unsigned char **)pbAttr = buf;
2468 }
2469 else
2470 {
2471 buf = pbAttr;
2472
2473 /* if only get the length */
2474 if (NULL == pbAttr)
2475 /* use a reasonable size */
2476 *pcbAttrLen = MAX_BUFFER_SIZE;
2477 }
2478
2479 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2480 pcbAttrLen);
2481
2482end:
2483 PROFILE_END(ret)
2484
2485 return ret;
2486}
2487
2523LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2524 DWORD cbAttrLen)
2525{
2526 LONG ret;
2527
2528 PROFILE_START
2529
2530 if (NULL == pbAttr || 0 == cbAttrLen)
2532
2533 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2534 &cbAttrLen);
2535
2536 PROFILE_END(ret)
2537
2538 return ret;
2539}
2540
2541static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2542 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2543{
2544 LONG rv;
2545 struct getset_struct scGetSetStruct;
2546 SCONTEXTMAP * currentContextMap;
2547 CHANNEL_MAP * pChannelMap;
2548
2549 /*
2550 * Make sure this handle has been opened
2551 */
2552 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2553 &pChannelMap);
2554 if (rv == -1)
2556
2557 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2558 {
2560 goto end;
2561 }
2562
2563 scGetSetStruct.hCard = hCard;
2564 scGetSetStruct.dwAttrId = dwAttrId;
2565 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2566 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2567 if (SCARD_SET_ATTRIB == command)
2568 {
2569 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2570 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2571 }
2572 else
2573 /* we can get up to the communication buffer size */
2574 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2575
2576 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2577 sizeof(scGetSetStruct), &scGetSetStruct);
2578
2579 if (rv != SCARD_S_SUCCESS)
2580 goto end;
2581
2582 /*
2583 * Read a message from the server
2584 */
2585 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2586 currentContextMap->dwClientID);
2587
2588 if (rv != SCARD_S_SUCCESS)
2589 goto end;
2590
2591 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2592 {
2593 /*
2594 * Copy and zero it so any secret information is not leaked
2595 */
2596 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2597 {
2598 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2599 * buffer overflow in the memcpy() below */
2600 DWORD correct_value = scGetSetStruct.cbAttrLen;
2601 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2602 *pcbAttrLen = correct_value;
2603
2604 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2605 }
2606 else
2607 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2608
2609 if (pbAttr)
2610 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2611
2612 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2613 }
2614 rv = scGetSetStruct.rv;
2615
2616end:
2617 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2618
2619 return rv;
2620}
2621
2680LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2681 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2682 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2683 LPDWORD pcbRecvLength)
2684{
2685 LONG rv;
2686 SCONTEXTMAP * currentContextMap;
2687 CHANNEL_MAP * pChannelMap;
2688 struct transmit_struct scTransmitStruct;
2689
2690 PROFILE_START
2691
2692 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2693 pcbRecvLength == NULL || pioSendPci == NULL)
2695
2696 /* Retry loop for blocking behaviour */
2697retry:
2698
2699 /*
2700 * Make sure this handle has been opened
2701 */
2702 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2703 &pChannelMap);
2704 if (rv == -1)
2705 {
2706 *pcbRecvLength = 0;
2707 PROFILE_END(SCARD_E_INVALID_HANDLE)
2709 }
2710
2711 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2712 {
2714 goto end;
2715 }
2716
2717 scTransmitStruct.hCard = hCard;
2718 scTransmitStruct.cbSendLength = cbSendLength;
2719 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2720 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2721 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2722 scTransmitStruct.rv = SCARD_S_SUCCESS;
2723
2724 if (pioRecvPci)
2725 {
2726 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2727 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2728 }
2729 else
2730 {
2731 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2732 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2733 }
2734
2735 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2736 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2737
2738 if (rv != SCARD_S_SUCCESS)
2739 goto end;
2740
2741 /* write the sent buffer */
2742 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2743 currentContextMap->dwClientID);
2744
2745 if (rv != SCARD_S_SUCCESS)
2746 goto end;
2747
2748 /*
2749 * Read a message from the server
2750 */
2751 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2752 currentContextMap->dwClientID);
2753
2754 if (rv != SCARD_S_SUCCESS)
2755 goto end;
2756
2757 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2758 {
2759 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2760 {
2761 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2763 goto end;
2764 }
2765
2766 /* read the received buffer */
2767 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2768 currentContextMap->dwClientID);
2769
2770 if (rv != SCARD_S_SUCCESS)
2771 goto end;
2772
2773 if (pioRecvPci)
2774 {
2775 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2776 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2777 }
2778 }
2779
2780 rv = scTransmitStruct.rv;
2781
2782 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2783 {
2784 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2785 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2786 goto retry;
2787 }
2788
2789 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2790
2791end:
2792 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2793
2794 PROFILE_END(rv)
2795
2796 return rv;
2797}
2798
2861LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2862 LPSTR mszReaders, LPDWORD pcchReaders)
2863{
2864 DWORD dwReadersLen = 0;
2865 int i;
2866 SCONTEXTMAP * currentContextMap;
2867 LONG rv = SCARD_S_SUCCESS;
2868 char *buf = NULL;
2869
2870 (void)mszGroups;
2871 PROFILE_START
2872 API_TRACE_IN("%ld", hContext)
2873
2874 /*
2875 * Check for NULL parameters
2876 */
2877 if (pcchReaders == NULL)
2879
2880 /*
2881 * Make sure this context has been opened
2882 */
2883 currentContextMap = SCardGetAndLockContext(hContext);
2884 if (NULL == currentContextMap)
2885 {
2886 PROFILE_END(SCARD_E_INVALID_HANDLE)
2888 }
2889
2890 /* lock access to readerStates[] */
2891 (void)pthread_mutex_lock(&readerStatesMutex);
2892
2893 /* synchronize reader states with daemon */
2894 rv = getReaderStates(currentContextMap);
2895 if (rv != SCARD_S_SUCCESS)
2896 goto end;
2897
2898 dwReadersLen = 0;
2899 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2900 if (readerStates[i].readerName[0] != '\0')
2901 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2902
2903 /* for the last NULL byte */
2904 dwReadersLen += 1;
2905
2906 if (1 == dwReadersLen)
2907 {
2909 goto end;
2910 }
2911
2912 if (SCARD_AUTOALLOCATE == *pcchReaders)
2913 {
2914 if (NULL == mszReaders)
2915 {
2917 goto end;
2918 }
2919 buf = malloc(dwReadersLen);
2920 if (NULL == buf)
2921 {
2922 rv = SCARD_E_NO_MEMORY;
2923 goto end;
2924 }
2925 *(char **)mszReaders = buf;
2926 }
2927 else
2928 {
2929 buf = mszReaders;
2930
2931 /* not enough place to store the reader names */
2932 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2933 {
2935 goto end;
2936 }
2937 }
2938
2939 if (mszReaders == NULL) /* text array not allocated */
2940 goto end;
2941
2942 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2943 {
2944 if (readerStates[i].readerName[0] != '\0')
2945 {
2946 /*
2947 * Build the multi-string
2948 */
2949 strcpy(buf, readerStates[i].readerName);
2950 buf += strlen(readerStates[i].readerName)+1;
2951 }
2952 }
2953 *buf = '\0'; /* Add the last null */
2954
2955end:
2956 /* set the reader names length */
2957 *pcchReaders = dwReadersLen;
2958
2959 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2960 (void)pthread_mutex_unlock(&readerStatesMutex);
2961
2962 PROFILE_END(rv)
2963 API_TRACE_OUT("%d", *pcchReaders)
2964
2965 return rv;
2966}
2967
2981LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2982{
2983 LONG rv = SCARD_S_SUCCESS;
2984
2985 PROFILE_START
2986
2987 /*
2988 * Make sure this context has been opened
2989 */
2990 if (! SCardGetContextValidity(hContext))
2992
2993 free((void *)pvMem);
2994
2995 PROFILE_END(rv)
2996
2997 return rv;
2998}
2999
3051LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3052 LPDWORD pcchGroups)
3053{
3054 LONG rv = SCARD_S_SUCCESS;
3055 SCONTEXTMAP * currentContextMap;
3056 char *buf = NULL;
3057
3058 PROFILE_START
3059
3060 /* Multi-string with two trailing \0 */
3061 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3062 const unsigned int dwGroups = sizeof(ReaderGroup);
3063
3064 /*
3065 * Make sure this context has been opened
3066 */
3067 currentContextMap = SCardGetAndLockContext(hContext);
3068 if (NULL == currentContextMap)
3070
3071 if (SCARD_AUTOALLOCATE == *pcchGroups)
3072 {
3073 if (NULL == mszGroups)
3074 {
3076 goto end;
3077 }
3078 buf = malloc(dwGroups);
3079 if (NULL == buf)
3080 {
3081 rv = SCARD_E_NO_MEMORY;
3082 goto end;
3083 }
3084 *(char **)mszGroups = buf;
3085 }
3086 else
3087 {
3088 buf = mszGroups;
3089
3090 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3091 {
3093 goto end;
3094 }
3095 }
3096
3097 if (buf)
3098 memcpy(buf, ReaderGroup, dwGroups);
3099
3100end:
3101 *pcchGroups = dwGroups;
3102
3103 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3104
3105 PROFILE_END(rv)
3106
3107 return rv;
3108}
3109
3142{
3143 SCONTEXTMAP * currentContextMap;
3144 LONG rv = SCARD_S_SUCCESS;
3145 uint32_t dwClientID = 0;
3146 struct cancel_struct scCancelStruct;
3147 bool cancellable;
3148
3149 PROFILE_START
3150 API_TRACE_IN("%ld", hContext)
3151
3152 /*
3153 * Make sure this context has been opened
3154 */
3155 (void)SCardLockThread();
3156 currentContextMap = SCardGetContextTH(hContext);
3157
3158 if (NULL == currentContextMap)
3159 {
3160 (void)SCardUnlockThread();
3162 goto error;
3163 }
3164 cancellable = currentContextMap->cancellable;
3165 (void)SCardUnlockThread();
3166
3167 if (! cancellable)
3168 {
3169 rv = SCARD_S_SUCCESS;
3170 goto error;
3171 }
3172
3173 /* create a new connection to the server */
3174 if (ClientSetupSession(&dwClientID) != 0)
3175 {
3176 rv = SCARD_E_NO_SERVICE;
3177 goto error;
3178 }
3179
3180 scCancelStruct.hContext = hContext;
3181 scCancelStruct.rv = SCARD_S_SUCCESS;
3182
3183 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3184 sizeof(scCancelStruct), (void *) &scCancelStruct);
3185
3186 if (rv != SCARD_S_SUCCESS)
3187 goto end;
3188
3189 /*
3190 * Read a message from the server
3191 */
3192 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3193
3194 if (rv != SCARD_S_SUCCESS)
3195 goto end;
3196
3197 rv = scCancelStruct.rv;
3198end:
3199 ClientCloseSession(dwClientID);
3200
3201error:
3202 PROFILE_END(rv)
3203 API_TRACE_OUT("")
3204
3205 return rv;
3206}
3207
3232{
3233 LONG rv;
3234
3235 PROFILE_START
3236 API_TRACE_IN("%ld", hContext)
3237
3238 rv = SCARD_S_SUCCESS;
3239
3240 /*
3241 * Make sure this context has been opened
3242 */
3243 if (! SCardGetContextValidity(hContext))
3245
3246 PROFILE_END(rv)
3247 API_TRACE_OUT("")
3248
3249 return rv;
3250}
3251
3268static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3269{
3270 int lrv;
3271 SCONTEXTMAP * newContextMap;
3272
3273 newContextMap = malloc(sizeof(SCONTEXTMAP));
3274 if (NULL == newContextMap)
3275 return SCARD_E_NO_MEMORY;
3276
3277 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3278 newContextMap->hContext = hContext;
3279 newContextMap->dwClientID = dwClientID;
3280 newContextMap->cancellable = false;
3281
3282 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3283
3284 lrv = list_init(&newContextMap->channelMapList);
3285 if (lrv < 0)
3286 {
3287 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3288 goto error;
3289 }
3290
3291 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3292 CHANNEL_MAP_seeker);
3293 if (lrv <0)
3294 {
3295 Log2(PCSC_LOG_CRITICAL,
3296 "list_attributes_seeker failed with return value: %d", lrv);
3297 list_destroy(&newContextMap->channelMapList);
3298 goto error;
3299 }
3300
3301 lrv = list_append(&contextMapList, newContextMap);
3302 if (lrv < 0)
3303 {
3304 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3305 lrv);
3306 list_destroy(&newContextMap->channelMapList);
3307 goto error;
3308 }
3309
3310 return SCARD_S_SUCCESS;
3311
3312error:
3313
3314 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3315 free(newContextMap);
3316
3317 return SCARD_E_NO_MEMORY;
3318}
3319
3337{
3338 SCONTEXTMAP * currentContextMap;
3339
3341 currentContextMap = SCardGetContextTH(hContext);
3342
3343 /* lock the context (if available) */
3344 if (NULL != currentContextMap)
3345 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3346
3348
3349 return currentContextMap;
3350}
3351
3365{
3366 return list_seek(&contextMapList, &hContext);
3367}
3368
3376{
3377 SCONTEXTMAP * currentContextMap;
3378 currentContextMap = SCardGetContextTH(hContext);
3379
3380 if (NULL != currentContextMap)
3381 SCardCleanContext(currentContextMap);
3382}
3383
3384static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3385{
3386 int list_index, lrv;
3387 int listSize;
3388 CHANNEL_MAP * currentChannelMap;
3389
3390 targetContextMap->hContext = 0;
3391 ClientCloseSession(targetContextMap->dwClientID);
3392 targetContextMap->dwClientID = 0;
3393 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3394
3395 listSize = list_size(&targetContextMap->channelMapList);
3396 for (list_index = 0; list_index < listSize; list_index++)
3397 {
3398 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3399 list_index);
3400 if (NULL == currentChannelMap)
3401 {
3402 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3403 list_index);
3404 continue;
3405 }
3406 else
3407 {
3408 free(currentChannelMap->readerName);
3409 free(currentChannelMap);
3410 }
3411
3412 }
3413 list_destroy(&targetContextMap->channelMapList);
3414
3415 lrv = list_delete(&contextMapList, targetContextMap);
3416 if (lrv < 0)
3417 {
3418 Log2(PCSC_LOG_CRITICAL,
3419 "list_delete failed with return value: %d", lrv);
3420 }
3421
3422 free(targetContextMap);
3423
3424 return;
3425}
3426
3427/*
3428 * Functions for managing hCard values returned from SCardConnect.
3429 */
3430
3431static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3432 LPCSTR readerName)
3433{
3434 CHANNEL_MAP * newChannelMap;
3435 int lrv = -1;
3436
3437 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3438 if (NULL == newChannelMap)
3439 return SCARD_E_NO_MEMORY;
3440
3441 newChannelMap->hCard = hCard;
3442 newChannelMap->readerName = strdup(readerName);
3443
3444 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3445 if (lrv < 0)
3446 {
3447 free(newChannelMap->readerName);
3448 free(newChannelMap);
3449 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3450 lrv);
3451 return SCARD_E_NO_MEMORY;
3452 }
3453
3454 return SCARD_S_SUCCESS;
3455}
3456
3457static void SCardRemoveHandle(SCARDHANDLE hCard)
3458{
3459 SCONTEXTMAP * currentContextMap;
3460 CHANNEL_MAP * currentChannelMap;
3461 int lrv;
3462 LONG rv;
3463
3464 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3465 &currentChannelMap);
3466 if (rv == -1)
3467 return;
3468
3469 free(currentChannelMap->readerName);
3470
3471 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3472 if (lrv < 0)
3473 {
3474 Log2(PCSC_LOG_CRITICAL,
3475 "list_delete failed with return value: %d", lrv);
3476 }
3477
3478 free(currentChannelMap);
3479
3480 return;
3481}
3482
3483static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3484 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3485{
3486 LONG rv;
3487
3488 if (0 == hCard)
3489 return -1;
3490
3492 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3493 targetChannelMap);
3494
3495 if (SCARD_S_SUCCESS == rv)
3496 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3497
3499
3500 return rv;
3501}
3502
3503static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3504 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3505{
3506 int listSize;
3507 int list_index;
3508 SCONTEXTMAP * currentContextMap;
3509 CHANNEL_MAP * currentChannelMap;
3510
3511 /* Best to get the caller a crash early if we fail unsafely */
3512 *targetContextMap = NULL;
3513 *targetChannelMap = NULL;
3514
3515 listSize = list_size(&contextMapList);
3516
3517 for (list_index = 0; list_index < listSize; list_index++)
3518 {
3519 currentContextMap = list_get_at(&contextMapList, list_index);
3520 if (currentContextMap == NULL)
3521 {
3522 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3523 list_index);
3524 continue;
3525 }
3526 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3527 &hCard);
3528 if (currentChannelMap != NULL)
3529 {
3530 *targetContextMap = currentContextMap;
3531 *targetChannelMap = currentChannelMap;
3532 return SCARD_S_SUCCESS;
3533 }
3534 }
3535
3536 return -1;
3537}
3538
3547{
3548 LONG rv;
3549 struct stat statBuffer;
3550 char *socketName;
3551
3552 socketName = getSocketName();
3553 rv = stat(socketName, &statBuffer);
3554
3555 if (rv != 0)
3556 {
3557 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3558 socketName, strerror(errno));
3559 return SCARD_E_NO_SERVICE;
3560 }
3561
3562 return SCARD_S_SUCCESS;
3563}
3564
3565static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3566{
3567 int32_t dwClientID = currentContextMap->dwClientID;
3568 LONG rv;
3569
3570 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3571 if (rv != SCARD_S_SUCCESS)
3572 return rv;
3573
3574 /* Read a message from the server */
3575 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3576 if (rv != SCARD_S_SUCCESS)
3577 return rv;
3578
3579 return SCARD_S_SUCCESS;
3580}
3581
3582static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3583{
3584 int32_t dwClientID = currentContextMap->dwClientID;
3585 LONG rv;
3586
3587 /* Get current reader states from server and register on event list */
3589 0, NULL);
3590 if (rv != SCARD_S_SUCCESS)
3591 return rv;
3592
3593 /* Read a message from the server */
3594 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3595 return rv;
3596}
3597
3598static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3599{
3600 int32_t dwClientID = currentContextMap->dwClientID;
3601 LONG rv;
3602 struct wait_reader_state_change waitStatusStruct = {0};
3603
3604 /* ask server to remove us from the event list */
3606 dwClientID, 0, NULL);
3607 if (rv != SCARD_S_SUCCESS)
3608 return rv;
3609
3610 /* This message can be the response to
3611 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3612 * cancel notification.
3613 * The server side ensures, that no more messages will be sent to
3614 * the client. */
3615
3616 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3617 dwClientID);
3618 if (rv != SCARD_S_SUCCESS)
3619 return rv;
3620
3621 /* if we received a cancel event the return value will be set
3622 * accordingly */
3623 rv = waitStatusStruct.rv;
3624
3625 return rv;
3626}
3627
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.
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
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
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#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:202
#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
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition pcsclite.h:267
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:261
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:260
#define SCARD_STATE_INUSE
Shared Mode.
Definition pcsclite.h:275
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:234
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition pcsclite.h:270
#define SCARD_STATE_PRESENT
Card inserted.
Definition pcsclite.h:272
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:259
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:258
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:269
#define INFINITE
Infinite timeout.
Definition pcsclite.h:280
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:271
#define SCARD_STATE_MUTE
Unresponsive card.
Definition pcsclite.h:276
#define SCARD_STATE_CHANGED
State has changed.
Definition pcsclite.h:268
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition pcsclite.h:247
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:298
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition pcsclite.h:299
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition pcsclite.h:274
#define SCARD_STATE_UNAWARE
App wants status.
Definition pcsclite.h:266
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:285
This keeps track of a list of currently available reader structures.
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
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...
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
uint32_t eventCounter
number of card events
_Atomic uint32_t cardAtrLength
ATR length.
uint32_t readerState
SCARD_* bit field.
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.
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168
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 bool 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.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
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()