pcsc-lite 2.5.0
winscard_clnt.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2005
9 * Martin Paljak <martin@paljak.pri.ee>
10 * Copyright (C) 2002-2025
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
104
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;
138static int Protocol_version;
139
140#define COLOR_RED "\33[01;31m"
141#define COLOR_GREEN "\33[32m"
142#define COLOR_BLUE "\33[34m"
143#define COLOR_MAGENTA "\33[35m"
144#define COLOR_NORMAL "\33[0m"
145
146#ifdef DO_TRACE
147
148#include <stdio.h>
149#include <stdarg.h>
150
151static void trace(const char *func, const char direction, const char *fmt, ...)
152{
153 va_list args;
154
155 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
156 direction, pthread_self(), func);
157
158 fprintf(stderr, COLOR_MAGENTA);
159 va_start(args, fmt);
160 vfprintf(stderr, fmt, args);
161 va_end(args);
162
163 fprintf(stderr, COLOR_NORMAL "\n");
164}
165
166#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
167#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
168#else
169#define API_TRACE_IN(...)
170#define API_TRACE_OUT(...)
171#endif
172
173#ifdef DO_PROFILE
174
175#define PROFILE_FILE "/tmp/pcsc_profile"
176#include <stdio.h>
177#include <sys/time.h>
178
179/* we can profile a maximum of 5 simultaneous calls */
180#define MAX_THREADS 5
181pthread_t threads[MAX_THREADS];
182struct timeval profile_time_start[MAX_THREADS];
183FILE *profile_fd;
184bool profile_tty;
185
186#define PROFILE_START profile_start();
187#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
188
189static void profile_start(void)
190{
191 static bool initialized = false;
192 pthread_t t;
193 int i;
194
195 if (!initialized)
196 {
197 char filename[80];
198
199 initialized = true;
200 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
201 profile_fd = fopen(filename, "a+");
202 if (NULL == profile_fd)
203 {
204 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
205 PROFILE_FILE, strerror(errno));
206 exit(-1);
207 }
208 fprintf(profile_fd, "\nStart a new profile\n");
209
210 if (isatty(fileno(stderr)))
211 profile_tty = true;
212 else
213 profile_tty = false;
214 }
215
216 t = pthread_self();
217 for (i=0; i<MAX_THREADS; i++)
218 if (pthread_equal(0, threads[i]))
219 {
220 threads[i] = t;
221 break;
222 }
223
224 gettimeofday(&profile_time_start[i], NULL);
225} /* profile_start */
226
227static void profile_end(const char *f, LONG rv)
228{
229 struct timeval profile_time_end;
230 long d;
231 pthread_t t;
232 int i;
233
234 gettimeofday(&profile_time_end, NULL);
235
236 t = pthread_self();
237 for (i=0; i<MAX_THREADS; i++)
238 if (pthread_equal(t, threads[i]))
239 break;
240
241 if (i>=MAX_THREADS)
242 {
243 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
244 return;
245 }
246
247 d = time_sub(&profile_time_end, &profile_time_start[i]);
248
249 /* free this entry */
250 threads[i] = 0;
251
252 if (profile_tty)
253 {
254 fprintf(stderr,
255 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
256 COLOR_BLUE "0x%08lX" COLOR_NORMAL "\n",
257 f, d, rv);
258 }
259 fprintf(profile_fd, "%s %ld\n", f, d);
260 fflush(profile_fd);
261} /* profile_end */
262
263#else
264#define PROFILE_START
265#define PROFILE_END(rv)
266#endif
267
273{
274 SCARDHANDLE hCard;
275 LPSTR readerName;
276};
277
278typedef struct _psChannelMap CHANNEL_MAP;
279
280static int CHANNEL_MAP_seeker(const void *el, const void *key)
281{
282 const CHANNEL_MAP * channelMap = el;
283
284 if ((el == NULL) || (key == NULL))
285 {
286 Log3(PCSC_LOG_CRITICAL,
287 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
288 el, key);
289 return 0;
290 }
291
292 if (channelMap->hCard == *(SCARDHANDLE *)key)
293 return 1;
294
295 return 0;
296}
297
304{
307 pthread_mutex_t mMutex;
308 list_t channelMapList;
310};
311
317
318static list_t contextMapList;
319pthread_mutex_t contextMapList_lock;
320
321static int SCONTEXTMAP_seeker(const void *el, const void *key)
322{
323 const SCONTEXTMAP * contextMap = el;
324
325 if ((el == NULL) || (key == NULL))
326 {
327 Log3(PCSC_LOG_CRITICAL,
328 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
329 el, key);
330 return 0;
331 }
332
333 if (contextMap->hContext == *(SCARDCONTEXT *) key)
334 return 1;
335
336 return 0;
337}
338
342static bool isExecuted = false;
343static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
344
345
350static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
351
355int pcsclite_max_reader_context = 0;
356static READER_STATE * readerStates = NULL;
357static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
358
359
360static LONG SCardAddContext(SCARDCONTEXT, DWORD);
364static void SCardCleanContext(SCONTEXTMAP *);
365
366static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
367static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
368 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
369static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
370 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
371static void SCardRemoveHandle(SCARDHANDLE);
372
373static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
374 LPBYTE pbAttr, LPDWORD pcbAttrLen);
375
376static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents);
377static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
378static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
379static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
380
381/*
382 * Thread safety functions
383 */
390inline static void SCardLockThread(void)
391{
392 pthread_mutex_lock(&clientMutex);
393}
394
400inline static void SCardUnlockThread(void)
401{
402 pthread_mutex_unlock(&clientMutex);
403}
404
415{
416 SCONTEXTMAP * currentContextMap;
417
419 currentContextMap = SCardGetContextTH(hContext);
421
422 return currentContextMap != NULL;
423}
424
425static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
426 /*@out@*/ LPSCARDCONTEXT);
427
464LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
465 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
466{
467 LONG rv;
468
469 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
470 PROFILE_START
471
472 /* Check if the server is running */
474 if (rv != SCARD_S_SUCCESS)
475 goto end;
476
478 rv = SCardEstablishContextTH(dwScope, pvReserved1,
479 pvReserved2, phContext);
481
482end:
483 PROFILE_END(rv)
484 API_TRACE_OUT("%ld", *phContext)
485
486 return rv;
487}
488
489#ifdef DESTRUCTOR
490DESTRUCTOR static void destructor(void)
491{
492 (void)pthread_mutex_lock(&contextMapList_lock);
493 list_destroy(&contextMapList);
494 (void)pthread_mutex_unlock(&contextMapList_lock);
495
496 (void)pthread_mutex_destroy(&contextMapList_lock);
497}
498#endif
499
500/*
501 * Do this only once:
502 * - Initialize context list.
503 */
504static void init_lib(void)
505{
506 int lrv;
507
508 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
509 * Applications which load and unload the library may leak
510 * the list's internal structures. */
511 lrv = list_init(&contextMapList);
512 if (lrv < 0)
513 {
514 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
515 lrv);
516 return;
517 }
518
519 lrv = list_attributes_seeker(&contextMapList,
520 SCONTEXTMAP_seeker);
521 if (lrv <0)
522 {
523 Log2(PCSC_LOG_CRITICAL,
524 "list_attributes_seeker failed with return value: %d", lrv);
525 list_destroy(&contextMapList);
526 return;
527 }
528
529 if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
530 {
531 Log1(PCSC_LOG_INFO, "Disable shared blocking");
532 sharing_shall_block = false;
533 }
534
535 (void)pthread_mutex_init(&contextMapList_lock, NULL);
536
537 isExecuted = true;
538}
539
567static LONG SCardEstablishContextTH(DWORD dwScope,
568 /*@unused@*/ LPCVOID pvReserved1,
569 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
570{
571 LONG rv;
572 struct establish_struct scEstablishStruct;
573 uint32_t dwClientID = 0;
574 struct version_struct veStr;
575
576 (void)pvReserved1;
577 (void)pvReserved2;
578 if (phContext == NULL)
580 else
581 *phContext = 0;
582
583 pthread_once(&init_lib_control, init_lib);
584 if (!isExecuted)
585 return SCARD_E_NO_MEMORY;
586
587 /* Establishes a connection to the server */
588 if (ClientSetupSession(&dwClientID) != 0)
589 {
590 return SCARD_E_NO_SERVICE;
591 }
592
595
596connect_again:
597 /* exchange client/server protocol versions */
598
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");
612 goto cleanup;
613 }
614
615 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
616 veStr.major, veStr.minor);
617 Log3(PCSC_LOG_INFO, "Client is protocol version %d:%d",
619
620 if (SCARD_E_SERVICE_STOPPED == veStr.rv)
621 {
622 /* server complained about our protocol version? */
623 if (PROTOCOL_VERSION_MAJOR == veStr.major)
624 {
626 {
627 /* try again with the protocol version proposed by
628 * the server */
629 Log1(PCSC_LOG_INFO, "Using backward compatibility");
630 goto connect_again;
631 }
632 }
633 }
634
635 if (veStr.rv != SCARD_S_SUCCESS)
636 {
637 rv = veStr.rv;
638 goto cleanup;
639 }
640
641 /* store protocol version of the server */
642 Protocol_version = veStr.major * 1000 + veStr.minor;
643
644again:
645 /*
646 * Try to establish an Application Context with the server
647 */
648 scEstablishStruct.dwScope = dwScope;
649 scEstablishStruct.hContext = 0;
650 scEstablishStruct.rv = SCARD_S_SUCCESS;
651
653 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
654
655 if (rv != SCARD_S_SUCCESS)
656 goto cleanup;
657
658 /*
659 * Read the response from the server
660 */
661 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
662 dwClientID);
663
664 if (rv != SCARD_S_SUCCESS)
665 goto cleanup;
666
667 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
668 {
669 rv = scEstablishStruct.rv;
670 goto cleanup;
671 }
672
673 /* check we do not reuse an existing hContext */
674 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
675 /* we do not need to release the allocated context since
676 * SCardReleaseContext() does nothing on the server side */
677 goto again;
678
679 *phContext = scEstablishStruct.hContext;
680
681 /*
682 * Allocate the new hContext - if allocator full return an error
683 */
684 rv = SCardAddContext(*phContext, dwClientID);
685
686 return rv;
687
688cleanup:
689 ClientCloseSession(dwClientID);
690
691 return rv;
692}
693
716{
717 LONG rv;
718 struct release_struct scReleaseStruct;
719 SCONTEXTMAP * currentContextMap;
720
721 API_TRACE_IN("%ld", hContext)
722 PROFILE_START
723
724 /*
725 * Make sure this context has been opened
726 * and get currentContextMap
727 */
728 currentContextMap = SCardGetAndLockContext(hContext);
729 if (NULL == currentContextMap)
730 {
732 goto error;
733 }
734
735 scReleaseStruct.hContext = hContext;
736 scReleaseStruct.rv = SCARD_S_SUCCESS;
737
739 currentContextMap->dwClientID,
740 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
741
742 if (rv != SCARD_S_SUCCESS)
743 goto end;
744
745 /*
746 * Read a message from the server
747 */
748 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
749 currentContextMap->dwClientID);
750
751 if (rv != SCARD_S_SUCCESS)
752 goto end;
753
754 rv = scReleaseStruct.rv;
755end:
756 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
757
758 /*
759 * Remove the local context from the stack
760 */
762 SCardRemoveContext(hContext);
764
765error:
766 PROFILE_END(rv)
767 API_TRACE_OUT("")
768
769 return rv;
770}
771
827LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
828 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
829 LPDWORD pdwActiveProtocol)
830{
831 LONG rv;
832 struct connect_struct scConnectStruct;
833 SCONTEXTMAP * currentContextMap;
834
835 PROFILE_START
836 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
837
838 /*
839 * Check for NULL parameters
840 */
841 if (phCard == NULL || pdwActiveProtocol == NULL)
843 else
844 *phCard = 0;
845
846 if (szReader == NULL)
848
849 /*
850 * Check for uninitialized strings
851 */
852 if (strlen(szReader) > MAX_READERNAME)
854
855 /*
856 * Make sure this context has been opened
857 */
858 currentContextMap = SCardGetAndLockContext(hContext);
859 if (NULL == currentContextMap)
861
862 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
863 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
864 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
865
866 scConnectStruct.hContext = hContext;
867 scConnectStruct.dwShareMode = dwShareMode;
868 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
869 scConnectStruct.hCard = 0;
870 scConnectStruct.dwActiveProtocol = 0;
871 scConnectStruct.rv = SCARD_S_SUCCESS;
872
873 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
874 sizeof(scConnectStruct), (void *) &scConnectStruct);
875
876 if (rv != SCARD_S_SUCCESS)
877 goto end;
878
879 /*
880 * Read a message from the server
881 */
882 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
883 currentContextMap->dwClientID);
884
885 if (rv != SCARD_S_SUCCESS)
886 goto end;
887
888 *phCard = scConnectStruct.hCard;
889 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
890
891 if (scConnectStruct.rv == SCARD_S_SUCCESS)
892 {
893 /*
894 * Keep track of the handle locally
895 */
896 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
897 }
898 else
899 rv = scConnectStruct.rv;
900
901end:
902 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
903
904 PROFILE_END(rv)
905 API_TRACE_OUT("%d", *pdwActiveProtocol)
906
907 return rv;
908}
909
982LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
983 DWORD dwPreferredProtocols, DWORD dwInitialization,
984 LPDWORD pdwActiveProtocol)
985{
986 LONG rv;
987 struct reconnect_struct scReconnectStruct;
988 SCONTEXTMAP * currentContextMap;
989 CHANNEL_MAP * pChannelMap;
990
991 PROFILE_START
992 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
993
994 if (pdwActiveProtocol == NULL)
996
997 /* Retry loop for blocking behaviour */
998retry:
999
1000 /*
1001 * Make sure this handle has been opened
1002 */
1003 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1004 &pChannelMap);
1005 if (rv == -1)
1007
1008 scReconnectStruct.hCard = hCard;
1009 scReconnectStruct.dwShareMode = dwShareMode;
1010 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
1011 scReconnectStruct.dwInitialization = dwInitialization;
1012 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
1013 scReconnectStruct.rv = SCARD_S_SUCCESS;
1014
1015 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
1016 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
1017
1018 if (rv != SCARD_S_SUCCESS)
1019 goto end;
1020
1021 /*
1022 * Read a message from the server
1023 */
1024 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1025 currentContextMap->dwClientID);
1026
1027 if (rv != SCARD_S_SUCCESS)
1028 goto end;
1029
1030 rv = scReconnectStruct.rv;
1031
1032 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1033 {
1034 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1035 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1036 goto retry;
1037 }
1038
1039 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1040
1041end:
1042 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1043
1044 PROFILE_END(rv)
1045 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1046
1047 return rv;
1048}
1049
1081LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1082{
1083 LONG rv;
1084 struct disconnect_struct scDisconnectStruct;
1085 SCONTEXTMAP * currentContextMap;
1086 CHANNEL_MAP * pChannelMap;
1087
1088 PROFILE_START
1089 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1090
1091 /*
1092 * Make sure this handle has been opened
1093 */
1094 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1095 &pChannelMap);
1096 if (rv == -1)
1097 {
1099 goto error;
1100 }
1101
1102 scDisconnectStruct.hCard = hCard;
1103 scDisconnectStruct.dwDisposition = dwDisposition;
1104 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1105
1106 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1107 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1108
1109 if (rv != SCARD_S_SUCCESS)
1110 goto end;
1111
1112 /*
1113 * Read a message from the server
1114 */
1115 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1116 currentContextMap->dwClientID);
1117
1118 if (rv != SCARD_S_SUCCESS)
1119 goto end;
1120
1121 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1122 SCardRemoveHandle(hCard);
1123 rv = scDisconnectStruct.rv;
1124
1125end:
1126 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1127
1128error:
1129 PROFILE_END(rv)
1130 API_TRACE_OUT("")
1131
1132 return rv;
1133}
1134
1172{
1173
1174 LONG rv;
1175 struct begin_struct scBeginStruct;
1176 SCONTEXTMAP * currentContextMap;
1177 CHANNEL_MAP * pChannelMap;
1178
1179 PROFILE_START
1180 API_TRACE_IN("%ld", hCard)
1181
1182 /*
1183 * Query the server every so often until the sharing violation ends
1184 * and then hold the lock for yourself.
1185 */
1186
1187 for(;;)
1188 {
1189 /*
1190 * Make sure this handle has been opened
1191 */
1192 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1193 &pChannelMap);
1194 if (rv == -1)
1196
1197 scBeginStruct.hCard = hCard;
1198 scBeginStruct.rv = SCARD_S_SUCCESS;
1199
1201 currentContextMap->dwClientID,
1202 sizeof(scBeginStruct), (void *) &scBeginStruct);
1203
1204 if (rv != SCARD_S_SUCCESS)
1205 break;
1206
1207 /*
1208 * Read a message from the server
1209 */
1210 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1211 currentContextMap->dwClientID);
1212
1213 if (rv != SCARD_S_SUCCESS)
1214 break;
1215
1216 rv = scBeginStruct.rv;
1217
1218 if (SCARD_E_SHARING_VIOLATION != rv)
1219 break;
1220
1221 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1222 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1223 }
1224
1225 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1226
1227 PROFILE_END(rv)
1228 API_TRACE_OUT("")
1229
1230 return rv;
1231}
1232
1272LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1273{
1274 LONG rv;
1275 struct end_struct scEndStruct;
1276 SCONTEXTMAP * currentContextMap;
1277 CHANNEL_MAP * pChannelMap;
1278
1279 PROFILE_START
1280 API_TRACE_IN("%ld", hCard)
1281
1282 /*
1283 * Make sure this handle has been opened
1284 */
1285 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1286 &pChannelMap);
1287 if (rv == -1)
1289
1290 scEndStruct.hCard = hCard;
1291 scEndStruct.dwDisposition = dwDisposition;
1292 scEndStruct.rv = SCARD_S_SUCCESS;
1293
1295 currentContextMap->dwClientID,
1296 sizeof(scEndStruct), (void *) &scEndStruct);
1297
1298 if (rv != SCARD_S_SUCCESS)
1299 goto end;
1300
1301 /*
1302 * Read a message from the server
1303 */
1304 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1305 currentContextMap->dwClientID);
1306
1307 if (rv != SCARD_S_SUCCESS)
1308 goto end;
1309
1310 rv = scEndStruct.rv;
1311
1312end:
1313 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1314
1315 PROFILE_END(rv)
1316 API_TRACE_OUT("")
1317
1318 return rv;
1319}
1320
1416LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1417 LPDWORD pcchReaderLen, LPDWORD pdwState,
1418 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1419{
1420 DWORD dwReaderLen, dwAtrLen;
1421 LONG rv;
1422 int i;
1423 struct status_struct scStatusStruct;
1424 SCONTEXTMAP * currentContextMap;
1425 CHANNEL_MAP * pChannelMap;
1426 char *r;
1427 char *bufReader = NULL;
1428 LPBYTE bufAtr = NULL;
1429 DWORD dummy = 0;
1430
1431 PROFILE_START
1432
1433 /* default output values */
1434 if (pdwState)
1435 *pdwState = 0;
1436
1437 if (pdwProtocol)
1438 *pdwProtocol = 0;
1439
1440 /* Check for NULL parameters */
1441 if (pcchReaderLen == NULL)
1442 pcchReaderLen = &dummy;
1443
1444 if (pcbAtrLen == NULL)
1445 pcbAtrLen = &dummy;
1446
1447 /* length passed from caller */
1448 dwReaderLen = *pcchReaderLen;
1449 dwAtrLen = *pcbAtrLen;
1450
1451 *pcchReaderLen = 0;
1452 *pcbAtrLen = 0;
1453
1454 /* Retry loop for blocking behaviour */
1455retry:
1456
1457 /*
1458 * Make sure this handle has been opened
1459 */
1460 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1461 &pChannelMap);
1462 if (rv == -1)
1464
1465 /* lock access to readerStates[] */
1466 (void)pthread_mutex_lock(&readerStatesMutex);
1467
1468 /* synchronize reader states with daemon */
1469 rv = getReaderStates(currentContextMap);
1470 if (rv != SCARD_S_SUCCESS)
1471 goto end;
1472
1473 r = pChannelMap->readerName;
1474 for (i = 0; i < pcsclite_max_reader_context; i++)
1475 {
1476 /* by default r == NULL */
1477 if (r && strcmp(r, readerStates[i].readerName) == 0)
1478 break;
1479 }
1480
1481 if (i == pcsclite_max_reader_context)
1482 {
1484 goto end;
1485 }
1486
1487 /* initialise the structure */
1488 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1489 scStatusStruct.hCard = hCard;
1490
1491 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1492 sizeof(scStatusStruct), (void *) &scStatusStruct);
1493
1494 if (rv != SCARD_S_SUCCESS)
1495 goto end;
1496
1497 /*
1498 * Read a message from the server
1499 */
1500 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1501 currentContextMap->dwClientID);
1502
1503 if (rv != SCARD_S_SUCCESS)
1504 goto end;
1505
1506 rv = scStatusStruct.rv;
1507
1508 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1509 {
1510 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1511 (void)pthread_mutex_unlock(&readerStatesMutex);
1512 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1513 goto retry;
1514 }
1515
1517 {
1518 /*
1519 * An event must have occurred
1520 */
1521 goto end;
1522 }
1523
1524 /*
1525 * Now continue with the client side SCardStatus
1526 */
1527
1528 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1529 *pcbAtrLen = readerStates[i].cardAtrLength;
1530
1531 if (pdwState)
1532 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1533
1534 if (pdwProtocol)
1535 *pdwProtocol = readerStates[i].cardProtocol;
1536
1537 if (SCARD_AUTOALLOCATE == dwReaderLen)
1538 {
1539 dwReaderLen = *pcchReaderLen;
1540 if (NULL == szReaderName)
1541 {
1543 goto end;
1544 }
1545 bufReader = malloc(dwReaderLen);
1546 if (NULL == bufReader)
1547 {
1548 rv = SCARD_E_NO_MEMORY;
1549 goto end;
1550 }
1551 *(char **)szReaderName = bufReader;
1552 }
1553 else
1554 bufReader = szReaderName;
1555
1556 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1557 if (bufReader)
1558 {
1559 if (*pcchReaderLen > dwReaderLen)
1561
1562 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1563 }
1564
1565 if (SCARD_AUTOALLOCATE == dwAtrLen)
1566 {
1567 dwAtrLen = *pcbAtrLen;
1568 if (NULL == pbAtr)
1569 {
1571 goto end;
1572 }
1573 bufAtr = malloc(dwAtrLen);
1574 if (NULL == bufAtr)
1575 {
1576 rv = SCARD_E_NO_MEMORY;
1577 goto end;
1578 }
1579 *(LPBYTE *)pbAtr = bufAtr;
1580 }
1581 else
1582 bufAtr = pbAtr;
1583
1584 if (bufAtr)
1585 {
1586 if (*pcbAtrLen > dwAtrLen)
1588
1589 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1590 }
1591
1592end:
1593 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1594 (void)pthread_mutex_unlock(&readerStatesMutex);
1595
1596 PROFILE_END(rv)
1597
1598 return rv;
1599}
1600
1712LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1713 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1714{
1715 SCARD_READERSTATE *currReader;
1716 READER_STATE *rContext;
1717 long dwTime;
1718 DWORD dwBreakFlag = 0;
1719 unsigned int j;
1720 SCONTEXTMAP * currentContextMap;
1721 int currentReaderCount = 0;
1722 LONG rv = SCARD_S_SUCCESS;
1723 int pnp_reader = -1;
1724
1725 PROFILE_START
1726 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1727#ifdef DO_TRACE
1728 for (j=0; j<cReaders; j++)
1729 {
1730 API_TRACE_IN("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1731 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1732 rgReaderStates[j].cbAtr)
1733 }
1734#endif
1735
1736 if (rgReaderStates == NULL && cReaders > 0)
1737 {
1739 goto error;
1740 }
1741
1742 /* Check the integrity of the reader states structures */
1743 for (j = 0; j < cReaders; j++)
1744 {
1745 if (rgReaderStates[j].szReader == NULL)
1746 return SCARD_E_INVALID_VALUE;
1747 }
1748
1749 /* return if all readers are SCARD_STATE_IGNORE */
1750 if (cReaders > 0)
1751 {
1752 int nbNonIgnoredReaders = cReaders;
1753
1754 for (j=0; j<cReaders; j++)
1755 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1756 nbNonIgnoredReaders--;
1757
1758 if (0 == nbNonIgnoredReaders)
1759 {
1760 rv = SCARD_S_SUCCESS;
1761 goto error;
1762 }
1763 }
1764 else
1765 {
1766 /* reader list is empty */
1767 rv = SCARD_S_SUCCESS;
1768 goto error;
1769 }
1770
1771 /*
1772 * Make sure this context has been opened
1773 */
1774 currentContextMap = SCardGetAndLockContext(hContext);
1775 if (NULL == currentContextMap)
1776 {
1778 goto error;
1779 }
1780
1781 /* lock access to readerStates[] */
1782 (void)pthread_mutex_lock(&readerStatesMutex);
1783
1784 /* synchronize reader states with daemon */
1785 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1786
1787 if (rv != SCARD_S_SUCCESS)
1788 {
1789 (void)pthread_mutex_unlock(&readerStatesMutex);
1790 goto end;
1791 }
1792
1793 /* check all the readers are already known */
1794 for (j=0; j<cReaders; j++)
1795 {
1796 const char *readerName;
1797 int i;
1798
1799 readerName = rgReaderStates[j].szReader;
1800 for (i = 0; i < pcsclite_max_reader_context; i++)
1801 {
1802 if (strcmp(readerName, readerStates[i].readerName) == 0)
1803 break;
1804 }
1805
1806 /* The requested reader name is not recognized */
1807 if (i == pcsclite_max_reader_context)
1808 {
1809 /* PnP special reader? */
1810 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1811 {
1813 (void)pthread_mutex_unlock(&readerStatesMutex);
1814 goto end;
1815 }
1816 else
1817 pnp_reader = j;
1818 }
1819 }
1820 (void)pthread_mutex_unlock(&readerStatesMutex);
1821
1822 /* Clear the event state for all readers */
1823 for (j = 0; j < cReaders; j++)
1824 rgReaderStates[j].dwEventState = 0;
1825
1826 /* Now is where we start our event checking loop */
1827 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1828
1829 /* index of the PnP readerin rgReaderStates[] */
1830 if (pnp_reader >= 0)
1831 {
1832 int readerEvents;
1833 currReader = &rgReaderStates[pnp_reader];
1834
1835 /* PnP special reader */
1836 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1837 {
1838 int previousReaderEvents = currReader->dwCurrentState >> 16;
1839
1840 // store readerEvents in .dwEventState high word
1841 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1842 if (
1843 /* the value has changed since the last call */
1844 (previousReaderEvents != readerEvents)
1845 /* backward compatibility: only if we had a non-null
1846 * reader events value */
1847 && previousReaderEvents)
1848 {
1849 currReader->dwEventState |= SCARD_STATE_CHANGED;
1850 rv = SCARD_S_SUCCESS;
1851 dwBreakFlag = 1;
1852 }
1853 }
1854 }
1855
1856 /* Get the initial reader count on the system */
1857 for (int k=0; k < pcsclite_max_reader_context; k++)
1858 if (readerStates[k].readerName[0] != '\0')
1859 currentReaderCount++;
1860
1861 /* catch possible sign extension problems from 32 to 64-bits integers */
1862 if ((DWORD)-1 == dwTimeout)
1863 dwTimeout = INFINITE;
1864 if (INFINITE == dwTimeout)
1865 dwTime = 60*1000; /* "infinite" timeout */
1866 else
1867 dwTime = dwTimeout;
1868
1869 j = 0;
1870 do
1871 {
1872 currReader = &rgReaderStates[j];
1873
1874 /* Ignore for IGNORED readers */
1875 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1876 {
1877 const char *readerName;
1878 int i;
1879
1880 /* lock access to readerStates[] */
1881 (void)pthread_mutex_lock(&readerStatesMutex);
1882
1883 /* Looks for correct readernames */
1884 readerName = currReader->szReader;
1885 for (i = 0; i < pcsclite_max_reader_context; i++)
1886 {
1887 if (strcmp(readerName, readerStates[i].readerName) == 0)
1888 break;
1889 }
1890
1891 /* The requested reader name is not recognized */
1892 if (i == pcsclite_max_reader_context)
1893 {
1894 /* PnP special reader? */
1895 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1896 {
1897 int k, newReaderCount = 0;
1898
1899 for (k=0; k < pcsclite_max_reader_context; k++)
1900 if (readerStates[k].readerName[0] != '\0')
1901 newReaderCount++;
1902
1903 if (newReaderCount != currentReaderCount)
1904 {
1905 int readerEvents;
1906
1907 Log1(PCSC_LOG_INFO, "Reader list changed");
1908 currentReaderCount = newReaderCount;
1909
1910 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1911 {
1912 // store readerEvents in .dwEventState high word
1913 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1914 }
1915
1916 currReader->dwEventState |= SCARD_STATE_CHANGED;
1917 dwBreakFlag = 1;
1918 }
1919 }
1920 else
1921 {
1922 currReader->dwEventState =
1924 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1925 {
1926 currReader->dwEventState |= SCARD_STATE_CHANGED;
1927 /*
1928 * Spec says use SCARD_STATE_IGNORE but a removed USB
1929 * reader with eventState fed into currentState will
1930 * be ignored forever
1931 */
1932 dwBreakFlag = 1;
1933 }
1934 }
1935 }
1936 else
1937 {
1938 uint32_t readerState;
1939
1940 /* The reader has come back after being away */
1941 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1942 {
1943 currReader->dwEventState |= SCARD_STATE_CHANGED;
1944 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1945 Log0(PCSC_LOG_DEBUG);
1946 dwBreakFlag = 1;
1947 }
1948
1949 /* Set the reader status structure */
1950 rContext = &readerStates[i];
1951
1952 /* Now we check all the Reader States */
1953 readerState = rContext->readerState;
1954
1955 /* only if current state has an non null event counter */
1956 if (currReader->dwCurrentState & 0xFFFF0000)
1957 {
1958 unsigned int currentCounter;
1959
1960 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1961
1962 /* has the event counter changed since the last call? */
1963 if (rContext->eventCounter != currentCounter)
1964 {
1965 currReader->dwEventState |= SCARD_STATE_CHANGED;
1966 Log0(PCSC_LOG_DEBUG);
1967 dwBreakFlag = 1;
1968 }
1969 }
1970
1971 /* add an event counter in the upper word of dwEventState */
1972 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1973 | (rContext->eventCounter << 16));
1974
1975 /* Check if the reader is in the correct state */
1976 if (readerState & SCARD_UNKNOWN)
1977 {
1978 /* reader is in bad state */
1979 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1980 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1981 {
1982 /* App thinks reader is in good state and it is not */
1983 currReader->dwEventState |= SCARD_STATE_CHANGED;
1984 Log0(PCSC_LOG_DEBUG);
1985 dwBreakFlag = 1;
1986 }
1987 }
1988 else
1989 {
1990 /* App thinks reader in bad state but it is not */
1991 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1992 {
1993 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1994 currReader->dwEventState |= SCARD_STATE_CHANGED;
1995 Log0(PCSC_LOG_DEBUG);
1996 dwBreakFlag = 1;
1997 }
1998 }
1999
2000 /* Check for card presence in the reader */
2001 if (readerState & SCARD_PRESENT)
2002 {
2003#ifndef DISABLE_AUTO_POWER_ON
2004 /* card present but not yet powered up */
2005 if (0 == rContext->cardAtrLength)
2006 /* Allow the status thread to convey information */
2007 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2008#endif
2009
2010 currReader->cbAtr = rContext->cardAtrLength;
2011 memcpy(currReader->rgbAtr, rContext->cardAtr,
2012 currReader->cbAtr);
2013 }
2014 else
2015 currReader->cbAtr = 0;
2016
2017 /* Card is now absent */
2018 if (readerState & SCARD_ABSENT)
2019 {
2020 currReader->dwEventState |= SCARD_STATE_EMPTY;
2021 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
2022 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2023 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2024 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2025 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2026 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
2027 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2028 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2029
2030 /* After present the rest are assumed */
2031 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2032 {
2033 currReader->dwEventState |= SCARD_STATE_CHANGED;
2034 Log0(PCSC_LOG_DEBUG);
2035 dwBreakFlag = 1;
2036 }
2037 }
2038 /* Card is now present */
2039 else if (readerState & SCARD_PRESENT)
2040 {
2041 currReader->dwEventState |= SCARD_STATE_PRESENT;
2042 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2043 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2044 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2045 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2046 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2047 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2048
2049 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2050 {
2051 currReader->dwEventState |= SCARD_STATE_CHANGED;
2052 Log0(PCSC_LOG_DEBUG);
2053 dwBreakFlag = 1;
2054 }
2055
2056 if (readerState & SCARD_SWALLOWED)
2057 {
2058 currReader->dwEventState |= SCARD_STATE_MUTE;
2059 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2060 {
2061 currReader->dwEventState |= SCARD_STATE_CHANGED;
2062 Log0(PCSC_LOG_DEBUG);
2063 dwBreakFlag = 1;
2064 }
2065 }
2066 else
2067 {
2068 /* App thinks card is mute but it is not */
2069 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2070 {
2071 currReader->dwEventState |= SCARD_STATE_CHANGED;
2072 Log0(PCSC_LOG_DEBUG);
2073 dwBreakFlag = 1;
2074 }
2075 }
2076 }
2077
2078 /* Now figure out sharing modes */
2080 {
2081 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2082 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2083 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2084 {
2085 currReader->dwEventState |= SCARD_STATE_CHANGED;
2086 Log0(PCSC_LOG_DEBUG);
2087 dwBreakFlag = 1;
2088 }
2089 }
2090 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2091 {
2092 /* A card must be inserted for it to be INUSE */
2093 if (readerState & SCARD_PRESENT)
2094 {
2095 currReader->dwEventState |= SCARD_STATE_INUSE;
2096 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2097 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2098 {
2099 currReader->dwEventState |= SCARD_STATE_CHANGED;
2100 Log0(PCSC_LOG_DEBUG);
2101 dwBreakFlag = 1;
2102 }
2103 }
2104 }
2105 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2106 {
2107 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2108 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2109
2110 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2111 {
2112 currReader->dwEventState |= SCARD_STATE_CHANGED;
2113 Log0(PCSC_LOG_DEBUG);
2114 dwBreakFlag = 1;
2115 }
2116 else if (currReader-> dwCurrentState
2118 {
2119 currReader->dwEventState |= SCARD_STATE_CHANGED;
2120 Log0(PCSC_LOG_DEBUG);
2121 dwBreakFlag = 1;
2122 }
2123 }
2124
2125 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2126 {
2127 /*
2128 * Break out of the while .. loop and return status
2129 * once all the status's for all readers is met
2130 */
2131 currReader->dwEventState |= SCARD_STATE_CHANGED;
2132 Log0(PCSC_LOG_DEBUG);
2133 dwBreakFlag = 1;
2134 }
2135 } /* End of SCARD_STATE_UNKNOWN */
2136
2137 (void)pthread_mutex_unlock(&readerStatesMutex);
2138 } /* End of SCARD_STATE_IGNORE */
2139
2140 /* Counter and resetter */
2141 j++;
2142 if (j == cReaders)
2143 {
2144 /* go back to the first reader */
2145 j = 0;
2146
2147 /* Declare all the break conditions */
2148
2149 /* Break if UNAWARE is set and all readers have been checked */
2150 if (dwBreakFlag == 1)
2151 break;
2152
2153 /* Only sleep once for each cycle of reader checks. */
2154 {
2155 struct wait_reader_state_change waitStatusStruct = {0};
2156 struct timeval before, after;
2157
2158 gettimeofday(&before, NULL);
2159
2160 waitStatusStruct.rv = SCARD_S_SUCCESS;
2161
2162 /* another thread can do SCardCancel() */
2163 currentContextMap->cancellable = true;
2164
2165 /*
2166 * Read a message from the server
2167 */
2169 &waitStatusStruct, sizeof(waitStatusStruct),
2170 currentContextMap->dwClientID, dwTime);
2171
2172 /* SCardCancel() will return immediately with success
2173 * because something changed on the daemon side. */
2174 currentContextMap->cancellable = false;
2175
2176 /* timeout */
2177 if (SCARD_E_TIMEOUT == rv)
2178 {
2179 /* ask server to remove us from the event list */
2180 rv = unregisterFromEvents(currentContextMap);
2181 }
2182
2183 if (rv != SCARD_S_SUCCESS)
2184 goto end;
2185
2186 /* an event occurs or SCardCancel() was called */
2187 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2188 {
2189 rv = waitStatusStruct.rv;
2190 goto end;
2191 }
2192
2193 /* synchronize reader states with daemon */
2194 (void)pthread_mutex_lock(&readerStatesMutex);
2195 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2196 (void)pthread_mutex_unlock(&readerStatesMutex);
2197 if (rv != SCARD_S_SUCCESS)
2198 goto end;
2199
2200 if (INFINITE != dwTimeout)
2201 {
2202 long int diff;
2203
2204 gettimeofday(&after, NULL);
2205 diff = time_sub(&after, &before);
2206 dwTime -= diff/1000;
2207 }
2208 }
2209
2210 if (dwTimeout != INFINITE)
2211 {
2212 /* If time is greater than timeout and all readers have been
2213 * checked
2214 */
2215 if (dwTime <= 0)
2216 {
2217 rv = SCARD_E_TIMEOUT;
2218 goto end;
2219 }
2220 }
2221 }
2222 }
2223 while (1);
2224
2225end:
2226 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2227
2228 /* if SCardCancel() has been used then the client is already
2229 * unregistered */
2230 if (SCARD_E_CANCELLED != rv)
2231 (void)unregisterFromEvents(currentContextMap);
2232
2233 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2234
2235error:
2236 PROFILE_END(rv)
2237#ifdef DO_TRACE
2238 for (j=0; j<cReaders; j++)
2239 {
2240 API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2241 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2242 rgReaderStates[j].cbAtr)
2243 }
2244#endif
2245
2246 return rv;
2247}
2248
2299LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2300 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2301 LPDWORD lpBytesReturned)
2302{
2303 LONG rv;
2304 struct control_struct scControlStruct;
2305 SCONTEXTMAP * currentContextMap;
2306 CHANNEL_MAP * pChannelMap;
2307
2308 PROFILE_START
2309
2310 /* 0 bytes received by default */
2311 if (NULL != lpBytesReturned)
2312 *lpBytesReturned = 0;
2313
2314 /*
2315 * Make sure this handle has been opened
2316 */
2317 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2318 &pChannelMap);
2319 if (rv == -1)
2320 {
2321 PROFILE_END(SCARD_E_INVALID_HANDLE)
2323 }
2324
2325 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2326 {
2328 goto end;
2329 }
2330
2331 scControlStruct.hCard = hCard;
2332 scControlStruct.dwControlCode = dwControlCode;
2333 scControlStruct.cbSendLength = cbSendLength;
2334 scControlStruct.cbRecvLength = cbRecvLength;
2335 scControlStruct.dwBytesReturned = 0;
2336 scControlStruct.rv = 0;
2337
2338 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2339 sizeof(scControlStruct), &scControlStruct);
2340
2341 if (rv != SCARD_S_SUCCESS)
2342 goto end;
2343
2344 /* write the sent buffer */
2345 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2346 currentContextMap->dwClientID);
2347
2348 if (rv != SCARD_S_SUCCESS)
2349 goto end;
2350
2351 /*
2352 * Read a message from the server
2353 */
2354 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2355 currentContextMap->dwClientID);
2356
2357 if (rv != SCARD_S_SUCCESS)
2358 goto end;
2359
2360 if (SCARD_S_SUCCESS == scControlStruct.rv)
2361 {
2362 if (scControlStruct.dwBytesReturned > cbRecvLength)
2363 {
2364 if (NULL != lpBytesReturned)
2365 *lpBytesReturned = scControlStruct.dwBytesReturned;
2367 goto end;
2368 }
2369
2370 /* read the received buffer */
2371 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2372 currentContextMap->dwClientID);
2373
2374 if (rv != SCARD_S_SUCCESS)
2375 goto end;
2376
2377 }
2378
2379 if (NULL != lpBytesReturned)
2380 *lpBytesReturned = scControlStruct.dwBytesReturned;
2381
2382 rv = scControlStruct.rv;
2383
2384end:
2385 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2386
2387 PROFILE_END(rv)
2388
2389 return rv;
2390}
2391
2510LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2511 LPDWORD pcbAttrLen)
2512{
2513 LONG ret;
2514 unsigned char *buf = NULL;
2515
2516 PROFILE_START
2517
2518 if (NULL == pcbAttrLen)
2519 {
2521 goto end;
2522 }
2523
2524 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2525 {
2526 if (NULL == pbAttr)
2528
2529 *pcbAttrLen = MAX_BUFFER_SIZE;
2530 buf = malloc(*pcbAttrLen);
2531 if (NULL == buf)
2532 {
2533 ret = SCARD_E_NO_MEMORY;
2534 goto end;
2535 }
2536
2537 *(unsigned char **)pbAttr = buf;
2538 }
2539 else
2540 {
2541 buf = pbAttr;
2542
2543 /* if only get the length */
2544 if (NULL == pbAttr)
2545 /* use a reasonable size */
2546 *pcbAttrLen = MAX_BUFFER_SIZE;
2547 }
2548
2549 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2550 pcbAttrLen);
2551
2552end:
2553 PROFILE_END(ret)
2554
2555 return ret;
2556}
2557
2593LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2594 DWORD cbAttrLen)
2595{
2596 LONG ret;
2597
2598 PROFILE_START
2599
2600 if (NULL == pbAttr || 0 == cbAttrLen)
2602
2603 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2604 &cbAttrLen);
2605
2606 PROFILE_END(ret)
2607
2608 return ret;
2609}
2610
2611static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2612 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2613{
2614 LONG rv;
2615 struct getset_struct scGetSetStruct;
2616 SCONTEXTMAP * currentContextMap;
2617 CHANNEL_MAP * pChannelMap;
2618
2619 /*
2620 * Make sure this handle has been opened
2621 */
2622 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2623 &pChannelMap);
2624 if (rv == -1)
2626
2627 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2628 {
2630 goto end;
2631 }
2632
2633 scGetSetStruct.hCard = hCard;
2634 scGetSetStruct.dwAttrId = dwAttrId;
2635 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2636 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2637 if (SCARD_SET_ATTRIB == command)
2638 {
2639 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2640 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2641 }
2642 else
2643 /* we can get up to the communication buffer size */
2644 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2645
2646 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2647 sizeof(scGetSetStruct), &scGetSetStruct);
2648
2649 if (rv != SCARD_S_SUCCESS)
2650 goto end;
2651
2652 /*
2653 * Read a message from the server
2654 */
2655 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2656 currentContextMap->dwClientID);
2657
2658 if (rv != SCARD_S_SUCCESS)
2659 goto end;
2660
2661 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2662 {
2663 /*
2664 * Copy and zero it so any secret information is not leaked
2665 */
2666 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2667 {
2668 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2669 * buffer overflow in the memcpy() below */
2670 DWORD correct_value = scGetSetStruct.cbAttrLen;
2671 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2672 *pcbAttrLen = correct_value;
2673
2674 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2675 }
2676 else
2677 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2678
2679 if (pbAttr)
2680 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2681
2682 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2683 }
2684 rv = scGetSetStruct.rv;
2685
2686end:
2687 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2688
2689 return rv;
2690}
2691
2750LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2751 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2752 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2753 LPDWORD pcbRecvLength)
2754{
2755 LONG rv;
2756 SCONTEXTMAP * currentContextMap;
2757 CHANNEL_MAP * pChannelMap;
2758 struct transmit_struct scTransmitStruct;
2759
2760 PROFILE_START
2761
2762 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2763 pcbRecvLength == NULL || pioSendPci == NULL)
2765
2766 /* Retry loop for blocking behaviour */
2767retry:
2768
2769 /*
2770 * Make sure this handle has been opened
2771 */
2772 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2773 &pChannelMap);
2774 if (rv == -1)
2775 {
2776 *pcbRecvLength = 0;
2777 PROFILE_END(SCARD_E_INVALID_HANDLE)
2779 }
2780
2781 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2782 {
2784 goto end;
2785 }
2786
2787 scTransmitStruct.hCard = hCard;
2788 scTransmitStruct.cbSendLength = cbSendLength;
2789 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2790 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2791 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2792 scTransmitStruct.rv = SCARD_S_SUCCESS;
2793
2794 if (pioRecvPci)
2795 {
2796 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2797 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2798 }
2799 else
2800 {
2801 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2802 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2803 }
2804
2805 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2806 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2807
2808 if (rv != SCARD_S_SUCCESS)
2809 goto end;
2810
2811 /* write the sent buffer */
2812 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2813 currentContextMap->dwClientID);
2814
2815 if (rv != SCARD_S_SUCCESS)
2816 goto end;
2817
2818 /*
2819 * Read a message from the server
2820 */
2821 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2822 currentContextMap->dwClientID);
2823
2824 if (rv != SCARD_S_SUCCESS)
2825 goto end;
2826
2827 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2828 {
2829 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2830 {
2831 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2833 goto end;
2834 }
2835
2836 /* read the received buffer */
2837 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2838 currentContextMap->dwClientID);
2839
2840 if (rv != SCARD_S_SUCCESS)
2841 goto end;
2842
2843 if (pioRecvPci)
2844 {
2845 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2846 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2847 }
2848 }
2849
2850 rv = scTransmitStruct.rv;
2851
2852 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2853 {
2854 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2855 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2856 goto retry;
2857 }
2858
2859 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2860
2861end:
2862 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2863
2864 PROFILE_END(rv)
2865
2866 return rv;
2867}
2868
2935LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2936 LPSTR mszReaders, LPDWORD pcchReaders)
2937{
2938 DWORD dwReadersLen = 0;
2939 int i;
2940 SCONTEXTMAP * currentContextMap;
2941 LONG rv = SCARD_S_SUCCESS;
2942 char *buf = NULL;
2943
2944 (void)mszGroups;
2945 PROFILE_START
2946 API_TRACE_IN("%ld", hContext)
2947
2948 /*
2949 * Check for NULL parameters
2950 */
2951 if (pcchReaders == NULL)
2953
2954 /*
2955 * Make sure this context has been opened
2956 */
2957 currentContextMap = SCardGetAndLockContext(hContext);
2958 if (NULL == currentContextMap)
2959 {
2960 PROFILE_END(SCARD_E_INVALID_HANDLE)
2962 }
2963
2964 /* lock access to readerStates[] */
2965 (void)pthread_mutex_lock(&readerStatesMutex);
2966
2967 /* synchronize reader states with daemon */
2968 rv = getReaderStates(currentContextMap);
2969 if (rv != SCARD_S_SUCCESS)
2970 goto end;
2971
2972 dwReadersLen = 0;
2973 for (i = 0; i < pcsclite_max_reader_context; i++)
2974 if (readerStates[i].readerName[0] != '\0')
2975 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2976
2977 /* for the last NULL byte */
2978 dwReadersLen += 1;
2979
2980 if (1 == dwReadersLen)
2981 {
2983 goto end;
2984 }
2985
2986 if (SCARD_AUTOALLOCATE == *pcchReaders)
2987 {
2988 if (NULL == mszReaders)
2989 {
2991 goto end;
2992 }
2993 buf = malloc(dwReadersLen);
2994 if (NULL == buf)
2995 {
2996 rv = SCARD_E_NO_MEMORY;
2997 goto end;
2998 }
2999 *(char **)mszReaders = buf;
3000 }
3001 else
3002 {
3003 buf = mszReaders;
3004
3005 /* not enough place to store the reader names */
3006 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3007 {
3009 goto end;
3010 }
3011 }
3012
3013 if (mszReaders == NULL) /* text array not allocated */
3014 goto end;
3015
3016 for (i = 0; i < pcsclite_max_reader_context; i++)
3017 {
3018 if (readerStates[i].readerName[0] != '\0')
3019 {
3020 /*
3021 * Build the multi-string
3022 */
3023 strcpy(buf, readerStates[i].readerName);
3024 buf += strlen(readerStates[i].readerName)+1;
3025 }
3026 }
3027 *buf = '\0'; /* Add the last null */
3028
3029end:
3030 /* set the reader names length */
3031 *pcchReaders = dwReadersLen;
3032
3033 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3034 (void)pthread_mutex_unlock(&readerStatesMutex);
3035
3036 PROFILE_END(rv)
3037 API_TRACE_OUT("%d", *pcchReaders)
3038
3039 return rv;
3040}
3041
3054
3055LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3056{
3057 LONG rv = SCARD_S_SUCCESS;
3058
3059 PROFILE_START
3060
3061 /*
3062 * Make sure this context has been opened
3063 */
3064 if (! SCardGetContextValidity(hContext))
3066
3067 free((void *)pvMem);
3068
3069 PROFILE_END(rv)
3070
3071 return rv;
3072}
3073
3125LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3126 LPDWORD pcchGroups)
3127{
3128 LONG rv = SCARD_S_SUCCESS;
3129 SCONTEXTMAP * currentContextMap;
3130 char *buf = NULL;
3131
3132 PROFILE_START
3133
3134 /* Multi-string with two trailing \0 */
3135 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3136 const unsigned int dwGroups = sizeof(ReaderGroup);
3137
3138 /*
3139 * Make sure this context has been opened
3140 */
3141 currentContextMap = SCardGetAndLockContext(hContext);
3142 if (NULL == currentContextMap)
3144
3145 if (SCARD_AUTOALLOCATE == *pcchGroups)
3146 {
3147 if (NULL == mszGroups)
3148 {
3150 goto end;
3151 }
3152 buf = malloc(dwGroups);
3153 if (NULL == buf)
3154 {
3155 rv = SCARD_E_NO_MEMORY;
3156 goto end;
3157 }
3158 *(char **)mszGroups = buf;
3159 }
3160 else
3161 {
3162 buf = mszGroups;
3163
3164 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3165 {
3167 goto end;
3168 }
3169 }
3170
3171 if (buf)
3172 memcpy(buf, ReaderGroup, dwGroups);
3173
3174end:
3175 *pcchGroups = dwGroups;
3176
3177 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3178
3179 PROFILE_END(rv)
3180
3181 return rv;
3182}
3183
3216{
3217 SCONTEXTMAP * currentContextMap;
3218 LONG rv = SCARD_S_SUCCESS;
3219 uint32_t dwClientID = 0;
3220 struct cancel_struct scCancelStruct;
3221 bool cancellable;
3222
3223 PROFILE_START
3224 API_TRACE_IN("%ld", hContext)
3225
3226 /*
3227 * Make sure this context has been opened
3228 */
3229 (void)SCardLockThread();
3230 currentContextMap = SCardGetContextTH(hContext);
3231
3232 if (NULL == currentContextMap)
3233 {
3234 (void)SCardUnlockThread();
3236 goto error;
3237 }
3238 cancellable = currentContextMap->cancellable;
3239 (void)SCardUnlockThread();
3240
3241 if (! cancellable)
3242 {
3243 rv = SCARD_S_SUCCESS;
3244 goto error;
3245 }
3246
3247 /* create a new connection to the server */
3248 if (ClientSetupSession(&dwClientID) != 0)
3249 {
3250 rv = SCARD_E_NO_SERVICE;
3251 goto error;
3252 }
3253
3254 scCancelStruct.hContext = hContext;
3255 scCancelStruct.rv = SCARD_S_SUCCESS;
3256
3257 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3258 sizeof(scCancelStruct), (void *) &scCancelStruct);
3259
3260 if (rv != SCARD_S_SUCCESS)
3261 goto end;
3262
3263 /*
3264 * Read a message from the server
3265 */
3266 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3267
3268 if (rv != SCARD_S_SUCCESS)
3269 goto end;
3270
3271 rv = scCancelStruct.rv;
3272end:
3273 ClientCloseSession(dwClientID);
3274
3275error:
3276 PROFILE_END(rv)
3277 API_TRACE_OUT("")
3278
3279 return rv;
3280}
3281
3306{
3307 LONG rv;
3308
3309 PROFILE_START
3310 API_TRACE_IN("%ld", hContext)
3311
3312 rv = SCARD_S_SUCCESS;
3313
3314 /*
3315 * Make sure this context has been opened
3316 */
3317 if (! SCardGetContextValidity(hContext))
3319
3320 PROFILE_END(rv)
3321 API_TRACE_OUT("")
3322
3323 return rv;
3324}
3325
3331
3342static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3343{
3344 int lrv;
3345 SCONTEXTMAP * newContextMap;
3346
3347 newContextMap = malloc(sizeof(SCONTEXTMAP));
3348 if (NULL == newContextMap)
3349 return SCARD_E_NO_MEMORY;
3350
3351 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3352 newContextMap->hContext = hContext;
3353 newContextMap->dwClientID = dwClientID;
3354 newContextMap->cancellable = false;
3355
3356 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3357
3358 lrv = list_init(&newContextMap->channelMapList);
3359 if (lrv < 0)
3360 {
3361 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3362 goto error;
3363 }
3364
3365 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3366 CHANNEL_MAP_seeker);
3367 if (lrv <0)
3368 {
3369 Log2(PCSC_LOG_CRITICAL,
3370 "list_attributes_seeker failed with return value: %d", lrv);
3371 list_destroy(&newContextMap->channelMapList);
3372 goto error;
3373 }
3374
3375 (void)pthread_mutex_lock(&contextMapList_lock);
3376 lrv = list_append(&contextMapList, newContextMap);
3377 (void)pthread_mutex_unlock(&contextMapList_lock);
3378 if (lrv < 0)
3379 {
3380 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3381 lrv);
3382 list_destroy(&newContextMap->channelMapList);
3383 goto error;
3384 }
3385
3386 return SCARD_S_SUCCESS;
3387
3388error:
3389
3390 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3391 free(newContextMap);
3392
3393 return SCARD_E_NO_MEMORY;
3394}
3395
3413{
3414 SCONTEXTMAP * currentContextMap;
3415
3417 currentContextMap = SCardGetContextTH(hContext);
3418
3419 /* lock the context (if available) */
3420 if (NULL != currentContextMap)
3421 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3422
3424
3425 return currentContextMap;
3426}
3427
3441{
3442 SCONTEXTMAP * currentContextMap;
3443
3444 (void)pthread_mutex_lock(&contextMapList_lock);
3445 currentContextMap = list_seek(&contextMapList, &hContext);
3446 (void)pthread_mutex_unlock(&contextMapList_lock);
3447
3448 return currentContextMap;
3449}
3450
3458{
3459 SCONTEXTMAP * currentContextMap;
3460 currentContextMap = SCardGetContextTH(hContext);
3461
3462 if (NULL != currentContextMap)
3463 SCardCleanContext(currentContextMap);
3464}
3465
3466static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3467{
3468 int list_index, lrv;
3469 int listSize;
3470 CHANNEL_MAP * currentChannelMap;
3471
3472 targetContextMap->hContext = 0;
3473 ClientCloseSession(targetContextMap->dwClientID);
3474 targetContextMap->dwClientID = 0;
3475 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3476
3477 listSize = list_size(&targetContextMap->channelMapList);
3478 for (list_index = 0; list_index < listSize; list_index++)
3479 {
3480 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3481 list_index);
3482 if (NULL == currentChannelMap)
3483 {
3484 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3485 list_index);
3486 continue;
3487 }
3488 else
3489 {
3490 free(currentChannelMap->readerName);
3491 free(currentChannelMap);
3492 }
3493
3494 }
3495 list_destroy(&targetContextMap->channelMapList);
3496
3497 (void)pthread_mutex_lock(&contextMapList_lock);
3498 lrv = list_delete(&contextMapList, targetContextMap);
3499 (void)pthread_mutex_unlock(&contextMapList_lock);
3500 if (lrv < 0)
3501 {
3502 Log2(PCSC_LOG_CRITICAL,
3503 "list_delete failed with return value: %d", lrv);
3504 }
3505
3506 free(targetContextMap);
3507
3508 return;
3509}
3510
3511/*
3512 * Functions for managing hCard values returned from SCardConnect.
3513 */
3514
3515static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3516 LPCSTR readerName)
3517{
3518 CHANNEL_MAP * newChannelMap;
3519 int lrv = -1;
3520
3521 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3522 if (NULL == newChannelMap)
3523 return SCARD_E_NO_MEMORY;
3524
3525 newChannelMap->hCard = hCard;
3526 newChannelMap->readerName = strdup(readerName);
3527
3528 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3529 if (lrv < 0)
3530 {
3531 free(newChannelMap->readerName);
3532 free(newChannelMap);
3533 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3534 lrv);
3535 return SCARD_E_NO_MEMORY;
3536 }
3537
3538 return SCARD_S_SUCCESS;
3539}
3540
3541static void SCardRemoveHandle(SCARDHANDLE hCard)
3542{
3543 SCONTEXTMAP * currentContextMap;
3544 CHANNEL_MAP * currentChannelMap;
3545 int lrv;
3546 LONG rv;
3547
3548 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3549 &currentChannelMap);
3550 if (rv == -1)
3551 return;
3552
3553 free(currentChannelMap->readerName);
3554
3555 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3556 if (lrv < 0)
3557 {
3558 Log2(PCSC_LOG_CRITICAL,
3559 "list_delete failed with return value: %d", lrv);
3560 }
3561
3562 free(currentChannelMap);
3563
3564 return;
3565}
3566
3567static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3568 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3569{
3570 LONG rv;
3571
3572 if (0 == hCard)
3573 return -1;
3574
3576 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3577 targetChannelMap);
3578
3579 if (SCARD_S_SUCCESS == rv)
3580 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3581
3583
3584 return rv;
3585}
3586
3587static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3588 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3589{
3590 LONG rv = -1;
3591 int listSize;
3592 int list_index;
3593 SCONTEXTMAP * currentContextMap;
3594 CHANNEL_MAP * currentChannelMap;
3595
3596 /* Best to get the caller a crash early if we fail unsafely */
3597 *targetContextMap = NULL;
3598 *targetChannelMap = NULL;
3599
3600 (void)pthread_mutex_lock(&contextMapList_lock);
3601 listSize = list_size(&contextMapList);
3602
3603 for (list_index = 0; list_index < listSize; list_index++)
3604 {
3605 currentContextMap = list_get_at(&contextMapList, list_index);
3606 if (currentContextMap == NULL)
3607 {
3608 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3609 list_index);
3610 continue;
3611 }
3612 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3613 &hCard);
3614 if (currentChannelMap != NULL)
3615 {
3616 *targetContextMap = currentContextMap;
3617 *targetChannelMap = currentChannelMap;
3618 rv = SCARD_S_SUCCESS;
3619 break;
3620 }
3621 }
3622
3623 (void)pthread_mutex_unlock(&contextMapList_lock);
3624
3625 return rv;
3626}
3627
3636{
3637 LONG rv;
3638 struct stat statBuffer;
3639 char *socketName;
3640
3641 socketName = getSocketName();
3642 rv = stat(socketName, &statBuffer);
3643
3644 if (rv != 0)
3645 {
3646 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3647 socketName, strerror(errno));
3648 return SCARD_E_NO_SERVICE;
3649 }
3650
3651 return SCARD_S_SUCCESS;
3652}
3653
3654static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3655{
3656 int32_t dwClientID = currentContextMap->dwClientID;
3657 LONG rv;
3659
3660 /* CMD_GET_READER_EVENTS was added in protocol 4:5 */
3661 if (Protocol_version < 4005)
3663
3664 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3665 if (rv != SCARD_S_SUCCESS)
3666 return rv;
3667
3668 /* Read a message from the server */
3669 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3670 if (rv != SCARD_S_SUCCESS)
3671 return rv;
3672
3673 *readerEvents = get_reader_events.readerEvents;
3674
3675 return SCARD_S_SUCCESS;
3676}
3677
3678static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3679{
3680 int32_t dwClientID = currentContextMap->dwClientID;
3681 LONG rv;
3682 int32_t array_size;
3683
3684 if (Protocol_version <= 4005)
3685 /* protocol up to 4:5 used a fixed size */
3686 array_size = PCSCLITE_MAX_READERS_CONTEXTS;
3687 else
3688 {
3689 rv = MessageSendWithHeader(CMD_GET_READERS_STATE_SIZE, dwClientID, 0, NULL);
3690 if (rv != SCARD_S_SUCCESS)
3691 return rv;
3692
3693 /* Read a message from the server */
3694 rv = MessageReceive(&array_size, sizeof(array_size), dwClientID);
3695 if (rv != SCARD_S_SUCCESS)
3696 return rv;
3697 }
3698
3699 if (array_size > pcsclite_max_reader_context)
3700 {
3701 /* need to resize */
3702 readerStates = realloc(readerStates, array_size * sizeof(readerStates[0]));
3703 if (NULL == readerStates)
3705 pcsclite_max_reader_context = array_size;
3706 }
3707
3708 if (array_size != pcsclite_max_reader_context)
3709 {
3710 /* Should never happen */
3712 }
3713
3714 if (Protocol_version <= 4005)
3715 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3716 else
3717 rv = MessageSendWithHeader(CMD_GET_READERS_STATE_ARRAY, dwClientID, 0, NULL);
3718 if (rv != SCARD_S_SUCCESS)
3719 return rv;
3720
3721 /* Read a message from the server */
3722 rv = MessageReceive(readerStates, array_size * sizeof(readerStates[0]), dwClientID);
3723 if (rv != SCARD_S_SUCCESS)
3724 return rv;
3725
3726 return SCARD_S_SUCCESS;
3727}
3728
3729static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3730{
3731 int32_t dwClientID = currentContextMap->dwClientID;
3732 LONG rv;
3733
3734 /* Get current reader states from server and register on event list */
3736 0, NULL);
3737 if (rv != SCARD_S_SUCCESS)
3738 return rv;
3739
3740 if (Protocol_version <= 4005)
3741 {
3742 /* This should not happen
3743 * pcsclite_max_reader_context should be set to the backward
3744 * compatible value from a previous call to getReaderStates()
3745 * called from SCardStatus() or SCardListReaders() */
3746 if (pcsclite_max_reader_context != PCSCLITE_MAX_READERS_CONTEXTS)
3747 return SCARD_E_NO_SERVICE;
3748
3749 rv = MessageReceive(readerStates, pcsclite_max_reader_context * sizeof(readerStates[0]), dwClientID);
3750 return rv;
3751 }
3752 else
3753 return getReaderStates(currentContextMap);
3754}
3755
3756static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3757{
3758 int32_t dwClientID = currentContextMap->dwClientID;
3759 LONG rv;
3760 struct wait_reader_state_change waitStatusStruct = {0};
3761
3762 /* ask server to remove us from the event list */
3764 dwClientID, 0, NULL);
3765 if (rv != SCARD_S_SUCCESS)
3766 return rv;
3767
3768 /* This message can be the response to
3769 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3770 * cancel notification.
3771 * The server side ensures, that no more messages will be sent to
3772 * the client. */
3773
3774 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3775 dwClientID);
3776 if (rv != SCARD_S_SUCCESS)
3777 return rv;
3778
3779 /* if we received a cancel event the return value will be set
3780 * accordingly */
3781 rv = waitStatusStruct.rv;
3782
3783 return rv;
3784}
3785
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition pcsclite.h:167
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:202
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
Definition pcsclite.h:171
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition pcsclite.h:267
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:261
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:260
#define SCARD_STATE_INUSE
Shared Mode.
Definition pcsclite.h:275
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:234
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition pcsclite.h:270
#define SCARD_STATE_PRESENT
Card inserted.
Definition pcsclite.h:272
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:259
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:258
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:269
#define INFINITE
Infinite timeout.
Definition pcsclite.h:280
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:271
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition pcsclite.h:273
#define SCARD_STATE_MUTE
Unresponsive card.
Definition pcsclite.h:276
#define SCARD_STATE_CHANGED
State has changed.
Definition pcsclite.h:268
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition pcsclite.h:247
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:298
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition pcsclite.h:299
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition pcsclite.h:274
#define SCARD_STATE_UNAWARE
App wants status.
Definition pcsclite.h:266
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader).
Definition pcsclite.h:285
struct pubReaderState READER_STATE
Define an exported public reader state structure so each application gets instant notification of cha...
Protocol Control Information (PCI).
Definition pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition pcsclite.h:82
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
bool cancellable
We are in a cancellable call.
contained in SCARD_BEGIN_TRANSACTION Messages.
contained in SCARD_CANCEL Messages.
contained in SCARD_CONNECT Messages.
contained in SCARD_CONTROL Messages.
contained in SCARD_DISCONNECT Messages.
contained in SCARD_END_TRANSACTION Messages.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
contained in SCARD_GET_ATTRIB and Messages.
list object
Definition simclist.h:181
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition readers.h:54
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition readers.h:56
uint32_t eventCounter
number of card events
Definition readers.h:52
_Atomic uint32_t cardAtrLength
ATR length.
Definition readers.h:57
uint32_t readerState
SCARD_* bit field.
Definition readers.h:53
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.
pthread_mutex_t contextMapList_lock
lock for the above list
struct _psContextMap SCONTEXTMAP
Represents an Application Context on the Client side.
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...
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.
#define PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD
Minor version the client also supports.
@ 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_GET_READERS_STATE_ARRAY
get the readers state array
@ 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()