pcsc-lite 2.3.3
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
2905LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2906 LPSTR mszReaders, LPDWORD pcchReaders)
2907{
2908 DWORD dwReadersLen = 0;
2909 int i;
2910 SCONTEXTMAP * currentContextMap;
2911 LONG rv = SCARD_S_SUCCESS;
2912 char *buf = NULL;
2913
2914 (void)mszGroups;
2915 PROFILE_START
2916 API_TRACE_IN("%ld", hContext)
2917
2918 /*
2919 * Check for NULL parameters
2920 */
2921 if (pcchReaders == NULL)
2923
2924 /*
2925 * Make sure this context has been opened
2926 */
2927 currentContextMap = SCardGetAndLockContext(hContext);
2928 if (NULL == currentContextMap)
2929 {
2930 PROFILE_END(SCARD_E_INVALID_HANDLE)
2932 }
2933
2934 /* lock access to readerStates[] */
2935 (void)pthread_mutex_lock(&readerStatesMutex);
2936
2937 /* synchronize reader states with daemon */
2938 rv = getReaderStates(currentContextMap);
2939 if (rv != SCARD_S_SUCCESS)
2940 goto end;
2941
2942 dwReadersLen = 0;
2943 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2944 if (readerStates[i].readerName[0] != '\0')
2945 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2946
2947 /* for the last NULL byte */
2948 dwReadersLen += 1;
2949
2950 if (1 == dwReadersLen)
2951 {
2953 goto end;
2954 }
2955
2956 if (SCARD_AUTOALLOCATE == *pcchReaders)
2957 {
2958 if (NULL == mszReaders)
2959 {
2961 goto end;
2962 }
2963 buf = malloc(dwReadersLen);
2964 if (NULL == buf)
2965 {
2966 rv = SCARD_E_NO_MEMORY;
2967 goto end;
2968 }
2969 *(char **)mszReaders = buf;
2970 }
2971 else
2972 {
2973 buf = mszReaders;
2974
2975 /* not enough place to store the reader names */
2976 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2977 {
2979 goto end;
2980 }
2981 }
2982
2983 if (mszReaders == NULL) /* text array not allocated */
2984 goto end;
2985
2986 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2987 {
2988 if (readerStates[i].readerName[0] != '\0')
2989 {
2990 /*
2991 * Build the multi-string
2992 */
2993 strcpy(buf, readerStates[i].readerName);
2994 buf += strlen(readerStates[i].readerName)+1;
2995 }
2996 }
2997 *buf = '\0'; /* Add the last null */
2998
2999end:
3000 /* set the reader names length */
3001 *pcchReaders = dwReadersLen;
3002
3003 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3004 (void)pthread_mutex_unlock(&readerStatesMutex);
3005
3006 PROFILE_END(rv)
3007 API_TRACE_OUT("%d", *pcchReaders)
3008
3009 return rv;
3010}
3011
3025LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3026{
3027 LONG rv = SCARD_S_SUCCESS;
3028
3029 PROFILE_START
3030
3031 /*
3032 * Make sure this context has been opened
3033 */
3034 if (! SCardGetContextValidity(hContext))
3036
3037 free((void *)pvMem);
3038
3039 PROFILE_END(rv)
3040
3041 return rv;
3042}
3043
3095LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3096 LPDWORD pcchGroups)
3097{
3098 LONG rv = SCARD_S_SUCCESS;
3099 SCONTEXTMAP * currentContextMap;
3100 char *buf = NULL;
3101
3102 PROFILE_START
3103
3104 /* Multi-string with two trailing \0 */
3105 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3106 const unsigned int dwGroups = sizeof(ReaderGroup);
3107
3108 /*
3109 * Make sure this context has been opened
3110 */
3111 currentContextMap = SCardGetAndLockContext(hContext);
3112 if (NULL == currentContextMap)
3114
3115 if (SCARD_AUTOALLOCATE == *pcchGroups)
3116 {
3117 if (NULL == mszGroups)
3118 {
3120 goto end;
3121 }
3122 buf = malloc(dwGroups);
3123 if (NULL == buf)
3124 {
3125 rv = SCARD_E_NO_MEMORY;
3126 goto end;
3127 }
3128 *(char **)mszGroups = buf;
3129 }
3130 else
3131 {
3132 buf = mszGroups;
3133
3134 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3135 {
3137 goto end;
3138 }
3139 }
3140
3141 if (buf)
3142 memcpy(buf, ReaderGroup, dwGroups);
3143
3144end:
3145 *pcchGroups = dwGroups;
3146
3147 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3148
3149 PROFILE_END(rv)
3150
3151 return rv;
3152}
3153
3186{
3187 SCONTEXTMAP * currentContextMap;
3188 LONG rv = SCARD_S_SUCCESS;
3189 uint32_t dwClientID = 0;
3190 struct cancel_struct scCancelStruct;
3191 bool cancellable;
3192
3193 PROFILE_START
3194 API_TRACE_IN("%ld", hContext)
3195
3196 /*
3197 * Make sure this context has been opened
3198 */
3199 (void)SCardLockThread();
3200 currentContextMap = SCardGetContextTH(hContext);
3201
3202 if (NULL == currentContextMap)
3203 {
3204 (void)SCardUnlockThread();
3206 goto error;
3207 }
3208 cancellable = currentContextMap->cancellable;
3209 (void)SCardUnlockThread();
3210
3211 if (! cancellable)
3212 {
3213 rv = SCARD_S_SUCCESS;
3214 goto error;
3215 }
3216
3217 /* create a new connection to the server */
3218 if (ClientSetupSession(&dwClientID) != 0)
3219 {
3220 rv = SCARD_E_NO_SERVICE;
3221 goto error;
3222 }
3223
3224 scCancelStruct.hContext = hContext;
3225 scCancelStruct.rv = SCARD_S_SUCCESS;
3226
3227 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3228 sizeof(scCancelStruct), (void *) &scCancelStruct);
3229
3230 if (rv != SCARD_S_SUCCESS)
3231 goto end;
3232
3233 /*
3234 * Read a message from the server
3235 */
3236 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3237
3238 if (rv != SCARD_S_SUCCESS)
3239 goto end;
3240
3241 rv = scCancelStruct.rv;
3242end:
3243 ClientCloseSession(dwClientID);
3244
3245error:
3246 PROFILE_END(rv)
3247 API_TRACE_OUT("")
3248
3249 return rv;
3250}
3251
3276{
3277 LONG rv;
3278
3279 PROFILE_START
3280 API_TRACE_IN("%ld", hContext)
3281
3282 rv = SCARD_S_SUCCESS;
3283
3284 /*
3285 * Make sure this context has been opened
3286 */
3287 if (! SCardGetContextValidity(hContext))
3289
3290 PROFILE_END(rv)
3291 API_TRACE_OUT("")
3292
3293 return rv;
3294}
3295
3312static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3313{
3314 int lrv;
3315 SCONTEXTMAP * newContextMap;
3316
3317 newContextMap = malloc(sizeof(SCONTEXTMAP));
3318 if (NULL == newContextMap)
3319 return SCARD_E_NO_MEMORY;
3320
3321 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3322 newContextMap->hContext = hContext;
3323 newContextMap->dwClientID = dwClientID;
3324 newContextMap->cancellable = false;
3325
3326 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3327
3328 lrv = list_init(&newContextMap->channelMapList);
3329 if (lrv < 0)
3330 {
3331 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3332 goto error;
3333 }
3334
3335 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3336 CHANNEL_MAP_seeker);
3337 if (lrv <0)
3338 {
3339 Log2(PCSC_LOG_CRITICAL,
3340 "list_attributes_seeker failed with return value: %d", lrv);
3341 list_destroy(&newContextMap->channelMapList);
3342 goto error;
3343 }
3344
3345 lrv = list_append(&contextMapList, newContextMap);
3346 if (lrv < 0)
3347 {
3348 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3349 lrv);
3350 list_destroy(&newContextMap->channelMapList);
3351 goto error;
3352 }
3353
3354 return SCARD_S_SUCCESS;
3355
3356error:
3357
3358 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3359 free(newContextMap);
3360
3361 return SCARD_E_NO_MEMORY;
3362}
3363
3381{
3382 SCONTEXTMAP * currentContextMap;
3383
3385 currentContextMap = SCardGetContextTH(hContext);
3386
3387 /* lock the context (if available) */
3388 if (NULL != currentContextMap)
3389 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3390
3392
3393 return currentContextMap;
3394}
3395
3409{
3410 return list_seek(&contextMapList, &hContext);
3411}
3412
3420{
3421 SCONTEXTMAP * currentContextMap;
3422 currentContextMap = SCardGetContextTH(hContext);
3423
3424 if (NULL != currentContextMap)
3425 SCardCleanContext(currentContextMap);
3426}
3427
3428static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3429{
3430 int list_index, lrv;
3431 int listSize;
3432 CHANNEL_MAP * currentChannelMap;
3433
3434 targetContextMap->hContext = 0;
3435 ClientCloseSession(targetContextMap->dwClientID);
3436 targetContextMap->dwClientID = 0;
3437 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3438
3439 listSize = list_size(&targetContextMap->channelMapList);
3440 for (list_index = 0; list_index < listSize; list_index++)
3441 {
3442 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3443 list_index);
3444 if (NULL == currentChannelMap)
3445 {
3446 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3447 list_index);
3448 continue;
3449 }
3450 else
3451 {
3452 free(currentChannelMap->readerName);
3453 free(currentChannelMap);
3454 }
3455
3456 }
3457 list_destroy(&targetContextMap->channelMapList);
3458
3459 lrv = list_delete(&contextMapList, targetContextMap);
3460 if (lrv < 0)
3461 {
3462 Log2(PCSC_LOG_CRITICAL,
3463 "list_delete failed with return value: %d", lrv);
3464 }
3465
3466 free(targetContextMap);
3467
3468 return;
3469}
3470
3471/*
3472 * Functions for managing hCard values returned from SCardConnect.
3473 */
3474
3475static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3476 LPCSTR readerName)
3477{
3478 CHANNEL_MAP * newChannelMap;
3479 int lrv = -1;
3480
3481 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3482 if (NULL == newChannelMap)
3483 return SCARD_E_NO_MEMORY;
3484
3485 newChannelMap->hCard = hCard;
3486 newChannelMap->readerName = strdup(readerName);
3487
3488 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3489 if (lrv < 0)
3490 {
3491 free(newChannelMap->readerName);
3492 free(newChannelMap);
3493 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3494 lrv);
3495 return SCARD_E_NO_MEMORY;
3496 }
3497
3498 return SCARD_S_SUCCESS;
3499}
3500
3501static void SCardRemoveHandle(SCARDHANDLE hCard)
3502{
3503 SCONTEXTMAP * currentContextMap;
3504 CHANNEL_MAP * currentChannelMap;
3505 int lrv;
3506 LONG rv;
3507
3508 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3509 &currentChannelMap);
3510 if (rv == -1)
3511 return;
3512
3513 free(currentChannelMap->readerName);
3514
3515 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3516 if (lrv < 0)
3517 {
3518 Log2(PCSC_LOG_CRITICAL,
3519 "list_delete failed with return value: %d", lrv);
3520 }
3521
3522 free(currentChannelMap);
3523
3524 return;
3525}
3526
3527static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3528 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3529{
3530 LONG rv;
3531
3532 if (0 == hCard)
3533 return -1;
3534
3536 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3537 targetChannelMap);
3538
3539 if (SCARD_S_SUCCESS == rv)
3540 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3541
3543
3544 return rv;
3545}
3546
3547static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3548 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3549{
3550 int listSize;
3551 int list_index;
3552 SCONTEXTMAP * currentContextMap;
3553 CHANNEL_MAP * currentChannelMap;
3554
3555 /* Best to get the caller a crash early if we fail unsafely */
3556 *targetContextMap = NULL;
3557 *targetChannelMap = NULL;
3558
3559 listSize = list_size(&contextMapList);
3560
3561 for (list_index = 0; list_index < listSize; list_index++)
3562 {
3563 currentContextMap = list_get_at(&contextMapList, list_index);
3564 if (currentContextMap == NULL)
3565 {
3566 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3567 list_index);
3568 continue;
3569 }
3570 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3571 &hCard);
3572 if (currentChannelMap != NULL)
3573 {
3574 *targetContextMap = currentContextMap;
3575 *targetChannelMap = currentChannelMap;
3576 return SCARD_S_SUCCESS;
3577 }
3578 }
3579
3580 return -1;
3581}
3582
3591{
3592 LONG rv;
3593 struct stat statBuffer;
3594 char *socketName;
3595
3596 socketName = getSocketName();
3597 rv = stat(socketName, &statBuffer);
3598
3599 if (rv != 0)
3600 {
3601 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3602 socketName, strerror(errno));
3603 return SCARD_E_NO_SERVICE;
3604 }
3605
3606 return SCARD_S_SUCCESS;
3607}
3608
3609static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3610{
3611 int32_t dwClientID = currentContextMap->dwClientID;
3612 LONG rv;
3614
3615 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3616 if (rv != SCARD_S_SUCCESS)
3617 return rv;
3618
3619 /* Read a message from the server */
3620 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3621 if (rv != SCARD_S_SUCCESS)
3622 return rv;
3623
3624 *readerEvents = get_reader_events.readerEvents;
3625
3626 return SCARD_S_SUCCESS;
3627}
3628
3629static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3630{
3631 int32_t dwClientID = currentContextMap->dwClientID;
3632 LONG rv;
3633
3634 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3635 if (rv != SCARD_S_SUCCESS)
3636 return rv;
3637
3638 /* Read a message from the server */
3639 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3640 if (rv != SCARD_S_SUCCESS)
3641 return rv;
3642
3643 return SCARD_S_SUCCESS;
3644}
3645
3646static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3647{
3648 int32_t dwClientID = currentContextMap->dwClientID;
3649 LONG rv;
3650
3651 /* Get current reader states from server and register on event list */
3653 0, NULL);
3654 if (rv != SCARD_S_SUCCESS)
3655 return rv;
3656
3657 /* Read a message from the server */
3658 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3659 return rv;
3660}
3661
3662static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3663{
3664 int32_t dwClientID = currentContextMap->dwClientID;
3665 LONG rv;
3666 struct wait_reader_state_change waitStatusStruct = {0};
3667
3668 /* ask server to remove us from the event list */
3670 dwClientID, 0, NULL);
3671 if (rv != SCARD_S_SUCCESS)
3672 return rv;
3673
3674 /* This message can be the response to
3675 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3676 * cancel notification.
3677 * The server side ensures, that no more messages will be sent to
3678 * the client. */
3679
3680 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3681 dwClientID);
3682 if (rv != SCARD_S_SUCCESS)
3683 return rv;
3684
3685 /* if we received a cancel event the return value will be set
3686 * accordingly */
3687 rv = waitStatusStruct.rv;
3688
3689 return rv;
3690}
3691
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.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
#define SCARD_S_SUCCESS
No error was encountered.
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
#define SCARD_STATE_IGNORE
Ignore this reader.
#define SCARD_SWALLOWED
Card not powered.
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_PRESENT
Card is present.
#define SCARD_STATE_INUSE
Shared Mode.
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
#define SCARD_STATE_PRESENT
Card inserted.
#define SCARD_ABSENT
Card is absent.
#define SCARD_UNKNOWN
Unknown state.
#define SCARD_STATE_UNKNOWN
Reader unknown.
#define INFINITE
Infinite timeout.
#define SCARD_STATE_EMPTY
Card removed.
#define SCARD_STATE_MUTE
Unresponsive card.
#define SCARD_STATE_CHANGED
State has changed.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
#define SCARD_STATE_UNAWARE
App wants status.
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Protocol Control Information (PCI)
unsigned long dwProtocol
Protocol identifier.
unsigned long cbPciLength
Protocol Control Inf Length.
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()