pcsc-lite  1.8.24
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  /* if SCardCancel() has been used then the client is already
2133  * unregistered */
2134  if (SCARD_E_CANCELLED != rv)
2135  (void)unregisterFromEvents(currentContextMap);
2136 
2137  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2138 
2139 error:
2140  PROFILE_END(rv)
2141 #ifdef DO_TRACE
2142  for (j=0; j<cReaders; j++)
2143  {
2144  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2145  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2146  }
2147 #endif
2148 
2149  return rv;
2150 }
2151 
2202 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2203  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2204  LPDWORD lpBytesReturned)
2205 {
2206  LONG rv;
2207  struct control_struct scControlStruct;
2208  SCONTEXTMAP * currentContextMap;
2209  CHANNEL_MAP * pChannelMap;
2210 
2211  PROFILE_START
2212 
2213  /* 0 bytes received by default */
2214  if (NULL != lpBytesReturned)
2215  *lpBytesReturned = 0;
2216 
2217  /*
2218  * Make sure this handle has been opened
2219  */
2220  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2221  &pChannelMap);
2222  if (rv == -1)
2223  {
2224  PROFILE_END(SCARD_E_INVALID_HANDLE)
2225  return SCARD_E_INVALID_HANDLE;
2226  }
2227 
2228  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2229  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2230  {
2232  goto end;
2233  }
2234 
2235  scControlStruct.hCard = hCard;
2236  scControlStruct.dwControlCode = dwControlCode;
2237  scControlStruct.cbSendLength = cbSendLength;
2238  scControlStruct.cbRecvLength = cbRecvLength;
2239  scControlStruct.dwBytesReturned = 0;
2240  scControlStruct.rv = 0;
2241 
2242  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2243  sizeof(scControlStruct), &scControlStruct);
2244 
2245  if (rv != SCARD_S_SUCCESS)
2246  goto end;
2247 
2248  /* write the sent buffer */
2249  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2250  currentContextMap->dwClientID);
2251 
2252  if (rv != SCARD_S_SUCCESS)
2253  goto end;
2254 
2255  /*
2256  * Read a message from the server
2257  */
2258  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2259  currentContextMap->dwClientID);
2260 
2261  if (rv != SCARD_S_SUCCESS)
2262  goto end;
2263 
2264  if (SCARD_S_SUCCESS == scControlStruct.rv)
2265  {
2266  /* read the received buffer */
2267  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2268  currentContextMap->dwClientID);
2269 
2270  if (rv != SCARD_S_SUCCESS)
2271  goto end;
2272 
2273  }
2274 
2275  if (NULL != lpBytesReturned)
2276  *lpBytesReturned = scControlStruct.dwBytesReturned;
2277 
2278  rv = scControlStruct.rv;
2279 
2280 end:
2281  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2282 
2283  PROFILE_END(rv)
2284 
2285  return rv;
2286 }
2287 
2403 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2404  LPDWORD pcbAttrLen)
2405 {
2406  LONG ret;
2407  unsigned char *buf = NULL;
2408 
2409  PROFILE_START
2410 
2411  if (NULL == pcbAttrLen)
2412  {
2414  goto end;
2415  }
2416 
2417  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2418  {
2419  if (NULL == pbAttr)
2421 
2422  *pcbAttrLen = MAX_BUFFER_SIZE;
2423  buf = malloc(*pcbAttrLen);
2424  if (NULL == buf)
2425  {
2426  ret = SCARD_E_NO_MEMORY;
2427  goto end;
2428  }
2429 
2430  *(unsigned char **)pbAttr = buf;
2431  }
2432  else
2433  {
2434  buf = pbAttr;
2435 
2436  /* if only get the length */
2437  if (NULL == pbAttr)
2438  /* use a reasonable size */
2439  *pcbAttrLen = MAX_BUFFER_SIZE;
2440  }
2441 
2442  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2443  pcbAttrLen);
2444 
2445 end:
2446  PROFILE_END(ret)
2447 
2448  return ret;
2449 }
2450 
2486 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2487  DWORD cbAttrLen)
2488 {
2489  LONG ret;
2490 
2491  PROFILE_START
2492 
2493  if (NULL == pbAttr || 0 == cbAttrLen)
2495 
2496  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2497  &cbAttrLen);
2498 
2499  PROFILE_END(ret)
2500 
2501  return ret;
2502 }
2503 
2504 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2505  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2506 {
2507  LONG rv;
2508  struct getset_struct scGetSetStruct;
2509  SCONTEXTMAP * currentContextMap;
2510  CHANNEL_MAP * pChannelMap;
2511 
2512  /*
2513  * Make sure this handle has been opened
2514  */
2515  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2516  &pChannelMap);
2517  if (rv == -1)
2518  return SCARD_E_INVALID_HANDLE;
2519 
2520  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2521  {
2523  goto end;
2524  }
2525 
2526  scGetSetStruct.hCard = hCard;
2527  scGetSetStruct.dwAttrId = dwAttrId;
2528  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2529  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2530  if (SCARD_SET_ATTRIB == command)
2531  {
2532  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2533  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2534  }
2535  else
2536  /* we can get up to the communication buffer size */
2537  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2538 
2539  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2540  sizeof(scGetSetStruct), &scGetSetStruct);
2541 
2542  if (rv != SCARD_S_SUCCESS)
2543  goto end;
2544 
2545  /*
2546  * Read a message from the server
2547  */
2548  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2549  currentContextMap->dwClientID);
2550 
2551  if (rv != SCARD_S_SUCCESS)
2552  goto end;
2553 
2554  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2555  {
2556  /*
2557  * Copy and zero it so any secret information is not leaked
2558  */
2559  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2560  {
2561  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2562  * buffer overflow in the memcpy() bellow */
2563  DWORD correct_value = scGetSetStruct.cbAttrLen;
2564  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2565  *pcbAttrLen = correct_value;
2566 
2567  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2568  }
2569  else
2570  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2571 
2572  if (pbAttr)
2573  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2574 
2575  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2576  }
2577  rv = scGetSetStruct.rv;
2578 
2579 end:
2580  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2581 
2582  return rv;
2583 }
2584 
2643 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2644  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2645  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2646  LPDWORD pcbRecvLength)
2647 {
2648  LONG rv;
2649  SCONTEXTMAP * currentContextMap;
2650  CHANNEL_MAP * pChannelMap;
2651  struct transmit_struct scTransmitStruct;
2652 
2653  PROFILE_START
2654 
2655  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2656  pcbRecvLength == NULL || pioSendPci == NULL)
2658 
2659  /* Retry loop for blocking behaviour */
2660 retry:
2661 
2662  /*
2663  * Make sure this handle has been opened
2664  */
2665  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2666  &pChannelMap);
2667  if (rv == -1)
2668  {
2669  *pcbRecvLength = 0;
2670  PROFILE_END(SCARD_E_INVALID_HANDLE)
2671  return SCARD_E_INVALID_HANDLE;
2672  }
2673 
2674  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2675  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2676  {
2678  goto end;
2679  }
2680 
2681  scTransmitStruct.hCard = hCard;
2682  scTransmitStruct.cbSendLength = cbSendLength;
2683  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2684  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2685  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2686  scTransmitStruct.rv = SCARD_S_SUCCESS;
2687 
2688  if (pioRecvPci)
2689  {
2690  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2691  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2692  }
2693  else
2694  {
2695  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2696  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2697  }
2698 
2699  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2700  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2701 
2702  if (rv != SCARD_S_SUCCESS)
2703  goto end;
2704 
2705  /* write the sent buffer */
2706  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2707  currentContextMap->dwClientID);
2708 
2709  if (rv != SCARD_S_SUCCESS)
2710  goto end;
2711 
2712  /*
2713  * Read a message from the server
2714  */
2715  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2716  currentContextMap->dwClientID);
2717 
2718  if (rv != SCARD_S_SUCCESS)
2719  goto end;
2720 
2721  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2722  {
2723  /* read the received buffer */
2724  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2725  currentContextMap->dwClientID);
2726 
2727  if (rv != SCARD_S_SUCCESS)
2728  goto end;
2729 
2730  if (pioRecvPci)
2731  {
2732  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2733  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2734  }
2735  }
2736 
2737  rv = scTransmitStruct.rv;
2738 
2739  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2740  {
2741  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2743  goto retry;
2744  }
2745 
2746  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2747 
2748 end:
2749  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2750 
2751  PROFILE_END(rv)
2752 
2753  return rv;
2754 }
2755 
2818 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2819  LPSTR mszReaders, LPDWORD pcchReaders)
2820 {
2821  DWORD dwReadersLen = 0;
2822  int i;
2823  SCONTEXTMAP * currentContextMap;
2824  LONG rv = SCARD_S_SUCCESS;
2825  char *buf = NULL;
2826 
2827  (void)mszGroups;
2828  PROFILE_START
2829  API_TRACE_IN("%ld", hContext)
2830 
2831  /*
2832  * Check for NULL parameters
2833  */
2834  if (pcchReaders == NULL)
2836 
2837  /*
2838  * Make sure this context has been opened
2839  */
2840  currentContextMap = SCardGetAndLockContext(hContext);
2841  if (NULL == currentContextMap)
2842  {
2843  PROFILE_END(SCARD_E_INVALID_HANDLE)
2844  return SCARD_E_INVALID_HANDLE;
2845  }
2846 
2847  /* synchronize reader states with daemon */
2848  rv = getReaderStates(currentContextMap);
2849  if (rv != SCARD_S_SUCCESS)
2850  goto end;
2851 
2852  dwReadersLen = 0;
2853  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2854  if (readerStates[i].readerName[0] != '\0')
2855  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2856 
2857  /* for the last NULL byte */
2858  dwReadersLen += 1;
2859 
2860  if (1 == dwReadersLen)
2861  {
2863  goto end;
2864  }
2865 
2866  if (SCARD_AUTOALLOCATE == *pcchReaders)
2867  {
2868  if (NULL == mszReaders)
2869  {
2871  goto end;
2872  }
2873  buf = malloc(dwReadersLen);
2874  if (NULL == buf)
2875  {
2876  rv = SCARD_E_NO_MEMORY;
2877  goto end;
2878  }
2879  *(char **)mszReaders = buf;
2880  }
2881  else
2882  {
2883  buf = mszReaders;
2884 
2885  /* not enough place to store the reader names */
2886  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2887  {
2889  goto end;
2890  }
2891  }
2892 
2893  if (mszReaders == NULL) /* text array not allocated */
2894  goto end;
2895 
2896  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2897  {
2898  if (readerStates[i].readerName[0] != '\0')
2899  {
2900  /*
2901  * Build the multi-string
2902  */
2903  strcpy(buf, readerStates[i].readerName);
2904  buf += strlen(readerStates[i].readerName)+1;
2905  }
2906  }
2907  *buf = '\0'; /* Add the last null */
2908 
2909 end:
2910  /* set the reader names length */
2911  *pcchReaders = dwReadersLen;
2912 
2913  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2914 
2915  PROFILE_END(rv)
2916  API_TRACE_OUT("%d", *pcchReaders)
2917 
2918  return rv;
2919 }
2920 
2934 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2935 {
2936  LONG rv = SCARD_S_SUCCESS;
2937 
2938  PROFILE_START
2939 
2940  /*
2941  * Make sure this context has been opened
2942  */
2943  if (! SCardGetContextValidity(hContext))
2944  return SCARD_E_INVALID_HANDLE;
2945 
2946  free((void *)pvMem);
2947 
2948  PROFILE_END(rv)
2949 
2950  return rv;
2951 }
2952 
3004 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3005  LPDWORD pcchGroups)
3006 {
3007  LONG rv = SCARD_S_SUCCESS;
3008  SCONTEXTMAP * currentContextMap;
3009  char *buf = NULL;
3010 
3011  PROFILE_START
3012 
3013  /* Multi-string with two trailing \0 */
3014  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3015  const unsigned int dwGroups = sizeof(ReaderGroup);
3016 
3017  /*
3018  * Make sure this context has been opened
3019  */
3020  currentContextMap = SCardGetAndLockContext(hContext);
3021  if (NULL == currentContextMap)
3022  return SCARD_E_INVALID_HANDLE;
3023 
3024  if (SCARD_AUTOALLOCATE == *pcchGroups)
3025  {
3026  if (NULL == mszGroups)
3027  {
3029  goto end;
3030  }
3031  buf = malloc(dwGroups);
3032  if (NULL == buf)
3033  {
3034  rv = SCARD_E_NO_MEMORY;
3035  goto end;
3036  }
3037  *(char **)mszGroups = buf;
3038  }
3039  else
3040  {
3041  buf = mszGroups;
3042 
3043  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3044  {
3046  goto end;
3047  }
3048  }
3049 
3050  if (buf)
3051  memcpy(buf, ReaderGroup, dwGroups);
3052 
3053 end:
3054  *pcchGroups = dwGroups;
3055 
3056  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3057 
3058  PROFILE_END(rv)
3059 
3060  return rv;
3061 }
3062 
3095 {
3096  SCONTEXTMAP * currentContextMap;
3097  LONG rv = SCARD_S_SUCCESS;
3098  uint32_t dwClientID = 0;
3099  struct cancel_struct scCancelStruct;
3100  char cancellable;
3101 
3102  PROFILE_START
3103  API_TRACE_IN("%ld", hContext)
3104 
3105  /*
3106  * Make sure this context has been opened
3107  */
3108  (void)SCardLockThread();
3109  currentContextMap = SCardGetContextTH(hContext);
3110 
3111  if (NULL == currentContextMap)
3112  {
3113  (void)SCardUnlockThread();
3115  goto error;
3116  }
3117  cancellable = currentContextMap->cancellable;
3118  (void)SCardUnlockThread();
3119 
3120  if (! cancellable)
3121  {
3122  rv = SCARD_S_SUCCESS;
3123  goto error;
3124  }
3125 
3126  /* create a new connection to the server */
3127  if (ClientSetupSession(&dwClientID) != 0)
3128  {
3129  rv = SCARD_E_NO_SERVICE;
3130  goto error;
3131  }
3132 
3133  scCancelStruct.hContext = hContext;
3134  scCancelStruct.rv = SCARD_S_SUCCESS;
3135 
3136  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3137  sizeof(scCancelStruct), (void *) &scCancelStruct);
3138 
3139  if (rv != SCARD_S_SUCCESS)
3140  goto end;
3141 
3142  /*
3143  * Read a message from the server
3144  */
3145  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3146 
3147  if (rv != SCARD_S_SUCCESS)
3148  goto end;
3149 
3150  rv = scCancelStruct.rv;
3151 end:
3152  ClientCloseSession(dwClientID);
3153 
3154 error:
3155  PROFILE_END(rv)
3156  API_TRACE_OUT("")
3157 
3158  return rv;
3159 }
3160 
3185 {
3186  LONG rv;
3187 
3188  PROFILE_START
3189  API_TRACE_IN("%ld", hContext)
3190 
3191  rv = SCARD_S_SUCCESS;
3192 
3193  /*
3194  * Make sure this context has been opened
3195  */
3196  if (! SCardGetContextValidity(hContext))
3198 
3199  PROFILE_END(rv)
3200  API_TRACE_OUT("")
3201 
3202  return rv;
3203 }
3204 
3221 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3222 {
3223  int lrv;
3224  SCONTEXTMAP * newContextMap;
3225 
3226  newContextMap = malloc(sizeof(SCONTEXTMAP));
3227  if (NULL == newContextMap)
3228  return SCARD_E_NO_MEMORY;
3229 
3230  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3231  newContextMap->hContext = hContext;
3232  newContextMap->dwClientID = dwClientID;
3233  newContextMap->cancellable = FALSE;
3234 
3235  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3236 
3237  lrv = list_init(&newContextMap->channelMapList);
3238  if (lrv < 0)
3239  {
3240  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3241  goto error;
3242  }
3243 
3244  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3245  CHANNEL_MAP_seeker);
3246  if (lrv <0)
3247  {
3248  Log2(PCSC_LOG_CRITICAL,
3249  "list_attributes_seeker failed with return value: %d", lrv);
3250  list_destroy(&newContextMap->channelMapList);
3251  goto error;
3252  }
3253 
3254  lrv = list_append(&contextMapList, newContextMap);
3255  if (lrv < 0)
3256  {
3257  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3258  lrv);
3259  list_destroy(&newContextMap->channelMapList);
3260  goto error;
3261  }
3262 
3263  return SCARD_S_SUCCESS;
3264 
3265 error:
3266 
3267  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3268  free(newContextMap);
3269 
3270  return SCARD_E_NO_MEMORY;
3271 }
3272 
3290 {
3291  SCONTEXTMAP * currentContextMap;
3292 
3293  SCardLockThread();
3294  currentContextMap = SCardGetContextTH(hContext);
3295 
3296  /* lock the context (if available) */
3297  if (NULL != currentContextMap)
3298  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3299 
3301 
3302  return currentContextMap;
3303 }
3304 
3318 {
3319  return list_seek(&contextMapList, &hContext);
3320 }
3321 
3331 static void SCardRemoveContext(SCARDCONTEXT hContext)
3332 {
3333  SCONTEXTMAP * currentContextMap;
3334  currentContextMap = SCardGetContextTH(hContext);
3335 
3336  if (NULL != currentContextMap)
3337  SCardCleanContext(currentContextMap);
3338 }
3339 
3340 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3341 {
3342  int list_index, lrv;
3343  int listSize;
3344  CHANNEL_MAP * currentChannelMap;
3345 
3346  targetContextMap->hContext = 0;
3347  ClientCloseSession(targetContextMap->dwClientID);
3348  targetContextMap->dwClientID = 0;
3349  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3350 
3351  listSize = list_size(&targetContextMap->channelMapList);
3352  for (list_index = 0; list_index < listSize; list_index++)
3353  {
3354  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3355  list_index);
3356  if (NULL == currentChannelMap)
3357  {
3358  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3359  list_index);
3360  continue;
3361  }
3362  else
3363  {
3364  free(currentChannelMap->readerName);
3365  free(currentChannelMap);
3366  }
3367 
3368  }
3369  list_destroy(&targetContextMap->channelMapList);
3370 
3371  lrv = list_delete(&contextMapList, targetContextMap);
3372  if (lrv < 0)
3373  {
3374  Log2(PCSC_LOG_CRITICAL,
3375  "list_delete failed with return value: %d", lrv);
3376  }
3377 
3378  free(targetContextMap);
3379 
3380  return;
3381 }
3382 
3383 /*
3384  * Functions for managing hCard values returned from SCardConnect.
3385  */
3386 
3387 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3388  LPCSTR readerName)
3389 {
3390  CHANNEL_MAP * newChannelMap;
3391  int lrv = -1;
3392 
3393  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3394  if (NULL == newChannelMap)
3395  return SCARD_E_NO_MEMORY;
3396 
3397  newChannelMap->hCard = hCard;
3398  newChannelMap->readerName = strdup(readerName);
3399 
3400  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3401  if (lrv < 0)
3402  {
3403  free(newChannelMap->readerName);
3404  free(newChannelMap);
3405  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3406  lrv);
3407  return SCARD_E_NO_MEMORY;
3408  }
3409 
3410  return SCARD_S_SUCCESS;
3411 }
3412 
3413 static void SCardRemoveHandle(SCARDHANDLE hCard)
3414 {
3415  SCONTEXTMAP * currentContextMap;
3416  CHANNEL_MAP * currentChannelMap;
3417  int lrv;
3418  LONG rv;
3419 
3420  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3421  &currentChannelMap);
3422  if (rv == -1)
3423  return;
3424 
3425  free(currentChannelMap->readerName);
3426 
3427  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3428  if (lrv < 0)
3429  {
3430  Log2(PCSC_LOG_CRITICAL,
3431  "list_delete failed with return value: %d", lrv);
3432  }
3433 
3434  free(currentChannelMap);
3435 
3436  return;
3437 }
3438 
3439 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3440  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3441 {
3442  LONG rv;
3443 
3444  if (0 == hCard)
3445  return -1;
3446 
3447  SCardLockThread();
3448  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3449  targetChannelMap);
3450 
3451  if (SCARD_S_SUCCESS == rv)
3452  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3453 
3455 
3456  return rv;
3457 }
3458 
3459 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3460  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3461 {
3462  int listSize;
3463  int list_index;
3464  SCONTEXTMAP * currentContextMap;
3465  CHANNEL_MAP * currentChannelMap;
3466 
3467  /* Best to get the caller a crash early if we fail unsafely */
3468  *targetContextMap = NULL;
3469  *targetChannelMap = NULL;
3470 
3471  listSize = list_size(&contextMapList);
3472 
3473  for (list_index = 0; list_index < listSize; list_index++)
3474  {
3475  currentContextMap = list_get_at(&contextMapList, list_index);
3476  if (currentContextMap == NULL)
3477  {
3478  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3479  list_index);
3480  continue;
3481  }
3482  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3483  &hCard);
3484  if (currentChannelMap != NULL)
3485  {
3486  *targetContextMap = currentContextMap;
3487  *targetChannelMap = currentChannelMap;
3488  return SCARD_S_SUCCESS;
3489  }
3490  }
3491 
3492  return -1;
3493 }
3494 
3503 {
3504  LONG rv;
3505  struct stat statBuffer;
3506  char *socketName;
3507 
3508  socketName = getSocketName();
3509  rv = stat(socketName, &statBuffer);
3510 
3511  if (rv != 0)
3512  {
3513  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3514  socketName, strerror(errno));
3515  return SCARD_E_NO_SERVICE;
3516  }
3517 
3518  return SCARD_S_SUCCESS;
3519 }
3520 
3521 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3522 {
3523  int32_t dwClientID = currentContextMap->dwClientID;
3524  LONG rv;
3525 
3526  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3527  if (rv != SCARD_S_SUCCESS)
3528  return rv;
3529 
3530  /* Read a message from the server */
3531  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3532  if (rv != SCARD_S_SUCCESS)
3533  return rv;
3534 
3535  return SCARD_S_SUCCESS;
3536 }
3537 
3538 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3539 {
3540  int32_t dwClientID = currentContextMap->dwClientID;
3541  LONG rv;
3542 
3543  /* Get current reader states from server and register on event list */
3545  0, NULL);
3546  if (rv != SCARD_S_SUCCESS)
3547  return rv;
3548 
3549  /* Read a message from the server */
3550  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3551  return rv;
3552 }
3553 
3554 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3555 {
3556  int32_t dwClientID = currentContextMap->dwClientID;
3557  LONG rv;
3558  struct wait_reader_state_change waitStatusStruct = {0};
3559 
3560  /* ask server to remove us from the event list */
3562  dwClientID, 0, NULL);
3563  if (rv != SCARD_S_SUCCESS)
3564  return rv;
3565 
3566  /* This message can be the response to
3567  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3568  * cancel notification.
3569  * The server side ensures, that no more messages will be sent to
3570  * the client. */
3571 
3572  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3573  dwClientID);
3574  if (rv != SCARD_S_SUCCESS)
3575  return rv;
3576 
3577  /* if we received a cancel event the return value will be set
3578  * accordingly */
3579  rv = waitStatusStruct.rv;
3580 
3581  return rv;
3582 }
3583 
#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:174
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:320
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:454
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
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
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:119
#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:356
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:195
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