pcsc-lite  2.0.3
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 #include <stdbool.h>
118 
119 #include "misc.h"
120 #include "pcscd.h"
121 #include "winscard.h"
122 #include "debuglog.h"
123 
124 #include "readerfactory.h"
125 #include "eventhandler.h"
126 #include "sys_generic.h"
127 #include "winscard_msg.h"
128 #include "utils.h"
129 
130 /* Display, on stderr, a trace of the WinSCard calls with arguments and
131  * results */
132 //#define DO_TRACE
133 
134 /* Profile the execution time of WinSCard calls */
135 //#define DO_PROFILE
136 
137 
138 static bool sharing_shall_block = true;
139 
140 #define COLOR_RED "\33[01;31m"
141 #define COLOR_GREEN "\33[32m"
142 #define COLOR_BLUE "\33[34m"
143 #define COLOR_MAGENTA "\33[35m"
144 #define COLOR_NORMAL "\33[0m"
145 
146 #ifdef DO_TRACE
147 
148 #include <stdio.h>
149 #include <stdarg.h>
150 
151 static void trace(const char *func, const char direction, const char *fmt, ...)
152 {
153  va_list args;
154 
155  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
156  direction, pthread_self(), func);
157 
158  fprintf(stderr, COLOR_MAGENTA);
159  va_start(args, fmt);
160  vfprintf(stderr, fmt, args);
161  va_end(args);
162 
163  fprintf(stderr, COLOR_NORMAL "\n");
164 }
165 
166 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
167 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
168 #else
169 #define API_TRACE_IN(...)
170 #define API_TRACE_OUT(...)
171 #endif
172 
173 #ifdef DO_PROFILE
174 
175 #define PROFILE_FILE "/tmp/pcsc_profile"
176 #include <stdio.h>
177 #include <sys/time.h>
178 
179 /* we can profile a maximum of 5 simultaneous calls */
180 #define MAX_THREADS 5
181 pthread_t threads[MAX_THREADS];
182 struct timeval profile_time_start[MAX_THREADS];
183 FILE *profile_fd;
184 bool profile_tty;
185 
186 #define PROFILE_START profile_start();
187 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
188 
189 static void profile_start(void)
190 {
191  static bool initialized = false;
192  pthread_t t;
193  int i;
194 
195  if (!initialized)
196  {
197  char filename[80];
198 
199  initialized = true;
200  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
201  profile_fd = fopen(filename, "a+");
202  if (NULL == profile_fd)
203  {
204  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
205  PROFILE_FILE, strerror(errno));
206  exit(-1);
207  }
208  fprintf(profile_fd, "\nStart a new profile\n");
209 
210  if (isatty(fileno(stderr)))
211  profile_tty = true;
212  else
213  profile_tty = false;
214  }
215 
216  t = pthread_self();
217  for (i=0; i<MAX_THREADS; i++)
218  if (pthread_equal(0, threads[i]))
219  {
220  threads[i] = t;
221  break;
222  }
223 
224  gettimeofday(&profile_time_start[i], NULL);
225 } /* profile_start */
226 
227 static void profile_end(const char *f, LONG rv)
228 {
229  struct timeval profile_time_end;
230  long d;
231  pthread_t t;
232  int i;
233 
234  gettimeofday(&profile_time_end, NULL);
235 
236  t = pthread_self();
237  for (i=0; i<MAX_THREADS; i++)
238  if (pthread_equal(t, threads[i]))
239  break;
240 
241  if (i>=MAX_THREADS)
242  {
243  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
244  return;
245  }
246 
247  d = time_sub(&profile_time_end, &profile_time_start[i]);
248 
249  /* free this entry */
250  threads[i] = 0;
251 
252  if (profile_tty)
253  {
254  if (rv != SCARD_S_SUCCESS)
255  fprintf(stderr,
256  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
257  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
258  f, d, rv, pcsc_stringify_error(rv));
259  else
260  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
261  COLOR_NORMAL "\n", f, d);
262  }
263  fprintf(profile_fd, "%s %ld\n", f, d);
264  fflush(profile_fd);
265 } /* profile_end */
266 
267 #else
268 #define PROFILE_START
269 #define PROFILE_END(rv)
270 #endif
271 
277 {
278  SCARDHANDLE hCard;
279  LPSTR readerName;
280 };
281 
282 typedef struct _psChannelMap CHANNEL_MAP;
283 
284 static int CHANNEL_MAP_seeker(const void *el, const void *key)
285 {
286  const CHANNEL_MAP * channelMap = el;
287 
288  if ((el == NULL) || (key == NULL))
289  {
290  Log3(PCSC_LOG_CRITICAL,
291  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
292  el, key);
293  return 0;
294  }
295 
296  if (channelMap->hCard == *(SCARDHANDLE *)key)
297  return 1;
298 
299  return 0;
300 }
301 
308 {
309  DWORD dwClientID;
311  pthread_mutex_t mMutex;
312  list_t channelMapList;
313  bool cancellable;
314 };
320 typedef struct _psContextMap SCONTEXTMAP;
321 
322 static list_t contextMapList;
323 
324 static int SCONTEXTMAP_seeker(const void *el, const void *key)
325 {
326  const SCONTEXTMAP * contextMap = el;
327 
328  if ((el == NULL) || (key == NULL))
329  {
330  Log3(PCSC_LOG_CRITICAL,
331  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
332  el, key);
333  return 0;
334  }
335 
336  if (contextMap->hContext == *(SCARDCONTEXT *) key)
337  return 1;
338 
339  return 0;
340 }
341 
345 static bool isExecuted = false;
346 static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
347 
348 
353 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
354 
359 static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
360 
367 
368 
369 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
372 static void SCardRemoveContext(SCARDCONTEXT);
373 static void SCardCleanContext(SCONTEXTMAP *);
374 
375 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
376 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
377  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
378 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
379  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380 static void SCardRemoveHandle(SCARDHANDLE);
381 
382 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
383  LPBYTE pbAttr, LPDWORD pcbAttrLen);
384 
385 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
386 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
387 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
388 
389 /*
390  * Thread safety functions
391  */
398 inline static void SCardLockThread(void)
399 {
400  pthread_mutex_lock(&clientMutex);
401 }
402 
408 inline static void SCardUnlockThread(void)
409 {
410  pthread_mutex_unlock(&clientMutex);
411 }
412 
423 {
424  SCONTEXTMAP * currentContextMap;
425 
426  SCardLockThread();
427  currentContextMap = SCardGetContextTH(hContext);
429 
430  return currentContextMap != NULL;
431 }
432 
433 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
434  /*@out@*/ LPSCARDCONTEXT);
435 
471 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
472  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
473 {
474  LONG rv;
475 
476  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
477  PROFILE_START
478 
479  /* Check if the server is running */
481  if (rv != SCARD_S_SUCCESS)
482  goto end;
483 
484  SCardLockThread();
485  rv = SCardEstablishContextTH(dwScope, pvReserved1,
486  pvReserved2, phContext);
488 
489 end:
490  PROFILE_END(rv)
491  API_TRACE_OUT("%ld", *phContext)
492 
493  return rv;
494 }
495 
496 #ifdef DESTRUCTOR
497 DESTRUCTOR static void destructor(void)
498 {
499  list_destroy(&contextMapList);
500 }
501 #endif
502 
503 /*
504  * Do this only once:
505  * - Initialize context list.
506  */
507 static void init_lib(void)
508 {
509  int lrv;
510 
511  /* NOTE: The list will be freed only if DESTRUCTOR is defined.
512  * Applications which load and unload the library may leak
513  * the list's internal structures. */
514  lrv = list_init(&contextMapList);
515  if (lrv < 0)
516  {
517  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
518  lrv);
519  return;
520  }
521 
522  lrv = list_attributes_seeker(&contextMapList,
523  SCONTEXTMAP_seeker);
524  if (lrv <0)
525  {
526  Log2(PCSC_LOG_CRITICAL,
527  "list_attributes_seeker failed with return value: %d", lrv);
528  list_destroy(&contextMapList);
529  return;
530  }
531 
532  if (getenv("PCSCLITE_NO_BLOCKING"))
533  {
534  Log1(PCSC_LOG_INFO, "Disable shared blocking");
535  sharing_shall_block = false;
536  }
537 
538  isExecuted = true;
539 }
540 
568 static LONG SCardEstablishContextTH(DWORD dwScope,
569  /*@unused@*/ LPCVOID pvReserved1,
570  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
571 {
572  LONG rv;
573  struct establish_struct scEstablishStruct;
574  uint32_t dwClientID = 0;
575 
576  (void)pvReserved1;
577  (void)pvReserved2;
578  if (phContext == NULL)
580  else
581  *phContext = 0;
582 
583  pthread_once(&init_lib_control, init_lib);
584  if (!isExecuted)
585  return SCARD_E_NO_MEMORY;
586 
587  /* Establishes a connection to the server */
588  if (ClientSetupSession(&dwClientID) != 0)
589  {
590  return SCARD_E_NO_SERVICE;
591  }
592 
593  { /* exchange client/server protocol versions */
594  struct version_struct veStr;
595 
598  veStr.rv = SCARD_S_SUCCESS;
599 
600  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
601  &veStr);
602  if (rv != SCARD_S_SUCCESS)
603  goto cleanup;
604 
605  /* Read a message from the server */
606  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
607  if (rv != SCARD_S_SUCCESS)
608  {
609  Log1(PCSC_LOG_CRITICAL,
610  "Your pcscd is too old and does not support CMD_VERSION");
611  goto cleanup;
612  }
613 
614  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
615  veStr.major, veStr.minor);
616 
617  if (veStr.rv != SCARD_S_SUCCESS)
618  {
619  rv = veStr.rv;
620  goto cleanup;
621  }
622  }
623 
624 again:
625  /*
626  * Try to establish an Application Context with the server
627  */
628  scEstablishStruct.dwScope = dwScope;
629  scEstablishStruct.hContext = 0;
630  scEstablishStruct.rv = SCARD_S_SUCCESS;
631 
633  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
634 
635  if (rv != SCARD_S_SUCCESS)
636  goto cleanup;
637 
638  /*
639  * Read the response from the server
640  */
641  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
642  dwClientID);
643 
644  if (rv != SCARD_S_SUCCESS)
645  goto cleanup;
646 
647  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
648  {
649  rv = scEstablishStruct.rv;
650  goto cleanup;
651  }
652 
653  /* check we do not reuse an existing hContext */
654  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
655  /* we do not need to release the allocated context since
656  * SCardReleaseContext() does nothing on the server side */
657  goto again;
658 
659  *phContext = scEstablishStruct.hContext;
660 
661  /*
662  * Allocate the new hContext - if allocator full return an error
663  */
664  rv = SCardAddContext(*phContext, dwClientID);
665 
666  return rv;
667 
668 cleanup:
669  ClientCloseSession(dwClientID);
670 
671  return rv;
672 }
673 
696 {
697  LONG rv;
698  struct release_struct scReleaseStruct;
699  SCONTEXTMAP * currentContextMap;
700 
701  API_TRACE_IN("%ld", hContext)
702  PROFILE_START
703 
704  /*
705  * Make sure this context has been opened
706  * and get currentContextMap
707  */
708  currentContextMap = SCardGetAndLockContext(hContext);
709  if (NULL == currentContextMap)
710  {
712  goto error;
713  }
714 
715  scReleaseStruct.hContext = hContext;
716  scReleaseStruct.rv = SCARD_S_SUCCESS;
717 
719  currentContextMap->dwClientID,
720  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
721 
722  if (rv != SCARD_S_SUCCESS)
723  goto end;
724 
725  /*
726  * Read a message from the server
727  */
728  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
729  currentContextMap->dwClientID);
730 
731  if (rv != SCARD_S_SUCCESS)
732  goto end;
733 
734  rv = scReleaseStruct.rv;
735 end:
736  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
737 
738  /*
739  * Remove the local context from the stack
740  */
741  SCardLockThread();
742  SCardRemoveContext(hContext);
744 
745 error:
746  PROFILE_END(rv)
747  API_TRACE_OUT("")
748 
749  return rv;
750 }
751 
807 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
808  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
809  LPDWORD pdwActiveProtocol)
810 {
811  LONG rv;
812  struct connect_struct scConnectStruct;
813  SCONTEXTMAP * currentContextMap;
814 
815  PROFILE_START
816  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
817 
818  /*
819  * Check for NULL parameters
820  */
821  if (phCard == NULL || pdwActiveProtocol == NULL)
823  else
824  *phCard = 0;
825 
826  if (szReader == NULL)
827  return SCARD_E_UNKNOWN_READER;
828 
829  /*
830  * Check for uninitialized strings
831  */
832  if (strlen(szReader) > MAX_READERNAME)
833  return SCARD_E_INVALID_VALUE;
834 
835  /*
836  * Make sure this context has been opened
837  */
838  currentContextMap = SCardGetAndLockContext(hContext);
839  if (NULL == currentContextMap)
840  return SCARD_E_INVALID_HANDLE;
841 
842  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
843  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
844  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
845 
846  scConnectStruct.hContext = hContext;
847  scConnectStruct.dwShareMode = dwShareMode;
848  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
849  scConnectStruct.hCard = 0;
850  scConnectStruct.dwActiveProtocol = 0;
851  scConnectStruct.rv = SCARD_S_SUCCESS;
852 
853  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
854  sizeof(scConnectStruct), (void *) &scConnectStruct);
855 
856  if (rv != SCARD_S_SUCCESS)
857  goto end;
858 
859  /*
860  * Read a message from the server
861  */
862  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
863  currentContextMap->dwClientID);
864 
865  if (rv != SCARD_S_SUCCESS)
866  goto end;
867 
868  *phCard = scConnectStruct.hCard;
869  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
870 
871  if (scConnectStruct.rv == SCARD_S_SUCCESS)
872  {
873  /*
874  * Keep track of the handle locally
875  */
876  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
877  }
878  else
879  rv = scConnectStruct.rv;
880 
881 end:
882  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
883 
884  PROFILE_END(rv)
885  API_TRACE_OUT("%d", *pdwActiveProtocol)
886 
887  return rv;
888 }
889 
962 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
963  DWORD dwPreferredProtocols, DWORD dwInitialization,
964  LPDWORD pdwActiveProtocol)
965 {
966  LONG rv;
967  struct reconnect_struct scReconnectStruct;
968  SCONTEXTMAP * currentContextMap;
969  CHANNEL_MAP * pChannelMap;
970 
971  PROFILE_START
972  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
973 
974  if (pdwActiveProtocol == NULL)
976 
977  /* Retry loop for blocking behaviour */
978 retry:
979 
980  /*
981  * Make sure this handle has been opened
982  */
983  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
984  &pChannelMap);
985  if (rv == -1)
986  return SCARD_E_INVALID_HANDLE;
987 
988  scReconnectStruct.hCard = hCard;
989  scReconnectStruct.dwShareMode = dwShareMode;
990  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
991  scReconnectStruct.dwInitialization = dwInitialization;
992  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
993  scReconnectStruct.rv = SCARD_S_SUCCESS;
994 
995  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
996  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
997 
998  if (rv != SCARD_S_SUCCESS)
999  goto end;
1000 
1001  /*
1002  * Read a message from the server
1003  */
1004  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1005  currentContextMap->dwClientID);
1006 
1007  if (rv != SCARD_S_SUCCESS)
1008  goto end;
1009 
1010  rv = scReconnectStruct.rv;
1011 
1012  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1013  {
1014  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1016  goto retry;
1017  }
1018 
1019  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1020 
1021 end:
1022  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1023 
1024  PROFILE_END(rv)
1025  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1026 
1027  return rv;
1028 }
1029 
1061 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1062 {
1063  LONG rv;
1064  struct disconnect_struct scDisconnectStruct;
1065  SCONTEXTMAP * currentContextMap;
1066  CHANNEL_MAP * pChannelMap;
1067 
1068  PROFILE_START
1069  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1070 
1071  /*
1072  * Make sure this handle has been opened
1073  */
1074  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1075  &pChannelMap);
1076  if (rv == -1)
1077  {
1079  goto error;
1080  }
1081 
1082  scDisconnectStruct.hCard = hCard;
1083  scDisconnectStruct.dwDisposition = dwDisposition;
1084  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1085 
1086  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1087  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1088 
1089  if (rv != SCARD_S_SUCCESS)
1090  goto end;
1091 
1092  /*
1093  * Read a message from the server
1094  */
1095  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1096  currentContextMap->dwClientID);
1097 
1098  if (rv != SCARD_S_SUCCESS)
1099  goto end;
1100 
1101  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1102  SCardRemoveHandle(hCard);
1103  rv = scDisconnectStruct.rv;
1104 
1105 end:
1106  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1107 
1108 error:
1109  PROFILE_END(rv)
1110  API_TRACE_OUT("")
1111 
1112  return rv;
1113 }
1114 
1152 {
1153 
1154  LONG rv;
1155  struct begin_struct scBeginStruct;
1156  SCONTEXTMAP * currentContextMap;
1157  CHANNEL_MAP * pChannelMap;
1158 
1159  PROFILE_START
1160  API_TRACE_IN("%ld", hCard)
1161 
1162  /*
1163  * Query the server every so often until the sharing violation ends
1164  * and then hold the lock for yourself.
1165  */
1166 
1167  for(;;)
1168  {
1169  /*
1170  * Make sure this handle has been opened
1171  */
1172  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1173  &pChannelMap);
1174  if (rv == -1)
1175  return SCARD_E_INVALID_HANDLE;
1176 
1177  scBeginStruct.hCard = hCard;
1178  scBeginStruct.rv = SCARD_S_SUCCESS;
1179 
1181  currentContextMap->dwClientID,
1182  sizeof(scBeginStruct), (void *) &scBeginStruct);
1183 
1184  if (rv != SCARD_S_SUCCESS)
1185  break;
1186 
1187  /*
1188  * Read a message from the server
1189  */
1190  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1191  currentContextMap->dwClientID);
1192 
1193  if (rv != SCARD_S_SUCCESS)
1194  break;
1195 
1196  rv = scBeginStruct.rv;
1197 
1198  if (SCARD_E_SHARING_VIOLATION != rv)
1199  break;
1200 
1201  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1203  }
1204 
1205  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1206 
1207  PROFILE_END(rv)
1208  API_TRACE_OUT("")
1209 
1210  return rv;
1211 }
1212 
1252 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1253 {
1254  LONG rv;
1255  struct end_struct scEndStruct;
1256  SCONTEXTMAP * currentContextMap;
1257  CHANNEL_MAP * pChannelMap;
1258 
1259  PROFILE_START
1260  API_TRACE_IN("%ld", hCard)
1261 
1262  /*
1263  * Make sure this handle has been opened
1264  */
1265  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1266  &pChannelMap);
1267  if (rv == -1)
1268  return SCARD_E_INVALID_HANDLE;
1269 
1270  scEndStruct.hCard = hCard;
1271  scEndStruct.dwDisposition = dwDisposition;
1272  scEndStruct.rv = SCARD_S_SUCCESS;
1273 
1275  currentContextMap->dwClientID,
1276  sizeof(scEndStruct), (void *) &scEndStruct);
1277 
1278  if (rv != SCARD_S_SUCCESS)
1279  goto end;
1280 
1281  /*
1282  * Read a message from the server
1283  */
1284  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1285  currentContextMap->dwClientID);
1286 
1287  if (rv != SCARD_S_SUCCESS)
1288  goto end;
1289 
1290  rv = scEndStruct.rv;
1291 
1292 end:
1293  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1294 
1295  PROFILE_END(rv)
1296  API_TRACE_OUT("")
1297 
1298  return rv;
1299 }
1300 
1396 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1397  LPDWORD pcchReaderLen, LPDWORD pdwState,
1398  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1399 {
1400  DWORD dwReaderLen, dwAtrLen;
1401  LONG rv;
1402  int i;
1403  struct status_struct scStatusStruct;
1404  SCONTEXTMAP * currentContextMap;
1405  CHANNEL_MAP * pChannelMap;
1406  char *r;
1407  char *bufReader = NULL;
1408  LPBYTE bufAtr = NULL;
1409  DWORD dummy = 0;
1410 
1411  PROFILE_START
1412 
1413  /* default output values */
1414  if (pdwState)
1415  *pdwState = 0;
1416 
1417  if (pdwProtocol)
1418  *pdwProtocol = 0;
1419 
1420  /* Check for NULL parameters */
1421  if (pcchReaderLen == NULL)
1422  pcchReaderLen = &dummy;
1423 
1424  if (pcbAtrLen == NULL)
1425  pcbAtrLen = &dummy;
1426 
1427  /* length passed from caller */
1428  dwReaderLen = *pcchReaderLen;
1429  dwAtrLen = *pcbAtrLen;
1430 
1431  *pcchReaderLen = 0;
1432  *pcbAtrLen = 0;
1433 
1434  /* Retry loop for blocking behaviour */
1435 retry:
1436 
1437  /*
1438  * Make sure this handle has been opened
1439  */
1440  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1441  &pChannelMap);
1442  if (rv == -1)
1443  return SCARD_E_INVALID_HANDLE;
1444 
1445  /* lock access to readerStates[] */
1446  (void)pthread_mutex_lock(&readerStatesMutex);
1447 
1448  /* synchronize reader states with daemon */
1449  rv = getReaderStates(currentContextMap);
1450  if (rv != SCARD_S_SUCCESS)
1451  goto end;
1452 
1453  r = pChannelMap->readerName;
1454  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1455  {
1456  /* by default r == NULL */
1457  if (r && strcmp(r, readerStates[i].readerName) == 0)
1458  break;
1459  }
1460 
1461  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1462  {
1464  goto end;
1465  }
1466 
1467  /* initialise the structure */
1468  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1469  scStatusStruct.hCard = hCard;
1470 
1471  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1472  sizeof(scStatusStruct), (void *) &scStatusStruct);
1473 
1474  if (rv != SCARD_S_SUCCESS)
1475  goto end;
1476 
1477  /*
1478  * Read a message from the server
1479  */
1480  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1481  currentContextMap->dwClientID);
1482 
1483  if (rv != SCARD_S_SUCCESS)
1484  goto end;
1485 
1486  rv = scStatusStruct.rv;
1487 
1488  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1489  {
1490  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1491  (void)pthread_mutex_unlock(&readerStatesMutex);
1493  goto retry;
1494  }
1495 
1496  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1497  {
1498  /*
1499  * An event must have occurred
1500  */
1501  goto end;
1502  }
1503 
1504  /*
1505  * Now continue with the client side SCardStatus
1506  */
1507 
1508  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1509  *pcbAtrLen = readerStates[i].cardAtrLength;
1510 
1511  if (pdwState)
1512  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1513 
1514  if (pdwProtocol)
1515  *pdwProtocol = readerStates[i].cardProtocol;
1516 
1517  if (SCARD_AUTOALLOCATE == dwReaderLen)
1518  {
1519  dwReaderLen = *pcchReaderLen;
1520  if (NULL == szReaderName)
1521  {
1523  goto end;
1524  }
1525  bufReader = malloc(dwReaderLen);
1526  if (NULL == bufReader)
1527  {
1528  rv = SCARD_E_NO_MEMORY;
1529  goto end;
1530  }
1531  *(char **)szReaderName = bufReader;
1532  }
1533  else
1534  bufReader = szReaderName;
1535 
1536  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1537  if (bufReader)
1538  {
1539  if (*pcchReaderLen > dwReaderLen)
1541 
1542  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1543  }
1544 
1545  if (SCARD_AUTOALLOCATE == dwAtrLen)
1546  {
1547  dwAtrLen = *pcbAtrLen;
1548  if (NULL == pbAtr)
1549  {
1551  goto end;
1552  }
1553  bufAtr = malloc(dwAtrLen);
1554  if (NULL == bufAtr)
1555  {
1556  rv = SCARD_E_NO_MEMORY;
1557  goto end;
1558  }
1559  *(LPBYTE *)pbAtr = bufAtr;
1560  }
1561  else
1562  bufAtr = pbAtr;
1563 
1564  if (bufAtr)
1565  {
1566  if (*pcbAtrLen > dwAtrLen)
1568 
1569  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1570  }
1571 
1572 end:
1573  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1574  (void)pthread_mutex_unlock(&readerStatesMutex);
1575 
1576  PROFILE_END(rv)
1577 
1578  return rv;
1579 }
1580 
1688 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1689  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1690 {
1691  SCARD_READERSTATE *currReader;
1692  READER_STATE *rContext;
1693  long dwTime;
1694  DWORD dwBreakFlag = 0;
1695  unsigned int j;
1696  SCONTEXTMAP * currentContextMap;
1697  int currentReaderCount = 0;
1698  LONG rv = SCARD_S_SUCCESS;
1699 
1700  PROFILE_START
1701  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1702 #ifdef DO_TRACE
1703  for (j=0; j<cReaders; j++)
1704  {
1705  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1706  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1707  }
1708 #endif
1709 
1710  if ((rgReaderStates == NULL && cReaders > 0)
1711  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1712  {
1714  goto error;
1715  }
1716 
1717  /* Check the integrity of the reader states structures */
1718  for (j = 0; j < cReaders; j++)
1719  {
1720  if (rgReaderStates[j].szReader == NULL)
1721  return SCARD_E_INVALID_VALUE;
1722  }
1723 
1724  /* return if all readers are SCARD_STATE_IGNORE */
1725  if (cReaders > 0)
1726  {
1727  int nbNonIgnoredReaders = cReaders;
1728 
1729  for (j=0; j<cReaders; j++)
1730  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1731  nbNonIgnoredReaders--;
1732 
1733  if (0 == nbNonIgnoredReaders)
1734  {
1735  rv = SCARD_S_SUCCESS;
1736  goto error;
1737  }
1738  }
1739  else
1740  {
1741  /* reader list is empty */
1742  rv = SCARD_S_SUCCESS;
1743  goto error;
1744  }
1745 
1746  /*
1747  * Make sure this context has been opened
1748  */
1749  currentContextMap = SCardGetAndLockContext(hContext);
1750  if (NULL == currentContextMap)
1751  {
1753  goto error;
1754  }
1755 
1756  /* lock access to readerStates[] */
1757  (void)pthread_mutex_lock(&readerStatesMutex);
1758 
1759  /* synchronize reader states with daemon */
1760  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1761 
1762  if (rv != SCARD_S_SUCCESS)
1763  {
1764  (void)pthread_mutex_unlock(&readerStatesMutex);
1765  goto end;
1766  }
1767 
1768  /* check all the readers are already known */
1769  for (j=0; j<cReaders; j++)
1770  {
1771  const char *readerName;
1772  int i;
1773 
1774  readerName = rgReaderStates[j].szReader;
1775  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1776  {
1777  if (strcmp(readerName, readerStates[i].readerName) == 0)
1778  break;
1779  }
1780 
1781  /* The requested reader name is not recognized */
1782  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1783  {
1784  /* PnP special reader? */
1785  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1786  {
1788  (void)pthread_mutex_unlock(&readerStatesMutex);
1789  goto end;
1790  }
1791  }
1792  }
1793  (void)pthread_mutex_unlock(&readerStatesMutex);
1794 
1795  /* Clear the event state for all readers */
1796  for (j = 0; j < cReaders; j++)
1797  rgReaderStates[j].dwEventState = 0;
1798 
1799  /* Now is where we start our event checking loop */
1800  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1801 
1802  /* Get the initial reader count on the system */
1803  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1804  if (readerStates[j].readerName[0] != '\0')
1805  currentReaderCount++;
1806 
1807  /* catch possible sign extension problems from 32 to 64-bits integers */
1808  if ((DWORD)-1 == dwTimeout)
1809  dwTimeout = INFINITE;
1810  if (INFINITE == dwTimeout)
1811  dwTime = 60*1000; /* "infinite" timeout */
1812  else
1813  dwTime = dwTimeout;
1814 
1815  j = 0;
1816  do
1817  {
1818  currReader = &rgReaderStates[j];
1819 
1820  /* Ignore for IGNORED readers */
1821  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1822  {
1823  const char *readerName;
1824  int i;
1825 
1826  /* lock access to readerStates[] */
1827  (void)pthread_mutex_lock(&readerStatesMutex);
1828 
1829  /* Looks for correct readernames */
1830  readerName = currReader->szReader;
1831  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1832  {
1833  if (strcmp(readerName, readerStates[i].readerName) == 0)
1834  break;
1835  }
1836 
1837  /* The requested reader name is not recognized */
1838  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1839  {
1840  /* PnP special reader? */
1841  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1842  {
1843  int k, newReaderCount = 0;
1844 
1845  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1846  if (readerStates[k].readerName[0] != '\0')
1847  newReaderCount++;
1848 
1849  if (newReaderCount != currentReaderCount)
1850  {
1851  Log1(PCSC_LOG_INFO, "Reader list changed");
1852  currentReaderCount = newReaderCount;
1853 
1854  currReader->dwEventState |= SCARD_STATE_CHANGED;
1855  dwBreakFlag = 1;
1856  }
1857  }
1858  else
1859  {
1860  currReader->dwEventState =
1862  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1863  {
1864  currReader->dwEventState |= SCARD_STATE_CHANGED;
1865  /*
1866  * Spec says use SCARD_STATE_IGNORE but a removed USB
1867  * reader with eventState fed into currentState will
1868  * be ignored forever
1869  */
1870  dwBreakFlag = 1;
1871  }
1872  }
1873  }
1874  else
1875  {
1876  uint32_t readerState;
1877 
1878  /* The reader has come back after being away */
1879  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1880  {
1881  currReader->dwEventState |= SCARD_STATE_CHANGED;
1882  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1883  Log0(PCSC_LOG_DEBUG);
1884  dwBreakFlag = 1;
1885  }
1886 
1887  /* Set the reader status structure */
1888  rContext = &readerStates[i];
1889 
1890  /* Now we check all the Reader States */
1891  readerState = rContext->readerState;
1892 
1893  /* only if current state has an non null event counter */
1894  if (currReader->dwCurrentState & 0xFFFF0000)
1895  {
1896  unsigned int currentCounter;
1897 
1898  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1899 
1900  /* has the event counter changed since the last call? */
1901  if (rContext->eventCounter != currentCounter)
1902  {
1903  currReader->dwEventState |= SCARD_STATE_CHANGED;
1904  Log0(PCSC_LOG_DEBUG);
1905  dwBreakFlag = 1;
1906  }
1907  }
1908 
1909  /* add an event counter in the upper word of dwEventState */
1910  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1911  | (rContext->eventCounter << 16));
1912 
1913  /* Check if the reader is in the correct state */
1914  if (readerState & SCARD_UNKNOWN)
1915  {
1916  /* reader is in bad state */
1917  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1918  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1919  {
1920  /* App thinks reader is in good state and it is not */
1921  currReader->dwEventState |= SCARD_STATE_CHANGED;
1922  Log0(PCSC_LOG_DEBUG);
1923  dwBreakFlag = 1;
1924  }
1925  }
1926  else
1927  {
1928  /* App thinks reader in bad state but it is not */
1929  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1930  {
1931  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1932  currReader->dwEventState |= SCARD_STATE_CHANGED;
1933  Log0(PCSC_LOG_DEBUG);
1934  dwBreakFlag = 1;
1935  }
1936  }
1937 
1938  /* Check for card presence in the reader */
1939  if (readerState & SCARD_PRESENT)
1940  {
1941 #ifndef DISABLE_AUTO_POWER_ON
1942  /* card present but not yet powered up */
1943  if (0 == rContext->cardAtrLength)
1944  /* Allow the status thread to convey information */
1946 #endif
1947 
1948  currReader->cbAtr = rContext->cardAtrLength;
1949  memcpy(currReader->rgbAtr, rContext->cardAtr,
1950  currReader->cbAtr);
1951  }
1952  else
1953  currReader->cbAtr = 0;
1954 
1955  /* Card is now absent */
1956  if (readerState & SCARD_ABSENT)
1957  {
1958  currReader->dwEventState |= SCARD_STATE_EMPTY;
1959  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1960  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1961  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1962  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1963  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1964  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1965  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1966  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1967 
1968  /* After present the rest are assumed */
1969  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1970  {
1971  currReader->dwEventState |= SCARD_STATE_CHANGED;
1972  Log0(PCSC_LOG_DEBUG);
1973  dwBreakFlag = 1;
1974  }
1975  }
1976  /* Card is now present */
1977  else if (readerState & SCARD_PRESENT)
1978  {
1979  currReader->dwEventState |= SCARD_STATE_PRESENT;
1980  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1981  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1982  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1983  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1984  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1985  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1986 
1987  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1988  {
1989  currReader->dwEventState |= SCARD_STATE_CHANGED;
1990  Log0(PCSC_LOG_DEBUG);
1991  dwBreakFlag = 1;
1992  }
1993 
1994  if (readerState & SCARD_SWALLOWED)
1995  {
1996  currReader->dwEventState |= SCARD_STATE_MUTE;
1997  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1998  {
1999  currReader->dwEventState |= SCARD_STATE_CHANGED;
2000  Log0(PCSC_LOG_DEBUG);
2001  dwBreakFlag = 1;
2002  }
2003  }
2004  else
2005  {
2006  /* App thinks card is mute but it is not */
2007  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2008  {
2009  currReader->dwEventState |= SCARD_STATE_CHANGED;
2010  Log0(PCSC_LOG_DEBUG);
2011  dwBreakFlag = 1;
2012  }
2013  }
2014  }
2015 
2016  /* Now figure out sharing modes */
2018  {
2019  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2020  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2021  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2022  {
2023  currReader->dwEventState |= SCARD_STATE_CHANGED;
2024  Log0(PCSC_LOG_DEBUG);
2025  dwBreakFlag = 1;
2026  }
2027  }
2028  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2029  {
2030  /* A card must be inserted for it to be INUSE */
2031  if (readerState & SCARD_PRESENT)
2032  {
2033  currReader->dwEventState |= SCARD_STATE_INUSE;
2034  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2035  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2036  {
2037  currReader->dwEventState |= SCARD_STATE_CHANGED;
2038  Log0(PCSC_LOG_DEBUG);
2039  dwBreakFlag = 1;
2040  }
2041  }
2042  }
2043  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2044  {
2045  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2046  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2047 
2048  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2049  {
2050  currReader->dwEventState |= SCARD_STATE_CHANGED;
2051  Log0(PCSC_LOG_DEBUG);
2052  dwBreakFlag = 1;
2053  }
2054  else if (currReader-> dwCurrentState
2056  {
2057  currReader->dwEventState |= SCARD_STATE_CHANGED;
2058  Log0(PCSC_LOG_DEBUG);
2059  dwBreakFlag = 1;
2060  }
2061  }
2062 
2063  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2064  {
2065  /*
2066  * Break out of the while .. loop and return status
2067  * once all the status's for all readers is met
2068  */
2069  currReader->dwEventState |= SCARD_STATE_CHANGED;
2070  Log0(PCSC_LOG_DEBUG);
2071  dwBreakFlag = 1;
2072  }
2073  } /* End of SCARD_STATE_UNKNOWN */
2074 
2075  (void)pthread_mutex_unlock(&readerStatesMutex);
2076  } /* End of SCARD_STATE_IGNORE */
2077 
2078  /* Counter and resetter */
2079  j++;
2080  if (j == cReaders)
2081  {
2082  /* go back to the first reader */
2083  j = 0;
2084 
2085  /* Declare all the break conditions */
2086 
2087  /* Break if UNAWARE is set and all readers have been checked */
2088  if (dwBreakFlag == 1)
2089  break;
2090 
2091  /* Only sleep once for each cycle of reader checks. */
2092  {
2093  struct wait_reader_state_change waitStatusStruct = {0};
2094  struct timeval before, after;
2095 
2096  gettimeofday(&before, NULL);
2097 
2098  waitStatusStruct.rv = SCARD_S_SUCCESS;
2099 
2100  /* another thread can do SCardCancel() */
2101  currentContextMap->cancellable = true;
2102 
2103  /*
2104  * Read a message from the server
2105  */
2107  &waitStatusStruct, sizeof(waitStatusStruct),
2108  currentContextMap->dwClientID, dwTime);
2109 
2110  /* SCardCancel() will return immediately with success
2111  * because something changed on the daemon side. */
2112  currentContextMap->cancellable = false;
2113 
2114  /* timeout */
2115  if (SCARD_E_TIMEOUT == rv)
2116  {
2117  /* ask server to remove us from the event list */
2118  rv = unregisterFromEvents(currentContextMap);
2119  }
2120 
2121  if (rv != SCARD_S_SUCCESS)
2122  goto end;
2123 
2124  /* an event occurs or SCardCancel() was called */
2125  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2126  {
2127  rv = waitStatusStruct.rv;
2128  goto end;
2129  }
2130 
2131  /* synchronize reader states with daemon */
2132  (void)pthread_mutex_lock(&readerStatesMutex);
2133  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2134  (void)pthread_mutex_unlock(&readerStatesMutex);
2135  if (rv != SCARD_S_SUCCESS)
2136  goto end;
2137 
2138  if (INFINITE != dwTimeout)
2139  {
2140  long int diff;
2141 
2142  gettimeofday(&after, NULL);
2143  diff = time_sub(&after, &before);
2144  dwTime -= diff/1000;
2145  }
2146  }
2147 
2148  if (dwTimeout != INFINITE)
2149  {
2150  /* If time is greater than timeout and all readers have been
2151  * checked
2152  */
2153  if (dwTime <= 0)
2154  {
2155  rv = SCARD_E_TIMEOUT;
2156  goto end;
2157  }
2158  }
2159  }
2160  }
2161  while (1);
2162 
2163 end:
2164  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2165 
2166  /* if SCardCancel() has been used then the client is already
2167  * unregistered */
2168  if (SCARD_E_CANCELLED != rv)
2169  (void)unregisterFromEvents(currentContextMap);
2170 
2171  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2172 
2173 error:
2174  PROFILE_END(rv)
2175 #ifdef DO_TRACE
2176  for (j=0; j<cReaders; j++)
2177  {
2178  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2179  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2180  }
2181 #endif
2182 
2183  return rv;
2184 }
2185 
2236 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2237  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2238  LPDWORD lpBytesReturned)
2239 {
2240  LONG rv;
2241  struct control_struct scControlStruct;
2242  SCONTEXTMAP * currentContextMap;
2243  CHANNEL_MAP * pChannelMap;
2244 
2245  PROFILE_START
2246 
2247  /* 0 bytes received by default */
2248  if (NULL != lpBytesReturned)
2249  *lpBytesReturned = 0;
2250 
2251  /*
2252  * Make sure this handle has been opened
2253  */
2254  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2255  &pChannelMap);
2256  if (rv == -1)
2257  {
2258  PROFILE_END(SCARD_E_INVALID_HANDLE)
2259  return SCARD_E_INVALID_HANDLE;
2260  }
2261 
2262  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2263  {
2265  goto end;
2266  }
2267 
2268  scControlStruct.hCard = hCard;
2269  scControlStruct.dwControlCode = dwControlCode;
2270  scControlStruct.cbSendLength = cbSendLength;
2271  scControlStruct.cbRecvLength = cbRecvLength;
2272  scControlStruct.dwBytesReturned = 0;
2273  scControlStruct.rv = 0;
2274 
2275  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2276  sizeof(scControlStruct), &scControlStruct);
2277 
2278  if (rv != SCARD_S_SUCCESS)
2279  goto end;
2280 
2281  /* write the sent buffer */
2282  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2283  currentContextMap->dwClientID);
2284 
2285  if (rv != SCARD_S_SUCCESS)
2286  goto end;
2287 
2288  /*
2289  * Read a message from the server
2290  */
2291  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2292  currentContextMap->dwClientID);
2293 
2294  if (rv != SCARD_S_SUCCESS)
2295  goto end;
2296 
2297  if (SCARD_S_SUCCESS == scControlStruct.rv)
2298  {
2299  if (scControlStruct.dwBytesReturned > cbRecvLength)
2300  {
2301  if (NULL != lpBytesReturned)
2302  *lpBytesReturned = scControlStruct.dwBytesReturned;
2304  goto end;
2305  }
2306 
2307  /* read the received buffer */
2308  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2309  currentContextMap->dwClientID);
2310 
2311  if (rv != SCARD_S_SUCCESS)
2312  goto end;
2313 
2314  }
2315 
2316  if (NULL != lpBytesReturned)
2317  *lpBytesReturned = scControlStruct.dwBytesReturned;
2318 
2319  rv = scControlStruct.rv;
2320 
2321 end:
2322  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2323 
2324  PROFILE_END(rv)
2325 
2326  return rv;
2327 }
2328 
2447 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2448  LPDWORD pcbAttrLen)
2449 {
2450  LONG ret;
2451  unsigned char *buf = NULL;
2452 
2453  PROFILE_START
2454 
2455  if (NULL == pcbAttrLen)
2456  {
2458  goto end;
2459  }
2460 
2461  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2462  {
2463  if (NULL == pbAttr)
2465 
2466  *pcbAttrLen = MAX_BUFFER_SIZE;
2467  buf = malloc(*pcbAttrLen);
2468  if (NULL == buf)
2469  {
2470  ret = SCARD_E_NO_MEMORY;
2471  goto end;
2472  }
2473 
2474  *(unsigned char **)pbAttr = buf;
2475  }
2476  else
2477  {
2478  buf = pbAttr;
2479 
2480  /* if only get the length */
2481  if (NULL == pbAttr)
2482  /* use a reasonable size */
2483  *pcbAttrLen = MAX_BUFFER_SIZE;
2484  }
2485 
2486  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2487  pcbAttrLen);
2488 
2489 end:
2490  PROFILE_END(ret)
2491 
2492  return ret;
2493 }
2494 
2530 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2531  DWORD cbAttrLen)
2532 {
2533  LONG ret;
2534 
2535  PROFILE_START
2536 
2537  if (NULL == pbAttr || 0 == cbAttrLen)
2539 
2540  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2541  &cbAttrLen);
2542 
2543  PROFILE_END(ret)
2544 
2545  return ret;
2546 }
2547 
2548 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2549  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2550 {
2551  LONG rv;
2552  struct getset_struct scGetSetStruct;
2553  SCONTEXTMAP * currentContextMap;
2554  CHANNEL_MAP * pChannelMap;
2555 
2556  /*
2557  * Make sure this handle has been opened
2558  */
2559  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2560  &pChannelMap);
2561  if (rv == -1)
2562  return SCARD_E_INVALID_HANDLE;
2563 
2564  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2565  {
2567  goto end;
2568  }
2569 
2570  scGetSetStruct.hCard = hCard;
2571  scGetSetStruct.dwAttrId = dwAttrId;
2572  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2573  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2574  if (SCARD_SET_ATTRIB == command)
2575  {
2576  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2577  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2578  }
2579  else
2580  /* we can get up to the communication buffer size */
2581  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2582 
2583  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2584  sizeof(scGetSetStruct), &scGetSetStruct);
2585 
2586  if (rv != SCARD_S_SUCCESS)
2587  goto end;
2588 
2589  /*
2590  * Read a message from the server
2591  */
2592  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2593  currentContextMap->dwClientID);
2594 
2595  if (rv != SCARD_S_SUCCESS)
2596  goto end;
2597 
2598  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2599  {
2600  /*
2601  * Copy and zero it so any secret information is not leaked
2602  */
2603  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2604  {
2605  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2606  * buffer overflow in the memcpy() below */
2607  DWORD correct_value = scGetSetStruct.cbAttrLen;
2608  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2609  *pcbAttrLen = correct_value;
2610 
2611  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2612  }
2613  else
2614  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2615 
2616  if (pbAttr)
2617  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2618 
2619  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2620  }
2621  rv = scGetSetStruct.rv;
2622 
2623 end:
2624  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2625 
2626  return rv;
2627 }
2628 
2687 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2688  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2689  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2690  LPDWORD pcbRecvLength)
2691 {
2692  LONG rv;
2693  SCONTEXTMAP * currentContextMap;
2694  CHANNEL_MAP * pChannelMap;
2695  struct transmit_struct scTransmitStruct;
2696 
2697  PROFILE_START
2698 
2699  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2700  pcbRecvLength == NULL || pioSendPci == NULL)
2702 
2703  /* Retry loop for blocking behaviour */
2704 retry:
2705 
2706  /*
2707  * Make sure this handle has been opened
2708  */
2709  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2710  &pChannelMap);
2711  if (rv == -1)
2712  {
2713  *pcbRecvLength = 0;
2714  PROFILE_END(SCARD_E_INVALID_HANDLE)
2715  return SCARD_E_INVALID_HANDLE;
2716  }
2717 
2718  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2719  {
2721  goto end;
2722  }
2723 
2724  scTransmitStruct.hCard = hCard;
2725  scTransmitStruct.cbSendLength = cbSendLength;
2726  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2727  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2728  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2729  scTransmitStruct.rv = SCARD_S_SUCCESS;
2730 
2731  if (pioRecvPci)
2732  {
2733  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2734  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2735  }
2736  else
2737  {
2738  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2739  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2740  }
2741 
2742  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2743  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2744 
2745  if (rv != SCARD_S_SUCCESS)
2746  goto end;
2747 
2748  /* write the sent buffer */
2749  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2750  currentContextMap->dwClientID);
2751 
2752  if (rv != SCARD_S_SUCCESS)
2753  goto end;
2754 
2755  /*
2756  * Read a message from the server
2757  */
2758  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2759  currentContextMap->dwClientID);
2760 
2761  if (rv != SCARD_S_SUCCESS)
2762  goto end;
2763 
2764  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2765  {
2766  if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2767  {
2768  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2770  goto end;
2771  }
2772 
2773  /* read the received buffer */
2774  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2775  currentContextMap->dwClientID);
2776 
2777  if (rv != SCARD_S_SUCCESS)
2778  goto end;
2779 
2780  if (pioRecvPci)
2781  {
2782  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2783  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2784  }
2785  }
2786 
2787  rv = scTransmitStruct.rv;
2788 
2789  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2790  {
2791  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2793  goto retry;
2794  }
2795 
2796  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2797 
2798 end:
2799  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2800 
2801  PROFILE_END(rv)
2802 
2803  return rv;
2804 }
2805 
2868 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2869  LPSTR mszReaders, LPDWORD pcchReaders)
2870 {
2871  DWORD dwReadersLen = 0;
2872  int i;
2873  SCONTEXTMAP * currentContextMap;
2874  LONG rv = SCARD_S_SUCCESS;
2875  char *buf = NULL;
2876 
2877  (void)mszGroups;
2878  PROFILE_START
2879  API_TRACE_IN("%ld", hContext)
2880 
2881  /*
2882  * Check for NULL parameters
2883  */
2884  if (pcchReaders == NULL)
2886 
2887  /*
2888  * Make sure this context has been opened
2889  */
2890  currentContextMap = SCardGetAndLockContext(hContext);
2891  if (NULL == currentContextMap)
2892  {
2893  PROFILE_END(SCARD_E_INVALID_HANDLE)
2894  return SCARD_E_INVALID_HANDLE;
2895  }
2896 
2897  /* lock access to readerStates[] */
2898  (void)pthread_mutex_lock(&readerStatesMutex);
2899 
2900  /* synchronize reader states with daemon */
2901  rv = getReaderStates(currentContextMap);
2902  if (rv != SCARD_S_SUCCESS)
2903  goto end;
2904 
2905  dwReadersLen = 0;
2906  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2907  if (readerStates[i].readerName[0] != '\0')
2908  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2909 
2910  /* for the last NULL byte */
2911  dwReadersLen += 1;
2912 
2913  if (1 == dwReadersLen)
2914  {
2916  goto end;
2917  }
2918 
2919  if (SCARD_AUTOALLOCATE == *pcchReaders)
2920  {
2921  if (NULL == mszReaders)
2922  {
2924  goto end;
2925  }
2926  buf = malloc(dwReadersLen);
2927  if (NULL == buf)
2928  {
2929  rv = SCARD_E_NO_MEMORY;
2930  goto end;
2931  }
2932  *(char **)mszReaders = buf;
2933  }
2934  else
2935  {
2936  buf = mszReaders;
2937 
2938  /* not enough place to store the reader names */
2939  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2940  {
2942  goto end;
2943  }
2944  }
2945 
2946  if (mszReaders == NULL) /* text array not allocated */
2947  goto end;
2948 
2949  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2950  {
2951  if (readerStates[i].readerName[0] != '\0')
2952  {
2953  /*
2954  * Build the multi-string
2955  */
2956  strcpy(buf, readerStates[i].readerName);
2957  buf += strlen(readerStates[i].readerName)+1;
2958  }
2959  }
2960  *buf = '\0'; /* Add the last null */
2961 
2962 end:
2963  /* set the reader names length */
2964  *pcchReaders = dwReadersLen;
2965 
2966  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2967  (void)pthread_mutex_unlock(&readerStatesMutex);
2968 
2969  PROFILE_END(rv)
2970  API_TRACE_OUT("%d", *pcchReaders)
2971 
2972  return rv;
2973 }
2974 
2988 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2989 {
2990  LONG rv = SCARD_S_SUCCESS;
2991 
2992  PROFILE_START
2993 
2994  /*
2995  * Make sure this context has been opened
2996  */
2997  if (! SCardGetContextValidity(hContext))
2998  return SCARD_E_INVALID_HANDLE;
2999 
3000  free((void *)pvMem);
3001 
3002  PROFILE_END(rv)
3003 
3004  return rv;
3005 }
3006 
3058 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3059  LPDWORD pcchGroups)
3060 {
3061  LONG rv = SCARD_S_SUCCESS;
3062  SCONTEXTMAP * currentContextMap;
3063  char *buf = NULL;
3064 
3065  PROFILE_START
3066 
3067  /* Multi-string with two trailing \0 */
3068  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3069  const unsigned int dwGroups = sizeof(ReaderGroup);
3070 
3071  /*
3072  * Make sure this context has been opened
3073  */
3074  currentContextMap = SCardGetAndLockContext(hContext);
3075  if (NULL == currentContextMap)
3076  return SCARD_E_INVALID_HANDLE;
3077 
3078  if (SCARD_AUTOALLOCATE == *pcchGroups)
3079  {
3080  if (NULL == mszGroups)
3081  {
3083  goto end;
3084  }
3085  buf = malloc(dwGroups);
3086  if (NULL == buf)
3087  {
3088  rv = SCARD_E_NO_MEMORY;
3089  goto end;
3090  }
3091  *(char **)mszGroups = buf;
3092  }
3093  else
3094  {
3095  buf = mszGroups;
3096 
3097  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3098  {
3100  goto end;
3101  }
3102  }
3103 
3104  if (buf)
3105  memcpy(buf, ReaderGroup, dwGroups);
3106 
3107 end:
3108  *pcchGroups = dwGroups;
3109 
3110  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3111 
3112  PROFILE_END(rv)
3113 
3114  return rv;
3115 }
3116 
3149 {
3150  SCONTEXTMAP * currentContextMap;
3151  LONG rv = SCARD_S_SUCCESS;
3152  uint32_t dwClientID = 0;
3153  struct cancel_struct scCancelStruct;
3154  bool cancellable;
3155 
3156  PROFILE_START
3157  API_TRACE_IN("%ld", hContext)
3158 
3159  /*
3160  * Make sure this context has been opened
3161  */
3162  (void)SCardLockThread();
3163  currentContextMap = SCardGetContextTH(hContext);
3164 
3165  if (NULL == currentContextMap)
3166  {
3167  (void)SCardUnlockThread();
3169  goto error;
3170  }
3171  cancellable = currentContextMap->cancellable;
3172  (void)SCardUnlockThread();
3173 
3174  if (! cancellable)
3175  {
3176  rv = SCARD_S_SUCCESS;
3177  goto error;
3178  }
3179 
3180  /* create a new connection to the server */
3181  if (ClientSetupSession(&dwClientID) != 0)
3182  {
3183  rv = SCARD_E_NO_SERVICE;
3184  goto error;
3185  }
3186 
3187  scCancelStruct.hContext = hContext;
3188  scCancelStruct.rv = SCARD_S_SUCCESS;
3189 
3190  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3191  sizeof(scCancelStruct), (void *) &scCancelStruct);
3192 
3193  if (rv != SCARD_S_SUCCESS)
3194  goto end;
3195 
3196  /*
3197  * Read a message from the server
3198  */
3199  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3200 
3201  if (rv != SCARD_S_SUCCESS)
3202  goto end;
3203 
3204  rv = scCancelStruct.rv;
3205 end:
3206  ClientCloseSession(dwClientID);
3207 
3208 error:
3209  PROFILE_END(rv)
3210  API_TRACE_OUT("")
3211 
3212  return rv;
3213 }
3214 
3239 {
3240  LONG rv;
3241 
3242  PROFILE_START
3243  API_TRACE_IN("%ld", hContext)
3244 
3245  rv = SCARD_S_SUCCESS;
3246 
3247  /*
3248  * Make sure this context has been opened
3249  */
3250  if (! SCardGetContextValidity(hContext))
3252 
3253  PROFILE_END(rv)
3254  API_TRACE_OUT("")
3255 
3256  return rv;
3257 }
3258 
3275 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3276 {
3277  int lrv;
3278  SCONTEXTMAP * newContextMap;
3279 
3280  newContextMap = malloc(sizeof(SCONTEXTMAP));
3281  if (NULL == newContextMap)
3282  return SCARD_E_NO_MEMORY;
3283 
3284  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3285  newContextMap->hContext = hContext;
3286  newContextMap->dwClientID = dwClientID;
3287  newContextMap->cancellable = false;
3288 
3289  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3290 
3291  lrv = list_init(&newContextMap->channelMapList);
3292  if (lrv < 0)
3293  {
3294  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3295  goto error;
3296  }
3297 
3298  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3299  CHANNEL_MAP_seeker);
3300  if (lrv <0)
3301  {
3302  Log2(PCSC_LOG_CRITICAL,
3303  "list_attributes_seeker failed with return value: %d", lrv);
3304  list_destroy(&newContextMap->channelMapList);
3305  goto error;
3306  }
3307 
3308  lrv = list_append(&contextMapList, newContextMap);
3309  if (lrv < 0)
3310  {
3311  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3312  lrv);
3313  list_destroy(&newContextMap->channelMapList);
3314  goto error;
3315  }
3316 
3317  return SCARD_S_SUCCESS;
3318 
3319 error:
3320 
3321  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3322  free(newContextMap);
3323 
3324  return SCARD_E_NO_MEMORY;
3325 }
3326 
3344 {
3345  SCONTEXTMAP * currentContextMap;
3346 
3347  SCardLockThread();
3348  currentContextMap = SCardGetContextTH(hContext);
3349 
3350  /* lock the context (if available) */
3351  if (NULL != currentContextMap)
3352  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3353 
3355 
3356  return currentContextMap;
3357 }
3358 
3372 {
3373  return list_seek(&contextMapList, &hContext);
3374 }
3375 
3382 static void SCardRemoveContext(SCARDCONTEXT hContext)
3383 {
3384  SCONTEXTMAP * currentContextMap;
3385  currentContextMap = SCardGetContextTH(hContext);
3386 
3387  if (NULL != currentContextMap)
3388  SCardCleanContext(currentContextMap);
3389 }
3390 
3391 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3392 {
3393  int list_index, lrv;
3394  int listSize;
3395  CHANNEL_MAP * currentChannelMap;
3396 
3397  targetContextMap->hContext = 0;
3398  ClientCloseSession(targetContextMap->dwClientID);
3399  targetContextMap->dwClientID = 0;
3400  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3401 
3402  listSize = list_size(&targetContextMap->channelMapList);
3403  for (list_index = 0; list_index < listSize; list_index++)
3404  {
3405  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3406  list_index);
3407  if (NULL == currentChannelMap)
3408  {
3409  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3410  list_index);
3411  continue;
3412  }
3413  else
3414  {
3415  free(currentChannelMap->readerName);
3416  free(currentChannelMap);
3417  }
3418 
3419  }
3420  list_destroy(&targetContextMap->channelMapList);
3421 
3422  lrv = list_delete(&contextMapList, targetContextMap);
3423  if (lrv < 0)
3424  {
3425  Log2(PCSC_LOG_CRITICAL,
3426  "list_delete failed with return value: %d", lrv);
3427  }
3428 
3429  free(targetContextMap);
3430 
3431  return;
3432 }
3433 
3434 /*
3435  * Functions for managing hCard values returned from SCardConnect.
3436  */
3437 
3438 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3439  LPCSTR readerName)
3440 {
3441  CHANNEL_MAP * newChannelMap;
3442  int lrv = -1;
3443 
3444  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3445  if (NULL == newChannelMap)
3446  return SCARD_E_NO_MEMORY;
3447 
3448  newChannelMap->hCard = hCard;
3449  newChannelMap->readerName = strdup(readerName);
3450 
3451  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3452  if (lrv < 0)
3453  {
3454  free(newChannelMap->readerName);
3455  free(newChannelMap);
3456  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3457  lrv);
3458  return SCARD_E_NO_MEMORY;
3459  }
3460 
3461  return SCARD_S_SUCCESS;
3462 }
3463 
3464 static void SCardRemoveHandle(SCARDHANDLE hCard)
3465 {
3466  SCONTEXTMAP * currentContextMap;
3467  CHANNEL_MAP * currentChannelMap;
3468  int lrv;
3469  LONG rv;
3470 
3471  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3472  &currentChannelMap);
3473  if (rv == -1)
3474  return;
3475 
3476  free(currentChannelMap->readerName);
3477 
3478  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3479  if (lrv < 0)
3480  {
3481  Log2(PCSC_LOG_CRITICAL,
3482  "list_delete failed with return value: %d", lrv);
3483  }
3484 
3485  free(currentChannelMap);
3486 
3487  return;
3488 }
3489 
3490 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3491  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3492 {
3493  LONG rv;
3494 
3495  if (0 == hCard)
3496  return -1;
3497 
3498  SCardLockThread();
3499  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3500  targetChannelMap);
3501 
3502  if (SCARD_S_SUCCESS == rv)
3503  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3504 
3506 
3507  return rv;
3508 }
3509 
3510 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3511  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3512 {
3513  int listSize;
3514  int list_index;
3515  SCONTEXTMAP * currentContextMap;
3516  CHANNEL_MAP * currentChannelMap;
3517 
3518  /* Best to get the caller a crash early if we fail unsafely */
3519  *targetContextMap = NULL;
3520  *targetChannelMap = NULL;
3521 
3522  listSize = list_size(&contextMapList);
3523 
3524  for (list_index = 0; list_index < listSize; list_index++)
3525  {
3526  currentContextMap = list_get_at(&contextMapList, list_index);
3527  if (currentContextMap == NULL)
3528  {
3529  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3530  list_index);
3531  continue;
3532  }
3533  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3534  &hCard);
3535  if (currentChannelMap != NULL)
3536  {
3537  *targetContextMap = currentContextMap;
3538  *targetChannelMap = currentChannelMap;
3539  return SCARD_S_SUCCESS;
3540  }
3541  }
3542 
3543  return -1;
3544 }
3545 
3554 {
3555  LONG rv;
3556  struct stat statBuffer;
3557  char *socketName;
3558 
3559  socketName = getSocketName();
3560  rv = stat(socketName, &statBuffer);
3561 
3562  if (rv != 0)
3563  {
3564  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3565  socketName, strerror(errno));
3566  return SCARD_E_NO_SERVICE;
3567  }
3568 
3569  return SCARD_S_SUCCESS;
3570 }
3571 
3572 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3573 {
3574  int32_t dwClientID = currentContextMap->dwClientID;
3575  LONG rv;
3576 
3577  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3578  if (rv != SCARD_S_SUCCESS)
3579  return rv;
3580 
3581  /* Read a message from the server */
3582  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3583  if (rv != SCARD_S_SUCCESS)
3584  return rv;
3585 
3586  return SCARD_S_SUCCESS;
3587 }
3588 
3589 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3590 {
3591  int32_t dwClientID = currentContextMap->dwClientID;
3592  LONG rv;
3593 
3594  /* Get current reader states from server and register on event list */
3596  0, NULL);
3597  if (rv != SCARD_S_SUCCESS)
3598  return rv;
3599 
3600  /* Read a message from the server */
3601  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3602  return rv;
3603 }
3604 
3605 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3606 {
3607  int32_t dwClientID = currentContextMap->dwClientID;
3608  LONG rv;
3609  struct wait_reader_state_change waitStatusStruct = {0};
3610 
3611  /* ask server to remove us from the event list */
3613  dwClientID, 0, NULL);
3614  if (rv != SCARD_S_SUCCESS)
3615  return rv;
3616 
3617  /* This message can be the response to
3618  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3619  * cancel notification.
3620  * The server side ensures, that no more messages will be sent to
3621  * the client. */
3622 
3623  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3624  dwClientID);
3625  if (rv != SCARD_S_SUCCESS)
3626  return rv;
3627 
3628  /* if we received a cancel event the return value will be set
3629  * accordingly */
3630  rv = waitStatusStruct.rv;
3631 
3632  return rv;
3633 }
3634 
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
used by SCardBeginTransaction()
Definition: winscard_msg.h:85
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:144
list object
Definition: simclist.h:181
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
wait for a reader state change
Definition: winscard_msg.h:97
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:210
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:232
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:270
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:198
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:77
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:298
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:271
_Atomic uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
get the client/server protocol version
Definition: winscard_msg.h:95
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:176
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:267
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:258
used by SCardEstablishContext()
Definition: winscard_msg.h:79
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:202
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:321
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:60
used by SCardEndTransaction()
Definition: winscard_msg.h:86
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:268
This handles abstract system level calls.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:55
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
used by SCardConnect()
Definition: winscard_msg.h:82
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:243
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:175
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes...
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:260
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:133
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:80
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:187
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:79
bool cancellable
We are in a cancellable call.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:280
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:269
Represents an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:121
get the readers state
Definition: winscard_msg.h:96
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:234
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:57
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
Definition: winscard_msg.c:458
used by SCardReleaseContext()
Definition: winscard_msg.h:80
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:221
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:160
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:285
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:264
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:272
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:110
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:242
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:273
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context...
used by SCardReconnect()
Definition: winscard_msg.h:83
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:138
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:299
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:87
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
Represents an Application Context Channel.
This handles card insertion/removal events, updates ATR, protocol, and status information.
SCARDCONTEXT hContext
Application Context ID.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:247
stop waiting for a reader state change
Definition: winscard_msg.h:98
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:274
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:261
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:59
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:122
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:57
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
static bool isExecuted
Make sure the initialization code is executed only once.
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction...
used by SCardControl()
Definition: winscard_msg.h:88
This keeps a list of defines for pcsc-lite.
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:244
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:275
Protocol Control Information (PCI)
Definition: pcsclite.h:79
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader...
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:259
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:61
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:52
used by SCardSetAttrib()
Definition: winscard_msg.h:94
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:358
used by SCardDisconnect()
Definition: winscard_msg.h:84
PCSC_API const char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:82
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:249
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:93
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
pthread_mutex_t mMutex
Mutex for this context.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:56
used by SCardCancel()
Definition: winscard_msg.h:91
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:75
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:59
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not...
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:89
This handles smart card reader communications.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
Definition: winscard_msg.c:198
This handles debugging.
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:266
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:276