pcsc-lite 2.4.1
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;
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
356static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
357
358
359static LONG SCardAddContext(SCARDCONTEXT, DWORD);
363static void SCardCleanContext(SCONTEXTMAP *);
364
365static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
366static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
367 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
368static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
369 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
370static void SCardRemoveHandle(SCARDHANDLE);
371
372static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
373 LPBYTE pbAttr, LPDWORD pcbAttrLen);
374
375static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents);
376static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
377static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
378static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
379
380/*
381 * Thread safety functions
382 */
389inline static void SCardLockThread(void)
390{
391 pthread_mutex_lock(&clientMutex);
392}
393
399inline static void SCardUnlockThread(void)
400{
401 pthread_mutex_unlock(&clientMutex);
402}
403
414{
415 SCONTEXTMAP * currentContextMap;
416
418 currentContextMap = SCardGetContextTH(hContext);
420
421 return currentContextMap != NULL;
422}
423
424static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
425 /*@out@*/ LPSCARDCONTEXT);
426
463LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
464 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
465{
466 LONG rv;
467
468 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
469 PROFILE_START
470
471 /* Check if the server is running */
473 if (rv != SCARD_S_SUCCESS)
474 goto end;
475
477 rv = SCardEstablishContextTH(dwScope, pvReserved1,
478 pvReserved2, phContext);
480
481end:
482 PROFILE_END(rv)
483 API_TRACE_OUT("%ld", *phContext)
484
485 return rv;
486}
487
488#ifdef DESTRUCTOR
489DESTRUCTOR static void destructor(void)
490{
491 (void)pthread_mutex_lock(&contextMapList_lock);
492 list_destroy(&contextMapList);
493 (void)pthread_mutex_unlock(&contextMapList_lock);
494
495 (void)pthread_mutex_destroy(&contextMapList_lock);
496}
497#endif
498
499/*
500 * Do this only once:
501 * - Initialize context list.
502 */
503static void init_lib(void)
504{
505 int lrv;
506
507 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
508 * Applications which load and unload the library may leak
509 * the list's internal structures. */
510 lrv = list_init(&contextMapList);
511 if (lrv < 0)
512 {
513 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
514 lrv);
515 return;
516 }
517
518 lrv = list_attributes_seeker(&contextMapList,
519 SCONTEXTMAP_seeker);
520 if (lrv <0)
521 {
522 Log2(PCSC_LOG_CRITICAL,
523 "list_attributes_seeker failed with return value: %d", lrv);
524 list_destroy(&contextMapList);
525 return;
526 }
527
528 if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
529 {
530 Log1(PCSC_LOG_INFO, "Disable shared blocking");
531 sharing_shall_block = false;
532 }
533
534 (void)pthread_mutex_init(&contextMapList_lock, NULL);
535
536 isExecuted = true;
537}
538
566static LONG SCardEstablishContextTH(DWORD dwScope,
567 /*@unused@*/ LPCVOID pvReserved1,
568 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
569{
570 LONG rv;
571 struct establish_struct scEstablishStruct;
572 uint32_t dwClientID = 0;
573 struct version_struct veStr;
574
575 (void)pvReserved1;
576 (void)pvReserved2;
577 if (phContext == NULL)
579 else
580 *phContext = 0;
581
582 pthread_once(&init_lib_control, init_lib);
583 if (!isExecuted)
584 return SCARD_E_NO_MEMORY;
585
586 /* Establishes a connection to the server */
587 if (ClientSetupSession(&dwClientID) != 0)
588 {
589 return SCARD_E_NO_SERVICE;
590 }
591
594
595connect_again:
596 /* exchange client/server protocol versions */
597
598 veStr.rv = SCARD_S_SUCCESS;
599
600 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
601 &veStr);
602 if (rv != SCARD_S_SUCCESS)
603 goto cleanup;
604
605 /* Read a message from the server */
606 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
607 if (rv != SCARD_S_SUCCESS)
608 {
609 Log1(PCSC_LOG_CRITICAL,
610 "Your pcscd is too old and does not support CMD_VERSION");
611 goto cleanup;
612 }
613
614 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
615 veStr.major, veStr.minor);
616 Log3(PCSC_LOG_INFO, "Client is protocol version %d:%d",
618
619 if (SCARD_E_SERVICE_STOPPED == veStr.rv)
620 {
621 /* server complained about our protocol version? */
622 if (PROTOCOL_VERSION_MAJOR == veStr.major)
623 {
625 {
626 /* try again with the protocol version proposed by
627 * the server */
628 Log1(PCSC_LOG_INFO, "Using backward compatibility");
629 goto connect_again;
630 }
631 }
632 }
633
634 if (veStr.rv != SCARD_S_SUCCESS)
635 {
636 rv = veStr.rv;
637 goto cleanup;
638 }
639
640 /* store protocol version of the server */
641 Protocol_version = veStr.major * 1000 + veStr.minor;
642
643again:
644 /*
645 * Try to establish an Application Context with the server
646 */
647 scEstablishStruct.dwScope = dwScope;
648 scEstablishStruct.hContext = 0;
649 scEstablishStruct.rv = SCARD_S_SUCCESS;
650
652 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
653
654 if (rv != SCARD_S_SUCCESS)
655 goto cleanup;
656
657 /*
658 * Read the response from the server
659 */
660 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
661 dwClientID);
662
663 if (rv != SCARD_S_SUCCESS)
664 goto cleanup;
665
666 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
667 {
668 rv = scEstablishStruct.rv;
669 goto cleanup;
670 }
671
672 /* check we do not reuse an existing hContext */
673 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
674 /* we do not need to release the allocated context since
675 * SCardReleaseContext() does nothing on the server side */
676 goto again;
677
678 *phContext = scEstablishStruct.hContext;
679
680 /*
681 * Allocate the new hContext - if allocator full return an error
682 */
683 rv = SCardAddContext(*phContext, dwClientID);
684
685 return rv;
686
687cleanup:
688 ClientCloseSession(dwClientID);
689
690 return rv;
691}
692
715{
716 LONG rv;
717 struct release_struct scReleaseStruct;
718 SCONTEXTMAP * currentContextMap;
719
720 API_TRACE_IN("%ld", hContext)
721 PROFILE_START
722
723 /*
724 * Make sure this context has been opened
725 * and get currentContextMap
726 */
727 currentContextMap = SCardGetAndLockContext(hContext);
728 if (NULL == currentContextMap)
729 {
731 goto error;
732 }
733
734 scReleaseStruct.hContext = hContext;
735 scReleaseStruct.rv = SCARD_S_SUCCESS;
736
738 currentContextMap->dwClientID,
739 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
740
741 if (rv != SCARD_S_SUCCESS)
742 goto end;
743
744 /*
745 * Read a message from the server
746 */
747 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
748 currentContextMap->dwClientID);
749
750 if (rv != SCARD_S_SUCCESS)
751 goto end;
752
753 rv = scReleaseStruct.rv;
754end:
755 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
756
757 /*
758 * Remove the local context from the stack
759 */
761 SCardRemoveContext(hContext);
763
764error:
765 PROFILE_END(rv)
766 API_TRACE_OUT("")
767
768 return rv;
769}
770
826LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
827 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
828 LPDWORD pdwActiveProtocol)
829{
830 LONG rv;
831 struct connect_struct scConnectStruct;
832 SCONTEXTMAP * currentContextMap;
833
834 PROFILE_START
835 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
836
837 /*
838 * Check for NULL parameters
839 */
840 if (phCard == NULL || pdwActiveProtocol == NULL)
842 else
843 *phCard = 0;
844
845 if (szReader == NULL)
847
848 /*
849 * Check for uninitialized strings
850 */
851 if (strlen(szReader) > MAX_READERNAME)
853
854 /*
855 * Make sure this context has been opened
856 */
857 currentContextMap = SCardGetAndLockContext(hContext);
858 if (NULL == currentContextMap)
860
861 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
862 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
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_READERS_CONTEXTS; i++)
1474 {
1475 /* by default r == NULL */
1476 if (r && strcmp(r, readerStates[i].readerName) == 0)
1477 break;
1478 }
1479
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 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1737 {
1739 goto error;
1740 }
1741
1742 /* Check the integrity of the reader states structures */
1743 for (j = 0; j < cReaders; j++)
1744 {
1745 if (rgReaderStates[j].szReader == NULL)
1746 return SCARD_E_INVALID_VALUE;
1747 }
1748
1749 /* return if all readers are SCARD_STATE_IGNORE */
1750 if (cReaders > 0)
1751 {
1752 int nbNonIgnoredReaders = cReaders;
1753
1754 for (j=0; j<cReaders; j++)
1755 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1756 nbNonIgnoredReaders--;
1757
1758 if (0 == nbNonIgnoredReaders)
1759 {
1760 rv = SCARD_S_SUCCESS;
1761 goto error;
1762 }
1763 }
1764 else
1765 {
1766 /* reader list is empty */
1767 rv = SCARD_S_SUCCESS;
1768 goto error;
1769 }
1770
1771 /*
1772 * Make sure this context has been opened
1773 */
1774 currentContextMap = SCardGetAndLockContext(hContext);
1775 if (NULL == currentContextMap)
1776 {
1778 goto error;
1779 }
1780
1781 /* lock access to readerStates[] */
1782 (void)pthread_mutex_lock(&readerStatesMutex);
1783
1784 /* synchronize reader states with daemon */
1785 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1786
1787 if (rv != SCARD_S_SUCCESS)
1788 {
1789 (void)pthread_mutex_unlock(&readerStatesMutex);
1790 goto end;
1791 }
1792
1793 /* check all the readers are already known */
1794 for (j=0; j<cReaders; j++)
1795 {
1796 const char *readerName;
1797 int i;
1798
1799 readerName = rgReaderStates[j].szReader;
1800 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1801 {
1802 if (strcmp(readerName, readerStates[i].readerName) == 0)
1803 break;
1804 }
1805
1806 /* The requested reader name is not recognized */
1808 {
1809 /* PnP special reader? */
1810 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1811 {
1813 (void)pthread_mutex_unlock(&readerStatesMutex);
1814 goto end;
1815 }
1816 else
1817 pnp_reader = j;
1818 }
1819 }
1820 (void)pthread_mutex_unlock(&readerStatesMutex);
1821
1822 /* Clear the event state for all readers */
1823 for (j = 0; j < cReaders; j++)
1824 rgReaderStates[j].dwEventState = 0;
1825
1826 /* Now is where we start our event checking loop */
1827 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1828
1829 /* index of the PnP readerin rgReaderStates[] */
1830 if (pnp_reader >= 0)
1831 {
1832 int readerEvents;
1833 currReader = &rgReaderStates[pnp_reader];
1834
1835 /* PnP special reader */
1836 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1837 {
1838 int previousReaderEvents = currReader->dwCurrentState >> 16;
1839
1840 // store readerEvents in .dwEventState high word
1841 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1842 if (
1843 /* the value has changed since the last call */
1844 (previousReaderEvents != readerEvents)
1845 /* backward compatibility: only if we had a non-null
1846 * reader events value */
1847 && previousReaderEvents)
1848 {
1849 currReader->dwEventState |= SCARD_STATE_CHANGED;
1850 rv = SCARD_S_SUCCESS;
1851 dwBreakFlag = 1;
1852 }
1853 }
1854 }
1855
1856 /* Get the initial reader count on the system */
1857 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1858 if (readerStates[j].readerName[0] != '\0')
1859 currentReaderCount++;
1860
1861 /* catch possible sign extension problems from 32 to 64-bits integers */
1862 if ((DWORD)-1 == dwTimeout)
1863 dwTimeout = INFINITE;
1864 if (INFINITE == dwTimeout)
1865 dwTime = 60*1000; /* "infinite" timeout */
1866 else
1867 dwTime = dwTimeout;
1868
1869 j = 0;
1870 do
1871 {
1872 currReader = &rgReaderStates[j];
1873
1874 /* Ignore for IGNORED readers */
1875 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1876 {
1877 const char *readerName;
1878 int i;
1879
1880 /* lock access to readerStates[] */
1881 (void)pthread_mutex_lock(&readerStatesMutex);
1882
1883 /* Looks for correct readernames */
1884 readerName = currReader->szReader;
1885 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1886 {
1887 if (strcmp(readerName, readerStates[i].readerName) == 0)
1888 break;
1889 }
1890
1891 /* The requested reader name is not recognized */
1893 {
1894 /* PnP special reader? */
1895 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1896 {
1897 int k, newReaderCount = 0;
1898
1899 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1900 if (readerStates[k].readerName[0] != '\0')
1901 newReaderCount++;
1902
1903 if (newReaderCount != currentReaderCount)
1904 {
1905 int readerEvents;
1906
1907 Log1(PCSC_LOG_INFO, "Reader list changed");
1908 currentReaderCount = newReaderCount;
1909
1910 if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1911 {
1912 // store readerEvents in .dwEventState high word
1913 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1914 }
1915
1916 currReader->dwEventState |= SCARD_STATE_CHANGED;
1917 dwBreakFlag = 1;
1918 }
1919 }
1920 else
1921 {
1922 currReader->dwEventState =
1924 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1925 {
1926 currReader->dwEventState |= SCARD_STATE_CHANGED;
1927 /*
1928 * Spec says use SCARD_STATE_IGNORE but a removed USB
1929 * reader with eventState fed into currentState will
1930 * be ignored forever
1931 */
1932 dwBreakFlag = 1;
1933 }
1934 }
1935 }
1936 else
1937 {
1938 uint32_t readerState;
1939
1940 /* The reader has come back after being away */
1941 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1942 {
1943 currReader->dwEventState |= SCARD_STATE_CHANGED;
1944 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1945 Log0(PCSC_LOG_DEBUG);
1946 dwBreakFlag = 1;
1947 }
1948
1949 /* Set the reader status structure */
1950 rContext = &readerStates[i];
1951
1952 /* Now we check all the Reader States */
1953 readerState = rContext->readerState;
1954
1955 /* only if current state has an non null event counter */
1956 if (currReader->dwCurrentState & 0xFFFF0000)
1957 {
1958 unsigned int currentCounter;
1959
1960 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1961
1962 /* has the event counter changed since the last call? */
1963 if (rContext->eventCounter != currentCounter)
1964 {
1965 currReader->dwEventState |= SCARD_STATE_CHANGED;
1966 Log0(PCSC_LOG_DEBUG);
1967 dwBreakFlag = 1;
1968 }
1969 }
1970
1971 /* add an event counter in the upper word of dwEventState */
1972 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1973 | (rContext->eventCounter << 16));
1974
1975 /* Check if the reader is in the correct state */
1976 if (readerState & SCARD_UNKNOWN)
1977 {
1978 /* reader is in bad state */
1979 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1980 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1981 {
1982 /* App thinks reader is in good state and it is not */
1983 currReader->dwEventState |= SCARD_STATE_CHANGED;
1984 Log0(PCSC_LOG_DEBUG);
1985 dwBreakFlag = 1;
1986 }
1987 }
1988 else
1989 {
1990 /* App thinks reader in bad state but it is not */
1991 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1992 {
1993 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1994 currReader->dwEventState |= SCARD_STATE_CHANGED;
1995 Log0(PCSC_LOG_DEBUG);
1996 dwBreakFlag = 1;
1997 }
1998 }
1999
2000 /* Check for card presence in the reader */
2001 if (readerState & SCARD_PRESENT)
2002 {
2003#ifndef DISABLE_AUTO_POWER_ON
2004 /* card present but not yet powered up */
2005 if (0 == rContext->cardAtrLength)
2006 /* Allow the status thread to convey information */
2007 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2008#endif
2009
2010 currReader->cbAtr = rContext->cardAtrLength;
2011 memcpy(currReader->rgbAtr, rContext->cardAtr,
2012 currReader->cbAtr);
2013 }
2014 else
2015 currReader->cbAtr = 0;
2016
2017 /* Card is now absent */
2018 if (readerState & SCARD_ABSENT)
2019 {
2020 currReader->dwEventState |= SCARD_STATE_EMPTY;
2021 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
2022 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2023 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2024 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2025 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2026 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
2027 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2028 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2029
2030 /* After present the rest are assumed */
2031 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2032 {
2033 currReader->dwEventState |= SCARD_STATE_CHANGED;
2034 Log0(PCSC_LOG_DEBUG);
2035 dwBreakFlag = 1;
2036 }
2037 }
2038 /* Card is now present */
2039 else if (readerState & SCARD_PRESENT)
2040 {
2041 currReader->dwEventState |= SCARD_STATE_PRESENT;
2042 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2043 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2044 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2045 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2046 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2047 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2048
2049 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2050 {
2051 currReader->dwEventState |= SCARD_STATE_CHANGED;
2052 Log0(PCSC_LOG_DEBUG);
2053 dwBreakFlag = 1;
2054 }
2055
2056 if (readerState & SCARD_SWALLOWED)
2057 {
2058 currReader->dwEventState |= SCARD_STATE_MUTE;
2059 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2060 {
2061 currReader->dwEventState |= SCARD_STATE_CHANGED;
2062 Log0(PCSC_LOG_DEBUG);
2063 dwBreakFlag = 1;
2064 }
2065 }
2066 else
2067 {
2068 /* App thinks card is mute but it is not */
2069 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2070 {
2071 currReader->dwEventState |= SCARD_STATE_CHANGED;
2072 Log0(PCSC_LOG_DEBUG);
2073 dwBreakFlag = 1;
2074 }
2075 }
2076 }
2077
2078 /* Now figure out sharing modes */
2080 {
2081 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2082 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2083 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2084 {
2085 currReader->dwEventState |= SCARD_STATE_CHANGED;
2086 Log0(PCSC_LOG_DEBUG);
2087 dwBreakFlag = 1;
2088 }
2089 }
2090 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2091 {
2092 /* A card must be inserted for it to be INUSE */
2093 if (readerState & SCARD_PRESENT)
2094 {
2095 currReader->dwEventState |= SCARD_STATE_INUSE;
2096 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2097 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2098 {
2099 currReader->dwEventState |= SCARD_STATE_CHANGED;
2100 Log0(PCSC_LOG_DEBUG);
2101 dwBreakFlag = 1;
2102 }
2103 }
2104 }
2105 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2106 {
2107 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2108 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2109
2110 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2111 {
2112 currReader->dwEventState |= SCARD_STATE_CHANGED;
2113 Log0(PCSC_LOG_DEBUG);
2114 dwBreakFlag = 1;
2115 }
2116 else if (currReader-> dwCurrentState
2118 {
2119 currReader->dwEventState |= SCARD_STATE_CHANGED;
2120 Log0(PCSC_LOG_DEBUG);
2121 dwBreakFlag = 1;
2122 }
2123 }
2124
2125 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2126 {
2127 /*
2128 * Break out of the while .. loop and return status
2129 * once all the status's for all readers is met
2130 */
2131 currReader->dwEventState |= SCARD_STATE_CHANGED;
2132 Log0(PCSC_LOG_DEBUG);
2133 dwBreakFlag = 1;
2134 }
2135 } /* End of SCARD_STATE_UNKNOWN */
2136
2137 (void)pthread_mutex_unlock(&readerStatesMutex);
2138 } /* End of SCARD_STATE_IGNORE */
2139
2140 /* Counter and resetter */
2141 j++;
2142 if (j == cReaders)
2143 {
2144 /* go back to the first reader */
2145 j = 0;
2146
2147 /* Declare all the break conditions */
2148
2149 /* Break if UNAWARE is set and all readers have been checked */
2150 if (dwBreakFlag == 1)
2151 break;
2152
2153 /* Only sleep once for each cycle of reader checks. */
2154 {
2155 struct wait_reader_state_change waitStatusStruct = {0};
2156 struct timeval before, after;
2157
2158 gettimeofday(&before, NULL);
2159
2160 waitStatusStruct.rv = SCARD_S_SUCCESS;
2161
2162 /* another thread can do SCardCancel() */
2163 currentContextMap->cancellable = true;
2164
2165 /*
2166 * Read a message from the server
2167 */
2169 &waitStatusStruct, sizeof(waitStatusStruct),
2170 currentContextMap->dwClientID, dwTime);
2171
2172 /* SCardCancel() will return immediately with success
2173 * because something changed on the daemon side. */
2174 currentContextMap->cancellable = false;
2175
2176 /* timeout */
2177 if (SCARD_E_TIMEOUT == rv)
2178 {
2179 /* ask server to remove us from the event list */
2180 rv = unregisterFromEvents(currentContextMap);
2181 }
2182
2183 if (rv != SCARD_S_SUCCESS)
2184 goto end;
2185
2186 /* an event occurs or SCardCancel() was called */
2187 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2188 {
2189 rv = waitStatusStruct.rv;
2190 goto end;
2191 }
2192
2193 /* synchronize reader states with daemon */
2194 (void)pthread_mutex_lock(&readerStatesMutex);
2195 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2196 (void)pthread_mutex_unlock(&readerStatesMutex);
2197 if (rv != SCARD_S_SUCCESS)
2198 goto end;
2199
2200 if (INFINITE != dwTimeout)
2201 {
2202 long int diff;
2203
2204 gettimeofday(&after, NULL);
2205 diff = time_sub(&after, &before);
2206 dwTime -= diff/1000;
2207 }
2208 }
2209
2210 if (dwTimeout != INFINITE)
2211 {
2212 /* If time is greater than timeout and all readers have been
2213 * checked
2214 */
2215 if (dwTime <= 0)
2216 {
2217 rv = SCARD_E_TIMEOUT;
2218 goto end;
2219 }
2220 }
2221 }
2222 }
2223 while (1);
2224
2225end:
2226 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2227
2228 /* if SCardCancel() has been used then the client is already
2229 * unregistered */
2230 if (SCARD_E_CANCELLED != rv)
2231 (void)unregisterFromEvents(currentContextMap);
2232
2233 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2234
2235error:
2236 PROFILE_END(rv)
2237#ifdef DO_TRACE
2238 for (j=0; j<cReaders; j++)
2239 {
2240 API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2241 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2242 rgReaderStates[j].cbAtr)
2243 }
2244#endif
2245
2246 return rv;
2247}
2248
2299LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2300 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2301 LPDWORD lpBytesReturned)
2302{
2303 LONG rv;
2304 struct control_struct scControlStruct;
2305 SCONTEXTMAP * currentContextMap;
2306 CHANNEL_MAP * pChannelMap;
2307
2308 PROFILE_START
2309
2310 /* 0 bytes received by default */
2311 if (NULL != lpBytesReturned)
2312 *lpBytesReturned = 0;
2313
2314 /*
2315 * Make sure this handle has been opened
2316 */
2317 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2318 &pChannelMap);
2319 if (rv == -1)
2320 {
2321 PROFILE_END(SCARD_E_INVALID_HANDLE)
2323 }
2324
2325 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2326 {
2328 goto end;
2329 }
2330
2331 scControlStruct.hCard = hCard;
2332 scControlStruct.dwControlCode = dwControlCode;
2333 scControlStruct.cbSendLength = cbSendLength;
2334 scControlStruct.cbRecvLength = cbRecvLength;
2335 scControlStruct.dwBytesReturned = 0;
2336 scControlStruct.rv = 0;
2337
2338 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2339 sizeof(scControlStruct), &scControlStruct);
2340
2341 if (rv != SCARD_S_SUCCESS)
2342 goto end;
2343
2344 /* write the sent buffer */
2345 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2346 currentContextMap->dwClientID);
2347
2348 if (rv != SCARD_S_SUCCESS)
2349 goto end;
2350
2351 /*
2352 * Read a message from the server
2353 */
2354 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2355 currentContextMap->dwClientID);
2356
2357 if (rv != SCARD_S_SUCCESS)
2358 goto end;
2359
2360 if (SCARD_S_SUCCESS == scControlStruct.rv)
2361 {
2362 if (scControlStruct.dwBytesReturned > cbRecvLength)
2363 {
2364 if (NULL != lpBytesReturned)
2365 *lpBytesReturned = scControlStruct.dwBytesReturned;
2367 goto end;
2368 }
2369
2370 /* read the received buffer */
2371 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2372 currentContextMap->dwClientID);
2373
2374 if (rv != SCARD_S_SUCCESS)
2375 goto end;
2376
2377 }
2378
2379 if (NULL != lpBytesReturned)
2380 *lpBytesReturned = scControlStruct.dwBytesReturned;
2381
2382 rv = scControlStruct.rv;
2383
2384end:
2385 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2386
2387 PROFILE_END(rv)
2388
2389 return rv;
2390}
2391
2510LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2511 LPDWORD pcbAttrLen)
2512{
2513 LONG ret;
2514 unsigned char *buf = NULL;
2515
2516 PROFILE_START
2517
2518 if (NULL == pcbAttrLen)
2519 {
2521 goto end;
2522 }
2523
2524 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2525 {
2526 if (NULL == pbAttr)
2528
2529 *pcbAttrLen = MAX_BUFFER_SIZE;
2530 buf = malloc(*pcbAttrLen);
2531 if (NULL == buf)
2532 {
2533 ret = SCARD_E_NO_MEMORY;
2534 goto end;
2535 }
2536
2537 *(unsigned char **)pbAttr = buf;
2538 }
2539 else
2540 {
2541 buf = pbAttr;
2542
2543 /* if only get the length */
2544 if (NULL == pbAttr)
2545 /* use a reasonable size */
2546 *pcbAttrLen = MAX_BUFFER_SIZE;
2547 }
2548
2549 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2550 pcbAttrLen);
2551
2552end:
2553 PROFILE_END(ret)
2554
2555 return ret;
2556}
2557
2593LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2594 DWORD cbAttrLen)
2595{
2596 LONG ret;
2597
2598 PROFILE_START
2599
2600 if (NULL == pbAttr || 0 == cbAttrLen)
2602
2603 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2604 &cbAttrLen);
2605
2606 PROFILE_END(ret)
2607
2608 return ret;
2609}
2610
2611static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2612 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2613{
2614 LONG rv;
2615 struct getset_struct scGetSetStruct;
2616 SCONTEXTMAP * currentContextMap;
2617 CHANNEL_MAP * pChannelMap;
2618
2619 /*
2620 * Make sure this handle has been opened
2621 */
2622 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2623 &pChannelMap);
2624 if (rv == -1)
2626
2627 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2628 {
2630 goto end;
2631 }
2632
2633 scGetSetStruct.hCard = hCard;
2634 scGetSetStruct.dwAttrId = dwAttrId;
2635 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2636 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2637 if (SCARD_SET_ATTRIB == command)
2638 {
2639 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2640 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2641 }
2642 else
2643 /* we can get up to the communication buffer size */
2644 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2645
2646 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2647 sizeof(scGetSetStruct), &scGetSetStruct);
2648
2649 if (rv != SCARD_S_SUCCESS)
2650 goto end;
2651
2652 /*
2653 * Read a message from the server
2654 */
2655 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2656 currentContextMap->dwClientID);
2657
2658 if (rv != SCARD_S_SUCCESS)
2659 goto end;
2660
2661 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2662 {
2663 /*
2664 * Copy and zero it so any secret information is not leaked
2665 */
2666 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2667 {
2668 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2669 * buffer overflow in the memcpy() below */
2670 DWORD correct_value = scGetSetStruct.cbAttrLen;
2671 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2672 *pcbAttrLen = correct_value;
2673
2674 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2675 }
2676 else
2677 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2678
2679 if (pbAttr)
2680 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2681
2682 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2683 }
2684 rv = scGetSetStruct.rv;
2685
2686end:
2687 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2688
2689 return rv;
2690}
2691
2750LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2751 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2752 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2753 LPDWORD pcbRecvLength)
2754{
2755 LONG rv;
2756 SCONTEXTMAP * currentContextMap;
2757 CHANNEL_MAP * pChannelMap;
2758 struct transmit_struct scTransmitStruct;
2759
2760 PROFILE_START
2761
2762 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2763 pcbRecvLength == NULL || pioSendPci == NULL)
2765
2766 /* Retry loop for blocking behaviour */
2767retry:
2768
2769 /*
2770 * Make sure this handle has been opened
2771 */
2772 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2773 &pChannelMap);
2774 if (rv == -1)
2775 {
2776 *pcbRecvLength = 0;
2777 PROFILE_END(SCARD_E_INVALID_HANDLE)
2779 }
2780
2781 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2782 {
2784 goto end;
2785 }
2786
2787 scTransmitStruct.hCard = hCard;
2788 scTransmitStruct.cbSendLength = cbSendLength;
2789 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2790 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2791 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2792 scTransmitStruct.rv = SCARD_S_SUCCESS;
2793
2794 if (pioRecvPci)
2795 {
2796 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2797 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2798 }
2799 else
2800 {
2801 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2802 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2803 }
2804
2805 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2806 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2807
2808 if (rv != SCARD_S_SUCCESS)
2809 goto end;
2810
2811 /* write the sent buffer */
2812 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2813 currentContextMap->dwClientID);
2814
2815 if (rv != SCARD_S_SUCCESS)
2816 goto end;
2817
2818 /*
2819 * Read a message from the server
2820 */
2821 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2822 currentContextMap->dwClientID);
2823
2824 if (rv != SCARD_S_SUCCESS)
2825 goto end;
2826
2827 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2828 {
2829 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2830 {
2831 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2833 goto end;
2834 }
2835
2836 /* read the received buffer */
2837 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2838 currentContextMap->dwClientID);
2839
2840 if (rv != SCARD_S_SUCCESS)
2841 goto end;
2842
2843 if (pioRecvPci)
2844 {
2845 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2846 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2847 }
2848 }
2849
2850 rv = scTransmitStruct.rv;
2851
2852 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2853 {
2854 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2855 (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2856 goto retry;
2857 }
2858
2859 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2860
2861end:
2862 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2863
2864 PROFILE_END(rv)
2865
2866 return rv;
2867}
2868
2935LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2936 LPSTR mszReaders, LPDWORD pcchReaders)
2937{
2938 DWORD dwReadersLen = 0;
2939 int i;
2940 SCONTEXTMAP * currentContextMap;
2941 LONG rv = SCARD_S_SUCCESS;
2942 char *buf = NULL;
2943
2944 (void)mszGroups;
2945 PROFILE_START
2946 API_TRACE_IN("%ld", hContext)
2947
2948 /*
2949 * Check for NULL parameters
2950 */
2951 if (pcchReaders == NULL)
2953
2954 /*
2955 * Make sure this context has been opened
2956 */
2957 currentContextMap = SCardGetAndLockContext(hContext);
2958 if (NULL == currentContextMap)
2959 {
2960 PROFILE_END(SCARD_E_INVALID_HANDLE)
2962 }
2963
2964 /* lock access to readerStates[] */
2965 (void)pthread_mutex_lock(&readerStatesMutex);
2966
2967 /* synchronize reader states with daemon */
2968 rv = getReaderStates(currentContextMap);
2969 if (rv != SCARD_S_SUCCESS)
2970 goto end;
2971
2972 dwReadersLen = 0;
2973 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2974 if (readerStates[i].readerName[0] != '\0')
2975 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2976
2977 /* for the last NULL byte */
2978 dwReadersLen += 1;
2979
2980 if (1 == dwReadersLen)
2981 {
2983 goto end;
2984 }
2985
2986 if (SCARD_AUTOALLOCATE == *pcchReaders)
2987 {
2988 if (NULL == mszReaders)
2989 {
2991 goto end;
2992 }
2993 buf = malloc(dwReadersLen);
2994 if (NULL == buf)
2995 {
2996 rv = SCARD_E_NO_MEMORY;
2997 goto end;
2998 }
2999 *(char **)mszReaders = buf;
3000 }
3001 else
3002 {
3003 buf = mszReaders;
3004
3005 /* not enough place to store the reader names */
3006 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3007 {
3009 goto end;
3010 }
3011 }
3012
3013 if (mszReaders == NULL) /* text array not allocated */
3014 goto end;
3015
3016 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
3017 {
3018 if (readerStates[i].readerName[0] != '\0')
3019 {
3020 /*
3021 * Build the multi-string
3022 */
3023 strcpy(buf, readerStates[i].readerName);
3024 buf += strlen(readerStates[i].readerName)+1;
3025 }
3026 }
3027 *buf = '\0'; /* Add the last null */
3028
3029end:
3030 /* set the reader names length */
3031 *pcchReaders = dwReadersLen;
3032
3033 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3034 (void)pthread_mutex_unlock(&readerStatesMutex);
3035
3036 PROFILE_END(rv)
3037 API_TRACE_OUT("%d", *pcchReaders)
3038
3039 return rv;
3040}
3041
3054
3055LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3056{
3057 LONG rv = SCARD_S_SUCCESS;
3058
3059 PROFILE_START
3060
3061 /*
3062 * Make sure this context has been opened
3063 */
3064 if (! SCardGetContextValidity(hContext))
3066
3067 free((void *)pvMem);
3068
3069 PROFILE_END(rv)
3070
3071 return rv;
3072}
3073
3125LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3126 LPDWORD pcchGroups)
3127{
3128 LONG rv = SCARD_S_SUCCESS;
3129 SCONTEXTMAP * currentContextMap;
3130 char *buf = NULL;
3131
3132 PROFILE_START
3133
3134 /* Multi-string with two trailing \0 */
3135 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3136 const unsigned int dwGroups = sizeof(ReaderGroup);
3137
3138 /*
3139 * Make sure this context has been opened
3140 */
3141 currentContextMap = SCardGetAndLockContext(hContext);
3142 if (NULL == currentContextMap)
3144
3145 if (SCARD_AUTOALLOCATE == *pcchGroups)
3146 {
3147 if (NULL == mszGroups)
3148 {
3150 goto end;
3151 }
3152 buf = malloc(dwGroups);
3153 if (NULL == buf)
3154 {
3155 rv = SCARD_E_NO_MEMORY;
3156 goto end;
3157 }
3158 *(char **)mszGroups = buf;
3159 }
3160 else
3161 {
3162 buf = mszGroups;
3163
3164 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3165 {
3167 goto end;
3168 }
3169 }
3170
3171 if (buf)
3172 memcpy(buf, ReaderGroup, dwGroups);
3173
3174end:
3175 *pcchGroups = dwGroups;
3176
3177 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3178
3179 PROFILE_END(rv)
3180
3181 return rv;
3182}
3183
3216{
3217 SCONTEXTMAP * currentContextMap;
3218 LONG rv = SCARD_S_SUCCESS;
3219 uint32_t dwClientID = 0;
3220 struct cancel_struct scCancelStruct;
3221 bool cancellable;
3222
3223 PROFILE_START
3224 API_TRACE_IN("%ld", hContext)
3225
3226 /*
3227 * Make sure this context has been opened
3228 */
3229 (void)SCardLockThread();
3230 currentContextMap = SCardGetContextTH(hContext);
3231
3232 if (NULL == currentContextMap)
3233 {
3234 (void)SCardUnlockThread();
3236 goto error;
3237 }
3238 cancellable = currentContextMap->cancellable;
3239 (void)SCardUnlockThread();
3240
3241 if (! cancellable)
3242 {
3243 rv = SCARD_S_SUCCESS;
3244 goto error;
3245 }
3246
3247 /* create a new connection to the server */
3248 if (ClientSetupSession(&dwClientID) != 0)
3249 {
3250 rv = SCARD_E_NO_SERVICE;
3251 goto error;
3252 }
3253
3254 scCancelStruct.hContext = hContext;
3255 scCancelStruct.rv = SCARD_S_SUCCESS;
3256
3257 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3258 sizeof(scCancelStruct), (void *) &scCancelStruct);
3259
3260 if (rv != SCARD_S_SUCCESS)
3261 goto end;
3262
3263 /*
3264 * Read a message from the server
3265 */
3266 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3267
3268 if (rv != SCARD_S_SUCCESS)
3269 goto end;
3270
3271 rv = scCancelStruct.rv;
3272end:
3273 ClientCloseSession(dwClientID);
3274
3275error:
3276 PROFILE_END(rv)
3277 API_TRACE_OUT("")
3278
3279 return rv;
3280}
3281
3306{
3307 LONG rv;
3308
3309 PROFILE_START
3310 API_TRACE_IN("%ld", hContext)
3311
3312 rv = SCARD_S_SUCCESS;
3313
3314 /*
3315 * Make sure this context has been opened
3316 */
3317 if (! SCardGetContextValidity(hContext))
3319
3320 PROFILE_END(rv)
3321 API_TRACE_OUT("")
3322
3323 return rv;
3324}
3325
3331
3342static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3343{
3344 int lrv;
3345 SCONTEXTMAP * newContextMap;
3346
3347 newContextMap = malloc(sizeof(SCONTEXTMAP));
3348 if (NULL == newContextMap)
3349 return SCARD_E_NO_MEMORY;
3350
3351 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3352 newContextMap->hContext = hContext;
3353 newContextMap->dwClientID = dwClientID;
3354 newContextMap->cancellable = false;
3355
3356 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3357
3358 lrv = list_init(&newContextMap->channelMapList);
3359 if (lrv < 0)
3360 {
3361 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3362 goto error;
3363 }
3364
3365 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3366 CHANNEL_MAP_seeker);
3367 if (lrv <0)
3368 {
3369 Log2(PCSC_LOG_CRITICAL,
3370 "list_attributes_seeker failed with return value: %d", lrv);
3371 list_destroy(&newContextMap->channelMapList);
3372 goto error;
3373 }
3374
3375 (void)pthread_mutex_lock(&contextMapList_lock);
3376 lrv = list_append(&contextMapList, newContextMap);
3377 (void)pthread_mutex_unlock(&contextMapList_lock);
3378 if (lrv < 0)
3379 {
3380 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3381 lrv);
3382 list_destroy(&newContextMap->channelMapList);
3383 goto error;
3384 }
3385
3386 return SCARD_S_SUCCESS;
3387
3388error:
3389
3390 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3391 free(newContextMap);
3392
3393 return SCARD_E_NO_MEMORY;
3394}
3395
3413{
3414 SCONTEXTMAP * currentContextMap;
3415
3417 currentContextMap = SCardGetContextTH(hContext);
3418
3419 /* lock the context (if available) */
3420 if (NULL != currentContextMap)
3421 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3422
3424
3425 return currentContextMap;
3426}
3427
3441{
3442 SCONTEXTMAP * currentContextMap;
3443
3444 (void)pthread_mutex_lock(&contextMapList_lock);
3445 currentContextMap = list_seek(&contextMapList, &hContext);
3446 (void)pthread_mutex_unlock(&contextMapList_lock);
3447
3448 return currentContextMap;
3449}
3450
3458{
3459 SCONTEXTMAP * currentContextMap;
3460 currentContextMap = SCardGetContextTH(hContext);
3461
3462 if (NULL != currentContextMap)
3463 SCardCleanContext(currentContextMap);
3464}
3465
3466static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3467{
3468 int list_index, lrv;
3469 int listSize;
3470 CHANNEL_MAP * currentChannelMap;
3471
3472 targetContextMap->hContext = 0;
3473 ClientCloseSession(targetContextMap->dwClientID);
3474 targetContextMap->dwClientID = 0;
3475 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3476
3477 listSize = list_size(&targetContextMap->channelMapList);
3478 for (list_index = 0; list_index < listSize; list_index++)
3479 {
3480 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3481 list_index);
3482 if (NULL == currentChannelMap)
3483 {
3484 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3485 list_index);
3486 continue;
3487 }
3488 else
3489 {
3490 free(currentChannelMap->readerName);
3491 free(currentChannelMap);
3492 }
3493
3494 }
3495 list_destroy(&targetContextMap->channelMapList);
3496
3497 (void)pthread_mutex_lock(&contextMapList_lock);
3498 lrv = list_delete(&contextMapList, targetContextMap);
3499 (void)pthread_mutex_unlock(&contextMapList_lock);
3500 if (lrv < 0)
3501 {
3502 Log2(PCSC_LOG_CRITICAL,
3503 "list_delete failed with return value: %d", lrv);
3504 }
3505
3506 free(targetContextMap);
3507
3508 return;
3509}
3510
3511/*
3512 * Functions for managing hCard values returned from SCardConnect.
3513 */
3514
3515static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3516 LPCSTR readerName)
3517{
3518 CHANNEL_MAP * newChannelMap;
3519 int lrv = -1;
3520
3521 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3522 if (NULL == newChannelMap)
3523 return SCARD_E_NO_MEMORY;
3524
3525 newChannelMap->hCard = hCard;
3526 newChannelMap->readerName = strdup(readerName);
3527
3528 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3529 if (lrv < 0)
3530 {
3531 free(newChannelMap->readerName);
3532 free(newChannelMap);
3533 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3534 lrv);
3535 return SCARD_E_NO_MEMORY;
3536 }
3537
3538 return SCARD_S_SUCCESS;
3539}
3540
3541static void SCardRemoveHandle(SCARDHANDLE hCard)
3542{
3543 SCONTEXTMAP * currentContextMap;
3544 CHANNEL_MAP * currentChannelMap;
3545 int lrv;
3546 LONG rv;
3547
3548 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3549 &currentChannelMap);
3550 if (rv == -1)
3551 return;
3552
3553 free(currentChannelMap->readerName);
3554
3555 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3556 if (lrv < 0)
3557 {
3558 Log2(PCSC_LOG_CRITICAL,
3559 "list_delete failed with return value: %d", lrv);
3560 }
3561
3562 free(currentChannelMap);
3563
3564 return;
3565}
3566
3567static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3568 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3569{
3570 LONG rv;
3571
3572 if (0 == hCard)
3573 return -1;
3574
3576 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3577 targetChannelMap);
3578
3579 if (SCARD_S_SUCCESS == rv)
3580 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3581
3583
3584 return rv;
3585}
3586
3587static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3588 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3589{
3590 LONG rv = -1;
3591 int listSize;
3592 int list_index;
3593 SCONTEXTMAP * currentContextMap;
3594 CHANNEL_MAP * currentChannelMap;
3595
3596 /* Best to get the caller a crash early if we fail unsafely */
3597 *targetContextMap = NULL;
3598 *targetChannelMap = NULL;
3599
3600 (void)pthread_mutex_lock(&contextMapList_lock);
3601 listSize = list_size(&contextMapList);
3602
3603 for (list_index = 0; list_index < listSize; list_index++)
3604 {
3605 currentContextMap = list_get_at(&contextMapList, list_index);
3606 if (currentContextMap == NULL)
3607 {
3608 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3609 list_index);
3610 continue;
3611 }
3612 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3613 &hCard);
3614 if (currentChannelMap != NULL)
3615 {
3616 *targetContextMap = currentContextMap;
3617 *targetChannelMap = currentChannelMap;
3618 rv = SCARD_S_SUCCESS;
3619 break;
3620 }
3621 }
3622
3623 (void)pthread_mutex_unlock(&contextMapList_lock);
3624
3625 return rv;
3626}
3627
3636{
3637 LONG rv;
3638 struct stat statBuffer;
3639 char *socketName;
3640
3641 socketName = getSocketName();
3642 rv = stat(socketName, &statBuffer);
3643
3644 if (rv != 0)
3645 {
3646 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3647 socketName, strerror(errno));
3648 return SCARD_E_NO_SERVICE;
3649 }
3650
3651 return SCARD_S_SUCCESS;
3652}
3653
3654static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3655{
3656 int32_t dwClientID = currentContextMap->dwClientID;
3657 LONG rv;
3659
3660 /* CMD_GET_READER_EVENTS was added in protocol 4:5 */
3661 if (Protocol_version < 4005)
3663
3664 rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3665 if (rv != SCARD_S_SUCCESS)
3666 return rv;
3667
3668 /* Read a message from the server */
3669 rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3670 if (rv != SCARD_S_SUCCESS)
3671 return rv;
3672
3673 *readerEvents = get_reader_events.readerEvents;
3674
3675 return SCARD_S_SUCCESS;
3676}
3677
3678static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3679{
3680 int32_t dwClientID = currentContextMap->dwClientID;
3681 LONG rv;
3682
3683 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3684 if (rv != SCARD_S_SUCCESS)
3685 return rv;
3686
3687 /* Read a message from the server */
3688 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3689 if (rv != SCARD_S_SUCCESS)
3690 return rv;
3691
3692 return SCARD_S_SUCCESS;
3693}
3694
3695static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3696{
3697 int32_t dwClientID = currentContextMap->dwClientID;
3698 LONG rv;
3699
3700 /* Get current reader states from server and register on event list */
3702 0, NULL);
3703 if (rv != SCARD_S_SUCCESS)
3704 return rv;
3705
3706 /* Read a message from the server */
3707 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3708 return rv;
3709}
3710
3711static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3712{
3713 int32_t dwClientID = currentContextMap->dwClientID;
3714 LONG rv;
3715 struct wait_reader_state_change waitStatusStruct = {0};
3716
3717 /* ask server to remove us from the event list */
3719 dwClientID, 0, NULL);
3720 if (rv != SCARD_S_SUCCESS)
3721 return rv;
3722
3723 /* This message can be the response to
3724 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3725 * cancel notification.
3726 * The server side ensures, that no more messages will be sent to
3727 * the client. */
3728
3729 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3730 dwClientID);
3731 if (rv != SCARD_S_SUCCESS)
3732 return rv;
3733
3734 /* if we received a cancel event the return value will be set
3735 * accordingly */
3736 rv = waitStatusStruct.rv;
3737
3738 return rv;
3739}
3740
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_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
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.
#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_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()