pcsc-lite 2.3.0
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 fprintf(stderr,
255 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
256 COLOR_BLUE "0x%08lX" COLOR_NORMAL "\n",
257 f, d, rv);
258 }
259 fprintf(profile_fd, "%s %ld\n", f, d);
260 fflush(profile_fd);
261} /* profile_end */
262
263#else
264#define PROFILE_START
265#define PROFILE_END(rv)
266#endif
267
273{
274 SCARDHANDLE hCard;
275 LPSTR readerName;
276};
277
278typedef struct _psChannelMap CHANNEL_MAP;
279
280static int CHANNEL_MAP_seeker(const void *el, const void *key)
281{
282 const CHANNEL_MAP * channelMap = el;
283
284 if ((el == NULL) || (key == NULL))
285 {
286 Log3(PCSC_LOG_CRITICAL,
287 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
288 el, key);
289 return 0;
290 }
291
292 if (channelMap->hCard == *(SCARDHANDLE *)key)
293 return 1;
294
295 return 0;
296}
297
304{
307 pthread_mutex_t mMutex;
308 list_t channelMapList;
310};
317
318static list_t contextMapList;
319
320static int SCONTEXTMAP_seeker(const void *el, const void *key)
321{
322 const SCONTEXTMAP * contextMap = el;
323
324 if ((el == NULL) || (key == NULL))
325 {
326 Log3(PCSC_LOG_CRITICAL,
327 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
328 el, key);
329 return 0;
330 }
331
332 if (contextMap->hContext == *(SCARDCONTEXT *) key)
333 return 1;
334
335 return 0;
336}
337
341static bool isExecuted = false;
342static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
343
344
349static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
350
355static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
356
357
358static LONG SCardAddContext(SCARDCONTEXT, DWORD);
362static void SCardCleanContext(SCONTEXTMAP *);
363
364static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
365static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
366 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
367static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
368 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
369static void SCardRemoveHandle(SCARDHANDLE);
370
371static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
372 LPBYTE pbAttr, LPDWORD pcbAttrLen);
373
374static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents);
375static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
376static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
377static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
378
379/*
380 * Thread safety functions
381 */
388inline static void SCardLockThread(void)
389{
390 pthread_mutex_lock(&clientMutex);
391}
392
398inline static void SCardUnlockThread(void)
399{
400 pthread_mutex_unlock(&clientMutex);
401}
402
413{
414 SCONTEXTMAP * currentContextMap;
415
417 currentContextMap = SCardGetContextTH(hContext);
419
420 return currentContextMap != NULL;
421}
422
423static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
424 /*@out@*/ LPSCARDCONTEXT);
425
461LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
462 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
463{
464 LONG rv;
465
466 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
467 PROFILE_START
468
469 /* Check if the server is running */
471 if (rv != SCARD_S_SUCCESS)
472 goto end;
473
475 rv = SCardEstablishContextTH(dwScope, pvReserved1,
476 pvReserved2, phContext);
478
479end:
480 PROFILE_END(rv)
481 API_TRACE_OUT("%ld", *phContext)
482
483 return rv;
484}
485
486#ifdef DESTRUCTOR
487DESTRUCTOR static void destructor(void)
488{
489 list_destroy(&contextMapList);
490}
491#endif
492
493/*
494 * Do this only once:
495 * - Initialize context list.
496 */
497static void init_lib(void)
498{
499 int lrv;
500
501 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
502 * Applications which load and unload the library may leak
503 * the list's internal structures. */
504 lrv = list_init(&contextMapList);
505 if (lrv < 0)
506 {
507 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
508 lrv);
509 return;
510 }
511
512 lrv = list_attributes_seeker(&contextMapList,
513 SCONTEXTMAP_seeker);
514 if (lrv <0)
515 {
516 Log2(PCSC_LOG_CRITICAL,
517 "list_attributes_seeker failed with return value: %d", lrv);
518 list_destroy(&contextMapList);
519 return;
520 }
521
522 if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
523 {
524 Log1(PCSC_LOG_INFO, "Disable shared blocking");
525 sharing_shall_block = false;
526 }
527
528 isExecuted = true;
529}
530
558static LONG SCardEstablishContextTH(DWORD dwScope,
559 /*@unused@*/ LPCVOID pvReserved1,
560 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
561{
562 LONG rv;
563 struct establish_struct scEstablishStruct;
564 uint32_t dwClientID = 0;
565
566 (void)pvReserved1;
567 (void)pvReserved2;
568 if (phContext == NULL)
570 else
571 *phContext = 0;
572
573 pthread_once(&init_lib_control, init_lib);
574 if (!isExecuted)
575 return SCARD_E_NO_MEMORY;
576
577 /* Establishes a connection to the server */
578 if (ClientSetupSession(&dwClientID) != 0)
579 {
580 return SCARD_E_NO_SERVICE;
581 }
582
583 { /* exchange client/server protocol versions */
584 struct version_struct veStr;
585
588 veStr.rv = SCARD_S_SUCCESS;
589
590 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
591 &veStr);
592 if (rv != SCARD_S_SUCCESS)
593 goto cleanup;
594
595 /* Read a message from the server */
596 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
597 if (rv != SCARD_S_SUCCESS)
598 {
599 Log1(PCSC_LOG_CRITICAL,
600 "Your pcscd is too old and does not support CMD_VERSION");
601 goto cleanup;
602 }
603
604 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
605 veStr.major, veStr.minor);
606
607 if (veStr.rv != SCARD_S_SUCCESS)
608 {
609 rv = veStr.rv;
610 goto cleanup;
611 }
612 }
613
614again:
615 /*
616 * Try to establish an Application Context with the server
617 */
618 scEstablishStruct.dwScope = dwScope;
619 scEstablishStruct.hContext = 0;
620 scEstablishStruct.rv = SCARD_S_SUCCESS;
621
623 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
624
625 if (rv != SCARD_S_SUCCESS)
626 goto cleanup;
627
628 /*
629 * Read the response from the server
630 */
631 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
632 dwClientID);
633
634 if (rv != SCARD_S_SUCCESS)
635 goto cleanup;
636
637 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
638 {
639 rv = scEstablishStruct.rv;
640 goto cleanup;
641 }
642
643 /* check we do not reuse an existing hContext */
644 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
645 /* we do not need to release the allocated context since
646 * SCardReleaseContext() does nothing on the server side */
647 goto again;
648
649 *phContext = scEstablishStruct.hContext;
650
651 /*
652 * Allocate the new hContext - if allocator full return an error
653 */
654 rv = SCardAddContext(*phContext, dwClientID);
655
656 return rv;
657
658cleanup:
659 ClientCloseSession(dwClientID);
660
661 return rv;
662}
663
686{
687 LONG rv;
688 struct release_struct scReleaseStruct;
689 SCONTEXTMAP * currentContextMap;
690
691 API_TRACE_IN("%ld", hContext)
692 PROFILE_START
693
694 /*
695 * Make sure this context has been opened
696 * and get currentContextMap
697 */
698 currentContextMap = SCardGetAndLockContext(hContext);
699 if (NULL == currentContextMap)
700 {
702 goto error;
703 }
704
705 scReleaseStruct.hContext = hContext;
706 scReleaseStruct.rv = SCARD_S_SUCCESS;
707
709 currentContextMap->dwClientID,
710 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
711
712 if (rv != SCARD_S_SUCCESS)
713 goto end;
714
715 /*
716 * Read a message from the server
717 */
718 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
719 currentContextMap->dwClientID);
720
721 if (rv != SCARD_S_SUCCESS)
722 goto end;
723
724 rv = scReleaseStruct.rv;
725end:
726 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
727
728 /*
729 * Remove the local context from the stack
730 */
732 SCardRemoveContext(hContext);
734
735error:
736 PROFILE_END(rv)
737 API_TRACE_OUT("")
738
739 return rv;
740}
741
797LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
798 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
799 LPDWORD pdwActiveProtocol)
800{
801 LONG rv;
802 struct connect_struct scConnectStruct;
803 SCONTEXTMAP * currentContextMap;
804
805 PROFILE_START
806 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
807
808 /*
809 * Check for NULL parameters
810 */
811 if (phCard == NULL || pdwActiveProtocol == NULL)
813 else
814 *phCard = 0;
815
816 if (szReader == NULL)
818
819 /*
820 * Check for uninitialized strings
821 */
822 if (strlen(szReader) > MAX_READERNAME)
824
825 /*
826 * Make sure this context has been opened
827 */
828 currentContextMap = SCardGetAndLockContext(hContext);
829 if (NULL == currentContextMap)
831
832 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
833 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
834 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
835
836 scConnectStruct.hContext = hContext;
837 scConnectStruct.dwShareMode = dwShareMode;
838 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
839 scConnectStruct.hCard = 0;
840 scConnectStruct.dwActiveProtocol = 0;
841 scConnectStruct.rv = SCARD_S_SUCCESS;
842
843 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
844 sizeof(scConnectStruct), (void *) &scConnectStruct);
845
846 if (rv != SCARD_S_SUCCESS)
847 goto end;
848
849 /*
850 * Read a message from the server
851 */
852 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
853 currentContextMap->dwClientID);
854
855 if (rv != SCARD_S_SUCCESS)
856 goto end;
857
858 *phCard = scConnectStruct.hCard;
859 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
860
861 if (scConnectStruct.rv == SCARD_S_SUCCESS)
862 {
863 /*
864 * Keep track of the handle locally
865 */
866 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
867 }
868 else
869 rv = scConnectStruct.rv;
870
871end:
872 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
873
874 PROFILE_END(rv)
875 API_TRACE_OUT("%d", *pdwActiveProtocol)
876
877 return rv;
878}
879
952LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
953 DWORD dwPreferredProtocols, DWORD dwInitialization,
954 LPDWORD pdwActiveProtocol)
955{
956 LONG rv;
957 struct reconnect_struct scReconnectStruct;
958 SCONTEXTMAP * currentContextMap;
959 CHANNEL_MAP * pChannelMap;
960
961 PROFILE_START
962 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
963
964 if (pdwActiveProtocol == NULL)
966
967 /* Retry loop for blocking behaviour */
968retry:
969
970 /*
971 * Make sure this handle has been opened
972 */
973 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
974 &pChannelMap);
975 if (rv == -1)
977
978 scReconnectStruct.hCard = hCard;
979 scReconnectStruct.dwShareMode = dwShareMode;
980 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
981 scReconnectStruct.dwInitialization = dwInitialization;
982 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
983 scReconnectStruct.rv = SCARD_S_SUCCESS;
984
985 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
986 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
987
988 if (rv != SCARD_S_SUCCESS)
989 goto end;
990
991 /*
992 * Read a message from the server
993 */
994 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
995 currentContextMap->dwClientID);
996
997 if (rv != SCARD_S_SUCCESS)
998 goto end;
999
1000 rv = scReconnectStruct.rv;
1001
1002 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1003 {
1004 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1005 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1006 goto retry;
1007 }
1008
1009 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1010
1011end:
1012 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1013
1014 PROFILE_END(rv)
1015 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1016
1017 return rv;
1018}
1019
1051LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1052{
1053 LONG rv;
1054 struct disconnect_struct scDisconnectStruct;
1055 SCONTEXTMAP * currentContextMap;
1056 CHANNEL_MAP * pChannelMap;
1057
1058 PROFILE_START
1059 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1060
1061 /*
1062 * Make sure this handle has been opened
1063 */
1064 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1065 &pChannelMap);
1066 if (rv == -1)
1067 {
1069 goto error;
1070 }
1071
1072 scDisconnectStruct.hCard = hCard;
1073 scDisconnectStruct.dwDisposition = dwDisposition;
1074 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1075
1076 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1077 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1078
1079 if (rv != SCARD_S_SUCCESS)
1080 goto end;
1081
1082 /*
1083 * Read a message from the server
1084 */
1085 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1086 currentContextMap->dwClientID);
1087
1088 if (rv != SCARD_S_SUCCESS)
1089 goto end;
1090
1091 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1092 SCardRemoveHandle(hCard);
1093 rv = scDisconnectStruct.rv;
1094
1095end:
1096 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1097
1098error:
1099 PROFILE_END(rv)
1100 API_TRACE_OUT("")
1101
1102 return rv;
1103}
1104
1142{
1143
1144 LONG rv;
1145 struct begin_struct scBeginStruct;
1146 SCONTEXTMAP * currentContextMap;
1147 CHANNEL_MAP * pChannelMap;
1148
1149 PROFILE_START
1150 API_TRACE_IN("%ld", hCard)
1151
1152 /*
1153 * Query the server every so often until the sharing violation ends
1154 * and then hold the lock for yourself.
1155 */
1156
1157 for(;;)
1158 {
1159 /*
1160 * Make sure this handle has been opened
1161 */
1162 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1163 &pChannelMap);
1164 if (rv == -1)
1166
1167 scBeginStruct.hCard = hCard;
1168 scBeginStruct.rv = SCARD_S_SUCCESS;
1169
1171 currentContextMap->dwClientID,
1172 sizeof(scBeginStruct), (void *) &scBeginStruct);
1173
1174 if (rv != SCARD_S_SUCCESS)
1175 break;
1176
1177 /*
1178 * Read a message from the server
1179 */
1180 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1181 currentContextMap->dwClientID);
1182
1183 if (rv != SCARD_S_SUCCESS)
1184 break;
1185
1186 rv = scBeginStruct.rv;
1187
1188 if (SCARD_E_SHARING_VIOLATION != rv)
1189 break;
1190
1191 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1192 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1193 }
1194
1195 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1196
1197 PROFILE_END(rv)
1198 API_TRACE_OUT("")
1199
1200 return rv;
1201}
1202
1242LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1243{
1244 LONG rv;
1245 struct end_struct scEndStruct;
1246 SCONTEXTMAP * currentContextMap;
1247 CHANNEL_MAP * pChannelMap;
1248
1249 PROFILE_START
1250 API_TRACE_IN("%ld", hCard)
1251
1252 /*
1253 * Make sure this handle has been opened
1254 */
1255 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1256 &pChannelMap);
1257 if (rv == -1)
1259
1260 scEndStruct.hCard = hCard;
1261 scEndStruct.dwDisposition = dwDisposition;
1262 scEndStruct.rv = SCARD_S_SUCCESS;
1263
1265 currentContextMap->dwClientID,
1266 sizeof(scEndStruct), (void *) &scEndStruct);
1267
1268 if (rv != SCARD_S_SUCCESS)
1269 goto end;
1270
1271 /*
1272 * Read a message from the server
1273 */
1274 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1275 currentContextMap->dwClientID);
1276
1277 if (rv != SCARD_S_SUCCESS)
1278 goto end;
1279
1280 rv = scEndStruct.rv;
1281
1282end:
1283 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1284
1285 PROFILE_END(rv)
1286 API_TRACE_OUT("")
1287
1288 return rv;
1289}
1290
1386LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1387 LPDWORD pcchReaderLen, LPDWORD pdwState,
1388 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1389{
1390 DWORD dwReaderLen, dwAtrLen;
1391 LONG rv;
1392 int i;
1393 struct status_struct scStatusStruct;
1394 SCONTEXTMAP * currentContextMap;
1395 CHANNEL_MAP * pChannelMap;
1396 char *r;
1397 char *bufReader = NULL;
1398 LPBYTE bufAtr = NULL;
1399 DWORD dummy = 0;
1400
1401 PROFILE_START
1402
1403 /* default output values */
1404 if (pdwState)
1405 *pdwState = 0;
1406
1407 if (pdwProtocol)
1408 *pdwProtocol = 0;
1409
1410 /* Check for NULL parameters */
1411 if (pcchReaderLen == NULL)
1412 pcchReaderLen = &dummy;
1413
1414 if (pcbAtrLen == NULL)
1415 pcbAtrLen = &dummy;
1416
1417 /* length passed from caller */
1418 dwReaderLen = *pcchReaderLen;
1419 dwAtrLen = *pcbAtrLen;
1420
1421 *pcchReaderLen = 0;
1422 *pcbAtrLen = 0;
1423
1424 /* Retry loop for blocking behaviour */
1425retry:
1426
1427 /*
1428 * Make sure this handle has been opened
1429 */
1430 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1431 &pChannelMap);
1432 if (rv == -1)
1434
1435 /* lock access to readerStates[] */
1436 (void)pthread_mutex_lock(&readerStatesMutex);
1437
1438 /* synchronize reader states with daemon */
1439 rv = getReaderStates(currentContextMap);
1440 if (rv != SCARD_S_SUCCESS)
1441 goto end;
1442
1443 r = pChannelMap->readerName;
1444 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1445 {
1446 /* by default r == NULL */
1447 if (r && strcmp(r, readerStates[i].readerName) == 0)
1448 break;
1449 }
1450
1452 {
1454 goto end;
1455 }
1456
1457 /* initialise the structure */
1458 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1459 scStatusStruct.hCard = hCard;
1460
1461 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1462 sizeof(scStatusStruct), (void *) &scStatusStruct);
1463
1464 if (rv != SCARD_S_SUCCESS)
1465 goto end;
1466
1467 /*
1468 * Read a message from the server
1469 */
1470 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1471 currentContextMap->dwClientID);
1472
1473 if (rv != SCARD_S_SUCCESS)
1474 goto end;
1475
1476 rv = scStatusStruct.rv;
1477
1478 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1479 {
1480 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1481 (void)pthread_mutex_unlock(&readerStatesMutex);
1482 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1483 goto retry;
1484 }
1485
1487 {
1488 /*
1489 * An event must have occurred
1490 */
1491 goto end;
1492 }
1493
1494 /*
1495 * Now continue with the client side SCardStatus
1496 */
1497
1498 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1499 *pcbAtrLen = readerStates[i].cardAtrLength;
1500
1501 if (pdwState)
1502 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1503
1504 if (pdwProtocol)
1505 *pdwProtocol = readerStates[i].cardProtocol;
1506
1507 if (SCARD_AUTOALLOCATE == dwReaderLen)
1508 {
1509 dwReaderLen = *pcchReaderLen;
1510 if (NULL == szReaderName)
1511 {
1513 goto end;
1514 }
1515 bufReader = malloc(dwReaderLen);
1516 if (NULL == bufReader)
1517 {
1518 rv = SCARD_E_NO_MEMORY;
1519 goto end;
1520 }
1521 *(char **)szReaderName = bufReader;
1522 }
1523 else
1524 bufReader = szReaderName;
1525
1526 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1527 if (bufReader)
1528 {
1529 if (*pcchReaderLen > dwReaderLen)
1531
1532 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1533 }
1534
1535 if (SCARD_AUTOALLOCATE == dwAtrLen)
1536 {
1537 dwAtrLen = *pcbAtrLen;
1538 if (NULL == pbAtr)
1539 {
1541 goto end;
1542 }
1543 bufAtr = malloc(dwAtrLen);
1544 if (NULL == bufAtr)
1545 {
1546 rv = SCARD_E_NO_MEMORY;
1547 goto end;
1548 }
1549 *(LPBYTE *)pbAtr = bufAtr;
1550 }
1551 else
1552 bufAtr = pbAtr;
1553
1554 if (bufAtr)
1555 {
1556 if (*pcbAtrLen > dwAtrLen)
1558
1559 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1560 }
1561
1562end:
1563 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1564 (void)pthread_mutex_unlock(&readerStatesMutex);
1565
1566 PROFILE_END(rv)
1567
1568 return rv;
1569}
1570
1682LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1683 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1684{
1685 SCARD_READERSTATE *currReader;
1686 READER_STATE *rContext;
1687 long dwTime;
1688 DWORD dwBreakFlag = 0;
1689 unsigned int j;
1690 SCONTEXTMAP * currentContextMap;
1691 int currentReaderCount = 0;
1692 LONG rv = SCARD_S_SUCCESS;
1693 int pnp_reader = -1;
1694
1695 PROFILE_START
1696 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1697#ifdef DO_TRACE
1698 for (j=0; j<cReaders; j++)
1699 {
1700 API_TRACE_IN("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1701 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1702 rgReaderStates[j].cbAtr)
1703 }
1704#endif
1705
1706 if ((rgReaderStates == NULL && cReaders > 0)
1707 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1708 {
1710 goto error;
1711 }
1712
1713 /* Check the integrity of the reader states structures */
1714 for (j = 0; j < cReaders; j++)
1715 {
1716 if (rgReaderStates[j].szReader == NULL)
1717 return SCARD_E_INVALID_VALUE;
1718 }
1719
1720 /* return if all readers are SCARD_STATE_IGNORE */
1721 if (cReaders > 0)
1722 {
1723 int nbNonIgnoredReaders = cReaders;
1724
1725 for (j=0; j<cReaders; j++)
1726 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1727 nbNonIgnoredReaders--;
1728
1729 if (0 == nbNonIgnoredReaders)
1730 {
1731 rv = SCARD_S_SUCCESS;
1732 goto error;
1733 }
1734 }
1735 else
1736 {
1737 /* reader list is empty */
1738 rv = SCARD_S_SUCCESS;
1739 goto error;
1740 }
1741
1742 /*
1743 * Make sure this context has been opened
1744 */
1745 currentContextMap = SCardGetAndLockContext(hContext);
1746 if (NULL == currentContextMap)
1747 {
1749 goto error;
1750 }
1751
1752 /* lock access to readerStates[] */
1753 (void)pthread_mutex_lock(&readerStatesMutex);
1754
1755 /* synchronize reader states with daemon */
1756 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1757
1758 if (rv != SCARD_S_SUCCESS)
1759 {
1760 (void)pthread_mutex_unlock(&readerStatesMutex);
1761 goto end;
1762 }
1763
1764 /* check all the readers are already known */
1765 for (j=0; j<cReaders; j++)
1766 {
1767 const char *readerName;
1768 int i;
1769
1770 readerName = rgReaderStates[j].szReader;
1771 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1772 {
1773 if (strcmp(readerName, readerStates[i].readerName) == 0)
1774 break;
1775 }
1776
1777 /* The requested reader name is not recognized */
1779 {
1780 /* PnP special reader? */
1781 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1782 {
1784 (void)pthread_mutex_unlock(&readerStatesMutex);
1785 goto end;
1786 }
1787 else
1788 pnp_reader = j;
1789 }
1790 }
1791 (void)pthread_mutex_unlock(&readerStatesMutex);
1792
1793 /* Clear the event state for all readers */
1794 for (j = 0; j < cReaders; j++)
1795 rgReaderStates[j].dwEventState = 0;
1796
1797 /* Now is where we start our event checking loop */
1798 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1799
1800 /* index of the PnP readerin rgReaderStates[] */
1801 if (pnp_reader >= 0)
1802 {
1803 int readerEvents;
1804 currReader = &rgReaderStates[pnp_reader];
1805
1806 /* PnP special reader */
1807 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1808 {
1809 int previousReaderEvents = currReader->dwCurrentState >> 16;
1810
1811 // store readerEvents in .dwEventState high word
1812 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1813 if (
1814 /* the value has changed since the last call */
1815 (previousReaderEvents != readerEvents)
1816 /* backward compatibility: only if we had a non-null
1817 * reader events value */
1818 && previousReaderEvents)
1819 {
1820 currReader->dwEventState |= SCARD_STATE_CHANGED;
1821 rv = SCARD_S_SUCCESS;
1822 dwBreakFlag = 1;
1823 }
1824 }
1825 }
1826
1827 /* Get the initial reader count on the system */
1828 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1829 if (readerStates[j].readerName[0] != '\0')
1830 currentReaderCount++;
1831
1832 /* catch possible sign extension problems from 32 to 64-bits integers */
1833 if ((DWORD)-1 == dwTimeout)
1834 dwTimeout = INFINITE;
1835 if (INFINITE == dwTimeout)
1836 dwTime = 60*1000; /* "infinite" timeout */
1837 else
1838 dwTime = dwTimeout;
1839
1840 j = 0;
1841 do
1842 {
1843 currReader = &rgReaderStates[j];
1844
1845 /* Ignore for IGNORED readers */
1846 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1847 {
1848 const char *readerName;
1849 int i;
1850
1851 /* lock access to readerStates[] */
1852 (void)pthread_mutex_lock(&readerStatesMutex);
1853
1854 /* Looks for correct readernames */
1855 readerName = currReader->szReader;
1856 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1857 {
1858 if (strcmp(readerName, readerStates[i].readerName) == 0)
1859 break;
1860 }
1861
1862 /* The requested reader name is not recognized */
1864 {
1865 /* PnP special reader? */
1866 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1867 {
1868 int k, newReaderCount = 0;
1869
1870 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1871 if (readerStates[k].readerName[0] != '\0')
1872 newReaderCount++;
1873
1874 if (newReaderCount != currentReaderCount)
1875 {
1876 int readerEvents;
1877
1878 Log1(PCSC_LOG_INFO, "Reader list changed");
1879 currentReaderCount = newReaderCount;
1880
1881 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1882 {
1883 // store readerEvents in .dwEventState high word
1884 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1885 }
1886
1887 currReader->dwEventState |= SCARD_STATE_CHANGED;
1888 dwBreakFlag = 1;
1889 }
1890 }
1891 else
1892 {
1893 currReader->dwEventState =
1895 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1896 {
1897 currReader->dwEventState |= SCARD_STATE_CHANGED;
1898 /*
1899 * Spec says use SCARD_STATE_IGNORE but a removed USB
1900 * reader with eventState fed into currentState will
1901 * be ignored forever
1902 */
1903 dwBreakFlag = 1;
1904 }
1905 }
1906 }
1907 else
1908 {
1909 uint32_t readerState;
1910
1911 /* The reader has come back after being away */
1912 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1913 {
1914 currReader->dwEventState |= SCARD_STATE_CHANGED;
1915 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1916 Log0(PCSC_LOG_DEBUG);
1917 dwBreakFlag = 1;
1918 }
1919
1920 /* Set the reader status structure */
1921 rContext = &readerStates[i];
1922
1923 /* Now we check all the Reader States */
1924 readerState = rContext->readerState;
1925
1926 /* only if current state has an non null event counter */
1927 if (currReader->dwCurrentState & 0xFFFF0000)
1928 {
1929 unsigned int currentCounter;
1930
1931 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1932
1933 /* has the event counter changed since the last call? */
1934 if (rContext->eventCounter != currentCounter)
1935 {
1936 currReader->dwEventState |= SCARD_STATE_CHANGED;
1937 Log0(PCSC_LOG_DEBUG);
1938 dwBreakFlag = 1;
1939 }
1940 }
1941
1942 /* add an event counter in the upper word of dwEventState */
1943 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1944 | (rContext->eventCounter << 16));
1945
1946 /* Check if the reader is in the correct state */
1947 if (readerState & SCARD_UNKNOWN)
1948 {
1949 /* reader is in bad state */
1950 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1951 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1952 {
1953 /* App thinks reader is in good state and it is not */
1954 currReader->dwEventState |= SCARD_STATE_CHANGED;
1955 Log0(PCSC_LOG_DEBUG);
1956 dwBreakFlag = 1;
1957 }
1958 }
1959 else
1960 {
1961 /* App thinks reader in bad state but it is not */
1962 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1963 {
1964 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1965 currReader->dwEventState |= SCARD_STATE_CHANGED;
1966 Log0(PCSC_LOG_DEBUG);
1967 dwBreakFlag = 1;
1968 }
1969 }
1970
1971 /* Check for card presence in the reader */
1972 if (readerState & SCARD_PRESENT)
1973 {
1974#ifndef DISABLE_AUTO_POWER_ON
1975 /* card present but not yet powered up */
1976 if (0 == rContext->cardAtrLength)
1977 /* Allow the status thread to convey information */
1978 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1979#endif
1980
1981 currReader->cbAtr = rContext->cardAtrLength;
1982 memcpy(currReader->rgbAtr, rContext->cardAtr,
1983 currReader->cbAtr);
1984 }
1985 else
1986 currReader->cbAtr = 0;
1987
1988 /* Card is now absent */
1989 if (readerState & SCARD_ABSENT)
1990 {
1991 currReader->dwEventState |= SCARD_STATE_EMPTY;
1992 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1993 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1994 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1995 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1996 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1997 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1998 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1999 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2000
2001 /* After present the rest are assumed */
2002 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2003 {
2004 currReader->dwEventState |= SCARD_STATE_CHANGED;
2005 Log0(PCSC_LOG_DEBUG);
2006 dwBreakFlag = 1;
2007 }
2008 }
2009 /* Card is now present */
2010 else if (readerState & SCARD_PRESENT)
2011 {
2012 currReader->dwEventState |= SCARD_STATE_PRESENT;
2013 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2014 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2015 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2016 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2017 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2018 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2019
2020 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2021 {
2022 currReader->dwEventState |= SCARD_STATE_CHANGED;
2023 Log0(PCSC_LOG_DEBUG);
2024 dwBreakFlag = 1;
2025 }
2026
2027 if (readerState & SCARD_SWALLOWED)
2028 {
2029 currReader->dwEventState |= SCARD_STATE_MUTE;
2030 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2031 {
2032 currReader->dwEventState |= SCARD_STATE_CHANGED;
2033 Log0(PCSC_LOG_DEBUG);
2034 dwBreakFlag = 1;
2035 }
2036 }
2037 else
2038 {
2039 /* App thinks card is mute but it is not */
2040 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2041 {
2042 currReader->dwEventState |= SCARD_STATE_CHANGED;
2043 Log0(PCSC_LOG_DEBUG);
2044 dwBreakFlag = 1;
2045 }
2046 }
2047 }
2048
2049 /* Now figure out sharing modes */
2051 {
2052 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2053 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2054 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2055 {
2056 currReader->dwEventState |= SCARD_STATE_CHANGED;
2057 Log0(PCSC_LOG_DEBUG);
2058 dwBreakFlag = 1;
2059 }
2060 }
2061 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2062 {
2063 /* A card must be inserted for it to be INUSE */
2064 if (readerState & SCARD_PRESENT)
2065 {
2066 currReader->dwEventState |= SCARD_STATE_INUSE;
2067 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2068 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2069 {
2070 currReader->dwEventState |= SCARD_STATE_CHANGED;
2071 Log0(PCSC_LOG_DEBUG);
2072 dwBreakFlag = 1;
2073 }
2074 }
2075 }
2076 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2077 {
2078 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2079 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2080
2081 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2082 {
2083 currReader->dwEventState |= SCARD_STATE_CHANGED;
2084 Log0(PCSC_LOG_DEBUG);
2085 dwBreakFlag = 1;
2086 }
2087 else if (currReader-> dwCurrentState
2089 {
2090 currReader->dwEventState |= SCARD_STATE_CHANGED;
2091 Log0(PCSC_LOG_DEBUG);
2092 dwBreakFlag = 1;
2093 }
2094 }
2095
2096 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2097 {
2098 /*
2099 * Break out of the while .. loop and return status
2100 * once all the status's for all readers is met
2101 */
2102 currReader->dwEventState |= SCARD_STATE_CHANGED;
2103 Log0(PCSC_LOG_DEBUG);
2104 dwBreakFlag = 1;
2105 }
2106 } /* End of SCARD_STATE_UNKNOWN */
2107
2108 (void)pthread_mutex_unlock(&readerStatesMutex);
2109 } /* End of SCARD_STATE_IGNORE */
2110
2111 /* Counter and resetter */
2112 j++;
2113 if (j == cReaders)
2114 {
2115 /* go back to the first reader */
2116 j = 0;
2117
2118 /* Declare all the break conditions */
2119
2120 /* Break if UNAWARE is set and all readers have been checked */
2121 if (dwBreakFlag == 1)
2122 break;
2123
2124 /* Only sleep once for each cycle of reader checks. */
2125 {
2126 struct wait_reader_state_change waitStatusStruct = {0};
2127 struct timeval before, after;
2128
2129 gettimeofday(&before, NULL);
2130
2131 waitStatusStruct.rv = SCARD_S_SUCCESS;
2132
2133 /* another thread can do SCardCancel() */
2134 currentContextMap->cancellable = true;
2135
2136 /*
2137 * Read a message from the server
2138 */
2140 &waitStatusStruct, sizeof(waitStatusStruct),
2141 currentContextMap->dwClientID, dwTime);
2142
2143 /* SCardCancel() will return immediately with success
2144 * because something changed on the daemon side. */
2145 currentContextMap->cancellable = false;
2146
2147 /* timeout */
2148 if (SCARD_E_TIMEOUT == rv)
2149 {
2150 /* ask server to remove us from the event list */
2151 rv = unregisterFromEvents(currentContextMap);
2152 }
2153
2154 if (rv != SCARD_S_SUCCESS)
2155 goto end;
2156
2157 /* an event occurs or SCardCancel() was called */
2158 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2159 {
2160 rv = waitStatusStruct.rv;
2161 goto end;
2162 }
2163
2164 /* synchronize reader states with daemon */
2165 (void)pthread_mutex_lock(&readerStatesMutex);
2166 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2167 (void)pthread_mutex_unlock(&readerStatesMutex);
2168 if (rv != SCARD_S_SUCCESS)
2169 goto end;
2170
2171 if (INFINITE != dwTimeout)
2172 {
2173 long int diff;
2174
2175 gettimeofday(&after, NULL);
2176 diff = time_sub(&after, &before);
2177 dwTime -= diff/1000;
2178 }
2179 }
2180
2181 if (dwTimeout != INFINITE)
2182 {
2183 /* If time is greater than timeout and all readers have been
2184 * checked
2185 */
2186 if (dwTime <= 0)
2187 {
2188 rv = SCARD_E_TIMEOUT;
2189 goto end;
2190 }
2191 }
2192 }
2193 }
2194 while (1);
2195
2196end:
2197 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2198
2199 /* if SCardCancel() has been used then the client is already
2200 * unregistered */
2201 if (SCARD_E_CANCELLED != rv)
2202 (void)unregisterFromEvents(currentContextMap);
2203
2204 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2205
2206error:
2207 PROFILE_END(rv)
2208#ifdef DO_TRACE
2209 for (j=0; j<cReaders; j++)
2210 {
2211 API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2212 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2213 rgReaderStates[j].cbAtr)
2214 }
2215#endif
2216
2217 return rv;
2218}
2219
2270LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2271 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2272 LPDWORD lpBytesReturned)
2273{
2274 LONG rv;
2275 struct control_struct scControlStruct;
2276 SCONTEXTMAP * currentContextMap;
2277 CHANNEL_MAP * pChannelMap;
2278
2279 PROFILE_START
2280
2281 /* 0 bytes received by default */
2282 if (NULL != lpBytesReturned)
2283 *lpBytesReturned = 0;
2284
2285 /*
2286 * Make sure this handle has been opened
2287 */
2288 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2289 &pChannelMap);
2290 if (rv == -1)
2291 {
2292 PROFILE_END(SCARD_E_INVALID_HANDLE)
2294 }
2295
2296 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2297 {
2299 goto end;
2300 }
2301
2302 scControlStruct.hCard = hCard;
2303 scControlStruct.dwControlCode = dwControlCode;
2304 scControlStruct.cbSendLength = cbSendLength;
2305 scControlStruct.cbRecvLength = cbRecvLength;
2306 scControlStruct.dwBytesReturned = 0;
2307 scControlStruct.rv = 0;
2308
2309 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2310 sizeof(scControlStruct), &scControlStruct);
2311
2312 if (rv != SCARD_S_SUCCESS)
2313 goto end;
2314
2315 /* write the sent buffer */
2316 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2317 currentContextMap->dwClientID);
2318
2319 if (rv != SCARD_S_SUCCESS)
2320 goto end;
2321
2322 /*
2323 * Read a message from the server
2324 */
2325 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2326 currentContextMap->dwClientID);
2327
2328 if (rv != SCARD_S_SUCCESS)
2329 goto end;
2330
2331 if (SCARD_S_SUCCESS == scControlStruct.rv)
2332 {
2333 if (scControlStruct.dwBytesReturned > cbRecvLength)
2334 {
2335 if (NULL != lpBytesReturned)
2336 *lpBytesReturned = scControlStruct.dwBytesReturned;
2338 goto end;
2339 }
2340
2341 /* read the received buffer */
2342 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2343 currentContextMap->dwClientID);
2344
2345 if (rv != SCARD_S_SUCCESS)
2346 goto end;
2347
2348 }
2349
2350 if (NULL != lpBytesReturned)
2351 *lpBytesReturned = scControlStruct.dwBytesReturned;
2352
2353 rv = scControlStruct.rv;
2354
2355end:
2356 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2357
2358 PROFILE_END(rv)
2359
2360 return rv;
2361}
2362
2481LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2482 LPDWORD pcbAttrLen)
2483{
2484 LONG ret;
2485 unsigned char *buf = NULL;
2486
2487 PROFILE_START
2488
2489 if (NULL == pcbAttrLen)
2490 {
2492 goto end;
2493 }
2494
2495 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2496 {
2497 if (NULL == pbAttr)
2499
2500 *pcbAttrLen = MAX_BUFFER_SIZE;
2501 buf = malloc(*pcbAttrLen);
2502 if (NULL == buf)
2503 {
2504 ret = SCARD_E_NO_MEMORY;
2505 goto end;
2506 }
2507
2508 *(unsigned char **)pbAttr = buf;
2509 }
2510 else
2511 {
2512 buf = pbAttr;
2513
2514 /* if only get the length */
2515 if (NULL == pbAttr)
2516 /* use a reasonable size */
2517 *pcbAttrLen = MAX_BUFFER_SIZE;
2518 }
2519
2520 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2521 pcbAttrLen);
2522
2523end:
2524 PROFILE_END(ret)
2525
2526 return ret;
2527}
2528
2564LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2565 DWORD cbAttrLen)
2566{
2567 LONG ret;
2568
2569 PROFILE_START
2570
2571 if (NULL == pbAttr || 0 == cbAttrLen)
2573
2574 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2575 &cbAttrLen);
2576
2577 PROFILE_END(ret)
2578
2579 return ret;
2580}
2581
2582static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2583 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2584{
2585 LONG rv;
2586 struct getset_struct scGetSetStruct;
2587 SCONTEXTMAP * currentContextMap;
2588 CHANNEL_MAP * pChannelMap;
2589
2590 /*
2591 * Make sure this handle has been opened
2592 */
2593 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2594 &pChannelMap);
2595 if (rv == -1)
2597
2598 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2599 {
2601 goto end;
2602 }
2603
2604 scGetSetStruct.hCard = hCard;
2605 scGetSetStruct.dwAttrId = dwAttrId;
2606 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2607 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2608 if (SCARD_SET_ATTRIB == command)
2609 {
2610 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2611 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2612 }
2613 else
2614 /* we can get up to the communication buffer size */
2615 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2616
2617 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2618 sizeof(scGetSetStruct), &scGetSetStruct);
2619
2620 if (rv != SCARD_S_SUCCESS)
2621 goto end;
2622
2623 /*
2624 * Read a message from the server
2625 */
2626 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2627 currentContextMap->dwClientID);
2628
2629 if (rv != SCARD_S_SUCCESS)
2630 goto end;
2631
2632 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2633 {
2634 /*
2635 * Copy and zero it so any secret information is not leaked
2636 */
2637 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2638 {
2639 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2640 * buffer overflow in the memcpy() below */
2641 DWORD correct_value = scGetSetStruct.cbAttrLen;
2642 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2643 *pcbAttrLen = correct_value;
2644
2645 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2646 }
2647 else
2648 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2649
2650 if (pbAttr)
2651 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2652
2653 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2654 }
2655 rv = scGetSetStruct.rv;
2656
2657end:
2658 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2659
2660 return rv;
2661}
2662
2721LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2722 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2723 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2724 LPDWORD pcbRecvLength)
2725{
2726 LONG rv;
2727 SCONTEXTMAP * currentContextMap;
2728 CHANNEL_MAP * pChannelMap;
2729 struct transmit_struct scTransmitStruct;
2730
2731 PROFILE_START
2732
2733 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2734 pcbRecvLength == NULL || pioSendPci == NULL)
2736
2737 /* Retry loop for blocking behaviour */
2738retry:
2739
2740 /*
2741 * Make sure this handle has been opened
2742 */
2743 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2744 &pChannelMap);
2745 if (rv == -1)
2746 {
2747 *pcbRecvLength = 0;
2748 PROFILE_END(SCARD_E_INVALID_HANDLE)
2750 }
2751
2752 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2753 {
2755 goto end;
2756 }
2757
2758 scTransmitStruct.hCard = hCard;
2759 scTransmitStruct.cbSendLength = cbSendLength;
2760 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2761 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2762 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2763 scTransmitStruct.rv = SCARD_S_SUCCESS;
2764
2765 if (pioRecvPci)
2766 {
2767 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2768 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2769 }
2770 else
2771 {
2772 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2773 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2774 }
2775
2776 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2777 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2778
2779 if (rv != SCARD_S_SUCCESS)
2780 goto end;
2781
2782 /* write the sent buffer */
2783 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2784 currentContextMap->dwClientID);
2785
2786 if (rv != SCARD_S_SUCCESS)
2787 goto end;
2788
2789 /*
2790 * Read a message from the server
2791 */
2792 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2793 currentContextMap->dwClientID);
2794
2795 if (rv != SCARD_S_SUCCESS)
2796 goto end;
2797
2798 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2799 {
2800 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2801 {
2802 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2804 goto end;
2805 }
2806
2807 /* read the received buffer */
2808 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2809 currentContextMap->dwClientID);
2810
2811 if (rv != SCARD_S_SUCCESS)
2812 goto end;
2813
2814 if (pioRecvPci)
2815 {
2816 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2817 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2818 }
2819 }
2820
2821 rv = scTransmitStruct.rv;
2822
2823 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2824 {
2825 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2826 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2827 goto retry;
2828 }
2829
2830 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2831
2832end:
2833 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2834
2835 PROFILE_END(rv)
2836
2837 return rv;
2838}
2839
2902LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2903 LPSTR mszReaders, LPDWORD pcchReaders)
2904{
2905 DWORD dwReadersLen = 0;
2906 int i;
2907 SCONTEXTMAP * currentContextMap;
2908 LONG rv = SCARD_S_SUCCESS;
2909 char *buf = NULL;
2910
2911 (void)mszGroups;
2912 PROFILE_START
2913 API_TRACE_IN("%ld", hContext)
2914
2915 /*
2916 * Check for NULL parameters
2917 */
2918 if (pcchReaders == NULL)
2920
2921 /*
2922 * Make sure this context has been opened
2923 */
2924 currentContextMap = SCardGetAndLockContext(hContext);
2925 if (NULL == currentContextMap)
2926 {
2927 PROFILE_END(SCARD_E_INVALID_HANDLE)
2929 }
2930
2931 /* lock access to readerStates[] */
2932 (void)pthread_mutex_lock(&readerStatesMutex);
2933
2934 /* synchronize reader states with daemon */
2935 rv = getReaderStates(currentContextMap);
2936 if (rv != SCARD_S_SUCCESS)
2937 goto end;
2938
2939 dwReadersLen = 0;
2940 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2941 if (readerStates[i].readerName[0] != '\0')
2942 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2943
2944 /* for the last NULL byte */
2945 dwReadersLen += 1;
2946
2947 if (1 == dwReadersLen)
2948 {
2950 goto end;
2951 }
2952
2953 if (SCARD_AUTOALLOCATE == *pcchReaders)
2954 {
2955 if (NULL == mszReaders)
2956 {
2958 goto end;
2959 }
2960 buf = malloc(dwReadersLen);
2961 if (NULL == buf)
2962 {
2963 rv = SCARD_E_NO_MEMORY;
2964 goto end;
2965 }
2966 *(char **)mszReaders = buf;
2967 }
2968 else
2969 {
2970 buf = mszReaders;
2971
2972 /* not enough place to store the reader names */
2973 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2974 {
2976 goto end;
2977 }
2978 }
2979
2980 if (mszReaders == NULL) /* text array not allocated */
2981 goto end;
2982
2983 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2984 {
2985 if (readerStates[i].readerName[0] != '\0')
2986 {
2987 /*
2988 * Build the multi-string
2989 */
2990 strcpy(buf, readerStates[i].readerName);
2991 buf += strlen(readerStates[i].readerName)+1;
2992 }
2993 }
2994 *buf = '\0'; /* Add the last null */
2995
2996end:
2997 /* set the reader names length */
2998 *pcchReaders = dwReadersLen;
2999
3000 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3001 (void)pthread_mutex_unlock(&readerStatesMutex);
3002
3003 PROFILE_END(rv)
3004 API_TRACE_OUT("%d", *pcchReaders)
3005
3006 return rv;
3007}
3008
3022LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3023{
3024 LONG rv = SCARD_S_SUCCESS;
3025
3026 PROFILE_START
3027
3028 /*
3029 * Make sure this context has been opened
3030 */
3031 if (! SCardGetContextValidity(hContext))
3033
3034 free((void *)pvMem);
3035
3036 PROFILE_END(rv)
3037
3038 return rv;
3039}
3040
3092LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3093 LPDWORD pcchGroups)
3094{
3095 LONG rv = SCARD_S_SUCCESS;
3096 SCONTEXTMAP * currentContextMap;
3097 char *buf = NULL;
3098
3099 PROFILE_START
3100
3101 /* Multi-string with two trailing \0 */
3102 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3103 const unsigned int dwGroups = sizeof(ReaderGroup);
3104
3105 /*
3106 * Make sure this context has been opened
3107 */
3108 currentContextMap = SCardGetAndLockContext(hContext);
3109 if (NULL == currentContextMap)
3111
3112 if (SCARD_AUTOALLOCATE == *pcchGroups)
3113 {
3114 if (NULL == mszGroups)
3115 {
3117 goto end;
3118 }
3119 buf = malloc(dwGroups);
3120 if (NULL == buf)
3121 {
3122 rv = SCARD_E_NO_MEMORY;
3123 goto end;
3124 }
3125 *(char **)mszGroups = buf;
3126 }
3127 else
3128 {
3129 buf = mszGroups;
3130
3131 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3132 {
3134 goto end;
3135 }
3136 }
3137
3138 if (buf)
3139 memcpy(buf, ReaderGroup, dwGroups);
3140
3141end:
3142 *pcchGroups = dwGroups;
3143
3144 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3145
3146 PROFILE_END(rv)
3147
3148 return rv;
3149}
3150
3183{
3184 SCONTEXTMAP * currentContextMap;
3185 LONG rv = SCARD_S_SUCCESS;
3186 uint32_t dwClientID = 0;
3187 struct cancel_struct scCancelStruct;
3188 bool cancellable;
3189
3190 PROFILE_START
3191 API_TRACE_IN("%ld", hContext)
3192
3193 /*
3194 * Make sure this context has been opened
3195 */
3196 (void)SCardLockThread();
3197 currentContextMap = SCardGetContextTH(hContext);
3198
3199 if (NULL == currentContextMap)
3200 {
3201 (void)SCardUnlockThread();
3203 goto error;
3204 }
3205 cancellable = currentContextMap->cancellable;
3206 (void)SCardUnlockThread();
3207
3208 if (! cancellable)
3209 {
3210 rv = SCARD_S_SUCCESS;
3211 goto error;
3212 }
3213
3214 /* create a new connection to the server */
3215 if (ClientSetupSession(&dwClientID) != 0)
3216 {
3217 rv = SCARD_E_NO_SERVICE;
3218 goto error;
3219 }
3220
3221 scCancelStruct.hContext = hContext;
3222 scCancelStruct.rv = SCARD_S_SUCCESS;
3223
3224 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3225 sizeof(scCancelStruct), (void *) &scCancelStruct);
3226
3227 if (rv != SCARD_S_SUCCESS)
3228 goto end;
3229
3230 /*
3231 * Read a message from the server
3232 */
3233 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3234
3235 if (rv != SCARD_S_SUCCESS)
3236 goto end;
3237
3238 rv = scCancelStruct.rv;
3239end:
3240 ClientCloseSession(dwClientID);
3241
3242error:
3243 PROFILE_END(rv)
3244 API_TRACE_OUT("")
3245
3246 return rv;
3247}
3248
3273{
3274 LONG rv;
3275
3276 PROFILE_START
3277 API_TRACE_IN("%ld", hContext)
3278
3279 rv = SCARD_S_SUCCESS;
3280
3281 /*
3282 * Make sure this context has been opened
3283 */
3284 if (! SCardGetContextValidity(hContext))
3286
3287 PROFILE_END(rv)
3288 API_TRACE_OUT("")
3289
3290 return rv;
3291}
3292
3309static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3310{
3311 int lrv;
3312 SCONTEXTMAP * newContextMap;
3313
3314 newContextMap = malloc(sizeof(SCONTEXTMAP));
3315 if (NULL == newContextMap)
3316 return SCARD_E_NO_MEMORY;
3317
3318 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3319 newContextMap->hContext = hContext;
3320 newContextMap->dwClientID = dwClientID;
3321 newContextMap->cancellable = false;
3322
3323 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3324
3325 lrv = list_init(&newContextMap->channelMapList);
3326 if (lrv < 0)
3327 {
3328 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3329 goto error;
3330 }
3331
3332 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3333 CHANNEL_MAP_seeker);
3334 if (lrv <0)
3335 {
3336 Log2(PCSC_LOG_CRITICAL,
3337 "list_attributes_seeker failed with return value: %d", lrv);
3338 list_destroy(&newContextMap->channelMapList);
3339 goto error;
3340 }
3341
3342 lrv = list_append(&contextMapList, newContextMap);
3343 if (lrv < 0)
3344 {
3345 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3346 lrv);
3347 list_destroy(&newContextMap->channelMapList);
3348 goto error;
3349 }
3350
3351 return SCARD_S_SUCCESS;
3352
3353error:
3354
3355 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3356 free(newContextMap);
3357
3358 return SCARD_E_NO_MEMORY;
3359}
3360
3378{
3379 SCONTEXTMAP * currentContextMap;
3380
3382 currentContextMap = SCardGetContextTH(hContext);
3383
3384 /* lock the context (if available) */
3385 if (NULL != currentContextMap)
3386 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3387
3389
3390 return currentContextMap;
3391}
3392
3406{
3407 return list_seek(&contextMapList, &hContext);
3408}
3409
3417{
3418 SCONTEXTMAP * currentContextMap;
3419 currentContextMap = SCardGetContextTH(hContext);
3420
3421 if (NULL != currentContextMap)
3422 SCardCleanContext(currentContextMap);
3423}
3424
3425static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3426{
3427 int list_index, lrv;
3428 int listSize;
3429 CHANNEL_MAP * currentChannelMap;
3430
3431 targetContextMap->hContext = 0;
3432 ClientCloseSession(targetContextMap->dwClientID);
3433 targetContextMap->dwClientID = 0;
3434 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3435
3436 listSize = list_size(&targetContextMap->channelMapList);
3437 for (list_index = 0; list_index < listSize; list_index++)
3438 {
3439 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3440 list_index);
3441 if (NULL == currentChannelMap)
3442 {
3443 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3444 list_index);
3445 continue;
3446 }
3447 else
3448 {
3449 free(currentChannelMap->readerName);
3450 free(currentChannelMap);
3451 }
3452
3453 }
3454 list_destroy(&targetContextMap->channelMapList);
3455
3456 lrv = list_delete(&contextMapList, targetContextMap);
3457 if (lrv < 0)
3458 {
3459 Log2(PCSC_LOG_CRITICAL,
3460 "list_delete failed with return value: %d", lrv);
3461 }
3462
3463 free(targetContextMap);
3464
3465 return;
3466}
3467
3468/*
3469 * Functions for managing hCard values returned from SCardConnect.
3470 */
3471
3472static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3473 LPCSTR readerName)
3474{
3475 CHANNEL_MAP * newChannelMap;
3476 int lrv = -1;
3477
3478 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3479 if (NULL == newChannelMap)
3480 return SCARD_E_NO_MEMORY;
3481
3482 newChannelMap->hCard = hCard;
3483 newChannelMap->readerName = strdup(readerName);
3484
3485 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3486 if (lrv < 0)
3487 {
3488 free(newChannelMap->readerName);
3489 free(newChannelMap);
3490 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3491 lrv);
3492 return SCARD_E_NO_MEMORY;
3493 }
3494
3495 return SCARD_S_SUCCESS;
3496}
3497
3498static void SCardRemoveHandle(SCARDHANDLE hCard)
3499{
3500 SCONTEXTMAP * currentContextMap;
3501 CHANNEL_MAP * currentChannelMap;
3502 int lrv;
3503 LONG rv;
3504
3505 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3506 &currentChannelMap);
3507 if (rv == -1)
3508 return;
3509
3510 free(currentChannelMap->readerName);
3511
3512 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3513 if (lrv < 0)
3514 {
3515 Log2(PCSC_LOG_CRITICAL,
3516 "list_delete failed with return value: %d", lrv);
3517 }
3518
3519 free(currentChannelMap);
3520
3521 return;
3522}
3523
3524static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3525 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3526{
3527 LONG rv;
3528
3529 if (0 == hCard)
3530 return -1;
3531
3533 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3534 targetChannelMap);
3535
3536 if (SCARD_S_SUCCESS == rv)
3537 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3538
3540
3541 return rv;
3542}
3543
3544static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3545 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3546{
3547 int listSize;
3548 int list_index;
3549 SCONTEXTMAP * currentContextMap;
3550 CHANNEL_MAP * currentChannelMap;
3551
3552 /* Best to get the caller a crash early if we fail unsafely */
3553 *targetContextMap = NULL;
3554 *targetChannelMap = NULL;
3555
3556 listSize = list_size(&contextMapList);
3557
3558 for (list_index = 0; list_index < listSize; list_index++)
3559 {
3560 currentContextMap = list_get_at(&contextMapList, list_index);
3561 if (currentContextMap == NULL)
3562 {
3563 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3564 list_index);
3565 continue;
3566 }
3567 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3568 &hCard);
3569 if (currentChannelMap != NULL)
3570 {
3571 *targetContextMap = currentContextMap;
3572 *targetChannelMap = currentChannelMap;
3573 return SCARD_S_SUCCESS;
3574 }
3575 }
3576
3577 return -1;
3578}
3579
3588{
3589 LONG rv;
3590 struct stat statBuffer;
3591 char *socketName;
3592
3593 socketName = getSocketName();
3594 rv = stat(socketName, &statBuffer);
3595
3596 if (rv != 0)
3597 {
3598 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3599 socketName, strerror(errno));
3600 return SCARD_E_NO_SERVICE;
3601 }
3602
3603 return SCARD_S_SUCCESS;
3604}
3605
3606static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3607{
3608 int32_t dwClientID = currentContextMap->dwClientID;
3609 LONG rv;
3611
3612 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3613 if (rv != SCARD_S_SUCCESS)
3614 return rv;
3615
3616 /* Read a message from the server */
3617 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3618 if (rv != SCARD_S_SUCCESS)
3619 return rv;
3620
3621 *readerEvents = get_reader_events.readerEvents;
3622
3623 return SCARD_S_SUCCESS;
3624}
3625
3626static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3627{
3628 int32_t dwClientID = currentContextMap->dwClientID;
3629 LONG rv;
3630
3631 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3632 if (rv != SCARD_S_SUCCESS)
3633 return rv;
3634
3635 /* Read a message from the server */
3636 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3637 if (rv != SCARD_S_SUCCESS)
3638 return rv;
3639
3640 return SCARD_S_SUCCESS;
3641}
3642
3643static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3644{
3645 int32_t dwClientID = currentContextMap->dwClientID;
3646 LONG rv;
3647
3648 /* Get current reader states from server and register on event list */
3650 0, NULL);
3651 if (rv != SCARD_S_SUCCESS)
3652 return rv;
3653
3654 /* Read a message from the server */
3655 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3656 return rv;
3657}
3658
3659static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3660{
3661 int32_t dwClientID = currentContextMap->dwClientID;
3662 LONG rv;
3663 struct wait_reader_state_change waitStatusStruct = {0};
3664
3665 /* ask server to remove us from the event list */
3667 dwClientID, 0, NULL);
3668 if (rv != SCARD_S_SUCCESS)
3669 return rv;
3670
3671 /* This message can be the response to
3672 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3673 * cancel notification.
3674 * The server side ensures, that no more messages will be sent to
3675 * the client. */
3676
3677 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3678 dwClientID);
3679 if (rv != SCARD_S_SUCCESS)
3680 return rv;
3681
3682 /* if we received a cancel event the return value will be set
3683 * accordingly */
3684 rv = waitStatusStruct.rv;
3685
3686 return rv;
3687}
3688
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.
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()
@ CMD_GET_READER_EVENTS
get the number of reader events
@ 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()