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