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