pcsc-lite 2.0.1
winscard_clnt.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2005
9 * Martin Paljak <martin@paljak.pri.ee>
10 * Copyright (C) 2002-2011
11 * Ludovic Rousseau <ludovic.rousseau@free.fr>
12 * Copyright (C) 2009
13 * Jean-Luc Giraud <jlgiraud@googlemail.com>
14 *
15Redistribution and use in source and binary forms, with or without
16modification, are permitted provided that the following conditions
17are met:
18
191. Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
212. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
243. The name of the author may not be used to endorse or promote products
25 derived from this software without specific prior written permission.
26
27THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
105#include "config.h"
106#include <stdlib.h>
107#include <string.h>
108#include <sys/types.h>
109#include <fcntl.h>
110#include <unistd.h>
111#include <sys/un.h>
112#include <errno.h>
113#include <stddef.h>
114#include <sys/time.h>
115#include <pthread.h>
116#include <sys/wait.h>
117#include <stdbool.h>
118
119#include "misc.h"
120#include "pcscd.h"
121#include "winscard.h"
122#include "debuglog.h"
123
124#include "readerfactory.h"
125#include "eventhandler.h"
126#include "sys_generic.h"
127#include "winscard_msg.h"
128#include "utils.h"
129
130/* Display, on stderr, a trace of the WinSCard calls with arguments and
131 * results */
132//#define DO_TRACE
133
134/* Profile the execution time of WinSCard calls */
135//#define DO_PROFILE
136
137
138static bool sharing_shall_block = true;
139
140#define COLOR_RED "\33[01;31m"
141#define COLOR_GREEN "\33[32m"
142#define COLOR_BLUE "\33[34m"
143#define COLOR_MAGENTA "\33[35m"
144#define COLOR_NORMAL "\33[0m"
145
146#ifdef DO_TRACE
147
148#include <stdio.h>
149#include <stdarg.h>
150
151static void trace(const char *func, const char direction, const char *fmt, ...)
152{
153 va_list args;
154
155 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
156 direction, pthread_self(), func);
157
158 fprintf(stderr, COLOR_MAGENTA);
159 va_start(args, fmt);
160 vfprintf(stderr, fmt, args);
161 va_end(args);
162
163 fprintf(stderr, COLOR_NORMAL "\n");
164}
165
166#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
167#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
168#else
169#define API_TRACE_IN(...)
170#define API_TRACE_OUT(...)
171#endif
172
173#ifdef DO_PROFILE
174
175#define PROFILE_FILE "/tmp/pcsc_profile"
176#include <stdio.h>
177#include <sys/time.h>
178
179/* we can profile a maximum of 5 simultaneous calls */
180#define MAX_THREADS 5
181pthread_t threads[MAX_THREADS];
182struct timeval profile_time_start[MAX_THREADS];
183FILE *profile_fd;
184bool profile_tty;
185
186#define PROFILE_START profile_start();
187#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
188
189static void profile_start(void)
190{
191 static bool initialized = false;
192 pthread_t t;
193 int i;
194
195 if (!initialized)
196 {
197 char filename[80];
198
199 initialized = true;
200 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
201 profile_fd = fopen(filename, "a+");
202 if (NULL == profile_fd)
203 {
204 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
205 PROFILE_FILE, strerror(errno));
206 exit(-1);
207 }
208 fprintf(profile_fd, "\nStart a new profile\n");
209
210 if (isatty(fileno(stderr)))
211 profile_tty = true;
212 else
213 profile_tty = false;
214 }
215
216 t = pthread_self();
217 for (i=0; i<MAX_THREADS; i++)
218 if (pthread_equal(0, threads[i]))
219 {
220 threads[i] = t;
221 break;
222 }
223
224 gettimeofday(&profile_time_start[i], NULL);
225} /* profile_start */
226
227static void profile_end(const char *f, LONG rv)
228{
229 struct timeval profile_time_end;
230 long d;
231 pthread_t t;
232 int i;
233
234 gettimeofday(&profile_time_end, NULL);
235
236 t = pthread_self();
237 for (i=0; i<MAX_THREADS; i++)
238 if (pthread_equal(t, threads[i]))
239 break;
240
241 if (i>=MAX_THREADS)
242 {
243 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
244 return;
245 }
246
247 d = time_sub(&profile_time_end, &profile_time_start[i]);
248
249 /* free this entry */
250 threads[i] = 0;
251
252 if (profile_tty)
253 {
254 if (rv != SCARD_S_SUCCESS)
255 fprintf(stderr,
256 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
257 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
258 f, d, rv, pcsc_stringify_error(rv));
259 else
260 fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
261 COLOR_NORMAL "\n", f, d);
262 }
263 fprintf(profile_fd, "%s %ld\n", f, d);
264 fflush(profile_fd);
265} /* profile_end */
266
267#else
268#define PROFILE_START
269#define PROFILE_END(rv)
270#endif
271
277{
278 SCARDHANDLE hCard;
279 LPSTR readerName;
280};
281
282typedef struct _psChannelMap CHANNEL_MAP;
283
284static int CHANNEL_MAP_seeker(const void *el, const void *key)
285{
286 const CHANNEL_MAP * channelMap = el;
287
288 if ((el == NULL) || (key == NULL))
289 {
290 Log3(PCSC_LOG_CRITICAL,
291 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
292 el, key);
293 return 0;
294 }
295
296 if (channelMap->hCard == *(SCARDHANDLE *)key)
297 return 1;
298
299 return 0;
300}
301
308{
311 pthread_mutex_t mMutex;
312 list_t channelMapList;
314};
321
322static list_t contextMapList;
323
324static int SCONTEXTMAP_seeker(const void *el, const void *key)
325{
326 const SCONTEXTMAP * contextMap = el;
327
328 if ((el == NULL) || (key == NULL))
329 {
330 Log3(PCSC_LOG_CRITICAL,
331 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
332 el, key);
333 return 0;
334 }
335
336 if (contextMap->hContext == *(SCARDCONTEXT *) key)
337 return 1;
338
339 return 0;
340}
341
345static bool isExecuted = false;
346static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
347
348
353static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
354
359static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
360
367
368
369static LONG SCardAddContext(SCARDCONTEXT, DWORD);
373static void SCardCleanContext(SCONTEXTMAP *);
374
375static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
376static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
377 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
378static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
379 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380static void SCardRemoveHandle(SCARDHANDLE);
381
382static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
383 LPBYTE pbAttr, LPDWORD pcbAttrLen);
384
385static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
386static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
387static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
388
389/*
390 * Thread safety functions
391 */
398inline static void SCardLockThread(void)
399{
400 pthread_mutex_lock(&clientMutex);
401}
402
408inline static void SCardUnlockThread(void)
409{
410 pthread_mutex_unlock(&clientMutex);
411}
412
423{
424 SCONTEXTMAP * currentContextMap;
425
427 currentContextMap = SCardGetContextTH(hContext);
429
430 return currentContextMap != NULL;
431}
432
433static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
434 /*@out@*/ LPSCARDCONTEXT);
435
471LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
472 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
473{
474 LONG rv;
475
476 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
477 PROFILE_START
478
479 /* Check if the server is running */
481 if (rv != SCARD_S_SUCCESS)
482 goto end;
483
485 rv = SCardEstablishContextTH(dwScope, pvReserved1,
486 pvReserved2, phContext);
488
489end:
490 PROFILE_END(rv)
491 API_TRACE_OUT("%ld", *phContext)
492
493 return rv;
494}
495
496#ifdef DESTRUCTOR
497DESTRUCTOR static void destructor(void)
498{
499 list_destroy(&contextMapList);
500}
501#endif
502
503/*
504 * Do this only once:
505 * - Initialize context list.
506 */
507static void init_lib(void)
508{
509 int lrv;
510
511 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
512 * Applications which load and unload the library may leak
513 * the list's internal structures. */
514 lrv = list_init(&contextMapList);
515 if (lrv < 0)
516 {
517 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
518 lrv);
519 return;
520 }
521
522 lrv = list_attributes_seeker(&contextMapList,
523 SCONTEXTMAP_seeker);
524 if (lrv <0)
525 {
526 Log2(PCSC_LOG_CRITICAL,
527 "list_attributes_seeker failed with return value: %d", lrv);
528 list_destroy(&contextMapList);
529 return;
530 }
531
532 if (getenv("PCSCLITE_NO_BLOCKING"))
533 {
534 Log1(PCSC_LOG_INFO, "Disable shared blocking");
535 sharing_shall_block = false;
536 }
537
538 isExecuted = true;
539}
540
568static LONG SCardEstablishContextTH(DWORD dwScope,
569 /*@unused@*/ LPCVOID pvReserved1,
570 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
571{
572 LONG rv;
573 struct establish_struct scEstablishStruct;
574 uint32_t dwClientID = 0;
575
576 (void)pvReserved1;
577 (void)pvReserved2;
578 if (phContext == NULL)
580 else
581 *phContext = 0;
582
583 pthread_once(&init_lib_control, init_lib);
584 if (!isExecuted)
585 return SCARD_E_NO_MEMORY;
586
587 /* Establishes a connection to the server */
588 if (ClientSetupSession(&dwClientID) != 0)
589 {
590 return SCARD_E_NO_SERVICE;
591 }
592
593 { /* exchange client/server protocol versions */
594 struct version_struct veStr;
595
598 veStr.rv = SCARD_S_SUCCESS;
599
600 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
601 &veStr);
602 if (rv != SCARD_S_SUCCESS)
603 goto cleanup;
604
605 /* Read a message from the server */
606 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
607 if (rv != SCARD_S_SUCCESS)
608 {
609 Log1(PCSC_LOG_CRITICAL,
610 "Your pcscd is too old and does not support CMD_VERSION");
611 goto cleanup;
612 }
613
614 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
615 veStr.major, veStr.minor);
616
617 if (veStr.rv != SCARD_S_SUCCESS)
618 {
619 rv = veStr.rv;
620 goto cleanup;
621 }
622 }
623
624again:
625 /*
626 * Try to establish an Application Context with the server
627 */
628 scEstablishStruct.dwScope = dwScope;
629 scEstablishStruct.hContext = 0;
630 scEstablishStruct.rv = SCARD_S_SUCCESS;
631
633 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
634
635 if (rv != SCARD_S_SUCCESS)
636 goto cleanup;
637
638 /*
639 * Read the response from the server
640 */
641 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
642 dwClientID);
643
644 if (rv != SCARD_S_SUCCESS)
645 goto cleanup;
646
647 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
648 {
649 rv = scEstablishStruct.rv;
650 goto cleanup;
651 }
652
653 /* check we do not reuse an existing hContext */
654 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
655 /* we do not need to release the allocated context since
656 * SCardReleaseContext() does nothing on the server side */
657 goto again;
658
659 *phContext = scEstablishStruct.hContext;
660
661 /*
662 * Allocate the new hContext - if allocator full return an error
663 */
664 rv = SCardAddContext(*phContext, dwClientID);
665
666 return rv;
667
668cleanup:
669 ClientCloseSession(dwClientID);
670
671 return rv;
672}
673
695LONG SCardReleaseContext(SCARDCONTEXT hContext)
696{
697 LONG rv;
698 struct release_struct scReleaseStruct;
699 SCONTEXTMAP * currentContextMap;
700
701 API_TRACE_IN("%ld", hContext)
702 PROFILE_START
703
704 /*
705 * Make sure this context has been opened
706 * and get currentContextMap
707 */
708 currentContextMap = SCardGetAndLockContext(hContext);
709 if (NULL == currentContextMap)
710 {
712 goto error;
713 }
714
715 scReleaseStruct.hContext = hContext;
716 scReleaseStruct.rv = SCARD_S_SUCCESS;
717
719 currentContextMap->dwClientID,
720 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
721
722 if (rv != SCARD_S_SUCCESS)
723 goto end;
724
725 /*
726 * Read a message from the server
727 */
728 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
729 currentContextMap->dwClientID);
730
731 if (rv != SCARD_S_SUCCESS)
732 goto end;
733
734 rv = scReleaseStruct.rv;
735end:
736 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
737
738 /*
739 * Remove the local context from the stack
740 */
742 SCardRemoveContext(hContext);
744
745error:
746 PROFILE_END(rv)
747 API_TRACE_OUT("")
748
749 return rv;
750}
751
807LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
808 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
809 LPDWORD pdwActiveProtocol)
810{
811 LONG rv;
812 struct connect_struct scConnectStruct;
813 SCONTEXTMAP * currentContextMap;
814
815 PROFILE_START
816 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
817
818 /*
819 * Check for NULL parameters
820 */
821 if (phCard == NULL || pdwActiveProtocol == NULL)
823 else
824 *phCard = 0;
825
826 if (szReader == NULL)
828
829 /*
830 * Check for uninitialized strings
831 */
832 if (strlen(szReader) > MAX_READERNAME)
834
835 /*
836 * Make sure this context has been opened
837 */
838 currentContextMap = SCardGetAndLockContext(hContext);
839 if (NULL == currentContextMap)
841
842 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
843 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
844 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
845
846 scConnectStruct.hContext = hContext;
847 scConnectStruct.dwShareMode = dwShareMode;
848 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
849 scConnectStruct.hCard = 0;
850 scConnectStruct.dwActiveProtocol = 0;
851 scConnectStruct.rv = SCARD_S_SUCCESS;
852
853 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
854 sizeof(scConnectStruct), (void *) &scConnectStruct);
855
856 if (rv != SCARD_S_SUCCESS)
857 goto end;
858
859 /*
860 * Read a message from the server
861 */
862 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
863 currentContextMap->dwClientID);
864
865 if (rv != SCARD_S_SUCCESS)
866 goto end;
867
868 *phCard = scConnectStruct.hCard;
869 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
870
871 if (scConnectStruct.rv == SCARD_S_SUCCESS)
872 {
873 /*
874 * Keep track of the handle locally
875 */
876 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
877 }
878 else
879 rv = scConnectStruct.rv;
880
881end:
882 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
883
884 PROFILE_END(rv)
885 API_TRACE_OUT("%d", *pdwActiveProtocol)
886
887 return rv;
888}
889
962LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
963 DWORD dwPreferredProtocols, DWORD dwInitialization,
964 LPDWORD pdwActiveProtocol)
965{
966 LONG rv;
967 struct reconnect_struct scReconnectStruct;
968 SCONTEXTMAP * currentContextMap;
969 CHANNEL_MAP * pChannelMap;
970
971 PROFILE_START
972 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
973
974 if (pdwActiveProtocol == NULL)
976
977 /* Retry loop for blocking behaviour */
978retry:
979
980 /*
981 * Make sure this handle has been opened
982 */
983 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
984 &pChannelMap);
985 if (rv == -1)
987
988 scReconnectStruct.hCard = hCard;
989 scReconnectStruct.dwShareMode = dwShareMode;
990 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
991 scReconnectStruct.dwInitialization = dwInitialization;
992 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
993 scReconnectStruct.rv = SCARD_S_SUCCESS;
994
995 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
996 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
997
998 if (rv != SCARD_S_SUCCESS)
999 goto end;
1000
1001 /*
1002 * Read a message from the server
1003 */
1004 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1005 currentContextMap->dwClientID);
1006
1007 if (rv != SCARD_S_SUCCESS)
1008 goto end;
1009
1010 rv = scReconnectStruct.rv;
1011
1012 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1013 {
1014 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1016 goto retry;
1017 }
1018
1019 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1020
1021end:
1022 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1023
1024 PROFILE_END(rv)
1025 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1026
1027 return rv;
1028}
1029
1061LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1062{
1063 LONG rv;
1064 struct disconnect_struct scDisconnectStruct;
1065 SCONTEXTMAP * currentContextMap;
1066 CHANNEL_MAP * pChannelMap;
1067
1068 PROFILE_START
1069 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1070
1071 /*
1072 * Make sure this handle has been opened
1073 */
1074 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1075 &pChannelMap);
1076 if (rv == -1)
1077 {
1079 goto error;
1080 }
1081
1082 scDisconnectStruct.hCard = hCard;
1083 scDisconnectStruct.dwDisposition = dwDisposition;
1084 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1085
1086 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1087 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1088
1089 if (rv != SCARD_S_SUCCESS)
1090 goto end;
1091
1092 /*
1093 * Read a message from the server
1094 */
1095 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1096 currentContextMap->dwClientID);
1097
1098 if (rv != SCARD_S_SUCCESS)
1099 goto end;
1100
1101 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1102 SCardRemoveHandle(hCard);
1103 rv = scDisconnectStruct.rv;
1104
1105end:
1106 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1107
1108error:
1109 PROFILE_END(rv)
1110 API_TRACE_OUT("")
1111
1112 return rv;
1113}
1114
1151LONG SCardBeginTransaction(SCARDHANDLE hCard)
1152{
1153
1154 LONG rv;
1155 struct begin_struct scBeginStruct;
1156 SCONTEXTMAP * currentContextMap;
1157 CHANNEL_MAP * pChannelMap;
1158
1159 PROFILE_START
1160 API_TRACE_IN("%ld", hCard)
1161
1162 /*
1163 * Query the server every so often until the sharing violation ends
1164 * and then hold the lock for yourself.
1165 */
1166
1167 for(;;)
1168 {
1169 /*
1170 * Make sure this handle has been opened
1171 */
1172 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1173 &pChannelMap);
1174 if (rv == -1)
1176
1177 scBeginStruct.hCard = hCard;
1178 scBeginStruct.rv = SCARD_S_SUCCESS;
1179
1181 currentContextMap->dwClientID,
1182 sizeof(scBeginStruct), (void *) &scBeginStruct);
1183
1184 if (rv != SCARD_S_SUCCESS)
1185 break;
1186
1187 /*
1188 * Read a message from the server
1189 */
1190 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1191 currentContextMap->dwClientID);
1192
1193 if (rv != SCARD_S_SUCCESS)
1194 break;
1195
1196 rv = scBeginStruct.rv;
1197
1198 if (SCARD_E_SHARING_VIOLATION != rv)
1199 break;
1200
1201 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1203 }
1204
1205 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1206
1207 PROFILE_END(rv)
1208 API_TRACE_OUT("")
1209
1210 return rv;
1211}
1212
1252LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1253{
1254 LONG rv;
1255 struct end_struct scEndStruct;
1256 SCONTEXTMAP * currentContextMap;
1257 CHANNEL_MAP * pChannelMap;
1258
1259 PROFILE_START
1260 API_TRACE_IN("%ld", hCard)
1261
1262 /*
1263 * Make sure this handle has been opened
1264 */
1265 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1266 &pChannelMap);
1267 if (rv == -1)
1269
1270 scEndStruct.hCard = hCard;
1271 scEndStruct.dwDisposition = dwDisposition;
1272 scEndStruct.rv = SCARD_S_SUCCESS;
1273
1275 currentContextMap->dwClientID,
1276 sizeof(scEndStruct), (void *) &scEndStruct);
1277
1278 if (rv != SCARD_S_SUCCESS)
1279 goto end;
1280
1281 /*
1282 * Read a message from the server
1283 */
1284 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1285 currentContextMap->dwClientID);
1286
1287 if (rv != SCARD_S_SUCCESS)
1288 goto end;
1289
1290 rv = scEndStruct.rv;
1291
1292end:
1293 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1294
1295 PROFILE_END(rv)
1296 API_TRACE_OUT("")
1297
1298 return rv;
1299}
1300
1396LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1397 LPDWORD pcchReaderLen, LPDWORD pdwState,
1398 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1399{
1400 DWORD dwReaderLen, dwAtrLen;
1401 LONG rv;
1402 int i;
1403 struct status_struct scStatusStruct;
1404 SCONTEXTMAP * currentContextMap;
1405 CHANNEL_MAP * pChannelMap;
1406 char *r;
1407 char *bufReader = NULL;
1408 LPBYTE bufAtr = NULL;
1409 DWORD dummy = 0;
1410
1411 PROFILE_START
1412
1413 /* default output values */
1414 if (pdwState)
1415 *pdwState = 0;
1416
1417 if (pdwProtocol)
1418 *pdwProtocol = 0;
1419
1420 /* Check for NULL parameters */
1421 if (pcchReaderLen == NULL)
1422 pcchReaderLen = &dummy;
1423
1424 if (pcbAtrLen == NULL)
1425 pcbAtrLen = &dummy;
1426
1427 /* length passed from caller */
1428 dwReaderLen = *pcchReaderLen;
1429 dwAtrLen = *pcbAtrLen;
1430
1431 *pcchReaderLen = 0;
1432 *pcbAtrLen = 0;
1433
1434 /* Retry loop for blocking behaviour */
1435retry:
1436
1437 /*
1438 * Make sure this handle has been opened
1439 */
1440 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1441 &pChannelMap);
1442 if (rv == -1)
1444
1445 /* lock access to readerStates[] */
1446 (void)pthread_mutex_lock(&readerStatesMutex);
1447
1448 /* synchronize reader states with daemon */
1449 rv = getReaderStates(currentContextMap);
1450 if (rv != SCARD_S_SUCCESS)
1451 goto end;
1452
1453 r = pChannelMap->readerName;
1454 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1455 {
1456 /* by default r == NULL */
1457 if (r && strcmp(r, readerStates[i].readerName) == 0)
1458 break;
1459 }
1460
1462 {
1464 goto end;
1465 }
1466
1467 /* initialise the structure */
1468 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1469 scStatusStruct.hCard = hCard;
1470
1471 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1472 sizeof(scStatusStruct), (void *) &scStatusStruct);
1473
1474 if (rv != SCARD_S_SUCCESS)
1475 goto end;
1476
1477 /*
1478 * Read a message from the server
1479 */
1480 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1481 currentContextMap->dwClientID);
1482
1483 if (rv != SCARD_S_SUCCESS)
1484 goto end;
1485
1486 rv = scStatusStruct.rv;
1487
1488 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1489 {
1490 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1491 (void)pthread_mutex_unlock(&readerStatesMutex);
1493 goto retry;
1494 }
1495
1497 {
1498 /*
1499 * An event must have occurred
1500 */
1501 goto end;
1502 }
1503
1504 /*
1505 * Now continue with the client side SCardStatus
1506 */
1507
1508 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1509 *pcbAtrLen = readerStates[i].cardAtrLength;
1510
1511 if (pdwState)
1512 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1513
1514 if (pdwProtocol)
1515 *pdwProtocol = readerStates[i].cardProtocol;
1516
1517 if (SCARD_AUTOALLOCATE == dwReaderLen)
1518 {
1519 dwReaderLen = *pcchReaderLen;
1520 if (NULL == szReaderName)
1521 {
1523 goto end;
1524 }
1525 bufReader = malloc(dwReaderLen);
1526 if (NULL == bufReader)
1527 {
1528 rv = SCARD_E_NO_MEMORY;
1529 goto end;
1530 }
1531 *(char **)szReaderName = bufReader;
1532 }
1533 else
1534 bufReader = szReaderName;
1535
1536 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1537 if (bufReader)
1538 {
1539 if (*pcchReaderLen > dwReaderLen)
1541
1542 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1543 }
1544
1545 if (SCARD_AUTOALLOCATE == dwAtrLen)
1546 {
1547 dwAtrLen = *pcbAtrLen;
1548 if (NULL == pbAtr)
1549 {
1551 goto end;
1552 }
1553 bufAtr = malloc(dwAtrLen);
1554 if (NULL == bufAtr)
1555 {
1556 rv = SCARD_E_NO_MEMORY;
1557 goto end;
1558 }
1559 *(LPBYTE *)pbAtr = bufAtr;
1560 }
1561 else
1562 bufAtr = pbAtr;
1563
1564 if (bufAtr)
1565 {
1566 if (*pcbAtrLen > dwAtrLen)
1568
1569 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1570 }
1571
1572end:
1573 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1574 (void)pthread_mutex_unlock(&readerStatesMutex);
1575
1576 PROFILE_END(rv)
1577
1578 return rv;
1579}
1580
1688LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1689 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1690{
1691 SCARD_READERSTATE *currReader;
1692 READER_STATE *rContext;
1693 long dwTime;
1694 DWORD dwBreakFlag = 0;
1695 unsigned int j;
1696 SCONTEXTMAP * currentContextMap;
1697 int currentReaderCount = 0;
1698 LONG rv = SCARD_S_SUCCESS;
1699
1700 PROFILE_START
1701 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1702#ifdef DO_TRACE
1703 for (j=0; j<cReaders; j++)
1704 {
1705 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1706 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1707 }
1708#endif
1709
1710 if ((rgReaderStates == NULL && cReaders > 0)
1711 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1712 {
1714 goto error;
1715 }
1716
1717 /* Check the integrity of the reader states structures */
1718 for (j = 0; j < cReaders; j++)
1719 {
1720 if (rgReaderStates[j].szReader == NULL)
1721 return SCARD_E_INVALID_VALUE;
1722 }
1723
1724 /* return if all readers are SCARD_STATE_IGNORE */
1725 if (cReaders > 0)
1726 {
1727 int nbNonIgnoredReaders = cReaders;
1728
1729 for (j=0; j<cReaders; j++)
1730 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1731 nbNonIgnoredReaders--;
1732
1733 if (0 == nbNonIgnoredReaders)
1734 {
1735 rv = SCARD_S_SUCCESS;
1736 goto error;
1737 }
1738 }
1739 else
1740 {
1741 /* reader list is empty */
1742 rv = SCARD_S_SUCCESS;
1743 goto error;
1744 }
1745
1746 /*
1747 * Make sure this context has been opened
1748 */
1749 currentContextMap = SCardGetAndLockContext(hContext);
1750 if (NULL == currentContextMap)
1751 {
1753 goto error;
1754 }
1755
1756 /* lock access to readerStates[] */
1757 (void)pthread_mutex_lock(&readerStatesMutex);
1758
1759 /* synchronize reader states with daemon */
1760 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1761
1762 if (rv != SCARD_S_SUCCESS)
1763 {
1764 (void)pthread_mutex_unlock(&readerStatesMutex);
1765 goto end;
1766 }
1767
1768 /* check all the readers are already known */
1769 for (j=0; j<cReaders; j++)
1770 {
1771 const char *readerName;
1772 int i;
1773
1774 readerName = rgReaderStates[j].szReader;
1775 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1776 {
1777 if (strcmp(readerName, readerStates[i].readerName) == 0)
1778 break;
1779 }
1780
1781 /* The requested reader name is not recognized */
1783 {
1784 /* PnP special reader? */
1785 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1786 {
1788 (void)pthread_mutex_unlock(&readerStatesMutex);
1789 goto end;
1790 }
1791 }
1792 }
1793 (void)pthread_mutex_unlock(&readerStatesMutex);
1794
1795 /* Clear the event state for all readers */
1796 for (j = 0; j < cReaders; j++)
1797 rgReaderStates[j].dwEventState = 0;
1798
1799 /* Now is where we start our event checking loop */
1800 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1801
1802 /* Get the initial reader count on the system */
1803 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1804 if (readerStates[j].readerName[0] != '\0')
1805 currentReaderCount++;
1806
1807 /* catch possible sign extension problems from 32 to 64-bits integers */
1808 if ((DWORD)-1 == dwTimeout)
1809 dwTimeout = INFINITE;
1810 if (INFINITE == dwTimeout)
1811 dwTime = 60*1000; /* "infinite" timeout */
1812 else
1813 dwTime = dwTimeout;
1814
1815 j = 0;
1816 do
1817 {
1818 currReader = &rgReaderStates[j];
1819
1820 /* Ignore for IGNORED readers */
1821 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1822 {
1823 const char *readerName;
1824 int i;
1825
1826 /* lock access to readerStates[] */
1827 (void)pthread_mutex_lock(&readerStatesMutex);
1828
1829 /* Looks for correct readernames */
1830 readerName = currReader->szReader;
1831 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1832 {
1833 if (strcmp(readerName, readerStates[i].readerName) == 0)
1834 break;
1835 }
1836
1837 /* The requested reader name is not recognized */
1839 {
1840 /* PnP special reader? */
1841 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1842 {
1843 int k, newReaderCount = 0;
1844
1845 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1846 if (readerStates[k].readerName[0] != '\0')
1847 newReaderCount++;
1848
1849 if (newReaderCount != currentReaderCount)
1850 {
1851 Log1(PCSC_LOG_INFO, "Reader list changed");
1852 currentReaderCount = newReaderCount;
1853
1854 currReader->dwEventState |= SCARD_STATE_CHANGED;
1855 dwBreakFlag = 1;
1856 }
1857 }
1858 else
1859 {
1860 currReader->dwEventState =
1862 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1863 {
1864 currReader->dwEventState |= SCARD_STATE_CHANGED;
1865 /*
1866 * Spec says use SCARD_STATE_IGNORE but a removed USB
1867 * reader with eventState fed into currentState will
1868 * be ignored forever
1869 */
1870 dwBreakFlag = 1;
1871 }
1872 }
1873 }
1874 else
1875 {
1876 uint32_t readerState;
1877
1878 /* The reader has come back after being away */
1879 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1880 {
1881 currReader->dwEventState |= SCARD_STATE_CHANGED;
1882 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1883 Log0(PCSC_LOG_DEBUG);
1884 dwBreakFlag = 1;
1885 }
1886
1887 /* Set the reader status structure */
1888 rContext = &readerStates[i];
1889
1890 /* Now we check all the Reader States */
1891 readerState = rContext->readerState;
1892
1893 /* only if current state has an non null event counter */
1894 if (currReader->dwCurrentState & 0xFFFF0000)
1895 {
1896 unsigned int currentCounter;
1897
1898 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1899
1900 /* has the event counter changed since the last call? */
1901 if (rContext->eventCounter != currentCounter)
1902 {
1903 currReader->dwEventState |= SCARD_STATE_CHANGED;
1904 Log0(PCSC_LOG_DEBUG);
1905 dwBreakFlag = 1;
1906 }
1907 }
1908
1909 /* add an event counter in the upper word of dwEventState */
1910 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1911 | (rContext->eventCounter << 16));
1912
1913 /* Check if the reader is in the correct state */
1914 if (readerState & SCARD_UNKNOWN)
1915 {
1916 /* reader is in bad state */
1917 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1918 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1919 {
1920 /* App thinks reader is in good state and it is not */
1921 currReader->dwEventState |= SCARD_STATE_CHANGED;
1922 Log0(PCSC_LOG_DEBUG);
1923 dwBreakFlag = 1;
1924 }
1925 }
1926 else
1927 {
1928 /* App thinks reader in bad state but it is not */
1929 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1930 {
1931 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1932 currReader->dwEventState |= SCARD_STATE_CHANGED;
1933 Log0(PCSC_LOG_DEBUG);
1934 dwBreakFlag = 1;
1935 }
1936 }
1937
1938 /* Check for card presence in the reader */
1939 if (readerState & SCARD_PRESENT)
1940 {
1941#ifndef DISABLE_AUTO_POWER_ON
1942 /* card present but not yet powered up */
1943 if (0 == rContext->cardAtrLength)
1944 /* Allow the status thread to convey information */
1946#endif
1947
1948 currReader->cbAtr = rContext->cardAtrLength;
1949 memcpy(currReader->rgbAtr, rContext->cardAtr,
1950 currReader->cbAtr);
1951 }
1952 else
1953 currReader->cbAtr = 0;
1954
1955 /* Card is now absent */
1956 if (readerState & SCARD_ABSENT)
1957 {
1958 currReader->dwEventState |= SCARD_STATE_EMPTY;
1959 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1960 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1961 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1962 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1963 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1964 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1965 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1966 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1967
1968 /* After present the rest are assumed */
1969 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1970 {
1971 currReader->dwEventState |= SCARD_STATE_CHANGED;
1972 Log0(PCSC_LOG_DEBUG);
1973 dwBreakFlag = 1;
1974 }
1975 }
1976 /* Card is now present */
1977 else if (readerState & SCARD_PRESENT)
1978 {
1979 currReader->dwEventState |= SCARD_STATE_PRESENT;
1980 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1981 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1982 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1983 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1984 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1985 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1986
1987 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1988 {
1989 currReader->dwEventState |= SCARD_STATE_CHANGED;
1990 Log0(PCSC_LOG_DEBUG);
1991 dwBreakFlag = 1;
1992 }
1993
1994 if (readerState & SCARD_SWALLOWED)
1995 {
1996 currReader->dwEventState |= SCARD_STATE_MUTE;
1997 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1998 {
1999 currReader->dwEventState |= SCARD_STATE_CHANGED;
2000 Log0(PCSC_LOG_DEBUG);
2001 dwBreakFlag = 1;
2002 }
2003 }
2004 else
2005 {
2006 /* App thinks card is mute but it is not */
2007 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2008 {
2009 currReader->dwEventState |= SCARD_STATE_CHANGED;
2010 Log0(PCSC_LOG_DEBUG);
2011 dwBreakFlag = 1;
2012 }
2013 }
2014 }
2015
2016 /* Now figure out sharing modes */
2018 {
2019 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2020 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2021 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2022 {
2023 currReader->dwEventState |= SCARD_STATE_CHANGED;
2024 Log0(PCSC_LOG_DEBUG);
2025 dwBreakFlag = 1;
2026 }
2027 }
2028 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2029 {
2030 /* A card must be inserted for it to be INUSE */
2031 if (readerState & SCARD_PRESENT)
2032 {
2033 currReader->dwEventState |= SCARD_STATE_INUSE;
2034 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2035 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2036 {
2037 currReader->dwEventState |= SCARD_STATE_CHANGED;
2038 Log0(PCSC_LOG_DEBUG);
2039 dwBreakFlag = 1;
2040 }
2041 }
2042 }
2043 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2044 {
2045 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2046 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2047
2048 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2049 {
2050 currReader->dwEventState |= SCARD_STATE_CHANGED;
2051 Log0(PCSC_LOG_DEBUG);
2052 dwBreakFlag = 1;
2053 }
2054 else if (currReader-> dwCurrentState
2056 {
2057 currReader->dwEventState |= SCARD_STATE_CHANGED;
2058 Log0(PCSC_LOG_DEBUG);
2059 dwBreakFlag = 1;
2060 }
2061 }
2062
2063 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2064 {
2065 /*
2066 * Break out of the while .. loop and return status
2067 * once all the status's for all readers is met
2068 */
2069 currReader->dwEventState |= SCARD_STATE_CHANGED;
2070 Log0(PCSC_LOG_DEBUG);
2071 dwBreakFlag = 1;
2072 }
2073 } /* End of SCARD_STATE_UNKNOWN */
2074
2075 (void)pthread_mutex_unlock(&readerStatesMutex);
2076 } /* End of SCARD_STATE_IGNORE */
2077
2078 /* Counter and resetter */
2079 j++;
2080 if (j == cReaders)
2081 {
2082 /* go back to the first reader */
2083 j = 0;
2084
2085 /* Declare all the break conditions */
2086
2087 /* Break if UNAWARE is set and all readers have been checked */
2088 if (dwBreakFlag == 1)
2089 break;
2090
2091 /* Only sleep once for each cycle of reader checks. */
2092 {
2093 struct wait_reader_state_change waitStatusStruct = {0};
2094 struct timeval before, after;
2095
2096 gettimeofday(&before, NULL);
2097
2098 waitStatusStruct.rv = SCARD_S_SUCCESS;
2099
2100 /* another thread can do SCardCancel() */
2101 currentContextMap->cancellable = true;
2102
2103 /*
2104 * Read a message from the server
2105 */
2107 &waitStatusStruct, sizeof(waitStatusStruct),
2108 currentContextMap->dwClientID, dwTime);
2109
2110 /* SCardCancel() will return immediately with success
2111 * because something changed on the daemon side. */
2112 currentContextMap->cancellable = false;
2113
2114 /* timeout */
2115 if (SCARD_E_TIMEOUT == rv)
2116 {
2117 /* ask server to remove us from the event list */
2118 rv = unregisterFromEvents(currentContextMap);
2119 }
2120
2121 if (rv != SCARD_S_SUCCESS)
2122 goto end;
2123
2124 /* an event occurs or SCardCancel() was called */
2125 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2126 {
2127 rv = waitStatusStruct.rv;
2128 goto end;
2129 }
2130
2131 /* synchronize reader states with daemon */
2132 (void)pthread_mutex_lock(&readerStatesMutex);
2133 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2134 (void)pthread_mutex_unlock(&readerStatesMutex);
2135 if (rv != SCARD_S_SUCCESS)
2136 goto end;
2137
2138 if (INFINITE != dwTimeout)
2139 {
2140 long int diff;
2141
2142 gettimeofday(&after, NULL);
2143 diff = time_sub(&after, &before);
2144 dwTime -= diff/1000;
2145 }
2146 }
2147
2148 if (dwTimeout != INFINITE)
2149 {
2150 /* If time is greater than timeout and all readers have been
2151 * checked
2152 */
2153 if (dwTime <= 0)
2154 {
2155 rv = SCARD_E_TIMEOUT;
2156 goto end;
2157 }
2158 }
2159 }
2160 }
2161 while (1);
2162
2163end:
2164 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2165
2166 /* if SCardCancel() has been used then the client is already
2167 * unregistered */
2168 if (SCARD_E_CANCELLED != rv)
2169 (void)unregisterFromEvents(currentContextMap);
2170
2171 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2172
2173error:
2174 PROFILE_END(rv)
2175#ifdef DO_TRACE
2176 for (j=0; j<cReaders; j++)
2177 {
2178 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2179 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2180 }
2181#endif
2182
2183 return rv;
2184}
2185
2236LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2237 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2238 LPDWORD lpBytesReturned)
2239{
2240 LONG rv;
2241 struct control_struct scControlStruct;
2242 SCONTEXTMAP * currentContextMap;
2243 CHANNEL_MAP * pChannelMap;
2244
2245 PROFILE_START
2246
2247 /* 0 bytes received by default */
2248 if (NULL != lpBytesReturned)
2249 *lpBytesReturned = 0;
2250
2251 /*
2252 * Make sure this handle has been opened
2253 */
2254 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2255 &pChannelMap);
2256 if (rv == -1)
2257 {
2258 PROFILE_END(SCARD_E_INVALID_HANDLE)
2260 }
2261
2262 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2263 {
2265 goto end;
2266 }
2267
2268 scControlStruct.hCard = hCard;
2269 scControlStruct.dwControlCode = dwControlCode;
2270 scControlStruct.cbSendLength = cbSendLength;
2271 scControlStruct.cbRecvLength = cbRecvLength;
2272 scControlStruct.dwBytesReturned = 0;
2273 scControlStruct.rv = 0;
2274
2275 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2276 sizeof(scControlStruct), &scControlStruct);
2277
2278 if (rv != SCARD_S_SUCCESS)
2279 goto end;
2280
2281 /* write the sent buffer */
2282 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2283 currentContextMap->dwClientID);
2284
2285 if (rv != SCARD_S_SUCCESS)
2286 goto end;
2287
2288 /*
2289 * Read a message from the server
2290 */
2291 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2292 currentContextMap->dwClientID);
2293
2294 if (rv != SCARD_S_SUCCESS)
2295 goto end;
2296
2297 if (SCARD_S_SUCCESS == scControlStruct.rv)
2298 {
2299 if (scControlStruct.dwBytesReturned > cbRecvLength)
2300 {
2301 if (NULL != lpBytesReturned)
2302 *lpBytesReturned = scControlStruct.dwBytesReturned;
2304 goto end;
2305 }
2306
2307 /* read the received buffer */
2308 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2309 currentContextMap->dwClientID);
2310
2311 if (rv != SCARD_S_SUCCESS)
2312 goto end;
2313
2314 }
2315
2316 if (NULL != lpBytesReturned)
2317 *lpBytesReturned = scControlStruct.dwBytesReturned;
2318
2319 rv = scControlStruct.rv;
2320
2321end:
2322 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2323
2324 PROFILE_END(rv)
2325
2326 return rv;
2327}
2328
2447LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2448 LPDWORD pcbAttrLen)
2449{
2450 LONG ret;
2451 unsigned char *buf = NULL;
2452
2453 PROFILE_START
2454
2455 if (NULL == pcbAttrLen)
2456 {
2458 goto end;
2459 }
2460
2461 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2462 {
2463 if (NULL == pbAttr)
2465
2466 *pcbAttrLen = MAX_BUFFER_SIZE;
2467 buf = malloc(*pcbAttrLen);
2468 if (NULL == buf)
2469 {
2470 ret = SCARD_E_NO_MEMORY;
2471 goto end;
2472 }
2473
2474 *(unsigned char **)pbAttr = buf;
2475 }
2476 else
2477 {
2478 buf = pbAttr;
2479
2480 /* if only get the length */
2481 if (NULL == pbAttr)
2482 /* use a reasonable size */
2483 *pcbAttrLen = MAX_BUFFER_SIZE;
2484 }
2485
2486 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2487 pcbAttrLen);
2488
2489end:
2490 PROFILE_END(ret)
2491
2492 return ret;
2493}
2494
2530LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2531 DWORD cbAttrLen)
2532{
2533 LONG ret;
2534
2535 PROFILE_START
2536
2537 if (NULL == pbAttr || 0 == cbAttrLen)
2539
2540 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2541 &cbAttrLen);
2542
2543 PROFILE_END(ret)
2544
2545 return ret;
2546}
2547
2548static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2549 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2550{
2551 LONG rv;
2552 struct getset_struct scGetSetStruct;
2553 SCONTEXTMAP * currentContextMap;
2554 CHANNEL_MAP * pChannelMap;
2555
2556 /*
2557 * Make sure this handle has been opened
2558 */
2559 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2560 &pChannelMap);
2561 if (rv == -1)
2563
2564 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2565 {
2567 goto end;
2568 }
2569
2570 scGetSetStruct.hCard = hCard;
2571 scGetSetStruct.dwAttrId = dwAttrId;
2572 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2573 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2574 if (SCARD_SET_ATTRIB == command)
2575 {
2576 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2577 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2578 }
2579 else
2580 /* we can get up to the communication buffer size */
2581 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2582
2583 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2584 sizeof(scGetSetStruct), &scGetSetStruct);
2585
2586 if (rv != SCARD_S_SUCCESS)
2587 goto end;
2588
2589 /*
2590 * Read a message from the server
2591 */
2592 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2593 currentContextMap->dwClientID);
2594
2595 if (rv != SCARD_S_SUCCESS)
2596 goto end;
2597
2598 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2599 {
2600 /*
2601 * Copy and zero it so any secret information is not leaked
2602 */
2603 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2604 {
2605 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2606 * buffer overflow in the memcpy() below */
2607 DWORD correct_value = scGetSetStruct.cbAttrLen;
2608 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2609 *pcbAttrLen = correct_value;
2610
2611 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2612 }
2613 else
2614 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2615
2616 if (pbAttr)
2617 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2618
2619 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2620 }
2621 rv = scGetSetStruct.rv;
2622
2623end:
2624 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2625
2626 return rv;
2627}
2628
2687LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2688 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2689 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2690 LPDWORD pcbRecvLength)
2691{
2692 LONG rv;
2693 SCONTEXTMAP * currentContextMap;
2694 CHANNEL_MAP * pChannelMap;
2695 struct transmit_struct scTransmitStruct;
2696
2697 PROFILE_START
2698
2699 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2700 pcbRecvLength == NULL || pioSendPci == NULL)
2702
2703 /* Retry loop for blocking behaviour */
2704retry:
2705
2706 /*
2707 * Make sure this handle has been opened
2708 */
2709 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2710 &pChannelMap);
2711 if (rv == -1)
2712 {
2713 *pcbRecvLength = 0;
2714 PROFILE_END(SCARD_E_INVALID_HANDLE)
2716 }
2717
2718 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2719 {
2721 goto end;
2722 }
2723
2724 scTransmitStruct.hCard = hCard;
2725 scTransmitStruct.cbSendLength = cbSendLength;
2726 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2727 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2728 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2729 scTransmitStruct.rv = SCARD_S_SUCCESS;
2730
2731 if (pioRecvPci)
2732 {
2733 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2734 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2735 }
2736 else
2737 {
2738 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2739 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2740 }
2741
2742 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2743 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2744
2745 if (rv != SCARD_S_SUCCESS)
2746 goto end;
2747
2748 /* write the sent buffer */
2749 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2750 currentContextMap->dwClientID);
2751
2752 if (rv != SCARD_S_SUCCESS)
2753 goto end;
2754
2755 /*
2756 * Read a message from the server
2757 */
2758 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2759 currentContextMap->dwClientID);
2760
2761 if (rv != SCARD_S_SUCCESS)
2762 goto end;
2763
2764 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2765 {
2766 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2767 {
2768 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2770 goto end;
2771 }
2772
2773 /* read the received buffer */
2774 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2775 currentContextMap->dwClientID);
2776
2777 if (rv != SCARD_S_SUCCESS)
2778 goto end;
2779
2780 if (pioRecvPci)
2781 {
2782 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2783 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2784 }
2785 }
2786
2787 rv = scTransmitStruct.rv;
2788
2789 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2790 {
2791 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2793 goto retry;
2794 }
2795
2796 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2797
2798end:
2799 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2800
2801 PROFILE_END(rv)
2802
2803 return rv;
2804}
2805
2868LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2869 LPSTR mszReaders, LPDWORD pcchReaders)
2870{
2871 DWORD dwReadersLen = 0;
2872 int i;
2873 SCONTEXTMAP * currentContextMap;
2874 LONG rv = SCARD_S_SUCCESS;
2875 char *buf = NULL;
2876
2877 (void)mszGroups;
2878 PROFILE_START
2879 API_TRACE_IN("%ld", hContext)
2880
2881 /*
2882 * Check for NULL parameters
2883 */
2884 if (pcchReaders == NULL)
2886
2887 /*
2888 * Make sure this context has been opened
2889 */
2890 currentContextMap = SCardGetAndLockContext(hContext);
2891 if (NULL == currentContextMap)
2892 {
2893 PROFILE_END(SCARD_E_INVALID_HANDLE)
2895 }
2896
2897 /* lock access to readerStates[] */
2898 (void)pthread_mutex_lock(&readerStatesMutex);
2899
2900 /* synchronize reader states with daemon */
2901 rv = getReaderStates(currentContextMap);
2902 if (rv != SCARD_S_SUCCESS)
2903 goto end;
2904
2905 dwReadersLen = 0;
2906 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2907 if (readerStates[i].readerName[0] != '\0')
2908 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2909
2910 /* for the last NULL byte */
2911 dwReadersLen += 1;
2912
2913 if (1 == dwReadersLen)
2914 {
2916 goto end;
2917 }
2918
2919 if (SCARD_AUTOALLOCATE == *pcchReaders)
2920 {
2921 if (NULL == mszReaders)
2922 {
2924 goto end;
2925 }
2926 buf = malloc(dwReadersLen);
2927 if (NULL == buf)
2928 {
2929 rv = SCARD_E_NO_MEMORY;
2930 goto end;
2931 }
2932 *(char **)mszReaders = buf;
2933 }
2934 else
2935 {
2936 buf = mszReaders;
2937
2938 /* not enough place to store the reader names */
2939 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2940 {
2942 goto end;
2943 }
2944 }
2945
2946 if (mszReaders == NULL) /* text array not allocated */
2947 goto end;
2948
2949 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2950 {
2951 if (readerStates[i].readerName[0] != '\0')
2952 {
2953 /*
2954 * Build the multi-string
2955 */
2956 strcpy(buf, readerStates[i].readerName);
2957 buf += strlen(readerStates[i].readerName)+1;
2958 }
2959 }
2960 *buf = '\0'; /* Add the last null */
2961
2962end:
2963 /* set the reader names length */
2964 *pcchReaders = dwReadersLen;
2965
2966 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2967 (void)pthread_mutex_unlock(&readerStatesMutex);
2968
2969 PROFILE_END(rv)
2970 API_TRACE_OUT("%d", *pcchReaders)
2971
2972 return rv;
2973}
2974
2988LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2989{
2990 LONG rv = SCARD_S_SUCCESS;
2991
2992 PROFILE_START
2993
2994 /*
2995 * Make sure this context has been opened
2996 */
2997 if (! SCardGetContextValidity(hContext))
2999
3000 free((void *)pvMem);
3001
3002 PROFILE_END(rv)
3003
3004 return rv;
3005}
3006
3058LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3059 LPDWORD pcchGroups)
3060{
3061 LONG rv = SCARD_S_SUCCESS;
3062 SCONTEXTMAP * currentContextMap;
3063 char *buf = NULL;
3064
3065 PROFILE_START
3066
3067 /* Multi-string with two trailing \0 */
3068 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3069 const unsigned int dwGroups = sizeof(ReaderGroup);
3070
3071 /*
3072 * Make sure this context has been opened
3073 */
3074 currentContextMap = SCardGetAndLockContext(hContext);
3075 if (NULL == currentContextMap)
3077
3078 if (SCARD_AUTOALLOCATE == *pcchGroups)
3079 {
3080 if (NULL == mszGroups)
3081 {
3083 goto end;
3084 }
3085 buf = malloc(dwGroups);
3086 if (NULL == buf)
3087 {
3088 rv = SCARD_E_NO_MEMORY;
3089 goto end;
3090 }
3091 *(char **)mszGroups = buf;
3092 }
3093 else
3094 {
3095 buf = mszGroups;
3096
3097 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3098 {
3100 goto end;
3101 }
3102 }
3103
3104 if (buf)
3105 memcpy(buf, ReaderGroup, dwGroups);
3106
3107end:
3108 *pcchGroups = dwGroups;
3109
3110 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3111
3112 PROFILE_END(rv)
3113
3114 return rv;
3115}
3116
3148LONG SCardCancel(SCARDCONTEXT hContext)
3149{
3150 SCONTEXTMAP * currentContextMap;
3151 LONG rv = SCARD_S_SUCCESS;
3152 uint32_t dwClientID = 0;
3153 struct cancel_struct scCancelStruct;
3154 bool cancellable;
3155
3156 PROFILE_START
3157 API_TRACE_IN("%ld", hContext)
3158
3159 /*
3160 * Make sure this context has been opened
3161 */
3162 (void)SCardLockThread();
3163 currentContextMap = SCardGetContextTH(hContext);
3164
3165 if (NULL == currentContextMap)
3166 {
3167 (void)SCardUnlockThread();
3169 goto error;
3170 }
3171 cancellable = currentContextMap->cancellable;
3172 (void)SCardUnlockThread();
3173
3174 if (! cancellable)
3175 {
3176 rv = SCARD_S_SUCCESS;
3177 goto error;
3178 }
3179
3180 /* create a new connection to the server */
3181 if (ClientSetupSession(&dwClientID) != 0)
3182 {
3183 rv = SCARD_E_NO_SERVICE;
3184 goto error;
3185 }
3186
3187 scCancelStruct.hContext = hContext;
3188 scCancelStruct.rv = SCARD_S_SUCCESS;
3189
3190 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3191 sizeof(scCancelStruct), (void *) &scCancelStruct);
3192
3193 if (rv != SCARD_S_SUCCESS)
3194 goto end;
3195
3196 /*
3197 * Read a message from the server
3198 */
3199 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3200
3201 if (rv != SCARD_S_SUCCESS)
3202 goto end;
3203
3204 rv = scCancelStruct.rv;
3205end:
3206 ClientCloseSession(dwClientID);
3207
3208error:
3209 PROFILE_END(rv)
3210 API_TRACE_OUT("")
3211
3212 return rv;
3213}
3214
3238LONG SCardIsValidContext(SCARDCONTEXT hContext)
3239{
3240 LONG rv;
3241
3242 PROFILE_START
3243 API_TRACE_IN("%ld", hContext)
3244
3245 rv = SCARD_S_SUCCESS;
3246
3247 /*
3248 * Make sure this context has been opened
3249 */
3250 if (! SCardGetContextValidity(hContext))
3252
3253 PROFILE_END(rv)
3254 API_TRACE_OUT("")
3255
3256 return rv;
3257}
3258
3275static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3276{
3277 int lrv;
3278 SCONTEXTMAP * newContextMap;
3279
3280 newContextMap = malloc(sizeof(SCONTEXTMAP));
3281 if (NULL == newContextMap)
3282 return SCARD_E_NO_MEMORY;
3283
3284 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3285 newContextMap->hContext = hContext;
3286 newContextMap->dwClientID = dwClientID;
3287 newContextMap->cancellable = false;
3288
3289 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3290
3291 lrv = list_init(&newContextMap->channelMapList);
3292 if (lrv < 0)
3293 {
3294 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3295 goto error;
3296 }
3297
3298 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3299 CHANNEL_MAP_seeker);
3300 if (lrv <0)
3301 {
3302 Log2(PCSC_LOG_CRITICAL,
3303 "list_attributes_seeker failed with return value: %d", lrv);
3304 list_destroy(&newContextMap->channelMapList);
3305 goto error;
3306 }
3307
3308 lrv = list_append(&contextMapList, newContextMap);
3309 if (lrv < 0)
3310 {
3311 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3312 lrv);
3313 list_destroy(&newContextMap->channelMapList);
3314 goto error;
3315 }
3316
3317 return SCARD_S_SUCCESS;
3318
3319error:
3320
3321 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3322 free(newContextMap);
3323
3324 return SCARD_E_NO_MEMORY;
3325}
3326
3344{
3345 SCONTEXTMAP * currentContextMap;
3346
3348 currentContextMap = SCardGetContextTH(hContext);
3349
3350 /* lock the context (if available) */
3351 if (NULL != currentContextMap)
3352 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3353
3355
3356 return currentContextMap;
3357}
3358
3372{
3373 return list_seek(&contextMapList, &hContext);
3374}
3375
3383{
3384 SCONTEXTMAP * currentContextMap;
3385 currentContextMap = SCardGetContextTH(hContext);
3386
3387 if (NULL != currentContextMap)
3388 SCardCleanContext(currentContextMap);
3389}
3390
3391static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3392{
3393 int list_index, lrv;
3394 int listSize;
3395 CHANNEL_MAP * currentChannelMap;
3396
3397 targetContextMap->hContext = 0;
3398 ClientCloseSession(targetContextMap->dwClientID);
3399 targetContextMap->dwClientID = 0;
3400 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3401
3402 listSize = list_size(&targetContextMap->channelMapList);
3403 for (list_index = 0; list_index < listSize; list_index++)
3404 {
3405 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3406 list_index);
3407 if (NULL == currentChannelMap)
3408 {
3409 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3410 list_index);
3411 continue;
3412 }
3413 else
3414 {
3415 free(currentChannelMap->readerName);
3416 free(currentChannelMap);
3417 }
3418
3419 }
3420 list_destroy(&targetContextMap->channelMapList);
3421
3422 lrv = list_delete(&contextMapList, targetContextMap);
3423 if (lrv < 0)
3424 {
3425 Log2(PCSC_LOG_CRITICAL,
3426 "list_delete failed with return value: %d", lrv);
3427 }
3428
3429 free(targetContextMap);
3430
3431 return;
3432}
3433
3434/*
3435 * Functions for managing hCard values returned from SCardConnect.
3436 */
3437
3438static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3439 LPCSTR readerName)
3440{
3441 CHANNEL_MAP * newChannelMap;
3442 int lrv = -1;
3443
3444 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3445 if (NULL == newChannelMap)
3446 return SCARD_E_NO_MEMORY;
3447
3448 newChannelMap->hCard = hCard;
3449 newChannelMap->readerName = strdup(readerName);
3450
3451 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3452 if (lrv < 0)
3453 {
3454 free(newChannelMap->readerName);
3455 free(newChannelMap);
3456 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3457 lrv);
3458 return SCARD_E_NO_MEMORY;
3459 }
3460
3461 return SCARD_S_SUCCESS;
3462}
3463
3464static void SCardRemoveHandle(SCARDHANDLE hCard)
3465{
3466 SCONTEXTMAP * currentContextMap;
3467 CHANNEL_MAP * currentChannelMap;
3468 int lrv;
3469 LONG rv;
3470
3471 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3472 &currentChannelMap);
3473 if (rv == -1)
3474 return;
3475
3476 free(currentChannelMap->readerName);
3477
3478 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3479 if (lrv < 0)
3480 {
3481 Log2(PCSC_LOG_CRITICAL,
3482 "list_delete failed with return value: %d", lrv);
3483 }
3484
3485 free(currentChannelMap);
3486
3487 return;
3488}
3489
3490static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3491 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3492{
3493 LONG rv;
3494
3495 if (0 == hCard)
3496 return -1;
3497
3499 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3500 targetChannelMap);
3501
3502 if (SCARD_S_SUCCESS == rv)
3503 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3504
3506
3507 return rv;
3508}
3509
3510static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3511 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3512{
3513 int listSize;
3514 int list_index;
3515 SCONTEXTMAP * currentContextMap;
3516 CHANNEL_MAP * currentChannelMap;
3517
3518 /* Best to get the caller a crash early if we fail unsafely */
3519 *targetContextMap = NULL;
3520 *targetChannelMap = NULL;
3521
3522 listSize = list_size(&contextMapList);
3523
3524 for (list_index = 0; list_index < listSize; list_index++)
3525 {
3526 currentContextMap = list_get_at(&contextMapList, list_index);
3527 if (currentContextMap == NULL)
3528 {
3529 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3530 list_index);
3531 continue;
3532 }
3533 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3534 &hCard);
3535 if (currentChannelMap != NULL)
3536 {
3537 *targetContextMap = currentContextMap;
3538 *targetChannelMap = currentChannelMap;
3539 return SCARD_S_SUCCESS;
3540 }
3541 }
3542
3543 return -1;
3544}
3545
3554{
3555 LONG rv;
3556 struct stat statBuffer;
3557 char *socketName;
3558
3559 socketName = getSocketName();
3560 rv = stat(socketName, &statBuffer);
3561
3562 if (rv != 0)
3563 {
3564 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3565 socketName, strerror(errno));
3566 return SCARD_E_NO_SERVICE;
3567 }
3568
3569 return SCARD_S_SUCCESS;
3570}
3571
3572static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3573{
3574 int32_t dwClientID = currentContextMap->dwClientID;
3575 LONG rv;
3576
3577 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3578 if (rv != SCARD_S_SUCCESS)
3579 return rv;
3580
3581 /* Read a message from the server */
3582 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3583 if (rv != SCARD_S_SUCCESS)
3584 return rv;
3585
3586 return SCARD_S_SUCCESS;
3587}
3588
3589static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3590{
3591 int32_t dwClientID = currentContextMap->dwClientID;
3592 LONG rv;
3593
3594 /* Get current reader states from server and register on event list */
3596 0, NULL);
3597 if (rv != SCARD_S_SUCCESS)
3598 return rv;
3599
3600 /* Read a message from the server */
3601 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3602 return rv;
3603}
3604
3605static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3606{
3607 int32_t dwClientID = currentContextMap->dwClientID;
3608 LONG rv;
3609 struct wait_reader_state_change waitStatusStruct = {0};
3610
3611 /* ask server to remove us from the event list */
3613 dwClientID, 0, NULL);
3614 if (rv != SCARD_S_SUCCESS)
3615 return rv;
3616
3617 /* This message can be the response to
3618 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3619 * cancel notification.
3620 * The server side ensures, that no more messages will be sent to
3621 * the client. */
3622
3623 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3624 dwClientID);
3625 if (rv != SCARD_S_SUCCESS)
3626 return rv;
3627
3628 /* if we received a cancel event the return value will be set
3629 * accordingly */
3630 rv = waitStatusStruct.rv;
3631
3632 return rv;
3633}
3634
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition pcscd.h:53
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition pcscd.h:54
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition pcsclite.h:266
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:260
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition pcsclite.h:242
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:259
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition pcsclite.h:241
#define SCARD_STATE_INUSE
Shared Mode.
Definition pcsclite.h:274
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:233
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition pcsclite.h:269
#define SCARD_STATE_PRESENT
Card inserted.
Definition pcsclite.h:271
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:257
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:268
#define INFINITE
Infinite timeout.
Definition pcsclite.h:279
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:270
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition pcsclite.h:243
#define SCARD_STATE_MUTE
Unresponsive card.
Definition pcsclite.h:275
#define SCARD_STATE_CHANGED
State has changed.
Definition pcsclite.h:267
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition pcsclite.h:246
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:297
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition pcsclite.h:298
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition pcsclite.h:273
#define SCARD_STATE_UNAWARE
App wants status.
Definition pcsclite.h:265
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition pcsclite.h:284
This keeps track of a list of currently available reader structures.
Protocol Control Information (PCI)
Definition pcsclite.h:80
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.
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.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
@ SCARD_DISCONNECT
used by SCardDisconnect()
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
@ CMD_GET_READERS_STATE
get the readers state
@ SCARD_CONTROL
used by SCardControl()
@ CMD_VERSION
get the client/server protocol version
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
@ SCARD_RECONNECT
used by SCardReconnect()
@ SCARD_STATUS
used by SCardStatus()
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
@ SCARD_TRANSMIT
used by SCardTransmit()
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
@ SCARD_CANCEL
used by SCardCancel()
@ SCARD_CONNECT
used by SCardConnect()
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()