pcsc-lite  1.8.25
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  int randnum;
1252  SCONTEXTMAP * currentContextMap;
1253  CHANNEL_MAP * pChannelMap;
1254 
1255  PROFILE_START
1256  API_TRACE_IN("%ld", hCard)
1257 
1258  /*
1259  * Make sure this handle has been opened
1260  */
1261  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1262  &pChannelMap);
1263  if (rv == -1)
1264  return SCARD_E_INVALID_HANDLE;
1265 
1266  scEndStruct.hCard = hCard;
1267  scEndStruct.dwDisposition = dwDisposition;
1268  scEndStruct.rv = SCARD_S_SUCCESS;
1269 
1271  currentContextMap->dwClientID,
1272  sizeof(scEndStruct), (void *) &scEndStruct);
1273 
1274  if (rv != SCARD_S_SUCCESS)
1275  goto end;
1276 
1277  /*
1278  * Read a message from the server
1279  */
1280  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1281  currentContextMap->dwClientID);
1282 
1283  if (rv != SCARD_S_SUCCESS)
1284  goto end;
1285 
1286  /*
1287  * This helps prevent starvation
1288  */
1289  randnum = SYS_RandomInt(1000, 10000);
1290  (void)SYS_USleep(randnum);
1291  rv = scEndStruct.rv;
1292 
1293 end:
1294  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1295 
1296  PROFILE_END(rv)
1297  API_TRACE_OUT("")
1298 
1299  return rv;
1300 }
1301 
1397 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1398  LPDWORD pcchReaderLen, LPDWORD pdwState,
1399  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1400 {
1401  DWORD dwReaderLen, dwAtrLen;
1402  LONG rv;
1403  int i;
1404  struct status_struct scStatusStruct;
1405  SCONTEXTMAP * currentContextMap;
1406  CHANNEL_MAP * pChannelMap;
1407  char *r;
1408  char *bufReader = NULL;
1409  LPBYTE bufAtr = NULL;
1410  DWORD dummy = 0;
1411 
1412  PROFILE_START
1413 
1414  /* default output values */
1415  if (pdwState)
1416  *pdwState = 0;
1417 
1418  if (pdwProtocol)
1419  *pdwProtocol = 0;
1420 
1421  /* Check for NULL parameters */
1422  if (pcchReaderLen == NULL)
1423  pcchReaderLen = &dummy;
1424 
1425  if (pcbAtrLen == NULL)
1426  pcbAtrLen = &dummy;
1427 
1428  /* length passed from caller */
1429  dwReaderLen = *pcchReaderLen;
1430  dwAtrLen = *pcbAtrLen;
1431 
1432  *pcchReaderLen = 0;
1433  *pcbAtrLen = 0;
1434 
1435  /* Retry loop for blocking behaviour */
1436 retry:
1437 
1438  /*
1439  * Make sure this handle has been opened
1440  */
1441  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1442  &pChannelMap);
1443  if (rv == -1)
1444  return SCARD_E_INVALID_HANDLE;
1445 
1446  /* synchronize reader states with daemon */
1447  rv = getReaderStates(currentContextMap);
1448  if (rv != SCARD_S_SUCCESS)
1449  goto end;
1450 
1451  r = pChannelMap->readerName;
1452  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1453  {
1454  /* by default r == NULL */
1455  if (r && strcmp(r, readerStates[i].readerName) == 0)
1456  break;
1457  }
1458 
1460  {
1462  goto end;
1463  }
1464 
1465  /* initialise the structure */
1466  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1467  scStatusStruct.hCard = hCard;
1468 
1469  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1470  sizeof(scStatusStruct), (void *) &scStatusStruct);
1471 
1472  if (rv != SCARD_S_SUCCESS)
1473  goto end;
1474 
1475  /*
1476  * Read a message from the server
1477  */
1478  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1479  currentContextMap->dwClientID);
1480 
1481  if (rv != SCARD_S_SUCCESS)
1482  goto end;
1483 
1484  rv = scStatusStruct.rv;
1485 
1486  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1487  {
1488  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1490  goto retry;
1491  }
1492 
1493  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1494  {
1495  /*
1496  * An event must have occurred
1497  */
1498  goto end;
1499  }
1500 
1501  /*
1502  * Now continue with the client side SCardStatus
1503  */
1504 
1505  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1506  *pcbAtrLen = readerStates[i].cardAtrLength;
1507 
1508  if (pdwState)
1509  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1510 
1511  if (pdwProtocol)
1512  *pdwProtocol = readerStates[i].cardProtocol;
1513 
1514  if (SCARD_AUTOALLOCATE == dwReaderLen)
1515  {
1516  dwReaderLen = *pcchReaderLen;
1517  if (NULL == szReaderName)
1518  {
1520  goto end;
1521  }
1522  bufReader = malloc(dwReaderLen);
1523  if (NULL == bufReader)
1524  {
1525  rv = SCARD_E_NO_MEMORY;
1526  goto end;
1527  }
1528  *(char **)szReaderName = bufReader;
1529  }
1530  else
1531  bufReader = szReaderName;
1532 
1533  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1534  if (bufReader)
1535  {
1536  if (*pcchReaderLen > dwReaderLen)
1538 
1539  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1540  }
1541 
1542  if (SCARD_AUTOALLOCATE == dwAtrLen)
1543  {
1544  dwAtrLen = *pcbAtrLen;
1545  if (NULL == pbAtr)
1546  {
1548  goto end;
1549  }
1550  bufAtr = malloc(dwAtrLen);
1551  if (NULL == bufAtr)
1552  {
1553  rv = SCARD_E_NO_MEMORY;
1554  goto end;
1555  }
1556  *(LPBYTE *)pbAtr = bufAtr;
1557  }
1558  else
1559  bufAtr = pbAtr;
1560 
1561  if (bufAtr)
1562  {
1563  if (*pcbAtrLen > dwAtrLen)
1565 
1566  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1567  }
1568 
1569 end:
1570  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1571 
1572  PROFILE_END(rv)
1573 
1574  return rv;
1575 }
1576 
1684 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1685  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1686 {
1687  SCARD_READERSTATE *currReader;
1688  READER_STATE *rContext;
1689  long dwTime;
1690  DWORD dwBreakFlag = 0;
1691  unsigned int j;
1692  SCONTEXTMAP * currentContextMap;
1693  int currentReaderCount = 0;
1694  LONG rv = SCARD_S_SUCCESS;
1695 
1696  PROFILE_START
1697  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1698 #ifdef DO_TRACE
1699  for (j=0; j<cReaders; j++)
1700  {
1701  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1702  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1703  }
1704 #endif
1705 
1706  if ((rgReaderStates == NULL && cReaders > 0)
1707  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1708  {
1710  goto error;
1711  }
1712 
1713  /* Check the integrity of the reader states structures */
1714  for (j = 0; j < cReaders; j++)
1715  {
1716  if (rgReaderStates[j].szReader == NULL)
1717  return SCARD_E_INVALID_VALUE;
1718  }
1719 
1720  /* return if all readers are SCARD_STATE_IGNORE */
1721  if (cReaders > 0)
1722  {
1723  int nbNonIgnoredReaders = cReaders;
1724 
1725  for (j=0; j<cReaders; j++)
1726  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1727  nbNonIgnoredReaders--;
1728 
1729  if (0 == nbNonIgnoredReaders)
1730  {
1731  rv = SCARD_S_SUCCESS;
1732  goto error;
1733  }
1734  }
1735  else
1736  {
1737  /* reader list is empty */
1738  rv = SCARD_S_SUCCESS;
1739  goto error;
1740  }
1741 
1742  /*
1743  * Make sure this context has been opened
1744  */
1745  currentContextMap = SCardGetAndLockContext(hContext);
1746  if (NULL == currentContextMap)
1747  {
1749  goto error;
1750  }
1751 
1752  /* synchronize reader states with daemon */
1753  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1754  if (rv != SCARD_S_SUCCESS)
1755  goto end;
1756 
1757  /* check all the readers are already known */
1758  for (j=0; j<cReaders; j++)
1759  {
1760  const char *readerName;
1761  int i;
1762 
1763  readerName = rgReaderStates[j].szReader;
1764  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1765  {
1766  if (strcmp(readerName, readerStates[i].readerName) == 0)
1767  break;
1768  }
1769 
1770  /* The requested reader name is not recognized */
1772  {
1773  /* PnP special reader? */
1774  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1775  {
1777  goto end;
1778  }
1779  }
1780  }
1781 
1782  /* Clear the event state for all readers */
1783  for (j = 0; j < cReaders; j++)
1784  rgReaderStates[j].dwEventState = 0;
1785 
1786  /* Now is where we start our event checking loop */
1787  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1788 
1789  /* Get the initial reader count on the system */
1790  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1791  if (readerStates[j].readerName[0] != '\0')
1792  currentReaderCount++;
1793 
1794  /* catch possible sign extension problems from 32 to 64-bits integers */
1795  if ((DWORD)-1 == dwTimeout)
1796  dwTimeout = INFINITE;
1797  if (INFINITE == dwTimeout)
1798  dwTime = 60*1000; /* "infinite" timeout */
1799  else
1800  dwTime = dwTimeout;
1801 
1802  j = 0;
1803  do
1804  {
1805  currReader = &rgReaderStates[j];
1806 
1807  /* Ignore for IGNORED readers */
1808  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1809  {
1810  const char *readerName;
1811  int i;
1812 
1813  /* Looks for correct readernames */
1814  readerName = currReader->szReader;
1815  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1816  {
1817  if (strcmp(readerName, readerStates[i].readerName) == 0)
1818  break;
1819  }
1820 
1821  /* The requested reader name is not recognized */
1823  {
1824  /* PnP special reader? */
1825  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1826  {
1827  int k, newReaderCount = 0;
1828 
1829  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1830  if (readerStates[k].readerName[0] != '\0')
1831  newReaderCount++;
1832 
1833  if (newReaderCount != currentReaderCount)
1834  {
1835  Log1(PCSC_LOG_INFO, "Reader list changed");
1836  currentReaderCount = newReaderCount;
1837 
1838  currReader->dwEventState |= SCARD_STATE_CHANGED;
1839  dwBreakFlag = 1;
1840  }
1841  }
1842  else
1843  {
1844  currReader->dwEventState =
1846  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1847  {
1848  currReader->dwEventState |= SCARD_STATE_CHANGED;
1849  /*
1850  * Spec says use SCARD_STATE_IGNORE but a removed USB
1851  * reader with eventState fed into currentState will
1852  * be ignored forever
1853  */
1854  dwBreakFlag = 1;
1855  }
1856  }
1857  }
1858  else
1859  {
1860  uint32_t readerState;
1861 
1862  /* The reader has come back after being away */
1863  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1864  {
1865  currReader->dwEventState |= SCARD_STATE_CHANGED;
1866  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1867  Log0(PCSC_LOG_DEBUG);
1868  dwBreakFlag = 1;
1869  }
1870 
1871  /* Set the reader status structure */
1872  rContext = &readerStates[i];
1873 
1874  /* Now we check all the Reader States */
1875  readerState = rContext->readerState;
1876 
1877  /* only if current state has an non null event counter */
1878  if (currReader->dwCurrentState & 0xFFFF0000)
1879  {
1880  unsigned int currentCounter;
1881 
1882  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1883 
1884  /* has the event counter changed since the last call? */
1885  if (rContext->eventCounter != currentCounter)
1886  {
1887  currReader->dwEventState |= SCARD_STATE_CHANGED;
1888  Log0(PCSC_LOG_DEBUG);
1889  dwBreakFlag = 1;
1890  }
1891  }
1892 
1893  /* add an event counter in the upper word of dwEventState */
1894  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1895  | (rContext->eventCounter << 16));
1896 
1897  /* Check if the reader is in the correct state */
1898  if (readerState & SCARD_UNKNOWN)
1899  {
1900  /* reader is in bad state */
1901  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1902  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1903  {
1904  /* App thinks reader is in good state and it is not */
1905  currReader->dwEventState |= SCARD_STATE_CHANGED;
1906  Log0(PCSC_LOG_DEBUG);
1907  dwBreakFlag = 1;
1908  }
1909  }
1910  else
1911  {
1912  /* App thinks reader in bad state but it is not */
1913  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1914  {
1915  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1916  currReader->dwEventState |= SCARD_STATE_CHANGED;
1917  Log0(PCSC_LOG_DEBUG);
1918  dwBreakFlag = 1;
1919  }
1920  }
1921 
1922  /* Check for card presence in the reader */
1923  if (readerState & SCARD_PRESENT)
1924  {
1925  /* card present but not yet powered up */
1926  if (0 == rContext->cardAtrLength)
1927  /* Allow the status thread to convey information */
1929 
1930  currReader->cbAtr = rContext->cardAtrLength;
1931  memcpy(currReader->rgbAtr, rContext->cardAtr,
1932  currReader->cbAtr);
1933  }
1934  else
1935  currReader->cbAtr = 0;
1936 
1937  /* Card is now absent */
1938  if (readerState & SCARD_ABSENT)
1939  {
1940  currReader->dwEventState |= SCARD_STATE_EMPTY;
1941  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1942  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1943  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1944  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1945  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1946  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1947  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1948  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1949 
1950  /* After present the rest are assumed */
1951  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1952  {
1953  currReader->dwEventState |= SCARD_STATE_CHANGED;
1954  Log0(PCSC_LOG_DEBUG);
1955  dwBreakFlag = 1;
1956  }
1957  }
1958  /* Card is now present */
1959  else if (readerState & SCARD_PRESENT)
1960  {
1961  currReader->dwEventState |= SCARD_STATE_PRESENT;
1962  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1963  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1964  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1965  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1966  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1967  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1968 
1969  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1970  {
1971  currReader->dwEventState |= SCARD_STATE_CHANGED;
1972  Log0(PCSC_LOG_DEBUG);
1973  dwBreakFlag = 1;
1974  }
1975 
1976  if (readerState & SCARD_SWALLOWED)
1977  {
1978  currReader->dwEventState |= SCARD_STATE_MUTE;
1979  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1980  {
1981  currReader->dwEventState |= SCARD_STATE_CHANGED;
1982  Log0(PCSC_LOG_DEBUG);
1983  dwBreakFlag = 1;
1984  }
1985  }
1986  else
1987  {
1988  /* App thinks card is mute but it is not */
1989  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1990  {
1991  currReader->dwEventState |= SCARD_STATE_CHANGED;
1992  Log0(PCSC_LOG_DEBUG);
1993  dwBreakFlag = 1;
1994  }
1995  }
1996  }
1997 
1998  /* Now figure out sharing modes */
2000  {
2001  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2002  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2003  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2004  {
2005  currReader->dwEventState |= SCARD_STATE_CHANGED;
2006  Log0(PCSC_LOG_DEBUG);
2007  dwBreakFlag = 1;
2008  }
2009  }
2010  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2011  {
2012  /* A card must be inserted for it to be INUSE */
2013  if (readerState & SCARD_PRESENT)
2014  {
2015  currReader->dwEventState |= SCARD_STATE_INUSE;
2016  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2017  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2018  {
2019  currReader->dwEventState |= SCARD_STATE_CHANGED;
2020  Log0(PCSC_LOG_DEBUG);
2021  dwBreakFlag = 1;
2022  }
2023  }
2024  }
2025  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2026  {
2027  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2028  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2029 
2030  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2031  {
2032  currReader->dwEventState |= SCARD_STATE_CHANGED;
2033  Log0(PCSC_LOG_DEBUG);
2034  dwBreakFlag = 1;
2035  }
2036  else if (currReader-> dwCurrentState
2038  {
2039  currReader->dwEventState |= SCARD_STATE_CHANGED;
2040  Log0(PCSC_LOG_DEBUG);
2041  dwBreakFlag = 1;
2042  }
2043  }
2044 
2045  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2046  {
2047  /*
2048  * Break out of the while .. loop and return status
2049  * once all the status's for all readers is met
2050  */
2051  currReader->dwEventState |= SCARD_STATE_CHANGED;
2052  Log0(PCSC_LOG_DEBUG);
2053  dwBreakFlag = 1;
2054  }
2055  } /* End of SCARD_STATE_UNKNOWN */
2056  } /* End of SCARD_STATE_IGNORE */
2057 
2058  /* Counter and resetter */
2059  j++;
2060  if (j == cReaders)
2061  {
2062  /* go back to the first reader */
2063  j = 0;
2064 
2065  /* Declare all the break conditions */
2066 
2067  /* Break if UNAWARE is set and all readers have been checked */
2068  if (dwBreakFlag == 1)
2069  break;
2070 
2071  /* Only sleep once for each cycle of reader checks. */
2072  {
2073  struct wait_reader_state_change waitStatusStruct = {0};
2074  struct timeval before, after;
2075 
2076  gettimeofday(&before, NULL);
2077 
2078  waitStatusStruct.rv = SCARD_S_SUCCESS;
2079 
2080  /* another thread can do SCardCancel() */
2081  currentContextMap->cancellable = TRUE;
2082 
2083  /*
2084  * Read a message from the server
2085  */
2087  &waitStatusStruct, sizeof(waitStatusStruct),
2088  currentContextMap->dwClientID, dwTime);
2089 
2090  /* SCardCancel() will return immediatly with success
2091  * because something changed on the daemon side. */
2092  currentContextMap->cancellable = FALSE;
2093 
2094  /* timeout */
2095  if (SCARD_E_TIMEOUT == rv)
2096  {
2097  /* ask server to remove us from the event list */
2098  rv = unregisterFromEvents(currentContextMap);
2099  }
2100 
2101  if (rv != SCARD_S_SUCCESS)
2102  goto end;
2103 
2104  /* an event occurs or SCardCancel() was called */
2105  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2106  {
2107  rv = waitStatusStruct.rv;
2108  goto end;
2109  }
2110 
2111  /* synchronize reader states with daemon */
2112  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2113  if (rv != SCARD_S_SUCCESS)
2114  goto end;
2115 
2116  if (INFINITE != dwTimeout)
2117  {
2118  long int diff;
2119 
2120  gettimeofday(&after, NULL);
2121  diff = time_sub(&after, &before);
2122  dwTime -= diff/1000;
2123  }
2124  }
2125 
2126  if (dwTimeout != INFINITE)
2127  {
2128  /* If time is greater than timeout and all readers have been
2129  * checked
2130  */
2131  if (dwTime <= 0)
2132  {
2133  rv = SCARD_E_TIMEOUT;
2134  goto end;
2135  }
2136  }
2137  }
2138  }
2139  while (1);
2140 
2141 end:
2142  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2143 
2144  /* if SCardCancel() has been used then the client is already
2145  * unregistered */
2146  if (SCARD_E_CANCELLED != rv)
2147  (void)unregisterFromEvents(currentContextMap);
2148 
2149  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2150 
2151 error:
2152  PROFILE_END(rv)
2153 #ifdef DO_TRACE
2154  for (j=0; j<cReaders; j++)
2155  {
2156  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2157  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2158  }
2159 #endif
2160 
2161  return rv;
2162 }
2163 
2214 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2215  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2216  LPDWORD lpBytesReturned)
2217 {
2218  LONG rv;
2219  struct control_struct scControlStruct;
2220  SCONTEXTMAP * currentContextMap;
2221  CHANNEL_MAP * pChannelMap;
2222 
2223  PROFILE_START
2224 
2225  /* 0 bytes received by default */
2226  if (NULL != lpBytesReturned)
2227  *lpBytesReturned = 0;
2228 
2229  /*
2230  * Make sure this handle has been opened
2231  */
2232  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2233  &pChannelMap);
2234  if (rv == -1)
2235  {
2236  PROFILE_END(SCARD_E_INVALID_HANDLE)
2237  return SCARD_E_INVALID_HANDLE;
2238  }
2239 
2240  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2241  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2242  {
2244  goto end;
2245  }
2246 
2247  scControlStruct.hCard = hCard;
2248  scControlStruct.dwControlCode = dwControlCode;
2249  scControlStruct.cbSendLength = cbSendLength;
2250  scControlStruct.cbRecvLength = cbRecvLength;
2251  scControlStruct.dwBytesReturned = 0;
2252  scControlStruct.rv = 0;
2253 
2254  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2255  sizeof(scControlStruct), &scControlStruct);
2256 
2257  if (rv != SCARD_S_SUCCESS)
2258  goto end;
2259 
2260  /* write the sent buffer */
2261  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2262  currentContextMap->dwClientID);
2263 
2264  if (rv != SCARD_S_SUCCESS)
2265  goto end;
2266 
2267  /*
2268  * Read a message from the server
2269  */
2270  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2271  currentContextMap->dwClientID);
2272 
2273  if (rv != SCARD_S_SUCCESS)
2274  goto end;
2275 
2276  if (SCARD_S_SUCCESS == scControlStruct.rv)
2277  {
2278  /* read the received buffer */
2279  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2280  currentContextMap->dwClientID);
2281 
2282  if (rv != SCARD_S_SUCCESS)
2283  goto end;
2284 
2285  }
2286 
2287  if (NULL != lpBytesReturned)
2288  *lpBytesReturned = scControlStruct.dwBytesReturned;
2289 
2290  rv = scControlStruct.rv;
2291 
2292 end:
2293  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2294 
2295  PROFILE_END(rv)
2296 
2297  return rv;
2298 }
2299 
2415 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2416  LPDWORD pcbAttrLen)
2417 {
2418  LONG ret;
2419  unsigned char *buf = NULL;
2420 
2421  PROFILE_START
2422 
2423  if (NULL == pcbAttrLen)
2424  {
2426  goto end;
2427  }
2428 
2429  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2430  {
2431  if (NULL == pbAttr)
2433 
2434  *pcbAttrLen = MAX_BUFFER_SIZE;
2435  buf = malloc(*pcbAttrLen);
2436  if (NULL == buf)
2437  {
2438  ret = SCARD_E_NO_MEMORY;
2439  goto end;
2440  }
2441 
2442  *(unsigned char **)pbAttr = buf;
2443  }
2444  else
2445  {
2446  buf = pbAttr;
2447 
2448  /* if only get the length */
2449  if (NULL == pbAttr)
2450  /* use a reasonable size */
2451  *pcbAttrLen = MAX_BUFFER_SIZE;
2452  }
2453 
2454  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2455  pcbAttrLen);
2456 
2457 end:
2458  PROFILE_END(ret)
2459 
2460  return ret;
2461 }
2462 
2498 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2499  DWORD cbAttrLen)
2500 {
2501  LONG ret;
2502 
2503  PROFILE_START
2504 
2505  if (NULL == pbAttr || 0 == cbAttrLen)
2507 
2508  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2509  &cbAttrLen);
2510 
2511  PROFILE_END(ret)
2512 
2513  return ret;
2514 }
2515 
2516 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2517  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2518 {
2519  LONG rv;
2520  struct getset_struct scGetSetStruct;
2521  SCONTEXTMAP * currentContextMap;
2522  CHANNEL_MAP * pChannelMap;
2523 
2524  /*
2525  * Make sure this handle has been opened
2526  */
2527  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2528  &pChannelMap);
2529  if (rv == -1)
2530  return SCARD_E_INVALID_HANDLE;
2531 
2532  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2533  {
2535  goto end;
2536  }
2537 
2538  scGetSetStruct.hCard = hCard;
2539  scGetSetStruct.dwAttrId = dwAttrId;
2540  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2541  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2542  if (SCARD_SET_ATTRIB == command)
2543  {
2544  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2545  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2546  }
2547  else
2548  /* we can get up to the communication buffer size */
2549  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2550 
2551  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2552  sizeof(scGetSetStruct), &scGetSetStruct);
2553 
2554  if (rv != SCARD_S_SUCCESS)
2555  goto end;
2556 
2557  /*
2558  * Read a message from the server
2559  */
2560  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2561  currentContextMap->dwClientID);
2562 
2563  if (rv != SCARD_S_SUCCESS)
2564  goto end;
2565 
2566  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2567  {
2568  /*
2569  * Copy and zero it so any secret information is not leaked
2570  */
2571  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2572  {
2573  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2574  * buffer overflow in the memcpy() bellow */
2575  DWORD correct_value = scGetSetStruct.cbAttrLen;
2576  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2577  *pcbAttrLen = correct_value;
2578 
2579  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2580  }
2581  else
2582  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2583 
2584  if (pbAttr)
2585  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2586 
2587  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2588  }
2589  rv = scGetSetStruct.rv;
2590 
2591 end:
2592  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2593 
2594  return rv;
2595 }
2596 
2655 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2656  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2657  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2658  LPDWORD pcbRecvLength)
2659 {
2660  LONG rv;
2661  SCONTEXTMAP * currentContextMap;
2662  CHANNEL_MAP * pChannelMap;
2663  struct transmit_struct scTransmitStruct;
2664 
2665  PROFILE_START
2666 
2667  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2668  pcbRecvLength == NULL || pioSendPci == NULL)
2670 
2671  /* Retry loop for blocking behaviour */
2672 retry:
2673 
2674  /*
2675  * Make sure this handle has been opened
2676  */
2677  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2678  &pChannelMap);
2679  if (rv == -1)
2680  {
2681  *pcbRecvLength = 0;
2682  PROFILE_END(SCARD_E_INVALID_HANDLE)
2683  return SCARD_E_INVALID_HANDLE;
2684  }
2685 
2686  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2687  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2688  {
2690  goto end;
2691  }
2692 
2693  scTransmitStruct.hCard = hCard;
2694  scTransmitStruct.cbSendLength = cbSendLength;
2695  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2696  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2697  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2698  scTransmitStruct.rv = SCARD_S_SUCCESS;
2699 
2700  if (pioRecvPci)
2701  {
2702  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2703  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2704  }
2705  else
2706  {
2707  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2708  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2709  }
2710 
2711  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2712  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2713 
2714  if (rv != SCARD_S_SUCCESS)
2715  goto end;
2716 
2717  /* write the sent buffer */
2718  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2719  currentContextMap->dwClientID);
2720 
2721  if (rv != SCARD_S_SUCCESS)
2722  goto end;
2723 
2724  /*
2725  * Read a message from the server
2726  */
2727  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2728  currentContextMap->dwClientID);
2729 
2730  if (rv != SCARD_S_SUCCESS)
2731  goto end;
2732 
2733  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2734  {
2735  /* read the received buffer */
2736  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2737  currentContextMap->dwClientID);
2738 
2739  if (rv != SCARD_S_SUCCESS)
2740  goto end;
2741 
2742  if (pioRecvPci)
2743  {
2744  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2745  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2746  }
2747  }
2748 
2749  rv = scTransmitStruct.rv;
2750 
2751  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2752  {
2753  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2755  goto retry;
2756  }
2757 
2758  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2759 
2760 end:
2761  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2762 
2763  PROFILE_END(rv)
2764 
2765  return rv;
2766 }
2767 
2830 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2831  LPSTR mszReaders, LPDWORD pcchReaders)
2832 {
2833  DWORD dwReadersLen = 0;
2834  int i;
2835  SCONTEXTMAP * currentContextMap;
2836  LONG rv = SCARD_S_SUCCESS;
2837  char *buf = NULL;
2838 
2839  (void)mszGroups;
2840  PROFILE_START
2841  API_TRACE_IN("%ld", hContext)
2842 
2843  /*
2844  * Check for NULL parameters
2845  */
2846  if (pcchReaders == NULL)
2848 
2849  /*
2850  * Make sure this context has been opened
2851  */
2852  currentContextMap = SCardGetAndLockContext(hContext);
2853  if (NULL == currentContextMap)
2854  {
2855  PROFILE_END(SCARD_E_INVALID_HANDLE)
2856  return SCARD_E_INVALID_HANDLE;
2857  }
2858 
2859  /* synchronize reader states with daemon */
2860  rv = getReaderStates(currentContextMap);
2861  if (rv != SCARD_S_SUCCESS)
2862  goto end;
2863 
2864  dwReadersLen = 0;
2865  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2866  if (readerStates[i].readerName[0] != '\0')
2867  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2868 
2869  /* for the last NULL byte */
2870  dwReadersLen += 1;
2871 
2872  if (1 == dwReadersLen)
2873  {
2875  goto end;
2876  }
2877 
2878  if (SCARD_AUTOALLOCATE == *pcchReaders)
2879  {
2880  if (NULL == mszReaders)
2881  {
2883  goto end;
2884  }
2885  buf = malloc(dwReadersLen);
2886  if (NULL == buf)
2887  {
2888  rv = SCARD_E_NO_MEMORY;
2889  goto end;
2890  }
2891  *(char **)mszReaders = buf;
2892  }
2893  else
2894  {
2895  buf = mszReaders;
2896 
2897  /* not enough place to store the reader names */
2898  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2899  {
2901  goto end;
2902  }
2903  }
2904 
2905  if (mszReaders == NULL) /* text array not allocated */
2906  goto end;
2907 
2908  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2909  {
2910  if (readerStates[i].readerName[0] != '\0')
2911  {
2912  /*
2913  * Build the multi-string
2914  */
2915  strcpy(buf, readerStates[i].readerName);
2916  buf += strlen(readerStates[i].readerName)+1;
2917  }
2918  }
2919  *buf = '\0'; /* Add the last null */
2920 
2921 end:
2922  /* set the reader names length */
2923  *pcchReaders = dwReadersLen;
2924 
2925  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2926 
2927  PROFILE_END(rv)
2928  API_TRACE_OUT("%d", *pcchReaders)
2929 
2930  return rv;
2931 }
2932 
2946 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2947 {
2948  LONG rv = SCARD_S_SUCCESS;
2949 
2950  PROFILE_START
2951 
2952  /*
2953  * Make sure this context has been opened
2954  */
2955  if (! SCardGetContextValidity(hContext))
2956  return SCARD_E_INVALID_HANDLE;
2957 
2958  free((void *)pvMem);
2959 
2960  PROFILE_END(rv)
2961 
2962  return rv;
2963 }
2964 
3016 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3017  LPDWORD pcchGroups)
3018 {
3019  LONG rv = SCARD_S_SUCCESS;
3020  SCONTEXTMAP * currentContextMap;
3021  char *buf = NULL;
3022 
3023  PROFILE_START
3024 
3025  /* Multi-string with two trailing \0 */
3026  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3027  const unsigned int dwGroups = sizeof(ReaderGroup);
3028 
3029  /*
3030  * Make sure this context has been opened
3031  */
3032  currentContextMap = SCardGetAndLockContext(hContext);
3033  if (NULL == currentContextMap)
3034  return SCARD_E_INVALID_HANDLE;
3035 
3036  if (SCARD_AUTOALLOCATE == *pcchGroups)
3037  {
3038  if (NULL == mszGroups)
3039  {
3041  goto end;
3042  }
3043  buf = malloc(dwGroups);
3044  if (NULL == buf)
3045  {
3046  rv = SCARD_E_NO_MEMORY;
3047  goto end;
3048  }
3049  *(char **)mszGroups = buf;
3050  }
3051  else
3052  {
3053  buf = mszGroups;
3054 
3055  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3056  {
3058  goto end;
3059  }
3060  }
3061 
3062  if (buf)
3063  memcpy(buf, ReaderGroup, dwGroups);
3064 
3065 end:
3066  *pcchGroups = dwGroups;
3067 
3068  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3069 
3070  PROFILE_END(rv)
3071 
3072  return rv;
3073 }
3074 
3107 {
3108  SCONTEXTMAP * currentContextMap;
3109  LONG rv = SCARD_S_SUCCESS;
3110  uint32_t dwClientID = 0;
3111  struct cancel_struct scCancelStruct;
3112  char cancellable;
3113 
3114  PROFILE_START
3115  API_TRACE_IN("%ld", hContext)
3116 
3117  /*
3118  * Make sure this context has been opened
3119  */
3120  (void)SCardLockThread();
3121  currentContextMap = SCardGetContextTH(hContext);
3122 
3123  if (NULL == currentContextMap)
3124  {
3125  (void)SCardUnlockThread();
3127  goto error;
3128  }
3129  cancellable = currentContextMap->cancellable;
3130  (void)SCardUnlockThread();
3131 
3132  if (! cancellable)
3133  {
3134  rv = SCARD_S_SUCCESS;
3135  goto error;
3136  }
3137 
3138  /* create a new connection to the server */
3139  if (ClientSetupSession(&dwClientID) != 0)
3140  {
3141  rv = SCARD_E_NO_SERVICE;
3142  goto error;
3143  }
3144 
3145  scCancelStruct.hContext = hContext;
3146  scCancelStruct.rv = SCARD_S_SUCCESS;
3147 
3148  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3149  sizeof(scCancelStruct), (void *) &scCancelStruct);
3150 
3151  if (rv != SCARD_S_SUCCESS)
3152  goto end;
3153 
3154  /*
3155  * Read a message from the server
3156  */
3157  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3158 
3159  if (rv != SCARD_S_SUCCESS)
3160  goto end;
3161 
3162  rv = scCancelStruct.rv;
3163 end:
3164  ClientCloseSession(dwClientID);
3165 
3166 error:
3167  PROFILE_END(rv)
3168  API_TRACE_OUT("")
3169 
3170  return rv;
3171 }
3172 
3197 {
3198  LONG rv;
3199 
3200  PROFILE_START
3201  API_TRACE_IN("%ld", hContext)
3202 
3203  rv = SCARD_S_SUCCESS;
3204 
3205  /*
3206  * Make sure this context has been opened
3207  */
3208  if (! SCardGetContextValidity(hContext))
3210 
3211  PROFILE_END(rv)
3212  API_TRACE_OUT("")
3213 
3214  return rv;
3215 }
3216 
3233 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3234 {
3235  int lrv;
3236  SCONTEXTMAP * newContextMap;
3237 
3238  newContextMap = malloc(sizeof(SCONTEXTMAP));
3239  if (NULL == newContextMap)
3240  return SCARD_E_NO_MEMORY;
3241 
3242  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3243  newContextMap->hContext = hContext;
3244  newContextMap->dwClientID = dwClientID;
3245  newContextMap->cancellable = FALSE;
3246 
3247  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3248 
3249  lrv = list_init(&newContextMap->channelMapList);
3250  if (lrv < 0)
3251  {
3252  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3253  goto error;
3254  }
3255 
3256  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3257  CHANNEL_MAP_seeker);
3258  if (lrv <0)
3259  {
3260  Log2(PCSC_LOG_CRITICAL,
3261  "list_attributes_seeker failed with return value: %d", lrv);
3262  list_destroy(&newContextMap->channelMapList);
3263  goto error;
3264  }
3265 
3266  lrv = list_append(&contextMapList, newContextMap);
3267  if (lrv < 0)
3268  {
3269  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3270  lrv);
3271  list_destroy(&newContextMap->channelMapList);
3272  goto error;
3273  }
3274 
3275  return SCARD_S_SUCCESS;
3276 
3277 error:
3278 
3279  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3280  free(newContextMap);
3281 
3282  return SCARD_E_NO_MEMORY;
3283 }
3284 
3302 {
3303  SCONTEXTMAP * currentContextMap;
3304 
3305  SCardLockThread();
3306  currentContextMap = SCardGetContextTH(hContext);
3307 
3308  /* lock the context (if available) */
3309  if (NULL != currentContextMap)
3310  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3311 
3313 
3314  return currentContextMap;
3315 }
3316 
3330 {
3331  return list_seek(&contextMapList, &hContext);
3332 }
3333 
3343 static void SCardRemoveContext(SCARDCONTEXT hContext)
3344 {
3345  SCONTEXTMAP * currentContextMap;
3346  currentContextMap = SCardGetContextTH(hContext);
3347 
3348  if (NULL != currentContextMap)
3349  SCardCleanContext(currentContextMap);
3350 }
3351 
3352 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3353 {
3354  int list_index, lrv;
3355  int listSize;
3356  CHANNEL_MAP * currentChannelMap;
3357 
3358  targetContextMap->hContext = 0;
3359  ClientCloseSession(targetContextMap->dwClientID);
3360  targetContextMap->dwClientID = 0;
3361  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3362 
3363  listSize = list_size(&targetContextMap->channelMapList);
3364  for (list_index = 0; list_index < listSize; list_index++)
3365  {
3366  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3367  list_index);
3368  if (NULL == currentChannelMap)
3369  {
3370  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3371  list_index);
3372  continue;
3373  }
3374  else
3375  {
3376  free(currentChannelMap->readerName);
3377  free(currentChannelMap);
3378  }
3379 
3380  }
3381  list_destroy(&targetContextMap->channelMapList);
3382 
3383  lrv = list_delete(&contextMapList, targetContextMap);
3384  if (lrv < 0)
3385  {
3386  Log2(PCSC_LOG_CRITICAL,
3387  "list_delete failed with return value: %d", lrv);
3388  }
3389 
3390  free(targetContextMap);
3391 
3392  return;
3393 }
3394 
3395 /*
3396  * Functions for managing hCard values returned from SCardConnect.
3397  */
3398 
3399 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3400  LPCSTR readerName)
3401 {
3402  CHANNEL_MAP * newChannelMap;
3403  int lrv = -1;
3404 
3405  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3406  if (NULL == newChannelMap)
3407  return SCARD_E_NO_MEMORY;
3408 
3409  newChannelMap->hCard = hCard;
3410  newChannelMap->readerName = strdup(readerName);
3411 
3412  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3413  if (lrv < 0)
3414  {
3415  free(newChannelMap->readerName);
3416  free(newChannelMap);
3417  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3418  lrv);
3419  return SCARD_E_NO_MEMORY;
3420  }
3421 
3422  return SCARD_S_SUCCESS;
3423 }
3424 
3425 static void SCardRemoveHandle(SCARDHANDLE hCard)
3426 {
3427  SCONTEXTMAP * currentContextMap;
3428  CHANNEL_MAP * currentChannelMap;
3429  int lrv;
3430  LONG rv;
3431 
3432  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3433  &currentChannelMap);
3434  if (rv == -1)
3435  return;
3436 
3437  free(currentChannelMap->readerName);
3438 
3439  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3440  if (lrv < 0)
3441  {
3442  Log2(PCSC_LOG_CRITICAL,
3443  "list_delete failed with return value: %d", lrv);
3444  }
3445 
3446  free(currentChannelMap);
3447 
3448  return;
3449 }
3450 
3451 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3452  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3453 {
3454  LONG rv;
3455 
3456  if (0 == hCard)
3457  return -1;
3458 
3459  SCardLockThread();
3460  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3461  targetChannelMap);
3462 
3463  if (SCARD_S_SUCCESS == rv)
3464  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3465 
3467 
3468  return rv;
3469 }
3470 
3471 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3472  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3473 {
3474  int listSize;
3475  int list_index;
3476  SCONTEXTMAP * currentContextMap;
3477  CHANNEL_MAP * currentChannelMap;
3478 
3479  /* Best to get the caller a crash early if we fail unsafely */
3480  *targetContextMap = NULL;
3481  *targetChannelMap = NULL;
3482 
3483  listSize = list_size(&contextMapList);
3484 
3485  for (list_index = 0; list_index < listSize; list_index++)
3486  {
3487  currentContextMap = list_get_at(&contextMapList, list_index);
3488  if (currentContextMap == NULL)
3489  {
3490  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3491  list_index);
3492  continue;
3493  }
3494  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3495  &hCard);
3496  if (currentChannelMap != NULL)
3497  {
3498  *targetContextMap = currentContextMap;
3499  *targetChannelMap = currentChannelMap;
3500  return SCARD_S_SUCCESS;
3501  }
3502  }
3503 
3504  return -1;
3505 }
3506 
3515 {
3516  LONG rv;
3517  struct stat statBuffer;
3518  char *socketName;
3519 
3520  socketName = getSocketName();
3521  rv = stat(socketName, &statBuffer);
3522 
3523  if (rv != 0)
3524  {
3525  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3526  socketName, strerror(errno));
3527  return SCARD_E_NO_SERVICE;
3528  }
3529 
3530  return SCARD_S_SUCCESS;
3531 }
3532 
3533 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3534 {
3535  int32_t dwClientID = currentContextMap->dwClientID;
3536  LONG rv;
3537 
3538  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3539  if (rv != SCARD_S_SUCCESS)
3540  return rv;
3541 
3542  /* Read a message from the server */
3543  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3544  if (rv != SCARD_S_SUCCESS)
3545  return rv;
3546 
3547  return SCARD_S_SUCCESS;
3548 }
3549 
3550 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3551 {
3552  int32_t dwClientID = currentContextMap->dwClientID;
3553  LONG rv;
3554 
3555  /* Get current reader states from server and register on event list */
3557  0, NULL);
3558  if (rv != SCARD_S_SUCCESS)
3559  return rv;
3560 
3561  /* Read a message from the server */
3562  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3563  return rv;
3564 }
3565 
3566 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3567 {
3568  int32_t dwClientID = currentContextMap->dwClientID;
3569  LONG rv;
3570  struct wait_reader_state_change waitStatusStruct = {0};
3571 
3572  /* ask server to remove us from the event list */
3574  dwClientID, 0, NULL);
3575  if (rv != SCARD_S_SUCCESS)
3576  return rv;
3577 
3578  /* This message can be the response to
3579  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3580  * cancel notification.
3581  * The server side ensures, that no more messages will be sent to
3582  * the client. */
3583 
3584  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3585  dwClientID);
3586  if (rv != SCARD_S_SUCCESS)
3587  return rv;
3588 
3589  /* if we received a cancel event the return value will be set
3590  * accordingly */
3591  rv = waitStatusStruct.rv;
3592 
3593  return rv;
3594 }
3595 
#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