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
1678LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1679 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1680{
1681 SCARD_READERSTATE *currReader;
1682 READER_STATE *rContext;
1683 long dwTime;
1684 DWORD dwBreakFlag = 0;
1685 unsigned int j;
1686 SCONTEXTMAP * currentContextMap;
1687 int currentReaderCount = 0;
1688 LONG rv = SCARD_S_SUCCESS;
1689 int pnp_reader = -1;
1690
1691 PROFILE_START
1692 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1693#ifdef DO_TRACE
1694 for (j=0; j<cReaders; j++)
1695 {
1696 API_TRACE_IN("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1697 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1698 rgReaderStates[j].cbAtr)
1699 }
1700#endif
1701
1702 if ((rgReaderStates == NULL && cReaders > 0)
1703 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1704 {
1706 goto error;
1707 }
1708
1709 /* Check the integrity of the reader states structures */
1710 for (j = 0; j < cReaders; j++)
1711 {
1712 if (rgReaderStates[j].szReader == NULL)
1713 return SCARD_E_INVALID_VALUE;
1714 }
1715
1716 /* return if all readers are SCARD_STATE_IGNORE */
1717 if (cReaders > 0)
1718 {
1719 int nbNonIgnoredReaders = cReaders;
1720
1721 for (j=0; j<cReaders; j++)
1722 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1723 nbNonIgnoredReaders--;
1724
1725 if (0 == nbNonIgnoredReaders)
1726 {
1727 rv = SCARD_S_SUCCESS;
1728 goto error;
1729 }
1730 }
1731 else
1732 {
1733 /* reader list is empty */
1734 rv = SCARD_S_SUCCESS;
1735 goto error;
1736 }
1737
1738 /*
1739 * Make sure this context has been opened
1740 */
1741 currentContextMap = SCardGetAndLockContext(hContext);
1742 if (NULL == currentContextMap)
1743 {
1745 goto error;
1746 }
1747
1748 /* lock access to readerStates[] */
1749 (void)pthread_mutex_lock(&readerStatesMutex);
1750
1751 /* synchronize reader states with daemon */
1752 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1753
1754 if (rv != SCARD_S_SUCCESS)
1755 {
1756 (void)pthread_mutex_unlock(&readerStatesMutex);
1757 goto end;
1758 }
1759
1760 /* check all the readers are already known */
1761 for (j=0; j<cReaders; j++)
1762 {
1763 const char *readerName;
1764 int i;
1765
1766 readerName = rgReaderStates[j].szReader;
1767 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1768 {
1769 if (strcmp(readerName, readerStates[i].readerName) == 0)
1770 break;
1771 }
1772
1773 /* The requested reader name is not recognized */
1775 {
1776 /* PnP special reader? */
1777 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1778 {
1780 (void)pthread_mutex_unlock(&readerStatesMutex);
1781 goto end;
1782 }
1783 else
1784 pnp_reader = j;
1785 }
1786 }
1787 (void)pthread_mutex_unlock(&readerStatesMutex);
1788
1789 /* Clear the event state for all readers */
1790 for (j = 0; j < cReaders; j++)
1791 rgReaderStates[j].dwEventState = 0;
1792
1793 /* Now is where we start our event checking loop */
1794 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1795
1796 /* index of the PnP readerin rgReaderStates[] */
1797 if (pnp_reader >= 0)
1798 {
1799 int readerEvents;
1800 currReader = &rgReaderStates[pnp_reader];
1801
1802 /* PnP special reader */
1803 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1804 {
1805 int previousReaderEvents = currReader->dwCurrentState >> 16;
1806
1807 // store readerEvents in .dwEventState high word
1808 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1809 if (
1810 /* the value has changed since the last call */
1811 (previousReaderEvents != readerEvents)
1812 /* backward compatibility: only if we had a non-null
1813 * reader events value */
1814 && previousReaderEvents)
1815 {
1816 currReader->dwEventState |= SCARD_STATE_CHANGED;
1817 rv = SCARD_S_SUCCESS;
1818 dwBreakFlag = 1;
1819 }
1820 }
1821 }
1822
1823 /* Get the initial reader count on the system */
1824 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1825 if (readerStates[j].readerName[0] != '\0')
1826 currentReaderCount++;
1827
1828 /* catch possible sign extension problems from 32 to 64-bits integers */
1829 if ((DWORD)-1 == dwTimeout)
1830 dwTimeout = INFINITE;
1831 if (INFINITE == dwTimeout)
1832 dwTime = 60*1000; /* "infinite" timeout */
1833 else
1834 dwTime = dwTimeout;
1835
1836 j = 0;
1837 do
1838 {
1839 currReader = &rgReaderStates[j];
1840
1841 /* Ignore for IGNORED readers */
1842 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1843 {
1844 const char *readerName;
1845 int i;
1846
1847 /* lock access to readerStates[] */
1848 (void)pthread_mutex_lock(&readerStatesMutex);
1849
1850 /* Looks for correct readernames */
1851 readerName = currReader->szReader;
1852 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1853 {
1854 if (strcmp(readerName, readerStates[i].readerName) == 0)
1855 break;
1856 }
1857
1858 /* The requested reader name is not recognized */
1860 {
1861 /* PnP special reader? */
1862 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1863 {
1864 int k, newReaderCount = 0;
1865
1866 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1867 if (readerStates[k].readerName[0] != '\0')
1868 newReaderCount++;
1869
1870 if (newReaderCount != currentReaderCount)
1871 {
1872 int readerEvents;
1873
1874 Log1(PCSC_LOG_INFO, "Reader list changed");
1875 currentReaderCount = newReaderCount;
1876
1877 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1878 {
1879 // store readerEvents in .dwEventState high word
1880 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1881 }
1882
1883 currReader->dwEventState |= SCARD_STATE_CHANGED;
1884 dwBreakFlag = 1;
1885 }
1886 }
1887 else
1888 {
1889 currReader->dwEventState =
1891 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1892 {
1893 currReader->dwEventState |= SCARD_STATE_CHANGED;
1894 /*
1895 * Spec says use SCARD_STATE_IGNORE but a removed USB
1896 * reader with eventState fed into currentState will
1897 * be ignored forever
1898 */
1899 dwBreakFlag = 1;
1900 }
1901 }
1902 }
1903 else
1904 {
1905 uint32_t readerState;
1906
1907 /* The reader has come back after being away */
1908 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1909 {
1910 currReader->dwEventState |= SCARD_STATE_CHANGED;
1911 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1912 Log0(PCSC_LOG_DEBUG);
1913 dwBreakFlag = 1;
1914 }
1915
1916 /* Set the reader status structure */
1917 rContext = &readerStates[i];
1918
1919 /* Now we check all the Reader States */
1920 readerState = rContext->readerState;
1921
1922 /* only if current state has an non null event counter */
1923 if (currReader->dwCurrentState & 0xFFFF0000)
1924 {
1925 unsigned int currentCounter;
1926
1927 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1928
1929 /* has the event counter changed since the last call? */
1930 if (rContext->eventCounter != currentCounter)
1931 {
1932 currReader->dwEventState |= SCARD_STATE_CHANGED;
1933 Log0(PCSC_LOG_DEBUG);
1934 dwBreakFlag = 1;
1935 }
1936 }
1937
1938 /* add an event counter in the upper word of dwEventState */
1939 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1940 | (rContext->eventCounter << 16));
1941
1942 /* Check if the reader is in the correct state */
1943 if (readerState & SCARD_UNKNOWN)
1944 {
1945 /* reader is in bad state */
1946 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1947 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1948 {
1949 /* App thinks reader is in good state and it is not */
1950 currReader->dwEventState |= SCARD_STATE_CHANGED;
1951 Log0(PCSC_LOG_DEBUG);
1952 dwBreakFlag = 1;
1953 }
1954 }
1955 else
1956 {
1957 /* App thinks reader in bad state but it is not */
1958 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1959 {
1960 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1961 currReader->dwEventState |= SCARD_STATE_CHANGED;
1962 Log0(PCSC_LOG_DEBUG);
1963 dwBreakFlag = 1;
1964 }
1965 }
1966
1967 /* Check for card presence in the reader */
1968 if (readerState & SCARD_PRESENT)
1969 {
1970#ifndef DISABLE_AUTO_POWER_ON
1971 /* card present but not yet powered up */
1972 if (0 == rContext->cardAtrLength)
1973 /* Allow the status thread to convey information */
1974 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1975#endif
1976
1977 currReader->cbAtr = rContext->cardAtrLength;
1978 memcpy(currReader->rgbAtr, rContext->cardAtr,
1979 currReader->cbAtr);
1980 }
1981 else
1982 currReader->cbAtr = 0;
1983
1984 /* Card is now absent */
1985 if (readerState & SCARD_ABSENT)
1986 {
1987 currReader->dwEventState |= SCARD_STATE_EMPTY;
1988 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1989 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1990 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1991 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1992 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1993 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1994 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1995 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1996
1997 /* After present the rest are assumed */
1998 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1999 {
2000 currReader->dwEventState |= SCARD_STATE_CHANGED;
2001 Log0(PCSC_LOG_DEBUG);
2002 dwBreakFlag = 1;
2003 }
2004 }
2005 /* Card is now present */
2006 else if (readerState & SCARD_PRESENT)
2007 {
2008 currReader->dwEventState |= SCARD_STATE_PRESENT;
2009 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2010 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2011 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2012 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2013 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2014 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2015
2016 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2017 {
2018 currReader->dwEventState |= SCARD_STATE_CHANGED;
2019 Log0(PCSC_LOG_DEBUG);
2020 dwBreakFlag = 1;
2021 }
2022
2023 if (readerState & SCARD_SWALLOWED)
2024 {
2025 currReader->dwEventState |= SCARD_STATE_MUTE;
2026 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2027 {
2028 currReader->dwEventState |= SCARD_STATE_CHANGED;
2029 Log0(PCSC_LOG_DEBUG);
2030 dwBreakFlag = 1;
2031 }
2032 }
2033 else
2034 {
2035 /* App thinks card is mute but it is not */
2036 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2037 {
2038 currReader->dwEventState |= SCARD_STATE_CHANGED;
2039 Log0(PCSC_LOG_DEBUG);
2040 dwBreakFlag = 1;
2041 }
2042 }
2043 }
2044
2045 /* Now figure out sharing modes */
2047 {
2048 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2049 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2050 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2051 {
2052 currReader->dwEventState |= SCARD_STATE_CHANGED;
2053 Log0(PCSC_LOG_DEBUG);
2054 dwBreakFlag = 1;
2055 }
2056 }
2057 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2058 {
2059 /* A card must be inserted for it to be INUSE */
2060 if (readerState & SCARD_PRESENT)
2061 {
2062 currReader->dwEventState |= SCARD_STATE_INUSE;
2063 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2064 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2065 {
2066 currReader->dwEventState |= SCARD_STATE_CHANGED;
2067 Log0(PCSC_LOG_DEBUG);
2068 dwBreakFlag = 1;
2069 }
2070 }
2071 }
2072 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2073 {
2074 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2075 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2076
2077 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2078 {
2079 currReader->dwEventState |= SCARD_STATE_CHANGED;
2080 Log0(PCSC_LOG_DEBUG);
2081 dwBreakFlag = 1;
2082 }
2083 else if (currReader-> dwCurrentState
2085 {
2086 currReader->dwEventState |= SCARD_STATE_CHANGED;
2087 Log0(PCSC_LOG_DEBUG);
2088 dwBreakFlag = 1;
2089 }
2090 }
2091
2092 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2093 {
2094 /*
2095 * Break out of the while .. loop and return status
2096 * once all the status's for all readers is met
2097 */
2098 currReader->dwEventState |= SCARD_STATE_CHANGED;
2099 Log0(PCSC_LOG_DEBUG);
2100 dwBreakFlag = 1;
2101 }
2102 } /* End of SCARD_STATE_UNKNOWN */
2103
2104 (void)pthread_mutex_unlock(&readerStatesMutex);
2105 } /* End of SCARD_STATE_IGNORE */
2106
2107 /* Counter and resetter */
2108 j++;
2109 if (j == cReaders)
2110 {
2111 /* go back to the first reader */
2112 j = 0;
2113
2114 /* Declare all the break conditions */
2115
2116 /* Break if UNAWARE is set and all readers have been checked */
2117 if (dwBreakFlag == 1)
2118 break;
2119
2120 /* Only sleep once for each cycle of reader checks. */
2121 {
2122 struct wait_reader_state_change waitStatusStruct = {0};
2123 struct timeval before, after;
2124
2125 gettimeofday(&before, NULL);
2126
2127 waitStatusStruct.rv = SCARD_S_SUCCESS;
2128
2129 /* another thread can do SCardCancel() */
2130 currentContextMap->cancellable = true;
2131
2132 /*
2133 * Read a message from the server
2134 */
2136 &waitStatusStruct, sizeof(waitStatusStruct),
2137 currentContextMap->dwClientID, dwTime);
2138
2139 /* SCardCancel() will return immediately with success
2140 * because something changed on the daemon side. */
2141 currentContextMap->cancellable = false;
2142
2143 /* timeout */
2144 if (SCARD_E_TIMEOUT == rv)
2145 {
2146 /* ask server to remove us from the event list */
2147 rv = unregisterFromEvents(currentContextMap);
2148 }
2149
2150 if (rv != SCARD_S_SUCCESS)
2151 goto end;
2152
2153 /* an event occurs or SCardCancel() was called */
2154 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2155 {
2156 rv = waitStatusStruct.rv;
2157 goto end;
2158 }
2159
2160 /* synchronize reader states with daemon */
2161 (void)pthread_mutex_lock(&readerStatesMutex);
2162 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2163 (void)pthread_mutex_unlock(&readerStatesMutex);
2164 if (rv != SCARD_S_SUCCESS)
2165 goto end;
2166
2167 if (INFINITE != dwTimeout)
2168 {
2169 long int diff;
2170
2171 gettimeofday(&after, NULL);
2172 diff = time_sub(&after, &before);
2173 dwTime -= diff/1000;
2174 }
2175 }
2176
2177 if (dwTimeout != INFINITE)
2178 {
2179 /* If time is greater than timeout and all readers have been
2180 * checked
2181 */
2182 if (dwTime <= 0)
2183 {
2184 rv = SCARD_E_TIMEOUT;
2185 goto end;
2186 }
2187 }
2188 }
2189 }
2190 while (1);
2191
2192end:
2193 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2194
2195 /* if SCardCancel() has been used then the client is already
2196 * unregistered */
2197 if (SCARD_E_CANCELLED != rv)
2198 (void)unregisterFromEvents(currentContextMap);
2199
2200 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2201
2202error:
2203 PROFILE_END(rv)
2204#ifdef DO_TRACE
2205 for (j=0; j<cReaders; j++)
2206 {
2207 API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2208 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2209 rgReaderStates[j].cbAtr)
2210 }
2211#endif
2212
2213 return rv;
2214}
2215
2266LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2267 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2268 LPDWORD lpBytesReturned)
2269{
2270 LONG rv;
2271 struct control_struct scControlStruct;
2272 SCONTEXTMAP * currentContextMap;
2273 CHANNEL_MAP * pChannelMap;
2274
2275 PROFILE_START
2276
2277 /* 0 bytes received by default */
2278 if (NULL != lpBytesReturned)
2279 *lpBytesReturned = 0;
2280
2281 /*
2282 * Make sure this handle has been opened
2283 */
2284 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2285 &pChannelMap);
2286 if (rv == -1)
2287 {
2288 PROFILE_END(SCARD_E_INVALID_HANDLE)
2290 }
2291
2292 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2293 {
2295 goto end;
2296 }
2297
2298 scControlStruct.hCard = hCard;
2299 scControlStruct.dwControlCode = dwControlCode;
2300 scControlStruct.cbSendLength = cbSendLength;
2301 scControlStruct.cbRecvLength = cbRecvLength;
2302 scControlStruct.dwBytesReturned = 0;
2303 scControlStruct.rv = 0;
2304
2305 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2306 sizeof(scControlStruct), &scControlStruct);
2307
2308 if (rv != SCARD_S_SUCCESS)
2309 goto end;
2310
2311 /* write the sent buffer */
2312 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2313 currentContextMap->dwClientID);
2314
2315 if (rv != SCARD_S_SUCCESS)
2316 goto end;
2317
2318 /*
2319 * Read a message from the server
2320 */
2321 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2322 currentContextMap->dwClientID);
2323
2324 if (rv != SCARD_S_SUCCESS)
2325 goto end;
2326
2327 if (SCARD_S_SUCCESS == scControlStruct.rv)
2328 {
2329 if (scControlStruct.dwBytesReturned > cbRecvLength)
2330 {
2331 if (NULL != lpBytesReturned)
2332 *lpBytesReturned = scControlStruct.dwBytesReturned;
2334 goto end;
2335 }
2336
2337 /* read the received buffer */
2338 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2339 currentContextMap->dwClientID);
2340
2341 if (rv != SCARD_S_SUCCESS)
2342 goto end;
2343
2344 }
2345
2346 if (NULL != lpBytesReturned)
2347 *lpBytesReturned = scControlStruct.dwBytesReturned;
2348
2349 rv = scControlStruct.rv;
2350
2351end:
2352 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2353
2354 PROFILE_END(rv)
2355
2356 return rv;
2357}
2358
2477LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2478 LPDWORD pcbAttrLen)
2479{
2480 LONG ret;
2481 unsigned char *buf = NULL;
2482
2483 PROFILE_START
2484
2485 if (NULL == pcbAttrLen)
2486 {
2488 goto end;
2489 }
2490
2491 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2492 {
2493 if (NULL == pbAttr)
2495
2496 *pcbAttrLen = MAX_BUFFER_SIZE;
2497 buf = malloc(*pcbAttrLen);
2498 if (NULL == buf)
2499 {
2500 ret = SCARD_E_NO_MEMORY;
2501 goto end;
2502 }
2503
2504 *(unsigned char **)pbAttr = buf;
2505 }
2506 else
2507 {
2508 buf = pbAttr;
2509
2510 /* if only get the length */
2511 if (NULL == pbAttr)
2512 /* use a reasonable size */
2513 *pcbAttrLen = MAX_BUFFER_SIZE;
2514 }
2515
2516 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2517 pcbAttrLen);
2518
2519end:
2520 PROFILE_END(ret)
2521
2522 return ret;
2523}
2524
2560LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2561 DWORD cbAttrLen)
2562{
2563 LONG ret;
2564
2565 PROFILE_START
2566
2567 if (NULL == pbAttr || 0 == cbAttrLen)
2569
2570 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2571 &cbAttrLen);
2572
2573 PROFILE_END(ret)
2574
2575 return ret;
2576}
2577
2578static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2579 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2580{
2581 LONG rv;
2582 struct getset_struct scGetSetStruct;
2583 SCONTEXTMAP * currentContextMap;
2584 CHANNEL_MAP * pChannelMap;
2585
2586 /*
2587 * Make sure this handle has been opened
2588 */
2589 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2590 &pChannelMap);
2591 if (rv == -1)
2593
2594 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2595 {
2597 goto end;
2598 }
2599
2600 scGetSetStruct.hCard = hCard;
2601 scGetSetStruct.dwAttrId = dwAttrId;
2602 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2603 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2604 if (SCARD_SET_ATTRIB == command)
2605 {
2606 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2607 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2608 }
2609 else
2610 /* we can get up to the communication buffer size */
2611 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2612
2613 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2614 sizeof(scGetSetStruct), &scGetSetStruct);
2615
2616 if (rv != SCARD_S_SUCCESS)
2617 goto end;
2618
2619 /*
2620 * Read a message from the server
2621 */
2622 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2623 currentContextMap->dwClientID);
2624
2625 if (rv != SCARD_S_SUCCESS)
2626 goto end;
2627
2628 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2629 {
2630 /*
2631 * Copy and zero it so any secret information is not leaked
2632 */
2633 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2634 {
2635 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2636 * buffer overflow in the memcpy() below */
2637 DWORD correct_value = scGetSetStruct.cbAttrLen;
2638 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2639 *pcbAttrLen = correct_value;
2640
2641 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2642 }
2643 else
2644 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2645
2646 if (pbAttr)
2647 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2648
2649 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2650 }
2651 rv = scGetSetStruct.rv;
2652
2653end:
2654 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2655
2656 return rv;
2657}
2658
2717LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2718 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2719 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2720 LPDWORD pcbRecvLength)
2721{
2722 LONG rv;
2723 SCONTEXTMAP * currentContextMap;
2724 CHANNEL_MAP * pChannelMap;
2725 struct transmit_struct scTransmitStruct;
2726
2727 PROFILE_START
2728
2729 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2730 pcbRecvLength == NULL || pioSendPci == NULL)
2732
2733 /* Retry loop for blocking behaviour */
2734retry:
2735
2736 /*
2737 * Make sure this handle has been opened
2738 */
2739 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2740 &pChannelMap);
2741 if (rv == -1)
2742 {
2743 *pcbRecvLength = 0;
2744 PROFILE_END(SCARD_E_INVALID_HANDLE)
2746 }
2747
2748 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2749 {
2751 goto end;
2752 }
2753
2754 scTransmitStruct.hCard = hCard;
2755 scTransmitStruct.cbSendLength = cbSendLength;
2756 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2757 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2758 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2759 scTransmitStruct.rv = SCARD_S_SUCCESS;
2760
2761 if (pioRecvPci)
2762 {
2763 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2764 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2765 }
2766 else
2767 {
2768 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2769 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2770 }
2771
2772 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2773 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2774
2775 if (rv != SCARD_S_SUCCESS)
2776 goto end;
2777
2778 /* write the sent buffer */
2779 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2780 currentContextMap->dwClientID);
2781
2782 if (rv != SCARD_S_SUCCESS)
2783 goto end;
2784
2785 /*
2786 * Read a message from the server
2787 */
2788 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2789 currentContextMap->dwClientID);
2790
2791 if (rv != SCARD_S_SUCCESS)
2792 goto end;
2793
2794 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2795 {
2796 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2797 {
2798 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2800 goto end;
2801 }
2802
2803 /* read the received buffer */
2804 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2805 currentContextMap->dwClientID);
2806
2807 if (rv != SCARD_S_SUCCESS)
2808 goto end;
2809
2810 if (pioRecvPci)
2811 {
2812 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2813 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2814 }
2815 }
2816
2817 rv = scTransmitStruct.rv;
2818
2819 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2820 {
2821 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2822 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2823 goto retry;
2824 }
2825
2826 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2827
2828end:
2829 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2830
2831 PROFILE_END(rv)
2832
2833 return rv;
2834}
2835
2898LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2899 LPSTR mszReaders, LPDWORD pcchReaders)
2900{
2901 DWORD dwReadersLen = 0;
2902 int i;
2903 SCONTEXTMAP * currentContextMap;
2904 LONG rv = SCARD_S_SUCCESS;
2905 char *buf = NULL;
2906
2907 (void)mszGroups;
2908 PROFILE_START
2909 API_TRACE_IN("%ld", hContext)
2910
2911 /*
2912 * Check for NULL parameters
2913 */
2914 if (pcchReaders == NULL)
2916
2917 /*
2918 * Make sure this context has been opened
2919 */
2920 currentContextMap = SCardGetAndLockContext(hContext);
2921 if (NULL == currentContextMap)
2922 {
2923 PROFILE_END(SCARD_E_INVALID_HANDLE)
2925 }
2926
2927 /* lock access to readerStates[] */
2928 (void)pthread_mutex_lock(&readerStatesMutex);
2929
2930 /* synchronize reader states with daemon */
2931 rv = getReaderStates(currentContextMap);
2932 if (rv != SCARD_S_SUCCESS)
2933 goto end;
2934
2935 dwReadersLen = 0;
2936 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2937 if (readerStates[i].readerName[0] != '\0')
2938 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2939
2940 /* for the last NULL byte */
2941 dwReadersLen += 1;
2942
2943 if (1 == dwReadersLen)
2944 {
2946 goto end;
2947 }
2948
2949 if (SCARD_AUTOALLOCATE == *pcchReaders)
2950 {
2951 if (NULL == mszReaders)
2952 {
2954 goto end;
2955 }
2956 buf = malloc(dwReadersLen);
2957 if (NULL == buf)
2958 {
2959 rv = SCARD_E_NO_MEMORY;
2960 goto end;
2961 }
2962 *(char **)mszReaders = buf;
2963 }
2964 else
2965 {
2966 buf = mszReaders;
2967
2968 /* not enough place to store the reader names */
2969 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2970 {
2972 goto end;
2973 }
2974 }
2975
2976 if (mszReaders == NULL) /* text array not allocated */
2977 goto end;
2978
2979 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2980 {
2981 if (readerStates[i].readerName[0] != '\0')
2982 {
2983 /*
2984 * Build the multi-string
2985 */
2986 strcpy(buf, readerStates[i].readerName);
2987 buf += strlen(readerStates[i].readerName)+1;
2988 }
2989 }
2990 *buf = '\0'; /* Add the last null */
2991
2992end:
2993 /* set the reader names length */
2994 *pcchReaders = dwReadersLen;
2995
2996 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2997 (void)pthread_mutex_unlock(&readerStatesMutex);
2998
2999 PROFILE_END(rv)
3000 API_TRACE_OUT("%d", *pcchReaders)
3001
3002 return rv;
3003}
3004
3018LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3019{
3020 LONG rv = SCARD_S_SUCCESS;
3021
3022 PROFILE_START
3023
3024 /*
3025 * Make sure this context has been opened
3026 */
3027 if (! SCardGetContextValidity(hContext))
3029
3030 free((void *)pvMem);
3031
3032 PROFILE_END(rv)
3033
3034 return rv;
3035}
3036
3088LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3089 LPDWORD pcchGroups)
3090{
3091 LONG rv = SCARD_S_SUCCESS;
3092 SCONTEXTMAP * currentContextMap;
3093 char *buf = NULL;
3094
3095 PROFILE_START
3096
3097 /* Multi-string with two trailing \0 */
3098 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3099 const unsigned int dwGroups = sizeof(ReaderGroup);
3100
3101 /*
3102 * Make sure this context has been opened
3103 */
3104 currentContextMap = SCardGetAndLockContext(hContext);
3105 if (NULL == currentContextMap)
3107
3108 if (SCARD_AUTOALLOCATE == *pcchGroups)
3109 {
3110 if (NULL == mszGroups)
3111 {
3113 goto end;
3114 }
3115 buf = malloc(dwGroups);
3116 if (NULL == buf)
3117 {
3118 rv = SCARD_E_NO_MEMORY;
3119 goto end;
3120 }
3121 *(char **)mszGroups = buf;
3122 }
3123 else
3124 {
3125 buf = mszGroups;
3126
3127 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3128 {
3130 goto end;
3131 }
3132 }
3133
3134 if (buf)
3135 memcpy(buf, ReaderGroup, dwGroups);
3136
3137end:
3138 *pcchGroups = dwGroups;
3139
3140 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3141
3142 PROFILE_END(rv)
3143
3144 return rv;
3145}
3146
3179{
3180 SCONTEXTMAP * currentContextMap;
3181 LONG rv = SCARD_S_SUCCESS;
3182 uint32_t dwClientID = 0;
3183 struct cancel_struct scCancelStruct;
3184 bool cancellable;
3185
3186 PROFILE_START
3187 API_TRACE_IN("%ld", hContext)
3188
3189 /*
3190 * Make sure this context has been opened
3191 */
3192 (void)SCardLockThread();
3193 currentContextMap = SCardGetContextTH(hContext);
3194
3195 if (NULL == currentContextMap)
3196 {
3197 (void)SCardUnlockThread();
3199 goto error;
3200 }
3201 cancellable = currentContextMap->cancellable;
3202 (void)SCardUnlockThread();
3203
3204 if (! cancellable)
3205 {
3206 rv = SCARD_S_SUCCESS;
3207 goto error;
3208 }
3209
3210 /* create a new connection to the server */
3211 if (ClientSetupSession(&dwClientID) != 0)
3212 {
3213 rv = SCARD_E_NO_SERVICE;
3214 goto error;
3215 }
3216
3217 scCancelStruct.hContext = hContext;
3218 scCancelStruct.rv = SCARD_S_SUCCESS;
3219
3220 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3221 sizeof(scCancelStruct), (void *) &scCancelStruct);
3222
3223 if (rv != SCARD_S_SUCCESS)
3224 goto end;
3225
3226 /*
3227 * Read a message from the server
3228 */
3229 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3230
3231 if (rv != SCARD_S_SUCCESS)
3232 goto end;
3233
3234 rv = scCancelStruct.rv;
3235end:
3236 ClientCloseSession(dwClientID);
3237
3238error:
3239 PROFILE_END(rv)
3240 API_TRACE_OUT("")
3241
3242 return rv;
3243}
3244
3269{
3270 LONG rv;
3271
3272 PROFILE_START
3273 API_TRACE_IN("%ld", hContext)
3274
3275 rv = SCARD_S_SUCCESS;
3276
3277 /*
3278 * Make sure this context has been opened
3279 */
3280 if (! SCardGetContextValidity(hContext))
3282
3283 PROFILE_END(rv)
3284 API_TRACE_OUT("")
3285
3286 return rv;
3287}
3288
3305static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3306{
3307 int lrv;
3308 SCONTEXTMAP * newContextMap;
3309
3310 newContextMap = malloc(sizeof(SCONTEXTMAP));
3311 if (NULL == newContextMap)
3312 return SCARD_E_NO_MEMORY;
3313
3314 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3315 newContextMap->hContext = hContext;
3316 newContextMap->dwClientID = dwClientID;
3317 newContextMap->cancellable = false;
3318
3319 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3320
3321 lrv = list_init(&newContextMap->channelMapList);
3322 if (lrv < 0)
3323 {
3324 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3325 goto error;
3326 }
3327
3328 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3329 CHANNEL_MAP_seeker);
3330 if (lrv <0)
3331 {
3332 Log2(PCSC_LOG_CRITICAL,
3333 "list_attributes_seeker failed with return value: %d", lrv);
3334 list_destroy(&newContextMap->channelMapList);
3335 goto error;
3336 }
3337
3338 lrv = list_append(&contextMapList, newContextMap);
3339 if (lrv < 0)
3340 {
3341 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3342 lrv);
3343 list_destroy(&newContextMap->channelMapList);
3344 goto error;
3345 }
3346
3347 return SCARD_S_SUCCESS;
3348
3349error:
3350
3351 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3352 free(newContextMap);
3353
3354 return SCARD_E_NO_MEMORY;
3355}
3356
3374{
3375 SCONTEXTMAP * currentContextMap;
3376
3378 currentContextMap = SCardGetContextTH(hContext);
3379
3380 /* lock the context (if available) */
3381 if (NULL != currentContextMap)
3382 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3383
3385
3386 return currentContextMap;
3387}
3388
3402{
3403 return list_seek(&contextMapList, &hContext);
3404}
3405
3413{
3414 SCONTEXTMAP * currentContextMap;
3415 currentContextMap = SCardGetContextTH(hContext);
3416
3417 if (NULL != currentContextMap)
3418 SCardCleanContext(currentContextMap);
3419}
3420
3421static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3422{
3423 int list_index, lrv;
3424 int listSize;
3425 CHANNEL_MAP * currentChannelMap;
3426
3427 targetContextMap->hContext = 0;
3428 ClientCloseSession(targetContextMap->dwClientID);
3429 targetContextMap->dwClientID = 0;
3430 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3431
3432 listSize = list_size(&targetContextMap->channelMapList);
3433 for (list_index = 0; list_index < listSize; list_index++)
3434 {
3435 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3436 list_index);
3437 if (NULL == currentChannelMap)
3438 {
3439 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3440 list_index);
3441 continue;
3442 }
3443 else
3444 {
3445 free(currentChannelMap->readerName);
3446 free(currentChannelMap);
3447 }
3448
3449 }
3450 list_destroy(&targetContextMap->channelMapList);
3451
3452 lrv = list_delete(&contextMapList, targetContextMap);
3453 if (lrv < 0)
3454 {
3455 Log2(PCSC_LOG_CRITICAL,
3456 "list_delete failed with return value: %d", lrv);
3457 }
3458
3459 free(targetContextMap);
3460
3461 return;
3462}
3463
3464/*
3465 * Functions for managing hCard values returned from SCardConnect.
3466 */
3467
3468static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3469 LPCSTR readerName)
3470{
3471 CHANNEL_MAP * newChannelMap;
3472 int lrv = -1;
3473
3474 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3475 if (NULL == newChannelMap)
3476 return SCARD_E_NO_MEMORY;
3477
3478 newChannelMap->hCard = hCard;
3479 newChannelMap->readerName = strdup(readerName);
3480
3481 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3482 if (lrv < 0)
3483 {
3484 free(newChannelMap->readerName);
3485 free(newChannelMap);
3486 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3487 lrv);
3488 return SCARD_E_NO_MEMORY;
3489 }
3490
3491 return SCARD_S_SUCCESS;
3492}
3493
3494static void SCardRemoveHandle(SCARDHANDLE hCard)
3495{
3496 SCONTEXTMAP * currentContextMap;
3497 CHANNEL_MAP * currentChannelMap;
3498 int lrv;
3499 LONG rv;
3500
3501 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3502 &currentChannelMap);
3503 if (rv == -1)
3504 return;
3505
3506 free(currentChannelMap->readerName);
3507
3508 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3509 if (lrv < 0)
3510 {
3511 Log2(PCSC_LOG_CRITICAL,
3512 "list_delete failed with return value: %d", lrv);
3513 }
3514
3515 free(currentChannelMap);
3516
3517 return;
3518}
3519
3520static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3521 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3522{
3523 LONG rv;
3524
3525 if (0 == hCard)
3526 return -1;
3527
3529 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3530 targetChannelMap);
3531
3532 if (SCARD_S_SUCCESS == rv)
3533 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3534
3536
3537 return rv;
3538}
3539
3540static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3541 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3542{
3543 int listSize;
3544 int list_index;
3545 SCONTEXTMAP * currentContextMap;
3546 CHANNEL_MAP * currentChannelMap;
3547
3548 /* Best to get the caller a crash early if we fail unsafely */
3549 *targetContextMap = NULL;
3550 *targetChannelMap = NULL;
3551
3552 listSize = list_size(&contextMapList);
3553
3554 for (list_index = 0; list_index < listSize; list_index++)
3555 {
3556 currentContextMap = list_get_at(&contextMapList, list_index);
3557 if (currentContextMap == NULL)
3558 {
3559 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3560 list_index);
3561 continue;
3562 }
3563 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3564 &hCard);
3565 if (currentChannelMap != NULL)
3566 {
3567 *targetContextMap = currentContextMap;
3568 *targetChannelMap = currentChannelMap;
3569 return SCARD_S_SUCCESS;
3570 }
3571 }
3572
3573 return -1;
3574}
3575
3584{
3585 LONG rv;
3586 struct stat statBuffer;
3587 char *socketName;
3588
3589 socketName = getSocketName();
3590 rv = stat(socketName, &statBuffer);
3591
3592 if (rv != 0)
3593 {
3594 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3595 socketName, strerror(errno));
3596 return SCARD_E_NO_SERVICE;
3597 }
3598
3599 return SCARD_S_SUCCESS;
3600}
3601
3602static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3603{
3604 int32_t dwClientID = currentContextMap->dwClientID;
3605 LONG rv;
3607
3608 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3609 if (rv != SCARD_S_SUCCESS)
3610 return rv;
3611
3612 /* Read a message from the server */
3613 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3614 if (rv != SCARD_S_SUCCESS)
3615 return rv;
3616
3617 *readerEvents = get_reader_events.readerEvents;
3618
3619 return SCARD_S_SUCCESS;
3620}
3621
3622static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3623{
3624 int32_t dwClientID = currentContextMap->dwClientID;
3625 LONG rv;
3626
3627 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3628 if (rv != SCARD_S_SUCCESS)
3629 return rv;
3630
3631 /* Read a message from the server */
3632 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3633 if (rv != SCARD_S_SUCCESS)
3634 return rv;
3635
3636 return SCARD_S_SUCCESS;
3637}
3638
3639static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3640{
3641 int32_t dwClientID = currentContextMap->dwClientID;
3642 LONG rv;
3643
3644 /* Get current reader states from server and register on event list */
3646 0, NULL);
3647 if (rv != SCARD_S_SUCCESS)
3648 return rv;
3649
3650 /* Read a message from the server */
3651 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3652 return rv;
3653}
3654
3655static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3656{
3657 int32_t dwClientID = currentContextMap->dwClientID;
3658 LONG rv;
3659 struct wait_reader_state_change waitStatusStruct = {0};
3660
3661 /* ask server to remove us from the event list */
3663 dwClientID, 0, NULL);
3664 if (rv != SCARD_S_SUCCESS)
3665 return rv;
3666
3667 /* This message can be the response to
3668 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3669 * cancel notification.
3670 * The server side ensures, that no more messages will be sent to
3671 * the client. */
3672
3673 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3674 dwClientID);
3675 if (rv != SCARD_S_SUCCESS)
3676 return rv;
3677
3678 /* if we received a cancel event the return value will be set
3679 * accordingly */
3680 rv = waitStatusStruct.rv;
3681
3682 return rv;
3683}
3684
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()