pcsc-lite  1.9.5
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  /* card present but not yet powered up */
1920  if (0 == rContext->cardAtrLength)
1921  /* Allow the status thread to convey information */
1923 
1924  currReader->cbAtr = rContext->cardAtrLength;
1925  memcpy(currReader->rgbAtr, rContext->cardAtr,
1926  currReader->cbAtr);
1927  }
1928  else
1929  currReader->cbAtr = 0;
1930 
1931  /* Card is now absent */
1932  if (readerState & SCARD_ABSENT)
1933  {
1934  currReader->dwEventState |= SCARD_STATE_EMPTY;
1935  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1936  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1937  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1938  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1939  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1940  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1941  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1942  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1943 
1944  /* After present the rest are assumed */
1945  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1946  {
1947  currReader->dwEventState |= SCARD_STATE_CHANGED;
1948  Log0(PCSC_LOG_DEBUG);
1949  dwBreakFlag = 1;
1950  }
1951  }
1952  /* Card is now present */
1953  else if (readerState & SCARD_PRESENT)
1954  {
1955  currReader->dwEventState |= SCARD_STATE_PRESENT;
1956  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1957  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1958  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1959  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1960  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1961  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1962 
1963  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1964  {
1965  currReader->dwEventState |= SCARD_STATE_CHANGED;
1966  Log0(PCSC_LOG_DEBUG);
1967  dwBreakFlag = 1;
1968  }
1969 
1970  if (readerState & SCARD_SWALLOWED)
1971  {
1972  currReader->dwEventState |= SCARD_STATE_MUTE;
1973  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1974  {
1975  currReader->dwEventState |= SCARD_STATE_CHANGED;
1976  Log0(PCSC_LOG_DEBUG);
1977  dwBreakFlag = 1;
1978  }
1979  }
1980  else
1981  {
1982  /* App thinks card is mute but it is not */
1983  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1984  {
1985  currReader->dwEventState |= SCARD_STATE_CHANGED;
1986  Log0(PCSC_LOG_DEBUG);
1987  dwBreakFlag = 1;
1988  }
1989  }
1990  }
1991 
1992  /* Now figure out sharing modes */
1994  {
1995  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1996  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1997  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1998  {
1999  currReader->dwEventState |= SCARD_STATE_CHANGED;
2000  Log0(PCSC_LOG_DEBUG);
2001  dwBreakFlag = 1;
2002  }
2003  }
2004  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2005  {
2006  /* A card must be inserted for it to be INUSE */
2007  if (readerState & SCARD_PRESENT)
2008  {
2009  currReader->dwEventState |= SCARD_STATE_INUSE;
2010  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2011  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2012  {
2013  currReader->dwEventState |= SCARD_STATE_CHANGED;
2014  Log0(PCSC_LOG_DEBUG);
2015  dwBreakFlag = 1;
2016  }
2017  }
2018  }
2019  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2020  {
2021  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2022  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2023 
2024  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2025  {
2026  currReader->dwEventState |= SCARD_STATE_CHANGED;
2027  Log0(PCSC_LOG_DEBUG);
2028  dwBreakFlag = 1;
2029  }
2030  else if (currReader-> dwCurrentState
2032  {
2033  currReader->dwEventState |= SCARD_STATE_CHANGED;
2034  Log0(PCSC_LOG_DEBUG);
2035  dwBreakFlag = 1;
2036  }
2037  }
2038 
2039  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2040  {
2041  /*
2042  * Break out of the while .. loop and return status
2043  * once all the status's for all readers is met
2044  */
2045  currReader->dwEventState |= SCARD_STATE_CHANGED;
2046  Log0(PCSC_LOG_DEBUG);
2047  dwBreakFlag = 1;
2048  }
2049  } /* End of SCARD_STATE_UNKNOWN */
2050  } /* End of SCARD_STATE_IGNORE */
2051 
2052  /* Counter and resetter */
2053  j++;
2054  if (j == cReaders)
2055  {
2056  /* go back to the first reader */
2057  j = 0;
2058 
2059  /* Declare all the break conditions */
2060 
2061  /* Break if UNAWARE is set and all readers have been checked */
2062  if (dwBreakFlag == 1)
2063  break;
2064 
2065  /* Only sleep once for each cycle of reader checks. */
2066  {
2067  struct wait_reader_state_change waitStatusStruct = {0};
2068  struct timeval before, after;
2069 
2070  gettimeofday(&before, NULL);
2071 
2072  waitStatusStruct.rv = SCARD_S_SUCCESS;
2073 
2074  /* another thread can do SCardCancel() */
2075  currentContextMap->cancellable = TRUE;
2076 
2077  /*
2078  * Read a message from the server
2079  */
2081  &waitStatusStruct, sizeof(waitStatusStruct),
2082  currentContextMap->dwClientID, dwTime);
2083 
2084  /* SCardCancel() will return immediatly with success
2085  * because something changed on the daemon side. */
2086  currentContextMap->cancellable = FALSE;
2087 
2088  /* timeout */
2089  if (SCARD_E_TIMEOUT == rv)
2090  {
2091  /* ask server to remove us from the event list */
2092  rv = unregisterFromEvents(currentContextMap);
2093  }
2094 
2095  if (rv != SCARD_S_SUCCESS)
2096  goto end;
2097 
2098  /* an event occurs or SCardCancel() was called */
2099  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2100  {
2101  rv = waitStatusStruct.rv;
2102  goto end;
2103  }
2104 
2105  /* synchronize reader states with daemon */
2106  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2107  if (rv != SCARD_S_SUCCESS)
2108  goto end;
2109 
2110  if (INFINITE != dwTimeout)
2111  {
2112  long int diff;
2113 
2114  gettimeofday(&after, NULL);
2115  diff = time_sub(&after, &before);
2116  dwTime -= diff/1000;
2117  }
2118  }
2119 
2120  if (dwTimeout != INFINITE)
2121  {
2122  /* If time is greater than timeout and all readers have been
2123  * checked
2124  */
2125  if (dwTime <= 0)
2126  {
2127  rv = SCARD_E_TIMEOUT;
2128  goto end;
2129  }
2130  }
2131  }
2132  }
2133  while (1);
2134 
2135 end:
2136  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2137 
2138  /* if SCardCancel() has been used then the client is already
2139  * unregistered */
2140  if (SCARD_E_CANCELLED != rv)
2141  (void)unregisterFromEvents(currentContextMap);
2142 
2143  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2144 
2145 error:
2146  PROFILE_END(rv)
2147 #ifdef DO_TRACE
2148  for (j=0; j<cReaders; j++)
2149  {
2150  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2151  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2152  }
2153 #endif
2154 
2155  return rv;
2156 }
2157 
2208 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2209  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2210  LPDWORD lpBytesReturned)
2211 {
2212  LONG rv;
2213  struct control_struct scControlStruct;
2214  SCONTEXTMAP * currentContextMap;
2215  CHANNEL_MAP * pChannelMap;
2216 
2217  PROFILE_START
2218 
2219  /* 0 bytes received by default */
2220  if (NULL != lpBytesReturned)
2221  *lpBytesReturned = 0;
2222 
2223  /*
2224  * Make sure this handle has been opened
2225  */
2226  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2227  &pChannelMap);
2228  if (rv == -1)
2229  {
2230  PROFILE_END(SCARD_E_INVALID_HANDLE)
2231  return SCARD_E_INVALID_HANDLE;
2232  }
2233 
2234  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2235  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2236  {
2238  goto end;
2239  }
2240 
2241  scControlStruct.hCard = hCard;
2242  scControlStruct.dwControlCode = dwControlCode;
2243  scControlStruct.cbSendLength = cbSendLength;
2244  scControlStruct.cbRecvLength = cbRecvLength;
2245  scControlStruct.dwBytesReturned = 0;
2246  scControlStruct.rv = 0;
2247 
2248  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2249  sizeof(scControlStruct), &scControlStruct);
2250 
2251  if (rv != SCARD_S_SUCCESS)
2252  goto end;
2253 
2254  /* write the sent buffer */
2255  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2256  currentContextMap->dwClientID);
2257 
2258  if (rv != SCARD_S_SUCCESS)
2259  goto end;
2260 
2261  /*
2262  * Read a message from the server
2263  */
2264  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2265  currentContextMap->dwClientID);
2266 
2267  if (rv != SCARD_S_SUCCESS)
2268  goto end;
2269 
2270  if (SCARD_S_SUCCESS == scControlStruct.rv)
2271  {
2272  /* read the received buffer */
2273  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2274  currentContextMap->dwClientID);
2275 
2276  if (rv != SCARD_S_SUCCESS)
2277  goto end;
2278 
2279  }
2280 
2281  if (NULL != lpBytesReturned)
2282  *lpBytesReturned = scControlStruct.dwBytesReturned;
2283 
2284  rv = scControlStruct.rv;
2285 
2286 end:
2287  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2288 
2289  PROFILE_END(rv)
2290 
2291  return rv;
2292 }
2293 
2411 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2412  LPDWORD pcbAttrLen)
2413 {
2414  LONG ret;
2415  unsigned char *buf = NULL;
2416 
2417  PROFILE_START
2418 
2419  if (NULL == pcbAttrLen)
2420  {
2422  goto end;
2423  }
2424 
2425  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2426  {
2427  if (NULL == pbAttr)
2429 
2430  *pcbAttrLen = MAX_BUFFER_SIZE;
2431  buf = malloc(*pcbAttrLen);
2432  if (NULL == buf)
2433  {
2434  ret = SCARD_E_NO_MEMORY;
2435  goto end;
2436  }
2437 
2438  *(unsigned char **)pbAttr = buf;
2439  }
2440  else
2441  {
2442  buf = pbAttr;
2443 
2444  /* if only get the length */
2445  if (NULL == pbAttr)
2446  /* use a reasonable size */
2447  *pcbAttrLen = MAX_BUFFER_SIZE;
2448  }
2449 
2450  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2451  pcbAttrLen);
2452 
2453 end:
2454  PROFILE_END(ret)
2455 
2456  return ret;
2457 }
2458 
2494 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2495  DWORD cbAttrLen)
2496 {
2497  LONG ret;
2498 
2499  PROFILE_START
2500 
2501  if (NULL == pbAttr || 0 == cbAttrLen)
2503 
2504  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2505  &cbAttrLen);
2506 
2507  PROFILE_END(ret)
2508 
2509  return ret;
2510 }
2511 
2512 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2513  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2514 {
2515  LONG rv;
2516  struct getset_struct scGetSetStruct;
2517  SCONTEXTMAP * currentContextMap;
2518  CHANNEL_MAP * pChannelMap;
2519 
2520  /*
2521  * Make sure this handle has been opened
2522  */
2523  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2524  &pChannelMap);
2525  if (rv == -1)
2526  return SCARD_E_INVALID_HANDLE;
2527 
2528  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2529  {
2531  goto end;
2532  }
2533 
2534  scGetSetStruct.hCard = hCard;
2535  scGetSetStruct.dwAttrId = dwAttrId;
2536  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2537  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2538  if (SCARD_SET_ATTRIB == command)
2539  {
2540  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2541  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2542  }
2543  else
2544  /* we can get up to the communication buffer size */
2545  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2546 
2547  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2548  sizeof(scGetSetStruct), &scGetSetStruct);
2549 
2550  if (rv != SCARD_S_SUCCESS)
2551  goto end;
2552 
2553  /*
2554  * Read a message from the server
2555  */
2556  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2557  currentContextMap->dwClientID);
2558 
2559  if (rv != SCARD_S_SUCCESS)
2560  goto end;
2561 
2562  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2563  {
2564  /*
2565  * Copy and zero it so any secret information is not leaked
2566  */
2567  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2568  {
2569  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2570  * buffer overflow in the memcpy() bellow */
2571  DWORD correct_value = scGetSetStruct.cbAttrLen;
2572  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2573  *pcbAttrLen = correct_value;
2574 
2575  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2576  }
2577  else
2578  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2579 
2580  if (pbAttr)
2581  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2582 
2583  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2584  }
2585  rv = scGetSetStruct.rv;
2586 
2587 end:
2588  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2589 
2590  return rv;
2591 }
2592 
2651 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2652  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2653  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2654  LPDWORD pcbRecvLength)
2655 {
2656  LONG rv;
2657  SCONTEXTMAP * currentContextMap;
2658  CHANNEL_MAP * pChannelMap;
2659  struct transmit_struct scTransmitStruct;
2660 
2661  PROFILE_START
2662 
2663  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2664  pcbRecvLength == NULL || pioSendPci == NULL)
2666 
2667  /* Retry loop for blocking behaviour */
2668 retry:
2669 
2670  /*
2671  * Make sure this handle has been opened
2672  */
2673  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2674  &pChannelMap);
2675  if (rv == -1)
2676  {
2677  *pcbRecvLength = 0;
2678  PROFILE_END(SCARD_E_INVALID_HANDLE)
2679  return SCARD_E_INVALID_HANDLE;
2680  }
2681 
2682  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2683  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2684  {
2686  goto end;
2687  }
2688 
2689  scTransmitStruct.hCard = hCard;
2690  scTransmitStruct.cbSendLength = cbSendLength;
2691  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2692  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2693  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2694  scTransmitStruct.rv = SCARD_S_SUCCESS;
2695 
2696  if (pioRecvPci)
2697  {
2698  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2699  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2700  }
2701  else
2702  {
2703  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2704  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2705  }
2706 
2707  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2708  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2709 
2710  if (rv != SCARD_S_SUCCESS)
2711  goto end;
2712 
2713  /* write the sent buffer */
2714  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2715  currentContextMap->dwClientID);
2716 
2717  if (rv != SCARD_S_SUCCESS)
2718  goto end;
2719 
2720  /*
2721  * Read a message from the server
2722  */
2723  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2724  currentContextMap->dwClientID);
2725 
2726  if (rv != SCARD_S_SUCCESS)
2727  goto end;
2728 
2729  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2730  {
2731  /* read the received buffer */
2732  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2733  currentContextMap->dwClientID);
2734 
2735  if (rv != SCARD_S_SUCCESS)
2736  goto end;
2737 
2738  if (pioRecvPci)
2739  {
2740  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2741  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2742  }
2743  }
2744 
2745  rv = scTransmitStruct.rv;
2746 
2747  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2748  {
2749  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2751  goto retry;
2752  }
2753 
2754  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2755 
2756 end:
2757  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2758 
2759  PROFILE_END(rv)
2760 
2761  return rv;
2762 }
2763 
2826 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2827  LPSTR mszReaders, LPDWORD pcchReaders)
2828 {
2829  DWORD dwReadersLen = 0;
2830  int i;
2831  SCONTEXTMAP * currentContextMap;
2832  LONG rv = SCARD_S_SUCCESS;
2833  char *buf = NULL;
2834 
2835  (void)mszGroups;
2836  PROFILE_START
2837  API_TRACE_IN("%ld", hContext)
2838 
2839  /*
2840  * Check for NULL parameters
2841  */
2842  if (pcchReaders == NULL)
2844 
2845  /*
2846  * Make sure this context has been opened
2847  */
2848  currentContextMap = SCardGetAndLockContext(hContext);
2849  if (NULL == currentContextMap)
2850  {
2851  PROFILE_END(SCARD_E_INVALID_HANDLE)
2852  return SCARD_E_INVALID_HANDLE;
2853  }
2854 
2855  /* synchronize reader states with daemon */
2856  rv = getReaderStates(currentContextMap);
2857  if (rv != SCARD_S_SUCCESS)
2858  goto end;
2859 
2860  dwReadersLen = 0;
2861  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2862  if (readerStates[i].readerName[0] != '\0')
2863  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2864 
2865  /* for the last NULL byte */
2866  dwReadersLen += 1;
2867 
2868  if (1 == dwReadersLen)
2869  {
2871  goto end;
2872  }
2873 
2874  if (SCARD_AUTOALLOCATE == *pcchReaders)
2875  {
2876  if (NULL == mszReaders)
2877  {
2879  goto end;
2880  }
2881  buf = malloc(dwReadersLen);
2882  if (NULL == buf)
2883  {
2884  rv = SCARD_E_NO_MEMORY;
2885  goto end;
2886  }
2887  *(char **)mszReaders = buf;
2888  }
2889  else
2890  {
2891  buf = mszReaders;
2892 
2893  /* not enough place to store the reader names */
2894  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2895  {
2897  goto end;
2898  }
2899  }
2900 
2901  if (mszReaders == NULL) /* text array not allocated */
2902  goto end;
2903 
2904  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2905  {
2906  if (readerStates[i].readerName[0] != '\0')
2907  {
2908  /*
2909  * Build the multi-string
2910  */
2911  strcpy(buf, readerStates[i].readerName);
2912  buf += strlen(readerStates[i].readerName)+1;
2913  }
2914  }
2915  *buf = '\0'; /* Add the last null */
2916 
2917 end:
2918  /* set the reader names length */
2919  *pcchReaders = dwReadersLen;
2920 
2921  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2922 
2923  PROFILE_END(rv)
2924  API_TRACE_OUT("%d", *pcchReaders)
2925 
2926  return rv;
2927 }
2928 
2942 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2943 {
2944  LONG rv = SCARD_S_SUCCESS;
2945 
2946  PROFILE_START
2947 
2948  /*
2949  * Make sure this context has been opened
2950  */
2951  if (! SCardGetContextValidity(hContext))
2952  return SCARD_E_INVALID_HANDLE;
2953 
2954  free((void *)pvMem);
2955 
2956  PROFILE_END(rv)
2957 
2958  return rv;
2959 }
2960 
3012 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3013  LPDWORD pcchGroups)
3014 {
3015  LONG rv = SCARD_S_SUCCESS;
3016  SCONTEXTMAP * currentContextMap;
3017  char *buf = NULL;
3018 
3019  PROFILE_START
3020 
3021  /* Multi-string with two trailing \0 */
3022  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3023  const unsigned int dwGroups = sizeof(ReaderGroup);
3024 
3025  /*
3026  * Make sure this context has been opened
3027  */
3028  currentContextMap = SCardGetAndLockContext(hContext);
3029  if (NULL == currentContextMap)
3030  return SCARD_E_INVALID_HANDLE;
3031 
3032  if (SCARD_AUTOALLOCATE == *pcchGroups)
3033  {
3034  if (NULL == mszGroups)
3035  {
3037  goto end;
3038  }
3039  buf = malloc(dwGroups);
3040  if (NULL == buf)
3041  {
3042  rv = SCARD_E_NO_MEMORY;
3043  goto end;
3044  }
3045  *(char **)mszGroups = buf;
3046  }
3047  else
3048  {
3049  buf = mszGroups;
3050 
3051  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3052  {
3054  goto end;
3055  }
3056  }
3057 
3058  if (buf)
3059  memcpy(buf, ReaderGroup, dwGroups);
3060 
3061 end:
3062  *pcchGroups = dwGroups;
3063 
3064  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3065 
3066  PROFILE_END(rv)
3067 
3068  return rv;
3069 }
3070 
3103 {
3104  SCONTEXTMAP * currentContextMap;
3105  LONG rv = SCARD_S_SUCCESS;
3106  uint32_t dwClientID = 0;
3107  struct cancel_struct scCancelStruct;
3108  char cancellable;
3109 
3110  PROFILE_START
3111  API_TRACE_IN("%ld", hContext)
3112 
3113  /*
3114  * Make sure this context has been opened
3115  */
3116  (void)SCardLockThread();
3117  currentContextMap = SCardGetContextTH(hContext);
3118 
3119  if (NULL == currentContextMap)
3120  {
3121  (void)SCardUnlockThread();
3123  goto error;
3124  }
3125  cancellable = currentContextMap->cancellable;
3126  (void)SCardUnlockThread();
3127 
3128  if (! cancellable)
3129  {
3130  rv = SCARD_S_SUCCESS;
3131  goto error;
3132  }
3133 
3134  /* create a new connection to the server */
3135  if (ClientSetupSession(&dwClientID) != 0)
3136  {
3137  rv = SCARD_E_NO_SERVICE;
3138  goto error;
3139  }
3140 
3141  scCancelStruct.hContext = hContext;
3142  scCancelStruct.rv = SCARD_S_SUCCESS;
3143 
3144  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3145  sizeof(scCancelStruct), (void *) &scCancelStruct);
3146 
3147  if (rv != SCARD_S_SUCCESS)
3148  goto end;
3149 
3150  /*
3151  * Read a message from the server
3152  */
3153  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3154 
3155  if (rv != SCARD_S_SUCCESS)
3156  goto end;
3157 
3158  rv = scCancelStruct.rv;
3159 end:
3160  ClientCloseSession(dwClientID);
3161 
3162 error:
3163  PROFILE_END(rv)
3164  API_TRACE_OUT("")
3165 
3166  return rv;
3167 }
3168 
3193 {
3194  LONG rv;
3195 
3196  PROFILE_START
3197  API_TRACE_IN("%ld", hContext)
3198 
3199  rv = SCARD_S_SUCCESS;
3200 
3201  /*
3202  * Make sure this context has been opened
3203  */
3204  if (! SCardGetContextValidity(hContext))
3206 
3207  PROFILE_END(rv)
3208  API_TRACE_OUT("")
3209 
3210  return rv;
3211 }
3212 
3229 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3230 {
3231  int lrv;
3232  SCONTEXTMAP * newContextMap;
3233 
3234  newContextMap = malloc(sizeof(SCONTEXTMAP));
3235  if (NULL == newContextMap)
3236  return SCARD_E_NO_MEMORY;
3237 
3238  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3239  newContextMap->hContext = hContext;
3240  newContextMap->dwClientID = dwClientID;
3241  newContextMap->cancellable = FALSE;
3242 
3243  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3244 
3245  lrv = list_init(&newContextMap->channelMapList);
3246  if (lrv < 0)
3247  {
3248  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3249  goto error;
3250  }
3251 
3252  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3253  CHANNEL_MAP_seeker);
3254  if (lrv <0)
3255  {
3256  Log2(PCSC_LOG_CRITICAL,
3257  "list_attributes_seeker failed with return value: %d", lrv);
3258  list_destroy(&newContextMap->channelMapList);
3259  goto error;
3260  }
3261 
3262  lrv = list_append(&contextMapList, newContextMap);
3263  if (lrv < 0)
3264  {
3265  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3266  lrv);
3267  list_destroy(&newContextMap->channelMapList);
3268  goto error;
3269  }
3270 
3271  return SCARD_S_SUCCESS;
3272 
3273 error:
3274 
3275  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3276  free(newContextMap);
3277 
3278  return SCARD_E_NO_MEMORY;
3279 }
3280 
3298 {
3299  SCONTEXTMAP * currentContextMap;
3300 
3301  SCardLockThread();
3302  currentContextMap = SCardGetContextTH(hContext);
3303 
3304  /* lock the context (if available) */
3305  if (NULL != currentContextMap)
3306  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3307 
3309 
3310  return currentContextMap;
3311 }
3312 
3326 {
3327  return list_seek(&contextMapList, &hContext);
3328 }
3329 
3336 static void SCardRemoveContext(SCARDCONTEXT hContext)
3337 {
3338  SCONTEXTMAP * currentContextMap;
3339  currentContextMap = SCardGetContextTH(hContext);
3340 
3341  if (NULL != currentContextMap)
3342  SCardCleanContext(currentContextMap);
3343 }
3344 
3345 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3346 {
3347  int list_index, lrv;
3348  int listSize;
3349  CHANNEL_MAP * currentChannelMap;
3350 
3351  targetContextMap->hContext = 0;
3352  ClientCloseSession(targetContextMap->dwClientID);
3353  targetContextMap->dwClientID = 0;
3354  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3355 
3356  listSize = list_size(&targetContextMap->channelMapList);
3357  for (list_index = 0; list_index < listSize; list_index++)
3358  {
3359  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3360  list_index);
3361  if (NULL == currentChannelMap)
3362  {
3363  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3364  list_index);
3365  continue;
3366  }
3367  else
3368  {
3369  free(currentChannelMap->readerName);
3370  free(currentChannelMap);
3371  }
3372 
3373  }
3374  list_destroy(&targetContextMap->channelMapList);
3375 
3376  lrv = list_delete(&contextMapList, targetContextMap);
3377  if (lrv < 0)
3378  {
3379  Log2(PCSC_LOG_CRITICAL,
3380  "list_delete failed with return value: %d", lrv);
3381  }
3382 
3383  free(targetContextMap);
3384 
3385  return;
3386 }
3387 
3388 /*
3389  * Functions for managing hCard values returned from SCardConnect.
3390  */
3391 
3392 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3393  LPCSTR readerName)
3394 {
3395  CHANNEL_MAP * newChannelMap;
3396  int lrv = -1;
3397 
3398  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3399  if (NULL == newChannelMap)
3400  return SCARD_E_NO_MEMORY;
3401 
3402  newChannelMap->hCard = hCard;
3403  newChannelMap->readerName = strdup(readerName);
3404 
3405  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3406  if (lrv < 0)
3407  {
3408  free(newChannelMap->readerName);
3409  free(newChannelMap);
3410  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3411  lrv);
3412  return SCARD_E_NO_MEMORY;
3413  }
3414 
3415  return SCARD_S_SUCCESS;
3416 }
3417 
3418 static void SCardRemoveHandle(SCARDHANDLE hCard)
3419 {
3420  SCONTEXTMAP * currentContextMap;
3421  CHANNEL_MAP * currentChannelMap;
3422  int lrv;
3423  LONG rv;
3424 
3425  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3426  &currentChannelMap);
3427  if (rv == -1)
3428  return;
3429 
3430  free(currentChannelMap->readerName);
3431 
3432  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3433  if (lrv < 0)
3434  {
3435  Log2(PCSC_LOG_CRITICAL,
3436  "list_delete failed with return value: %d", lrv);
3437  }
3438 
3439  free(currentChannelMap);
3440 
3441  return;
3442 }
3443 
3444 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3445  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3446 {
3447  LONG rv;
3448 
3449  if (0 == hCard)
3450  return -1;
3451 
3452  SCardLockThread();
3453  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3454  targetChannelMap);
3455 
3456  if (SCARD_S_SUCCESS == rv)
3457  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3458 
3460 
3461  return rv;
3462 }
3463 
3464 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3465  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3466 {
3467  int listSize;
3468  int list_index;
3469  SCONTEXTMAP * currentContextMap;
3470  CHANNEL_MAP * currentChannelMap;
3471 
3472  /* Best to get the caller a crash early if we fail unsafely */
3473  *targetContextMap = NULL;
3474  *targetChannelMap = NULL;
3475 
3476  listSize = list_size(&contextMapList);
3477 
3478  for (list_index = 0; list_index < listSize; list_index++)
3479  {
3480  currentContextMap = list_get_at(&contextMapList, list_index);
3481  if (currentContextMap == NULL)
3482  {
3483  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3484  list_index);
3485  continue;
3486  }
3487  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3488  &hCard);
3489  if (currentChannelMap != NULL)
3490  {
3491  *targetContextMap = currentContextMap;
3492  *targetChannelMap = currentChannelMap;
3493  return SCARD_S_SUCCESS;
3494  }
3495  }
3496 
3497  return -1;
3498 }
3499 
3508 {
3509  LONG rv;
3510  struct stat statBuffer;
3511  char *socketName;
3512 
3513  socketName = getSocketName();
3514  rv = stat(socketName, &statBuffer);
3515 
3516  if (rv != 0)
3517  {
3518  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3519  socketName, strerror(errno));
3520  return SCARD_E_NO_SERVICE;
3521  }
3522 
3523  return SCARD_S_SUCCESS;
3524 }
3525 
3526 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3527 {
3528  int32_t dwClientID = currentContextMap->dwClientID;
3529  LONG rv;
3530 
3531  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3532  if (rv != SCARD_S_SUCCESS)
3533  return rv;
3534 
3535  /* Read a message from the server */
3536  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3537  if (rv != SCARD_S_SUCCESS)
3538  return rv;
3539 
3540  return SCARD_S_SUCCESS;
3541 }
3542 
3543 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3544 {
3545  int32_t dwClientID = currentContextMap->dwClientID;
3546  LONG rv;
3547 
3548  /* Get current reader states from server and register on event list */
3550  0, NULL);
3551  if (rv != SCARD_S_SUCCESS)
3552  return rv;
3553 
3554  /* Read a message from the server */
3555  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3556  return rv;
3557 }
3558 
3559 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3560 {
3561  int32_t dwClientID = currentContextMap->dwClientID;
3562  LONG rv;
3563  struct wait_reader_state_change waitStatusStruct = {0};
3564 
3565  /* ask server to remove us from the event list */
3567  dwClientID, 0, NULL);
3568  if (rv != SCARD_S_SUCCESS)
3569  return rv;
3570 
3571  /* This message can be the response to
3572  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3573  * cancel notification.
3574  * The server side ensures, that no more messages will be sent to
3575  * the client. */
3576 
3577  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3578  dwClientID);
3579  if (rv != SCARD_S_SUCCESS)
3580  return rv;
3581 
3582  /* if we received a cancel event the return value will be set
3583  * accordingly */
3584  rv = waitStatusStruct.rv;
3585 
3586  return rv;
3587 }
3588 
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:79
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:77
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:75
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
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
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:274
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:272
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:243
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:265
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
This keeps track of a list of currently available reader structures.
Protocol Control Information (PCI)
Definition: pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
char cancellable
We are in a cancellable call.
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:188
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:211
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:145
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:250
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:176
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:199
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:122
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:265
list object
Definition: simclist.h:181
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:53
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:57
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:61
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:59
uint32_t eventCounter
number of card events
Definition: eventhandler.h:55
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:56
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:161
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:134
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:222
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:233
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:58
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:59
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:60
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:111
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:138
This handles smart card reader communications.
static short isExecuted
Make sure the initialization code is executed only once.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
static int SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:121
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
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
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
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
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
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
@ SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:84
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:94
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:80
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:98
@ CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:96
@ SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:88
@ CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:95
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:97
@ SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:83
@ SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:89
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:93
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:85
@ SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:87
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:86
@ SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:91
@ SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:82
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:79