pcsc-lite  1.9.7
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  goto cleanup;
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  rv = SCARD_F_COMM_ERROR;
607  goto cleanup;
608  }
609 
610  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
611  veStr.major, veStr.minor);
612 
613  if (veStr.rv != SCARD_S_SUCCESS)
614  {
615  rv = veStr.rv;
616  goto cleanup;
617  }
618  }
619 
620 again:
621  /*
622  * Try to establish an Application Context with the server
623  */
624  scEstablishStruct.dwScope = dwScope;
625  scEstablishStruct.hContext = 0;
626  scEstablishStruct.rv = SCARD_S_SUCCESS;
627 
629  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
630 
631  if (rv != SCARD_S_SUCCESS)
632  goto cleanup;
633 
634  /*
635  * Read the response from the server
636  */
637  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
638  dwClientID);
639 
640  if (rv != SCARD_S_SUCCESS)
641  goto cleanup;
642 
643  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
644  {
645  rv = scEstablishStruct.rv;
646  goto cleanup;
647  }
648 
649  /* check we do not reuse an existing hContext */
650  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
651  /* we do not need to release the allocated context since
652  * SCardReleaseContext() does nothing on the server side */
653  goto again;
654 
655  *phContext = scEstablishStruct.hContext;
656 
657  /*
658  * Allocate the new hContext - if allocator full return an error
659  */
660  rv = SCardAddContext(*phContext, dwClientID);
661 
662  return rv;
663 
664 cleanup:
665  ClientCloseSession(dwClientID);
666 
667  return rv;
668 }
669 
692 {
693  LONG rv;
694  struct release_struct scReleaseStruct;
695  SCONTEXTMAP * currentContextMap;
696 
697  API_TRACE_IN("%ld", hContext)
698  PROFILE_START
699 
700  /*
701  * Make sure this context has been opened
702  * and get currentContextMap
703  */
704  currentContextMap = SCardGetAndLockContext(hContext);
705  if (NULL == currentContextMap)
706  {
708  goto error;
709  }
710 
711  scReleaseStruct.hContext = hContext;
712  scReleaseStruct.rv = SCARD_S_SUCCESS;
713 
715  currentContextMap->dwClientID,
716  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
717 
718  if (rv != SCARD_S_SUCCESS)
719  goto end;
720 
721  /*
722  * Read a message from the server
723  */
724  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
725  currentContextMap->dwClientID);
726 
727  if (rv != SCARD_S_SUCCESS)
728  goto end;
729 
730  rv = scReleaseStruct.rv;
731 end:
732  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
733 
734  /*
735  * Remove the local context from the stack
736  */
737  SCardLockThread();
738  SCardRemoveContext(hContext);
740 
741 error:
742  PROFILE_END(rv)
743  API_TRACE_OUT("")
744 
745  return rv;
746 }
747 
803 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
804  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
805  LPDWORD pdwActiveProtocol)
806 {
807  LONG rv;
808  struct connect_struct scConnectStruct;
809  SCONTEXTMAP * currentContextMap;
810 
811  PROFILE_START
812  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
813 
814  /*
815  * Check for NULL parameters
816  */
817  if (phCard == NULL || pdwActiveProtocol == NULL)
819  else
820  *phCard = 0;
821 
822  if (szReader == NULL)
823  return SCARD_E_UNKNOWN_READER;
824 
825  /*
826  * Check for uninitialized strings
827  */
828  if (strlen(szReader) > MAX_READERNAME)
829  return SCARD_E_INVALID_VALUE;
830 
831  /*
832  * Make sure this context has been opened
833  */
834  currentContextMap = SCardGetAndLockContext(hContext);
835  if (NULL == currentContextMap)
836  return SCARD_E_INVALID_HANDLE;
837 
838  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
839  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
840  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
841 
842  scConnectStruct.hContext = hContext;
843  scConnectStruct.dwShareMode = dwShareMode;
844  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
845  scConnectStruct.hCard = 0;
846  scConnectStruct.dwActiveProtocol = 0;
847  scConnectStruct.rv = SCARD_S_SUCCESS;
848 
849  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
850  sizeof(scConnectStruct), (void *) &scConnectStruct);
851 
852  if (rv != SCARD_S_SUCCESS)
853  goto end;
854 
855  /*
856  * Read a message from the server
857  */
858  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
859  currentContextMap->dwClientID);
860 
861  if (rv != SCARD_S_SUCCESS)
862  goto end;
863 
864  *phCard = scConnectStruct.hCard;
865  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
866 
867  if (scConnectStruct.rv == SCARD_S_SUCCESS)
868  {
869  /*
870  * Keep track of the handle locally
871  */
872  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
873  }
874  else
875  rv = scConnectStruct.rv;
876 
877 end:
878  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
879 
880  PROFILE_END(rv)
881  API_TRACE_OUT("%d", *pdwActiveProtocol)
882 
883  return rv;
884 }
885 
958 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
959  DWORD dwPreferredProtocols, DWORD dwInitialization,
960  LPDWORD pdwActiveProtocol)
961 {
962  LONG rv;
963  struct reconnect_struct scReconnectStruct;
964  SCONTEXTMAP * currentContextMap;
965  CHANNEL_MAP * pChannelMap;
966 
967  PROFILE_START
968  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
969 
970  if (pdwActiveProtocol == NULL)
972 
973  /* Retry loop for blocking behaviour */
974 retry:
975 
976  /*
977  * Make sure this handle has been opened
978  */
979  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
980  &pChannelMap);
981  if (rv == -1)
982  return SCARD_E_INVALID_HANDLE;
983 
984  scReconnectStruct.hCard = hCard;
985  scReconnectStruct.dwShareMode = dwShareMode;
986  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
987  scReconnectStruct.dwInitialization = dwInitialization;
988  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
989  scReconnectStruct.rv = SCARD_S_SUCCESS;
990 
991  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
992  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
993 
994  if (rv != SCARD_S_SUCCESS)
995  goto end;
996 
997  /*
998  * Read a message from the server
999  */
1000  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1001  currentContextMap->dwClientID);
1002 
1003  if (rv != SCARD_S_SUCCESS)
1004  goto end;
1005 
1006  rv = scReconnectStruct.rv;
1007 
1008  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1009  {
1010  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1012  goto retry;
1013  }
1014 
1015  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1016 
1017 end:
1018  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1019 
1020  PROFILE_END(rv)
1021  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1022 
1023  return rv;
1024 }
1025 
1057 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1058 {
1059  LONG rv;
1060  struct disconnect_struct scDisconnectStruct;
1061  SCONTEXTMAP * currentContextMap;
1062  CHANNEL_MAP * pChannelMap;
1063 
1064  PROFILE_START
1065  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1066 
1067  /*
1068  * Make sure this handle has been opened
1069  */
1070  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1071  &pChannelMap);
1072  if (rv == -1)
1073  {
1075  goto error;
1076  }
1077 
1078  scDisconnectStruct.hCard = hCard;
1079  scDisconnectStruct.dwDisposition = dwDisposition;
1080  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1081 
1082  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1083  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1084 
1085  if (rv != SCARD_S_SUCCESS)
1086  goto end;
1087 
1088  /*
1089  * Read a message from the server
1090  */
1091  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1092  currentContextMap->dwClientID);
1093 
1094  if (rv != SCARD_S_SUCCESS)
1095  goto end;
1096 
1097  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1098  SCardRemoveHandle(hCard);
1099  rv = scDisconnectStruct.rv;
1100 
1101 end:
1102  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1103 
1104 error:
1105  PROFILE_END(rv)
1106  API_TRACE_OUT("")
1107 
1108  return rv;
1109 }
1110 
1147 {
1148 
1149  LONG rv;
1150  struct begin_struct scBeginStruct;
1151  SCONTEXTMAP * currentContextMap;
1152  CHANNEL_MAP * pChannelMap;
1153 
1154  PROFILE_START
1155  API_TRACE_IN("%ld", hCard)
1156 
1157  /*
1158  * Query the server every so often until the sharing violation ends
1159  * and then hold the lock for yourself.
1160  */
1161 
1162  for(;;)
1163  {
1164  /*
1165  * Make sure this handle has been opened
1166  */
1167  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1168  &pChannelMap);
1169  if (rv == -1)
1170  return SCARD_E_INVALID_HANDLE;
1171 
1172  scBeginStruct.hCard = hCard;
1173  scBeginStruct.rv = SCARD_S_SUCCESS;
1174 
1176  currentContextMap->dwClientID,
1177  sizeof(scBeginStruct), (void *) &scBeginStruct);
1178 
1179  if (rv != SCARD_S_SUCCESS)
1180  break;
1181 
1182  /*
1183  * Read a message from the server
1184  */
1185  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1186  currentContextMap->dwClientID);
1187 
1188  if (rv != SCARD_S_SUCCESS)
1189  break;
1190 
1191  rv = scBeginStruct.rv;
1192 
1193  if (SCARD_E_SHARING_VIOLATION != rv)
1194  break;
1195 
1196  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1198  }
1199 
1200  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1201 
1202  PROFILE_END(rv)
1203  API_TRACE_OUT("")
1204 
1205  return rv;
1206 }
1207 
1247 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1248 {
1249  LONG rv;
1250  struct end_struct scEndStruct;
1251  SCONTEXTMAP * currentContextMap;
1252  CHANNEL_MAP * pChannelMap;
1253 
1254  PROFILE_START
1255  API_TRACE_IN("%ld", hCard)
1256 
1257  /*
1258  * Make sure this handle has been opened
1259  */
1260  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1261  &pChannelMap);
1262  if (rv == -1)
1263  return SCARD_E_INVALID_HANDLE;
1264 
1265  scEndStruct.hCard = hCard;
1266  scEndStruct.dwDisposition = dwDisposition;
1267  scEndStruct.rv = SCARD_S_SUCCESS;
1268 
1270  currentContextMap->dwClientID,
1271  sizeof(scEndStruct), (void *) &scEndStruct);
1272 
1273  if (rv != SCARD_S_SUCCESS)
1274  goto end;
1275 
1276  /*
1277  * Read a message from the server
1278  */
1279  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1280  currentContextMap->dwClientID);
1281 
1282  if (rv != SCARD_S_SUCCESS)
1283  goto end;
1284 
1285  rv = scEndStruct.rv;
1286 
1287 end:
1288  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1289 
1290  PROFILE_END(rv)
1291  API_TRACE_OUT("")
1292 
1293  return rv;
1294 }
1295 
1391 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1392  LPDWORD pcchReaderLen, LPDWORD pdwState,
1393  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1394 {
1395  DWORD dwReaderLen, dwAtrLen;
1396  LONG rv;
1397  int i;
1398  struct status_struct scStatusStruct;
1399  SCONTEXTMAP * currentContextMap;
1400  CHANNEL_MAP * pChannelMap;
1401  char *r;
1402  char *bufReader = NULL;
1403  LPBYTE bufAtr = NULL;
1404  DWORD dummy = 0;
1405 
1406  PROFILE_START
1407 
1408  /* default output values */
1409  if (pdwState)
1410  *pdwState = 0;
1411 
1412  if (pdwProtocol)
1413  *pdwProtocol = 0;
1414 
1415  /* Check for NULL parameters */
1416  if (pcchReaderLen == NULL)
1417  pcchReaderLen = &dummy;
1418 
1419  if (pcbAtrLen == NULL)
1420  pcbAtrLen = &dummy;
1421 
1422  /* length passed from caller */
1423  dwReaderLen = *pcchReaderLen;
1424  dwAtrLen = *pcbAtrLen;
1425 
1426  *pcchReaderLen = 0;
1427  *pcbAtrLen = 0;
1428 
1429  /* Retry loop for blocking behaviour */
1430 retry:
1431 
1432  /*
1433  * Make sure this handle has been opened
1434  */
1435  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1436  &pChannelMap);
1437  if (rv == -1)
1438  return SCARD_E_INVALID_HANDLE;
1439 
1440  /* synchronize reader states with daemon */
1441  rv = getReaderStates(currentContextMap);
1442  if (rv != SCARD_S_SUCCESS)
1443  goto end;
1444 
1445  r = pChannelMap->readerName;
1446  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1447  {
1448  /* by default r == NULL */
1449  if (r && strcmp(r, readerStates[i].readerName) == 0)
1450  break;
1451  }
1452 
1454  {
1456  goto end;
1457  }
1458 
1459  /* initialise the structure */
1460  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1461  scStatusStruct.hCard = hCard;
1462 
1463  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1464  sizeof(scStatusStruct), (void *) &scStatusStruct);
1465 
1466  if (rv != SCARD_S_SUCCESS)
1467  goto end;
1468 
1469  /*
1470  * Read a message from the server
1471  */
1472  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1473  currentContextMap->dwClientID);
1474 
1475  if (rv != SCARD_S_SUCCESS)
1476  goto end;
1477 
1478  rv = scStatusStruct.rv;
1479 
1480  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1481  {
1482  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1484  goto retry;
1485  }
1486 
1487  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1488  {
1489  /*
1490  * An event must have occurred
1491  */
1492  goto end;
1493  }
1494 
1495  /*
1496  * Now continue with the client side SCardStatus
1497  */
1498 
1499  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1500  *pcbAtrLen = readerStates[i].cardAtrLength;
1501 
1502  if (pdwState)
1503  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1504 
1505  if (pdwProtocol)
1506  *pdwProtocol = readerStates[i].cardProtocol;
1507 
1508  if (SCARD_AUTOALLOCATE == dwReaderLen)
1509  {
1510  dwReaderLen = *pcchReaderLen;
1511  if (NULL == szReaderName)
1512  {
1514  goto end;
1515  }
1516  bufReader = malloc(dwReaderLen);
1517  if (NULL == bufReader)
1518  {
1519  rv = SCARD_E_NO_MEMORY;
1520  goto end;
1521  }
1522  *(char **)szReaderName = bufReader;
1523  }
1524  else
1525  bufReader = szReaderName;
1526 
1527  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1528  if (bufReader)
1529  {
1530  if (*pcchReaderLen > dwReaderLen)
1532 
1533  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1534  }
1535 
1536  if (SCARD_AUTOALLOCATE == dwAtrLen)
1537  {
1538  dwAtrLen = *pcbAtrLen;
1539  if (NULL == pbAtr)
1540  {
1542  goto end;
1543  }
1544  bufAtr = malloc(dwAtrLen);
1545  if (NULL == bufAtr)
1546  {
1547  rv = SCARD_E_NO_MEMORY;
1548  goto end;
1549  }
1550  *(LPBYTE *)pbAtr = bufAtr;
1551  }
1552  else
1553  bufAtr = pbAtr;
1554 
1555  if (bufAtr)
1556  {
1557  if (*pcbAtrLen > dwAtrLen)
1559 
1560  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1561  }
1562 
1563 end:
1564  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1565 
1566  PROFILE_END(rv)
1567 
1568  return rv;
1569 }
1570 
1678 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1679  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1680 {
1681  SCARD_READERSTATE *currReader;
1682  READER_STATE *rContext;
1683  long dwTime;
1684  DWORD dwBreakFlag = 0;
1685  unsigned int j;
1686  SCONTEXTMAP * currentContextMap;
1687  int currentReaderCount = 0;
1688  LONG rv = SCARD_S_SUCCESS;
1689 
1690  PROFILE_START
1691  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1692 #ifdef DO_TRACE
1693  for (j=0; j<cReaders; j++)
1694  {
1695  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1696  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1697  }
1698 #endif
1699 
1700  if ((rgReaderStates == NULL && cReaders > 0)
1701  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1702  {
1704  goto error;
1705  }
1706 
1707  /* Check the integrity of the reader states structures */
1708  for (j = 0; j < cReaders; j++)
1709  {
1710  if (rgReaderStates[j].szReader == NULL)
1711  return SCARD_E_INVALID_VALUE;
1712  }
1713 
1714  /* return if all readers are SCARD_STATE_IGNORE */
1715  if (cReaders > 0)
1716  {
1717  int nbNonIgnoredReaders = cReaders;
1718 
1719  for (j=0; j<cReaders; j++)
1720  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1721  nbNonIgnoredReaders--;
1722 
1723  if (0 == nbNonIgnoredReaders)
1724  {
1725  rv = SCARD_S_SUCCESS;
1726  goto error;
1727  }
1728  }
1729  else
1730  {
1731  /* reader list is empty */
1732  rv = SCARD_S_SUCCESS;
1733  goto error;
1734  }
1735 
1736  /*
1737  * Make sure this context has been opened
1738  */
1739  currentContextMap = SCardGetAndLockContext(hContext);
1740  if (NULL == currentContextMap)
1741  {
1743  goto error;
1744  }
1745 
1746  /* synchronize reader states with daemon */
1747  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1748  if (rv != SCARD_S_SUCCESS)
1749  goto end;
1750 
1751  /* check all the readers are already known */
1752  for (j=0; j<cReaders; j++)
1753  {
1754  const char *readerName;
1755  int i;
1756 
1757  readerName = rgReaderStates[j].szReader;
1758  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1759  {
1760  if (strcmp(readerName, readerStates[i].readerName) == 0)
1761  break;
1762  }
1763 
1764  /* The requested reader name is not recognized */
1766  {
1767  /* PnP special reader? */
1768  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1769  {
1771  goto end;
1772  }
1773  }
1774  }
1775 
1776  /* Clear the event state for all readers */
1777  for (j = 0; j < cReaders; j++)
1778  rgReaderStates[j].dwEventState = 0;
1779 
1780  /* Now is where we start our event checking loop */
1781  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1782 
1783  /* Get the initial reader count on the system */
1784  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1785  if (readerStates[j].readerName[0] != '\0')
1786  currentReaderCount++;
1787 
1788  /* catch possible sign extension problems from 32 to 64-bits integers */
1789  if ((DWORD)-1 == dwTimeout)
1790  dwTimeout = INFINITE;
1791  if (INFINITE == dwTimeout)
1792  dwTime = 60*1000; /* "infinite" timeout */
1793  else
1794  dwTime = dwTimeout;
1795 
1796  j = 0;
1797  do
1798  {
1799  currReader = &rgReaderStates[j];
1800 
1801  /* Ignore for IGNORED readers */
1802  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1803  {
1804  const char *readerName;
1805  int i;
1806 
1807  /* Looks for correct readernames */
1808  readerName = currReader->szReader;
1809  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1810  {
1811  if (strcmp(readerName, readerStates[i].readerName) == 0)
1812  break;
1813  }
1814 
1815  /* The requested reader name is not recognized */
1817  {
1818  /* PnP special reader? */
1819  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1820  {
1821  int k, newReaderCount = 0;
1822 
1823  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1824  if (readerStates[k].readerName[0] != '\0')
1825  newReaderCount++;
1826 
1827  if (newReaderCount != currentReaderCount)
1828  {
1829  Log1(PCSC_LOG_INFO, "Reader list changed");
1830  currentReaderCount = newReaderCount;
1831 
1832  currReader->dwEventState |= SCARD_STATE_CHANGED;
1833  dwBreakFlag = 1;
1834  }
1835  }
1836  else
1837  {
1838  currReader->dwEventState =
1840  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1841  {
1842  currReader->dwEventState |= SCARD_STATE_CHANGED;
1843  /*
1844  * Spec says use SCARD_STATE_IGNORE but a removed USB
1845  * reader with eventState fed into currentState will
1846  * be ignored forever
1847  */
1848  dwBreakFlag = 1;
1849  }
1850  }
1851  }
1852  else
1853  {
1854  uint32_t readerState;
1855 
1856  /* The reader has come back after being away */
1857  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1858  {
1859  currReader->dwEventState |= SCARD_STATE_CHANGED;
1860  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1861  Log0(PCSC_LOG_DEBUG);
1862  dwBreakFlag = 1;
1863  }
1864 
1865  /* Set the reader status structure */
1866  rContext = &readerStates[i];
1867 
1868  /* Now we check all the Reader States */
1869  readerState = rContext->readerState;
1870 
1871  /* only if current state has an non null event counter */
1872  if (currReader->dwCurrentState & 0xFFFF0000)
1873  {
1874  unsigned int currentCounter;
1875 
1876  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1877 
1878  /* has the event counter changed since the last call? */
1879  if (rContext->eventCounter != currentCounter)
1880  {
1881  currReader->dwEventState |= SCARD_STATE_CHANGED;
1882  Log0(PCSC_LOG_DEBUG);
1883  dwBreakFlag = 1;
1884  }
1885  }
1886 
1887  /* add an event counter in the upper word of dwEventState */
1888  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1889  | (rContext->eventCounter << 16));
1890 
1891  /* Check if the reader is in the correct state */
1892  if (readerState & SCARD_UNKNOWN)
1893  {
1894  /* reader is in bad state */
1895  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1896  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1897  {
1898  /* App thinks reader is in good state and it is not */
1899  currReader->dwEventState |= SCARD_STATE_CHANGED;
1900  Log0(PCSC_LOG_DEBUG);
1901  dwBreakFlag = 1;
1902  }
1903  }
1904  else
1905  {
1906  /* App thinks reader in bad state but it is not */
1907  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1908  {
1909  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1910  currReader->dwEventState |= SCARD_STATE_CHANGED;
1911  Log0(PCSC_LOG_DEBUG);
1912  dwBreakFlag = 1;
1913  }
1914  }
1915 
1916  /* Check for card presence in the reader */
1917  if (readerState & SCARD_PRESENT)
1918  {
1919 #ifndef DISABLE_AUTO_POWER_ON
1920  /* card present but not yet powered up */
1921  if (0 == rContext->cardAtrLength)
1922  /* Allow the status thread to convey information */
1924 #endif
1925 
1926  currReader->cbAtr = rContext->cardAtrLength;
1927  memcpy(currReader->rgbAtr, rContext->cardAtr,
1928  currReader->cbAtr);
1929  }
1930  else
1931  currReader->cbAtr = 0;
1932 
1933  /* Card is now absent */
1934  if (readerState & SCARD_ABSENT)
1935  {
1936  currReader->dwEventState |= SCARD_STATE_EMPTY;
1937  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1938  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1939  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1940  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1941  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1942  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1943  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1944  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1945 
1946  /* After present the rest are assumed */
1947  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1948  {
1949  currReader->dwEventState |= SCARD_STATE_CHANGED;
1950  Log0(PCSC_LOG_DEBUG);
1951  dwBreakFlag = 1;
1952  }
1953  }
1954  /* Card is now present */
1955  else if (readerState & SCARD_PRESENT)
1956  {
1957  currReader->dwEventState |= SCARD_STATE_PRESENT;
1958  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1959  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1960  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1961  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1962  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1963  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1964 
1965  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1966  {
1967  currReader->dwEventState |= SCARD_STATE_CHANGED;
1968  Log0(PCSC_LOG_DEBUG);
1969  dwBreakFlag = 1;
1970  }
1971 
1972  if (readerState & SCARD_SWALLOWED)
1973  {
1974  currReader->dwEventState |= SCARD_STATE_MUTE;
1975  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1976  {
1977  currReader->dwEventState |= SCARD_STATE_CHANGED;
1978  Log0(PCSC_LOG_DEBUG);
1979  dwBreakFlag = 1;
1980  }
1981  }
1982  else
1983  {
1984  /* App thinks card is mute but it is not */
1985  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1986  {
1987  currReader->dwEventState |= SCARD_STATE_CHANGED;
1988  Log0(PCSC_LOG_DEBUG);
1989  dwBreakFlag = 1;
1990  }
1991  }
1992  }
1993 
1994  /* Now figure out sharing modes */
1996  {
1997  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1998  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1999  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2000  {
2001  currReader->dwEventState |= SCARD_STATE_CHANGED;
2002  Log0(PCSC_LOG_DEBUG);
2003  dwBreakFlag = 1;
2004  }
2005  }
2006  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2007  {
2008  /* A card must be inserted for it to be INUSE */
2009  if (readerState & SCARD_PRESENT)
2010  {
2011  currReader->dwEventState |= SCARD_STATE_INUSE;
2012  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2013  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2014  {
2015  currReader->dwEventState |= SCARD_STATE_CHANGED;
2016  Log0(PCSC_LOG_DEBUG);
2017  dwBreakFlag = 1;
2018  }
2019  }
2020  }
2021  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2022  {
2023  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2024  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2025 
2026  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2027  {
2028  currReader->dwEventState |= SCARD_STATE_CHANGED;
2029  Log0(PCSC_LOG_DEBUG);
2030  dwBreakFlag = 1;
2031  }
2032  else if (currReader-> dwCurrentState
2034  {
2035  currReader->dwEventState |= SCARD_STATE_CHANGED;
2036  Log0(PCSC_LOG_DEBUG);
2037  dwBreakFlag = 1;
2038  }
2039  }
2040 
2041  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2042  {
2043  /*
2044  * Break out of the while .. loop and return status
2045  * once all the status's for all readers is met
2046  */
2047  currReader->dwEventState |= SCARD_STATE_CHANGED;
2048  Log0(PCSC_LOG_DEBUG);
2049  dwBreakFlag = 1;
2050  }
2051  } /* End of SCARD_STATE_UNKNOWN */
2052  } /* End of SCARD_STATE_IGNORE */
2053 
2054  /* Counter and resetter */
2055  j++;
2056  if (j == cReaders)
2057  {
2058  /* go back to the first reader */
2059  j = 0;
2060 
2061  /* Declare all the break conditions */
2062 
2063  /* Break if UNAWARE is set and all readers have been checked */
2064  if (dwBreakFlag == 1)
2065  break;
2066 
2067  /* Only sleep once for each cycle of reader checks. */
2068  {
2069  struct wait_reader_state_change waitStatusStruct = {0};
2070  struct timeval before, after;
2071 
2072  gettimeofday(&before, NULL);
2073 
2074  waitStatusStruct.rv = SCARD_S_SUCCESS;
2075 
2076  /* another thread can do SCardCancel() */
2077  currentContextMap->cancellable = TRUE;
2078 
2079  /*
2080  * Read a message from the server
2081  */
2083  &waitStatusStruct, sizeof(waitStatusStruct),
2084  currentContextMap->dwClientID, dwTime);
2085 
2086  /* SCardCancel() will return immediatly with success
2087  * because something changed on the daemon side. */
2088  currentContextMap->cancellable = FALSE;
2089 
2090  /* timeout */
2091  if (SCARD_E_TIMEOUT == rv)
2092  {
2093  /* ask server to remove us from the event list */
2094  rv = unregisterFromEvents(currentContextMap);
2095  }
2096 
2097  if (rv != SCARD_S_SUCCESS)
2098  goto end;
2099 
2100  /* an event occurs or SCardCancel() was called */
2101  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2102  {
2103  rv = waitStatusStruct.rv;
2104  goto end;
2105  }
2106 
2107  /* synchronize reader states with daemon */
2108  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2109  if (rv != SCARD_S_SUCCESS)
2110  goto end;
2111 
2112  if (INFINITE != dwTimeout)
2113  {
2114  long int diff;
2115 
2116  gettimeofday(&after, NULL);
2117  diff = time_sub(&after, &before);
2118  dwTime -= diff/1000;
2119  }
2120  }
2121 
2122  if (dwTimeout != INFINITE)
2123  {
2124  /* If time is greater than timeout and all readers have been
2125  * checked
2126  */
2127  if (dwTime <= 0)
2128  {
2129  rv = SCARD_E_TIMEOUT;
2130  goto end;
2131  }
2132  }
2133  }
2134  }
2135  while (1);
2136 
2137 end:
2138  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2139 
2140  /* if SCardCancel() has been used then the client is already
2141  * unregistered */
2142  if (SCARD_E_CANCELLED != rv)
2143  (void)unregisterFromEvents(currentContextMap);
2144 
2145  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2146 
2147 error:
2148  PROFILE_END(rv)
2149 #ifdef DO_TRACE
2150  for (j=0; j<cReaders; j++)
2151  {
2152  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2153  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2154  }
2155 #endif
2156 
2157  return rv;
2158 }
2159 
2210 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2211  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2212  LPDWORD lpBytesReturned)
2213 {
2214  LONG rv;
2215  struct control_struct scControlStruct;
2216  SCONTEXTMAP * currentContextMap;
2217  CHANNEL_MAP * pChannelMap;
2218 
2219  PROFILE_START
2220 
2221  /* 0 bytes received by default */
2222  if (NULL != lpBytesReturned)
2223  *lpBytesReturned = 0;
2224 
2225  /*
2226  * Make sure this handle has been opened
2227  */
2228  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2229  &pChannelMap);
2230  if (rv == -1)
2231  {
2232  PROFILE_END(SCARD_E_INVALID_HANDLE)
2233  return SCARD_E_INVALID_HANDLE;
2234  }
2235 
2236  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2237  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2238  {
2240  goto end;
2241  }
2242 
2243  scControlStruct.hCard = hCard;
2244  scControlStruct.dwControlCode = dwControlCode;
2245  scControlStruct.cbSendLength = cbSendLength;
2246  scControlStruct.cbRecvLength = cbRecvLength;
2247  scControlStruct.dwBytesReturned = 0;
2248  scControlStruct.rv = 0;
2249 
2250  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2251  sizeof(scControlStruct), &scControlStruct);
2252 
2253  if (rv != SCARD_S_SUCCESS)
2254  goto end;
2255 
2256  /* write the sent buffer */
2257  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2258  currentContextMap->dwClientID);
2259 
2260  if (rv != SCARD_S_SUCCESS)
2261  goto end;
2262 
2263  /*
2264  * Read a message from the server
2265  */
2266  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2267  currentContextMap->dwClientID);
2268 
2269  if (rv != SCARD_S_SUCCESS)
2270  goto end;
2271 
2272  if (SCARD_S_SUCCESS == scControlStruct.rv)
2273  {
2274  if (scControlStruct.dwBytesReturned > cbRecvLength)
2275  {
2276  if (NULL != lpBytesReturned)
2277  *lpBytesReturned = scControlStruct.dwBytesReturned;
2279  goto end;
2280  }
2281 
2282  /* read the received buffer */
2283  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2284  currentContextMap->dwClientID);
2285 
2286  if (rv != SCARD_S_SUCCESS)
2287  goto end;
2288 
2289  }
2290 
2291  if (NULL != lpBytesReturned)
2292  *lpBytesReturned = scControlStruct.dwBytesReturned;
2293 
2294  rv = scControlStruct.rv;
2295 
2296 end:
2297  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2298 
2299  PROFILE_END(rv)
2300 
2301  return rv;
2302 }
2303 
2421 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2422  LPDWORD pcbAttrLen)
2423 {
2424  LONG ret;
2425  unsigned char *buf = NULL;
2426 
2427  PROFILE_START
2428 
2429  if (NULL == pcbAttrLen)
2430  {
2432  goto end;
2433  }
2434 
2435  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2436  {
2437  if (NULL == pbAttr)
2439 
2440  *pcbAttrLen = MAX_BUFFER_SIZE;
2441  buf = malloc(*pcbAttrLen);
2442  if (NULL == buf)
2443  {
2444  ret = SCARD_E_NO_MEMORY;
2445  goto end;
2446  }
2447 
2448  *(unsigned char **)pbAttr = buf;
2449  }
2450  else
2451  {
2452  buf = pbAttr;
2453 
2454  /* if only get the length */
2455  if (NULL == pbAttr)
2456  /* use a reasonable size */
2457  *pcbAttrLen = MAX_BUFFER_SIZE;
2458  }
2459 
2460  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2461  pcbAttrLen);
2462 
2463 end:
2464  PROFILE_END(ret)
2465 
2466  return ret;
2467 }
2468 
2504 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2505  DWORD cbAttrLen)
2506 {
2507  LONG ret;
2508 
2509  PROFILE_START
2510 
2511  if (NULL == pbAttr || 0 == cbAttrLen)
2513 
2514  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2515  &cbAttrLen);
2516 
2517  PROFILE_END(ret)
2518 
2519  return ret;
2520 }
2521 
2522 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2523  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2524 {
2525  LONG rv;
2526  struct getset_struct scGetSetStruct;
2527  SCONTEXTMAP * currentContextMap;
2528  CHANNEL_MAP * pChannelMap;
2529 
2530  /*
2531  * Make sure this handle has been opened
2532  */
2533  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2534  &pChannelMap);
2535  if (rv == -1)
2536  return SCARD_E_INVALID_HANDLE;
2537 
2538  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2539  {
2541  goto end;
2542  }
2543 
2544  scGetSetStruct.hCard = hCard;
2545  scGetSetStruct.dwAttrId = dwAttrId;
2546  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2547  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2548  if (SCARD_SET_ATTRIB == command)
2549  {
2550  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2551  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2552  }
2553  else
2554  /* we can get up to the communication buffer size */
2555  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2556 
2557  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2558  sizeof(scGetSetStruct), &scGetSetStruct);
2559 
2560  if (rv != SCARD_S_SUCCESS)
2561  goto end;
2562 
2563  /*
2564  * Read a message from the server
2565  */
2566  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2567  currentContextMap->dwClientID);
2568 
2569  if (rv != SCARD_S_SUCCESS)
2570  goto end;
2571 
2572  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2573  {
2574  /*
2575  * Copy and zero it so any secret information is not leaked
2576  */
2577  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2578  {
2579  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2580  * buffer overflow in the memcpy() bellow */
2581  DWORD correct_value = scGetSetStruct.cbAttrLen;
2582  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2583  *pcbAttrLen = correct_value;
2584 
2585  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2586  }
2587  else
2588  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2589 
2590  if (pbAttr)
2591  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2592 
2593  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2594  }
2595  rv = scGetSetStruct.rv;
2596 
2597 end:
2598  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2599 
2600  return rv;
2601 }
2602 
2661 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2662  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2663  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2664  LPDWORD pcbRecvLength)
2665 {
2666  LONG rv;
2667  SCONTEXTMAP * currentContextMap;
2668  CHANNEL_MAP * pChannelMap;
2669  struct transmit_struct scTransmitStruct;
2670 
2671  PROFILE_START
2672 
2673  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2674  pcbRecvLength == NULL || pioSendPci == NULL)
2676 
2677  /* Retry loop for blocking behaviour */
2678 retry:
2679 
2680  /*
2681  * Make sure this handle has been opened
2682  */
2683  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2684  &pChannelMap);
2685  if (rv == -1)
2686  {
2687  *pcbRecvLength = 0;
2688  PROFILE_END(SCARD_E_INVALID_HANDLE)
2689  return SCARD_E_INVALID_HANDLE;
2690  }
2691 
2692  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2693  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2694  {
2696  goto end;
2697  }
2698 
2699  scTransmitStruct.hCard = hCard;
2700  scTransmitStruct.cbSendLength = cbSendLength;
2701  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2702  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2703  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2704  scTransmitStruct.rv = SCARD_S_SUCCESS;
2705 
2706  if (pioRecvPci)
2707  {
2708  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2709  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2710  }
2711  else
2712  {
2713  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2714  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2715  }
2716 
2717  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2718  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2719 
2720  if (rv != SCARD_S_SUCCESS)
2721  goto end;
2722 
2723  /* write the sent buffer */
2724  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2725  currentContextMap->dwClientID);
2726 
2727  if (rv != SCARD_S_SUCCESS)
2728  goto end;
2729 
2730  /*
2731  * Read a message from the server
2732  */
2733  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2734  currentContextMap->dwClientID);
2735 
2736  if (rv != SCARD_S_SUCCESS)
2737  goto end;
2738 
2739  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2740  {
2741  if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2742  {
2743  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2745  goto end;
2746  }
2747 
2748  /* read the received buffer */
2749  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2750  currentContextMap->dwClientID);
2751 
2752  if (rv != SCARD_S_SUCCESS)
2753  goto end;
2754 
2755  if (pioRecvPci)
2756  {
2757  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2758  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2759  }
2760  }
2761 
2762  rv = scTransmitStruct.rv;
2763 
2764  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2765  {
2766  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2768  goto retry;
2769  }
2770 
2771  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2772 
2773 end:
2774  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2775 
2776  PROFILE_END(rv)
2777 
2778  return rv;
2779 }
2780 
2843 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2844  LPSTR mszReaders, LPDWORD pcchReaders)
2845 {
2846  DWORD dwReadersLen = 0;
2847  int i;
2848  SCONTEXTMAP * currentContextMap;
2849  LONG rv = SCARD_S_SUCCESS;
2850  char *buf = NULL;
2851 
2852  (void)mszGroups;
2853  PROFILE_START
2854  API_TRACE_IN("%ld", hContext)
2855 
2856  /*
2857  * Check for NULL parameters
2858  */
2859  if (pcchReaders == NULL)
2861 
2862  /*
2863  * Make sure this context has been opened
2864  */
2865  currentContextMap = SCardGetAndLockContext(hContext);
2866  if (NULL == currentContextMap)
2867  {
2868  PROFILE_END(SCARD_E_INVALID_HANDLE)
2869  return SCARD_E_INVALID_HANDLE;
2870  }
2871 
2872  /* synchronize reader states with daemon */
2873  rv = getReaderStates(currentContextMap);
2874  if (rv != SCARD_S_SUCCESS)
2875  goto end;
2876 
2877  dwReadersLen = 0;
2878  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2879  if (readerStates[i].readerName[0] != '\0')
2880  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2881 
2882  /* for the last NULL byte */
2883  dwReadersLen += 1;
2884 
2885  if (1 == dwReadersLen)
2886  {
2888  goto end;
2889  }
2890 
2891  if (SCARD_AUTOALLOCATE == *pcchReaders)
2892  {
2893  if (NULL == mszReaders)
2894  {
2896  goto end;
2897  }
2898  buf = malloc(dwReadersLen);
2899  if (NULL == buf)
2900  {
2901  rv = SCARD_E_NO_MEMORY;
2902  goto end;
2903  }
2904  *(char **)mszReaders = buf;
2905  }
2906  else
2907  {
2908  buf = mszReaders;
2909 
2910  /* not enough place to store the reader names */
2911  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2912  {
2914  goto end;
2915  }
2916  }
2917 
2918  if (mszReaders == NULL) /* text array not allocated */
2919  goto end;
2920 
2921  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2922  {
2923  if (readerStates[i].readerName[0] != '\0')
2924  {
2925  /*
2926  * Build the multi-string
2927  */
2928  strcpy(buf, readerStates[i].readerName);
2929  buf += strlen(readerStates[i].readerName)+1;
2930  }
2931  }
2932  *buf = '\0'; /* Add the last null */
2933 
2934 end:
2935  /* set the reader names length */
2936  *pcchReaders = dwReadersLen;
2937 
2938  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2939 
2940  PROFILE_END(rv)
2941  API_TRACE_OUT("%d", *pcchReaders)
2942 
2943  return rv;
2944 }
2945 
2959 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2960 {
2961  LONG rv = SCARD_S_SUCCESS;
2962 
2963  PROFILE_START
2964 
2965  /*
2966  * Make sure this context has been opened
2967  */
2968  if (! SCardGetContextValidity(hContext))
2969  return SCARD_E_INVALID_HANDLE;
2970 
2971  free((void *)pvMem);
2972 
2973  PROFILE_END(rv)
2974 
2975  return rv;
2976 }
2977 
3029 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3030  LPDWORD pcchGroups)
3031 {
3032  LONG rv = SCARD_S_SUCCESS;
3033  SCONTEXTMAP * currentContextMap;
3034  char *buf = NULL;
3035 
3036  PROFILE_START
3037 
3038  /* Multi-string with two trailing \0 */
3039  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3040  const unsigned int dwGroups = sizeof(ReaderGroup);
3041 
3042  /*
3043  * Make sure this context has been opened
3044  */
3045  currentContextMap = SCardGetAndLockContext(hContext);
3046  if (NULL == currentContextMap)
3047  return SCARD_E_INVALID_HANDLE;
3048 
3049  if (SCARD_AUTOALLOCATE == *pcchGroups)
3050  {
3051  if (NULL == mszGroups)
3052  {
3054  goto end;
3055  }
3056  buf = malloc(dwGroups);
3057  if (NULL == buf)
3058  {
3059  rv = SCARD_E_NO_MEMORY;
3060  goto end;
3061  }
3062  *(char **)mszGroups = buf;
3063  }
3064  else
3065  {
3066  buf = mszGroups;
3067 
3068  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3069  {
3071  goto end;
3072  }
3073  }
3074 
3075  if (buf)
3076  memcpy(buf, ReaderGroup, dwGroups);
3077 
3078 end:
3079  *pcchGroups = dwGroups;
3080 
3081  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3082 
3083  PROFILE_END(rv)
3084 
3085  return rv;
3086 }
3087 
3120 {
3121  SCONTEXTMAP * currentContextMap;
3122  LONG rv = SCARD_S_SUCCESS;
3123  uint32_t dwClientID = 0;
3124  struct cancel_struct scCancelStruct;
3125  char cancellable;
3126 
3127  PROFILE_START
3128  API_TRACE_IN("%ld", hContext)
3129 
3130  /*
3131  * Make sure this context has been opened
3132  */
3133  (void)SCardLockThread();
3134  currentContextMap = SCardGetContextTH(hContext);
3135 
3136  if (NULL == currentContextMap)
3137  {
3138  (void)SCardUnlockThread();
3140  goto error;
3141  }
3142  cancellable = currentContextMap->cancellable;
3143  (void)SCardUnlockThread();
3144 
3145  if (! cancellable)
3146  {
3147  rv = SCARD_S_SUCCESS;
3148  goto error;
3149  }
3150 
3151  /* create a new connection to the server */
3152  if (ClientSetupSession(&dwClientID) != 0)
3153  {
3154  rv = SCARD_E_NO_SERVICE;
3155  goto error;
3156  }
3157 
3158  scCancelStruct.hContext = hContext;
3159  scCancelStruct.rv = SCARD_S_SUCCESS;
3160 
3161  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3162  sizeof(scCancelStruct), (void *) &scCancelStruct);
3163 
3164  if (rv != SCARD_S_SUCCESS)
3165  goto end;
3166 
3167  /*
3168  * Read a message from the server
3169  */
3170  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3171 
3172  if (rv != SCARD_S_SUCCESS)
3173  goto end;
3174 
3175  rv = scCancelStruct.rv;
3176 end:
3177  ClientCloseSession(dwClientID);
3178 
3179 error:
3180  PROFILE_END(rv)
3181  API_TRACE_OUT("")
3182 
3183  return rv;
3184 }
3185 
3210 {
3211  LONG rv;
3212 
3213  PROFILE_START
3214  API_TRACE_IN("%ld", hContext)
3215 
3216  rv = SCARD_S_SUCCESS;
3217 
3218  /*
3219  * Make sure this context has been opened
3220  */
3221  if (! SCardGetContextValidity(hContext))
3223 
3224  PROFILE_END(rv)
3225  API_TRACE_OUT("")
3226 
3227  return rv;
3228 }
3229 
3246 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3247 {
3248  int lrv;
3249  SCONTEXTMAP * newContextMap;
3250 
3251  newContextMap = malloc(sizeof(SCONTEXTMAP));
3252  if (NULL == newContextMap)
3253  return SCARD_E_NO_MEMORY;
3254 
3255  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3256  newContextMap->hContext = hContext;
3257  newContextMap->dwClientID = dwClientID;
3258  newContextMap->cancellable = FALSE;
3259 
3260  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3261 
3262  lrv = list_init(&newContextMap->channelMapList);
3263  if (lrv < 0)
3264  {
3265  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3266  goto error;
3267  }
3268 
3269  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3270  CHANNEL_MAP_seeker);
3271  if (lrv <0)
3272  {
3273  Log2(PCSC_LOG_CRITICAL,
3274  "list_attributes_seeker failed with return value: %d", lrv);
3275  list_destroy(&newContextMap->channelMapList);
3276  goto error;
3277  }
3278 
3279  lrv = list_append(&contextMapList, newContextMap);
3280  if (lrv < 0)
3281  {
3282  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3283  lrv);
3284  list_destroy(&newContextMap->channelMapList);
3285  goto error;
3286  }
3287 
3288  return SCARD_S_SUCCESS;
3289 
3290 error:
3291 
3292  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3293  free(newContextMap);
3294 
3295  return SCARD_E_NO_MEMORY;
3296 }
3297 
3315 {
3316  SCONTEXTMAP * currentContextMap;
3317 
3318  SCardLockThread();
3319  currentContextMap = SCardGetContextTH(hContext);
3320 
3321  /* lock the context (if available) */
3322  if (NULL != currentContextMap)
3323  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3324 
3326 
3327  return currentContextMap;
3328 }
3329 
3343 {
3344  return list_seek(&contextMapList, &hContext);
3345 }
3346 
3353 static void SCardRemoveContext(SCARDCONTEXT hContext)
3354 {
3355  SCONTEXTMAP * currentContextMap;
3356  currentContextMap = SCardGetContextTH(hContext);
3357 
3358  if (NULL != currentContextMap)
3359  SCardCleanContext(currentContextMap);
3360 }
3361 
3362 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3363 {
3364  int list_index, lrv;
3365  int listSize;
3366  CHANNEL_MAP * currentChannelMap;
3367 
3368  targetContextMap->hContext = 0;
3369  ClientCloseSession(targetContextMap->dwClientID);
3370  targetContextMap->dwClientID = 0;
3371  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3372 
3373  listSize = list_size(&targetContextMap->channelMapList);
3374  for (list_index = 0; list_index < listSize; list_index++)
3375  {
3376  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3377  list_index);
3378  if (NULL == currentChannelMap)
3379  {
3380  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3381  list_index);
3382  continue;
3383  }
3384  else
3385  {
3386  free(currentChannelMap->readerName);
3387  free(currentChannelMap);
3388  }
3389 
3390  }
3391  list_destroy(&targetContextMap->channelMapList);
3392 
3393  lrv = list_delete(&contextMapList, targetContextMap);
3394  if (lrv < 0)
3395  {
3396  Log2(PCSC_LOG_CRITICAL,
3397  "list_delete failed with return value: %d", lrv);
3398  }
3399 
3400  free(targetContextMap);
3401 
3402  return;
3403 }
3404 
3405 /*
3406  * Functions for managing hCard values returned from SCardConnect.
3407  */
3408 
3409 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3410  LPCSTR readerName)
3411 {
3412  CHANNEL_MAP * newChannelMap;
3413  int lrv = -1;
3414 
3415  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3416  if (NULL == newChannelMap)
3417  return SCARD_E_NO_MEMORY;
3418 
3419  newChannelMap->hCard = hCard;
3420  newChannelMap->readerName = strdup(readerName);
3421 
3422  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3423  if (lrv < 0)
3424  {
3425  free(newChannelMap->readerName);
3426  free(newChannelMap);
3427  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3428  lrv);
3429  return SCARD_E_NO_MEMORY;
3430  }
3431 
3432  return SCARD_S_SUCCESS;
3433 }
3434 
3435 static void SCardRemoveHandle(SCARDHANDLE hCard)
3436 {
3437  SCONTEXTMAP * currentContextMap;
3438  CHANNEL_MAP * currentChannelMap;
3439  int lrv;
3440  LONG rv;
3441 
3442  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3443  &currentChannelMap);
3444  if (rv == -1)
3445  return;
3446 
3447  free(currentChannelMap->readerName);
3448 
3449  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3450  if (lrv < 0)
3451  {
3452  Log2(PCSC_LOG_CRITICAL,
3453  "list_delete failed with return value: %d", lrv);
3454  }
3455 
3456  free(currentChannelMap);
3457 
3458  return;
3459 }
3460 
3461 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3462  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3463 {
3464  LONG rv;
3465 
3466  if (0 == hCard)
3467  return -1;
3468 
3469  SCardLockThread();
3470  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3471  targetChannelMap);
3472 
3473  if (SCARD_S_SUCCESS == rv)
3474  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3475 
3477 
3478  return rv;
3479 }
3480 
3481 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3482  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3483 {
3484  int listSize;
3485  int list_index;
3486  SCONTEXTMAP * currentContextMap;
3487  CHANNEL_MAP * currentChannelMap;
3488 
3489  /* Best to get the caller a crash early if we fail unsafely */
3490  *targetContextMap = NULL;
3491  *targetChannelMap = NULL;
3492 
3493  listSize = list_size(&contextMapList);
3494 
3495  for (list_index = 0; list_index < listSize; list_index++)
3496  {
3497  currentContextMap = list_get_at(&contextMapList, list_index);
3498  if (currentContextMap == NULL)
3499  {
3500  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3501  list_index);
3502  continue;
3503  }
3504  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3505  &hCard);
3506  if (currentChannelMap != NULL)
3507  {
3508  *targetContextMap = currentContextMap;
3509  *targetChannelMap = currentChannelMap;
3510  return SCARD_S_SUCCESS;
3511  }
3512  }
3513 
3514  return -1;
3515 }
3516 
3525 {
3526  LONG rv;
3527  struct stat statBuffer;
3528  char *socketName;
3529 
3530  socketName = getSocketName();
3531  rv = stat(socketName, &statBuffer);
3532 
3533  if (rv != 0)
3534  {
3535  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3536  socketName, strerror(errno));
3537  return SCARD_E_NO_SERVICE;
3538  }
3539 
3540  return SCARD_S_SUCCESS;
3541 }
3542 
3543 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3544 {
3545  int32_t dwClientID = currentContextMap->dwClientID;
3546  LONG rv;
3547 
3548  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3549  if (rv != SCARD_S_SUCCESS)
3550  return rv;
3551 
3552  /* Read a message from the server */
3553  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3554  if (rv != SCARD_S_SUCCESS)
3555  return rv;
3556 
3557  return SCARD_S_SUCCESS;
3558 }
3559 
3560 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3561 {
3562  int32_t dwClientID = currentContextMap->dwClientID;
3563  LONG rv;
3564 
3565  /* Get current reader states from server and register on event list */
3567  0, NULL);
3568  if (rv != SCARD_S_SUCCESS)
3569  return rv;
3570 
3571  /* Read a message from the server */
3572  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3573  return rv;
3574 }
3575 
3576 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3577 {
3578  int32_t dwClientID = currentContextMap->dwClientID;
3579  LONG rv;
3580  struct wait_reader_state_change waitStatusStruct = {0};
3581 
3582  /* ask server to remove us from the event list */
3584  dwClientID, 0, NULL);
3585  if (rv != SCARD_S_SUCCESS)
3586  return rv;
3587 
3588  /* This message can be the response to
3589  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3590  * cancel notification.
3591  * The server side ensures, that no more messages will be sent to
3592  * the client. */
3593 
3594  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3595  dwClientID);
3596  if (rv != SCARD_S_SUCCESS)
3597  return rv;
3598 
3599  /* if we received a cancel event the return value will be set
3600  * accordingly */
3601  rv = waitStatusStruct.rv;
3602 
3603  return rv;
3604 }
3605 
#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:85
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:144
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
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:97
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:210
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:232
#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:198
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:77
#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:95
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
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:79
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:60
used by SCardEndTransaction()
Definition: winscard_msg.h:86
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:57
#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:55
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
used by SCardConnect()
Definition: winscard_msg.h:82
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:175
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:133
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:187
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:79
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:121
get the readers state
Definition: winscard_msg.h:96
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:57
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:457
used by SCardReleaseContext()
Definition: winscard_msg.h:80
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:221
#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:160
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:264
#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:110
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:83
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:138
#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:87
#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:98
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:59
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:121
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
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:88
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:61
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:52
used by SCardSetAttrib()
Definition: winscard_msg.h:94
#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:357
used by SCardDisconnect()
Definition: winscard_msg.h:84
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:249
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:93
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:56
used by SCardCancel()
Definition: winscard_msg.h:91
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:75
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:59
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:89
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:197
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