pcsc-lite 1.9.8
winscard_clnt.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2005
9 * Martin Paljak <martin@paljak.pri.ee>
10 * Copyright (C) 2002-2011
11 * Ludovic Rousseau <ludovic.rousseau@free.fr>
12 * Copyright (C) 2009
13 * Jean-Luc Giraud <jlgiraud@googlemail.com>
14 *
15Redistribution and use in source and binary forms, with or without
16modification, are permitted provided that the following conditions
17are met:
18
191. Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
212. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
243. The name of the author may not be used to endorse or promote products
25 derived from this software without specific prior written permission.
26
27THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
105#include "config.h"
106#include <stdlib.h>
107#include <string.h>
108#include <sys/types.h>
109#include <fcntl.h>
110#include <unistd.h>
111#include <sys/un.h>
112#include <errno.h>
113#include <stddef.h>
114#include <sys/time.h>
115#include <pthread.h>
116#include <sys/wait.h>
117
118#include "misc.h"
119#include "pcscd.h"
120#include "winscard.h"
121#include "debuglog.h"
122
123#include "readerfactory.h"
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
138#define SCARD_PROTOCOL_ANY_OLD 0x1000
139
140#ifndef TRUE
141#define TRUE 1
142#define FALSE 0
143#endif
144
145static char sharing_shall_block = TRUE;
146
147#define COLOR_RED "\33[01;31m"
148#define COLOR_GREEN "\33[32m"
149#define COLOR_BLUE "\33[34m"
150#define COLOR_MAGENTA "\33[35m"
151#define COLOR_NORMAL "\33[0m"
152
153#ifdef DO_TRACE
154
155#include <stdio.h>
156#include <stdarg.h>
157
158static void trace(const char *func, const char direction, const char *fmt, ...)
159{
160 va_list args;
161
162 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163 direction, pthread_self(), func);
164
165 fprintf(stderr, COLOR_MAGENTA);
166 va_start(args, fmt);
167 vfprintf(stderr, fmt, args);
168 va_end(args);
169
170 fprintf(stderr, COLOR_NORMAL "\n");
171}
172
173#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175#else
176#define API_TRACE_IN(...)
177#define API_TRACE_OUT(...)
178#endif
179
180#ifdef DO_PROFILE
181
182#define PROFILE_FILE "/tmp/pcsc_profile"
183#include <stdio.h>
184#include <sys/time.h>
185
186/* we can profile a maximum of 5 simultaneous calls */
187#define MAX_THREADS 5
188pthread_t threads[MAX_THREADS];
189struct timeval profile_time_start[MAX_THREADS];
190FILE *profile_fd;
191char profile_tty;
192
193#define PROFILE_START profile_start();
194#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195
196static void profile_start(void)
197{
198 static char initialized = FALSE;
199 pthread_t t;
200 int i;
201
202 if (!initialized)
203 {
204 char filename[80];
205
206 initialized = TRUE;
207 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208 profile_fd = fopen(filename, "a+");
209 if (NULL == profile_fd)
210 {
211 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212 PROFILE_FILE, strerror(errno));
213 exit(-1);
214 }
215 fprintf(profile_fd, "\nStart a new profile\n");
216
217 if (isatty(fileno(stderr)))
218 profile_tty = TRUE;
219 else
220 profile_tty = FALSE;
221 }
222
223 t = pthread_self();
224 for (i=0; i<MAX_THREADS; i++)
225 if (pthread_equal(0, threads[i]))
226 {
227 threads[i] = t;
228 break;
229 }
230
231 gettimeofday(&profile_time_start[i], NULL);
232} /* profile_start */
233
234static void profile_end(const char *f, LONG rv)
235{
236 struct timeval profile_time_end;
237 long d;
238 pthread_t t;
239 int i;
240
241 gettimeofday(&profile_time_end, NULL);
242
243 t = pthread_self();
244 for (i=0; i<MAX_THREADS; i++)
245 if (pthread_equal(t, threads[i]))
246 break;
247
248 if (i>=MAX_THREADS)
249 {
250 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251 return;
252 }
253
254 d = time_sub(&profile_time_end, &profile_time_start[i]);
255
256 /* free this entry */
257 threads[i] = 0;
258
259 if (profile_tty)
260 {
261 if (rv != SCARD_S_SUCCESS)
262 fprintf(stderr,
263 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265 f, d, rv, pcsc_stringify_error(rv));
266 else
267 fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268 COLOR_NORMAL "\n", f, d);
269 }
270 fprintf(profile_fd, "%s %ld\n", f, d);
271 fflush(profile_fd);
272} /* profile_end */
273
274#else
275#define PROFILE_START
276#define PROFILE_END(rv)
277#endif
278
284{
285 SCARDHANDLE hCard;
286 LPSTR readerName;
287};
288
289typedef struct _psChannelMap CHANNEL_MAP;
290
291static int CHANNEL_MAP_seeker(const void *el, const void *key)
292{
293 const CHANNEL_MAP * channelMap = el;
294
295 if ((el == NULL) || (key == NULL))
296 {
297 Log3(PCSC_LOG_CRITICAL,
298 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299 el, key);
300 return 0;
301 }
302
303 if (channelMap->hCard == *(SCARDHANDLE *)key)
304 return 1;
305
306 return 0;
307}
308
315{
318 pthread_mutex_t mMutex;
319 list_t channelMapList;
321};
328
329static list_t contextMapList;
330
331static int SCONTEXTMAP_seeker(const void *el, const void *key)
332{
333 const SCONTEXTMAP * contextMap = el;
334
335 if ((el == NULL) || (key == NULL))
336 {
337 Log3(PCSC_LOG_CRITICAL,
338 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
339 el, key);
340 return 0;
341 }
342
343 if (contextMap->hContext == *(SCARDCONTEXT *) key)
344 return 1;
345
346 return 0;
347}
348
352static short isExecuted = 0;
353
354
359static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
360
365
372
373
374static LONG SCardAddContext(SCARDCONTEXT, DWORD);
378static void SCardCleanContext(SCONTEXTMAP *);
379
380static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
381static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
382 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
383static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
384 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
385static void SCardRemoveHandle(SCARDHANDLE);
386
387static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
388 LPBYTE pbAttr, LPDWORD pcbAttrLen);
389
390static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
391static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
392static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
393
394/*
395 * Thread safety functions
396 */
403inline static void SCardLockThread(void)
404{
405 pthread_mutex_lock(&clientMutex);
406}
407
413inline static void SCardUnlockThread(void)
414{
415 pthread_mutex_unlock(&clientMutex);
416}
417
428{
429 SCONTEXTMAP * currentContextMap;
430
432 currentContextMap = SCardGetContextTH(hContext);
434
435 return currentContextMap != NULL;
436}
437
438static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
439 /*@out@*/ LPSCARDCONTEXT);
440
476LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
477 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
478{
479 LONG rv;
480
481 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
482 PROFILE_START
483
484 /* Check if the server is running */
486 if (rv != SCARD_S_SUCCESS)
487 goto end;
488
490 rv = SCardEstablishContextTH(dwScope, pvReserved1,
491 pvReserved2, phContext);
493
494end:
495 PROFILE_END(rv)
496 API_TRACE_OUT("%ld", *phContext)
497
498 return rv;
499}
500
501#ifdef DESTRUCTOR
502DESTRUCTOR static void destructor(void)
503{
504 list_destroy(&contextMapList);
505}
506#endif
507
534static LONG SCardEstablishContextTH(DWORD dwScope,
535 /*@unused@*/ LPCVOID pvReserved1,
536 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
537{
538 LONG rv;
539 struct establish_struct scEstablishStruct;
540 uint32_t dwClientID = 0;
541
542 (void)pvReserved1;
543 (void)pvReserved2;
544 if (phContext == NULL)
546 else
547 *phContext = 0;
548
549 /*
550 * Do this only once:
551 * - Initialize context list.
552 */
553 if (isExecuted == 0)
554 {
555 int lrv;
556
557 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
558 * Applications which load and unload the library may leak
559 * the list's internal structures. */
560 lrv = list_init(&contextMapList);
561 if (lrv < 0)
562 {
563 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
564 lrv);
565 return SCARD_E_NO_MEMORY;
566 }
567
568 lrv = list_attributes_seeker(&contextMapList,
569 SCONTEXTMAP_seeker);
570 if (lrv <0)
571 {
572 Log2(PCSC_LOG_CRITICAL,
573 "list_attributes_seeker failed with return value: %d", lrv);
574 list_destroy(&contextMapList);
575 return SCARD_E_NO_MEMORY;
576 }
577
578 if (getenv("PCSCLITE_NO_BLOCKING"))
579 {
580 Log1(PCSC_LOG_INFO, "Disable shared blocking");
581 sharing_shall_block = FALSE;
582 }
583
584 isExecuted = 1;
585 }
586
587
588 /* Establishes a connection to the server */
589 if (ClientSetupSession(&dwClientID) != 0)
590 {
591 return SCARD_E_NO_SERVICE;
592 }
593
594 { /* exchange client/server protocol versions */
595 struct version_struct veStr;
596
599 veStr.rv = SCARD_S_SUCCESS;
600
601 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
602 &veStr);
603 if (rv != SCARD_S_SUCCESS)
604 goto cleanup;
605
606 /* Read a message from the server */
607 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
608 if (rv != SCARD_S_SUCCESS)
609 {
610 Log1(PCSC_LOG_CRITICAL,
611 "Your pcscd is too old and does not support CMD_VERSION");
613 goto cleanup;
614 }
615
616 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
617 veStr.major, veStr.minor);
618
619 if (veStr.rv != SCARD_S_SUCCESS)
620 {
621 rv = veStr.rv;
622 goto cleanup;
623 }
624 }
625
626again:
627 /*
628 * Try to establish an Application Context with the server
629 */
630 scEstablishStruct.dwScope = dwScope;
631 scEstablishStruct.hContext = 0;
632 scEstablishStruct.rv = SCARD_S_SUCCESS;
633
635 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
636
637 if (rv != SCARD_S_SUCCESS)
638 goto cleanup;
639
640 /*
641 * Read the response from the server
642 */
643 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
644 dwClientID);
645
646 if (rv != SCARD_S_SUCCESS)
647 goto cleanup;
648
649 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
650 {
651 rv = scEstablishStruct.rv;
652 goto cleanup;
653 }
654
655 /* check we do not reuse an existing hContext */
656 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
657 /* we do not need to release the allocated context since
658 * SCardReleaseContext() does nothing on the server side */
659 goto again;
660
661 *phContext = scEstablishStruct.hContext;
662
663 /*
664 * Allocate the new hContext - if allocator full return an error
665 */
666 rv = SCardAddContext(*phContext, dwClientID);
667
668 return rv;
669
670cleanup:
671 ClientCloseSession(dwClientID);
672
673 return rv;
674}
675
697LONG SCardReleaseContext(SCARDCONTEXT hContext)
698{
699 LONG rv;
700 struct release_struct scReleaseStruct;
701 SCONTEXTMAP * currentContextMap;
702
703 API_TRACE_IN("%ld", hContext)
704 PROFILE_START
705
706 /*
707 * Make sure this context has been opened
708 * and get currentContextMap
709 */
710 currentContextMap = SCardGetAndLockContext(hContext);
711 if (NULL == currentContextMap)
712 {
714 goto error;
715 }
716
717 scReleaseStruct.hContext = hContext;
718 scReleaseStruct.rv = SCARD_S_SUCCESS;
719
721 currentContextMap->dwClientID,
722 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
723
724 if (rv != SCARD_S_SUCCESS)
725 goto end;
726
727 /*
728 * Read a message from the server
729 */
730 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
731 currentContextMap->dwClientID);
732
733 if (rv != SCARD_S_SUCCESS)
734 goto end;
735
736 rv = scReleaseStruct.rv;
737end:
738 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
739
740 /*
741 * Remove the local context from the stack
742 */
744 SCardRemoveContext(hContext);
746
747error:
748 PROFILE_END(rv)
749 API_TRACE_OUT("")
750
751 return rv;
752}
753
809LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
810 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
811 LPDWORD pdwActiveProtocol)
812{
813 LONG rv;
814 struct connect_struct scConnectStruct;
815 SCONTEXTMAP * currentContextMap;
816
817 PROFILE_START
818 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
819
820 /*
821 * Check for NULL parameters
822 */
823 if (phCard == NULL || pdwActiveProtocol == NULL)
825 else
826 *phCard = 0;
827
828 if (szReader == NULL)
830
831 /*
832 * Check for uninitialized strings
833 */
834 if (strlen(szReader) > MAX_READERNAME)
836
837 /*
838 * Make sure this context has been opened
839 */
840 currentContextMap = SCardGetAndLockContext(hContext);
841 if (NULL == currentContextMap)
843
844 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
845 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
846 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
847
848 scConnectStruct.hContext = hContext;
849 scConnectStruct.dwShareMode = dwShareMode;
850 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
851 scConnectStruct.hCard = 0;
852 scConnectStruct.dwActiveProtocol = 0;
853 scConnectStruct.rv = SCARD_S_SUCCESS;
854
855 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
856 sizeof(scConnectStruct), (void *) &scConnectStruct);
857
858 if (rv != SCARD_S_SUCCESS)
859 goto end;
860
861 /*
862 * Read a message from the server
863 */
864 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
865 currentContextMap->dwClientID);
866
867 if (rv != SCARD_S_SUCCESS)
868 goto end;
869
870 *phCard = scConnectStruct.hCard;
871 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
872
873 if (scConnectStruct.rv == SCARD_S_SUCCESS)
874 {
875 /*
876 * Keep track of the handle locally
877 */
878 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
879 }
880 else
881 rv = scConnectStruct.rv;
882
883end:
884 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
885
886 PROFILE_END(rv)
887 API_TRACE_OUT("%d", *pdwActiveProtocol)
888
889 return rv;
890}
891
964LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
965 DWORD dwPreferredProtocols, DWORD dwInitialization,
966 LPDWORD pdwActiveProtocol)
967{
968 LONG rv;
969 struct reconnect_struct scReconnectStruct;
970 SCONTEXTMAP * currentContextMap;
971 CHANNEL_MAP * pChannelMap;
972
973 PROFILE_START
974 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
975
976 if (pdwActiveProtocol == NULL)
978
979 /* Retry loop for blocking behaviour */
980retry:
981
982 /*
983 * Make sure this handle has been opened
984 */
985 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
986 &pChannelMap);
987 if (rv == -1)
989
990 scReconnectStruct.hCard = hCard;
991 scReconnectStruct.dwShareMode = dwShareMode;
992 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
993 scReconnectStruct.dwInitialization = dwInitialization;
994 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
995 scReconnectStruct.rv = SCARD_S_SUCCESS;
996
997 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
998 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
999
1000 if (rv != SCARD_S_SUCCESS)
1001 goto end;
1002
1003 /*
1004 * Read a message from the server
1005 */
1006 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1007 currentContextMap->dwClientID);
1008
1009 if (rv != SCARD_S_SUCCESS)
1010 goto end;
1011
1012 rv = scReconnectStruct.rv;
1013
1014 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1015 {
1016 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1018 goto retry;
1019 }
1020
1021 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1022
1023end:
1024 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1025
1026 PROFILE_END(rv)
1027 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1028
1029 return rv;
1030}
1031
1063LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1064{
1065 LONG rv;
1066 struct disconnect_struct scDisconnectStruct;
1067 SCONTEXTMAP * currentContextMap;
1068 CHANNEL_MAP * pChannelMap;
1069
1070 PROFILE_START
1071 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1072
1073 /*
1074 * Make sure this handle has been opened
1075 */
1076 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1077 &pChannelMap);
1078 if (rv == -1)
1079 {
1081 goto error;
1082 }
1083
1084 scDisconnectStruct.hCard = hCard;
1085 scDisconnectStruct.dwDisposition = dwDisposition;
1086 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1087
1088 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1089 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1090
1091 if (rv != SCARD_S_SUCCESS)
1092 goto end;
1093
1094 /*
1095 * Read a message from the server
1096 */
1097 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1098 currentContextMap->dwClientID);
1099
1100 if (rv != SCARD_S_SUCCESS)
1101 goto end;
1102
1103 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1104 SCardRemoveHandle(hCard);
1105 rv = scDisconnectStruct.rv;
1106
1107end:
1108 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1109
1110error:
1111 PROFILE_END(rv)
1112 API_TRACE_OUT("")
1113
1114 return rv;
1115}
1116
1152LONG SCardBeginTransaction(SCARDHANDLE hCard)
1153{
1154
1155 LONG rv;
1156 struct begin_struct scBeginStruct;
1157 SCONTEXTMAP * currentContextMap;
1158 CHANNEL_MAP * pChannelMap;
1159
1160 PROFILE_START
1161 API_TRACE_IN("%ld", hCard)
1162
1163 /*
1164 * Query the server every so often until the sharing violation ends
1165 * and then hold the lock for yourself.
1166 */
1167
1168 for(;;)
1169 {
1170 /*
1171 * Make sure this handle has been opened
1172 */
1173 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1174 &pChannelMap);
1175 if (rv == -1)
1177
1178 scBeginStruct.hCard = hCard;
1179 scBeginStruct.rv = SCARD_S_SUCCESS;
1180
1182 currentContextMap->dwClientID,
1183 sizeof(scBeginStruct), (void *) &scBeginStruct);
1184
1185 if (rv != SCARD_S_SUCCESS)
1186 break;
1187
1188 /*
1189 * Read a message from the server
1190 */
1191 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1192 currentContextMap->dwClientID);
1193
1194 if (rv != SCARD_S_SUCCESS)
1195 break;
1196
1197 rv = scBeginStruct.rv;
1198
1199 if (SCARD_E_SHARING_VIOLATION != rv)
1200 break;
1201
1202 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1204 }
1205
1206 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1207
1208 PROFILE_END(rv)
1209 API_TRACE_OUT("")
1210
1211 return rv;
1212}
1213
1253LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1254{
1255 LONG rv;
1256 struct end_struct scEndStruct;
1257 SCONTEXTMAP * currentContextMap;
1258 CHANNEL_MAP * pChannelMap;
1259
1260 PROFILE_START
1261 API_TRACE_IN("%ld", hCard)
1262
1263 /*
1264 * Make sure this handle has been opened
1265 */
1266 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1267 &pChannelMap);
1268 if (rv == -1)
1270
1271 scEndStruct.hCard = hCard;
1272 scEndStruct.dwDisposition = dwDisposition;
1273 scEndStruct.rv = SCARD_S_SUCCESS;
1274
1276 currentContextMap->dwClientID,
1277 sizeof(scEndStruct), (void *) &scEndStruct);
1278
1279 if (rv != SCARD_S_SUCCESS)
1280 goto end;
1281
1282 /*
1283 * Read a message from the server
1284 */
1285 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1286 currentContextMap->dwClientID);
1287
1288 if (rv != SCARD_S_SUCCESS)
1289 goto end;
1290
1291 rv = scEndStruct.rv;
1292
1293end:
1294 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1295
1296 PROFILE_END(rv)
1297 API_TRACE_OUT("")
1298
1299 return rv;
1300}
1301
1397LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1398 LPDWORD pcchReaderLen, LPDWORD pdwState,
1399 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1400{
1401 DWORD dwReaderLen, dwAtrLen;
1402 LONG rv;
1403 int i;
1404 struct status_struct scStatusStruct;
1405 SCONTEXTMAP * currentContextMap;
1406 CHANNEL_MAP * pChannelMap;
1407 char *r;
1408 char *bufReader = NULL;
1409 LPBYTE bufAtr = NULL;
1410 DWORD dummy = 0;
1411
1412 PROFILE_START
1413
1414 /* default output values */
1415 if (pdwState)
1416 *pdwState = 0;
1417
1418 if (pdwProtocol)
1419 *pdwProtocol = 0;
1420
1421 /* Check for NULL parameters */
1422 if (pcchReaderLen == NULL)
1423 pcchReaderLen = &dummy;
1424
1425 if (pcbAtrLen == NULL)
1426 pcbAtrLen = &dummy;
1427
1428 /* length passed from caller */
1429 dwReaderLen = *pcchReaderLen;
1430 dwAtrLen = *pcbAtrLen;
1431
1432 *pcchReaderLen = 0;
1433 *pcbAtrLen = 0;
1434
1435 /* Retry loop for blocking behaviour */
1436retry:
1437
1438 /*
1439 * Make sure this handle has been opened
1440 */
1441 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1442 &pChannelMap);
1443 if (rv == -1)
1445
1446 /* synchronize reader states with daemon */
1447 rv = getReaderStates(currentContextMap);
1448 if (rv != SCARD_S_SUCCESS)
1449 goto end;
1450
1451 r = pChannelMap->readerName;
1452 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1453 {
1454 /* by default r == NULL */
1455 if (r && strcmp(r, readerStates[i].readerName) == 0)
1456 break;
1457 }
1458
1460 {
1462 goto end;
1463 }
1464
1465 /* initialise the structure */
1466 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1467 scStatusStruct.hCard = hCard;
1468
1469 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1470 sizeof(scStatusStruct), (void *) &scStatusStruct);
1471
1472 if (rv != SCARD_S_SUCCESS)
1473 goto end;
1474
1475 /*
1476 * Read a message from the server
1477 */
1478 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1479 currentContextMap->dwClientID);
1480
1481 if (rv != SCARD_S_SUCCESS)
1482 goto end;
1483
1484 rv = scStatusStruct.rv;
1485
1486 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1487 {
1488 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1490 goto retry;
1491 }
1492
1494 {
1495 /*
1496 * An event must have occurred
1497 */
1498 goto end;
1499 }
1500
1501 /*
1502 * Now continue with the client side SCardStatus
1503 */
1504
1505 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1506 *pcbAtrLen = readerStates[i].cardAtrLength;
1507
1508 if (pdwState)
1509 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1510
1511 if (pdwProtocol)
1512 *pdwProtocol = readerStates[i].cardProtocol;
1513
1514 if (SCARD_AUTOALLOCATE == dwReaderLen)
1515 {
1516 dwReaderLen = *pcchReaderLen;
1517 if (NULL == szReaderName)
1518 {
1520 goto end;
1521 }
1522 bufReader = malloc(dwReaderLen);
1523 if (NULL == bufReader)
1524 {
1525 rv = SCARD_E_NO_MEMORY;
1526 goto end;
1527 }
1528 *(char **)szReaderName = bufReader;
1529 }
1530 else
1531 bufReader = szReaderName;
1532
1533 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1534 if (bufReader)
1535 {
1536 if (*pcchReaderLen > dwReaderLen)
1538
1539 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1540 }
1541
1542 if (SCARD_AUTOALLOCATE == dwAtrLen)
1543 {
1544 dwAtrLen = *pcbAtrLen;
1545 if (NULL == pbAtr)
1546 {
1548 goto end;
1549 }
1550 bufAtr = malloc(dwAtrLen);
1551 if (NULL == bufAtr)
1552 {
1553 rv = SCARD_E_NO_MEMORY;
1554 goto end;
1555 }
1556 *(LPBYTE *)pbAtr = bufAtr;
1557 }
1558 else
1559 bufAtr = pbAtr;
1560
1561 if (bufAtr)
1562 {
1563 if (*pcbAtrLen > dwAtrLen)
1565
1566 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1567 }
1568
1569end:
1570 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1571
1572 PROFILE_END(rv)
1573
1574 return rv;
1575}
1576
1684LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1685 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1686{
1687 SCARD_READERSTATE *currReader;
1688 READER_STATE *rContext;
1689 long dwTime;
1690 DWORD dwBreakFlag = 0;
1691 unsigned int j;
1692 SCONTEXTMAP * currentContextMap;
1693 int currentReaderCount = 0;
1694 LONG rv = SCARD_S_SUCCESS;
1695
1696 PROFILE_START
1697 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1698#ifdef DO_TRACE
1699 for (j=0; j<cReaders; j++)
1700 {
1701 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1702 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1703 }
1704#endif
1705
1706 if ((rgReaderStates == NULL && cReaders > 0)
1707 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1708 {
1710 goto error;
1711 }
1712
1713 /* Check the integrity of the reader states structures */
1714 for (j = 0; j < cReaders; j++)
1715 {
1716 if (rgReaderStates[j].szReader == NULL)
1717 return SCARD_E_INVALID_VALUE;
1718 }
1719
1720 /* return if all readers are SCARD_STATE_IGNORE */
1721 if (cReaders > 0)
1722 {
1723 int nbNonIgnoredReaders = cReaders;
1724
1725 for (j=0; j<cReaders; j++)
1726 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1727 nbNonIgnoredReaders--;
1728
1729 if (0 == nbNonIgnoredReaders)
1730 {
1731 rv = SCARD_S_SUCCESS;
1732 goto error;
1733 }
1734 }
1735 else
1736 {
1737 /* reader list is empty */
1738 rv = SCARD_S_SUCCESS;
1739 goto error;
1740 }
1741
1742 /*
1743 * Make sure this context has been opened
1744 */
1745 currentContextMap = SCardGetAndLockContext(hContext);
1746 if (NULL == currentContextMap)
1747 {
1749 goto error;
1750 }
1751
1752 /* synchronize reader states with daemon */
1753 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1754 if (rv != SCARD_S_SUCCESS)
1755 goto end;
1756
1757 /* check all the readers are already known */
1758 for (j=0; j<cReaders; j++)
1759 {
1760 const char *readerName;
1761 int i;
1762
1763 readerName = rgReaderStates[j].szReader;
1764 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1765 {
1766 if (strcmp(readerName, readerStates[i].readerName) == 0)
1767 break;
1768 }
1769
1770 /* The requested reader name is not recognized */
1772 {
1773 /* PnP special reader? */
1774 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1775 {
1777 goto end;
1778 }
1779 }
1780 }
1781
1782 /* Clear the event state for all readers */
1783 for (j = 0; j < cReaders; j++)
1784 rgReaderStates[j].dwEventState = 0;
1785
1786 /* Now is where we start our event checking loop */
1787 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1788
1789 /* Get the initial reader count on the system */
1790 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1791 if (readerStates[j].readerName[0] != '\0')
1792 currentReaderCount++;
1793
1794 /* catch possible sign extension problems from 32 to 64-bits integers */
1795 if ((DWORD)-1 == dwTimeout)
1796 dwTimeout = INFINITE;
1797 if (INFINITE == dwTimeout)
1798 dwTime = 60*1000; /* "infinite" timeout */
1799 else
1800 dwTime = dwTimeout;
1801
1802 j = 0;
1803 do
1804 {
1805 currReader = &rgReaderStates[j];
1806
1807 /* Ignore for IGNORED readers */
1808 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1809 {
1810 const char *readerName;
1811 int i;
1812
1813 /* Looks for correct readernames */
1814 readerName = currReader->szReader;
1815 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1816 {
1817 if (strcmp(readerName, readerStates[i].readerName) == 0)
1818 break;
1819 }
1820
1821 /* The requested reader name is not recognized */
1823 {
1824 /* PnP special reader? */
1825 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1826 {
1827 int k, newReaderCount = 0;
1828
1829 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1830 if (readerStates[k].readerName[0] != '\0')
1831 newReaderCount++;
1832
1833 if (newReaderCount != currentReaderCount)
1834 {
1835 Log1(PCSC_LOG_INFO, "Reader list changed");
1836 currentReaderCount = newReaderCount;
1837
1838 currReader->dwEventState |= SCARD_STATE_CHANGED;
1839 dwBreakFlag = 1;
1840 }
1841 }
1842 else
1843 {
1844 currReader->dwEventState =
1846 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1847 {
1848 currReader->dwEventState |= SCARD_STATE_CHANGED;
1849 /*
1850 * Spec says use SCARD_STATE_IGNORE but a removed USB
1851 * reader with eventState fed into currentState will
1852 * be ignored forever
1853 */
1854 dwBreakFlag = 1;
1855 }
1856 }
1857 }
1858 else
1859 {
1860 uint32_t readerState;
1861
1862 /* The reader has come back after being away */
1863 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1864 {
1865 currReader->dwEventState |= SCARD_STATE_CHANGED;
1866 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1867 Log0(PCSC_LOG_DEBUG);
1868 dwBreakFlag = 1;
1869 }
1870
1871 /* Set the reader status structure */
1872 rContext = &readerStates[i];
1873
1874 /* Now we check all the Reader States */
1875 readerState = rContext->readerState;
1876
1877 /* only if current state has an non null event counter */
1878 if (currReader->dwCurrentState & 0xFFFF0000)
1879 {
1880 unsigned int currentCounter;
1881
1882 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1883
1884 /* has the event counter changed since the last call? */
1885 if (rContext->eventCounter != currentCounter)
1886 {
1887 currReader->dwEventState |= SCARD_STATE_CHANGED;
1888 Log0(PCSC_LOG_DEBUG);
1889 dwBreakFlag = 1;
1890 }
1891 }
1892
1893 /* add an event counter in the upper word of dwEventState */
1894 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1895 | (rContext->eventCounter << 16));
1896
1897 /* Check if the reader is in the correct state */
1898 if (readerState & SCARD_UNKNOWN)
1899 {
1900 /* reader is in bad state */
1901 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1902 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1903 {
1904 /* App thinks reader is in good state and it is not */
1905 currReader->dwEventState |= SCARD_STATE_CHANGED;
1906 Log0(PCSC_LOG_DEBUG);
1907 dwBreakFlag = 1;
1908 }
1909 }
1910 else
1911 {
1912 /* App thinks reader in bad state but it is not */
1913 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1914 {
1915 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1916 currReader->dwEventState |= SCARD_STATE_CHANGED;
1917 Log0(PCSC_LOG_DEBUG);
1918 dwBreakFlag = 1;
1919 }
1920 }
1921
1922 /* Check for card presence in the reader */
1923 if (readerState & SCARD_PRESENT)
1924 {
1925#ifndef DISABLE_AUTO_POWER_ON
1926 /* card present but not yet powered up */
1927 if (0 == rContext->cardAtrLength)
1928 /* Allow the status thread to convey information */
1930#endif
1931
1932 currReader->cbAtr = rContext->cardAtrLength;
1933 memcpy(currReader->rgbAtr, rContext->cardAtr,
1934 currReader->cbAtr);
1935 }
1936 else
1937 currReader->cbAtr = 0;
1938
1939 /* Card is now absent */
1940 if (readerState & SCARD_ABSENT)
1941 {
1942 currReader->dwEventState |= SCARD_STATE_EMPTY;
1943 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1944 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1945 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1946 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1947 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1948 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1949 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1950 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1951
1952 /* After present the rest are assumed */
1953 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1954 {
1955 currReader->dwEventState |= SCARD_STATE_CHANGED;
1956 Log0(PCSC_LOG_DEBUG);
1957 dwBreakFlag = 1;
1958 }
1959 }
1960 /* Card is now present */
1961 else if (readerState & SCARD_PRESENT)
1962 {
1963 currReader->dwEventState |= SCARD_STATE_PRESENT;
1964 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1965 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1966 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1967 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1968 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1969 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1970
1971 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1972 {
1973 currReader->dwEventState |= SCARD_STATE_CHANGED;
1974 Log0(PCSC_LOG_DEBUG);
1975 dwBreakFlag = 1;
1976 }
1977
1978 if (readerState & SCARD_SWALLOWED)
1979 {
1980 currReader->dwEventState |= SCARD_STATE_MUTE;
1981 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1982 {
1983 currReader->dwEventState |= SCARD_STATE_CHANGED;
1984 Log0(PCSC_LOG_DEBUG);
1985 dwBreakFlag = 1;
1986 }
1987 }
1988 else
1989 {
1990 /* App thinks card is mute but it is not */
1991 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1992 {
1993 currReader->dwEventState |= SCARD_STATE_CHANGED;
1994 Log0(PCSC_LOG_DEBUG);
1995 dwBreakFlag = 1;
1996 }
1997 }
1998 }
1999
2000 /* Now figure out sharing modes */
2002 {
2003 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2004 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2005 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2006 {
2007 currReader->dwEventState |= SCARD_STATE_CHANGED;
2008 Log0(PCSC_LOG_DEBUG);
2009 dwBreakFlag = 1;
2010 }
2011 }
2012 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2013 {
2014 /* A card must be inserted for it to be INUSE */
2015 if (readerState & SCARD_PRESENT)
2016 {
2017 currReader->dwEventState |= SCARD_STATE_INUSE;
2018 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2019 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2020 {
2021 currReader->dwEventState |= SCARD_STATE_CHANGED;
2022 Log0(PCSC_LOG_DEBUG);
2023 dwBreakFlag = 1;
2024 }
2025 }
2026 }
2027 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2028 {
2029 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2030 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2031
2032 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2033 {
2034 currReader->dwEventState |= SCARD_STATE_CHANGED;
2035 Log0(PCSC_LOG_DEBUG);
2036 dwBreakFlag = 1;
2037 }
2038 else if (currReader-> dwCurrentState
2040 {
2041 currReader->dwEventState |= SCARD_STATE_CHANGED;
2042 Log0(PCSC_LOG_DEBUG);
2043 dwBreakFlag = 1;
2044 }
2045 }
2046
2047 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2048 {
2049 /*
2050 * Break out of the while .. loop and return status
2051 * once all the status's for all readers is met
2052 */
2053 currReader->dwEventState |= SCARD_STATE_CHANGED;
2054 Log0(PCSC_LOG_DEBUG);
2055 dwBreakFlag = 1;
2056 }
2057 } /* End of SCARD_STATE_UNKNOWN */
2058 } /* End of SCARD_STATE_IGNORE */
2059
2060 /* Counter and resetter */
2061 j++;
2062 if (j == cReaders)
2063 {
2064 /* go back to the first reader */
2065 j = 0;
2066
2067 /* Declare all the break conditions */
2068
2069 /* Break if UNAWARE is set and all readers have been checked */
2070 if (dwBreakFlag == 1)
2071 break;
2072
2073 /* Only sleep once for each cycle of reader checks. */
2074 {
2075 struct wait_reader_state_change waitStatusStruct = {0};
2076 struct timeval before, after;
2077
2078 gettimeofday(&before, NULL);
2079
2080 waitStatusStruct.rv = SCARD_S_SUCCESS;
2081
2082 /* another thread can do SCardCancel() */
2083 currentContextMap->cancellable = TRUE;
2084
2085 /*
2086 * Read a message from the server
2087 */
2089 &waitStatusStruct, sizeof(waitStatusStruct),
2090 currentContextMap->dwClientID, dwTime);
2091
2092 /* SCardCancel() will return immediatly with success
2093 * because something changed on the daemon side. */
2094 currentContextMap->cancellable = FALSE;
2095
2096 /* timeout */
2097 if (SCARD_E_TIMEOUT == rv)
2098 {
2099 /* ask server to remove us from the event list */
2100 rv = unregisterFromEvents(currentContextMap);
2101 }
2102
2103 if (rv != SCARD_S_SUCCESS)
2104 goto end;
2105
2106 /* an event occurs or SCardCancel() was called */
2107 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2108 {
2109 rv = waitStatusStruct.rv;
2110 goto end;
2111 }
2112
2113 /* synchronize reader states with daemon */
2114 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2115 if (rv != SCARD_S_SUCCESS)
2116 goto end;
2117
2118 if (INFINITE != dwTimeout)
2119 {
2120 long int diff;
2121
2122 gettimeofday(&after, NULL);
2123 diff = time_sub(&after, &before);
2124 dwTime -= diff/1000;
2125 }
2126 }
2127
2128 if (dwTimeout != INFINITE)
2129 {
2130 /* If time is greater than timeout and all readers have been
2131 * checked
2132 */
2133 if (dwTime <= 0)
2134 {
2135 rv = SCARD_E_TIMEOUT;
2136 goto end;
2137 }
2138 }
2139 }
2140 }
2141 while (1);
2142
2143end:
2144 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2145
2146 /* if SCardCancel() has been used then the client is already
2147 * unregistered */
2148 if (SCARD_E_CANCELLED != rv)
2149 (void)unregisterFromEvents(currentContextMap);
2150
2151 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2152
2153error:
2154 PROFILE_END(rv)
2155#ifdef DO_TRACE
2156 for (j=0; j<cReaders; j++)
2157 {
2158 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2159 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2160 }
2161#endif
2162
2163 return rv;
2164}
2165
2216LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2217 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2218 LPDWORD lpBytesReturned)
2219{
2220 LONG rv;
2221 struct control_struct scControlStruct;
2222 SCONTEXTMAP * currentContextMap;
2223 CHANNEL_MAP * pChannelMap;
2224
2225 PROFILE_START
2226
2227 /* 0 bytes received by default */
2228 if (NULL != lpBytesReturned)
2229 *lpBytesReturned = 0;
2230
2231 /*
2232 * Make sure this handle has been opened
2233 */
2234 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2235 &pChannelMap);
2236 if (rv == -1)
2237 {
2238 PROFILE_END(SCARD_E_INVALID_HANDLE)
2240 }
2241
2242 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2243 {
2245 goto end;
2246 }
2247
2248 scControlStruct.hCard = hCard;
2249 scControlStruct.dwControlCode = dwControlCode;
2250 scControlStruct.cbSendLength = cbSendLength;
2251 scControlStruct.cbRecvLength = cbRecvLength;
2252 scControlStruct.dwBytesReturned = 0;
2253 scControlStruct.rv = 0;
2254
2255 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2256 sizeof(scControlStruct), &scControlStruct);
2257
2258 if (rv != SCARD_S_SUCCESS)
2259 goto end;
2260
2261 /* write the sent buffer */
2262 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2263 currentContextMap->dwClientID);
2264
2265 if (rv != SCARD_S_SUCCESS)
2266 goto end;
2267
2268 /*
2269 * Read a message from the server
2270 */
2271 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2272 currentContextMap->dwClientID);
2273
2274 if (rv != SCARD_S_SUCCESS)
2275 goto end;
2276
2277 if (SCARD_S_SUCCESS == scControlStruct.rv)
2278 {
2279 if (scControlStruct.dwBytesReturned > cbRecvLength)
2280 {
2281 if (NULL != lpBytesReturned)
2282 *lpBytesReturned = scControlStruct.dwBytesReturned;
2284 goto end;
2285 }
2286
2287 /* read the received buffer */
2288 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2289 currentContextMap->dwClientID);
2290
2291 if (rv != SCARD_S_SUCCESS)
2292 goto end;
2293
2294 }
2295
2296 if (NULL != lpBytesReturned)
2297 *lpBytesReturned = scControlStruct.dwBytesReturned;
2298
2299 rv = scControlStruct.rv;
2300
2301end:
2302 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2303
2304 PROFILE_END(rv)
2305
2306 return rv;
2307}
2308
2426LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2427 LPDWORD pcbAttrLen)
2428{
2429 LONG ret;
2430 unsigned char *buf = NULL;
2431
2432 PROFILE_START
2433
2434 if (NULL == pcbAttrLen)
2435 {
2437 goto end;
2438 }
2439
2440 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2441 {
2442 if (NULL == pbAttr)
2444
2445 *pcbAttrLen = MAX_BUFFER_SIZE;
2446 buf = malloc(*pcbAttrLen);
2447 if (NULL == buf)
2448 {
2449 ret = SCARD_E_NO_MEMORY;
2450 goto end;
2451 }
2452
2453 *(unsigned char **)pbAttr = buf;
2454 }
2455 else
2456 {
2457 buf = pbAttr;
2458
2459 /* if only get the length */
2460 if (NULL == pbAttr)
2461 /* use a reasonable size */
2462 *pcbAttrLen = MAX_BUFFER_SIZE;
2463 }
2464
2465 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2466 pcbAttrLen);
2467
2468end:
2469 PROFILE_END(ret)
2470
2471 return ret;
2472}
2473
2509LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2510 DWORD cbAttrLen)
2511{
2512 LONG ret;
2513
2514 PROFILE_START
2515
2516 if (NULL == pbAttr || 0 == cbAttrLen)
2518
2519 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2520 &cbAttrLen);
2521
2522 PROFILE_END(ret)
2523
2524 return ret;
2525}
2526
2527static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2528 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2529{
2530 LONG rv;
2531 struct getset_struct scGetSetStruct;
2532 SCONTEXTMAP * currentContextMap;
2533 CHANNEL_MAP * pChannelMap;
2534
2535 /*
2536 * Make sure this handle has been opened
2537 */
2538 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2539 &pChannelMap);
2540 if (rv == -1)
2542
2543 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2544 {
2546 goto end;
2547 }
2548
2549 scGetSetStruct.hCard = hCard;
2550 scGetSetStruct.dwAttrId = dwAttrId;
2551 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2552 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2553 if (SCARD_SET_ATTRIB == command)
2554 {
2555 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2556 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2557 }
2558 else
2559 /* we can get up to the communication buffer size */
2560 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2561
2562 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2563 sizeof(scGetSetStruct), &scGetSetStruct);
2564
2565 if (rv != SCARD_S_SUCCESS)
2566 goto end;
2567
2568 /*
2569 * Read a message from the server
2570 */
2571 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2572 currentContextMap->dwClientID);
2573
2574 if (rv != SCARD_S_SUCCESS)
2575 goto end;
2576
2577 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2578 {
2579 /*
2580 * Copy and zero it so any secret information is not leaked
2581 */
2582 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2583 {
2584 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2585 * buffer overflow in the memcpy() bellow */
2586 DWORD correct_value = scGetSetStruct.cbAttrLen;
2587 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2588 *pcbAttrLen = correct_value;
2589
2590 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2591 }
2592 else
2593 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2594
2595 if (pbAttr)
2596 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2597
2598 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2599 }
2600 rv = scGetSetStruct.rv;
2601
2602end:
2603 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2604
2605 return rv;
2606}
2607
2666LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2667 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2668 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2669 LPDWORD pcbRecvLength)
2670{
2671 LONG rv;
2672 SCONTEXTMAP * currentContextMap;
2673 CHANNEL_MAP * pChannelMap;
2674 struct transmit_struct scTransmitStruct;
2675
2676 PROFILE_START
2677
2678 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2679 pcbRecvLength == NULL || pioSendPci == NULL)
2681
2682 /* Retry loop for blocking behaviour */
2683retry:
2684
2685 /*
2686 * Make sure this handle has been opened
2687 */
2688 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2689 &pChannelMap);
2690 if (rv == -1)
2691 {
2692 *pcbRecvLength = 0;
2693 PROFILE_END(SCARD_E_INVALID_HANDLE)
2695 }
2696
2697 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2698 {
2700 goto end;
2701 }
2702
2703 scTransmitStruct.hCard = hCard;
2704 scTransmitStruct.cbSendLength = cbSendLength;
2705 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2706 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2707 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2708 scTransmitStruct.rv = SCARD_S_SUCCESS;
2709
2710 if (pioRecvPci)
2711 {
2712 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2713 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2714 }
2715 else
2716 {
2717 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2718 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2719 }
2720
2721 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2722 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2723
2724 if (rv != SCARD_S_SUCCESS)
2725 goto end;
2726
2727 /* write the sent buffer */
2728 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2729 currentContextMap->dwClientID);
2730
2731 if (rv != SCARD_S_SUCCESS)
2732 goto end;
2733
2734 /*
2735 * Read a message from the server
2736 */
2737 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2738 currentContextMap->dwClientID);
2739
2740 if (rv != SCARD_S_SUCCESS)
2741 goto end;
2742
2743 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2744 {
2745 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2746 {
2747 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2749 goto end;
2750 }
2751
2752 /* read the received buffer */
2753 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2754 currentContextMap->dwClientID);
2755
2756 if (rv != SCARD_S_SUCCESS)
2757 goto end;
2758
2759 if (pioRecvPci)
2760 {
2761 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2762 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2763 }
2764 }
2765
2766 rv = scTransmitStruct.rv;
2767
2768 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2769 {
2770 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2772 goto retry;
2773 }
2774
2775 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2776
2777end:
2778 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2779
2780 PROFILE_END(rv)
2781
2782 return rv;
2783}
2784
2847LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2848 LPSTR mszReaders, LPDWORD pcchReaders)
2849{
2850 DWORD dwReadersLen = 0;
2851 int i;
2852 SCONTEXTMAP * currentContextMap;
2853 LONG rv = SCARD_S_SUCCESS;
2854 char *buf = NULL;
2855
2856 (void)mszGroups;
2857 PROFILE_START
2858 API_TRACE_IN("%ld", hContext)
2859
2860 /*
2861 * Check for NULL parameters
2862 */
2863 if (pcchReaders == NULL)
2865
2866 /*
2867 * Make sure this context has been opened
2868 */
2869 currentContextMap = SCardGetAndLockContext(hContext);
2870 if (NULL == currentContextMap)
2871 {
2872 PROFILE_END(SCARD_E_INVALID_HANDLE)
2874 }
2875
2876 /* synchronize reader states with daemon */
2877 rv = getReaderStates(currentContextMap);
2878 if (rv != SCARD_S_SUCCESS)
2879 goto end;
2880
2881 dwReadersLen = 0;
2882 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2883 if (readerStates[i].readerName[0] != '\0')
2884 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2885
2886 /* for the last NULL byte */
2887 dwReadersLen += 1;
2888
2889 if (1 == dwReadersLen)
2890 {
2892 goto end;
2893 }
2894
2895 if (SCARD_AUTOALLOCATE == *pcchReaders)
2896 {
2897 if (NULL == mszReaders)
2898 {
2900 goto end;
2901 }
2902 buf = malloc(dwReadersLen);
2903 if (NULL == buf)
2904 {
2905 rv = SCARD_E_NO_MEMORY;
2906 goto end;
2907 }
2908 *(char **)mszReaders = buf;
2909 }
2910 else
2911 {
2912 buf = mszReaders;
2913
2914 /* not enough place to store the reader names */
2915 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2916 {
2918 goto end;
2919 }
2920 }
2921
2922 if (mszReaders == NULL) /* text array not allocated */
2923 goto end;
2924
2925 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2926 {
2927 if (readerStates[i].readerName[0] != '\0')
2928 {
2929 /*
2930 * Build the multi-string
2931 */
2932 strcpy(buf, readerStates[i].readerName);
2933 buf += strlen(readerStates[i].readerName)+1;
2934 }
2935 }
2936 *buf = '\0'; /* Add the last null */
2937
2938end:
2939 /* set the reader names length */
2940 *pcchReaders = dwReadersLen;
2941
2942 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2943
2944 PROFILE_END(rv)
2945 API_TRACE_OUT("%d", *pcchReaders)
2946
2947 return rv;
2948}
2949
2963LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2964{
2965 LONG rv = SCARD_S_SUCCESS;
2966
2967 PROFILE_START
2968
2969 /*
2970 * Make sure this context has been opened
2971 */
2972 if (! SCardGetContextValidity(hContext))
2974
2975 free((void *)pvMem);
2976
2977 PROFILE_END(rv)
2978
2979 return rv;
2980}
2981
3033LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3034 LPDWORD pcchGroups)
3035{
3036 LONG rv = SCARD_S_SUCCESS;
3037 SCONTEXTMAP * currentContextMap;
3038 char *buf = NULL;
3039
3040 PROFILE_START
3041
3042 /* Multi-string with two trailing \0 */
3043 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3044 const unsigned int dwGroups = sizeof(ReaderGroup);
3045
3046 /*
3047 * Make sure this context has been opened
3048 */
3049 currentContextMap = SCardGetAndLockContext(hContext);
3050 if (NULL == currentContextMap)
3052
3053 if (SCARD_AUTOALLOCATE == *pcchGroups)
3054 {
3055 if (NULL == mszGroups)
3056 {
3058 goto end;
3059 }
3060 buf = malloc(dwGroups);
3061 if (NULL == buf)
3062 {
3063 rv = SCARD_E_NO_MEMORY;
3064 goto end;
3065 }
3066 *(char **)mszGroups = buf;
3067 }
3068 else
3069 {
3070 buf = mszGroups;
3071
3072 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3073 {
3075 goto end;
3076 }
3077 }
3078
3079 if (buf)
3080 memcpy(buf, ReaderGroup, dwGroups);
3081
3082end:
3083 *pcchGroups = dwGroups;
3084
3085 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3086
3087 PROFILE_END(rv)
3088
3089 return rv;
3090}
3091
3123LONG SCardCancel(SCARDCONTEXT hContext)
3124{
3125 SCONTEXTMAP * currentContextMap;
3126 LONG rv = SCARD_S_SUCCESS;
3127 uint32_t dwClientID = 0;
3128 struct cancel_struct scCancelStruct;
3129 char cancellable;
3130
3131 PROFILE_START
3132 API_TRACE_IN("%ld", hContext)
3133
3134 /*
3135 * Make sure this context has been opened
3136 */
3137 (void)SCardLockThread();
3138 currentContextMap = SCardGetContextTH(hContext);
3139
3140 if (NULL == currentContextMap)
3141 {
3142 (void)SCardUnlockThread();
3144 goto error;
3145 }
3146 cancellable = currentContextMap->cancellable;
3147 (void)SCardUnlockThread();
3148
3149 if (! cancellable)
3150 {
3151 rv = SCARD_S_SUCCESS;
3152 goto error;
3153 }
3154
3155 /* create a new connection to the server */
3156 if (ClientSetupSession(&dwClientID) != 0)
3157 {
3158 rv = SCARD_E_NO_SERVICE;
3159 goto error;
3160 }
3161
3162 scCancelStruct.hContext = hContext;
3163 scCancelStruct.rv = SCARD_S_SUCCESS;
3164
3165 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3166 sizeof(scCancelStruct), (void *) &scCancelStruct);
3167
3168 if (rv != SCARD_S_SUCCESS)
3169 goto end;
3170
3171 /*
3172 * Read a message from the server
3173 */
3174 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3175
3176 if (rv != SCARD_S_SUCCESS)
3177 goto end;
3178
3179 rv = scCancelStruct.rv;
3180end:
3181 ClientCloseSession(dwClientID);
3182
3183error:
3184 PROFILE_END(rv)
3185 API_TRACE_OUT("")
3186
3187 return rv;
3188}
3189
3213LONG SCardIsValidContext(SCARDCONTEXT hContext)
3214{
3215 LONG rv;
3216
3217 PROFILE_START
3218 API_TRACE_IN("%ld", hContext)
3219
3220 rv = SCARD_S_SUCCESS;
3221
3222 /*
3223 * Make sure this context has been opened
3224 */
3225 if (! SCardGetContextValidity(hContext))
3227
3228 PROFILE_END(rv)
3229 API_TRACE_OUT("")
3230
3231 return rv;
3232}
3233
3250static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3251{
3252 int lrv;
3253 SCONTEXTMAP * newContextMap;
3254
3255 newContextMap = malloc(sizeof(SCONTEXTMAP));
3256 if (NULL == newContextMap)
3257 return SCARD_E_NO_MEMORY;
3258
3259 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3260 newContextMap->hContext = hContext;
3261 newContextMap->dwClientID = dwClientID;
3262 newContextMap->cancellable = FALSE;
3263
3264 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3265
3266 lrv = list_init(&newContextMap->channelMapList);
3267 if (lrv < 0)
3268 {
3269 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3270 goto error;
3271 }
3272
3273 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3274 CHANNEL_MAP_seeker);
3275 if (lrv <0)
3276 {
3277 Log2(PCSC_LOG_CRITICAL,
3278 "list_attributes_seeker failed with return value: %d", lrv);
3279 list_destroy(&newContextMap->channelMapList);
3280 goto error;
3281 }
3282
3283 lrv = list_append(&contextMapList, newContextMap);
3284 if (lrv < 0)
3285 {
3286 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3287 lrv);
3288 list_destroy(&newContextMap->channelMapList);
3289 goto error;
3290 }
3291
3292 return SCARD_S_SUCCESS;
3293
3294error:
3295
3296 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3297 free(newContextMap);
3298
3299 return SCARD_E_NO_MEMORY;
3300}
3301
3319{
3320 SCONTEXTMAP * currentContextMap;
3321
3323 currentContextMap = SCardGetContextTH(hContext);
3324
3325 /* lock the context (if available) */
3326 if (NULL != currentContextMap)
3327 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3328
3330
3331 return currentContextMap;
3332}
3333
3347{
3348 return list_seek(&contextMapList, &hContext);
3349}
3350
3358{
3359 SCONTEXTMAP * currentContextMap;
3360 currentContextMap = SCardGetContextTH(hContext);
3361
3362 if (NULL != currentContextMap)
3363 SCardCleanContext(currentContextMap);
3364}
3365
3366static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3367{
3368 int list_index, lrv;
3369 int listSize;
3370 CHANNEL_MAP * currentChannelMap;
3371
3372 targetContextMap->hContext = 0;
3373 ClientCloseSession(targetContextMap->dwClientID);
3374 targetContextMap->dwClientID = 0;
3375 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3376
3377 listSize = list_size(&targetContextMap->channelMapList);
3378 for (list_index = 0; list_index < listSize; list_index++)
3379 {
3380 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3381 list_index);
3382 if (NULL == currentChannelMap)
3383 {
3384 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3385 list_index);
3386 continue;
3387 }
3388 else
3389 {
3390 free(currentChannelMap->readerName);
3391 free(currentChannelMap);
3392 }
3393
3394 }
3395 list_destroy(&targetContextMap->channelMapList);
3396
3397 lrv = list_delete(&contextMapList, targetContextMap);
3398 if (lrv < 0)
3399 {
3400 Log2(PCSC_LOG_CRITICAL,
3401 "list_delete failed with return value: %d", lrv);
3402 }
3403
3404 free(targetContextMap);
3405
3406 return;
3407}
3408
3409/*
3410 * Functions for managing hCard values returned from SCardConnect.
3411 */
3412
3413static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3414 LPCSTR readerName)
3415{
3416 CHANNEL_MAP * newChannelMap;
3417 int lrv = -1;
3418
3419 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3420 if (NULL == newChannelMap)
3421 return SCARD_E_NO_MEMORY;
3422
3423 newChannelMap->hCard = hCard;
3424 newChannelMap->readerName = strdup(readerName);
3425
3426 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3427 if (lrv < 0)
3428 {
3429 free(newChannelMap->readerName);
3430 free(newChannelMap);
3431 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3432 lrv);
3433 return SCARD_E_NO_MEMORY;
3434 }
3435
3436 return SCARD_S_SUCCESS;
3437}
3438
3439static void SCardRemoveHandle(SCARDHANDLE hCard)
3440{
3441 SCONTEXTMAP * currentContextMap;
3442 CHANNEL_MAP * currentChannelMap;
3443 int lrv;
3444 LONG rv;
3445
3446 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3447 &currentChannelMap);
3448 if (rv == -1)
3449 return;
3450
3451 free(currentChannelMap->readerName);
3452
3453 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3454 if (lrv < 0)
3455 {
3456 Log2(PCSC_LOG_CRITICAL,
3457 "list_delete failed with return value: %d", lrv);
3458 }
3459
3460 free(currentChannelMap);
3461
3462 return;
3463}
3464
3465static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3466 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3467{
3468 LONG rv;
3469
3470 if (0 == hCard)
3471 return -1;
3472
3474 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3475 targetChannelMap);
3476
3477 if (SCARD_S_SUCCESS == rv)
3478 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3479
3481
3482 return rv;
3483}
3484
3485static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3486 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3487{
3488 int listSize;
3489 int list_index;
3490 SCONTEXTMAP * currentContextMap;
3491 CHANNEL_MAP * currentChannelMap;
3492
3493 /* Best to get the caller a crash early if we fail unsafely */
3494 *targetContextMap = NULL;
3495 *targetChannelMap = NULL;
3496
3497 listSize = list_size(&contextMapList);
3498
3499 for (list_index = 0; list_index < listSize; list_index++)
3500 {
3501 currentContextMap = list_get_at(&contextMapList, list_index);
3502 if (currentContextMap == NULL)
3503 {
3504 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3505 list_index);
3506 continue;
3507 }
3508 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3509 &hCard);
3510 if (currentChannelMap != NULL)
3511 {
3512 *targetContextMap = currentContextMap;
3513 *targetChannelMap = currentChannelMap;
3514 return SCARD_S_SUCCESS;
3515 }
3516 }
3517
3518 return -1;
3519}
3520
3529{
3530 LONG rv;
3531 struct stat statBuffer;
3532 char *socketName;
3533
3534 socketName = getSocketName();
3535 rv = stat(socketName, &statBuffer);
3536
3537 if (rv != 0)
3538 {
3539 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3540 socketName, strerror(errno));
3541 return SCARD_E_NO_SERVICE;
3542 }
3543
3544 return SCARD_S_SUCCESS;
3545}
3546
3547static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3548{
3549 int32_t dwClientID = currentContextMap->dwClientID;
3550 LONG rv;
3551
3552 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3553 if (rv != SCARD_S_SUCCESS)
3554 return rv;
3555
3556 /* Read a message from the server */
3557 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3558 if (rv != SCARD_S_SUCCESS)
3559 return rv;
3560
3561 return SCARD_S_SUCCESS;
3562}
3563
3564static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3565{
3566 int32_t dwClientID = currentContextMap->dwClientID;
3567 LONG rv;
3568
3569 /* Get current reader states from server and register on event list */
3571 0, NULL);
3572 if (rv != SCARD_S_SUCCESS)
3573 return rv;
3574
3575 /* Read a message from the server */
3576 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3577 return rv;
3578}
3579
3580static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3581{
3582 int32_t dwClientID = currentContextMap->dwClientID;
3583 LONG rv;
3584 struct wait_reader_state_change waitStatusStruct = {0};
3585
3586 /* ask server to remove us from the event list */
3588 dwClientID, 0, NULL);
3589 if (rv != SCARD_S_SUCCESS)
3590 return rv;
3591
3592 /* This message can be the response to
3593 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3594 * cancel notification.
3595 * The server side ensures, that no more messages will be sent to
3596 * the client. */
3597
3598 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3599 dwClientID);
3600 if (rv != SCARD_S_SUCCESS)
3601 return rv;
3602
3603 /* if we received a cancel event the return value will be set
3604 * accordingly */
3605 rv = waitStatusStruct.rv;
3606
3607 return rv;
3608}
3609
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition pcsclite.h:145
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition pcscd.h:53
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition pcscd.h:54
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition pcsclite.h:266
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:260
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition pcsclite.h:242
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:259
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition pcsclite.h:241
#define SCARD_STATE_INUSE
Shared Mode.
Definition pcsclite.h:274
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:233
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition pcsclite.h:269
#define SCARD_STATE_PRESENT
Card inserted.
Definition pcsclite.h:271
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:257
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:268
#define INFINITE
Infinite timeout.
Definition pcsclite.h:279
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:270
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition pcsclite.h:243
#define SCARD_STATE_MUTE
Unresponsive card.
Definition pcsclite.h:275
#define SCARD_STATE_CHANGED
State has changed.
Definition pcsclite.h:267
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition pcsclite.h:246
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:297
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition pcsclite.h:298
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition pcsclite.h:273
#define SCARD_STATE_UNAWARE
App wants status.
Definition pcsclite.h:265
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition pcsclite.h:284
This keeps track of a list of currently available reader structures.
Protocol Control Information (PCI)
Definition pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition pcsclite.h:82
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
char 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...
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
uint32_t readerState
SCARD_* bit field.
uint32_t cardAtrLength
ATR length.
contained in SCARD_RECONNECT Messages.
Information contained in SCARD_RELEASE_CONTEXT Messages.
contained in SCARD_STATUS Messages.
contained in SCARD_TRANSMIT Messages.
Information transmitted in CMD_VERSION Messages.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition sys_unix.c:78
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 short 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 int SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
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 void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the reponse 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 reponse from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
@ SCARD_DISCONNECT
used by SCardDisconnect()
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
@ CMD_GET_READERS_STATE
get the readers state
@ SCARD_CONTROL
used by SCardControl()
@ CMD_VERSION
get the client/server protocol version
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
@ SCARD_RECONNECT
used by SCardReconnect()
@ SCARD_STATUS
used by SCardStatus()
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
@ SCARD_TRANSMIT
used by SCardTransmit()
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
@ SCARD_CANCEL
used by SCardCancel()
@ SCARD_CONNECT
used by SCardConnect()
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()