pcsc-lite  1.8.23
winscard_clnt.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 1999-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2005
9  * Martin Paljak <martin@paljak.pri.ee>
10  * Copyright (C) 2002-2011
11  * Ludovic Rousseau <ludovic.rousseau@free.fr>
12  * Copyright (C) 2009
13  * Jean-Luc Giraud <jlgiraud@googlemail.com>
14  *
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
18 
19 1. Redistributions of source code must retain the above copyright
20  notice, this list of conditions and the following disclaimer.
21 2. 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.
24 3. 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 
27 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
105 #include "config.h"
106 #include <stdlib.h>
107 #include <string.h>
108 #include <sys/types.h>
109 #include <fcntl.h>
110 #include <unistd.h>
111 #include <sys/un.h>
112 #include <errno.h>
113 #include <stddef.h>
114 #include <sys/time.h>
115 #include <pthread.h>
116 #include <sys/wait.h>
117 
118 #include "misc.h"
119 #include "pcscd.h"
120 #include "winscard.h"
121 #include "debuglog.h"
122 
123 #include "readerfactory.h"
124 #include "eventhandler.h"
125 #include "sys_generic.h"
126 #include "winscard_msg.h"
127 #include "utils.h"
128 
129 /* Display, on stderr, a trace of the WinSCard calls with arguments and
130  * results */
131 //#define DO_TRACE
132 
133 /* Profile the execution time of WinSCard calls */
134 //#define DO_PROFILE
135 
136 
138 #define SCARD_PROTOCOL_ANY_OLD 0x1000
139 
140 #ifndef TRUE
141 #define TRUE 1
142 #define FALSE 0
143 #endif
144 
145 static char sharing_shall_block = TRUE;
146 
147 #define COLOR_RED "\33[01;31m"
148 #define COLOR_GREEN "\33[32m"
149 #define COLOR_BLUE "\33[34m"
150 #define COLOR_MAGENTA "\33[35m"
151 #define COLOR_NORMAL "\33[0m"
152 
153 #ifdef DO_TRACE
154 
155 #include <stdio.h>
156 #include <stdarg.h>
157 
158 static void trace(const char *func, const char direction, const char *fmt, ...)
159 {
160  va_list args;
161 
162  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163  direction, pthread_self(), func);
164 
165  fprintf(stderr, COLOR_MAGENTA);
166  va_start(args, fmt);
167  vfprintf(stderr, fmt, args);
168  va_end(args);
169 
170  fprintf(stderr, COLOR_NORMAL "\n");
171 }
172 
173 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175 #else
176 #define API_TRACE_IN(...)
177 #define API_TRACE_OUT(...)
178 #endif
179 
180 #ifdef DO_PROFILE
181 
182 #define PROFILE_FILE "/tmp/pcsc_profile"
183 #include <stdio.h>
184 #include <sys/time.h>
185 
186 /* we can profile a maximum of 5 simultaneous calls */
187 #define MAX_THREADS 5
188 pthread_t threads[MAX_THREADS];
189 struct timeval profile_time_start[MAX_THREADS];
190 FILE *profile_fd;
191 char profile_tty;
192 
193 #define PROFILE_START profile_start();
194 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195 
196 static void profile_start(void)
197 {
198  static char initialized = FALSE;
199  pthread_t t;
200  int i;
201 
202  if (!initialized)
203  {
204  char filename[80];
205 
206  initialized = TRUE;
207  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208  profile_fd = fopen(filename, "a+");
209  if (NULL == profile_fd)
210  {
211  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212  PROFILE_FILE, strerror(errno));
213  exit(-1);
214  }
215  fprintf(profile_fd, "\nStart a new profile\n");
216 
217  if (isatty(fileno(stderr)))
218  profile_tty = TRUE;
219  else
220  profile_tty = FALSE;
221  }
222 
223  t = pthread_self();
224  for (i=0; i<MAX_THREADS; i++)
225  if (pthread_equal(0, threads[i]))
226  {
227  threads[i] = t;
228  break;
229  }
230 
231  gettimeofday(&profile_time_start[i], NULL);
232 } /* profile_start */
233 
234 static void profile_end(const char *f, LONG rv)
235 {
236  struct timeval profile_time_end;
237  long d;
238  pthread_t t;
239  int i;
240 
241  gettimeofday(&profile_time_end, NULL);
242 
243  t = pthread_self();
244  for (i=0; i<MAX_THREADS; i++)
245  if (pthread_equal(t, threads[i]))
246  break;
247 
248  if (i>=MAX_THREADS)
249  {
250  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251  return;
252  }
253 
254  d = time_sub(&profile_time_end, &profile_time_start[i]);
255 
256  /* free this entry */
257  threads[i] = 0;
258 
259  if (profile_tty)
260  {
261  if (rv != SCARD_S_SUCCESS)
262  fprintf(stderr,
263  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265  f, d, rv, pcsc_stringify_error(rv));
266  else
267  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268  COLOR_NORMAL "\n", f, d);
269  }
270  fprintf(profile_fd, "%s %ld\n", f, d);
271  fflush(profile_fd);
272 } /* profile_end */
273 
274 #else
275 #define PROFILE_START
276 #define PROFILE_END(rv)
277 #endif
278 
284 {
285  SCARDHANDLE hCard;
286  LPSTR readerName;
287 };
288 
289 typedef struct _psChannelMap CHANNEL_MAP;
290 
291 static int CHANNEL_MAP_seeker(const void *el, const void *key)
292 {
293  const CHANNEL_MAP * channelMap = el;
294 
295  if ((el == NULL) || (key == NULL))
296  {
297  Log3(PCSC_LOG_CRITICAL,
298  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299  el, key);
300  return 0;
301  }
302 
303  if (channelMap->hCard == *(SCARDHANDLE *)key)
304  return 1;
305 
306  return 0;
307 }
308 
315 {
316  DWORD dwClientID;
318  pthread_mutex_t mMutex;
319  list_t channelMapList;
320  char cancellable;
321 };
327 typedef struct _psContextMap SCONTEXTMAP;
328 
329 static list_t contextMapList;
330 
331 static int SCONTEXTMAP_seeker(const void *el, const void *key)
332 {
333  const SCONTEXTMAP * contextMap = el;
334 
335  if ((el == NULL) || (key == NULL))
336  {
337  Log3(PCSC_LOG_CRITICAL,
338  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
339  el, key);
340  return 0;
341  }
342 
343  if (contextMap->hContext == *(SCARDCONTEXT *) key)
344  return 1;
345 
346  return 0;
347 }
348 
352 static short isExecuted = 0;
353 
354 
359 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
360 
365 
372 
373 
374 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
377 static void SCardRemoveContext(SCARDCONTEXT);
378 static void SCardCleanContext(SCONTEXTMAP *);
379 
380 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
381 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
382  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
383 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
384  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
385 static void SCardRemoveHandle(SCARDHANDLE);
386 
387 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
388  LPBYTE pbAttr, LPDWORD pcbAttrLen);
389 
390 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
391 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
392 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
393 
394 /*
395  * Thread safety functions
396  */
403 inline static void SCardLockThread(void)
404 {
405  pthread_mutex_lock(&clientMutex);
406 }
407 
413 inline static void SCardUnlockThread(void)
414 {
415  pthread_mutex_unlock(&clientMutex);
416 }
417 
428 {
429  SCONTEXTMAP * currentContextMap;
430 
431  SCardLockThread();
432  currentContextMap = SCardGetContextTH(hContext);
434 
435  return currentContextMap != NULL;
436 }
437 
438 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
439  /*@out@*/ LPSCARDCONTEXT);
440 
476 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
477  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
478 {
479  LONG rv;
480 
481  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
482  PROFILE_START
483 
484  /* Check if the server is running */
486  if (rv != SCARD_S_SUCCESS)
487  goto end;
488 
489  SCardLockThread();
490  rv = SCardEstablishContextTH(dwScope, pvReserved1,
491  pvReserved2, phContext);
493 
494 end:
495  PROFILE_END(rv)
496  API_TRACE_OUT("%ld", *phContext)
497 
498  return rv;
499 }
500 
527 static LONG SCardEstablishContextTH(DWORD dwScope,
528  /*@unused@*/ LPCVOID pvReserved1,
529  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
530 {
531  LONG rv;
532  struct establish_struct scEstablishStruct;
533  uint32_t dwClientID = 0;
534 
535  (void)pvReserved1;
536  (void)pvReserved2;
537  if (phContext == NULL)
539  else
540  *phContext = 0;
541 
542  /*
543  * Do this only once:
544  * - Initialize context list.
545  */
546  if (isExecuted == 0)
547  {
548  int lrv;
549 
550  /* NOTE: The list will never be freed (No API call exists to
551  * "close all contexts".
552  * Applications which load and unload the library will leak
553  * the list's internal structures. */
554  lrv = list_init(&contextMapList);
555  if (lrv < 0)
556  {
557  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
558  lrv);
559  return SCARD_E_NO_MEMORY;
560  }
561 
562  lrv = list_attributes_seeker(&contextMapList,
563  SCONTEXTMAP_seeker);
564  if (lrv <0)
565  {
566  Log2(PCSC_LOG_CRITICAL,
567  "list_attributes_seeker failed with return value: %d", lrv);
568  list_destroy(&contextMapList);
569  return SCARD_E_NO_MEMORY;
570  }
571 
572  if (getenv("PCSCLITE_NO_BLOCKING"))
573  {
574  Log1(PCSC_LOG_INFO, "Disable shared blocking");
575  sharing_shall_block = FALSE;
576  }
577 
578  isExecuted = 1;
579  }
580 
581 
582  /* Establishes a connection to the server */
583  if (ClientSetupSession(&dwClientID) != 0)
584  {
585  return SCARD_E_NO_SERVICE;
586  }
587 
588  { /* exchange client/server protocol versions */
589  struct version_struct veStr;
590 
593  veStr.rv = SCARD_S_SUCCESS;
594 
595  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
596  &veStr);
597  if (rv != SCARD_S_SUCCESS)
598  return rv;
599 
600  /* Read a message from the server */
601  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
602  if (rv != SCARD_S_SUCCESS)
603  {
604  Log1(PCSC_LOG_CRITICAL,
605  "Your pcscd is too old and does not support CMD_VERSION");
606  return SCARD_F_COMM_ERROR;
607  }
608 
609  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
610  veStr.major, veStr.minor);
611 
612  if (veStr.rv != SCARD_S_SUCCESS)
613  return veStr.rv;
614  }
615 
616 again:
617  /*
618  * Try to establish an Application Context with the server
619  */
620  scEstablishStruct.dwScope = dwScope;
621  scEstablishStruct.hContext = 0;
622  scEstablishStruct.rv = SCARD_S_SUCCESS;
623 
625  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
626 
627  if (rv != SCARD_S_SUCCESS)
628  return rv;
629 
630  /*
631  * Read the response from the server
632  */
633  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
634  dwClientID);
635 
636  if (rv != SCARD_S_SUCCESS)
637  return rv;
638 
639  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
640  return scEstablishStruct.rv;
641 
642  /* check we do not reuse an existing hContext */
643  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
644  /* we do not need to release the allocated context since
645  * SCardReleaseContext() does nothing on the server side */
646  goto again;
647 
648  *phContext = scEstablishStruct.hContext;
649 
650  /*
651  * Allocate the new hContext - if allocator full return an error
652  */
653  rv = SCardAddContext(*phContext, dwClientID);
654 
655  return rv;
656 }
657 
680 {
681  LONG rv;
682  struct release_struct scReleaseStruct;
683  SCONTEXTMAP * currentContextMap;
684 
685  API_TRACE_IN("%ld", hContext)
686  PROFILE_START
687 
688  /*
689  * Make sure this context has been opened
690  * and get currentContextMap
691  */
692  currentContextMap = SCardGetAndLockContext(hContext);
693  if (NULL == currentContextMap)
694  {
696  goto error;
697  }
698 
699  scReleaseStruct.hContext = hContext;
700  scReleaseStruct.rv = SCARD_S_SUCCESS;
701 
703  currentContextMap->dwClientID,
704  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
705 
706  if (rv != SCARD_S_SUCCESS)
707  goto end;
708 
709  /*
710  * Read a message from the server
711  */
712  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
713  currentContextMap->dwClientID);
714 
715  if (rv != SCARD_S_SUCCESS)
716  goto end;
717 
718  rv = scReleaseStruct.rv;
719 end:
720  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
721 
722  /*
723  * Remove the local context from the stack
724  */
725  SCardLockThread();
726  SCardRemoveContext(hContext);
728 
729 error:
730  PROFILE_END(rv)
731  API_TRACE_OUT("")
732 
733  return rv;
734 }
735 
791 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
792  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
793  LPDWORD pdwActiveProtocol)
794 {
795  LONG rv;
796  struct connect_struct scConnectStruct;
797  SCONTEXTMAP * currentContextMap;
798 
799  PROFILE_START
800  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
801 
802  /*
803  * Check for NULL parameters
804  */
805  if (phCard == NULL || pdwActiveProtocol == NULL)
807  else
808  *phCard = 0;
809 
810  if (szReader == NULL)
811  return SCARD_E_UNKNOWN_READER;
812 
813  /*
814  * Check for uninitialized strings
815  */
816  if (strlen(szReader) > MAX_READERNAME)
817  return SCARD_E_INVALID_VALUE;
818 
819  /*
820  * Make sure this context has been opened
821  */
822  currentContextMap = SCardGetAndLockContext(hContext);
823  if (NULL == currentContextMap)
824  return SCARD_E_INVALID_HANDLE;
825 
826  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
827  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
828  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
829 
830  scConnectStruct.hContext = hContext;
831  scConnectStruct.dwShareMode = dwShareMode;
832  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
833  scConnectStruct.hCard = 0;
834  scConnectStruct.dwActiveProtocol = 0;
835  scConnectStruct.rv = SCARD_S_SUCCESS;
836 
837  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
838  sizeof(scConnectStruct), (void *) &scConnectStruct);
839 
840  if (rv != SCARD_S_SUCCESS)
841  goto end;
842 
843  /*
844  * Read a message from the server
845  */
846  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
847  currentContextMap->dwClientID);
848 
849  if (rv != SCARD_S_SUCCESS)
850  goto end;
851 
852  *phCard = scConnectStruct.hCard;
853  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
854 
855  if (scConnectStruct.rv == SCARD_S_SUCCESS)
856  {
857  /*
858  * Keep track of the handle locally
859  */
860  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
861  }
862  else
863  rv = scConnectStruct.rv;
864 
865 end:
866  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
867 
868  PROFILE_END(rv)
869  API_TRACE_OUT("%d", *pdwActiveProtocol)
870 
871  return rv;
872 }
873 
946 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
947  DWORD dwPreferredProtocols, DWORD dwInitialization,
948  LPDWORD pdwActiveProtocol)
949 {
950  LONG rv;
951  struct reconnect_struct scReconnectStruct;
952  SCONTEXTMAP * currentContextMap;
953  CHANNEL_MAP * pChannelMap;
954 
955  PROFILE_START
956  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
957 
958  if (pdwActiveProtocol == NULL)
960 
961  /* Retry loop for blocking behaviour */
962 retry:
963 
964  /*
965  * Make sure this handle has been opened
966  */
967  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
968  &pChannelMap);
969  if (rv == -1)
970  return SCARD_E_INVALID_HANDLE;
971 
972  scReconnectStruct.hCard = hCard;
973  scReconnectStruct.dwShareMode = dwShareMode;
974  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
975  scReconnectStruct.dwInitialization = dwInitialization;
976  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
977  scReconnectStruct.rv = SCARD_S_SUCCESS;
978 
979  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
980  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
981 
982  if (rv != SCARD_S_SUCCESS)
983  goto end;
984 
985  /*
986  * Read a message from the server
987  */
988  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
989  currentContextMap->dwClientID);
990 
991  if (rv != SCARD_S_SUCCESS)
992  goto end;
993 
994  rv = scReconnectStruct.rv;
995 
996  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
997  {
998  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1000  goto retry;
1001  }
1002 
1003  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1004 
1005 end:
1006  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1007 
1008  PROFILE_END(rv)
1009  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1010 
1011  return rv;
1012 }
1013 
1045 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1046 {
1047  LONG rv;
1048  struct disconnect_struct scDisconnectStruct;
1049  SCONTEXTMAP * currentContextMap;
1050  CHANNEL_MAP * pChannelMap;
1051 
1052  PROFILE_START
1053  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1054 
1055  /*
1056  * Make sure this handle has been opened
1057  */
1058  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1059  &pChannelMap);
1060  if (rv == -1)
1061  {
1063  goto error;
1064  }
1065 
1066  scDisconnectStruct.hCard = hCard;
1067  scDisconnectStruct.dwDisposition = dwDisposition;
1068  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1069 
1070  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1071  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1072 
1073  if (rv != SCARD_S_SUCCESS)
1074  goto end;
1075 
1076  /*
1077  * Read a message from the server
1078  */
1079  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1080  currentContextMap->dwClientID);
1081 
1082  if (rv != SCARD_S_SUCCESS)
1083  goto end;
1084 
1085  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1086  SCardRemoveHandle(hCard);
1087  rv = scDisconnectStruct.rv;
1088 
1089 end:
1090  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1091 
1092 error:
1093  PROFILE_END(rv)
1094  API_TRACE_OUT("")
1095 
1096  return rv;
1097 }
1098 
1135 {
1136 
1137  LONG rv;
1138  struct begin_struct scBeginStruct;
1139  SCONTEXTMAP * currentContextMap;
1140  CHANNEL_MAP * pChannelMap;
1141 
1142  PROFILE_START
1143  API_TRACE_IN("%ld", hCard)
1144 
1145  /*
1146  * Query the server every so often until the sharing violation ends
1147  * and then hold the lock for yourself.
1148  */
1149 
1150  for(;;)
1151  {
1152  /*
1153  * Make sure this handle has been opened
1154  */
1155  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1156  &pChannelMap);
1157  if (rv == -1)
1158  return SCARD_E_INVALID_HANDLE;
1159 
1160  scBeginStruct.hCard = hCard;
1161  scBeginStruct.rv = SCARD_S_SUCCESS;
1162 
1164  currentContextMap->dwClientID,
1165  sizeof(scBeginStruct), (void *) &scBeginStruct);
1166 
1167  if (rv != SCARD_S_SUCCESS)
1168  break;
1169 
1170  /*
1171  * Read a message from the server
1172  */
1173  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1174  currentContextMap->dwClientID);
1175 
1176  if (rv != SCARD_S_SUCCESS)
1177  break;
1178 
1179  rv = scBeginStruct.rv;
1180 
1181  if (SCARD_E_SHARING_VIOLATION != rv)
1182  break;
1183 
1184  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1186  }
1187 
1188  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1189 
1190  PROFILE_END(rv)
1191  API_TRACE_OUT("")
1192 
1193  return rv;
1194 }
1195 
1235 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1236 {
1237  LONG rv;
1238  struct end_struct scEndStruct;
1239  int randnum;
1240  SCONTEXTMAP * currentContextMap;
1241  CHANNEL_MAP * pChannelMap;
1242 
1243  PROFILE_START
1244  API_TRACE_IN("%ld", hCard)
1245 
1246  /*
1247  * Make sure this handle has been opened
1248  */
1249  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1250  &pChannelMap);
1251  if (rv == -1)
1252  return SCARD_E_INVALID_HANDLE;
1253 
1254  scEndStruct.hCard = hCard;
1255  scEndStruct.dwDisposition = dwDisposition;
1256  scEndStruct.rv = SCARD_S_SUCCESS;
1257 
1259  currentContextMap->dwClientID,
1260  sizeof(scEndStruct), (void *) &scEndStruct);
1261 
1262  if (rv != SCARD_S_SUCCESS)
1263  goto end;
1264 
1265  /*
1266  * Read a message from the server
1267  */
1268  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1269  currentContextMap->dwClientID);
1270 
1271  if (rv != SCARD_S_SUCCESS)
1272  goto end;
1273 
1274  /*
1275  * This helps prevent starvation
1276  */
1277  randnum = SYS_RandomInt(1000, 10000);
1278  (void)SYS_USleep(randnum);
1279  rv = scEndStruct.rv;
1280 
1281 end:
1282  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1283 
1284  PROFILE_END(rv)
1285  API_TRACE_OUT("")
1286 
1287  return rv;
1288 }
1289 
1385 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1386  LPDWORD pcchReaderLen, LPDWORD pdwState,
1387  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1388 {
1389  DWORD dwReaderLen, dwAtrLen;
1390  LONG rv;
1391  int i;
1392  struct status_struct scStatusStruct;
1393  SCONTEXTMAP * currentContextMap;
1394  CHANNEL_MAP * pChannelMap;
1395  char *r;
1396  char *bufReader = NULL;
1397  LPBYTE bufAtr = NULL;
1398  DWORD dummy = 0;
1399 
1400  PROFILE_START
1401 
1402  /* default output values */
1403  if (pdwState)
1404  *pdwState = 0;
1405 
1406  if (pdwProtocol)
1407  *pdwProtocol = 0;
1408 
1409  /* Check for NULL parameters */
1410  if (pcchReaderLen == NULL)
1411  pcchReaderLen = &dummy;
1412 
1413  if (pcbAtrLen == NULL)
1414  pcbAtrLen = &dummy;
1415 
1416  /* length passed from caller */
1417  dwReaderLen = *pcchReaderLen;
1418  dwAtrLen = *pcbAtrLen;
1419 
1420  *pcchReaderLen = 0;
1421  *pcbAtrLen = 0;
1422 
1423  /* Retry loop for blocking behaviour */
1424 retry:
1425 
1426  /*
1427  * Make sure this handle has been opened
1428  */
1429  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1430  &pChannelMap);
1431  if (rv == -1)
1432  return SCARD_E_INVALID_HANDLE;
1433 
1434  /* synchronize reader states with daemon */
1435  rv = getReaderStates(currentContextMap);
1436  if (rv != SCARD_S_SUCCESS)
1437  goto end;
1438 
1439  r = pChannelMap->readerName;
1440  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1441  {
1442  /* by default r == NULL */
1443  if (r && strcmp(r, readerStates[i].readerName) == 0)
1444  break;
1445  }
1446 
1448  {
1450  goto end;
1451  }
1452 
1453  /* initialise the structure */
1454  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1455  scStatusStruct.hCard = hCard;
1456 
1457  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1458  sizeof(scStatusStruct), (void *) &scStatusStruct);
1459 
1460  if (rv != SCARD_S_SUCCESS)
1461  goto end;
1462 
1463  /*
1464  * Read a message from the server
1465  */
1466  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1467  currentContextMap->dwClientID);
1468 
1469  if (rv != SCARD_S_SUCCESS)
1470  goto end;
1471 
1472  rv = scStatusStruct.rv;
1473 
1474  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1475  {
1476  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1478  goto retry;
1479  }
1480 
1481  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1482  {
1483  /*
1484  * An event must have occurred
1485  */
1486  goto end;
1487  }
1488 
1489  /*
1490  * Now continue with the client side SCardStatus
1491  */
1492 
1493  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1494  *pcbAtrLen = readerStates[i].cardAtrLength;
1495 
1496  if (pdwState)
1497  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1498 
1499  if (pdwProtocol)
1500  *pdwProtocol = readerStates[i].cardProtocol;
1501 
1502  if (SCARD_AUTOALLOCATE == dwReaderLen)
1503  {
1504  dwReaderLen = *pcchReaderLen;
1505  if (NULL == szReaderName)
1506  {
1508  goto end;
1509  }
1510  bufReader = malloc(dwReaderLen);
1511  if (NULL == bufReader)
1512  {
1513  rv = SCARD_E_NO_MEMORY;
1514  goto end;
1515  }
1516  *(char **)szReaderName = bufReader;
1517  }
1518  else
1519  bufReader = szReaderName;
1520 
1521  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1522  if (bufReader)
1523  {
1524  if (*pcchReaderLen > dwReaderLen)
1526 
1527  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1528  }
1529 
1530  if (SCARD_AUTOALLOCATE == dwAtrLen)
1531  {
1532  dwAtrLen = *pcbAtrLen;
1533  if (NULL == pbAtr)
1534  {
1536  goto end;
1537  }
1538  bufAtr = malloc(dwAtrLen);
1539  if (NULL == bufAtr)
1540  {
1541  rv = SCARD_E_NO_MEMORY;
1542  goto end;
1543  }
1544  *(LPBYTE *)pbAtr = bufAtr;
1545  }
1546  else
1547  bufAtr = pbAtr;
1548 
1549  if (bufAtr)
1550  {
1551  if (*pcbAtrLen > dwAtrLen)
1553 
1554  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1555  }
1556 
1557 end:
1558  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1559 
1560  PROFILE_END(rv)
1561 
1562  return rv;
1563 }
1564 
1672 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1673  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1674 {
1675  SCARD_READERSTATE *currReader;
1676  READER_STATE *rContext;
1677  long dwTime;
1678  DWORD dwBreakFlag = 0;
1679  unsigned int j;
1680  SCONTEXTMAP * currentContextMap;
1681  int currentReaderCount = 0;
1682  LONG rv = SCARD_S_SUCCESS;
1683 
1684  PROFILE_START
1685  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1686 #ifdef DO_TRACE
1687  for (j=0; j<cReaders; j++)
1688  {
1689  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1690  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1691  }
1692 #endif
1693 
1694  if ((rgReaderStates == NULL && cReaders > 0)
1695  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1696  {
1698  goto error;
1699  }
1700 
1701  /* Check the integrity of the reader states structures */
1702  for (j = 0; j < cReaders; j++)
1703  {
1704  if (rgReaderStates[j].szReader == NULL)
1705  return SCARD_E_INVALID_VALUE;
1706  }
1707 
1708  /* return if all readers are SCARD_STATE_IGNORE */
1709  if (cReaders > 0)
1710  {
1711  int nbNonIgnoredReaders = cReaders;
1712 
1713  for (j=0; j<cReaders; j++)
1714  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1715  nbNonIgnoredReaders--;
1716 
1717  if (0 == nbNonIgnoredReaders)
1718  {
1719  rv = SCARD_S_SUCCESS;
1720  goto error;
1721  }
1722  }
1723  else
1724  {
1725  /* reader list is empty */
1726  rv = SCARD_S_SUCCESS;
1727  goto error;
1728  }
1729 
1730  /*
1731  * Make sure this context has been opened
1732  */
1733  currentContextMap = SCardGetAndLockContext(hContext);
1734  if (NULL == currentContextMap)
1735  {
1737  goto error;
1738  }
1739 
1740  /* synchronize reader states with daemon */
1741  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1742  if (rv != SCARD_S_SUCCESS)
1743  goto end;
1744 
1745  /* check all the readers are already known */
1746  for (j=0; j<cReaders; j++)
1747  {
1748  const char *readerName;
1749  int i;
1750 
1751  readerName = rgReaderStates[j].szReader;
1752  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1753  {
1754  if (strcmp(readerName, readerStates[i].readerName) == 0)
1755  break;
1756  }
1757 
1758  /* The requested reader name is not recognized */
1760  {
1761  /* PnP special reader? */
1762  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1763  {
1765  goto end;
1766  }
1767  }
1768  }
1769 
1770  /* Clear the event state for all readers */
1771  for (j = 0; j < cReaders; j++)
1772  rgReaderStates[j].dwEventState = 0;
1773 
1774  /* Now is where we start our event checking loop */
1775  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1776 
1777  /* Get the initial reader count on the system */
1778  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1779  if (readerStates[j].readerName[0] != '\0')
1780  currentReaderCount++;
1781 
1782  /* catch possible sign extension problems from 32 to 64-bits integers */
1783  if ((DWORD)-1 == dwTimeout)
1784  dwTimeout = INFINITE;
1785  if (INFINITE == dwTimeout)
1786  dwTime = 60*1000; /* "infinite" timeout */
1787  else
1788  dwTime = dwTimeout;
1789 
1790  j = 0;
1791  do
1792  {
1793  currReader = &rgReaderStates[j];
1794 
1795  /* Ignore for IGNORED readers */
1796  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1797  {
1798  const char *readerName;
1799  int i;
1800 
1801  /* Looks for correct readernames */
1802  readerName = currReader->szReader;
1803  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1804  {
1805  if (strcmp(readerName, readerStates[i].readerName) == 0)
1806  break;
1807  }
1808 
1809  /* The requested reader name is not recognized */
1811  {
1812  /* PnP special reader? */
1813  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1814  {
1815  int k, newReaderCount = 0;
1816 
1817  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1818  if (readerStates[k].readerName[0] != '\0')
1819  newReaderCount++;
1820 
1821  if (newReaderCount != currentReaderCount)
1822  {
1823  Log1(PCSC_LOG_INFO, "Reader list changed");
1824  currentReaderCount = newReaderCount;
1825 
1826  currReader->dwEventState |= SCARD_STATE_CHANGED;
1827  dwBreakFlag = 1;
1828  }
1829  }
1830  else
1831  {
1832  currReader->dwEventState =
1834  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1835  {
1836  currReader->dwEventState |= SCARD_STATE_CHANGED;
1837  /*
1838  * Spec says use SCARD_STATE_IGNORE but a removed USB
1839  * reader with eventState fed into currentState will
1840  * be ignored forever
1841  */
1842  dwBreakFlag = 1;
1843  }
1844  }
1845  }
1846  else
1847  {
1848  uint32_t readerState;
1849 
1850  /* The reader has come back after being away */
1851  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1852  {
1853  currReader->dwEventState |= SCARD_STATE_CHANGED;
1854  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1855  Log0(PCSC_LOG_DEBUG);
1856  dwBreakFlag = 1;
1857  }
1858 
1859  /* Set the reader status structure */
1860  rContext = &readerStates[i];
1861 
1862  /* Now we check all the Reader States */
1863  readerState = rContext->readerState;
1864 
1865  /* only if current state has an non null event counter */
1866  if (currReader->dwCurrentState & 0xFFFF0000)
1867  {
1868  unsigned int currentCounter;
1869 
1870  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1871 
1872  /* has the event counter changed since the last call? */
1873  if (rContext->eventCounter != currentCounter)
1874  {
1875  currReader->dwEventState |= SCARD_STATE_CHANGED;
1876  Log0(PCSC_LOG_DEBUG);
1877  dwBreakFlag = 1;
1878  }
1879  }
1880 
1881  /* add an event counter in the upper word of dwEventState */
1882  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1883  | (rContext->eventCounter << 16));
1884 
1885  /* Check if the reader is in the correct state */
1886  if (readerState & SCARD_UNKNOWN)
1887  {
1888  /* reader is in bad state */
1889  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1890  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1891  {
1892  /* App thinks reader is in good state and it is not */
1893  currReader->dwEventState |= SCARD_STATE_CHANGED;
1894  Log0(PCSC_LOG_DEBUG);
1895  dwBreakFlag = 1;
1896  }
1897  }
1898  else
1899  {
1900  /* App thinks reader in bad state but it is not */
1901  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1902  {
1903  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1904  currReader->dwEventState |= SCARD_STATE_CHANGED;
1905  Log0(PCSC_LOG_DEBUG);
1906  dwBreakFlag = 1;
1907  }
1908  }
1909 
1910  /* Check for card presence in the reader */
1911  if (readerState & SCARD_PRESENT)
1912  {
1913  /* card present but not yet powered up */
1914  if (0 == rContext->cardAtrLength)
1915  /* Allow the status thread to convey information */
1917 
1918  currReader->cbAtr = rContext->cardAtrLength;
1919  memcpy(currReader->rgbAtr, rContext->cardAtr,
1920  currReader->cbAtr);
1921  }
1922  else
1923  currReader->cbAtr = 0;
1924 
1925  /* Card is now absent */
1926  if (readerState & SCARD_ABSENT)
1927  {
1928  currReader->dwEventState |= SCARD_STATE_EMPTY;
1929  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1930  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1931  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1932  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1933  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1934  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1935  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1936  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1937 
1938  /* After present the rest are assumed */
1939  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1940  {
1941  currReader->dwEventState |= SCARD_STATE_CHANGED;
1942  Log0(PCSC_LOG_DEBUG);
1943  dwBreakFlag = 1;
1944  }
1945  }
1946  /* Card is now present */
1947  else if (readerState & SCARD_PRESENT)
1948  {
1949  currReader->dwEventState |= SCARD_STATE_PRESENT;
1950  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1951  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1952  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1953  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1954  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1955  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1956 
1957  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1958  {
1959  currReader->dwEventState |= SCARD_STATE_CHANGED;
1960  Log0(PCSC_LOG_DEBUG);
1961  dwBreakFlag = 1;
1962  }
1963 
1964  if (readerState & SCARD_SWALLOWED)
1965  {
1966  currReader->dwEventState |= SCARD_STATE_MUTE;
1967  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1968  {
1969  currReader->dwEventState |= SCARD_STATE_CHANGED;
1970  Log0(PCSC_LOG_DEBUG);
1971  dwBreakFlag = 1;
1972  }
1973  }
1974  else
1975  {
1976  /* App thinks card is mute but it is not */
1977  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1978  {
1979  currReader->dwEventState |= SCARD_STATE_CHANGED;
1980  Log0(PCSC_LOG_DEBUG);
1981  dwBreakFlag = 1;
1982  }
1983  }
1984  }
1985 
1986  /* Now figure out sharing modes */
1988  {
1989  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1990  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1991  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1992  {
1993  currReader->dwEventState |= SCARD_STATE_CHANGED;
1994  Log0(PCSC_LOG_DEBUG);
1995  dwBreakFlag = 1;
1996  }
1997  }
1998  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
1999  {
2000  /* A card must be inserted for it to be INUSE */
2001  if (readerState & SCARD_PRESENT)
2002  {
2003  currReader->dwEventState |= SCARD_STATE_INUSE;
2004  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2005  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2006  {
2007  currReader->dwEventState |= SCARD_STATE_CHANGED;
2008  Log0(PCSC_LOG_DEBUG);
2009  dwBreakFlag = 1;
2010  }
2011  }
2012  }
2013  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2014  {
2015  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2016  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2017 
2018  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2019  {
2020  currReader->dwEventState |= SCARD_STATE_CHANGED;
2021  Log0(PCSC_LOG_DEBUG);
2022  dwBreakFlag = 1;
2023  }
2024  else if (currReader-> dwCurrentState
2026  {
2027  currReader->dwEventState |= SCARD_STATE_CHANGED;
2028  Log0(PCSC_LOG_DEBUG);
2029  dwBreakFlag = 1;
2030  }
2031  }
2032 
2033  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2034  {
2035  /*
2036  * Break out of the while .. loop and return status
2037  * once all the status's for all readers is met
2038  */
2039  currReader->dwEventState |= SCARD_STATE_CHANGED;
2040  Log0(PCSC_LOG_DEBUG);
2041  dwBreakFlag = 1;
2042  }
2043  } /* End of SCARD_STATE_UNKNOWN */
2044  } /* End of SCARD_STATE_IGNORE */
2045 
2046  /* Counter and resetter */
2047  j++;
2048  if (j == cReaders)
2049  {
2050  /* go back to the first reader */
2051  j = 0;
2052 
2053  /* Declare all the break conditions */
2054 
2055  /* Break if UNAWARE is set and all readers have been checked */
2056  if (dwBreakFlag == 1)
2057  break;
2058 
2059  /* Only sleep once for each cycle of reader checks. */
2060  {
2061  struct wait_reader_state_change waitStatusStruct = {0};
2062  struct timeval before, after;
2063 
2064  gettimeofday(&before, NULL);
2065 
2066  waitStatusStruct.rv = SCARD_S_SUCCESS;
2067 
2068  /* another thread can do SCardCancel() */
2069  currentContextMap->cancellable = TRUE;
2070 
2071  /*
2072  * Read a message from the server
2073  */
2075  &waitStatusStruct, sizeof(waitStatusStruct),
2076  currentContextMap->dwClientID, dwTime);
2077 
2078  /* SCardCancel() will return immediatly with success
2079  * because something changed on the daemon side. */
2080  currentContextMap->cancellable = FALSE;
2081 
2082  /* timeout */
2083  if (SCARD_E_TIMEOUT == rv)
2084  {
2085  /* ask server to remove us from the event list */
2086  rv = unregisterFromEvents(currentContextMap);
2087  }
2088 
2089  if (rv != SCARD_S_SUCCESS)
2090  goto end;
2091 
2092  /* an event occurs or SCardCancel() was called */
2093  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2094  {
2095  rv = waitStatusStruct.rv;
2096  goto end;
2097  }
2098 
2099  /* synchronize reader states with daemon */
2100  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2101  if (rv != SCARD_S_SUCCESS)
2102  goto end;
2103 
2104  if (INFINITE != dwTimeout)
2105  {
2106  long int diff;
2107 
2108  gettimeofday(&after, NULL);
2109  diff = time_sub(&after, &before);
2110  dwTime -= diff/1000;
2111  }
2112  }
2113 
2114  if (dwTimeout != INFINITE)
2115  {
2116  /* If time is greater than timeout and all readers have been
2117  * checked
2118  */
2119  if (dwTime <= 0)
2120  {
2121  rv = SCARD_E_TIMEOUT;
2122  goto end;
2123  }
2124  }
2125  }
2126  }
2127  while (1);
2128 
2129 end:
2130  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2131 
2132  (void)unregisterFromEvents(currentContextMap);
2133 
2134  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2135 
2136 error:
2137  PROFILE_END(rv)
2138 #ifdef DO_TRACE
2139  for (j=0; j<cReaders; j++)
2140  {
2141  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2142  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2143  }
2144 #endif
2145 
2146  return rv;
2147 }
2148 
2199 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2200  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2201  LPDWORD lpBytesReturned)
2202 {
2203  LONG rv;
2204  struct control_struct scControlStruct;
2205  SCONTEXTMAP * currentContextMap;
2206  CHANNEL_MAP * pChannelMap;
2207 
2208  PROFILE_START
2209 
2210  /* 0 bytes received by default */
2211  if (NULL != lpBytesReturned)
2212  *lpBytesReturned = 0;
2213 
2214  /*
2215  * Make sure this handle has been opened
2216  */
2217  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2218  &pChannelMap);
2219  if (rv == -1)
2220  {
2221  PROFILE_END(SCARD_E_INVALID_HANDLE)
2222  return SCARD_E_INVALID_HANDLE;
2223  }
2224 
2225  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2226  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2227  {
2229  goto end;
2230  }
2231 
2232  scControlStruct.hCard = hCard;
2233  scControlStruct.dwControlCode = dwControlCode;
2234  scControlStruct.cbSendLength = cbSendLength;
2235  scControlStruct.cbRecvLength = cbRecvLength;
2236  scControlStruct.dwBytesReturned = 0;
2237  scControlStruct.rv = 0;
2238 
2239  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2240  sizeof(scControlStruct), &scControlStruct);
2241 
2242  if (rv != SCARD_S_SUCCESS)
2243  goto end;
2244 
2245  /* write the sent buffer */
2246  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2247  currentContextMap->dwClientID);
2248 
2249  if (rv != SCARD_S_SUCCESS)
2250  goto end;
2251 
2252  /*
2253  * Read a message from the server
2254  */
2255  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2256  currentContextMap->dwClientID);
2257 
2258  if (rv != SCARD_S_SUCCESS)
2259  goto end;
2260 
2261  if (SCARD_S_SUCCESS == scControlStruct.rv)
2262  {
2263  /* read the received buffer */
2264  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2265  currentContextMap->dwClientID);
2266 
2267  if (rv != SCARD_S_SUCCESS)
2268  goto end;
2269 
2270  }
2271 
2272  if (NULL != lpBytesReturned)
2273  *lpBytesReturned = scControlStruct.dwBytesReturned;
2274 
2275  rv = scControlStruct.rv;
2276 
2277 end:
2278  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2279 
2280  PROFILE_END(rv)
2281 
2282  return rv;
2283 }
2284 
2400 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2401  LPDWORD pcbAttrLen)
2402 {
2403  LONG ret;
2404  unsigned char *buf = NULL;
2405 
2406  PROFILE_START
2407 
2408  if (NULL == pcbAttrLen)
2409  {
2411  goto end;
2412  }
2413 
2414  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2415  {
2416  if (NULL == pbAttr)
2418 
2419  *pcbAttrLen = MAX_BUFFER_SIZE;
2420  buf = malloc(*pcbAttrLen);
2421  if (NULL == buf)
2422  {
2423  ret = SCARD_E_NO_MEMORY;
2424  goto end;
2425  }
2426 
2427  *(unsigned char **)pbAttr = buf;
2428  }
2429  else
2430  {
2431  buf = pbAttr;
2432 
2433  /* if only get the length */
2434  if (NULL == pbAttr)
2435  /* use a reasonable size */
2436  *pcbAttrLen = MAX_BUFFER_SIZE;
2437  }
2438 
2439  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2440  pcbAttrLen);
2441 
2442 end:
2443  PROFILE_END(ret)
2444 
2445  return ret;
2446 }
2447 
2483 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2484  DWORD cbAttrLen)
2485 {
2486  LONG ret;
2487 
2488  PROFILE_START
2489 
2490  if (NULL == pbAttr || 0 == cbAttrLen)
2492 
2493  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2494  &cbAttrLen);
2495 
2496  PROFILE_END(ret)
2497 
2498  return ret;
2499 }
2500 
2501 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2502  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2503 {
2504  LONG rv;
2505  struct getset_struct scGetSetStruct;
2506  SCONTEXTMAP * currentContextMap;
2507  CHANNEL_MAP * pChannelMap;
2508 
2509  /*
2510  * Make sure this handle has been opened
2511  */
2512  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2513  &pChannelMap);
2514  if (rv == -1)
2515  return SCARD_E_INVALID_HANDLE;
2516 
2517  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2518  {
2520  goto end;
2521  }
2522 
2523  scGetSetStruct.hCard = hCard;
2524  scGetSetStruct.dwAttrId = dwAttrId;
2525  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2526  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2527  if (SCARD_SET_ATTRIB == command)
2528  {
2529  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2530  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2531  }
2532  else
2533  /* we can get up to the communication buffer size */
2534  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2535 
2536  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2537  sizeof(scGetSetStruct), &scGetSetStruct);
2538 
2539  if (rv != SCARD_S_SUCCESS)
2540  goto end;
2541 
2542  /*
2543  * Read a message from the server
2544  */
2545  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2546  currentContextMap->dwClientID);
2547 
2548  if (rv != SCARD_S_SUCCESS)
2549  goto end;
2550 
2551  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2552  {
2553  /*
2554  * Copy and zero it so any secret information is not leaked
2555  */
2556  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2557  {
2558  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2559  * buffer overflow in the memcpy() bellow */
2560  DWORD correct_value = scGetSetStruct.cbAttrLen;
2561  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2562  *pcbAttrLen = correct_value;
2563 
2564  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2565  }
2566  else
2567  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2568 
2569  if (pbAttr)
2570  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2571 
2572  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2573  }
2574  rv = scGetSetStruct.rv;
2575 
2576 end:
2577  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2578 
2579  return rv;
2580 }
2581 
2640 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2641  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2642  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2643  LPDWORD pcbRecvLength)
2644 {
2645  LONG rv;
2646  SCONTEXTMAP * currentContextMap;
2647  CHANNEL_MAP * pChannelMap;
2648  struct transmit_struct scTransmitStruct;
2649 
2650  PROFILE_START
2651 
2652  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2653  pcbRecvLength == NULL || pioSendPci == NULL)
2655 
2656  /* Retry loop for blocking behaviour */
2657 retry:
2658 
2659  /*
2660  * Make sure this handle has been opened
2661  */
2662  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2663  &pChannelMap);
2664  if (rv == -1)
2665  {
2666  *pcbRecvLength = 0;
2667  PROFILE_END(SCARD_E_INVALID_HANDLE)
2668  return SCARD_E_INVALID_HANDLE;
2669  }
2670 
2671  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2672  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2673  {
2675  goto end;
2676  }
2677 
2678  scTransmitStruct.hCard = hCard;
2679  scTransmitStruct.cbSendLength = cbSendLength;
2680  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2681  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2682  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2683  scTransmitStruct.rv = SCARD_S_SUCCESS;
2684 
2685  if (pioRecvPci)
2686  {
2687  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2688  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2689  }
2690  else
2691  {
2692  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2693  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2694  }
2695 
2696  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2697  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2698 
2699  if (rv != SCARD_S_SUCCESS)
2700  goto end;
2701 
2702  /* write the sent buffer */
2703  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2704  currentContextMap->dwClientID);
2705 
2706  if (rv != SCARD_S_SUCCESS)
2707  goto end;
2708 
2709  /*
2710  * Read a message from the server
2711  */
2712  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2713  currentContextMap->dwClientID);
2714 
2715  if (rv != SCARD_S_SUCCESS)
2716  goto end;
2717 
2718  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2719  {
2720  /* read the received buffer */
2721  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2722  currentContextMap->dwClientID);
2723 
2724  if (rv != SCARD_S_SUCCESS)
2725  goto end;
2726 
2727  if (pioRecvPci)
2728  {
2729  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2730  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2731  }
2732  }
2733 
2734  rv = scTransmitStruct.rv;
2735 
2736  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2737  {
2738  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2740  goto retry;
2741  }
2742 
2743  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2744 
2745 end:
2746  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2747 
2748  PROFILE_END(rv)
2749 
2750  return rv;
2751 }
2752 
2815 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2816  LPSTR mszReaders, LPDWORD pcchReaders)
2817 {
2818  DWORD dwReadersLen = 0;
2819  int i;
2820  SCONTEXTMAP * currentContextMap;
2821  LONG rv = SCARD_S_SUCCESS;
2822  char *buf = NULL;
2823 
2824  (void)mszGroups;
2825  PROFILE_START
2826  API_TRACE_IN("%ld", hContext)
2827 
2828  /*
2829  * Check for NULL parameters
2830  */
2831  if (pcchReaders == NULL)
2833 
2834  /*
2835  * Make sure this context has been opened
2836  */
2837  currentContextMap = SCardGetAndLockContext(hContext);
2838  if (NULL == currentContextMap)
2839  {
2840  PROFILE_END(SCARD_E_INVALID_HANDLE)
2841  return SCARD_E_INVALID_HANDLE;
2842  }
2843 
2844  /* synchronize reader states with daemon */
2845  rv = getReaderStates(currentContextMap);
2846  if (rv != SCARD_S_SUCCESS)
2847  goto end;
2848 
2849  dwReadersLen = 0;
2850  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2851  if (readerStates[i].readerName[0] != '\0')
2852  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2853 
2854  /* for the last NULL byte */
2855  dwReadersLen += 1;
2856 
2857  if (1 == dwReadersLen)
2858  {
2860  goto end;
2861  }
2862 
2863  if (SCARD_AUTOALLOCATE == *pcchReaders)
2864  {
2865  if (NULL == mszReaders)
2866  {
2868  goto end;
2869  }
2870  buf = malloc(dwReadersLen);
2871  if (NULL == buf)
2872  {
2873  rv = SCARD_E_NO_MEMORY;
2874  goto end;
2875  }
2876  *(char **)mszReaders = buf;
2877  }
2878  else
2879  {
2880  buf = mszReaders;
2881 
2882  /* not enough place to store the reader names */
2883  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2884  {
2886  goto end;
2887  }
2888  }
2889 
2890  if (mszReaders == NULL) /* text array not allocated */
2891  goto end;
2892 
2893  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2894  {
2895  if (readerStates[i].readerName[0] != '\0')
2896  {
2897  /*
2898  * Build the multi-string
2899  */
2900  strcpy(buf, readerStates[i].readerName);
2901  buf += strlen(readerStates[i].readerName)+1;
2902  }
2903  }
2904  *buf = '\0'; /* Add the last null */
2905 
2906 end:
2907  /* set the reader names length */
2908  *pcchReaders = dwReadersLen;
2909 
2910  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2911 
2912  PROFILE_END(rv)
2913  API_TRACE_OUT("%d", *pcchReaders)
2914 
2915  return rv;
2916 }
2917 
2931 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2932 {
2933  LONG rv = SCARD_S_SUCCESS;
2934 
2935  PROFILE_START
2936 
2937  /*
2938  * Make sure this context has been opened
2939  */
2940  if (! SCardGetContextValidity(hContext))
2941  return SCARD_E_INVALID_HANDLE;
2942 
2943  free((void *)pvMem);
2944 
2945  PROFILE_END(rv)
2946 
2947  return rv;
2948 }
2949 
3001 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3002  LPDWORD pcchGroups)
3003 {
3004  LONG rv = SCARD_S_SUCCESS;
3005  SCONTEXTMAP * currentContextMap;
3006  char *buf = NULL;
3007 
3008  PROFILE_START
3009 
3010  /* Multi-string with two trailing \0 */
3011  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3012  const unsigned int dwGroups = sizeof(ReaderGroup);
3013 
3014  /*
3015  * Make sure this context has been opened
3016  */
3017  currentContextMap = SCardGetAndLockContext(hContext);
3018  if (NULL == currentContextMap)
3019  return SCARD_E_INVALID_HANDLE;
3020 
3021  if (SCARD_AUTOALLOCATE == *pcchGroups)
3022  {
3023  if (NULL == mszGroups)
3024  {
3026  goto end;
3027  }
3028  buf = malloc(dwGroups);
3029  if (NULL == buf)
3030  {
3031  rv = SCARD_E_NO_MEMORY;
3032  goto end;
3033  }
3034  *(char **)mszGroups = buf;
3035  }
3036  else
3037  {
3038  buf = mszGroups;
3039 
3040  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3041  {
3043  goto end;
3044  }
3045  }
3046 
3047  if (buf)
3048  memcpy(buf, ReaderGroup, dwGroups);
3049 
3050 end:
3051  *pcchGroups = dwGroups;
3052 
3053  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3054 
3055  PROFILE_END(rv)
3056 
3057  return rv;
3058 }
3059 
3092 {
3093  SCONTEXTMAP * currentContextMap;
3094  LONG rv = SCARD_S_SUCCESS;
3095  uint32_t dwClientID = 0;
3096  struct cancel_struct scCancelStruct;
3097  char cancellable;
3098 
3099  PROFILE_START
3100  API_TRACE_IN("%ld", hContext)
3101 
3102  /*
3103  * Make sure this context has been opened
3104  */
3105  (void)SCardLockThread();
3106  currentContextMap = SCardGetContextTH(hContext);
3107 
3108  if (NULL == currentContextMap)
3109  {
3110  (void)SCardUnlockThread();
3112  goto error;
3113  }
3114  cancellable = currentContextMap->cancellable;
3115  (void)SCardUnlockThread();
3116 
3117  if (! cancellable)
3118  {
3119  rv = SCARD_S_SUCCESS;
3120  goto error;
3121  }
3122 
3123  /* create a new connection to the server */
3124  if (ClientSetupSession(&dwClientID) != 0)
3125  {
3126  rv = SCARD_E_NO_SERVICE;
3127  goto error;
3128  }
3129 
3130  scCancelStruct.hContext = hContext;
3131  scCancelStruct.rv = SCARD_S_SUCCESS;
3132 
3133  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3134  sizeof(scCancelStruct), (void *) &scCancelStruct);
3135 
3136  if (rv != SCARD_S_SUCCESS)
3137  goto end;
3138 
3139  /*
3140  * Read a message from the server
3141  */
3142  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3143 
3144  if (rv != SCARD_S_SUCCESS)
3145  goto end;
3146 
3147  rv = scCancelStruct.rv;
3148 end:
3149  ClientCloseSession(dwClientID);
3150 
3151 error:
3152  PROFILE_END(rv)
3153  API_TRACE_OUT("")
3154 
3155  return rv;
3156 }
3157 
3182 {
3183  LONG rv;
3184 
3185  PROFILE_START
3186  API_TRACE_IN("%ld", hContext)
3187 
3188  rv = SCARD_S_SUCCESS;
3189 
3190  /*
3191  * Make sure this context has been opened
3192  */
3193  if (! SCardGetContextValidity(hContext))
3195 
3196  PROFILE_END(rv)
3197  API_TRACE_OUT("")
3198 
3199  return rv;
3200 }
3201 
3218 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3219 {
3220  int lrv;
3221  SCONTEXTMAP * newContextMap;
3222 
3223  newContextMap = malloc(sizeof(SCONTEXTMAP));
3224  if (NULL == newContextMap)
3225  return SCARD_E_NO_MEMORY;
3226 
3227  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3228  newContextMap->hContext = hContext;
3229  newContextMap->dwClientID = dwClientID;
3230  newContextMap->cancellable = FALSE;
3231 
3232  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3233 
3234  lrv = list_init(&newContextMap->channelMapList);
3235  if (lrv < 0)
3236  {
3237  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3238  goto error;
3239  }
3240 
3241  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3242  CHANNEL_MAP_seeker);
3243  if (lrv <0)
3244  {
3245  Log2(PCSC_LOG_CRITICAL,
3246  "list_attributes_seeker failed with return value: %d", lrv);
3247  list_destroy(&newContextMap->channelMapList);
3248  goto error;
3249  }
3250 
3251  lrv = list_append(&contextMapList, newContextMap);
3252  if (lrv < 0)
3253  {
3254  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3255  lrv);
3256  list_destroy(&newContextMap->channelMapList);
3257  goto error;
3258  }
3259 
3260  return SCARD_S_SUCCESS;
3261 
3262 error:
3263 
3264  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3265  free(newContextMap);
3266 
3267  return SCARD_E_NO_MEMORY;
3268 }
3269 
3287 {
3288  SCONTEXTMAP * currentContextMap;
3289 
3290  SCardLockThread();
3291  currentContextMap = SCardGetContextTH(hContext);
3292 
3293  /* lock the context (if available) */
3294  if (NULL != currentContextMap)
3295  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3296 
3298 
3299  return currentContextMap;
3300 }
3301 
3315 {
3316  return list_seek(&contextMapList, &hContext);
3317 }
3318 
3328 static void SCardRemoveContext(SCARDCONTEXT hContext)
3329 {
3330  SCONTEXTMAP * currentContextMap;
3331  currentContextMap = SCardGetContextTH(hContext);
3332 
3333  if (NULL != currentContextMap)
3334  SCardCleanContext(currentContextMap);
3335 }
3336 
3337 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3338 {
3339  int list_index, lrv;
3340  int listSize;
3341  CHANNEL_MAP * currentChannelMap;
3342 
3343  targetContextMap->hContext = 0;
3344  ClientCloseSession(targetContextMap->dwClientID);
3345  targetContextMap->dwClientID = 0;
3346  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3347 
3348  listSize = list_size(&targetContextMap->channelMapList);
3349  for (list_index = 0; list_index < listSize; list_index++)
3350  {
3351  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3352  list_index);
3353  if (NULL == currentChannelMap)
3354  {
3355  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3356  list_index);
3357  continue;
3358  }
3359  else
3360  {
3361  free(currentChannelMap->readerName);
3362  free(currentChannelMap);
3363  }
3364 
3365  }
3366  list_destroy(&targetContextMap->channelMapList);
3367 
3368  lrv = list_delete(&contextMapList, targetContextMap);
3369  if (lrv < 0)
3370  {
3371  Log2(PCSC_LOG_CRITICAL,
3372  "list_delete failed with return value: %d", lrv);
3373  }
3374 
3375  free(targetContextMap);
3376 
3377  return;
3378 }
3379 
3380 /*
3381  * Functions for managing hCard values returned from SCardConnect.
3382  */
3383 
3384 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3385  LPCSTR readerName)
3386 {
3387  CHANNEL_MAP * newChannelMap;
3388  int lrv = -1;
3389 
3390  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3391  if (NULL == newChannelMap)
3392  return SCARD_E_NO_MEMORY;
3393 
3394  newChannelMap->hCard = hCard;
3395  newChannelMap->readerName = strdup(readerName);
3396 
3397  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3398  if (lrv < 0)
3399  {
3400  free(newChannelMap->readerName);
3401  free(newChannelMap);
3402  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3403  lrv);
3404  return SCARD_E_NO_MEMORY;
3405  }
3406 
3407  return SCARD_S_SUCCESS;
3408 }
3409 
3410 static void SCardRemoveHandle(SCARDHANDLE hCard)
3411 {
3412  SCONTEXTMAP * currentContextMap;
3413  CHANNEL_MAP * currentChannelMap;
3414  int lrv;
3415  LONG rv;
3416 
3417  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3418  &currentChannelMap);
3419  if (rv == -1)
3420  return;
3421 
3422  free(currentChannelMap->readerName);
3423 
3424  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3425  if (lrv < 0)
3426  {
3427  Log2(PCSC_LOG_CRITICAL,
3428  "list_delete failed with return value: %d", lrv);
3429  }
3430 
3431  free(currentChannelMap);
3432 
3433  return;
3434 }
3435 
3436 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3437  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3438 {
3439  LONG rv;
3440 
3441  if (0 == hCard)
3442  return -1;
3443 
3444  SCardLockThread();
3445  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3446  targetChannelMap);
3447 
3448  if (SCARD_S_SUCCESS == rv)
3449  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3450 
3452 
3453  return rv;
3454 }
3455 
3456 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3457  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3458 {
3459  int listSize;
3460  int list_index;
3461  SCONTEXTMAP * currentContextMap;
3462  CHANNEL_MAP * currentChannelMap;
3463 
3464  /* Best to get the caller a crash early if we fail unsafely */
3465  *targetContextMap = NULL;
3466  *targetChannelMap = NULL;
3467 
3468  listSize = list_size(&contextMapList);
3469 
3470  for (list_index = 0; list_index < listSize; list_index++)
3471  {
3472  currentContextMap = list_get_at(&contextMapList, list_index);
3473  if (currentContextMap == NULL)
3474  {
3475  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3476  list_index);
3477  continue;
3478  }
3479  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3480  &hCard);
3481  if (currentChannelMap != NULL)
3482  {
3483  *targetContextMap = currentContextMap;
3484  *targetChannelMap = currentChannelMap;
3485  return SCARD_S_SUCCESS;
3486  }
3487  }
3488 
3489  return -1;
3490 }
3491 
3500 {
3501  LONG rv;
3502  struct stat statBuffer;
3503  char *socketName;
3504 
3505  socketName = getSocketName();
3506  rv = stat(socketName, &statBuffer);
3507 
3508  if (rv != 0)
3509  {
3510  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3511  socketName, strerror(errno));
3512  return SCARD_E_NO_SERVICE;
3513  }
3514 
3515  return SCARD_S_SUCCESS;
3516 }
3517 
3518 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3519 {
3520  int32_t dwClientID = currentContextMap->dwClientID;
3521  LONG rv;
3522 
3523  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3524  if (rv != SCARD_S_SUCCESS)
3525  return rv;
3526 
3527  /* Read a message from the server */
3528  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3529  if (rv != SCARD_S_SUCCESS)
3530  return rv;
3531 
3532  return SCARD_S_SUCCESS;
3533 }
3534 
3535 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3536 {
3537  int32_t dwClientID = currentContextMap->dwClientID;
3538  LONG rv;
3539 
3540  /* Get current reader states from server and register on event list */
3542  0, NULL);
3543  if (rv != SCARD_S_SUCCESS)
3544  return rv;
3545 
3546  /* Read a message from the server */
3547  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3548  return rv;
3549 }
3550 
3551 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3552 {
3553  int32_t dwClientID = currentContextMap->dwClientID;
3554  LONG rv;
3555  struct wait_reader_state_change waitStatusStruct = {0};
3556 
3557  /* ask server to remove us from the event list */
3559  dwClientID, 0, NULL);
3560  if (rv != SCARD_S_SUCCESS)
3561  return rv;
3562 
3563  /* This message can be the response to
3564  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3565  * cancel notification.
3566  * The server side ensures, that no more messages will be sent to
3567  * the client. */
3568 
3569  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3570  dwClientID);
3571  if (rv != SCARD_S_SUCCESS)
3572  return rv;
3573 
3574  /* if we received a cancel event the return value will be set
3575  * accordingly */
3576  rv = waitStatusStruct.rv;
3577 
3578  return rv;
3579 }
3580 
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:56
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
wait for a reader state change
Definition: winscard_msg.h:94
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:73
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
get the client/server protocol version
Definition: winscard_msg.h:92
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:172
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
static short isExecuted
Make sure the initialization code is executed only once.
used by SCardEstablishContext()
Definition: winscard_msg.h:76
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:318
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
used by SCardEndTransaction()
Definition: winscard_msg.h:83
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:53
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
This handles abstract system level calls.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
used by SCardConnect()
Definition: winscard_msg.h:79
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:47
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
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 SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:75
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
Represents an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
get the readers state
Definition: winscard_msg.h:93
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
static int SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not...
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:452
used by SCardReleaseContext()
Definition: winscard_msg.h:77
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:107
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:272
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context...
used by SCardReconnect()
Definition: winscard_msg.h:80
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 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:136
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:84
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
Represents an Application Context Channel.
This handles card insertion/removal events, updates ATR, protocol, and status information.
SCARDCONTEXT hContext
Application Context ID.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
char cancellable
We are in a cancellable call.
stop waiting for a reader state change
Definition: winscard_msg.h:95
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:55
int SYS_RandomInt(int, int)
Generate a pseudo random number.
Definition: sys_unix.c:95
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:117
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:49
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
used by SCardControl()
Definition: winscard_msg.h:85
This keeps a list of defines for pcsc-lite.
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:243
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:274
Protocol Control Information (PCI)
Definition: pcsclite.h:79
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...
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:57
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:48
used by SCardSetAttrib()
Definition: winscard_msg.h:91
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:354
used by SCardDisconnect()
Definition: winscard_msg.h:81
PCSC_API const char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:82
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:246
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:90
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
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.
pthread_mutex_t mMutex
Mutex for this context.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:52
used by SCardCancel()
Definition: winscard_msg.h:88
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:71
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:56
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
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().
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:86
This handles smart card reader communications.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:193
This handles debugging.
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:265
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275