pcsc-lite  1.9.9
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 
137 #ifndef TRUE
138 #define TRUE 1
139 #define FALSE 0
140 #endif
141 
142 static char sharing_shall_block = TRUE;
143 
144 #define COLOR_RED "\33[01;31m"
145 #define COLOR_GREEN "\33[32m"
146 #define COLOR_BLUE "\33[34m"
147 #define COLOR_MAGENTA "\33[35m"
148 #define COLOR_NORMAL "\33[0m"
149 
150 #ifdef DO_TRACE
151 
152 #include <stdio.h>
153 #include <stdarg.h>
154 
155 static void trace(const char *func, const char direction, const char *fmt, ...)
156 {
157  va_list args;
158 
159  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
160  direction, pthread_self(), func);
161 
162  fprintf(stderr, COLOR_MAGENTA);
163  va_start(args, fmt);
164  vfprintf(stderr, fmt, args);
165  va_end(args);
166 
167  fprintf(stderr, COLOR_NORMAL "\n");
168 }
169 
170 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
171 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
172 #else
173 #define API_TRACE_IN(...)
174 #define API_TRACE_OUT(...)
175 #endif
176 
177 #ifdef DO_PROFILE
178 
179 #define PROFILE_FILE "/tmp/pcsc_profile"
180 #include <stdio.h>
181 #include <sys/time.h>
182 
183 /* we can profile a maximum of 5 simultaneous calls */
184 #define MAX_THREADS 5
185 pthread_t threads[MAX_THREADS];
186 struct timeval profile_time_start[MAX_THREADS];
187 FILE *profile_fd;
188 char profile_tty;
189 
190 #define PROFILE_START profile_start();
191 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
192 
193 static void profile_start(void)
194 {
195  static char initialized = FALSE;
196  pthread_t t;
197  int i;
198 
199  if (!initialized)
200  {
201  char filename[80];
202 
203  initialized = TRUE;
204  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
205  profile_fd = fopen(filename, "a+");
206  if (NULL == profile_fd)
207  {
208  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
209  PROFILE_FILE, strerror(errno));
210  exit(-1);
211  }
212  fprintf(profile_fd, "\nStart a new profile\n");
213 
214  if (isatty(fileno(stderr)))
215  profile_tty = TRUE;
216  else
217  profile_tty = FALSE;
218  }
219 
220  t = pthread_self();
221  for (i=0; i<MAX_THREADS; i++)
222  if (pthread_equal(0, threads[i]))
223  {
224  threads[i] = t;
225  break;
226  }
227 
228  gettimeofday(&profile_time_start[i], NULL);
229 } /* profile_start */
230 
231 static void profile_end(const char *f, LONG rv)
232 {
233  struct timeval profile_time_end;
234  long d;
235  pthread_t t;
236  int i;
237 
238  gettimeofday(&profile_time_end, NULL);
239 
240  t = pthread_self();
241  for (i=0; i<MAX_THREADS; i++)
242  if (pthread_equal(t, threads[i]))
243  break;
244 
245  if (i>=MAX_THREADS)
246  {
247  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
248  return;
249  }
250 
251  d = time_sub(&profile_time_end, &profile_time_start[i]);
252 
253  /* free this entry */
254  threads[i] = 0;
255 
256  if (profile_tty)
257  {
258  if (rv != SCARD_S_SUCCESS)
259  fprintf(stderr,
260  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
261  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
262  f, d, rv, pcsc_stringify_error(rv));
263  else
264  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
265  COLOR_NORMAL "\n", f, d);
266  }
267  fprintf(profile_fd, "%s %ld\n", f, d);
268  fflush(profile_fd);
269 } /* profile_end */
270 
271 #else
272 #define PROFILE_START
273 #define PROFILE_END(rv)
274 #endif
275 
281 {
282  SCARDHANDLE hCard;
283  LPSTR readerName;
284 };
285 
286 typedef struct _psChannelMap CHANNEL_MAP;
287 
288 static int CHANNEL_MAP_seeker(const void *el, const void *key)
289 {
290  const CHANNEL_MAP * channelMap = el;
291 
292  if ((el == NULL) || (key == NULL))
293  {
294  Log3(PCSC_LOG_CRITICAL,
295  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
296  el, key);
297  return 0;
298  }
299 
300  if (channelMap->hCard == *(SCARDHANDLE *)key)
301  return 1;
302 
303  return 0;
304 }
305 
312 {
313  DWORD dwClientID;
315  pthread_mutex_t mMutex;
316  list_t channelMapList;
317  char cancellable;
318 };
324 typedef struct _psContextMap SCONTEXTMAP;
325 
326 static list_t contextMapList;
327 
328 static int SCONTEXTMAP_seeker(const void *el, const void *key)
329 {
330  const SCONTEXTMAP * contextMap = el;
331 
332  if ((el == NULL) || (key == NULL))
333  {
334  Log3(PCSC_LOG_CRITICAL,
335  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
336  el, key);
337  return 0;
338  }
339 
340  if (contextMap->hContext == *(SCARDCONTEXT *) key)
341  return 1;
342 
343  return 0;
344 }
345 
349 static short isExecuted = 0;
350 
351 
356 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
357 
362 
369 
370 
371 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
374 static void SCardRemoveContext(SCARDCONTEXT);
375 static void SCardCleanContext(SCONTEXTMAP *);
376 
377 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
378 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
379  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
381  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
382 static void SCardRemoveHandle(SCARDHANDLE);
383 
384 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
385  LPBYTE pbAttr, LPDWORD pcbAttrLen);
386 
387 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
388 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
389 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
390 
391 /*
392  * Thread safety functions
393  */
400 inline static void SCardLockThread(void)
401 {
402  pthread_mutex_lock(&clientMutex);
403 }
404 
410 inline static void SCardUnlockThread(void)
411 {
412  pthread_mutex_unlock(&clientMutex);
413 }
414 
425 {
426  SCONTEXTMAP * currentContextMap;
427 
428  SCardLockThread();
429  currentContextMap = SCardGetContextTH(hContext);
431 
432  return currentContextMap != NULL;
433 }
434 
435 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
436  /*@out@*/ LPSCARDCONTEXT);
437 
473 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
474  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
475 {
476  LONG rv;
477 
478  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
479  PROFILE_START
480 
481  /* Check if the server is running */
483  if (rv != SCARD_S_SUCCESS)
484  goto end;
485 
486  SCardLockThread();
487  rv = SCardEstablishContextTH(dwScope, pvReserved1,
488  pvReserved2, phContext);
490 
491 end:
492  PROFILE_END(rv)
493  API_TRACE_OUT("%ld", *phContext)
494 
495  return rv;
496 }
497 
498 #ifdef DESTRUCTOR
499 DESTRUCTOR static void destructor(void)
500 {
501  list_destroy(&contextMapList);
502 }
503 #endif
504 
532 static LONG SCardEstablishContextTH(DWORD dwScope,
533  /*@unused@*/ LPCVOID pvReserved1,
534  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
535 {
536  LONG rv;
537  struct establish_struct scEstablishStruct;
538  uint32_t dwClientID = 0;
539 
540  (void)pvReserved1;
541  (void)pvReserved2;
542  if (phContext == NULL)
544  else
545  *phContext = 0;
546 
547  /*
548  * Do this only once:
549  * - Initialize context list.
550  */
551  if (isExecuted == 0)
552  {
553  int lrv;
554 
555  /* NOTE: The list will be freed only if DESTRUCTOR is defined.
556  * Applications which load and unload the library may leak
557  * the list's internal structures. */
558  lrv = list_init(&contextMapList);
559  if (lrv < 0)
560  {
561  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
562  lrv);
563  return SCARD_E_NO_MEMORY;
564  }
565 
566  lrv = list_attributes_seeker(&contextMapList,
567  SCONTEXTMAP_seeker);
568  if (lrv <0)
569  {
570  Log2(PCSC_LOG_CRITICAL,
571  "list_attributes_seeker failed with return value: %d", lrv);
572  list_destroy(&contextMapList);
573  return SCARD_E_NO_MEMORY;
574  }
575 
576  if (getenv("PCSCLITE_NO_BLOCKING"))
577  {
578  Log1(PCSC_LOG_INFO, "Disable shared blocking");
579  sharing_shall_block = FALSE;
580  }
581 
582  isExecuted = 1;
583  }
584 
585 
586  /* Establishes a connection to the server */
587  if (ClientSetupSession(&dwClientID) != 0)
588  {
589  return SCARD_E_NO_SERVICE;
590  }
591 
592  { /* exchange client/server protocol versions */
593  struct version_struct veStr;
594 
597  veStr.rv = SCARD_S_SUCCESS;
598 
599  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
600  &veStr);
601  if (rv != SCARD_S_SUCCESS)
602  goto cleanup;
603 
604  /* Read a message from the server */
605  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
606  if (rv != SCARD_S_SUCCESS)
607  {
608  Log1(PCSC_LOG_CRITICAL,
609  "Your pcscd is too old and does not support CMD_VERSION");
610  goto cleanup;
611  }
612 
613  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
614  veStr.major, veStr.minor);
615 
616  if (veStr.rv != SCARD_S_SUCCESS)
617  {
618  rv = veStr.rv;
619  goto cleanup;
620  }
621  }
622 
623 again:
624  /*
625  * Try to establish an Application Context with the server
626  */
627  scEstablishStruct.dwScope = dwScope;
628  scEstablishStruct.hContext = 0;
629  scEstablishStruct.rv = SCARD_S_SUCCESS;
630 
632  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
633 
634  if (rv != SCARD_S_SUCCESS)
635  goto cleanup;
636 
637  /*
638  * Read the response from the server
639  */
640  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
641  dwClientID);
642 
643  if (rv != SCARD_S_SUCCESS)
644  goto cleanup;
645 
646  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
647  {
648  rv = scEstablishStruct.rv;
649  goto cleanup;
650  }
651 
652  /* check we do not reuse an existing hContext */
653  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
654  /* we do not need to release the allocated context since
655  * SCardReleaseContext() does nothing on the server side */
656  goto again;
657 
658  *phContext = scEstablishStruct.hContext;
659 
660  /*
661  * Allocate the new hContext - if allocator full return an error
662  */
663  rv = SCardAddContext(*phContext, dwClientID);
664 
665  return rv;
666 
667 cleanup:
668  ClientCloseSession(dwClientID);
669 
670  return rv;
671 }
672 
695 {
696  LONG rv;
697  struct release_struct scReleaseStruct;
698  SCONTEXTMAP * currentContextMap;
699 
700  API_TRACE_IN("%ld", hContext)
701  PROFILE_START
702 
703  /*
704  * Make sure this context has been opened
705  * and get currentContextMap
706  */
707  currentContextMap = SCardGetAndLockContext(hContext);
708  if (NULL == currentContextMap)
709  {
711  goto error;
712  }
713 
714  scReleaseStruct.hContext = hContext;
715  scReleaseStruct.rv = SCARD_S_SUCCESS;
716 
718  currentContextMap->dwClientID,
719  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
720 
721  if (rv != SCARD_S_SUCCESS)
722  goto end;
723 
724  /*
725  * Read a message from the server
726  */
727  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
728  currentContextMap->dwClientID);
729 
730  if (rv != SCARD_S_SUCCESS)
731  goto end;
732 
733  rv = scReleaseStruct.rv;
734 end:
735  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
736 
737  /*
738  * Remove the local context from the stack
739  */
740  SCardLockThread();
741  SCardRemoveContext(hContext);
743 
744 error:
745  PROFILE_END(rv)
746  API_TRACE_OUT("")
747 
748  return rv;
749 }
750 
806 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
807  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
808  LPDWORD pdwActiveProtocol)
809 {
810  LONG rv;
811  struct connect_struct scConnectStruct;
812  SCONTEXTMAP * currentContextMap;
813 
814  PROFILE_START
815  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
816 
817  /*
818  * Check for NULL parameters
819  */
820  if (phCard == NULL || pdwActiveProtocol == NULL)
822  else
823  *phCard = 0;
824 
825  if (szReader == NULL)
826  return SCARD_E_UNKNOWN_READER;
827 
828  /*
829  * Check for uninitialized strings
830  */
831  if (strlen(szReader) > MAX_READERNAME)
832  return SCARD_E_INVALID_VALUE;
833 
834  /*
835  * Make sure this context has been opened
836  */
837  currentContextMap = SCardGetAndLockContext(hContext);
838  if (NULL == currentContextMap)
839  return SCARD_E_INVALID_HANDLE;
840 
841  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
842  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
843  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
844 
845  scConnectStruct.hContext = hContext;
846  scConnectStruct.dwShareMode = dwShareMode;
847  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
848  scConnectStruct.hCard = 0;
849  scConnectStruct.dwActiveProtocol = 0;
850  scConnectStruct.rv = SCARD_S_SUCCESS;
851 
852  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
853  sizeof(scConnectStruct), (void *) &scConnectStruct);
854 
855  if (rv != SCARD_S_SUCCESS)
856  goto end;
857 
858  /*
859  * Read a message from the server
860  */
861  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
862  currentContextMap->dwClientID);
863 
864  if (rv != SCARD_S_SUCCESS)
865  goto end;
866 
867  *phCard = scConnectStruct.hCard;
868  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
869 
870  if (scConnectStruct.rv == SCARD_S_SUCCESS)
871  {
872  /*
873  * Keep track of the handle locally
874  */
875  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
876  }
877  else
878  rv = scConnectStruct.rv;
879 
880 end:
881  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
882 
883  PROFILE_END(rv)
884  API_TRACE_OUT("%d", *pdwActiveProtocol)
885 
886  return rv;
887 }
888 
961 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
962  DWORD dwPreferredProtocols, DWORD dwInitialization,
963  LPDWORD pdwActiveProtocol)
964 {
965  LONG rv;
966  struct reconnect_struct scReconnectStruct;
967  SCONTEXTMAP * currentContextMap;
968  CHANNEL_MAP * pChannelMap;
969 
970  PROFILE_START
971  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
972 
973  if (pdwActiveProtocol == NULL)
975 
976  /* Retry loop for blocking behaviour */
977 retry:
978 
979  /*
980  * Make sure this handle has been opened
981  */
982  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
983  &pChannelMap);
984  if (rv == -1)
985  return SCARD_E_INVALID_HANDLE;
986 
987  scReconnectStruct.hCard = hCard;
988  scReconnectStruct.dwShareMode = dwShareMode;
989  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
990  scReconnectStruct.dwInitialization = dwInitialization;
991  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
992  scReconnectStruct.rv = SCARD_S_SUCCESS;
993 
994  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
995  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
996 
997  if (rv != SCARD_S_SUCCESS)
998  goto end;
999 
1000  /*
1001  * Read a message from the server
1002  */
1003  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1004  currentContextMap->dwClientID);
1005 
1006  if (rv != SCARD_S_SUCCESS)
1007  goto end;
1008 
1009  rv = scReconnectStruct.rv;
1010 
1011  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1012  {
1013  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1015  goto retry;
1016  }
1017 
1018  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1019 
1020 end:
1021  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1022 
1023  PROFILE_END(rv)
1024  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1025 
1026  return rv;
1027 }
1028 
1060 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1061 {
1062  LONG rv;
1063  struct disconnect_struct scDisconnectStruct;
1064  SCONTEXTMAP * currentContextMap;
1065  CHANNEL_MAP * pChannelMap;
1066 
1067  PROFILE_START
1068  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1069 
1070  /*
1071  * Make sure this handle has been opened
1072  */
1073  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1074  &pChannelMap);
1075  if (rv == -1)
1076  {
1078  goto error;
1079  }
1080 
1081  scDisconnectStruct.hCard = hCard;
1082  scDisconnectStruct.dwDisposition = dwDisposition;
1083  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1084 
1085  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1086  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1087 
1088  if (rv != SCARD_S_SUCCESS)
1089  goto end;
1090 
1091  /*
1092  * Read a message from the server
1093  */
1094  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1095  currentContextMap->dwClientID);
1096 
1097  if (rv != SCARD_S_SUCCESS)
1098  goto end;
1099 
1100  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1101  SCardRemoveHandle(hCard);
1102  rv = scDisconnectStruct.rv;
1103 
1104 end:
1105  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1106 
1107 error:
1108  PROFILE_END(rv)
1109  API_TRACE_OUT("")
1110 
1111  return rv;
1112 }
1113 
1150 {
1151 
1152  LONG rv;
1153  struct begin_struct scBeginStruct;
1154  SCONTEXTMAP * currentContextMap;
1155  CHANNEL_MAP * pChannelMap;
1156 
1157  PROFILE_START
1158  API_TRACE_IN("%ld", hCard)
1159 
1160  /*
1161  * Query the server every so often until the sharing violation ends
1162  * and then hold the lock for yourself.
1163  */
1164 
1165  for(;;)
1166  {
1167  /*
1168  * Make sure this handle has been opened
1169  */
1170  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1171  &pChannelMap);
1172  if (rv == -1)
1173  return SCARD_E_INVALID_HANDLE;
1174 
1175  scBeginStruct.hCard = hCard;
1176  scBeginStruct.rv = SCARD_S_SUCCESS;
1177 
1179  currentContextMap->dwClientID,
1180  sizeof(scBeginStruct), (void *) &scBeginStruct);
1181 
1182  if (rv != SCARD_S_SUCCESS)
1183  break;
1184 
1185  /*
1186  * Read a message from the server
1187  */
1188  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1189  currentContextMap->dwClientID);
1190 
1191  if (rv != SCARD_S_SUCCESS)
1192  break;
1193 
1194  rv = scBeginStruct.rv;
1195 
1196  if (SCARD_E_SHARING_VIOLATION != rv)
1197  break;
1198 
1199  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1201  }
1202 
1203  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1204 
1205  PROFILE_END(rv)
1206  API_TRACE_OUT("")
1207 
1208  return rv;
1209 }
1210 
1250 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1251 {
1252  LONG rv;
1253  struct end_struct scEndStruct;
1254  SCONTEXTMAP * currentContextMap;
1255  CHANNEL_MAP * pChannelMap;
1256 
1257  PROFILE_START
1258  API_TRACE_IN("%ld", hCard)
1259 
1260  /*
1261  * Make sure this handle has been opened
1262  */
1263  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1264  &pChannelMap);
1265  if (rv == -1)
1266  return SCARD_E_INVALID_HANDLE;
1267 
1268  scEndStruct.hCard = hCard;
1269  scEndStruct.dwDisposition = dwDisposition;
1270  scEndStruct.rv = SCARD_S_SUCCESS;
1271 
1273  currentContextMap->dwClientID,
1274  sizeof(scEndStruct), (void *) &scEndStruct);
1275 
1276  if (rv != SCARD_S_SUCCESS)
1277  goto end;
1278 
1279  /*
1280  * Read a message from the server
1281  */
1282  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1283  currentContextMap->dwClientID);
1284 
1285  if (rv != SCARD_S_SUCCESS)
1286  goto end;
1287 
1288  rv = scEndStruct.rv;
1289 
1290 end:
1291  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1292 
1293  PROFILE_END(rv)
1294  API_TRACE_OUT("")
1295 
1296  return rv;
1297 }
1298 
1394 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1395  LPDWORD pcchReaderLen, LPDWORD pdwState,
1396  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1397 {
1398  DWORD dwReaderLen, dwAtrLen;
1399  LONG rv;
1400  int i;
1401  struct status_struct scStatusStruct;
1402  SCONTEXTMAP * currentContextMap;
1403  CHANNEL_MAP * pChannelMap;
1404  char *r;
1405  char *bufReader = NULL;
1406  LPBYTE bufAtr = NULL;
1407  DWORD dummy = 0;
1408 
1409  PROFILE_START
1410 
1411  /* default output values */
1412  if (pdwState)
1413  *pdwState = 0;
1414 
1415  if (pdwProtocol)
1416  *pdwProtocol = 0;
1417 
1418  /* Check for NULL parameters */
1419  if (pcchReaderLen == NULL)
1420  pcchReaderLen = &dummy;
1421 
1422  if (pcbAtrLen == NULL)
1423  pcbAtrLen = &dummy;
1424 
1425  /* length passed from caller */
1426  dwReaderLen = *pcchReaderLen;
1427  dwAtrLen = *pcbAtrLen;
1428 
1429  *pcchReaderLen = 0;
1430  *pcbAtrLen = 0;
1431 
1432  /* Retry loop for blocking behaviour */
1433 retry:
1434 
1435  /*
1436  * Make sure this handle has been opened
1437  */
1438  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1439  &pChannelMap);
1440  if (rv == -1)
1441  return SCARD_E_INVALID_HANDLE;
1442 
1443  /* synchronize reader states with daemon */
1444  rv = getReaderStates(currentContextMap);
1445  if (rv != SCARD_S_SUCCESS)
1446  goto end;
1447 
1448  r = pChannelMap->readerName;
1449  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1450  {
1451  /* by default r == NULL */
1452  if (r && strcmp(r, readerStates[i].readerName) == 0)
1453  break;
1454  }
1455 
1457  {
1459  goto end;
1460  }
1461 
1462  /* initialise the structure */
1463  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1464  scStatusStruct.hCard = hCard;
1465 
1466  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1467  sizeof(scStatusStruct), (void *) &scStatusStruct);
1468 
1469  if (rv != SCARD_S_SUCCESS)
1470  goto end;
1471 
1472  /*
1473  * Read a message from the server
1474  */
1475  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1476  currentContextMap->dwClientID);
1477 
1478  if (rv != SCARD_S_SUCCESS)
1479  goto end;
1480 
1481  rv = scStatusStruct.rv;
1482 
1483  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1484  {
1485  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1487  goto retry;
1488  }
1489 
1490  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1491  {
1492  /*
1493  * An event must have occurred
1494  */
1495  goto end;
1496  }
1497 
1498  /*
1499  * Now continue with the client side SCardStatus
1500  */
1501 
1502  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1503  *pcbAtrLen = readerStates[i].cardAtrLength;
1504 
1505  if (pdwState)
1506  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1507 
1508  if (pdwProtocol)
1509  *pdwProtocol = readerStates[i].cardProtocol;
1510 
1511  if (SCARD_AUTOALLOCATE == dwReaderLen)
1512  {
1513  dwReaderLen = *pcchReaderLen;
1514  if (NULL == szReaderName)
1515  {
1517  goto end;
1518  }
1519  bufReader = malloc(dwReaderLen);
1520  if (NULL == bufReader)
1521  {
1522  rv = SCARD_E_NO_MEMORY;
1523  goto end;
1524  }
1525  *(char **)szReaderName = bufReader;
1526  }
1527  else
1528  bufReader = szReaderName;
1529 
1530  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1531  if (bufReader)
1532  {
1533  if (*pcchReaderLen > dwReaderLen)
1535 
1536  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1537  }
1538 
1539  if (SCARD_AUTOALLOCATE == dwAtrLen)
1540  {
1541  dwAtrLen = *pcbAtrLen;
1542  if (NULL == pbAtr)
1543  {
1545  goto end;
1546  }
1547  bufAtr = malloc(dwAtrLen);
1548  if (NULL == bufAtr)
1549  {
1550  rv = SCARD_E_NO_MEMORY;
1551  goto end;
1552  }
1553  *(LPBYTE *)pbAtr = bufAtr;
1554  }
1555  else
1556  bufAtr = pbAtr;
1557 
1558  if (bufAtr)
1559  {
1560  if (*pcbAtrLen > dwAtrLen)
1562 
1563  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1564  }
1565 
1566 end:
1567  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1568 
1569  PROFILE_END(rv)
1570 
1571  return rv;
1572 }
1573 
1681 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1682  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1683 {
1684  SCARD_READERSTATE *currReader;
1685  READER_STATE *rContext;
1686  long dwTime;
1687  DWORD dwBreakFlag = 0;
1688  unsigned int j;
1689  SCONTEXTMAP * currentContextMap;
1690  int currentReaderCount = 0;
1691  LONG rv = SCARD_S_SUCCESS;
1692 
1693  PROFILE_START
1694  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1695 #ifdef DO_TRACE
1696  for (j=0; j<cReaders; j++)
1697  {
1698  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1699  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1700  }
1701 #endif
1702 
1703  if ((rgReaderStates == NULL && cReaders > 0)
1704  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1705  {
1707  goto error;
1708  }
1709 
1710  /* Check the integrity of the reader states structures */
1711  for (j = 0; j < cReaders; j++)
1712  {
1713  if (rgReaderStates[j].szReader == NULL)
1714  return SCARD_E_INVALID_VALUE;
1715  }
1716 
1717  /* return if all readers are SCARD_STATE_IGNORE */
1718  if (cReaders > 0)
1719  {
1720  int nbNonIgnoredReaders = cReaders;
1721 
1722  for (j=0; j<cReaders; j++)
1723  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1724  nbNonIgnoredReaders--;
1725 
1726  if (0 == nbNonIgnoredReaders)
1727  {
1728  rv = SCARD_S_SUCCESS;
1729  goto error;
1730  }
1731  }
1732  else
1733  {
1734  /* reader list is empty */
1735  rv = SCARD_S_SUCCESS;
1736  goto error;
1737  }
1738 
1739  /*
1740  * Make sure this context has been opened
1741  */
1742  currentContextMap = SCardGetAndLockContext(hContext);
1743  if (NULL == currentContextMap)
1744  {
1746  goto error;
1747  }
1748 
1749  /* synchronize reader states with daemon */
1750  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1751  if (rv != SCARD_S_SUCCESS)
1752  goto end;
1753 
1754  /* check all the readers are already known */
1755  for (j=0; j<cReaders; j++)
1756  {
1757  const char *readerName;
1758  int i;
1759 
1760  readerName = rgReaderStates[j].szReader;
1761  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1762  {
1763  if (strcmp(readerName, readerStates[i].readerName) == 0)
1764  break;
1765  }
1766 
1767  /* The requested reader name is not recognized */
1769  {
1770  /* PnP special reader? */
1771  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1772  {
1774  goto end;
1775  }
1776  }
1777  }
1778 
1779  /* Clear the event state for all readers */
1780  for (j = 0; j < cReaders; j++)
1781  rgReaderStates[j].dwEventState = 0;
1782 
1783  /* Now is where we start our event checking loop */
1784  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1785 
1786  /* Get the initial reader count on the system */
1787  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1788  if (readerStates[j].readerName[0] != '\0')
1789  currentReaderCount++;
1790 
1791  /* catch possible sign extension problems from 32 to 64-bits integers */
1792  if ((DWORD)-1 == dwTimeout)
1793  dwTimeout = INFINITE;
1794  if (INFINITE == dwTimeout)
1795  dwTime = 60*1000; /* "infinite" timeout */
1796  else
1797  dwTime = dwTimeout;
1798 
1799  j = 0;
1800  do
1801  {
1802  currReader = &rgReaderStates[j];
1803 
1804  /* Ignore for IGNORED readers */
1805  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1806  {
1807  const char *readerName;
1808  int i;
1809 
1810  /* Looks for correct readernames */
1811  readerName = currReader->szReader;
1812  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1813  {
1814  if (strcmp(readerName, readerStates[i].readerName) == 0)
1815  break;
1816  }
1817 
1818  /* The requested reader name is not recognized */
1820  {
1821  /* PnP special reader? */
1822  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1823  {
1824  int k, newReaderCount = 0;
1825 
1826  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1827  if (readerStates[k].readerName[0] != '\0')
1828  newReaderCount++;
1829 
1830  if (newReaderCount != currentReaderCount)
1831  {
1832  Log1(PCSC_LOG_INFO, "Reader list changed");
1833  currentReaderCount = newReaderCount;
1834 
1835  currReader->dwEventState |= SCARD_STATE_CHANGED;
1836  dwBreakFlag = 1;
1837  }
1838  }
1839  else
1840  {
1841  currReader->dwEventState =
1843  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1844  {
1845  currReader->dwEventState |= SCARD_STATE_CHANGED;
1846  /*
1847  * Spec says use SCARD_STATE_IGNORE but a removed USB
1848  * reader with eventState fed into currentState will
1849  * be ignored forever
1850  */
1851  dwBreakFlag = 1;
1852  }
1853  }
1854  }
1855  else
1856  {
1857  uint32_t readerState;
1858 
1859  /* The reader has come back after being away */
1860  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1861  {
1862  currReader->dwEventState |= SCARD_STATE_CHANGED;
1863  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1864  Log0(PCSC_LOG_DEBUG);
1865  dwBreakFlag = 1;
1866  }
1867 
1868  /* Set the reader status structure */
1869  rContext = &readerStates[i];
1870 
1871  /* Now we check all the Reader States */
1872  readerState = rContext->readerState;
1873 
1874  /* only if current state has an non null event counter */
1875  if (currReader->dwCurrentState & 0xFFFF0000)
1876  {
1877  unsigned int currentCounter;
1878 
1879  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1880 
1881  /* has the event counter changed since the last call? */
1882  if (rContext->eventCounter != currentCounter)
1883  {
1884  currReader->dwEventState |= SCARD_STATE_CHANGED;
1885  Log0(PCSC_LOG_DEBUG);
1886  dwBreakFlag = 1;
1887  }
1888  }
1889 
1890  /* add an event counter in the upper word of dwEventState */
1891  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1892  | (rContext->eventCounter << 16));
1893 
1894  /* Check if the reader is in the correct state */
1895  if (readerState & SCARD_UNKNOWN)
1896  {
1897  /* reader is in bad state */
1898  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1899  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1900  {
1901  /* App thinks reader is in good state and it is not */
1902  currReader->dwEventState |= SCARD_STATE_CHANGED;
1903  Log0(PCSC_LOG_DEBUG);
1904  dwBreakFlag = 1;
1905  }
1906  }
1907  else
1908  {
1909  /* App thinks reader in bad state but it is not */
1910  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1911  {
1912  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1913  currReader->dwEventState |= SCARD_STATE_CHANGED;
1914  Log0(PCSC_LOG_DEBUG);
1915  dwBreakFlag = 1;
1916  }
1917  }
1918 
1919  /* Check for card presence in the reader */
1920  if (readerState & SCARD_PRESENT)
1921  {
1922 #ifndef DISABLE_AUTO_POWER_ON
1923  /* card present but not yet powered up */
1924  if (0 == rContext->cardAtrLength)
1925  /* Allow the status thread to convey information */
1927 #endif
1928 
1929  currReader->cbAtr = rContext->cardAtrLength;
1930  memcpy(currReader->rgbAtr, rContext->cardAtr,
1931  currReader->cbAtr);
1932  }
1933  else
1934  currReader->cbAtr = 0;
1935 
1936  /* Card is now absent */
1937  if (readerState & SCARD_ABSENT)
1938  {
1939  currReader->dwEventState |= SCARD_STATE_EMPTY;
1940  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1941  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1942  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1943  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1944  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1945  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1946  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1947  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1948 
1949  /* After present the rest are assumed */
1950  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1951  {
1952  currReader->dwEventState |= SCARD_STATE_CHANGED;
1953  Log0(PCSC_LOG_DEBUG);
1954  dwBreakFlag = 1;
1955  }
1956  }
1957  /* Card is now present */
1958  else if (readerState & SCARD_PRESENT)
1959  {
1960  currReader->dwEventState |= SCARD_STATE_PRESENT;
1961  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1962  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1963  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1964  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1965  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1966  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1967 
1968  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1969  {
1970  currReader->dwEventState |= SCARD_STATE_CHANGED;
1971  Log0(PCSC_LOG_DEBUG);
1972  dwBreakFlag = 1;
1973  }
1974 
1975  if (readerState & SCARD_SWALLOWED)
1976  {
1977  currReader->dwEventState |= SCARD_STATE_MUTE;
1978  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1979  {
1980  currReader->dwEventState |= SCARD_STATE_CHANGED;
1981  Log0(PCSC_LOG_DEBUG);
1982  dwBreakFlag = 1;
1983  }
1984  }
1985  else
1986  {
1987  /* App thinks card is mute but it is not */
1988  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1989  {
1990  currReader->dwEventState |= SCARD_STATE_CHANGED;
1991  Log0(PCSC_LOG_DEBUG);
1992  dwBreakFlag = 1;
1993  }
1994  }
1995  }
1996 
1997  /* Now figure out sharing modes */
1999  {
2000  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2001  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2002  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2003  {
2004  currReader->dwEventState |= SCARD_STATE_CHANGED;
2005  Log0(PCSC_LOG_DEBUG);
2006  dwBreakFlag = 1;
2007  }
2008  }
2009  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2010  {
2011  /* A card must be inserted for it to be INUSE */
2012  if (readerState & SCARD_PRESENT)
2013  {
2014  currReader->dwEventState |= SCARD_STATE_INUSE;
2015  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2016  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2017  {
2018  currReader->dwEventState |= SCARD_STATE_CHANGED;
2019  Log0(PCSC_LOG_DEBUG);
2020  dwBreakFlag = 1;
2021  }
2022  }
2023  }
2024  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2025  {
2026  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2027  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2028 
2029  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2030  {
2031  currReader->dwEventState |= SCARD_STATE_CHANGED;
2032  Log0(PCSC_LOG_DEBUG);
2033  dwBreakFlag = 1;
2034  }
2035  else if (currReader-> dwCurrentState
2037  {
2038  currReader->dwEventState |= SCARD_STATE_CHANGED;
2039  Log0(PCSC_LOG_DEBUG);
2040  dwBreakFlag = 1;
2041  }
2042  }
2043 
2044  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2045  {
2046  /*
2047  * Break out of the while .. loop and return status
2048  * once all the status's for all readers is met
2049  */
2050  currReader->dwEventState |= SCARD_STATE_CHANGED;
2051  Log0(PCSC_LOG_DEBUG);
2052  dwBreakFlag = 1;
2053  }
2054  } /* End of SCARD_STATE_UNKNOWN */
2055  } /* End of SCARD_STATE_IGNORE */
2056 
2057  /* Counter and resetter */
2058  j++;
2059  if (j == cReaders)
2060  {
2061  /* go back to the first reader */
2062  j = 0;
2063 
2064  /* Declare all the break conditions */
2065 
2066  /* Break if UNAWARE is set and all readers have been checked */
2067  if (dwBreakFlag == 1)
2068  break;
2069 
2070  /* Only sleep once for each cycle of reader checks. */
2071  {
2072  struct wait_reader_state_change waitStatusStruct = {0};
2073  struct timeval before, after;
2074 
2075  gettimeofday(&before, NULL);
2076 
2077  waitStatusStruct.rv = SCARD_S_SUCCESS;
2078 
2079  /* another thread can do SCardCancel() */
2080  currentContextMap->cancellable = TRUE;
2081 
2082  /*
2083  * Read a message from the server
2084  */
2086  &waitStatusStruct, sizeof(waitStatusStruct),
2087  currentContextMap->dwClientID, dwTime);
2088 
2089  /* SCardCancel() will return immediatly with success
2090  * because something changed on the daemon side. */
2091  currentContextMap->cancellable = FALSE;
2092 
2093  /* timeout */
2094  if (SCARD_E_TIMEOUT == rv)
2095  {
2096  /* ask server to remove us from the event list */
2097  rv = unregisterFromEvents(currentContextMap);
2098  }
2099 
2100  if (rv != SCARD_S_SUCCESS)
2101  goto end;
2102 
2103  /* an event occurs or SCardCancel() was called */
2104  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2105  {
2106  rv = waitStatusStruct.rv;
2107  goto end;
2108  }
2109 
2110  /* synchronize reader states with daemon */
2111  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2112  if (rv != SCARD_S_SUCCESS)
2113  goto end;
2114 
2115  if (INFINITE != dwTimeout)
2116  {
2117  long int diff;
2118 
2119  gettimeofday(&after, NULL);
2120  diff = time_sub(&after, &before);
2121  dwTime -= diff/1000;
2122  }
2123  }
2124 
2125  if (dwTimeout != INFINITE)
2126  {
2127  /* If time is greater than timeout and all readers have been
2128  * checked
2129  */
2130  if (dwTime <= 0)
2131  {
2132  rv = SCARD_E_TIMEOUT;
2133  goto end;
2134  }
2135  }
2136  }
2137  }
2138  while (1);
2139 
2140 end:
2141  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2142 
2143  /* if SCardCancel() has been used then the client is already
2144  * unregistered */
2145  if (SCARD_E_CANCELLED != rv)
2146  (void)unregisterFromEvents(currentContextMap);
2147 
2148  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2149 
2150 error:
2151  PROFILE_END(rv)
2152 #ifdef DO_TRACE
2153  for (j=0; j<cReaders; j++)
2154  {
2155  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2156  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2157  }
2158 #endif
2159 
2160  return rv;
2161 }
2162 
2213 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2214  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2215  LPDWORD lpBytesReturned)
2216 {
2217  LONG rv;
2218  struct control_struct scControlStruct;
2219  SCONTEXTMAP * currentContextMap;
2220  CHANNEL_MAP * pChannelMap;
2221 
2222  PROFILE_START
2223 
2224  /* 0 bytes received by default */
2225  if (NULL != lpBytesReturned)
2226  *lpBytesReturned = 0;
2227 
2228  /*
2229  * Make sure this handle has been opened
2230  */
2231  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2232  &pChannelMap);
2233  if (rv == -1)
2234  {
2235  PROFILE_END(SCARD_E_INVALID_HANDLE)
2236  return SCARD_E_INVALID_HANDLE;
2237  }
2238 
2239  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2240  {
2242  goto end;
2243  }
2244 
2245  scControlStruct.hCard = hCard;
2246  scControlStruct.dwControlCode = dwControlCode;
2247  scControlStruct.cbSendLength = cbSendLength;
2248  scControlStruct.cbRecvLength = cbRecvLength;
2249  scControlStruct.dwBytesReturned = 0;
2250  scControlStruct.rv = 0;
2251 
2252  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2253  sizeof(scControlStruct), &scControlStruct);
2254 
2255  if (rv != SCARD_S_SUCCESS)
2256  goto end;
2257 
2258  /* write the sent buffer */
2259  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2260  currentContextMap->dwClientID);
2261 
2262  if (rv != SCARD_S_SUCCESS)
2263  goto end;
2264 
2265  /*
2266  * Read a message from the server
2267  */
2268  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2269  currentContextMap->dwClientID);
2270 
2271  if (rv != SCARD_S_SUCCESS)
2272  goto end;
2273 
2274  if (SCARD_S_SUCCESS == scControlStruct.rv)
2275  {
2276  if (scControlStruct.dwBytesReturned > cbRecvLength)
2277  {
2278  if (NULL != lpBytesReturned)
2279  *lpBytesReturned = scControlStruct.dwBytesReturned;
2281  goto end;
2282  }
2283 
2284  /* read the received buffer */
2285  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2286  currentContextMap->dwClientID);
2287 
2288  if (rv != SCARD_S_SUCCESS)
2289  goto end;
2290 
2291  }
2292 
2293  if (NULL != lpBytesReturned)
2294  *lpBytesReturned = scControlStruct.dwBytesReturned;
2295 
2296  rv = scControlStruct.rv;
2297 
2298 end:
2299  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2300 
2301  PROFILE_END(rv)
2302 
2303  return rv;
2304 }
2305 
2423 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2424  LPDWORD pcbAttrLen)
2425 {
2426  LONG ret;
2427  unsigned char *buf = NULL;
2428 
2429  PROFILE_START
2430 
2431  if (NULL == pcbAttrLen)
2432  {
2434  goto end;
2435  }
2436 
2437  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2438  {
2439  if (NULL == pbAttr)
2441 
2442  *pcbAttrLen = MAX_BUFFER_SIZE;
2443  buf = malloc(*pcbAttrLen);
2444  if (NULL == buf)
2445  {
2446  ret = SCARD_E_NO_MEMORY;
2447  goto end;
2448  }
2449 
2450  *(unsigned char **)pbAttr = buf;
2451  }
2452  else
2453  {
2454  buf = pbAttr;
2455 
2456  /* if only get the length */
2457  if (NULL == pbAttr)
2458  /* use a reasonable size */
2459  *pcbAttrLen = MAX_BUFFER_SIZE;
2460  }
2461 
2462  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2463  pcbAttrLen);
2464 
2465 end:
2466  PROFILE_END(ret)
2467 
2468  return ret;
2469 }
2470 
2506 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2507  DWORD cbAttrLen)
2508 {
2509  LONG ret;
2510 
2511  PROFILE_START
2512 
2513  if (NULL == pbAttr || 0 == cbAttrLen)
2515 
2516  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2517  &cbAttrLen);
2518 
2519  PROFILE_END(ret)
2520 
2521  return ret;
2522 }
2523 
2524 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2525  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2526 {
2527  LONG rv;
2528  struct getset_struct scGetSetStruct;
2529  SCONTEXTMAP * currentContextMap;
2530  CHANNEL_MAP * pChannelMap;
2531 
2532  /*
2533  * Make sure this handle has been opened
2534  */
2535  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2536  &pChannelMap);
2537  if (rv == -1)
2538  return SCARD_E_INVALID_HANDLE;
2539 
2540  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2541  {
2543  goto end;
2544  }
2545 
2546  scGetSetStruct.hCard = hCard;
2547  scGetSetStruct.dwAttrId = dwAttrId;
2548  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2549  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2550  if (SCARD_SET_ATTRIB == command)
2551  {
2552  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2553  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2554  }
2555  else
2556  /* we can get up to the communication buffer size */
2557  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2558 
2559  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2560  sizeof(scGetSetStruct), &scGetSetStruct);
2561 
2562  if (rv != SCARD_S_SUCCESS)
2563  goto end;
2564 
2565  /*
2566  * Read a message from the server
2567  */
2568  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2569  currentContextMap->dwClientID);
2570 
2571  if (rv != SCARD_S_SUCCESS)
2572  goto end;
2573 
2574  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2575  {
2576  /*
2577  * Copy and zero it so any secret information is not leaked
2578  */
2579  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2580  {
2581  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2582  * buffer overflow in the memcpy() bellow */
2583  DWORD correct_value = scGetSetStruct.cbAttrLen;
2584  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2585  *pcbAttrLen = correct_value;
2586 
2587  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2588  }
2589  else
2590  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2591 
2592  if (pbAttr)
2593  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2594 
2595  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2596  }
2597  rv = scGetSetStruct.rv;
2598 
2599 end:
2600  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2601 
2602  return rv;
2603 }
2604 
2663 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2664  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2665  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2666  LPDWORD pcbRecvLength)
2667 {
2668  LONG rv;
2669  SCONTEXTMAP * currentContextMap;
2670  CHANNEL_MAP * pChannelMap;
2671  struct transmit_struct scTransmitStruct;
2672 
2673  PROFILE_START
2674 
2675  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2676  pcbRecvLength == NULL || pioSendPci == NULL)
2678 
2679  /* Retry loop for blocking behaviour */
2680 retry:
2681 
2682  /*
2683  * Make sure this handle has been opened
2684  */
2685  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2686  &pChannelMap);
2687  if (rv == -1)
2688  {
2689  *pcbRecvLength = 0;
2690  PROFILE_END(SCARD_E_INVALID_HANDLE)
2691  return SCARD_E_INVALID_HANDLE;
2692  }
2693 
2694  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2695  {
2697  goto end;
2698  }
2699 
2700  scTransmitStruct.hCard = hCard;
2701  scTransmitStruct.cbSendLength = cbSendLength;
2702  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2703  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2704  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2705  scTransmitStruct.rv = SCARD_S_SUCCESS;
2706 
2707  if (pioRecvPci)
2708  {
2709  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2710  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2711  }
2712  else
2713  {
2714  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2715  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2716  }
2717 
2718  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2719  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2720 
2721  if (rv != SCARD_S_SUCCESS)
2722  goto end;
2723 
2724  /* write the sent buffer */
2725  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2726  currentContextMap->dwClientID);
2727 
2728  if (rv != SCARD_S_SUCCESS)
2729  goto end;
2730 
2731  /*
2732  * Read a message from the server
2733  */
2734  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2735  currentContextMap->dwClientID);
2736 
2737  if (rv != SCARD_S_SUCCESS)
2738  goto end;
2739 
2740  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2741  {
2742  if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2743  {
2744  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2746  goto end;
2747  }
2748 
2749  /* read the received buffer */
2750  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2751  currentContextMap->dwClientID);
2752 
2753  if (rv != SCARD_S_SUCCESS)
2754  goto end;
2755 
2756  if (pioRecvPci)
2757  {
2758  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2759  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2760  }
2761  }
2762 
2763  rv = scTransmitStruct.rv;
2764 
2765  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2766  {
2767  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2769  goto retry;
2770  }
2771 
2772  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2773 
2774 end:
2775  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2776 
2777  PROFILE_END(rv)
2778 
2779  return rv;
2780 }
2781 
2844 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2845  LPSTR mszReaders, LPDWORD pcchReaders)
2846 {
2847  DWORD dwReadersLen = 0;
2848  int i;
2849  SCONTEXTMAP * currentContextMap;
2850  LONG rv = SCARD_S_SUCCESS;
2851  char *buf = NULL;
2852 
2853  (void)mszGroups;
2854  PROFILE_START
2855  API_TRACE_IN("%ld", hContext)
2856 
2857  /*
2858  * Check for NULL parameters
2859  */
2860  if (pcchReaders == NULL)
2862 
2863  /*
2864  * Make sure this context has been opened
2865  */
2866  currentContextMap = SCardGetAndLockContext(hContext);
2867  if (NULL == currentContextMap)
2868  {
2869  PROFILE_END(SCARD_E_INVALID_HANDLE)
2870  return SCARD_E_INVALID_HANDLE;
2871  }
2872 
2873  /* synchronize reader states with daemon */
2874  rv = getReaderStates(currentContextMap);
2875  if (rv != SCARD_S_SUCCESS)
2876  goto end;
2877 
2878  dwReadersLen = 0;
2879  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2880  if (readerStates[i].readerName[0] != '\0')
2881  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2882 
2883  /* for the last NULL byte */
2884  dwReadersLen += 1;
2885 
2886  if (1 == dwReadersLen)
2887  {
2889  goto end;
2890  }
2891 
2892  if (SCARD_AUTOALLOCATE == *pcchReaders)
2893  {
2894  if (NULL == mszReaders)
2895  {
2897  goto end;
2898  }
2899  buf = malloc(dwReadersLen);
2900  if (NULL == buf)
2901  {
2902  rv = SCARD_E_NO_MEMORY;
2903  goto end;
2904  }
2905  *(char **)mszReaders = buf;
2906  }
2907  else
2908  {
2909  buf = mszReaders;
2910 
2911  /* not enough place to store the reader names */
2912  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2913  {
2915  goto end;
2916  }
2917  }
2918 
2919  if (mszReaders == NULL) /* text array not allocated */
2920  goto end;
2921 
2922  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2923  {
2924  if (readerStates[i].readerName[0] != '\0')
2925  {
2926  /*
2927  * Build the multi-string
2928  */
2929  strcpy(buf, readerStates[i].readerName);
2930  buf += strlen(readerStates[i].readerName)+1;
2931  }
2932  }
2933  *buf = '\0'; /* Add the last null */
2934 
2935 end:
2936  /* set the reader names length */
2937  *pcchReaders = dwReadersLen;
2938 
2939  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2940 
2941  PROFILE_END(rv)
2942  API_TRACE_OUT("%d", *pcchReaders)
2943 
2944  return rv;
2945 }
2946 
2960 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2961 {
2962  LONG rv = SCARD_S_SUCCESS;
2963 
2964  PROFILE_START
2965 
2966  /*
2967  * Make sure this context has been opened
2968  */
2969  if (! SCardGetContextValidity(hContext))
2970  return SCARD_E_INVALID_HANDLE;
2971 
2972  free((void *)pvMem);
2973 
2974  PROFILE_END(rv)
2975 
2976  return rv;
2977 }
2978 
3030 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3031  LPDWORD pcchGroups)
3032 {
3033  LONG rv = SCARD_S_SUCCESS;
3034  SCONTEXTMAP * currentContextMap;
3035  char *buf = NULL;
3036 
3037  PROFILE_START
3038 
3039  /* Multi-string with two trailing \0 */
3040  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3041  const unsigned int dwGroups = sizeof(ReaderGroup);
3042 
3043  /*
3044  * Make sure this context has been opened
3045  */
3046  currentContextMap = SCardGetAndLockContext(hContext);
3047  if (NULL == currentContextMap)
3048  return SCARD_E_INVALID_HANDLE;
3049 
3050  if (SCARD_AUTOALLOCATE == *pcchGroups)
3051  {
3052  if (NULL == mszGroups)
3053  {
3055  goto end;
3056  }
3057  buf = malloc(dwGroups);
3058  if (NULL == buf)
3059  {
3060  rv = SCARD_E_NO_MEMORY;
3061  goto end;
3062  }
3063  *(char **)mszGroups = buf;
3064  }
3065  else
3066  {
3067  buf = mszGroups;
3068 
3069  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3070  {
3072  goto end;
3073  }
3074  }
3075 
3076  if (buf)
3077  memcpy(buf, ReaderGroup, dwGroups);
3078 
3079 end:
3080  *pcchGroups = dwGroups;
3081 
3082  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3083 
3084  PROFILE_END(rv)
3085 
3086  return rv;
3087 }
3088 
3121 {
3122  SCONTEXTMAP * currentContextMap;
3123  LONG rv = SCARD_S_SUCCESS;
3124  uint32_t dwClientID = 0;
3125  struct cancel_struct scCancelStruct;
3126  char cancellable;
3127 
3128  PROFILE_START
3129  API_TRACE_IN("%ld", hContext)
3130 
3131  /*
3132  * Make sure this context has been opened
3133  */
3134  (void)SCardLockThread();
3135  currentContextMap = SCardGetContextTH(hContext);
3136 
3137  if (NULL == currentContextMap)
3138  {
3139  (void)SCardUnlockThread();
3141  goto error;
3142  }
3143  cancellable = currentContextMap->cancellable;
3144  (void)SCardUnlockThread();
3145 
3146  if (! cancellable)
3147  {
3148  rv = SCARD_S_SUCCESS;
3149  goto error;
3150  }
3151 
3152  /* create a new connection to the server */
3153  if (ClientSetupSession(&dwClientID) != 0)
3154  {
3155  rv = SCARD_E_NO_SERVICE;
3156  goto error;
3157  }
3158 
3159  scCancelStruct.hContext = hContext;
3160  scCancelStruct.rv = SCARD_S_SUCCESS;
3161 
3162  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3163  sizeof(scCancelStruct), (void *) &scCancelStruct);
3164 
3165  if (rv != SCARD_S_SUCCESS)
3166  goto end;
3167 
3168  /*
3169  * Read a message from the server
3170  */
3171  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3172 
3173  if (rv != SCARD_S_SUCCESS)
3174  goto end;
3175 
3176  rv = scCancelStruct.rv;
3177 end:
3178  ClientCloseSession(dwClientID);
3179 
3180 error:
3181  PROFILE_END(rv)
3182  API_TRACE_OUT("")
3183 
3184  return rv;
3185 }
3186 
3211 {
3212  LONG rv;
3213 
3214  PROFILE_START
3215  API_TRACE_IN("%ld", hContext)
3216 
3217  rv = SCARD_S_SUCCESS;
3218 
3219  /*
3220  * Make sure this context has been opened
3221  */
3222  if (! SCardGetContextValidity(hContext))
3224 
3225  PROFILE_END(rv)
3226  API_TRACE_OUT("")
3227 
3228  return rv;
3229 }
3230 
3247 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3248 {
3249  int lrv;
3250  SCONTEXTMAP * newContextMap;
3251 
3252  newContextMap = malloc(sizeof(SCONTEXTMAP));
3253  if (NULL == newContextMap)
3254  return SCARD_E_NO_MEMORY;
3255 
3256  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3257  newContextMap->hContext = hContext;
3258  newContextMap->dwClientID = dwClientID;
3259  newContextMap->cancellable = FALSE;
3260 
3261  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3262 
3263  lrv = list_init(&newContextMap->channelMapList);
3264  if (lrv < 0)
3265  {
3266  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3267  goto error;
3268  }
3269 
3270  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3271  CHANNEL_MAP_seeker);
3272  if (lrv <0)
3273  {
3274  Log2(PCSC_LOG_CRITICAL,
3275  "list_attributes_seeker failed with return value: %d", lrv);
3276  list_destroy(&newContextMap->channelMapList);
3277  goto error;
3278  }
3279 
3280  lrv = list_append(&contextMapList, newContextMap);
3281  if (lrv < 0)
3282  {
3283  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3284  lrv);
3285  list_destroy(&newContextMap->channelMapList);
3286  goto error;
3287  }
3288 
3289  return SCARD_S_SUCCESS;
3290 
3291 error:
3292 
3293  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3294  free(newContextMap);
3295 
3296  return SCARD_E_NO_MEMORY;
3297 }
3298 
3316 {
3317  SCONTEXTMAP * currentContextMap;
3318 
3319  SCardLockThread();
3320  currentContextMap = SCardGetContextTH(hContext);
3321 
3322  /* lock the context (if available) */
3323  if (NULL != currentContextMap)
3324  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3325 
3327 
3328  return currentContextMap;
3329 }
3330 
3344 {
3345  return list_seek(&contextMapList, &hContext);
3346 }
3347 
3354 static void SCardRemoveContext(SCARDCONTEXT hContext)
3355 {
3356  SCONTEXTMAP * currentContextMap;
3357  currentContextMap = SCardGetContextTH(hContext);
3358 
3359  if (NULL != currentContextMap)
3360  SCardCleanContext(currentContextMap);
3361 }
3362 
3363 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3364 {
3365  int list_index, lrv;
3366  int listSize;
3367  CHANNEL_MAP * currentChannelMap;
3368 
3369  targetContextMap->hContext = 0;
3370  ClientCloseSession(targetContextMap->dwClientID);
3371  targetContextMap->dwClientID = 0;
3372  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3373 
3374  listSize = list_size(&targetContextMap->channelMapList);
3375  for (list_index = 0; list_index < listSize; list_index++)
3376  {
3377  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3378  list_index);
3379  if (NULL == currentChannelMap)
3380  {
3381  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3382  list_index);
3383  continue;
3384  }
3385  else
3386  {
3387  free(currentChannelMap->readerName);
3388  free(currentChannelMap);
3389  }
3390 
3391  }
3392  list_destroy(&targetContextMap->channelMapList);
3393 
3394  lrv = list_delete(&contextMapList, targetContextMap);
3395  if (lrv < 0)
3396  {
3397  Log2(PCSC_LOG_CRITICAL,
3398  "list_delete failed with return value: %d", lrv);
3399  }
3400 
3401  free(targetContextMap);
3402 
3403  return;
3404 }
3405 
3406 /*
3407  * Functions for managing hCard values returned from SCardConnect.
3408  */
3409 
3410 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3411  LPCSTR readerName)
3412 {
3413  CHANNEL_MAP * newChannelMap;
3414  int lrv = -1;
3415 
3416  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3417  if (NULL == newChannelMap)
3418  return SCARD_E_NO_MEMORY;
3419 
3420  newChannelMap->hCard = hCard;
3421  newChannelMap->readerName = strdup(readerName);
3422 
3423  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3424  if (lrv < 0)
3425  {
3426  free(newChannelMap->readerName);
3427  free(newChannelMap);
3428  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3429  lrv);
3430  return SCARD_E_NO_MEMORY;
3431  }
3432 
3433  return SCARD_S_SUCCESS;
3434 }
3435 
3436 static void SCardRemoveHandle(SCARDHANDLE hCard)
3437 {
3438  SCONTEXTMAP * currentContextMap;
3439  CHANNEL_MAP * currentChannelMap;
3440  int lrv;
3441  LONG rv;
3442 
3443  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3444  &currentChannelMap);
3445  if (rv == -1)
3446  return;
3447 
3448  free(currentChannelMap->readerName);
3449 
3450  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3451  if (lrv < 0)
3452  {
3453  Log2(PCSC_LOG_CRITICAL,
3454  "list_delete failed with return value: %d", lrv);
3455  }
3456 
3457  free(currentChannelMap);
3458 
3459  return;
3460 }
3461 
3462 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3463  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3464 {
3465  LONG rv;
3466 
3467  if (0 == hCard)
3468  return -1;
3469 
3470  SCardLockThread();
3471  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3472  targetChannelMap);
3473 
3474  if (SCARD_S_SUCCESS == rv)
3475  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3476 
3478 
3479  return rv;
3480 }
3481 
3482 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3483  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3484 {
3485  int listSize;
3486  int list_index;
3487  SCONTEXTMAP * currentContextMap;
3488  CHANNEL_MAP * currentChannelMap;
3489 
3490  /* Best to get the caller a crash early if we fail unsafely */
3491  *targetContextMap = NULL;
3492  *targetChannelMap = NULL;
3493 
3494  listSize = list_size(&contextMapList);
3495 
3496  for (list_index = 0; list_index < listSize; list_index++)
3497  {
3498  currentContextMap = list_get_at(&contextMapList, list_index);
3499  if (currentContextMap == NULL)
3500  {
3501  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3502  list_index);
3503  continue;
3504  }
3505  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3506  &hCard);
3507  if (currentChannelMap != NULL)
3508  {
3509  *targetContextMap = currentContextMap;
3510  *targetChannelMap = currentChannelMap;
3511  return SCARD_S_SUCCESS;
3512  }
3513  }
3514 
3515  return -1;
3516 }
3517 
3526 {
3527  LONG rv;
3528  struct stat statBuffer;
3529  char *socketName;
3530 
3531  socketName = getSocketName();
3532  rv = stat(socketName, &statBuffer);
3533 
3534  if (rv != 0)
3535  {
3536  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3537  socketName, strerror(errno));
3538  return SCARD_E_NO_SERVICE;
3539  }
3540 
3541  return SCARD_S_SUCCESS;
3542 }
3543 
3544 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3545 {
3546  int32_t dwClientID = currentContextMap->dwClientID;
3547  LONG rv;
3548 
3549  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3550  if (rv != SCARD_S_SUCCESS)
3551  return rv;
3552 
3553  /* Read a message from the server */
3554  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3555  if (rv != SCARD_S_SUCCESS)
3556  return rv;
3557 
3558  return SCARD_S_SUCCESS;
3559 }
3560 
3561 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3562 {
3563  int32_t dwClientID = currentContextMap->dwClientID;
3564  LONG rv;
3565 
3566  /* Get current reader states from server and register on event list */
3568  0, NULL);
3569  if (rv != SCARD_S_SUCCESS)
3570  return rv;
3571 
3572  /* Read a message from the server */
3573  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3574  return rv;
3575 }
3576 
3577 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3578 {
3579  int32_t dwClientID = currentContextMap->dwClientID;
3580  LONG rv;
3581  struct wait_reader_state_change waitStatusStruct = {0};
3582 
3583  /* ask server to remove us from the event list */
3585  dwClientID, 0, NULL);
3586  if (rv != SCARD_S_SUCCESS)
3587  return rv;
3588 
3589  /* This message can be the response to
3590  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3591  * cancel notification.
3592  * The server side ensures, that no more messages will be sent to
3593  * the client. */
3594 
3595  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3596  dwClientID);
3597  if (rv != SCARD_S_SUCCESS)
3598  return rv;
3599 
3600  /* if we received a cancel event the return value will be set
3601  * accordingly */
3602  rv = waitStatusStruct.rv;
3603 
3604  return rv;
3605 }
3606 
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_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:78
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