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