pcsc-lite 2.5.2
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 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader -1);
863 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
864
865 scConnectStruct.hContext = hContext;
866 scConnectStruct.dwShareMode = dwShareMode;
867 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
868 scConnectStruct.hCard = 0;
869 scConnectStruct.dwActiveProtocol = 0;
870 scConnectStruct.rv = SCARD_S_SUCCESS;
871
872 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
873 sizeof(scConnectStruct), (void *) &scConnectStruct);
874
875 if (rv != SCARD_S_SUCCESS)
876 goto end;
877
878 /*
879 * Read a message from the server
880 */
881 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
882 currentContextMap->dwClientID);
883
884 if (rv != SCARD_S_SUCCESS)
885 goto end;
886
887 *phCard = scConnectStruct.hCard;
888 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
889
890 if (scConnectStruct.rv == SCARD_S_SUCCESS)
891 {
892 /*
893 * Keep track of the handle locally
894 */
895 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
896 }
897 else
898 rv = scConnectStruct.rv;
899
900end:
901 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
902
903 PROFILE_END(rv)
904 API_TRACE_OUT("%d", *pdwActiveProtocol)
905
906 return rv;
907}
908
981LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
982 DWORD dwPreferredProtocols, DWORD dwInitialization,
983 LPDWORD pdwActiveProtocol)
984{
985 LONG rv;
986 struct reconnect_struct scReconnectStruct;
987 SCONTEXTMAP * currentContextMap;
988 CHANNEL_MAP * pChannelMap;
989
990 PROFILE_START
991 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
992
993 if (pdwActiveProtocol == NULL)
995
996 /* Retry loop for blocking behaviour */
997retry:
998
999 /*
1000 * Make sure this handle has been opened
1001 */
1002 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1003 &pChannelMap);
1004 if (rv == -1)
1006
1007 scReconnectStruct.hCard = hCard;
1008 scReconnectStruct.dwShareMode = dwShareMode;
1009 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
1010 scReconnectStruct.dwInitialization = dwInitialization;
1011 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
1012 scReconnectStruct.rv = SCARD_S_SUCCESS;
1013
1014 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
1015 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
1016
1017 if (rv != SCARD_S_SUCCESS)
1018 goto end;
1019
1020 /*
1021 * Read a message from the server
1022 */
1023 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1024 currentContextMap->dwClientID);
1025
1026 if (rv != SCARD_S_SUCCESS)
1027 goto end;
1028
1029 rv = scReconnectStruct.rv;
1030
1031 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1032 {
1033 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1034 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1035 goto retry;
1036 }
1037
1038 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1039
1040end:
1041 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1042
1043 PROFILE_END(rv)
1044 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1045
1046 return rv;
1047}
1048
1080LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1081{
1082 LONG rv;
1083 struct disconnect_struct scDisconnectStruct;
1084 SCONTEXTMAP * currentContextMap;
1085 CHANNEL_MAP * pChannelMap;
1086
1087 PROFILE_START
1088 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1089
1090 /*
1091 * Make sure this handle has been opened
1092 */
1093 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1094 &pChannelMap);
1095 if (rv == -1)
1096 {
1098 goto error;
1099 }
1100
1101 scDisconnectStruct.hCard = hCard;
1102 scDisconnectStruct.dwDisposition = dwDisposition;
1103 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1104
1105 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1106 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1107
1108 if (rv != SCARD_S_SUCCESS)
1109 goto end;
1110
1111 /*
1112 * Read a message from the server
1113 */
1114 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1115 currentContextMap->dwClientID);
1116
1117 if (rv != SCARD_S_SUCCESS)
1118 goto end;
1119
1120 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1121 SCardRemoveHandle(hCard);
1122 rv = scDisconnectStruct.rv;
1123
1124end:
1125 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1126
1127error:
1128 PROFILE_END(rv)
1129 API_TRACE_OUT("")
1130
1131 return rv;
1132}
1133
1171{
1172
1173 LONG rv;
1174 struct begin_struct scBeginStruct;
1175 SCONTEXTMAP * currentContextMap;
1176 CHANNEL_MAP * pChannelMap;
1177
1178 PROFILE_START
1179 API_TRACE_IN("%ld", hCard)
1180
1181 /*
1182 * Query the server every so often until the sharing violation ends
1183 * and then hold the lock for yourself.
1184 */
1185
1186 for(;;)
1187 {
1188 /*
1189 * Make sure this handle has been opened
1190 */
1191 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1192 &pChannelMap);
1193 if (rv == -1)
1195
1196 scBeginStruct.hCard = hCard;
1197 scBeginStruct.rv = SCARD_S_SUCCESS;
1198
1200 currentContextMap->dwClientID,
1201 sizeof(scBeginStruct), (void *) &scBeginStruct);
1202
1203 if (rv != SCARD_S_SUCCESS)
1204 break;
1205
1206 /*
1207 * Read a message from the server
1208 */
1209 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1210 currentContextMap->dwClientID);
1211
1212 if (rv != SCARD_S_SUCCESS)
1213 break;
1214
1215 rv = scBeginStruct.rv;
1216
1217 if (SCARD_E_SHARING_VIOLATION != rv)
1218 break;
1219
1220 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1221 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1222 }
1223
1224 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1225
1226 PROFILE_END(rv)
1227 API_TRACE_OUT("")
1228
1229 return rv;
1230}
1231
1271LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1272{
1273 LONG rv;
1274 struct end_struct scEndStruct;
1275 SCONTEXTMAP * currentContextMap;
1276 CHANNEL_MAP * pChannelMap;
1277
1278 PROFILE_START
1279 API_TRACE_IN("%ld", hCard)
1280
1281 /*
1282 * Make sure this handle has been opened
1283 */
1284 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1285 &pChannelMap);
1286 if (rv == -1)
1288
1289 scEndStruct.hCard = hCard;
1290 scEndStruct.dwDisposition = dwDisposition;
1291 scEndStruct.rv = SCARD_S_SUCCESS;
1292
1294 currentContextMap->dwClientID,
1295 sizeof(scEndStruct), (void *) &scEndStruct);
1296
1297 if (rv != SCARD_S_SUCCESS)
1298 goto end;
1299
1300 /*
1301 * Read a message from the server
1302 */
1303 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1304 currentContextMap->dwClientID);
1305
1306 if (rv != SCARD_S_SUCCESS)
1307 goto end;
1308
1309 rv = scEndStruct.rv;
1310
1311end:
1312 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1313
1314 PROFILE_END(rv)
1315 API_TRACE_OUT("")
1316
1317 return rv;
1318}
1319
1415LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1416 LPDWORD pcchReaderLen, LPDWORD pdwState,
1417 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1418{
1419 DWORD dwReaderLen, dwAtrLen;
1420 LONG rv;
1421 int i;
1422 struct status_struct scStatusStruct;
1423 SCONTEXTMAP * currentContextMap;
1424 CHANNEL_MAP * pChannelMap;
1425 char *r;
1426 char *bufReader = NULL;
1427 LPBYTE bufAtr = NULL;
1428 DWORD dummy = 0;
1429
1430 PROFILE_START
1431
1432 /* default output values */
1433 if (pdwState)
1434 *pdwState = 0;
1435
1436 if (pdwProtocol)
1437 *pdwProtocol = 0;
1438
1439 /* Check for NULL parameters */
1440 if (pcchReaderLen == NULL)
1441 pcchReaderLen = &dummy;
1442
1443 if (pcbAtrLen == NULL)
1444 pcbAtrLen = &dummy;
1445
1446 /* length passed from caller */
1447 dwReaderLen = *pcchReaderLen;
1448 dwAtrLen = *pcbAtrLen;
1449
1450 *pcchReaderLen = 0;
1451 *pcbAtrLen = 0;
1452
1453 /* Retry loop for blocking behaviour */
1454retry:
1455
1456 /*
1457 * Make sure this handle has been opened
1458 */
1459 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1460 &pChannelMap);
1461 if (rv == -1)
1463
1464 /* lock access to readerStates[] */
1465 (void)pthread_mutex_lock(&readerStatesMutex);
1466
1467 /* synchronize reader states with daemon */
1468 rv = getReaderStates(currentContextMap);
1469 if (rv != SCARD_S_SUCCESS)
1470 goto end;
1471
1472 r = pChannelMap->readerName;
1473 for (i = 0; i < pcsclite_max_reader_context; i++)
1474 {
1475 /* by default r == NULL */
1476 if (r && strcmp(r, readerStates[i].readerName) == 0)
1477 break;
1478 }
1479
1480 if (i == pcsclite_max_reader_context)
1481 {
1483 goto end;
1484 }
1485
1486 /* initialise the structure */
1487 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1488 scStatusStruct.hCard = hCard;
1489
1490 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1491 sizeof(scStatusStruct), (void *) &scStatusStruct);
1492
1493 if (rv != SCARD_S_SUCCESS)
1494 goto end;
1495
1496 /*
1497 * Read a message from the server
1498 */
1499 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1500 currentContextMap->dwClientID);
1501
1502 if (rv != SCARD_S_SUCCESS)
1503 goto end;
1504
1505 rv = scStatusStruct.rv;
1506
1507 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1508 {
1509 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1510 (void)pthread_mutex_unlock(&readerStatesMutex);
1511 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1512 goto retry;
1513 }
1514
1516 {
1517 /*
1518 * An event must have occurred
1519 */
1520 goto end;
1521 }
1522
1523 /*
1524 * Now continue with the client side SCardStatus
1525 */
1526
1527 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1528 *pcbAtrLen = readerStates[i].cardAtrLength;
1529
1530 if (pdwState)
1531 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1532
1533 if (pdwProtocol)
1534 *pdwProtocol = readerStates[i].cardProtocol;
1535
1536 if (SCARD_AUTOALLOCATE == dwReaderLen)
1537 {
1538 dwReaderLen = *pcchReaderLen;
1539 if (NULL == szReaderName)
1540 {
1542 goto end;
1543 }
1544 bufReader = malloc(dwReaderLen);
1545 if (NULL == bufReader)
1546 {
1547 rv = SCARD_E_NO_MEMORY;
1548 goto end;
1549 }
1550 *(char **)szReaderName = bufReader;
1551 }
1552 else
1553 bufReader = szReaderName;
1554
1555 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1556 if (bufReader)
1557 {
1558 if (*pcchReaderLen > dwReaderLen)
1560
1561 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1562 }
1563
1564 if (SCARD_AUTOALLOCATE == dwAtrLen)
1565 {
1566 dwAtrLen = *pcbAtrLen;
1567 if (NULL == pbAtr)
1568 {
1570 goto end;
1571 }
1572 bufAtr = malloc(dwAtrLen);
1573 if (NULL == bufAtr)
1574 {
1575 rv = SCARD_E_NO_MEMORY;
1576 goto end;
1577 }
1578 *(LPBYTE *)pbAtr = bufAtr;
1579 }
1580 else
1581 bufAtr = pbAtr;
1582
1583 if (bufAtr)
1584 {
1585 if (*pcbAtrLen > dwAtrLen)
1587
1588 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1589 }
1590
1591end:
1592 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1593 (void)pthread_mutex_unlock(&readerStatesMutex);
1594
1595 PROFILE_END(rv)
1596
1597 return rv;
1598}
1599
1711LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1712 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1713{
1714 SCARD_READERSTATE *currReader;
1715 READER_STATE *rContext;
1716 long dwTime;
1717 DWORD dwBreakFlag = 0;
1718 unsigned int j;
1719 SCONTEXTMAP * currentContextMap;
1720 int currentReaderCount = 0;
1721 LONG rv = SCARD_S_SUCCESS;
1722 int pnp_reader = -1;
1723
1724 PROFILE_START
1725 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1726#ifdef DO_TRACE
1727 for (j=0; j<cReaders; j++)
1728 {
1729 API_TRACE_IN("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1730 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1731 rgReaderStates[j].cbAtr)
1732 }
1733#endif
1734
1735 if (rgReaderStates == NULL && cReaders > 0)
1736 {
1738 goto error;
1739 }
1740
1741 /* Check the integrity of the reader states structures */
1742 for (j = 0; j < cReaders; j++)
1743 {
1744 if (rgReaderStates[j].szReader == NULL)
1745 return SCARD_E_INVALID_VALUE;
1746 }
1747
1748 /* return if all readers are SCARD_STATE_IGNORE */
1749 if (cReaders > 0)
1750 {
1751 int nbNonIgnoredReaders = cReaders;
1752
1753 for (j=0; j<cReaders; j++)
1754 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1755 nbNonIgnoredReaders--;
1756
1757 if (0 == nbNonIgnoredReaders)
1758 {
1759 rv = SCARD_S_SUCCESS;
1760 goto error;
1761 }
1762 }
1763 else
1764 {
1765 /* reader list is empty */
1766 rv = SCARD_S_SUCCESS;
1767 goto error;
1768 }
1769
1770 /*
1771 * Make sure this context has been opened
1772 */
1773 currentContextMap = SCardGetAndLockContext(hContext);
1774 if (NULL == currentContextMap)
1775 {
1777 goto error;
1778 }
1779
1780 /* lock access to readerStates[] */
1781 (void)pthread_mutex_lock(&readerStatesMutex);
1782
1783 /* synchronize reader states with daemon */
1784 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1785
1786 if (rv != SCARD_S_SUCCESS)
1787 {
1788 (void)pthread_mutex_unlock(&readerStatesMutex);
1789 goto end;
1790 }
1791
1792 /* check all the readers are already known */
1793 for (j=0; j<cReaders; j++)
1794 {
1795 const char *readerName;
1796 int i;
1797
1798 readerName = rgReaderStates[j].szReader;
1799 for (i = 0; i < pcsclite_max_reader_context; i++)
1800 {
1801 if (strcmp(readerName, readerStates[i].readerName) == 0)
1802 break;
1803 }
1804
1805 /* The requested reader name is not recognized */
1806 if (i == pcsclite_max_reader_context)
1807 {
1808 /* PnP special reader? */
1809 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1810 {
1812 (void)pthread_mutex_unlock(&readerStatesMutex);
1813 goto end;
1814 }
1815 else
1816 pnp_reader = j;
1817 }
1818 }
1819 (void)pthread_mutex_unlock(&readerStatesMutex);
1820
1821 /* Clear the event state for all readers */
1822 for (j = 0; j < cReaders; j++)
1823 rgReaderStates[j].dwEventState = 0;
1824
1825 /* Now is where we start our event checking loop */
1826 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1827
1828 /* index of the PnP readerin rgReaderStates[] */
1829 if (pnp_reader >= 0)
1830 {
1831 int readerEvents;
1832 currReader = &rgReaderStates[pnp_reader];
1833
1834 /* PnP special reader */
1835 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1836 {
1837 int previousReaderEvents = currReader->dwCurrentState >> 16;
1838
1839 // store readerEvents in .dwEventState high word
1840 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1841 if (
1842 /* the value has changed since the last call */
1843 (previousReaderEvents != readerEvents)
1844 /* backward compatibility: only if we had a non-null
1845 * reader events value */
1846 && previousReaderEvents)
1847 {
1848 currReader->dwEventState |= SCARD_STATE_CHANGED;
1849 rv = SCARD_S_SUCCESS;
1850 dwBreakFlag = 1;
1851 }
1852 }
1853 }
1854
1855 /* Get the initial reader count on the system */
1856 for (int k=0; k < pcsclite_max_reader_context; k++)
1857 if (readerStates[k].readerName[0] != '\0')
1858 currentReaderCount++;
1859
1860 /* catch possible sign extension problems from 32 to 64-bits integers */
1861 if ((DWORD)-1 == dwTimeout)
1862 dwTimeout = INFINITE;
1863 if (INFINITE == dwTimeout)
1864 dwTime = 60*1000; /* "infinite" timeout */
1865 else
1866 dwTime = dwTimeout;
1867
1868 j = 0;
1869 do
1870 {
1871 currReader = &rgReaderStates[j];
1872
1873 /* Ignore for IGNORED readers */
1874 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1875 {
1876 const char *readerName;
1877 int i;
1878
1879 /* lock access to readerStates[] */
1880 (void)pthread_mutex_lock(&readerStatesMutex);
1881
1882 /* Looks for correct readernames */
1883 readerName = currReader->szReader;
1884 for (i = 0; i < pcsclite_max_reader_context; i++)
1885 {
1886 if (strcmp(readerName, readerStates[i].readerName) == 0)
1887 break;
1888 }
1889
1890 /* The requested reader name is not recognized */
1891 if (i == pcsclite_max_reader_context)
1892 {
1893 /* PnP special reader? */
1894 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1895 {
1896 int k, newReaderCount = 0;
1897
1898 for (k=0; k < pcsclite_max_reader_context; k++)
1899 if (readerStates[k].readerName[0] != '\0')
1900 newReaderCount++;
1901
1902 if (newReaderCount != currentReaderCount)
1903 {
1904 int readerEvents;
1905
1906 Log1(PCSC_LOG_INFO, "Reader list changed");
1907 currentReaderCount = newReaderCount;
1908
1909 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1910 {
1911 // store readerEvents in .dwEventState high word
1912 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1913 }
1914
1915 currReader->dwEventState |= SCARD_STATE_CHANGED;
1916 dwBreakFlag = 1;
1917 }
1918 }
1919 else
1920 {
1921 currReader->dwEventState =
1923 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1924 {
1925 currReader->dwEventState |= SCARD_STATE_CHANGED;
1926 /*
1927 * Spec says use SCARD_STATE_IGNORE but a removed USB
1928 * reader with eventState fed into currentState will
1929 * be ignored forever
1930 */
1931 dwBreakFlag = 1;
1932 }
1933 }
1934 }
1935 else
1936 {
1937 uint32_t readerState;
1938
1939 /* The reader has come back after being away */
1940 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1941 {
1942 currReader->dwEventState |= SCARD_STATE_CHANGED;
1943 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1944 Log0(PCSC_LOG_DEBUG);
1945 dwBreakFlag = 1;
1946 }
1947
1948 /* Set the reader status structure */
1949 rContext = &readerStates[i];
1950
1951 /* Now we check all the Reader States */
1952 readerState = rContext->readerState;
1953
1954 /* only if current state has an non null event counter */
1955 if (currReader->dwCurrentState & 0xFFFF0000)
1956 {
1957 unsigned int currentCounter;
1958
1959 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1960
1961 /* has the event counter changed since the last call? */
1962 if (rContext->eventCounter != currentCounter)
1963 {
1964 currReader->dwEventState |= SCARD_STATE_CHANGED;
1965 Log0(PCSC_LOG_DEBUG);
1966 dwBreakFlag = 1;
1967 }
1968 }
1969
1970 /* add an event counter in the upper word of dwEventState */
1971 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1972 | (rContext->eventCounter << 16));
1973
1974 /* Check if the reader is in the correct state */
1975 if (readerState & SCARD_UNKNOWN)
1976 {
1977 /* reader is in bad state */
1978 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1979 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1980 {
1981 /* App thinks reader is in good state and it is not */
1982 currReader->dwEventState |= SCARD_STATE_CHANGED;
1983 Log0(PCSC_LOG_DEBUG);
1984 dwBreakFlag = 1;
1985 }
1986 }
1987 else
1988 {
1989 /* App thinks reader in bad state but it is not */
1990 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1991 {
1992 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1993 currReader->dwEventState |= SCARD_STATE_CHANGED;
1994 Log0(PCSC_LOG_DEBUG);
1995 dwBreakFlag = 1;
1996 }
1997 }
1998
1999 /* Check for card presence in the reader */
2000 if (readerState & SCARD_PRESENT)
2001 {
2002#ifndef DISABLE_AUTO_POWER_ON
2003 /* card present but not yet powered up */
2004 if (0 == rContext->cardAtrLength)
2005 /* Allow the status thread to convey information */
2006 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2007#endif
2008
2009 currReader->cbAtr = rContext->cardAtrLength;
2010 memcpy(currReader->rgbAtr, rContext->cardAtr,
2011 currReader->cbAtr);
2012 }
2013 else
2014 currReader->cbAtr = 0;
2015
2016 /* Card is now absent */
2017 if (readerState & SCARD_ABSENT)
2018 {
2019 currReader->dwEventState |= SCARD_STATE_EMPTY;
2020 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
2021 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2022 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2023 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2024 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2025 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
2026 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2027 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2028
2029 /* After present the rest are assumed */
2030 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2031 {
2032 currReader->dwEventState |= SCARD_STATE_CHANGED;
2033 Log0(PCSC_LOG_DEBUG);
2034 dwBreakFlag = 1;
2035 }
2036 }
2037 /* Card is now present */
2038 else if (readerState & SCARD_PRESENT)
2039 {
2040 currReader->dwEventState |= SCARD_STATE_PRESENT;
2041 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2042 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2043 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2044 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2045 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2046 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2047
2048 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2049 {
2050 currReader->dwEventState |= SCARD_STATE_CHANGED;
2051 Log0(PCSC_LOG_DEBUG);
2052 dwBreakFlag = 1;
2053 }
2054
2055 if (readerState & SCARD_SWALLOWED)
2056 {
2057 currReader->dwEventState |= SCARD_STATE_MUTE;
2058 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2059 {
2060 currReader->dwEventState |= SCARD_STATE_CHANGED;
2061 Log0(PCSC_LOG_DEBUG);
2062 dwBreakFlag = 1;
2063 }
2064 }
2065 else
2066 {
2067 /* App thinks card is mute but it is not */
2068 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2069 {
2070 currReader->dwEventState |= SCARD_STATE_CHANGED;
2071 Log0(PCSC_LOG_DEBUG);
2072 dwBreakFlag = 1;
2073 }
2074 }
2075 }
2076
2077 /* Now figure out sharing modes */
2079 {
2080 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2081 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2082 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2083 {
2084 currReader->dwEventState |= SCARD_STATE_CHANGED;
2085 Log0(PCSC_LOG_DEBUG);
2086 dwBreakFlag = 1;
2087 }
2088 }
2089 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2090 {
2091 /* A card must be inserted for it to be INUSE */
2092 if (readerState & SCARD_PRESENT)
2093 {
2094 currReader->dwEventState |= SCARD_STATE_INUSE;
2095 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2096 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2097 {
2098 currReader->dwEventState |= SCARD_STATE_CHANGED;
2099 Log0(PCSC_LOG_DEBUG);
2100 dwBreakFlag = 1;
2101 }
2102 }
2103 }
2104 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2105 {
2106 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2107 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2108
2109 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2110 {
2111 currReader->dwEventState |= SCARD_STATE_CHANGED;
2112 Log0(PCSC_LOG_DEBUG);
2113 dwBreakFlag = 1;
2114 }
2115 else if (currReader-> dwCurrentState
2117 {
2118 currReader->dwEventState |= SCARD_STATE_CHANGED;
2119 Log0(PCSC_LOG_DEBUG);
2120 dwBreakFlag = 1;
2121 }
2122 }
2123
2124 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2125 {
2126 /*
2127 * Break out of the while .. loop and return status
2128 * once all the status's for all readers is met
2129 */
2130 currReader->dwEventState |= SCARD_STATE_CHANGED;
2131 Log0(PCSC_LOG_DEBUG);
2132 dwBreakFlag = 1;
2133 }
2134 } /* End of SCARD_STATE_UNKNOWN */
2135
2136 (void)pthread_mutex_unlock(&readerStatesMutex);
2137 } /* End of SCARD_STATE_IGNORE */
2138
2139 /* Counter and resetter */
2140 j++;
2141 if (j == cReaders)
2142 {
2143 /* go back to the first reader */
2144 j = 0;
2145
2146 /* Declare all the break conditions */
2147
2148 /* Break if UNAWARE is set and all readers have been checked */
2149 if (dwBreakFlag == 1)
2150 break;
2151
2152 /* Only sleep once for each cycle of reader checks. */
2153 {
2154 struct wait_reader_state_change waitStatusStruct = {0};
2155 struct timeval before, after;
2156
2157 gettimeofday(&before, NULL);
2158
2159 waitStatusStruct.rv = SCARD_S_SUCCESS;
2160
2161 /* another thread can do SCardCancel() */
2162 currentContextMap->cancellable = true;
2163
2164 /*
2165 * Read a message from the server
2166 */
2168 &waitStatusStruct, sizeof(waitStatusStruct),
2169 currentContextMap->dwClientID, dwTime);
2170
2171 /* SCardCancel() will return immediately with success
2172 * because something changed on the daemon side. */
2173 currentContextMap->cancellable = false;
2174
2175 /* timeout */
2176 if (SCARD_E_TIMEOUT == rv)
2177 {
2178 /* ask server to remove us from the event list */
2179 rv = unregisterFromEvents(currentContextMap);
2180 }
2181
2182 if (rv != SCARD_S_SUCCESS)
2183 goto end;
2184
2185 /* an event occurs or SCardCancel() was called */
2186 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2187 {
2188 rv = waitStatusStruct.rv;
2189 goto end;
2190 }
2191
2192 /* synchronize reader states with daemon */
2193 (void)pthread_mutex_lock(&readerStatesMutex);
2194 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2195 (void)pthread_mutex_unlock(&readerStatesMutex);
2196 if (rv != SCARD_S_SUCCESS)
2197 goto end;
2198
2199 if (INFINITE != dwTimeout)
2200 {
2201 long int diff;
2202
2203 gettimeofday(&after, NULL);
2204 diff = time_sub(&after, &before);
2205 dwTime -= diff/1000;
2206 }
2207 }
2208
2209 if (dwTimeout != INFINITE)
2210 {
2211 /* If time is greater than timeout and all readers have been
2212 * checked
2213 */
2214 if (dwTime <= 0)
2215 {
2216 rv = SCARD_E_TIMEOUT;
2217 goto end;
2218 }
2219 }
2220 }
2221 }
2222 while (1);
2223
2224end:
2225 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2226
2227 /* if SCardCancel() has been used then the client is already
2228 * unregistered */
2229 if (SCARD_E_CANCELLED != rv)
2230 (void)unregisterFromEvents(currentContextMap);
2231
2232 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2233
2234error:
2235 PROFILE_END(rv)
2236#ifdef DO_TRACE
2237 for (j=0; j<cReaders; j++)
2238 {
2239 API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2240 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2241 rgReaderStates[j].cbAtr)
2242 }
2243#endif
2244
2245 return rv;
2246}
2247
2298LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2299 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2300 LPDWORD lpBytesReturned)
2301{
2302 LONG rv;
2303 struct control_struct scControlStruct;
2304 SCONTEXTMAP * currentContextMap;
2305 CHANNEL_MAP * pChannelMap;
2306
2307 PROFILE_START
2308
2309 /* 0 bytes received by default */
2310 if (NULL != lpBytesReturned)
2311 *lpBytesReturned = 0;
2312
2313 /*
2314 * Make sure this handle has been opened
2315 */
2316 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2317 &pChannelMap);
2318 if (rv == -1)
2319 {
2320 PROFILE_END(SCARD_E_INVALID_HANDLE)
2322 }
2323
2324 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2325 {
2327 goto end;
2328 }
2329
2330 scControlStruct.hCard = hCard;
2331 scControlStruct.dwControlCode = dwControlCode;
2332 scControlStruct.cbSendLength = cbSendLength;
2333 scControlStruct.cbRecvLength = cbRecvLength;
2334 scControlStruct.dwBytesReturned = 0;
2335 scControlStruct.rv = 0;
2336
2337 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2338 sizeof(scControlStruct), &scControlStruct);
2339
2340 if (rv != SCARD_S_SUCCESS)
2341 goto end;
2342
2343 /* write the sent buffer */
2344 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2345 currentContextMap->dwClientID);
2346
2347 if (rv != SCARD_S_SUCCESS)
2348 goto end;
2349
2350 /*
2351 * Read a message from the server
2352 */
2353 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2354 currentContextMap->dwClientID);
2355
2356 if (rv != SCARD_S_SUCCESS)
2357 goto end;
2358
2359 if (SCARD_S_SUCCESS == scControlStruct.rv)
2360 {
2361 if (scControlStruct.dwBytesReturned > cbRecvLength)
2362 {
2363 if (NULL != lpBytesReturned)
2364 *lpBytesReturned = scControlStruct.dwBytesReturned;
2366 goto end;
2367 }
2368
2369 /* read the received buffer */
2370 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2371 currentContextMap->dwClientID);
2372
2373 if (rv != SCARD_S_SUCCESS)
2374 goto end;
2375
2376 }
2377
2378 if (NULL != lpBytesReturned)
2379 *lpBytesReturned = scControlStruct.dwBytesReturned;
2380
2381 rv = scControlStruct.rv;
2382
2383end:
2384 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2385
2386 PROFILE_END(rv)
2387
2388 return rv;
2389}
2390
2509LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2510 LPDWORD pcbAttrLen)
2511{
2512 LONG ret;
2513 unsigned char *buf = NULL;
2514
2515 PROFILE_START
2516
2517 if (NULL == pcbAttrLen)
2518 {
2520 goto end;
2521 }
2522
2523 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2524 {
2525 if (NULL == pbAttr)
2527
2528 *pcbAttrLen = MAX_BUFFER_SIZE;
2529 buf = malloc(*pcbAttrLen);
2530 if (NULL == buf)
2531 {
2532 ret = SCARD_E_NO_MEMORY;
2533 goto end;
2534 }
2535
2536 *(unsigned char **)pbAttr = buf;
2537 }
2538 else
2539 {
2540 buf = pbAttr;
2541
2542 /* if only get the length */
2543 if (NULL == pbAttr)
2544 /* use a reasonable size */
2545 *pcbAttrLen = MAX_BUFFER_SIZE;
2546 }
2547
2548 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2549 pcbAttrLen);
2550
2551end:
2552 PROFILE_END(ret)
2553
2554 return ret;
2555}
2556
2592LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2593 DWORD cbAttrLen)
2594{
2595 LONG ret;
2596
2597 PROFILE_START
2598
2599 if (NULL == pbAttr || 0 == cbAttrLen)
2601
2602 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2603 &cbAttrLen);
2604
2605 PROFILE_END(ret)
2606
2607 return ret;
2608}
2609
2610static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2611 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2612{
2613 LONG rv;
2614 struct getset_struct scGetSetStruct;
2615 SCONTEXTMAP * currentContextMap;
2616 CHANNEL_MAP * pChannelMap;
2617
2618 /*
2619 * Make sure this handle has been opened
2620 */
2621 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2622 &pChannelMap);
2623 if (rv == -1)
2625
2626 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2627 {
2629 goto end;
2630 }
2631
2632 scGetSetStruct.hCard = hCard;
2633 scGetSetStruct.dwAttrId = dwAttrId;
2634 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2635 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2636 if (SCARD_SET_ATTRIB == command)
2637 {
2638 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2639 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2640 }
2641 else
2642 /* we can get up to the communication buffer size */
2643 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2644
2645 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2646 sizeof(scGetSetStruct), &scGetSetStruct);
2647
2648 if (rv != SCARD_S_SUCCESS)
2649 goto end;
2650
2651 /*
2652 * Read a message from the server
2653 */
2654 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2655 currentContextMap->dwClientID);
2656
2657 if (rv != SCARD_S_SUCCESS)
2658 goto end;
2659
2660 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2661 {
2662 /*
2663 * Copy and zero it so any secret information is not leaked
2664 */
2665 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2666 {
2667 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2668 * buffer overflow in the memcpy() below */
2669 DWORD correct_value = scGetSetStruct.cbAttrLen;
2670 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2671 *pcbAttrLen = correct_value;
2672
2673 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2674 }
2675 else
2676 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2677
2678 if (pbAttr)
2679 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2680
2681 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2682 }
2683 rv = scGetSetStruct.rv;
2684
2685end:
2686 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2687
2688 return rv;
2689}
2690
2749LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2750 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2751 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2752 LPDWORD pcbRecvLength)
2753{
2754 LONG rv;
2755 SCONTEXTMAP * currentContextMap;
2756 CHANNEL_MAP * pChannelMap;
2757 struct transmit_struct scTransmitStruct;
2758
2759 PROFILE_START
2760
2761 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2762 pcbRecvLength == NULL || pioSendPci == NULL)
2764
2765 /* Retry loop for blocking behaviour */
2766retry:
2767
2768 /*
2769 * Make sure this handle has been opened
2770 */
2771 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2772 &pChannelMap);
2773 if (rv == -1)
2774 {
2775 *pcbRecvLength = 0;
2776 PROFILE_END(SCARD_E_INVALID_HANDLE)
2778 }
2779
2780 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2781 {
2783 goto end;
2784 }
2785
2786 scTransmitStruct.hCard = hCard;
2787 scTransmitStruct.cbSendLength = cbSendLength;
2788 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2789 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2790 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2791 scTransmitStruct.rv = SCARD_S_SUCCESS;
2792
2793 if (pioRecvPci)
2794 {
2795 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2796 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2797 }
2798 else
2799 {
2800 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2801 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2802 }
2803
2804 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2805 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2806
2807 if (rv != SCARD_S_SUCCESS)
2808 goto end;
2809
2810 /* write the sent buffer */
2811 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2812 currentContextMap->dwClientID);
2813
2814 if (rv != SCARD_S_SUCCESS)
2815 goto end;
2816
2817 /*
2818 * Read a message from the server
2819 */
2820 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2821 currentContextMap->dwClientID);
2822
2823 if (rv != SCARD_S_SUCCESS)
2824 goto end;
2825
2826 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2827 {
2828 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2829 {
2830 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2832 goto end;
2833 }
2834
2835 /* read the received buffer */
2836 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2837 currentContextMap->dwClientID);
2838
2839 if (rv != SCARD_S_SUCCESS)
2840 goto end;
2841
2842 if (pioRecvPci)
2843 {
2844 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2845 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2846 }
2847 }
2848
2849 rv = scTransmitStruct.rv;
2850
2851 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2852 {
2853 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2854 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2855 goto retry;
2856 }
2857
2858 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2859
2860end:
2861 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2862
2863 PROFILE_END(rv)
2864
2865 return rv;
2866}
2867
2934LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2935 LPSTR mszReaders, LPDWORD pcchReaders)
2936{
2937 DWORD dwReadersLen = 0;
2938 int i;
2939 SCONTEXTMAP * currentContextMap;
2940 LONG rv = SCARD_S_SUCCESS;
2941 char *buf = NULL;
2942
2943 (void)mszGroups;
2944 PROFILE_START
2945 API_TRACE_IN("%ld", hContext)
2946
2947 /*
2948 * Check for NULL parameters
2949 */
2950 if (pcchReaders == NULL)
2952
2953 /*
2954 * Make sure this context has been opened
2955 */
2956 currentContextMap = SCardGetAndLockContext(hContext);
2957 if (NULL == currentContextMap)
2958 {
2959 PROFILE_END(SCARD_E_INVALID_HANDLE)
2961 }
2962
2963 /* lock access to readerStates[] */
2964 (void)pthread_mutex_lock(&readerStatesMutex);
2965
2966 /* synchronize reader states with daemon */
2967 rv = getReaderStates(currentContextMap);
2968 if (rv != SCARD_S_SUCCESS)
2969 goto end;
2970
2971 dwReadersLen = 0;
2972 for (i = 0; i < pcsclite_max_reader_context; i++)
2973 if (readerStates[i].readerName[0] != '\0')
2974 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2975
2976 /* for the last NULL byte */
2977 dwReadersLen += 1;
2978
2979 if (1 == dwReadersLen)
2980 {
2982 goto end;
2983 }
2984
2985 if (SCARD_AUTOALLOCATE == *pcchReaders)
2986 {
2987 if (NULL == mszReaders)
2988 {
2990 goto end;
2991 }
2992 buf = malloc(dwReadersLen);
2993 if (NULL == buf)
2994 {
2995 rv = SCARD_E_NO_MEMORY;
2996 goto end;
2997 }
2998 *(char **)mszReaders = buf;
2999 }
3000 else
3001 {
3002 buf = mszReaders;
3003
3004 /* not enough place to store the reader names */
3005 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3006 {
3008 goto end;
3009 }
3010 }
3011
3012 if (mszReaders == NULL) /* text array not allocated */
3013 goto end;
3014
3015 for (i = 0; i < pcsclite_max_reader_context; i++)
3016 {
3017 if (readerStates[i].readerName[0] != '\0')
3018 {
3019 /*
3020 * Build the multi-string
3021 */
3022 strcpy(buf, readerStates[i].readerName);
3023 buf += strlen(readerStates[i].readerName)+1;
3024 }
3025 }
3026 *buf = '\0'; /* Add the last null */
3027
3028end:
3029 /* set the reader names length */
3030 *pcchReaders = dwReadersLen;
3031
3032 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3033 (void)pthread_mutex_unlock(&readerStatesMutex);
3034
3035 PROFILE_END(rv)
3036 API_TRACE_OUT("%d", *pcchReaders)
3037
3038 return rv;
3039}
3040
3053
3054LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3055{
3056 LONG rv = SCARD_S_SUCCESS;
3057
3058 PROFILE_START
3059
3060 /*
3061 * Make sure this context has been opened
3062 */
3063 if (! SCardGetContextValidity(hContext))
3065
3066 free((void *)pvMem);
3067
3068 PROFILE_END(rv)
3069
3070 return rv;
3071}
3072
3124LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3125 LPDWORD pcchGroups)
3126{
3127 LONG rv = SCARD_S_SUCCESS;
3128 SCONTEXTMAP * currentContextMap;
3129 char *buf = NULL;
3130
3131 PROFILE_START
3132
3133 /* Multi-string with two trailing \0 */
3134 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3135 const unsigned int dwGroups = sizeof(ReaderGroup);
3136
3137 /*
3138 * Make sure this context has been opened
3139 */
3140 currentContextMap = SCardGetAndLockContext(hContext);
3141 if (NULL == currentContextMap)
3143
3144 if (SCARD_AUTOALLOCATE == *pcchGroups)
3145 {
3146 if (NULL == mszGroups)
3147 {
3149 goto end;
3150 }
3151 buf = malloc(dwGroups);
3152 if (NULL == buf)
3153 {
3154 rv = SCARD_E_NO_MEMORY;
3155 goto end;
3156 }
3157 *(char **)mszGroups = buf;
3158 }
3159 else
3160 {
3161 buf = mszGroups;
3162
3163 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3164 {
3166 goto end;
3167 }
3168 }
3169
3170 if (buf)
3171 memcpy(buf, ReaderGroup, dwGroups);
3172
3173end:
3174 *pcchGroups = dwGroups;
3175
3176 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3177
3178 PROFILE_END(rv)
3179
3180 return rv;
3181}
3182
3215{
3216 SCONTEXTMAP * currentContextMap;
3217 LONG rv = SCARD_S_SUCCESS;
3218 uint32_t dwClientID = 0;
3219 struct cancel_struct scCancelStruct;
3220 bool cancellable;
3221
3222 PROFILE_START
3223 API_TRACE_IN("%ld", hContext)
3224
3225 /*
3226 * Make sure this context has been opened
3227 */
3228 (void)SCardLockThread();
3229 currentContextMap = SCardGetContextTH(hContext);
3230
3231 if (NULL == currentContextMap)
3232 {
3233 (void)SCardUnlockThread();
3235 goto error;
3236 }
3237 cancellable = currentContextMap->cancellable;
3238 (void)SCardUnlockThread();
3239
3240 if (! cancellable)
3241 {
3242 rv = SCARD_S_SUCCESS;
3243 goto error;
3244 }
3245
3246 /* create a new connection to the server */
3247 if (ClientSetupSession(&dwClientID) != 0)
3248 {
3249 rv = SCARD_E_NO_SERVICE;
3250 goto error;
3251 }
3252
3253 scCancelStruct.hContext = hContext;
3254 scCancelStruct.rv = SCARD_S_SUCCESS;
3255
3256 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3257 sizeof(scCancelStruct), (void *) &scCancelStruct);
3258
3259 if (rv != SCARD_S_SUCCESS)
3260 goto end;
3261
3262 /*
3263 * Read a message from the server
3264 */
3265 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3266
3267 if (rv != SCARD_S_SUCCESS)
3268 goto end;
3269
3270 rv = scCancelStruct.rv;
3271end:
3272 ClientCloseSession(dwClientID);
3273
3274error:
3275 PROFILE_END(rv)
3276 API_TRACE_OUT("")
3277
3278 return rv;
3279}
3280
3305{
3306 LONG rv;
3307
3308 PROFILE_START
3309 API_TRACE_IN("%ld", hContext)
3310
3311 rv = SCARD_S_SUCCESS;
3312
3313 /*
3314 * Make sure this context has been opened
3315 */
3316 if (! SCardGetContextValidity(hContext))
3318
3319 PROFILE_END(rv)
3320 API_TRACE_OUT("")
3321
3322 return rv;
3323}
3324
3330
3341static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3342{
3343 int lrv;
3344 SCONTEXTMAP * newContextMap;
3345
3346 newContextMap = malloc(sizeof(SCONTEXTMAP));
3347 if (NULL == newContextMap)
3348 return SCARD_E_NO_MEMORY;
3349
3350 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3351 newContextMap->hContext = hContext;
3352 newContextMap->dwClientID = dwClientID;
3353 newContextMap->cancellable = false;
3354
3355 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3356
3357 lrv = list_init(&newContextMap->channelMapList);
3358 if (lrv < 0)
3359 {
3360 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3361 goto error;
3362 }
3363
3364 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3365 CHANNEL_MAP_seeker);
3366 if (lrv <0)
3367 {
3368 Log2(PCSC_LOG_CRITICAL,
3369 "list_attributes_seeker failed with return value: %d", lrv);
3370 list_destroy(&newContextMap->channelMapList);
3371 goto error;
3372 }
3373
3374 (void)pthread_mutex_lock(&contextMapList_lock);
3375 lrv = list_append(&contextMapList, newContextMap);
3376 (void)pthread_mutex_unlock(&contextMapList_lock);
3377 if (lrv < 0)
3378 {
3379 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3380 lrv);
3381 list_destroy(&newContextMap->channelMapList);
3382 goto error;
3383 }
3384
3385 return SCARD_S_SUCCESS;
3386
3387error:
3388
3389 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3390 free(newContextMap);
3391
3392 return SCARD_E_NO_MEMORY;
3393}
3394
3412{
3413 SCONTEXTMAP * currentContextMap;
3414
3416 currentContextMap = SCardGetContextTH(hContext);
3417
3418 /* lock the context (if available) */
3419 if (NULL != currentContextMap)
3420 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3421
3423
3424 return currentContextMap;
3425}
3426
3440{
3441 SCONTEXTMAP * currentContextMap;
3442
3443 (void)pthread_mutex_lock(&contextMapList_lock);
3444 currentContextMap = list_seek(&contextMapList, &hContext);
3445 (void)pthread_mutex_unlock(&contextMapList_lock);
3446
3447 return currentContextMap;
3448}
3449
3457{
3458 SCONTEXTMAP * currentContextMap;
3459 currentContextMap = SCardGetContextTH(hContext);
3460
3461 if (NULL != currentContextMap)
3462 SCardCleanContext(currentContextMap);
3463}
3464
3465static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3466{
3467 int list_index, lrv;
3468 int listSize;
3469 CHANNEL_MAP * currentChannelMap;
3470
3471 targetContextMap->hContext = 0;
3472 ClientCloseSession(targetContextMap->dwClientID);
3473 targetContextMap->dwClientID = 0;
3474 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3475
3476 listSize = list_size(&targetContextMap->channelMapList);
3477 for (list_index = 0; list_index < listSize; list_index++)
3478 {
3479 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3480 list_index);
3481 if (NULL == currentChannelMap)
3482 {
3483 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3484 list_index);
3485 continue;
3486 }
3487 else
3488 {
3489 free(currentChannelMap->readerName);
3490 free(currentChannelMap);
3491 }
3492
3493 }
3494 list_destroy(&targetContextMap->channelMapList);
3495
3496 (void)pthread_mutex_lock(&contextMapList_lock);
3497 lrv = list_delete(&contextMapList, targetContextMap);
3498 (void)pthread_mutex_unlock(&contextMapList_lock);
3499 if (lrv < 0)
3500 {
3501 Log2(PCSC_LOG_CRITICAL,
3502 "list_delete failed with return value: %d", lrv);
3503 }
3504
3505 free(targetContextMap);
3506
3507 return;
3508}
3509
3510/*
3511 * Functions for managing hCard values returned from SCardConnect.
3512 */
3513
3514static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3515 LPCSTR readerName)
3516{
3517 CHANNEL_MAP * newChannelMap;
3518 int lrv = -1;
3519
3520 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3521 if (NULL == newChannelMap)
3522 return SCARD_E_NO_MEMORY;
3523
3524 newChannelMap->hCard = hCard;
3525 newChannelMap->readerName = strdup(readerName);
3526
3527 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3528 if (lrv < 0)
3529 {
3530 free(newChannelMap->readerName);
3531 free(newChannelMap);
3532 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3533 lrv);
3534 return SCARD_E_NO_MEMORY;
3535 }
3536
3537 return SCARD_S_SUCCESS;
3538}
3539
3540static void SCardRemoveHandle(SCARDHANDLE hCard)
3541{
3542 SCONTEXTMAP * currentContextMap;
3543 CHANNEL_MAP * currentChannelMap;
3544 int lrv;
3545 LONG rv;
3546
3547 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3548 &currentChannelMap);
3549 if (rv == -1)
3550 return;
3551
3552 free(currentChannelMap->readerName);
3553
3554 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3555 if (lrv < 0)
3556 {
3557 Log2(PCSC_LOG_CRITICAL,
3558 "list_delete failed with return value: %d", lrv);
3559 }
3560
3561 free(currentChannelMap);
3562
3563 return;
3564}
3565
3566static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3567 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3568{
3569 LONG rv;
3570
3571 if (0 == hCard)
3572 return -1;
3573
3575 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3576 targetChannelMap);
3577
3578 if (SCARD_S_SUCCESS == rv)
3579 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3580
3582
3583 return rv;
3584}
3585
3586static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3587 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3588{
3589 LONG rv = -1;
3590 int listSize;
3591 int list_index;
3592 SCONTEXTMAP * currentContextMap;
3593 CHANNEL_MAP * currentChannelMap;
3594
3595 /* Best to get the caller a crash early if we fail unsafely */
3596 *targetContextMap = NULL;
3597 *targetChannelMap = NULL;
3598
3599 (void)pthread_mutex_lock(&contextMapList_lock);
3600 listSize = list_size(&contextMapList);
3601
3602 for (list_index = 0; list_index < listSize; list_index++)
3603 {
3604 currentContextMap = list_get_at(&contextMapList, list_index);
3605 if (currentContextMap == NULL)
3606 {
3607 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3608 list_index);
3609 continue;
3610 }
3611 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3612 &hCard);
3613 if (currentChannelMap != NULL)
3614 {
3615 *targetContextMap = currentContextMap;
3616 *targetChannelMap = currentChannelMap;
3617 rv = SCARD_S_SUCCESS;
3618 break;
3619 }
3620 }
3621
3622 (void)pthread_mutex_unlock(&contextMapList_lock);
3623
3624 return rv;
3625}
3626
3635{
3636 LONG rv;
3637 struct stat statBuffer;
3638 char *socketName;
3639
3640 socketName = getSocketName();
3641 rv = stat(socketName, &statBuffer);
3642
3643 if (rv != 0)
3644 {
3645 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3646 socketName, strerror(errno));
3647 return SCARD_E_NO_SERVICE;
3648 }
3649
3650 return SCARD_S_SUCCESS;
3651}
3652
3653static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3654{
3655 int32_t dwClientID = currentContextMap->dwClientID;
3656 LONG rv;
3658
3659 /* CMD_GET_READER_EVENTS was added in protocol 4:5 */
3660 if (Protocol_version < 4005)
3662
3663 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3664 if (rv != SCARD_S_SUCCESS)
3665 return rv;
3666
3667 /* Read a message from the server */
3668 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3669 if (rv != SCARD_S_SUCCESS)
3670 return rv;
3671
3672 *readerEvents = get_reader_events.readerEvents;
3673
3674 return SCARD_S_SUCCESS;
3675}
3676
3677static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3678{
3679 int32_t dwClientID = currentContextMap->dwClientID;
3680 LONG rv;
3681 int32_t array_size;
3682
3683 if (Protocol_version <= 4005)
3684 /* protocol up to 4:5 used a fixed size */
3685 array_size = PCSCLITE_MAX_READERS_CONTEXTS;
3686 else
3687 {
3688 rv = MessageSendWithHeader(CMD_GET_READERS_STATE_SIZE, dwClientID, 0, NULL);
3689 if (rv != SCARD_S_SUCCESS)
3690 return rv;
3691
3692 /* Read a message from the server */
3693 rv = MessageReceive(&array_size, sizeof(array_size), dwClientID);
3694 if (rv != SCARD_S_SUCCESS)
3695 return rv;
3696
3697 /* this should not happen but coverity complained */
3698 if (array_size < 0)
3700 }
3701
3702 if (array_size > pcsclite_max_reader_context)
3703 {
3704 /* need to resize */
3705 readerStates = realloc(readerStates, array_size * sizeof(readerStates[0]));
3706 if (NULL == readerStates)
3708 pcsclite_max_reader_context = array_size;
3709 }
3710
3711 if (array_size != pcsclite_max_reader_context)
3712 {
3713 /* Should never happen */
3715 }
3716
3717 if (Protocol_version <= 4005)
3718 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3719 else
3720 rv = MessageSendWithHeader(CMD_GET_READERS_STATE_ARRAY, dwClientID, 0, NULL);
3721 if (rv != SCARD_S_SUCCESS)
3722 return rv;
3723
3724 /* Read a message from the server */
3725 rv = MessageReceive(readerStates, array_size * sizeof(readerStates[0]), dwClientID);
3726 if (rv != SCARD_S_SUCCESS)
3727 return rv;
3728
3729 return SCARD_S_SUCCESS;
3730}
3731
3732static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3733{
3734 int32_t dwClientID = currentContextMap->dwClientID;
3735 LONG rv;
3736
3737 /* Get current reader states from server and register on event list */
3739 0, NULL);
3740 if (rv != SCARD_S_SUCCESS)
3741 return rv;
3742
3743 if (Protocol_version <= 4005)
3744 {
3745 /* This should not happen
3746 * pcsclite_max_reader_context should be set to the backward
3747 * compatible value from a previous call to getReaderStates()
3748 * called from SCardStatus() or SCardListReaders() */
3749 if (pcsclite_max_reader_context != PCSCLITE_MAX_READERS_CONTEXTS)
3750 return SCARD_E_NO_SERVICE;
3751
3752 rv = MessageReceive(readerStates, pcsclite_max_reader_context * sizeof(readerStates[0]), dwClientID);
3753 return rv;
3754 }
3755 else
3756 return getReaderStates(currentContextMap);
3757}
3758
3759static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3760{
3761 int32_t dwClientID = currentContextMap->dwClientID;
3762 LONG rv;
3763 struct wait_reader_state_change waitStatusStruct = {0};
3764
3765 /* ask server to remove us from the event list */
3767 dwClientID, 0, NULL);
3768 if (rv != SCARD_S_SUCCESS)
3769 return rv;
3770
3771 /* This message can be the response to
3772 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3773 * cancel notification.
3774 * The server side ensures, that no more messages will be sent to
3775 * the client. */
3776
3777 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3778 dwClientID);
3779 if (rv != SCARD_S_SUCCESS)
3780 return rv;
3781
3782 /* if we received a cancel event the return value will be set
3783 * accordingly */
3784 rv = waitStatusStruct.rv;
3785
3786 return rv;
3787}
3788
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()