pcsc-lite  1.8.26
winscard_clnt.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 1999-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2005
9  * Martin Paljak <martin@paljak.pri.ee>
10  * Copyright (C) 2002-2011
11  * Ludovic Rousseau <ludovic.rousseau@free.fr>
12  * Copyright (C) 2009
13  * Jean-Luc Giraud <jlgiraud@googlemail.com>
14  *
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
18 
19 1. Redistributions of source code must retain the above copyright
20  notice, this list of conditions and the following disclaimer.
21 2. Redistributions in binary form must reproduce the above copyright
22  notice, this list of conditions and the following disclaimer in the
23  documentation and/or other materials provided with the distribution.
24 3. The name of the author may not be used to endorse or promote products
25  derived from this software without specific prior written permission.
26 
27 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
105 #include "config.h"
106 #include <stdlib.h>
107 #include <string.h>
108 #include <sys/types.h>
109 #include <fcntl.h>
110 #include <unistd.h>
111 #include <sys/un.h>
112 #include <errno.h>
113 #include <stddef.h>
114 #include <sys/time.h>
115 #include <pthread.h>
116 #include <sys/wait.h>
117 
118 #include "misc.h"
119 #include "pcscd.h"
120 #include "winscard.h"
121 #include "debuglog.h"
122 
123 #include "readerfactory.h"
124 #include "eventhandler.h"
125 #include "sys_generic.h"
126 #include "winscard_msg.h"
127 #include "utils.h"
128 
129 /* Display, on stderr, a trace of the WinSCard calls with arguments and
130  * results */
131 //#define DO_TRACE
132 
133 /* Profile the execution time of WinSCard calls */
134 //#define DO_PROFILE
135 
136 
138 #define SCARD_PROTOCOL_ANY_OLD 0x1000
139 
140 #ifndef TRUE
141 #define TRUE 1
142 #define FALSE 0
143 #endif
144 
145 static char sharing_shall_block = TRUE;
146 
147 #define COLOR_RED "\33[01;31m"
148 #define COLOR_GREEN "\33[32m"
149 #define COLOR_BLUE "\33[34m"
150 #define COLOR_MAGENTA "\33[35m"
151 #define COLOR_NORMAL "\33[0m"
152 
153 #ifdef DO_TRACE
154 
155 #include <stdio.h>
156 #include <stdarg.h>
157 
158 static void trace(const char *func, const char direction, const char *fmt, ...)
159 {
160  va_list args;
161 
162  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163  direction, pthread_self(), func);
164 
165  fprintf(stderr, COLOR_MAGENTA);
166  va_start(args, fmt);
167  vfprintf(stderr, fmt, args);
168  va_end(args);
169 
170  fprintf(stderr, COLOR_NORMAL "\n");
171 }
172 
173 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175 #else
176 #define API_TRACE_IN(...)
177 #define API_TRACE_OUT(...)
178 #endif
179 
180 #ifdef DO_PROFILE
181 
182 #define PROFILE_FILE "/tmp/pcsc_profile"
183 #include <stdio.h>
184 #include <sys/time.h>
185 
186 /* we can profile a maximum of 5 simultaneous calls */
187 #define MAX_THREADS 5
188 pthread_t threads[MAX_THREADS];
189 struct timeval profile_time_start[MAX_THREADS];
190 FILE *profile_fd;
191 char profile_tty;
192 
193 #define PROFILE_START profile_start();
194 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195 
196 static void profile_start(void)
197 {
198  static char initialized = FALSE;
199  pthread_t t;
200  int i;
201 
202  if (!initialized)
203  {
204  char filename[80];
205 
206  initialized = TRUE;
207  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208  profile_fd = fopen(filename, "a+");
209  if (NULL == profile_fd)
210  {
211  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212  PROFILE_FILE, strerror(errno));
213  exit(-1);
214  }
215  fprintf(profile_fd, "\nStart a new profile\n");
216 
217  if (isatty(fileno(stderr)))
218  profile_tty = TRUE;
219  else
220  profile_tty = FALSE;
221  }
222 
223  t = pthread_self();
224  for (i=0; i<MAX_THREADS; i++)
225  if (pthread_equal(0, threads[i]))
226  {
227  threads[i] = t;
228  break;
229  }
230 
231  gettimeofday(&profile_time_start[i], NULL);
232 } /* profile_start */
233 
234 static void profile_end(const char *f, LONG rv)
235 {
236  struct timeval profile_time_end;
237  long d;
238  pthread_t t;
239  int i;
240 
241  gettimeofday(&profile_time_end, NULL);
242 
243  t = pthread_self();
244  for (i=0; i<MAX_THREADS; i++)
245  if (pthread_equal(t, threads[i]))
246  break;
247 
248  if (i>=MAX_THREADS)
249  {
250  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251  return;
252  }
253 
254  d = time_sub(&profile_time_end, &profile_time_start[i]);
255 
256  /* free this entry */
257  threads[i] = 0;
258 
259  if (profile_tty)
260  {
261  if (rv != SCARD_S_SUCCESS)
262  fprintf(stderr,
263  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265  f, d, rv, pcsc_stringify_error(rv));
266  else
267  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268  COLOR_NORMAL "\n", f, d);
269  }
270  fprintf(profile_fd, "%s %ld\n", f, d);
271  fflush(profile_fd);
272 } /* profile_end */
273 
274 #else
275 #define PROFILE_START
276 #define PROFILE_END(rv)
277 #endif
278 
284 {
285  SCARDHANDLE hCard;
286  LPSTR readerName;
287 };
288 
289 typedef struct _psChannelMap CHANNEL_MAP;
290 
291 static int CHANNEL_MAP_seeker(const void *el, const void *key)
292 {
293  const CHANNEL_MAP * channelMap = el;
294 
295  if ((el == NULL) || (key == NULL))
296  {
297  Log3(PCSC_LOG_CRITICAL,
298  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299  el, key);
300  return 0;
301  }
302 
303  if (channelMap->hCard == *(SCARDHANDLE *)key)
304  return 1;
305 
306  return 0;
307 }
308 
315 {
316  DWORD dwClientID;
318  pthread_mutex_t mMutex;
319  list_t channelMapList;
320  char cancellable;
321 };
327 typedef struct _psContextMap SCONTEXTMAP;
328 
329 static list_t contextMapList;
330 
331 static int SCONTEXTMAP_seeker(const void *el, const void *key)
332 {
333  const SCONTEXTMAP * contextMap = el;
334 
335  if ((el == NULL) || (key == NULL))
336  {
337  Log3(PCSC_LOG_CRITICAL,
338  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
339  el, key);
340  return 0;
341  }
342 
343  if (contextMap->hContext == *(SCARDCONTEXT *) key)
344  return 1;
345 
346  return 0;
347 }
348 
352 static short isExecuted = 0;
353 
354 
359 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
360 
365 
372 
373 
374 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
377 static void SCardRemoveContext(SCARDCONTEXT);
378 static void SCardCleanContext(SCONTEXTMAP *);
379 
380 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
381 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
382  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
383 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
384  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
385 static void SCardRemoveHandle(SCARDHANDLE);
386 
387 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
388  LPBYTE pbAttr, LPDWORD pcbAttrLen);
389 
390 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
391 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
392 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
393 
394 /*
395  * Thread safety functions
396  */
403 inline static void SCardLockThread(void)
404 {
405  pthread_mutex_lock(&clientMutex);
406 }
407 
413 inline static void SCardUnlockThread(void)
414 {
415  pthread_mutex_unlock(&clientMutex);
416 }
417 
428 {
429  SCONTEXTMAP * currentContextMap;
430 
431  SCardLockThread();
432  currentContextMap = SCardGetContextTH(hContext);
434 
435  return currentContextMap != NULL;
436 }
437 
438 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
439  /*@out@*/ LPSCARDCONTEXT);
440 
476 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
477  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
478 {
479  LONG rv;
480 
481  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
482  PROFILE_START
483 
484  /* Check if the server is running */
486  if (rv != SCARD_S_SUCCESS)
487  goto end;
488 
489  SCardLockThread();
490  rv = SCardEstablishContextTH(dwScope, pvReserved1,
491  pvReserved2, phContext);
493 
494 end:
495  PROFILE_END(rv)
496  API_TRACE_OUT("%ld", *phContext)
497 
498  return rv;
499 }
500 
527 static LONG SCardEstablishContextTH(DWORD dwScope,
528  /*@unused@*/ LPCVOID pvReserved1,
529  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
530 {
531  LONG rv;
532  struct establish_struct scEstablishStruct;
533  uint32_t dwClientID = 0;
534 
535  (void)pvReserved1;
536  (void)pvReserved2;
537  if (phContext == NULL)
539  else
540  *phContext = 0;
541 
542  /*
543  * Do this only once:
544  * - Initialize context list.
545  */
546  if (isExecuted == 0)
547  {
548  int lrv;
549 
550  /* NOTE: The list will never be freed (No API call exists to
551  * "close all contexts".
552  * Applications which load and unload the library will leak
553  * the list's internal structures. */
554  lrv = list_init(&contextMapList);
555  if (lrv < 0)
556  {
557  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
558  lrv);
559  return SCARD_E_NO_MEMORY;
560  }
561 
562  lrv = list_attributes_seeker(&contextMapList,
563  SCONTEXTMAP_seeker);
564  if (lrv <0)
565  {
566  Log2(PCSC_LOG_CRITICAL,
567  "list_attributes_seeker failed with return value: %d", lrv);
568  list_destroy(&contextMapList);
569  return SCARD_E_NO_MEMORY;
570  }
571 
572  if (getenv("PCSCLITE_NO_BLOCKING"))
573  {
574  Log1(PCSC_LOG_INFO, "Disable shared blocking");
575  sharing_shall_block = FALSE;
576  }
577 
578  isExecuted = 1;
579  }
580 
581 
582  /* Establishes a connection to the server */
583  if (ClientSetupSession(&dwClientID) != 0)
584  {
585  return SCARD_E_NO_SERVICE;
586  }
587 
588  { /* exchange client/server protocol versions */
589  struct version_struct veStr;
590 
593  veStr.rv = SCARD_S_SUCCESS;
594 
595  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
596  &veStr);
597  if (rv != SCARD_S_SUCCESS)
598  goto cleanup;
599 
600  /* Read a message from the server */
601  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
602  if (rv != SCARD_S_SUCCESS)
603  {
604  Log1(PCSC_LOG_CRITICAL,
605  "Your pcscd is too old and does not support CMD_VERSION");
606  rv = SCARD_F_COMM_ERROR;
607  goto cleanup;
608  }
609 
610  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
611  veStr.major, veStr.minor);
612 
613  if (veStr.rv != SCARD_S_SUCCESS)
614  {
615  rv = veStr.rv;
616  goto cleanup;
617  }
618  }
619 
620 again:
621  /*
622  * Try to establish an Application Context with the server
623  */
624  scEstablishStruct.dwScope = dwScope;
625  scEstablishStruct.hContext = 0;
626  scEstablishStruct.rv = SCARD_S_SUCCESS;
627 
629  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
630 
631  if (rv != SCARD_S_SUCCESS)
632  goto cleanup;
633 
634  /*
635  * Read the response from the server
636  */
637  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
638  dwClientID);
639 
640  if (rv != SCARD_S_SUCCESS)
641  goto cleanup;
642 
643  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
644  {
645  rv = scEstablishStruct.rv;
646  goto cleanup;
647  }
648 
649  /* check we do not reuse an existing hContext */
650  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
651  /* we do not need to release the allocated context since
652  * SCardReleaseContext() does nothing on the server side */
653  goto again;
654 
655  *phContext = scEstablishStruct.hContext;
656 
657  /*
658  * Allocate the new hContext - if allocator full return an error
659  */
660  rv = SCardAddContext(*phContext, dwClientID);
661 
662  return rv;
663 
664 cleanup:
665  ClientCloseSession(dwClientID);
666 
667  return rv;
668 }
669 
692 {
693  LONG rv;
694  struct release_struct scReleaseStruct;
695  SCONTEXTMAP * currentContextMap;
696 
697  API_TRACE_IN("%ld", hContext)
698  PROFILE_START
699 
700  /*
701  * Make sure this context has been opened
702  * and get currentContextMap
703  */
704  currentContextMap = SCardGetAndLockContext(hContext);
705  if (NULL == currentContextMap)
706  {
708  goto error;
709  }
710 
711  scReleaseStruct.hContext = hContext;
712  scReleaseStruct.rv = SCARD_S_SUCCESS;
713 
715  currentContextMap->dwClientID,
716  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
717 
718  if (rv != SCARD_S_SUCCESS)
719  goto end;
720 
721  /*
722  * Read a message from the server
723  */
724  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
725  currentContextMap->dwClientID);
726 
727  if (rv != SCARD_S_SUCCESS)
728  goto end;
729 
730  rv = scReleaseStruct.rv;
731 end:
732  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
733 
734  /*
735  * Remove the local context from the stack
736  */
737  SCardLockThread();
738  SCardRemoveContext(hContext);
740 
741 error:
742  PROFILE_END(rv)
743  API_TRACE_OUT("")
744 
745  return rv;
746 }
747 
803 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
804  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
805  LPDWORD pdwActiveProtocol)
806 {
807  LONG rv;
808  struct connect_struct scConnectStruct;
809  SCONTEXTMAP * currentContextMap;
810 
811  PROFILE_START
812  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
813 
814  /*
815  * Check for NULL parameters
816  */
817  if (phCard == NULL || pdwActiveProtocol == NULL)
819  else
820  *phCard = 0;
821 
822  if (szReader == NULL)
823  return SCARD_E_UNKNOWN_READER;
824 
825  /*
826  * Check for uninitialized strings
827  */
828  if (strlen(szReader) > MAX_READERNAME)
829  return SCARD_E_INVALID_VALUE;
830 
831  /*
832  * Make sure this context has been opened
833  */
834  currentContextMap = SCardGetAndLockContext(hContext);
835  if (NULL == currentContextMap)
836  return SCARD_E_INVALID_HANDLE;
837 
838  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
839  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
840  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
841 
842  scConnectStruct.hContext = hContext;
843  scConnectStruct.dwShareMode = dwShareMode;
844  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
845  scConnectStruct.hCard = 0;
846  scConnectStruct.dwActiveProtocol = 0;
847  scConnectStruct.rv = SCARD_S_SUCCESS;
848 
849  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
850  sizeof(scConnectStruct), (void *) &scConnectStruct);
851 
852  if (rv != SCARD_S_SUCCESS)
853  goto end;
854 
855  /*
856  * Read a message from the server
857  */
858  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
859  currentContextMap->dwClientID);
860 
861  if (rv != SCARD_S_SUCCESS)
862  goto end;
863 
864  *phCard = scConnectStruct.hCard;
865  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
866 
867  if (scConnectStruct.rv == SCARD_S_SUCCESS)
868  {
869  /*
870  * Keep track of the handle locally
871  */
872  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
873  }
874  else
875  rv = scConnectStruct.rv;
876 
877 end:
878  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
879 
880  PROFILE_END(rv)
881  API_TRACE_OUT("%d", *pdwActiveProtocol)
882 
883  return rv;
884 }
885 
958 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
959  DWORD dwPreferredProtocols, DWORD dwInitialization,
960  LPDWORD pdwActiveProtocol)
961 {
962  LONG rv;
963  struct reconnect_struct scReconnectStruct;
964  SCONTEXTMAP * currentContextMap;
965  CHANNEL_MAP * pChannelMap;
966 
967  PROFILE_START
968  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
969 
970  if (pdwActiveProtocol == NULL)
972 
973  /* Retry loop for blocking behaviour */
974 retry:
975 
976  /*
977  * Make sure this handle has been opened
978  */
979  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
980  &pChannelMap);
981  if (rv == -1)
982  return SCARD_E_INVALID_HANDLE;
983 
984  scReconnectStruct.hCard = hCard;
985  scReconnectStruct.dwShareMode = dwShareMode;
986  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
987  scReconnectStruct.dwInitialization = dwInitialization;
988  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
989  scReconnectStruct.rv = SCARD_S_SUCCESS;
990 
991  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
992  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
993 
994  if (rv != SCARD_S_SUCCESS)
995  goto end;
996 
997  /*
998  * Read a message from the server
999  */
1000  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1001  currentContextMap->dwClientID);
1002 
1003  if (rv != SCARD_S_SUCCESS)
1004  goto end;
1005 
1006  rv = scReconnectStruct.rv;
1007 
1008  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1009  {
1010  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1012  goto retry;
1013  }
1014 
1015  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1016 
1017 end:
1018  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1019 
1020  PROFILE_END(rv)
1021  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1022 
1023  return rv;
1024 }
1025 
1057 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1058 {
1059  LONG rv;
1060  struct disconnect_struct scDisconnectStruct;
1061  SCONTEXTMAP * currentContextMap;
1062  CHANNEL_MAP * pChannelMap;
1063 
1064  PROFILE_START
1065  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1066 
1067  /*
1068  * Make sure this handle has been opened
1069  */
1070  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1071  &pChannelMap);
1072  if (rv == -1)
1073  {
1075  goto error;
1076  }
1077 
1078  scDisconnectStruct.hCard = hCard;
1079  scDisconnectStruct.dwDisposition = dwDisposition;
1080  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1081 
1082  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1083  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1084 
1085  if (rv != SCARD_S_SUCCESS)
1086  goto end;
1087 
1088  /*
1089  * Read a message from the server
1090  */
1091  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1092  currentContextMap->dwClientID);
1093 
1094  if (rv != SCARD_S_SUCCESS)
1095  goto end;
1096 
1097  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1098  SCardRemoveHandle(hCard);
1099  rv = scDisconnectStruct.rv;
1100 
1101 end:
1102  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1103 
1104 error:
1105  PROFILE_END(rv)
1106  API_TRACE_OUT("")
1107 
1108  return rv;
1109 }
1110 
1147 {
1148 
1149  LONG rv;
1150  struct begin_struct scBeginStruct;
1151  SCONTEXTMAP * currentContextMap;
1152  CHANNEL_MAP * pChannelMap;
1153 
1154  PROFILE_START
1155  API_TRACE_IN("%ld", hCard)
1156 
1157  /*
1158  * Query the server every so often until the sharing violation ends
1159  * and then hold the lock for yourself.
1160  */
1161 
1162  for(;;)
1163  {
1164  /*
1165  * Make sure this handle has been opened
1166  */
1167  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1168  &pChannelMap);
1169  if (rv == -1)
1170  return SCARD_E_INVALID_HANDLE;
1171 
1172  scBeginStruct.hCard = hCard;
1173  scBeginStruct.rv = SCARD_S_SUCCESS;
1174 
1176  currentContextMap->dwClientID,
1177  sizeof(scBeginStruct), (void *) &scBeginStruct);
1178 
1179  if (rv != SCARD_S_SUCCESS)
1180  break;
1181 
1182  /*
1183  * Read a message from the server
1184  */
1185  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1186  currentContextMap->dwClientID);
1187 
1188  if (rv != SCARD_S_SUCCESS)
1189  break;
1190 
1191  rv = scBeginStruct.rv;
1192 
1193  if (SCARD_E_SHARING_VIOLATION != rv)
1194  break;
1195 
1196  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1198  }
1199 
1200  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1201 
1202  PROFILE_END(rv)
1203  API_TRACE_OUT("")
1204 
1205  return rv;
1206 }
1207 
1247 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1248 {
1249  LONG rv;
1250  struct end_struct scEndStruct;
1251  int randnum;
1252  SCONTEXTMAP * currentContextMap;
1253  CHANNEL_MAP * pChannelMap;
1254 
1255  PROFILE_START
1256  API_TRACE_IN("%ld", hCard)
1257 
1258  /*
1259  * Make sure this handle has been opened
1260  */
1261  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1262  &pChannelMap);
1263  if (rv == -1)
1264  return SCARD_E_INVALID_HANDLE;
1265 
1266  scEndStruct.hCard = hCard;
1267  scEndStruct.dwDisposition = dwDisposition;
1268  scEndStruct.rv = SCARD_S_SUCCESS;
1269 
1271  currentContextMap->dwClientID,
1272  sizeof(scEndStruct), (void *) &scEndStruct);
1273 
1274  if (rv != SCARD_S_SUCCESS)
1275  goto end;
1276 
1277  /*
1278  * Read a message from the server
1279  */
1280  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1281  currentContextMap->dwClientID);
1282 
1283  if (rv != SCARD_S_SUCCESS)
1284  goto end;
1285 
1286  /*
1287  * This helps prevent starvation
1288  */
1289  randnum = SYS_RandomInt(1000, 10000);
1290  (void)SYS_USleep(randnum);
1291  rv = scEndStruct.rv;
1292 
1293 end:
1294  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1295 
1296  PROFILE_END(rv)
1297  API_TRACE_OUT("")
1298 
1299  return rv;
1300 }
1301 
1397 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1398  LPDWORD pcchReaderLen, LPDWORD pdwState,
1399  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1400 {
1401  DWORD dwReaderLen, dwAtrLen;
1402  LONG rv;
1403  int i;
1404  struct status_struct scStatusStruct;
1405  SCONTEXTMAP * currentContextMap;
1406  CHANNEL_MAP * pChannelMap;
1407  char *r;
1408  char *bufReader = NULL;
1409  LPBYTE bufAtr = NULL;
1410  DWORD dummy = 0;
1411 
1412  PROFILE_START
1413 
1414  /* default output values */
1415  if (pdwState)
1416  *pdwState = 0;
1417 
1418  if (pdwProtocol)
1419  *pdwProtocol = 0;
1420 
1421  /* Check for NULL parameters */
1422  if (pcchReaderLen == NULL)
1423  pcchReaderLen = &dummy;
1424 
1425  if (pcbAtrLen == NULL)
1426  pcbAtrLen = &dummy;
1427 
1428  /* length passed from caller */
1429  dwReaderLen = *pcchReaderLen;
1430  dwAtrLen = *pcbAtrLen;
1431 
1432  *pcchReaderLen = 0;
1433  *pcbAtrLen = 0;
1434 
1435  /* Retry loop for blocking behaviour */
1436 retry:
1437 
1438  /*
1439  * Make sure this handle has been opened
1440  */
1441  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1442  &pChannelMap);
1443  if (rv == -1)
1444  return SCARD_E_INVALID_HANDLE;
1445 
1446  /* synchronize reader states with daemon */
1447  rv = getReaderStates(currentContextMap);
1448  if (rv != SCARD_S_SUCCESS)
1449  goto end;
1450 
1451  r = pChannelMap->readerName;
1452  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1453  {
1454  /* by default r == NULL */
1455  if (r && strcmp(r, readerStates[i].readerName) == 0)
1456  break;
1457  }
1458 
1460  {
1462  goto end;
1463  }
1464 
1465  /* initialise the structure */
1466  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1467  scStatusStruct.hCard = hCard;
1468 
1469  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1470  sizeof(scStatusStruct), (void *) &scStatusStruct);
1471 
1472  if (rv != SCARD_S_SUCCESS)
1473  goto end;
1474 
1475  /*
1476  * Read a message from the server
1477  */
1478  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1479  currentContextMap->dwClientID);
1480 
1481  if (rv != SCARD_S_SUCCESS)
1482  goto end;
1483 
1484  rv = scStatusStruct.rv;
1485 
1486  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1487  {
1488  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1490  goto retry;
1491  }
1492 
1493  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1494  {
1495  /*
1496  * An event must have occurred
1497  */
1498  goto end;
1499  }
1500 
1501  /*
1502  * Now continue with the client side SCardStatus
1503  */
1504 
1505  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1506  *pcbAtrLen = readerStates[i].cardAtrLength;
1507 
1508  if (pdwState)
1509  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1510 
1511  if (pdwProtocol)
1512  *pdwProtocol = readerStates[i].cardProtocol;
1513 
1514  if (SCARD_AUTOALLOCATE == dwReaderLen)
1515  {
1516  dwReaderLen = *pcchReaderLen;
1517  if (NULL == szReaderName)
1518  {
1520  goto end;
1521  }
1522  bufReader = malloc(dwReaderLen);
1523  if (NULL == bufReader)
1524  {
1525  rv = SCARD_E_NO_MEMORY;
1526  goto end;
1527  }
1528  *(char **)szReaderName = bufReader;
1529  }
1530  else
1531  bufReader = szReaderName;
1532 
1533  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1534  if (bufReader)
1535  {
1536  if (*pcchReaderLen > dwReaderLen)
1538 
1539  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1540  }
1541 
1542  if (SCARD_AUTOALLOCATE == dwAtrLen)
1543  {
1544  dwAtrLen = *pcbAtrLen;
1545  if (NULL == pbAtr)
1546  {
1548  goto end;
1549  }
1550  bufAtr = malloc(dwAtrLen);
1551  if (NULL == bufAtr)
1552  {
1553  rv = SCARD_E_NO_MEMORY;
1554  goto end;
1555  }
1556  *(LPBYTE *)pbAtr = bufAtr;
1557  }
1558  else
1559  bufAtr = pbAtr;
1560 
1561  if (bufAtr)
1562  {
1563  if (*pcbAtrLen > dwAtrLen)
1565 
1566  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1567  }
1568 
1569 end:
1570  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1571 
1572  PROFILE_END(rv)
1573 
1574  return rv;
1575 }
1576 
1684 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1685  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1686 {
1687  SCARD_READERSTATE *currReader;
1688  READER_STATE *rContext;
1689  long dwTime;
1690  DWORD dwBreakFlag = 0;
1691  unsigned int j;
1692  SCONTEXTMAP * currentContextMap;
1693  int currentReaderCount = 0;
1694  LONG rv = SCARD_S_SUCCESS;
1695 
1696  PROFILE_START
1697  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1698 #ifdef DO_TRACE
1699  for (j=0; j<cReaders; j++)
1700  {
1701  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1702  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1703  }
1704 #endif
1705 
1706  if ((rgReaderStates == NULL && cReaders > 0)
1707  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1708  {
1710  goto error;
1711  }
1712 
1713  /* Check the integrity of the reader states structures */
1714  for (j = 0; j < cReaders; j++)
1715  {
1716  if (rgReaderStates[j].szReader == NULL)
1717  return SCARD_E_INVALID_VALUE;
1718  }
1719 
1720  /* return if all readers are SCARD_STATE_IGNORE */
1721  if (cReaders > 0)
1722  {
1723  int nbNonIgnoredReaders = cReaders;
1724 
1725  for (j=0; j<cReaders; j++)
1726  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1727  nbNonIgnoredReaders--;
1728 
1729  if (0 == nbNonIgnoredReaders)
1730  {
1731  rv = SCARD_S_SUCCESS;
1732  goto error;
1733  }
1734  }
1735  else
1736  {
1737  /* reader list is empty */
1738  rv = SCARD_S_SUCCESS;
1739  goto error;
1740  }
1741 
1742  /*
1743  * Make sure this context has been opened
1744  */
1745  currentContextMap = SCardGetAndLockContext(hContext);
1746  if (NULL == currentContextMap)
1747  {
1749  goto error;
1750  }
1751 
1752  /* synchronize reader states with daemon */
1753  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1754  if (rv != SCARD_S_SUCCESS)
1755  goto end;
1756 
1757  /* check all the readers are already known */
1758  for (j=0; j<cReaders; j++)
1759  {
1760  const char *readerName;
1761  int i;
1762 
1763  readerName = rgReaderStates[j].szReader;
1764  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1765  {
1766  if (strcmp(readerName, readerStates[i].readerName) == 0)
1767  break;
1768  }
1769 
1770  /* The requested reader name is not recognized */
1772  {
1773  /* PnP special reader? */
1774  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1775  {
1777  goto end;
1778  }
1779  }
1780  }
1781 
1782  /* Clear the event state for all readers */
1783  for (j = 0; j < cReaders; j++)
1784  rgReaderStates[j].dwEventState = 0;
1785 
1786  /* Now is where we start our event checking loop */
1787  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1788 
1789  /* Get the initial reader count on the system */
1790  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1791  if (readerStates[j].readerName[0] != '\0')
1792  currentReaderCount++;
1793 
1794  /* catch possible sign extension problems from 32 to 64-bits integers */
1795  if ((DWORD)-1 == dwTimeout)
1796  dwTimeout = INFINITE;
1797  if (INFINITE == dwTimeout)
1798  dwTime = 60*1000; /* "infinite" timeout */
1799  else
1800  dwTime = dwTimeout;
1801 
1802  j = 0;
1803  do
1804  {
1805  currReader = &rgReaderStates[j];
1806 
1807  /* Ignore for IGNORED readers */
1808  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1809  {
1810  const char *readerName;
1811  int i;
1812 
1813  /* Looks for correct readernames */
1814  readerName = currReader->szReader;
1815  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1816  {
1817  if (strcmp(readerName, readerStates[i].readerName) == 0)
1818  break;
1819  }
1820 
1821  /* The requested reader name is not recognized */
1823  {
1824  /* PnP special reader? */
1825  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1826  {
1827  int k, newReaderCount = 0;
1828 
1829  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1830  if (readerStates[k].readerName[0] != '\0')
1831  newReaderCount++;
1832 
1833  if (newReaderCount != currentReaderCount)
1834  {
1835  Log1(PCSC_LOG_INFO, "Reader list changed");
1836  currentReaderCount = newReaderCount;
1837 
1838  currReader->dwEventState |= SCARD_STATE_CHANGED;
1839  dwBreakFlag = 1;
1840  }
1841  }
1842  else
1843  {
1844  currReader->dwEventState =
1846  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1847  {
1848  currReader->dwEventState |= SCARD_STATE_CHANGED;
1849  /*
1850  * Spec says use SCARD_STATE_IGNORE but a removed USB
1851  * reader with eventState fed into currentState will
1852  * be ignored forever
1853  */
1854  dwBreakFlag = 1;
1855  }
1856  }
1857  }
1858  else
1859  {
1860  uint32_t readerState;
1861 
1862  /* The reader has come back after being away */
1863  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1864  {
1865  currReader->dwEventState |= SCARD_STATE_CHANGED;
1866  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1867  Log0(PCSC_LOG_DEBUG);
1868  dwBreakFlag = 1;
1869  }
1870 
1871  /* Set the reader status structure */
1872  rContext = &readerStates[i];
1873 
1874  /* Now we check all the Reader States */
1875  readerState = rContext->readerState;
1876 
1877  /* only if current state has an non null event counter */
1878  if (currReader->dwCurrentState & 0xFFFF0000)
1879  {
1880  unsigned int currentCounter;
1881 
1882  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1883 
1884  /* has the event counter changed since the last call? */
1885  if (rContext->eventCounter != currentCounter)
1886  {
1887  currReader->dwEventState |= SCARD_STATE_CHANGED;
1888  Log0(PCSC_LOG_DEBUG);
1889  dwBreakFlag = 1;
1890  }
1891  }
1892 
1893  /* add an event counter in the upper word of dwEventState */
1894  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1895  | (rContext->eventCounter << 16));
1896 
1897  /* Check if the reader is in the correct state */
1898  if (readerState & SCARD_UNKNOWN)
1899  {
1900  /* reader is in bad state */
1901  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1902  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1903  {
1904  /* App thinks reader is in good state and it is not */
1905  currReader->dwEventState |= SCARD_STATE_CHANGED;
1906  Log0(PCSC_LOG_DEBUG);
1907  dwBreakFlag = 1;
1908  }
1909  }
1910  else
1911  {
1912  /* App thinks reader in bad state but it is not */
1913  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1914  {
1915  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1916  currReader->dwEventState |= SCARD_STATE_CHANGED;
1917  Log0(PCSC_LOG_DEBUG);
1918  dwBreakFlag = 1;
1919  }
1920  }
1921 
1922  /* Check for card presence in the reader */
1923  if (readerState & SCARD_PRESENT)
1924  {
1925  /* card present but not yet powered up */
1926  if (0 == rContext->cardAtrLength)
1927  /* Allow the status thread to convey information */
1929 
1930  currReader->cbAtr = rContext->cardAtrLength;
1931  memcpy(currReader->rgbAtr, rContext->cardAtr,
1932  currReader->cbAtr);
1933  }
1934  else
1935  currReader->cbAtr = 0;
1936 
1937  /* Card is now absent */
1938  if (readerState & SCARD_ABSENT)
1939  {
1940  currReader->dwEventState |= SCARD_STATE_EMPTY;
1941  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1942  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1943  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1944  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1945  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1946  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1947  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1948  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1949 
1950  /* After present the rest are assumed */
1951  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1952  {
1953  currReader->dwEventState |= SCARD_STATE_CHANGED;
1954  Log0(PCSC_LOG_DEBUG);
1955  dwBreakFlag = 1;
1956  }
1957  }
1958  /* Card is now present */
1959  else if (readerState & SCARD_PRESENT)
1960  {
1961  currReader->dwEventState |= SCARD_STATE_PRESENT;
1962  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1963  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1964  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1965  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1966  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1967  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1968 
1969  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1970  {
1971  currReader->dwEventState |= SCARD_STATE_CHANGED;
1972  Log0(PCSC_LOG_DEBUG);
1973  dwBreakFlag = 1;
1974  }
1975 
1976  if (readerState & SCARD_SWALLOWED)
1977  {
1978  currReader->dwEventState |= SCARD_STATE_MUTE;
1979  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1980  {
1981  currReader->dwEventState |= SCARD_STATE_CHANGED;
1982  Log0(PCSC_LOG_DEBUG);
1983  dwBreakFlag = 1;
1984  }
1985  }
1986  else
1987  {
1988  /* App thinks card is mute but it is not */
1989  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1990  {
1991  currReader->dwEventState |= SCARD_STATE_CHANGED;
1992  Log0(PCSC_LOG_DEBUG);
1993  dwBreakFlag = 1;
1994  }
1995  }
1996  }
1997 
1998  /* Now figure out sharing modes */
2000  {
2001  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2002  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2003  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2004  {
2005  currReader->dwEventState |= SCARD_STATE_CHANGED;
2006  Log0(PCSC_LOG_DEBUG);
2007  dwBreakFlag = 1;
2008  }
2009  }
2010  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2011  {
2012  /* A card must be inserted for it to be INUSE */
2013  if (readerState & SCARD_PRESENT)
2014  {
2015  currReader->dwEventState |= SCARD_STATE_INUSE;
2016  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2017  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2018  {
2019  currReader->dwEventState |= SCARD_STATE_CHANGED;
2020  Log0(PCSC_LOG_DEBUG);
2021  dwBreakFlag = 1;
2022  }
2023  }
2024  }
2025  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2026  {
2027  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2028  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2029 
2030  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2031  {
2032  currReader->dwEventState |= SCARD_STATE_CHANGED;
2033  Log0(PCSC_LOG_DEBUG);
2034  dwBreakFlag = 1;
2035  }
2036  else if (currReader-> dwCurrentState
2038  {
2039  currReader->dwEventState |= SCARD_STATE_CHANGED;
2040  Log0(PCSC_LOG_DEBUG);
2041  dwBreakFlag = 1;
2042  }
2043  }
2044 
2045  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2046  {
2047  /*
2048  * Break out of the while .. loop and return status
2049  * once all the status's for all readers is met
2050  */
2051  currReader->dwEventState |= SCARD_STATE_CHANGED;
2052  Log0(PCSC_LOG_DEBUG);
2053  dwBreakFlag = 1;
2054  }
2055  } /* End of SCARD_STATE_UNKNOWN */
2056  } /* End of SCARD_STATE_IGNORE */
2057 
2058  /* Counter and resetter */
2059  j++;
2060  if (j == cReaders)
2061  {
2062  /* go back to the first reader */
2063  j = 0;
2064 
2065  /* Declare all the break conditions */
2066 
2067  /* Break if UNAWARE is set and all readers have been checked */
2068  if (dwBreakFlag == 1)
2069  break;
2070 
2071  /* Only sleep once for each cycle of reader checks. */
2072  {
2073  struct wait_reader_state_change waitStatusStruct = {0};
2074  struct timeval before, after;
2075 
2076  gettimeofday(&before, NULL);
2077 
2078  waitStatusStruct.rv = SCARD_S_SUCCESS;
2079 
2080  /* another thread can do SCardCancel() */
2081  currentContextMap->cancellable = TRUE;
2082 
2083  /*
2084  * Read a message from the server
2085  */
2087  &waitStatusStruct, sizeof(waitStatusStruct),
2088  currentContextMap->dwClientID, dwTime);
2089 
2090  /* SCardCancel() will return immediatly with success
2091  * because something changed on the daemon side. */
2092  currentContextMap->cancellable = FALSE;
2093 
2094  /* timeout */
2095  if (SCARD_E_TIMEOUT == rv)
2096  {
2097  /* ask server to remove us from the event list */
2098  rv = unregisterFromEvents(currentContextMap);
2099  }
2100 
2101  if (rv != SCARD_S_SUCCESS)
2102  goto end;
2103 
2104  /* an event occurs or SCardCancel() was called */
2105  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2106  {
2107  rv = waitStatusStruct.rv;
2108  goto end;
2109  }
2110 
2111  /* synchronize reader states with daemon */
2112  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2113  if (rv != SCARD_S_SUCCESS)
2114  goto end;
2115 
2116  if (INFINITE != dwTimeout)
2117  {
2118  long int diff;
2119 
2120  gettimeofday(&after, NULL);
2121  diff = time_sub(&after, &before);
2122  dwTime -= diff/1000;
2123  }
2124  }
2125 
2126  if (dwTimeout != INFINITE)
2127  {
2128  /* If time is greater than timeout and all readers have been
2129  * checked
2130  */
2131  if (dwTime <= 0)
2132  {
2133  rv = SCARD_E_TIMEOUT;
2134  goto end;
2135  }
2136  }
2137  }
2138  }
2139  while (1);
2140 
2141 end:
2142  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2143 
2144  /* if SCardCancel() has been used then the client is already
2145  * unregistered */
2146  if (SCARD_E_CANCELLED != rv)
2147  (void)unregisterFromEvents(currentContextMap);
2148 
2149  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2150 
2151 error:
2152  PROFILE_END(rv)
2153 #ifdef DO_TRACE
2154  for (j=0; j<cReaders; j++)
2155  {
2156  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2157  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2158  }
2159 #endif
2160 
2161  return rv;
2162 }
2163 
2214 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2215  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2216  LPDWORD lpBytesReturned)
2217 {
2218  LONG rv;
2219  struct control_struct scControlStruct;
2220  SCONTEXTMAP * currentContextMap;
2221  CHANNEL_MAP * pChannelMap;
2222 
2223  PROFILE_START
2224 
2225  /* 0 bytes received by default */
2226  if (NULL != lpBytesReturned)
2227  *lpBytesReturned = 0;
2228 
2229  /*
2230  * Make sure this handle has been opened
2231  */
2232  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2233  &pChannelMap);
2234  if (rv == -1)
2235  {
2236  PROFILE_END(SCARD_E_INVALID_HANDLE)
2237  return SCARD_E_INVALID_HANDLE;
2238  }
2239 
2240  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2241  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2242  {
2244  goto end;
2245  }
2246 
2247  scControlStruct.hCard = hCard;
2248  scControlStruct.dwControlCode = dwControlCode;
2249  scControlStruct.cbSendLength = cbSendLength;
2250  scControlStruct.cbRecvLength = cbRecvLength;
2251  scControlStruct.dwBytesReturned = 0;
2252  scControlStruct.rv = 0;
2253 
2254  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2255  sizeof(scControlStruct), &scControlStruct);
2256 
2257  if (rv != SCARD_S_SUCCESS)
2258  goto end;
2259 
2260  /* write the sent buffer */
2261  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2262  currentContextMap->dwClientID);
2263 
2264  if (rv != SCARD_S_SUCCESS)
2265  goto end;
2266 
2267  /*
2268  * Read a message from the server
2269  */
2270  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2271  currentContextMap->dwClientID);
2272 
2273  if (rv != SCARD_S_SUCCESS)
2274  goto end;
2275 
2276  if (SCARD_S_SUCCESS == scControlStruct.rv)
2277  {
2278  /* read the received buffer */
2279  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2280  currentContextMap->dwClientID);
2281 
2282  if (rv != SCARD_S_SUCCESS)
2283  goto end;
2284 
2285  }
2286 
2287  if (NULL != lpBytesReturned)
2288  *lpBytesReturned = scControlStruct.dwBytesReturned;
2289 
2290  rv = scControlStruct.rv;
2291 
2292 end:
2293  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2294 
2295  PROFILE_END(rv)
2296 
2297  return rv;
2298 }
2299 
2417 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2418  LPDWORD pcbAttrLen)
2419 {
2420  LONG ret;
2421  unsigned char *buf = NULL;
2422 
2423  PROFILE_START
2424 
2425  if (NULL == pcbAttrLen)
2426  {
2428  goto end;
2429  }
2430 
2431  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2432  {
2433  if (NULL == pbAttr)
2435 
2436  *pcbAttrLen = MAX_BUFFER_SIZE;
2437  buf = malloc(*pcbAttrLen);
2438  if (NULL == buf)
2439  {
2440  ret = SCARD_E_NO_MEMORY;
2441  goto end;
2442  }
2443 
2444  *(unsigned char **)pbAttr = buf;
2445  }
2446  else
2447  {
2448  buf = pbAttr;
2449 
2450  /* if only get the length */
2451  if (NULL == pbAttr)
2452  /* use a reasonable size */
2453  *pcbAttrLen = MAX_BUFFER_SIZE;
2454  }
2455 
2456  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2457  pcbAttrLen);
2458 
2459 end:
2460  PROFILE_END(ret)
2461 
2462  return ret;
2463 }
2464 
2500 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2501  DWORD cbAttrLen)
2502 {
2503  LONG ret;
2504 
2505  PROFILE_START
2506 
2507  if (NULL == pbAttr || 0 == cbAttrLen)
2509 
2510  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2511  &cbAttrLen);
2512 
2513  PROFILE_END(ret)
2514 
2515  return ret;
2516 }
2517 
2518 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2519  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2520 {
2521  LONG rv;
2522  struct getset_struct scGetSetStruct;
2523  SCONTEXTMAP * currentContextMap;
2524  CHANNEL_MAP * pChannelMap;
2525 
2526  /*
2527  * Make sure this handle has been opened
2528  */
2529  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2530  &pChannelMap);
2531  if (rv == -1)
2532  return SCARD_E_INVALID_HANDLE;
2533 
2534  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2535  {
2537  goto end;
2538  }
2539 
2540  scGetSetStruct.hCard = hCard;
2541  scGetSetStruct.dwAttrId = dwAttrId;
2542  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2543  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2544  if (SCARD_SET_ATTRIB == command)
2545  {
2546  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2547  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2548  }
2549  else
2550  /* we can get up to the communication buffer size */
2551  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2552 
2553  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2554  sizeof(scGetSetStruct), &scGetSetStruct);
2555 
2556  if (rv != SCARD_S_SUCCESS)
2557  goto end;
2558 
2559  /*
2560  * Read a message from the server
2561  */
2562  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2563  currentContextMap->dwClientID);
2564 
2565  if (rv != SCARD_S_SUCCESS)
2566  goto end;
2567 
2568  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2569  {
2570  /*
2571  * Copy and zero it so any secret information is not leaked
2572  */
2573  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2574  {
2575  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2576  * buffer overflow in the memcpy() bellow */
2577  DWORD correct_value = scGetSetStruct.cbAttrLen;
2578  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2579  *pcbAttrLen = correct_value;
2580 
2581  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2582  }
2583  else
2584  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2585 
2586  if (pbAttr)
2587  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2588 
2589  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2590  }
2591  rv = scGetSetStruct.rv;
2592 
2593 end:
2594  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2595 
2596  return rv;
2597 }
2598 
2657 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2658  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2659  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2660  LPDWORD pcbRecvLength)
2661 {
2662  LONG rv;
2663  SCONTEXTMAP * currentContextMap;
2664  CHANNEL_MAP * pChannelMap;
2665  struct transmit_struct scTransmitStruct;
2666 
2667  PROFILE_START
2668 
2669  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2670  pcbRecvLength == NULL || pioSendPci == NULL)
2672 
2673  /* Retry loop for blocking behaviour */
2674 retry:
2675 
2676  /*
2677  * Make sure this handle has been opened
2678  */
2679  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2680  &pChannelMap);
2681  if (rv == -1)
2682  {
2683  *pcbRecvLength = 0;
2684  PROFILE_END(SCARD_E_INVALID_HANDLE)
2685  return SCARD_E_INVALID_HANDLE;
2686  }
2687 
2688  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2689  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2690  {
2692  goto end;
2693  }
2694 
2695  scTransmitStruct.hCard = hCard;
2696  scTransmitStruct.cbSendLength = cbSendLength;
2697  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2698  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2699  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2700  scTransmitStruct.rv = SCARD_S_SUCCESS;
2701 
2702  if (pioRecvPci)
2703  {
2704  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2705  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2706  }
2707  else
2708  {
2709  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2710  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2711  }
2712 
2713  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2714  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2715 
2716  if (rv != SCARD_S_SUCCESS)
2717  goto end;
2718 
2719  /* write the sent buffer */
2720  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2721  currentContextMap->dwClientID);
2722 
2723  if (rv != SCARD_S_SUCCESS)
2724  goto end;
2725 
2726  /*
2727  * Read a message from the server
2728  */
2729  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2730  currentContextMap->dwClientID);
2731 
2732  if (rv != SCARD_S_SUCCESS)
2733  goto end;
2734 
2735  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2736  {
2737  /* read the received buffer */
2738  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2739  currentContextMap->dwClientID);
2740 
2741  if (rv != SCARD_S_SUCCESS)
2742  goto end;
2743 
2744  if (pioRecvPci)
2745  {
2746  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2747  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2748  }
2749  }
2750 
2751  rv = scTransmitStruct.rv;
2752 
2753  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2754  {
2755  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2757  goto retry;
2758  }
2759 
2760  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2761 
2762 end:
2763  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2764 
2765  PROFILE_END(rv)
2766 
2767  return rv;
2768 }
2769 
2832 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2833  LPSTR mszReaders, LPDWORD pcchReaders)
2834 {
2835  DWORD dwReadersLen = 0;
2836  int i;
2837  SCONTEXTMAP * currentContextMap;
2838  LONG rv = SCARD_S_SUCCESS;
2839  char *buf = NULL;
2840 
2841  (void)mszGroups;
2842  PROFILE_START
2843  API_TRACE_IN("%ld", hContext)
2844 
2845  /*
2846  * Check for NULL parameters
2847  */
2848  if (pcchReaders == NULL)
2850 
2851  /*
2852  * Make sure this context has been opened
2853  */
2854  currentContextMap = SCardGetAndLockContext(hContext);
2855  if (NULL == currentContextMap)
2856  {
2857  PROFILE_END(SCARD_E_INVALID_HANDLE)
2858  return SCARD_E_INVALID_HANDLE;
2859  }
2860 
2861  /* synchronize reader states with daemon */
2862  rv = getReaderStates(currentContextMap);
2863  if (rv != SCARD_S_SUCCESS)
2864  goto end;
2865 
2866  dwReadersLen = 0;
2867  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2868  if (readerStates[i].readerName[0] != '\0')
2869  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2870 
2871  /* for the last NULL byte */
2872  dwReadersLen += 1;
2873 
2874  if (1 == dwReadersLen)
2875  {
2877  goto end;
2878  }
2879 
2880  if (SCARD_AUTOALLOCATE == *pcchReaders)
2881  {
2882  if (NULL == mszReaders)
2883  {
2885  goto end;
2886  }
2887  buf = malloc(dwReadersLen);
2888  if (NULL == buf)
2889  {
2890  rv = SCARD_E_NO_MEMORY;
2891  goto end;
2892  }
2893  *(char **)mszReaders = buf;
2894  }
2895  else
2896  {
2897  buf = mszReaders;
2898 
2899  /* not enough place to store the reader names */
2900  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2901  {
2903  goto end;
2904  }
2905  }
2906 
2907  if (mszReaders == NULL) /* text array not allocated */
2908  goto end;
2909 
2910  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2911  {
2912  if (readerStates[i].readerName[0] != '\0')
2913  {
2914  /*
2915  * Build the multi-string
2916  */
2917  strcpy(buf, readerStates[i].readerName);
2918  buf += strlen(readerStates[i].readerName)+1;
2919  }
2920  }
2921  *buf = '\0'; /* Add the last null */
2922 
2923 end:
2924  /* set the reader names length */
2925  *pcchReaders = dwReadersLen;
2926 
2927  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2928 
2929  PROFILE_END(rv)
2930  API_TRACE_OUT("%d", *pcchReaders)
2931 
2932  return rv;
2933 }
2934 
2948 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2949 {
2950  LONG rv = SCARD_S_SUCCESS;
2951 
2952  PROFILE_START
2953 
2954  /*
2955  * Make sure this context has been opened
2956  */
2957  if (! SCardGetContextValidity(hContext))
2958  return SCARD_E_INVALID_HANDLE;
2959 
2960  free((void *)pvMem);
2961 
2962  PROFILE_END(rv)
2963 
2964  return rv;
2965 }
2966 
3018 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3019  LPDWORD pcchGroups)
3020 {
3021  LONG rv = SCARD_S_SUCCESS;
3022  SCONTEXTMAP * currentContextMap;
3023  char *buf = NULL;
3024 
3025  PROFILE_START
3026 
3027  /* Multi-string with two trailing \0 */
3028  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3029  const unsigned int dwGroups = sizeof(ReaderGroup);
3030 
3031  /*
3032  * Make sure this context has been opened
3033  */
3034  currentContextMap = SCardGetAndLockContext(hContext);
3035  if (NULL == currentContextMap)
3036  return SCARD_E_INVALID_HANDLE;
3037 
3038  if (SCARD_AUTOALLOCATE == *pcchGroups)
3039  {
3040  if (NULL == mszGroups)
3041  {
3043  goto end;
3044  }
3045  buf = malloc(dwGroups);
3046  if (NULL == buf)
3047  {
3048  rv = SCARD_E_NO_MEMORY;
3049  goto end;
3050  }
3051  *(char **)mszGroups = buf;
3052  }
3053  else
3054  {
3055  buf = mszGroups;
3056 
3057  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3058  {
3060  goto end;
3061  }
3062  }
3063 
3064  if (buf)
3065  memcpy(buf, ReaderGroup, dwGroups);
3066 
3067 end:
3068  *pcchGroups = dwGroups;
3069 
3070  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3071 
3072  PROFILE_END(rv)
3073 
3074  return rv;
3075 }
3076 
3109 {
3110  SCONTEXTMAP * currentContextMap;
3111  LONG rv = SCARD_S_SUCCESS;
3112  uint32_t dwClientID = 0;
3113  struct cancel_struct scCancelStruct;
3114  char cancellable;
3115 
3116  PROFILE_START
3117  API_TRACE_IN("%ld", hContext)
3118 
3119  /*
3120  * Make sure this context has been opened
3121  */
3122  (void)SCardLockThread();
3123  currentContextMap = SCardGetContextTH(hContext);
3124 
3125  if (NULL == currentContextMap)
3126  {
3127  (void)SCardUnlockThread();
3129  goto error;
3130  }
3131  cancellable = currentContextMap->cancellable;
3132  (void)SCardUnlockThread();
3133 
3134  if (! cancellable)
3135  {
3136  rv = SCARD_S_SUCCESS;
3137  goto error;
3138  }
3139 
3140  /* create a new connection to the server */
3141  if (ClientSetupSession(&dwClientID) != 0)
3142  {
3143  rv = SCARD_E_NO_SERVICE;
3144  goto error;
3145  }
3146 
3147  scCancelStruct.hContext = hContext;
3148  scCancelStruct.rv = SCARD_S_SUCCESS;
3149 
3150  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3151  sizeof(scCancelStruct), (void *) &scCancelStruct);
3152 
3153  if (rv != SCARD_S_SUCCESS)
3154  goto end;
3155 
3156  /*
3157  * Read a message from the server
3158  */
3159  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3160 
3161  if (rv != SCARD_S_SUCCESS)
3162  goto end;
3163 
3164  rv = scCancelStruct.rv;
3165 end:
3166  ClientCloseSession(dwClientID);
3167 
3168 error:
3169  PROFILE_END(rv)
3170  API_TRACE_OUT("")
3171 
3172  return rv;
3173 }
3174 
3199 {
3200  LONG rv;
3201 
3202  PROFILE_START
3203  API_TRACE_IN("%ld", hContext)
3204 
3205  rv = SCARD_S_SUCCESS;
3206 
3207  /*
3208  * Make sure this context has been opened
3209  */
3210  if (! SCardGetContextValidity(hContext))
3212 
3213  PROFILE_END(rv)
3214  API_TRACE_OUT("")
3215 
3216  return rv;
3217 }
3218 
3235 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3236 {
3237  int lrv;
3238  SCONTEXTMAP * newContextMap;
3239 
3240  newContextMap = malloc(sizeof(SCONTEXTMAP));
3241  if (NULL == newContextMap)
3242  return SCARD_E_NO_MEMORY;
3243 
3244  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3245  newContextMap->hContext = hContext;
3246  newContextMap->dwClientID = dwClientID;
3247  newContextMap->cancellable = FALSE;
3248 
3249  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3250 
3251  lrv = list_init(&newContextMap->channelMapList);
3252  if (lrv < 0)
3253  {
3254  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3255  goto error;
3256  }
3257 
3258  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3259  CHANNEL_MAP_seeker);
3260  if (lrv <0)
3261  {
3262  Log2(PCSC_LOG_CRITICAL,
3263  "list_attributes_seeker failed with return value: %d", lrv);
3264  list_destroy(&newContextMap->channelMapList);
3265  goto error;
3266  }
3267 
3268  lrv = list_append(&contextMapList, newContextMap);
3269  if (lrv < 0)
3270  {
3271  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3272  lrv);
3273  list_destroy(&newContextMap->channelMapList);
3274  goto error;
3275  }
3276 
3277  return SCARD_S_SUCCESS;
3278 
3279 error:
3280 
3281  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3282  free(newContextMap);
3283 
3284  return SCARD_E_NO_MEMORY;
3285 }
3286 
3304 {
3305  SCONTEXTMAP * currentContextMap;
3306 
3307  SCardLockThread();
3308  currentContextMap = SCardGetContextTH(hContext);
3309 
3310  /* lock the context (if available) */
3311  if (NULL != currentContextMap)
3312  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3313 
3315 
3316  return currentContextMap;
3317 }
3318 
3332 {
3333  return list_seek(&contextMapList, &hContext);
3334 }
3335 
3342 static void SCardRemoveContext(SCARDCONTEXT hContext)
3343 {
3344  SCONTEXTMAP * currentContextMap;
3345  currentContextMap = SCardGetContextTH(hContext);
3346 
3347  if (NULL != currentContextMap)
3348  SCardCleanContext(currentContextMap);
3349 }
3350 
3351 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3352 {
3353  int list_index, lrv;
3354  int listSize;
3355  CHANNEL_MAP * currentChannelMap;
3356 
3357  targetContextMap->hContext = 0;
3358  ClientCloseSession(targetContextMap->dwClientID);
3359  targetContextMap->dwClientID = 0;
3360  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3361 
3362  listSize = list_size(&targetContextMap->channelMapList);
3363  for (list_index = 0; list_index < listSize; list_index++)
3364  {
3365  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3366  list_index);
3367  if (NULL == currentChannelMap)
3368  {
3369  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3370  list_index);
3371  continue;
3372  }
3373  else
3374  {
3375  free(currentChannelMap->readerName);
3376  free(currentChannelMap);
3377  }
3378 
3379  }
3380  list_destroy(&targetContextMap->channelMapList);
3381 
3382  lrv = list_delete(&contextMapList, targetContextMap);
3383  if (lrv < 0)
3384  {
3385  Log2(PCSC_LOG_CRITICAL,
3386  "list_delete failed with return value: %d", lrv);
3387  }
3388 
3389  free(targetContextMap);
3390 
3391  return;
3392 }
3393 
3394 /*
3395  * Functions for managing hCard values returned from SCardConnect.
3396  */
3397 
3398 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3399  LPCSTR readerName)
3400 {
3401  CHANNEL_MAP * newChannelMap;
3402  int lrv = -1;
3403 
3404  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3405  if (NULL == newChannelMap)
3406  return SCARD_E_NO_MEMORY;
3407 
3408  newChannelMap->hCard = hCard;
3409  newChannelMap->readerName = strdup(readerName);
3410 
3411  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3412  if (lrv < 0)
3413  {
3414  free(newChannelMap->readerName);
3415  free(newChannelMap);
3416  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3417  lrv);
3418  return SCARD_E_NO_MEMORY;
3419  }
3420 
3421  return SCARD_S_SUCCESS;
3422 }
3423 
3424 static void SCardRemoveHandle(SCARDHANDLE hCard)
3425 {
3426  SCONTEXTMAP * currentContextMap;
3427  CHANNEL_MAP * currentChannelMap;
3428  int lrv;
3429  LONG rv;
3430 
3431  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3432  &currentChannelMap);
3433  if (rv == -1)
3434  return;
3435 
3436  free(currentChannelMap->readerName);
3437 
3438  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3439  if (lrv < 0)
3440  {
3441  Log2(PCSC_LOG_CRITICAL,
3442  "list_delete failed with return value: %d", lrv);
3443  }
3444 
3445  free(currentChannelMap);
3446 
3447  return;
3448 }
3449 
3450 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3451  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3452 {
3453  LONG rv;
3454 
3455  if (0 == hCard)
3456  return -1;
3457 
3458  SCardLockThread();
3459  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3460  targetChannelMap);
3461 
3462  if (SCARD_S_SUCCESS == rv)
3463  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3464 
3466 
3467  return rv;
3468 }
3469 
3470 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3471  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3472 {
3473  int listSize;
3474  int list_index;
3475  SCONTEXTMAP * currentContextMap;
3476  CHANNEL_MAP * currentChannelMap;
3477 
3478  /* Best to get the caller a crash early if we fail unsafely */
3479  *targetContextMap = NULL;
3480  *targetChannelMap = NULL;
3481 
3482  listSize = list_size(&contextMapList);
3483 
3484  for (list_index = 0; list_index < listSize; list_index++)
3485  {
3486  currentContextMap = list_get_at(&contextMapList, list_index);
3487  if (currentContextMap == NULL)
3488  {
3489  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3490  list_index);
3491  continue;
3492  }
3493  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3494  &hCard);
3495  if (currentChannelMap != NULL)
3496  {
3497  *targetContextMap = currentContextMap;
3498  *targetChannelMap = currentChannelMap;
3499  return SCARD_S_SUCCESS;
3500  }
3501  }
3502 
3503  return -1;
3504 }
3505 
3514 {
3515  LONG rv;
3516  struct stat statBuffer;
3517  char *socketName;
3518 
3519  socketName = getSocketName();
3520  rv = stat(socketName, &statBuffer);
3521 
3522  if (rv != 0)
3523  {
3524  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3525  socketName, strerror(errno));
3526  return SCARD_E_NO_SERVICE;
3527  }
3528 
3529  return SCARD_S_SUCCESS;
3530 }
3531 
3532 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3533 {
3534  int32_t dwClientID = currentContextMap->dwClientID;
3535  LONG rv;
3536 
3537  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3538  if (rv != SCARD_S_SUCCESS)
3539  return rv;
3540 
3541  /* Read a message from the server */
3542  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3543  if (rv != SCARD_S_SUCCESS)
3544  return rv;
3545 
3546  return SCARD_S_SUCCESS;
3547 }
3548 
3549 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3550 {
3551  int32_t dwClientID = currentContextMap->dwClientID;
3552  LONG rv;
3553 
3554  /* Get current reader states from server and register on event list */
3556  0, NULL);
3557  if (rv != SCARD_S_SUCCESS)
3558  return rv;
3559 
3560  /* Read a message from the server */
3561  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3562  return rv;
3563 }
3564 
3565 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3566 {
3567  int32_t dwClientID = currentContextMap->dwClientID;
3568  LONG rv;
3569  struct wait_reader_state_change waitStatusStruct = {0};
3570 
3571  /* ask server to remove us from the event list */
3573  dwClientID, 0, NULL);
3574  if (rv != SCARD_S_SUCCESS)
3575  return rv;
3576 
3577  /* This message can be the response to
3578  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3579  * cancel notification.
3580  * The server side ensures, that no more messages will be sent to
3581  * the client. */
3582 
3583  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3584  dwClientID);
3585  if (rv != SCARD_S_SUCCESS)
3586  return rv;
3587 
3588  /* if we received a cancel event the return value will be set
3589  * accordingly */
3590  rv = waitStatusStruct.rv;
3591 
3592  return rv;
3593 }
3594 
MessageReceiveTimeout
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
pubReaderStatesList::readerState
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:52
SCardReleaseContext
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
Definition: winscard_clnt.c:691
SCardDisconnect
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard_clnt.c:1057
_psContextMap::cancellable
char cancellable
We are in a cancellable call.
Definition: winscard_clnt.c:320
pubReaderStatesList::cardProtocol
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:57
debuglog.h
This handles debugging.
version_struct::minor
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
SCARD_STATE_EXCLUSIVE
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
SCARD_PROTOCOL_ANY
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
SCardEstablishContextTH
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
Definition: winscard_clnt.c:527
SCardGetAttrib
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard_clnt.c:2417
establish_struct
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
SCARD_E_INVALID_PARAMETER
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
wait_reader_state_change
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:107
SCardGetContextTH
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
Definition: winscard_clnt.c:3331
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
isExecuted
static short isExecuted
Make sure the initialization code is executed only once.
Definition: winscard_clnt.c:352
pubReaderStatesList::eventCounter
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
SCARD_STATE_PRESENT
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
PCSCLITE_SHARING_LAST_CONTEXT
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:71
MessageSendWithHeader
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
pubReaderStatesList
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:48
SYS_USleep
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
pcsc_stringify_error
const PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:82
SCARD_STATE_UNAVAILABLE
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
SCardUnlockThread
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
Definition: winscard_clnt.c:413
PROTOCOL_VERSION_MAJOR
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:47
SCARD_STATE_INUSE
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:274
disconnect_struct
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:85
SCARD_ABSENT
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
SCardCancel
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
Definition: winscard_clnt.c:3108
SCardGetContextValidity
static int SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
Definition: winscard_clnt.c:427
SCARD_IO_REQUEST::cbPciLength
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:95
SCardEstablishContext
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
Definition: winscard_clnt.c:476
SCARD_STATE_UNKNOWN
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
SCardListReaderGroups
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
Definition: winscard_clnt.c:3018
PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:75
SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:79
sys_generic.h
This handles abstract system level calls.
SCARD_READERSTATE
Definition: pcsclite.h:67
SCARD_E_SHARING_VIOLATION
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
SCARD_UNKNOWN
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
readerfactory.h
This keeps track of a list of currently available reader structures.
ClientCloseSession
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
g_rgSCardRawPci
const PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
Definition: winscard_clnt.c:371
eventhandler.h
This handles card insertion/removal events, updates ATR, protocol, and status information.
cancel_struct
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
SCARD_E_READER_UNAVAILABLE
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
SCARD_AUTOALLOCATE
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:88
SCARDHANDLE
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
pubReaderStatesList::readerSharing
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:53
MAX_BUFFER_SIZE_EXTENDED
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
_psContextMap
Represents an Application Context on the Client side.
Definition: winscard_clnt.c:314
SCardLockThread
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
Definition: winscard_clnt.c:403
SCARD_E_CANCELLED
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
list_t
list object
Definition: simclist.h:181
control_struct
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:246
connect_struct
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:94
status_struct
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
getset_struct
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
SCARD_SWALLOWED
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
g_rgSCardT1Pci
const PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
Definition: winscard_clnt.c:369
SCARD_E_INSUFFICIENT_BUFFER
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:90
SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:83
SCardFreeMemory
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
Definition: winscard_clnt.c:2948
SCardBeginTransaction
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
Definition: winscard_clnt.c:1146
SCARD_PROTOCOL_T0
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
_psContextMap::mMutex
pthread_mutex_t mMutex
Mutex for this context.
Definition: winscard_clnt.c:318
SCARD_E_NO_READERS_AVAILABLE
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:80
begin_struct
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
version_struct
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:93
SCardCheckDaemonAvailability
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
Definition: winscard_clnt.c:3513
SCARD_STATE_IGNORE
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
clientMutex
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
Definition: winscard_clnt.c:359
SCARD_PROTOCOL_T1
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
_psChannelMap
Represents an Application Context Channel.
Definition: winscard_clnt.c:283
end_struct
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
winscard_msg.h
This defines some structures and #defines to be used over the transport layer.
SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:76
SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:91
g_rgSCardT0Pci
const PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
Definition: winscard_clnt.c:367
SCARD_PROTOCOL_RAW
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:243
pcscd.h
This keeps a list of defines for pcsc-lite.
INFINITE
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
SCardRemoveContext
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
Definition: winscard_clnt.c:3342
SCARD_E_NO_MEMORY
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
PCSCLITE_MAX_READERS_CONTEXTS
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
SCARD_E_TIMEOUT
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
SCARD_STATE_MUTE
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275
MessageReceive
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
ClientSetupSession
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:121
SCARD_IO_REQUEST::dwProtocol
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
PCSCLITE_LOCK_POLL_RATE
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
winscard.h
This handles smart card reader communications.
MessageSend
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
SCardReconnect
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().
Definition: winscard_clnt.c:958
pubReaderStatesList::cardAtr
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:55
SCARDCONTEXT
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
SYS_RandomInt
int SYS_RandomInt(int, int)
Generate a pseudo random number.
Definition: sys_unix.c:95
SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
SCARD_STATE_ATRMATCH
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:272
SCardIsValidContext
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
Definition: winscard_clnt.c:3198
PCSCLITE_STATUS_POLL_RATE
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
time_sub
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in ┬Ás between 2 struct timeval r = a - b
Definition: utils.c:136
PROTOCOL_VERSION_MINOR
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:49
SCARD_STATE_CHANGED
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
version_struct::major
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:56
reconnect_struct
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
SCardListReaders
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
Definition: winscard_clnt.c:2832
pubReaderStatesList::cardAtrLength
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:56
SCARD_IO_REQUEST
Protocol Control Information (PCI)
Definition: pcsclite.h:79
SCARD_E_INVALID_VALUE
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:77
SCARD_STATE_UNAWARE
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:265
SCardAddContext
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
Definition: winscard_clnt.c:3235
SCardStatus
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.
Definition: winscard_clnt.c:1397
SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:84
_psContextMap::dwClientID
DWORD dwClientID
Client Connection ID.
Definition: winscard_clnt.c:316
SCARD_F_COMM_ERROR
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:81
SCardControl
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.
Definition: winscard_clnt.c:2214
SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:86
SCARD_PRESENT
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
SCARD_E_INVALID_HANDLE
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
transmit_struct
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
SCardGetAndLockContext
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
Definition: winscard_clnt.c:3303
SCardEndTransaction
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard_clnt.c:1247
CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:92
_psContextMap::hContext
SCARDCONTEXT hContext
Application Context ID.
Definition: winscard_clnt.c:317
SCardGetStatusChange
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.
Definition: winscard_clnt.c:1684
SCARD_STATE_EMPTY
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
SCARD_E_UNKNOWN_READER
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
readerStates
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
Definition: winscard_clnt.c:364
SCARD_E_NO_SERVICE
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
SCardConnect
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
Definition: winscard_clnt.c:803
release_struct
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
PCSCLITE_SHARING_NO_CONTEXT
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:73
SCardSetAttrib
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard_clnt.c:2500
SCardTransmit
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().
Definition: winscard_clnt.c:2657