pcsc-lite  2.2.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-2024
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 
361 
362 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
365 static void SCardRemoveContext(SCARDCONTEXT);
366 static void SCardCleanContext(SCONTEXTMAP *);
367 
368 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
369 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
370  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
371 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
372  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
373 static void SCardRemoveHandle(SCARDHANDLE);
374 
375 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
376  LPBYTE pbAttr, LPDWORD pcbAttrLen);
377 
378 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
379 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
380 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
381 
382 /*
383  * Thread safety functions
384  */
391 inline static void SCardLockThread(void)
392 {
393  pthread_mutex_lock(&clientMutex);
394 }
395 
401 inline static void SCardUnlockThread(void)
402 {
403  pthread_mutex_unlock(&clientMutex);
404 }
405 
416 {
417  SCONTEXTMAP * currentContextMap;
418 
419  SCardLockThread();
420  currentContextMap = SCardGetContextTH(hContext);
422 
423  return currentContextMap != NULL;
424 }
425 
426 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
427  /*@out@*/ LPSCARDCONTEXT);
428 
464 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
465  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
466 {
467  LONG rv;
468 
469  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
470  PROFILE_START
471 
472  /* Check if the server is running */
474  if (rv != SCARD_S_SUCCESS)
475  goto end;
476 
477  SCardLockThread();
478  rv = SCardEstablishContextTH(dwScope, pvReserved1,
479  pvReserved2, phContext);
481 
482 end:
483  PROFILE_END(rv)
484  API_TRACE_OUT("%ld", *phContext)
485 
486  return rv;
487 }
488 
489 #ifdef DESTRUCTOR
490 DESTRUCTOR static void destructor(void)
491 {
492  list_destroy(&contextMapList);
493 }
494 #endif
495 
496 /*
497  * Do this only once:
498  * - Initialize context list.
499  */
500 static void init_lib(void)
501 {
502  int lrv;
503 
504  /* NOTE: The list will be freed only if DESTRUCTOR is defined.
505  * Applications which load and unload the library may leak
506  * the list's internal structures. */
507  lrv = list_init(&contextMapList);
508  if (lrv < 0)
509  {
510  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
511  lrv);
512  return;
513  }
514 
515  lrv = list_attributes_seeker(&contextMapList,
516  SCONTEXTMAP_seeker);
517  if (lrv <0)
518  {
519  Log2(PCSC_LOG_CRITICAL,
520  "list_attributes_seeker failed with return value: %d", lrv);
521  list_destroy(&contextMapList);
522  return;
523  }
524 
525  if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
526  {
527  Log1(PCSC_LOG_INFO, "Disable shared blocking");
528  sharing_shall_block = false;
529  }
530 
531  isExecuted = true;
532 }
533 
561 static LONG SCardEstablishContextTH(DWORD dwScope,
562  /*@unused@*/ LPCVOID pvReserved1,
563  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
564 {
565  LONG rv;
566  struct establish_struct scEstablishStruct;
567  uint32_t dwClientID = 0;
568 
569  (void)pvReserved1;
570  (void)pvReserved2;
571  if (phContext == NULL)
573  else
574  *phContext = 0;
575 
576  pthread_once(&init_lib_control, init_lib);
577  if (!isExecuted)
578  return SCARD_E_NO_MEMORY;
579 
580  /* Establishes a connection to the server */
581  if (ClientSetupSession(&dwClientID) != 0)
582  {
583  return SCARD_E_NO_SERVICE;
584  }
585 
586  { /* exchange client/server protocol versions */
587  struct version_struct veStr;
588 
591  veStr.rv = SCARD_S_SUCCESS;
592 
593  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
594  &veStr);
595  if (rv != SCARD_S_SUCCESS)
596  goto cleanup;
597 
598  /* Read a message from the server */
599  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
600  if (rv != SCARD_S_SUCCESS)
601  {
602  Log1(PCSC_LOG_CRITICAL,
603  "Your pcscd is too old and does not support CMD_VERSION");
604  goto cleanup;
605  }
606 
607  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
608  veStr.major, veStr.minor);
609 
610  if (veStr.rv != SCARD_S_SUCCESS)
611  {
612  rv = veStr.rv;
613  goto cleanup;
614  }
615  }
616 
617 again:
618  /*
619  * Try to establish an Application Context with the server
620  */
621  scEstablishStruct.dwScope = dwScope;
622  scEstablishStruct.hContext = 0;
623  scEstablishStruct.rv = SCARD_S_SUCCESS;
624 
626  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
627 
628  if (rv != SCARD_S_SUCCESS)
629  goto cleanup;
630 
631  /*
632  * Read the response from the server
633  */
634  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
635  dwClientID);
636 
637  if (rv != SCARD_S_SUCCESS)
638  goto cleanup;
639 
640  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
641  {
642  rv = scEstablishStruct.rv;
643  goto cleanup;
644  }
645 
646  /* check we do not reuse an existing hContext */
647  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
648  /* we do not need to release the allocated context since
649  * SCardReleaseContext() does nothing on the server side */
650  goto again;
651 
652  *phContext = scEstablishStruct.hContext;
653 
654  /*
655  * Allocate the new hContext - if allocator full return an error
656  */
657  rv = SCardAddContext(*phContext, dwClientID);
658 
659  return rv;
660 
661 cleanup:
662  ClientCloseSession(dwClientID);
663 
664  return rv;
665 }
666 
689 {
690  LONG rv;
691  struct release_struct scReleaseStruct;
692  SCONTEXTMAP * currentContextMap;
693 
694  API_TRACE_IN("%ld", hContext)
695  PROFILE_START
696 
697  /*
698  * Make sure this context has been opened
699  * and get currentContextMap
700  */
701  currentContextMap = SCardGetAndLockContext(hContext);
702  if (NULL == currentContextMap)
703  {
705  goto error;
706  }
707 
708  scReleaseStruct.hContext = hContext;
709  scReleaseStruct.rv = SCARD_S_SUCCESS;
710 
712  currentContextMap->dwClientID,
713  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
714 
715  if (rv != SCARD_S_SUCCESS)
716  goto end;
717 
718  /*
719  * Read a message from the server
720  */
721  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
722  currentContextMap->dwClientID);
723 
724  if (rv != SCARD_S_SUCCESS)
725  goto end;
726 
727  rv = scReleaseStruct.rv;
728 end:
729  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
730 
731  /*
732  * Remove the local context from the stack
733  */
734  SCardLockThread();
735  SCardRemoveContext(hContext);
737 
738 error:
739  PROFILE_END(rv)
740  API_TRACE_OUT("")
741 
742  return rv;
743 }
744 
800 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
801  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
802  LPDWORD pdwActiveProtocol)
803 {
804  LONG rv;
805  struct connect_struct scConnectStruct;
806  SCONTEXTMAP * currentContextMap;
807 
808  PROFILE_START
809  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
810 
811  /*
812  * Check for NULL parameters
813  */
814  if (phCard == NULL || pdwActiveProtocol == NULL)
816  else
817  *phCard = 0;
818 
819  if (szReader == NULL)
820  return SCARD_E_UNKNOWN_READER;
821 
822  /*
823  * Check for uninitialized strings
824  */
825  if (strlen(szReader) > MAX_READERNAME)
826  return SCARD_E_INVALID_VALUE;
827 
828  /*
829  * Make sure this context has been opened
830  */
831  currentContextMap = SCardGetAndLockContext(hContext);
832  if (NULL == currentContextMap)
833  return SCARD_E_INVALID_HANDLE;
834 
835  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
836  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
837  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
838 
839  scConnectStruct.hContext = hContext;
840  scConnectStruct.dwShareMode = dwShareMode;
841  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
842  scConnectStruct.hCard = 0;
843  scConnectStruct.dwActiveProtocol = 0;
844  scConnectStruct.rv = SCARD_S_SUCCESS;
845 
846  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
847  sizeof(scConnectStruct), (void *) &scConnectStruct);
848 
849  if (rv != SCARD_S_SUCCESS)
850  goto end;
851 
852  /*
853  * Read a message from the server
854  */
855  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
856  currentContextMap->dwClientID);
857 
858  if (rv != SCARD_S_SUCCESS)
859  goto end;
860 
861  *phCard = scConnectStruct.hCard;
862  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
863 
864  if (scConnectStruct.rv == SCARD_S_SUCCESS)
865  {
866  /*
867  * Keep track of the handle locally
868  */
869  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
870  }
871  else
872  rv = scConnectStruct.rv;
873 
874 end:
875  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
876 
877  PROFILE_END(rv)
878  API_TRACE_OUT("%d", *pdwActiveProtocol)
879 
880  return rv;
881 }
882 
955 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
956  DWORD dwPreferredProtocols, DWORD dwInitialization,
957  LPDWORD pdwActiveProtocol)
958 {
959  LONG rv;
960  struct reconnect_struct scReconnectStruct;
961  SCONTEXTMAP * currentContextMap;
962  CHANNEL_MAP * pChannelMap;
963 
964  PROFILE_START
965  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
966 
967  if (pdwActiveProtocol == NULL)
969 
970  /* Retry loop for blocking behaviour */
971 retry:
972 
973  /*
974  * Make sure this handle has been opened
975  */
976  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
977  &pChannelMap);
978  if (rv == -1)
979  return SCARD_E_INVALID_HANDLE;
980 
981  scReconnectStruct.hCard = hCard;
982  scReconnectStruct.dwShareMode = dwShareMode;
983  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
984  scReconnectStruct.dwInitialization = dwInitialization;
985  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
986  scReconnectStruct.rv = SCARD_S_SUCCESS;
987 
988  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
989  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
990 
991  if (rv != SCARD_S_SUCCESS)
992  goto end;
993 
994  /*
995  * Read a message from the server
996  */
997  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
998  currentContextMap->dwClientID);
999 
1000  if (rv != SCARD_S_SUCCESS)
1001  goto end;
1002 
1003  rv = scReconnectStruct.rv;
1004 
1005  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1006  {
1007  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1008  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1009  goto retry;
1010  }
1011 
1012  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1013 
1014 end:
1015  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1016 
1017  PROFILE_END(rv)
1018  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1019 
1020  return rv;
1021 }
1022 
1054 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1055 {
1056  LONG rv;
1057  struct disconnect_struct scDisconnectStruct;
1058  SCONTEXTMAP * currentContextMap;
1059  CHANNEL_MAP * pChannelMap;
1060 
1061  PROFILE_START
1062  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1063 
1064  /*
1065  * Make sure this handle has been opened
1066  */
1067  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1068  &pChannelMap);
1069  if (rv == -1)
1070  {
1072  goto error;
1073  }
1074 
1075  scDisconnectStruct.hCard = hCard;
1076  scDisconnectStruct.dwDisposition = dwDisposition;
1077  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1078 
1079  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1080  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1081 
1082  if (rv != SCARD_S_SUCCESS)
1083  goto end;
1084 
1085  /*
1086  * Read a message from the server
1087  */
1088  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1089  currentContextMap->dwClientID);
1090 
1091  if (rv != SCARD_S_SUCCESS)
1092  goto end;
1093 
1094  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1095  SCardRemoveHandle(hCard);
1096  rv = scDisconnectStruct.rv;
1097 
1098 end:
1099  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1100 
1101 error:
1102  PROFILE_END(rv)
1103  API_TRACE_OUT("")
1104 
1105  return rv;
1106 }
1107 
1145 {
1146 
1147  LONG rv;
1148  struct begin_struct scBeginStruct;
1149  SCONTEXTMAP * currentContextMap;
1150  CHANNEL_MAP * pChannelMap;
1151 
1152  PROFILE_START
1153  API_TRACE_IN("%ld", hCard)
1154 
1155  /*
1156  * Query the server every so often until the sharing violation ends
1157  * and then hold the lock for yourself.
1158  */
1159 
1160  for(;;)
1161  {
1162  /*
1163  * Make sure this handle has been opened
1164  */
1165  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1166  &pChannelMap);
1167  if (rv == -1)
1168  return SCARD_E_INVALID_HANDLE;
1169 
1170  scBeginStruct.hCard = hCard;
1171  scBeginStruct.rv = SCARD_S_SUCCESS;
1172 
1174  currentContextMap->dwClientID,
1175  sizeof(scBeginStruct), (void *) &scBeginStruct);
1176 
1177  if (rv != SCARD_S_SUCCESS)
1178  break;
1179 
1180  /*
1181  * Read a message from the server
1182  */
1183  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1184  currentContextMap->dwClientID);
1185 
1186  if (rv != SCARD_S_SUCCESS)
1187  break;
1188 
1189  rv = scBeginStruct.rv;
1190 
1191  if (SCARD_E_SHARING_VIOLATION != rv)
1192  break;
1193 
1194  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1195  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1196  }
1197 
1198  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1199 
1200  PROFILE_END(rv)
1201  API_TRACE_OUT("")
1202 
1203  return rv;
1204 }
1205 
1245 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1246 {
1247  LONG rv;
1248  struct end_struct scEndStruct;
1249  SCONTEXTMAP * currentContextMap;
1250  CHANNEL_MAP * pChannelMap;
1251 
1252  PROFILE_START
1253  API_TRACE_IN("%ld", hCard)
1254 
1255  /*
1256  * Make sure this handle has been opened
1257  */
1258  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1259  &pChannelMap);
1260  if (rv == -1)
1261  return SCARD_E_INVALID_HANDLE;
1262 
1263  scEndStruct.hCard = hCard;
1264  scEndStruct.dwDisposition = dwDisposition;
1265  scEndStruct.rv = SCARD_S_SUCCESS;
1266 
1268  currentContextMap->dwClientID,
1269  sizeof(scEndStruct), (void *) &scEndStruct);
1270 
1271  if (rv != SCARD_S_SUCCESS)
1272  goto end;
1273 
1274  /*
1275  * Read a message from the server
1276  */
1277  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1278  currentContextMap->dwClientID);
1279 
1280  if (rv != SCARD_S_SUCCESS)
1281  goto end;
1282 
1283  rv = scEndStruct.rv;
1284 
1285 end:
1286  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1287 
1288  PROFILE_END(rv)
1289  API_TRACE_OUT("")
1290 
1291  return rv;
1292 }
1293 
1389 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1390  LPDWORD pcchReaderLen, LPDWORD pdwState,
1391  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1392 {
1393  DWORD dwReaderLen, dwAtrLen;
1394  LONG rv;
1395  int i;
1396  struct status_struct scStatusStruct;
1397  SCONTEXTMAP * currentContextMap;
1398  CHANNEL_MAP * pChannelMap;
1399  char *r;
1400  char *bufReader = NULL;
1401  LPBYTE bufAtr = NULL;
1402  DWORD dummy = 0;
1403 
1404  PROFILE_START
1405 
1406  /* default output values */
1407  if (pdwState)
1408  *pdwState = 0;
1409 
1410  if (pdwProtocol)
1411  *pdwProtocol = 0;
1412 
1413  /* Check for NULL parameters */
1414  if (pcchReaderLen == NULL)
1415  pcchReaderLen = &dummy;
1416 
1417  if (pcbAtrLen == NULL)
1418  pcbAtrLen = &dummy;
1419 
1420  /* length passed from caller */
1421  dwReaderLen = *pcchReaderLen;
1422  dwAtrLen = *pcbAtrLen;
1423 
1424  *pcchReaderLen = 0;
1425  *pcbAtrLen = 0;
1426 
1427  /* Retry loop for blocking behaviour */
1428 retry:
1429 
1430  /*
1431  * Make sure this handle has been opened
1432  */
1433  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1434  &pChannelMap);
1435  if (rv == -1)
1436  return SCARD_E_INVALID_HANDLE;
1437 
1438  /* lock access to readerStates[] */
1439  (void)pthread_mutex_lock(&readerStatesMutex);
1440 
1441  /* synchronize reader states with daemon */
1442  rv = getReaderStates(currentContextMap);
1443  if (rv != SCARD_S_SUCCESS)
1444  goto end;
1445 
1446  r = pChannelMap->readerName;
1447  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1448  {
1449  /* by default r == NULL */
1450  if (r && strcmp(r, readerStates[i].readerName) == 0)
1451  break;
1452  }
1453 
1455  {
1457  goto end;
1458  }
1459 
1460  /* initialise the structure */
1461  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1462  scStatusStruct.hCard = hCard;
1463 
1464  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1465  sizeof(scStatusStruct), (void *) &scStatusStruct);
1466 
1467  if (rv != SCARD_S_SUCCESS)
1468  goto end;
1469 
1470  /*
1471  * Read a message from the server
1472  */
1473  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1474  currentContextMap->dwClientID);
1475 
1476  if (rv != SCARD_S_SUCCESS)
1477  goto end;
1478 
1479  rv = scStatusStruct.rv;
1480 
1481  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1482  {
1483  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1484  (void)pthread_mutex_unlock(&readerStatesMutex);
1485  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1486  goto retry;
1487  }
1488 
1489  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1490  {
1491  /*
1492  * An event must have occurred
1493  */
1494  goto end;
1495  }
1496 
1497  /*
1498  * Now continue with the client side SCardStatus
1499  */
1500 
1501  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1502  *pcbAtrLen = readerStates[i].cardAtrLength;
1503 
1504  if (pdwState)
1505  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1506 
1507  if (pdwProtocol)
1508  *pdwProtocol = readerStates[i].cardProtocol;
1509 
1510  if (SCARD_AUTOALLOCATE == dwReaderLen)
1511  {
1512  dwReaderLen = *pcchReaderLen;
1513  if (NULL == szReaderName)
1514  {
1516  goto end;
1517  }
1518  bufReader = malloc(dwReaderLen);
1519  if (NULL == bufReader)
1520  {
1521  rv = SCARD_E_NO_MEMORY;
1522  goto end;
1523  }
1524  *(char **)szReaderName = bufReader;
1525  }
1526  else
1527  bufReader = szReaderName;
1528 
1529  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1530  if (bufReader)
1531  {
1532  if (*pcchReaderLen > dwReaderLen)
1534 
1535  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1536  }
1537 
1538  if (SCARD_AUTOALLOCATE == dwAtrLen)
1539  {
1540  dwAtrLen = *pcbAtrLen;
1541  if (NULL == pbAtr)
1542  {
1544  goto end;
1545  }
1546  bufAtr = malloc(dwAtrLen);
1547  if (NULL == bufAtr)
1548  {
1549  rv = SCARD_E_NO_MEMORY;
1550  goto end;
1551  }
1552  *(LPBYTE *)pbAtr = bufAtr;
1553  }
1554  else
1555  bufAtr = pbAtr;
1556 
1557  if (bufAtr)
1558  {
1559  if (*pcbAtrLen > dwAtrLen)
1561 
1562  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1563  }
1564 
1565 end:
1566  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1567  (void)pthread_mutex_unlock(&readerStatesMutex);
1568 
1569  PROFILE_END(rv)
1570 
1571  return rv;
1572 }
1573 
1681 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1682  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1683 {
1684  SCARD_READERSTATE *currReader;
1685  READER_STATE *rContext;
1686  long dwTime;
1687  DWORD dwBreakFlag = 0;
1688  unsigned int j;
1689  SCONTEXTMAP * currentContextMap;
1690  int currentReaderCount = 0;
1691  LONG rv = SCARD_S_SUCCESS;
1692 
1693  PROFILE_START
1694  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1695 #ifdef DO_TRACE
1696  for (j=0; j<cReaders; j++)
1697  {
1698  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1699  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1700  }
1701 #endif
1702 
1703  if ((rgReaderStates == NULL && cReaders > 0)
1704  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1705  {
1707  goto error;
1708  }
1709 
1710  /* Check the integrity of the reader states structures */
1711  for (j = 0; j < cReaders; j++)
1712  {
1713  if (rgReaderStates[j].szReader == NULL)
1714  return SCARD_E_INVALID_VALUE;
1715  }
1716 
1717  /* return if all readers are SCARD_STATE_IGNORE */
1718  if (cReaders > 0)
1719  {
1720  int nbNonIgnoredReaders = cReaders;
1721 
1722  for (j=0; j<cReaders; j++)
1723  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1724  nbNonIgnoredReaders--;
1725 
1726  if (0 == nbNonIgnoredReaders)
1727  {
1728  rv = SCARD_S_SUCCESS;
1729  goto error;
1730  }
1731  }
1732  else
1733  {
1734  /* reader list is empty */
1735  rv = SCARD_S_SUCCESS;
1736  goto error;
1737  }
1738 
1739  /*
1740  * Make sure this context has been opened
1741  */
1742  currentContextMap = SCardGetAndLockContext(hContext);
1743  if (NULL == currentContextMap)
1744  {
1746  goto error;
1747  }
1748 
1749  /* lock access to readerStates[] */
1750  (void)pthread_mutex_lock(&readerStatesMutex);
1751 
1752  /* synchronize reader states with daemon */
1753  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1754 
1755  if (rv != SCARD_S_SUCCESS)
1756  {
1757  (void)pthread_mutex_unlock(&readerStatesMutex);
1758  goto end;
1759  }
1760 
1761  /* check all the readers are already known */
1762  for (j=0; j<cReaders; j++)
1763  {
1764  const char *readerName;
1765  int i;
1766 
1767  readerName = rgReaderStates[j].szReader;
1768  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1769  {
1770  if (strcmp(readerName, readerStates[i].readerName) == 0)
1771  break;
1772  }
1773 
1774  /* The requested reader name is not recognized */
1776  {
1777  /* PnP special reader? */
1778  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1779  {
1781  (void)pthread_mutex_unlock(&readerStatesMutex);
1782  goto end;
1783  }
1784  }
1785  }
1786  (void)pthread_mutex_unlock(&readerStatesMutex);
1787 
1788  /* Clear the event state for all readers */
1789  for (j = 0; j < cReaders; j++)
1790  rgReaderStates[j].dwEventState = 0;
1791 
1792  /* Now is where we start our event checking loop */
1793  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1794 
1795  /* Get the initial reader count on the system */
1796  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1797  if (readerStates[j].readerName[0] != '\0')
1798  currentReaderCount++;
1799 
1800  /* catch possible sign extension problems from 32 to 64-bits integers */
1801  if ((DWORD)-1 == dwTimeout)
1802  dwTimeout = INFINITE;
1803  if (INFINITE == dwTimeout)
1804  dwTime = 60*1000; /* "infinite" timeout */
1805  else
1806  dwTime = dwTimeout;
1807 
1808  j = 0;
1809  do
1810  {
1811  currReader = &rgReaderStates[j];
1812 
1813  /* Ignore for IGNORED readers */
1814  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1815  {
1816  const char *readerName;
1817  int i;
1818 
1819  /* lock access to readerStates[] */
1820  (void)pthread_mutex_lock(&readerStatesMutex);
1821 
1822  /* Looks for correct readernames */
1823  readerName = currReader->szReader;
1824  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1825  {
1826  if (strcmp(readerName, readerStates[i].readerName) == 0)
1827  break;
1828  }
1829 
1830  /* The requested reader name is not recognized */
1832  {
1833  /* PnP special reader? */
1834  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1835  {
1836  int k, newReaderCount = 0;
1837 
1838  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1839  if (readerStates[k].readerName[0] != '\0')
1840  newReaderCount++;
1841 
1842  if (newReaderCount != currentReaderCount)
1843  {
1844  Log1(PCSC_LOG_INFO, "Reader list changed");
1845  currentReaderCount = newReaderCount;
1846 
1847  currReader->dwEventState |= SCARD_STATE_CHANGED;
1848  dwBreakFlag = 1;
1849  }
1850  }
1851  else
1852  {
1853  currReader->dwEventState =
1855  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1856  {
1857  currReader->dwEventState |= SCARD_STATE_CHANGED;
1858  /*
1859  * Spec says use SCARD_STATE_IGNORE but a removed USB
1860  * reader with eventState fed into currentState will
1861  * be ignored forever
1862  */
1863  dwBreakFlag = 1;
1864  }
1865  }
1866  }
1867  else
1868  {
1869  uint32_t readerState;
1870 
1871  /* The reader has come back after being away */
1872  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1873  {
1874  currReader->dwEventState |= SCARD_STATE_CHANGED;
1875  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1876  Log0(PCSC_LOG_DEBUG);
1877  dwBreakFlag = 1;
1878  }
1879 
1880  /* Set the reader status structure */
1881  rContext = &readerStates[i];
1882 
1883  /* Now we check all the Reader States */
1884  readerState = rContext->readerState;
1885 
1886  /* only if current state has an non null event counter */
1887  if (currReader->dwCurrentState & 0xFFFF0000)
1888  {
1889  unsigned int currentCounter;
1890 
1891  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1892 
1893  /* has the event counter changed since the last call? */
1894  if (rContext->eventCounter != currentCounter)
1895  {
1896  currReader->dwEventState |= SCARD_STATE_CHANGED;
1897  Log0(PCSC_LOG_DEBUG);
1898  dwBreakFlag = 1;
1899  }
1900  }
1901 
1902  /* add an event counter in the upper word of dwEventState */
1903  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1904  | (rContext->eventCounter << 16));
1905 
1906  /* Check if the reader is in the correct state */
1907  if (readerState & SCARD_UNKNOWN)
1908  {
1909  /* reader is in bad state */
1910  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1911  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1912  {
1913  /* App thinks reader is in good state and it is not */
1914  currReader->dwEventState |= SCARD_STATE_CHANGED;
1915  Log0(PCSC_LOG_DEBUG);
1916  dwBreakFlag = 1;
1917  }
1918  }
1919  else
1920  {
1921  /* App thinks reader in bad state but it is not */
1922  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1923  {
1924  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1925  currReader->dwEventState |= SCARD_STATE_CHANGED;
1926  Log0(PCSC_LOG_DEBUG);
1927  dwBreakFlag = 1;
1928  }
1929  }
1930 
1931  /* Check for card presence in the reader */
1932  if (readerState & SCARD_PRESENT)
1933  {
1934 #ifndef DISABLE_AUTO_POWER_ON
1935  /* card present but not yet powered up */
1936  if (0 == rContext->cardAtrLength)
1937  /* Allow the status thread to convey information */
1938  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1939 #endif
1940 
1941  currReader->cbAtr = rContext->cardAtrLength;
1942  memcpy(currReader->rgbAtr, rContext->cardAtr,
1943  currReader->cbAtr);
1944  }
1945  else
1946  currReader->cbAtr = 0;
1947 
1948  /* Card is now absent */
1949  if (readerState & SCARD_ABSENT)
1950  {
1951  currReader->dwEventState |= SCARD_STATE_EMPTY;
1952  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1953  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1954  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1955  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1956  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1957  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1958  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1959  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1960 
1961  /* After present the rest are assumed */
1962  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1963  {
1964  currReader->dwEventState |= SCARD_STATE_CHANGED;
1965  Log0(PCSC_LOG_DEBUG);
1966  dwBreakFlag = 1;
1967  }
1968  }
1969  /* Card is now present */
1970  else if (readerState & SCARD_PRESENT)
1971  {
1972  currReader->dwEventState |= SCARD_STATE_PRESENT;
1973  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1974  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1975  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1976  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1977  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1978  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1979 
1980  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1981  {
1982  currReader->dwEventState |= SCARD_STATE_CHANGED;
1983  Log0(PCSC_LOG_DEBUG);
1984  dwBreakFlag = 1;
1985  }
1986 
1987  if (readerState & SCARD_SWALLOWED)
1988  {
1989  currReader->dwEventState |= SCARD_STATE_MUTE;
1990  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1991  {
1992  currReader->dwEventState |= SCARD_STATE_CHANGED;
1993  Log0(PCSC_LOG_DEBUG);
1994  dwBreakFlag = 1;
1995  }
1996  }
1997  else
1998  {
1999  /* App thinks card is mute but it is not */
2000  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2001  {
2002  currReader->dwEventState |= SCARD_STATE_CHANGED;
2003  Log0(PCSC_LOG_DEBUG);
2004  dwBreakFlag = 1;
2005  }
2006  }
2007  }
2008 
2009  /* Now figure out sharing modes */
2011  {
2012  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2013  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2014  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2015  {
2016  currReader->dwEventState |= SCARD_STATE_CHANGED;
2017  Log0(PCSC_LOG_DEBUG);
2018  dwBreakFlag = 1;
2019  }
2020  }
2021  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2022  {
2023  /* A card must be inserted for it to be INUSE */
2024  if (readerState & SCARD_PRESENT)
2025  {
2026  currReader->dwEventState |= SCARD_STATE_INUSE;
2027  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2028  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2029  {
2030  currReader->dwEventState |= SCARD_STATE_CHANGED;
2031  Log0(PCSC_LOG_DEBUG);
2032  dwBreakFlag = 1;
2033  }
2034  }
2035  }
2036  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2037  {
2038  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2039  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2040 
2041  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2042  {
2043  currReader->dwEventState |= SCARD_STATE_CHANGED;
2044  Log0(PCSC_LOG_DEBUG);
2045  dwBreakFlag = 1;
2046  }
2047  else if (currReader-> dwCurrentState
2049  {
2050  currReader->dwEventState |= SCARD_STATE_CHANGED;
2051  Log0(PCSC_LOG_DEBUG);
2052  dwBreakFlag = 1;
2053  }
2054  }
2055 
2056  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2057  {
2058  /*
2059  * Break out of the while .. loop and return status
2060  * once all the status's for all readers is met
2061  */
2062  currReader->dwEventState |= SCARD_STATE_CHANGED;
2063  Log0(PCSC_LOG_DEBUG);
2064  dwBreakFlag = 1;
2065  }
2066  } /* End of SCARD_STATE_UNKNOWN */
2067 
2068  (void)pthread_mutex_unlock(&readerStatesMutex);
2069  } /* End of SCARD_STATE_IGNORE */
2070 
2071  /* Counter and resetter */
2072  j++;
2073  if (j == cReaders)
2074  {
2075  /* go back to the first reader */
2076  j = 0;
2077 
2078  /* Declare all the break conditions */
2079 
2080  /* Break if UNAWARE is set and all readers have been checked */
2081  if (dwBreakFlag == 1)
2082  break;
2083 
2084  /* Only sleep once for each cycle of reader checks. */
2085  {
2086  struct wait_reader_state_change waitStatusStruct = {0};
2087  struct timeval before, after;
2088 
2089  gettimeofday(&before, NULL);
2090 
2091  waitStatusStruct.rv = SCARD_S_SUCCESS;
2092 
2093  /* another thread can do SCardCancel() */
2094  currentContextMap->cancellable = true;
2095 
2096  /*
2097  * Read a message from the server
2098  */
2100  &waitStatusStruct, sizeof(waitStatusStruct),
2101  currentContextMap->dwClientID, dwTime);
2102 
2103  /* SCardCancel() will return immediately with success
2104  * because something changed on the daemon side. */
2105  currentContextMap->cancellable = false;
2106 
2107  /* timeout */
2108  if (SCARD_E_TIMEOUT == rv)
2109  {
2110  /* ask server to remove us from the event list */
2111  rv = unregisterFromEvents(currentContextMap);
2112  }
2113 
2114  if (rv != SCARD_S_SUCCESS)
2115  goto end;
2116 
2117  /* an event occurs or SCardCancel() was called */
2118  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2119  {
2120  rv = waitStatusStruct.rv;
2121  goto end;
2122  }
2123 
2124  /* synchronize reader states with daemon */
2125  (void)pthread_mutex_lock(&readerStatesMutex);
2126  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2127  (void)pthread_mutex_unlock(&readerStatesMutex);
2128  if (rv != SCARD_S_SUCCESS)
2129  goto end;
2130 
2131  if (INFINITE != dwTimeout)
2132  {
2133  long int diff;
2134 
2135  gettimeofday(&after, NULL);
2136  diff = time_sub(&after, &before);
2137  dwTime -= diff/1000;
2138  }
2139  }
2140 
2141  if (dwTimeout != INFINITE)
2142  {
2143  /* If time is greater than timeout and all readers have been
2144  * checked
2145  */
2146  if (dwTime <= 0)
2147  {
2148  rv = SCARD_E_TIMEOUT;
2149  goto end;
2150  }
2151  }
2152  }
2153  }
2154  while (1);
2155 
2156 end:
2157  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2158 
2159  /* if SCardCancel() has been used then the client is already
2160  * unregistered */
2161  if (SCARD_E_CANCELLED != rv)
2162  (void)unregisterFromEvents(currentContextMap);
2163 
2164  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2165 
2166 error:
2167  PROFILE_END(rv)
2168 #ifdef DO_TRACE
2169  for (j=0; j<cReaders; j++)
2170  {
2171  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2172  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2173  }
2174 #endif
2175 
2176  return rv;
2177 }
2178 
2229 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2230  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2231  LPDWORD lpBytesReturned)
2232 {
2233  LONG rv;
2234  struct control_struct scControlStruct;
2235  SCONTEXTMAP * currentContextMap;
2236  CHANNEL_MAP * pChannelMap;
2237 
2238  PROFILE_START
2239 
2240  /* 0 bytes received by default */
2241  if (NULL != lpBytesReturned)
2242  *lpBytesReturned = 0;
2243 
2244  /*
2245  * Make sure this handle has been opened
2246  */
2247  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2248  &pChannelMap);
2249  if (rv == -1)
2250  {
2251  PROFILE_END(SCARD_E_INVALID_HANDLE)
2252  return SCARD_E_INVALID_HANDLE;
2253  }
2254 
2255  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2256  {
2258  goto end;
2259  }
2260 
2261  scControlStruct.hCard = hCard;
2262  scControlStruct.dwControlCode = dwControlCode;
2263  scControlStruct.cbSendLength = cbSendLength;
2264  scControlStruct.cbRecvLength = cbRecvLength;
2265  scControlStruct.dwBytesReturned = 0;
2266  scControlStruct.rv = 0;
2267 
2268  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2269  sizeof(scControlStruct), &scControlStruct);
2270 
2271  if (rv != SCARD_S_SUCCESS)
2272  goto end;
2273 
2274  /* write the sent buffer */
2275  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2276  currentContextMap->dwClientID);
2277 
2278  if (rv != SCARD_S_SUCCESS)
2279  goto end;
2280 
2281  /*
2282  * Read a message from the server
2283  */
2284  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2285  currentContextMap->dwClientID);
2286 
2287  if (rv != SCARD_S_SUCCESS)
2288  goto end;
2289 
2290  if (SCARD_S_SUCCESS == scControlStruct.rv)
2291  {
2292  if (scControlStruct.dwBytesReturned > cbRecvLength)
2293  {
2294  if (NULL != lpBytesReturned)
2295  *lpBytesReturned = scControlStruct.dwBytesReturned;
2297  goto end;
2298  }
2299 
2300  /* read the received buffer */
2301  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2302  currentContextMap->dwClientID);
2303 
2304  if (rv != SCARD_S_SUCCESS)
2305  goto end;
2306 
2307  }
2308 
2309  if (NULL != lpBytesReturned)
2310  *lpBytesReturned = scControlStruct.dwBytesReturned;
2311 
2312  rv = scControlStruct.rv;
2313 
2314 end:
2315  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2316 
2317  PROFILE_END(rv)
2318 
2319  return rv;
2320 }
2321 
2440 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2441  LPDWORD pcbAttrLen)
2442 {
2443  LONG ret;
2444  unsigned char *buf = NULL;
2445 
2446  PROFILE_START
2447 
2448  if (NULL == pcbAttrLen)
2449  {
2451  goto end;
2452  }
2453 
2454  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2455  {
2456  if (NULL == pbAttr)
2458 
2459  *pcbAttrLen = MAX_BUFFER_SIZE;
2460  buf = malloc(*pcbAttrLen);
2461  if (NULL == buf)
2462  {
2463  ret = SCARD_E_NO_MEMORY;
2464  goto end;
2465  }
2466 
2467  *(unsigned char **)pbAttr = buf;
2468  }
2469  else
2470  {
2471  buf = pbAttr;
2472 
2473  /* if only get the length */
2474  if (NULL == pbAttr)
2475  /* use a reasonable size */
2476  *pcbAttrLen = MAX_BUFFER_SIZE;
2477  }
2478 
2479  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2480  pcbAttrLen);
2481 
2482 end:
2483  PROFILE_END(ret)
2484 
2485  return ret;
2486 }
2487 
2523 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2524  DWORD cbAttrLen)
2525 {
2526  LONG ret;
2527 
2528  PROFILE_START
2529 
2530  if (NULL == pbAttr || 0 == cbAttrLen)
2532 
2533  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2534  &cbAttrLen);
2535 
2536  PROFILE_END(ret)
2537 
2538  return ret;
2539 }
2540 
2541 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2542  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2543 {
2544  LONG rv;
2545  struct getset_struct scGetSetStruct;
2546  SCONTEXTMAP * currentContextMap;
2547  CHANNEL_MAP * pChannelMap;
2548 
2549  /*
2550  * Make sure this handle has been opened
2551  */
2552  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2553  &pChannelMap);
2554  if (rv == -1)
2555  return SCARD_E_INVALID_HANDLE;
2556 
2557  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2558  {
2560  goto end;
2561  }
2562 
2563  scGetSetStruct.hCard = hCard;
2564  scGetSetStruct.dwAttrId = dwAttrId;
2565  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2566  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2567  if (SCARD_SET_ATTRIB == command)
2568  {
2569  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2570  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2571  }
2572  else
2573  /* we can get up to the communication buffer size */
2574  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2575 
2576  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2577  sizeof(scGetSetStruct), &scGetSetStruct);
2578 
2579  if (rv != SCARD_S_SUCCESS)
2580  goto end;
2581 
2582  /*
2583  * Read a message from the server
2584  */
2585  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2586  currentContextMap->dwClientID);
2587 
2588  if (rv != SCARD_S_SUCCESS)
2589  goto end;
2590 
2591  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2592  {
2593  /*
2594  * Copy and zero it so any secret information is not leaked
2595  */
2596  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2597  {
2598  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2599  * buffer overflow in the memcpy() below */
2600  DWORD correct_value = scGetSetStruct.cbAttrLen;
2601  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2602  *pcbAttrLen = correct_value;
2603 
2604  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2605  }
2606  else
2607  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2608 
2609  if (pbAttr)
2610  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2611 
2612  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2613  }
2614  rv = scGetSetStruct.rv;
2615 
2616 end:
2617  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2618 
2619  return rv;
2620 }
2621 
2680 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2681  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2682  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2683  LPDWORD pcbRecvLength)
2684 {
2685  LONG rv;
2686  SCONTEXTMAP * currentContextMap;
2687  CHANNEL_MAP * pChannelMap;
2688  struct transmit_struct scTransmitStruct;
2689 
2690  PROFILE_START
2691 
2692  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2693  pcbRecvLength == NULL || pioSendPci == NULL)
2695 
2696  /* Retry loop for blocking behaviour */
2697 retry:
2698 
2699  /*
2700  * Make sure this handle has been opened
2701  */
2702  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2703  &pChannelMap);
2704  if (rv == -1)
2705  {
2706  *pcbRecvLength = 0;
2707  PROFILE_END(SCARD_E_INVALID_HANDLE)
2708  return SCARD_E_INVALID_HANDLE;
2709  }
2710 
2711  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2712  {
2714  goto end;
2715  }
2716 
2717  scTransmitStruct.hCard = hCard;
2718  scTransmitStruct.cbSendLength = cbSendLength;
2719  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2720  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2721  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2722  scTransmitStruct.rv = SCARD_S_SUCCESS;
2723 
2724  if (pioRecvPci)
2725  {
2726  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2727  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2728  }
2729  else
2730  {
2731  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2732  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2733  }
2734 
2735  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2736  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2737 
2738  if (rv != SCARD_S_SUCCESS)
2739  goto end;
2740 
2741  /* write the sent buffer */
2742  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2743  currentContextMap->dwClientID);
2744 
2745  if (rv != SCARD_S_SUCCESS)
2746  goto end;
2747 
2748  /*
2749  * Read a message from the server
2750  */
2751  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2752  currentContextMap->dwClientID);
2753 
2754  if (rv != SCARD_S_SUCCESS)
2755  goto end;
2756 
2757  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2758  {
2759  if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2760  {
2761  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2763  goto end;
2764  }
2765 
2766  /* read the received buffer */
2767  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2768  currentContextMap->dwClientID);
2769 
2770  if (rv != SCARD_S_SUCCESS)
2771  goto end;
2772 
2773  if (pioRecvPci)
2774  {
2775  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2776  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2777  }
2778  }
2779 
2780  rv = scTransmitStruct.rv;
2781 
2782  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2783  {
2784  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2785  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2786  goto retry;
2787  }
2788 
2789  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2790 
2791 end:
2792  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2793 
2794  PROFILE_END(rv)
2795 
2796  return rv;
2797 }
2798 
2861 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2862  LPSTR mszReaders, LPDWORD pcchReaders)
2863 {
2864  DWORD dwReadersLen = 0;
2865  int i;
2866  SCONTEXTMAP * currentContextMap;
2867  LONG rv = SCARD_S_SUCCESS;
2868  char *buf = NULL;
2869 
2870  (void)mszGroups;
2871  PROFILE_START
2872  API_TRACE_IN("%ld", hContext)
2873 
2874  /*
2875  * Check for NULL parameters
2876  */
2877  if (pcchReaders == NULL)
2879 
2880  /*
2881  * Make sure this context has been opened
2882  */
2883  currentContextMap = SCardGetAndLockContext(hContext);
2884  if (NULL == currentContextMap)
2885  {
2886  PROFILE_END(SCARD_E_INVALID_HANDLE)
2887  return SCARD_E_INVALID_HANDLE;
2888  }
2889 
2890  /* lock access to readerStates[] */
2891  (void)pthread_mutex_lock(&readerStatesMutex);
2892 
2893  /* synchronize reader states with daemon */
2894  rv = getReaderStates(currentContextMap);
2895  if (rv != SCARD_S_SUCCESS)
2896  goto end;
2897 
2898  dwReadersLen = 0;
2899  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2900  if (readerStates[i].readerName[0] != '\0')
2901  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2902 
2903  /* for the last NULL byte */
2904  dwReadersLen += 1;
2905 
2906  if (1 == dwReadersLen)
2907  {
2909  goto end;
2910  }
2911 
2912  if (SCARD_AUTOALLOCATE == *pcchReaders)
2913  {
2914  if (NULL == mszReaders)
2915  {
2917  goto end;
2918  }
2919  buf = malloc(dwReadersLen);
2920  if (NULL == buf)
2921  {
2922  rv = SCARD_E_NO_MEMORY;
2923  goto end;
2924  }
2925  *(char **)mszReaders = buf;
2926  }
2927  else
2928  {
2929  buf = mszReaders;
2930 
2931  /* not enough place to store the reader names */
2932  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2933  {
2935  goto end;
2936  }
2937  }
2938 
2939  if (mszReaders == NULL) /* text array not allocated */
2940  goto end;
2941 
2942  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2943  {
2944  if (readerStates[i].readerName[0] != '\0')
2945  {
2946  /*
2947  * Build the multi-string
2948  */
2949  strcpy(buf, readerStates[i].readerName);
2950  buf += strlen(readerStates[i].readerName)+1;
2951  }
2952  }
2953  *buf = '\0'; /* Add the last null */
2954 
2955 end:
2956  /* set the reader names length */
2957  *pcchReaders = dwReadersLen;
2958 
2959  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2960  (void)pthread_mutex_unlock(&readerStatesMutex);
2961 
2962  PROFILE_END(rv)
2963  API_TRACE_OUT("%d", *pcchReaders)
2964 
2965  return rv;
2966 }
2967 
2981 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2982 {
2983  LONG rv = SCARD_S_SUCCESS;
2984 
2985  PROFILE_START
2986 
2987  /*
2988  * Make sure this context has been opened
2989  */
2990  if (! SCardGetContextValidity(hContext))
2991  return SCARD_E_INVALID_HANDLE;
2992 
2993  free((void *)pvMem);
2994 
2995  PROFILE_END(rv)
2996 
2997  return rv;
2998 }
2999 
3051 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3052  LPDWORD pcchGroups)
3053 {
3054  LONG rv = SCARD_S_SUCCESS;
3055  SCONTEXTMAP * currentContextMap;
3056  char *buf = NULL;
3057 
3058  PROFILE_START
3059 
3060  /* Multi-string with two trailing \0 */
3061  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3062  const unsigned int dwGroups = sizeof(ReaderGroup);
3063 
3064  /*
3065  * Make sure this context has been opened
3066  */
3067  currentContextMap = SCardGetAndLockContext(hContext);
3068  if (NULL == currentContextMap)
3069  return SCARD_E_INVALID_HANDLE;
3070 
3071  if (SCARD_AUTOALLOCATE == *pcchGroups)
3072  {
3073  if (NULL == mszGroups)
3074  {
3076  goto end;
3077  }
3078  buf = malloc(dwGroups);
3079  if (NULL == buf)
3080  {
3081  rv = SCARD_E_NO_MEMORY;
3082  goto end;
3083  }
3084  *(char **)mszGroups = buf;
3085  }
3086  else
3087  {
3088  buf = mszGroups;
3089 
3090  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3091  {
3093  goto end;
3094  }
3095  }
3096 
3097  if (buf)
3098  memcpy(buf, ReaderGroup, dwGroups);
3099 
3100 end:
3101  *pcchGroups = dwGroups;
3102 
3103  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3104 
3105  PROFILE_END(rv)
3106 
3107  return rv;
3108 }
3109 
3142 {
3143  SCONTEXTMAP * currentContextMap;
3144  LONG rv = SCARD_S_SUCCESS;
3145  uint32_t dwClientID = 0;
3146  struct cancel_struct scCancelStruct;
3147  bool cancellable;
3148 
3149  PROFILE_START
3150  API_TRACE_IN("%ld", hContext)
3151 
3152  /*
3153  * Make sure this context has been opened
3154  */
3155  (void)SCardLockThread();
3156  currentContextMap = SCardGetContextTH(hContext);
3157 
3158  if (NULL == currentContextMap)
3159  {
3160  (void)SCardUnlockThread();
3162  goto error;
3163  }
3164  cancellable = currentContextMap->cancellable;
3165  (void)SCardUnlockThread();
3166 
3167  if (! cancellable)
3168  {
3169  rv = SCARD_S_SUCCESS;
3170  goto error;
3171  }
3172 
3173  /* create a new connection to the server */
3174  if (ClientSetupSession(&dwClientID) != 0)
3175  {
3176  rv = SCARD_E_NO_SERVICE;
3177  goto error;
3178  }
3179 
3180  scCancelStruct.hContext = hContext;
3181  scCancelStruct.rv = SCARD_S_SUCCESS;
3182 
3183  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3184  sizeof(scCancelStruct), (void *) &scCancelStruct);
3185 
3186  if (rv != SCARD_S_SUCCESS)
3187  goto end;
3188 
3189  /*
3190  * Read a message from the server
3191  */
3192  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3193 
3194  if (rv != SCARD_S_SUCCESS)
3195  goto end;
3196 
3197  rv = scCancelStruct.rv;
3198 end:
3199  ClientCloseSession(dwClientID);
3200 
3201 error:
3202  PROFILE_END(rv)
3203  API_TRACE_OUT("")
3204 
3205  return rv;
3206 }
3207 
3232 {
3233  LONG rv;
3234 
3235  PROFILE_START
3236  API_TRACE_IN("%ld", hContext)
3237 
3238  rv = SCARD_S_SUCCESS;
3239 
3240  /*
3241  * Make sure this context has been opened
3242  */
3243  if (! SCardGetContextValidity(hContext))
3245 
3246  PROFILE_END(rv)
3247  API_TRACE_OUT("")
3248 
3249  return rv;
3250 }
3251 
3268 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3269 {
3270  int lrv;
3271  SCONTEXTMAP * newContextMap;
3272 
3273  newContextMap = malloc(sizeof(SCONTEXTMAP));
3274  if (NULL == newContextMap)
3275  return SCARD_E_NO_MEMORY;
3276 
3277  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3278  newContextMap->hContext = hContext;
3279  newContextMap->dwClientID = dwClientID;
3280  newContextMap->cancellable = false;
3281 
3282  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3283 
3284  lrv = list_init(&newContextMap->channelMapList);
3285  if (lrv < 0)
3286  {
3287  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3288  goto error;
3289  }
3290 
3291  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3292  CHANNEL_MAP_seeker);
3293  if (lrv <0)
3294  {
3295  Log2(PCSC_LOG_CRITICAL,
3296  "list_attributes_seeker failed with return value: %d", lrv);
3297  list_destroy(&newContextMap->channelMapList);
3298  goto error;
3299  }
3300 
3301  lrv = list_append(&contextMapList, newContextMap);
3302  if (lrv < 0)
3303  {
3304  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3305  lrv);
3306  list_destroy(&newContextMap->channelMapList);
3307  goto error;
3308  }
3309 
3310  return SCARD_S_SUCCESS;
3311 
3312 error:
3313 
3314  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3315  free(newContextMap);
3316 
3317  return SCARD_E_NO_MEMORY;
3318 }
3319 
3337 {
3338  SCONTEXTMAP * currentContextMap;
3339 
3340  SCardLockThread();
3341  currentContextMap = SCardGetContextTH(hContext);
3342 
3343  /* lock the context (if available) */
3344  if (NULL != currentContextMap)
3345  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3346 
3348 
3349  return currentContextMap;
3350 }
3351 
3365 {
3366  return list_seek(&contextMapList, &hContext);
3367 }
3368 
3375 static void SCardRemoveContext(SCARDCONTEXT hContext)
3376 {
3377  SCONTEXTMAP * currentContextMap;
3378  currentContextMap = SCardGetContextTH(hContext);
3379 
3380  if (NULL != currentContextMap)
3381  SCardCleanContext(currentContextMap);
3382 }
3383 
3384 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3385 {
3386  int list_index, lrv;
3387  int listSize;
3388  CHANNEL_MAP * currentChannelMap;
3389 
3390  targetContextMap->hContext = 0;
3391  ClientCloseSession(targetContextMap->dwClientID);
3392  targetContextMap->dwClientID = 0;
3393  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3394 
3395  listSize = list_size(&targetContextMap->channelMapList);
3396  for (list_index = 0; list_index < listSize; list_index++)
3397  {
3398  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3399  list_index);
3400  if (NULL == currentChannelMap)
3401  {
3402  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3403  list_index);
3404  continue;
3405  }
3406  else
3407  {
3408  free(currentChannelMap->readerName);
3409  free(currentChannelMap);
3410  }
3411 
3412  }
3413  list_destroy(&targetContextMap->channelMapList);
3414 
3415  lrv = list_delete(&contextMapList, targetContextMap);
3416  if (lrv < 0)
3417  {
3418  Log2(PCSC_LOG_CRITICAL,
3419  "list_delete failed with return value: %d", lrv);
3420  }
3421 
3422  free(targetContextMap);
3423 
3424  return;
3425 }
3426 
3427 /*
3428  * Functions for managing hCard values returned from SCardConnect.
3429  */
3430 
3431 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3432  LPCSTR readerName)
3433 {
3434  CHANNEL_MAP * newChannelMap;
3435  int lrv = -1;
3436 
3437  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3438  if (NULL == newChannelMap)
3439  return SCARD_E_NO_MEMORY;
3440 
3441  newChannelMap->hCard = hCard;
3442  newChannelMap->readerName = strdup(readerName);
3443 
3444  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3445  if (lrv < 0)
3446  {
3447  free(newChannelMap->readerName);
3448  free(newChannelMap);
3449  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3450  lrv);
3451  return SCARD_E_NO_MEMORY;
3452  }
3453 
3454  return SCARD_S_SUCCESS;
3455 }
3456 
3457 static void SCardRemoveHandle(SCARDHANDLE hCard)
3458 {
3459  SCONTEXTMAP * currentContextMap;
3460  CHANNEL_MAP * currentChannelMap;
3461  int lrv;
3462  LONG rv;
3463 
3464  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3465  &currentChannelMap);
3466  if (rv == -1)
3467  return;
3468 
3469  free(currentChannelMap->readerName);
3470 
3471  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3472  if (lrv < 0)
3473  {
3474  Log2(PCSC_LOG_CRITICAL,
3475  "list_delete failed with return value: %d", lrv);
3476  }
3477 
3478  free(currentChannelMap);
3479 
3480  return;
3481 }
3482 
3483 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3484  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3485 {
3486  LONG rv;
3487 
3488  if (0 == hCard)
3489  return -1;
3490 
3491  SCardLockThread();
3492  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3493  targetChannelMap);
3494 
3495  if (SCARD_S_SUCCESS == rv)
3496  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3497 
3499 
3500  return rv;
3501 }
3502 
3503 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3504  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3505 {
3506  int listSize;
3507  int list_index;
3508  SCONTEXTMAP * currentContextMap;
3509  CHANNEL_MAP * currentChannelMap;
3510 
3511  /* Best to get the caller a crash early if we fail unsafely */
3512  *targetContextMap = NULL;
3513  *targetChannelMap = NULL;
3514 
3515  listSize = list_size(&contextMapList);
3516 
3517  for (list_index = 0; list_index < listSize; list_index++)
3518  {
3519  currentContextMap = list_get_at(&contextMapList, list_index);
3520  if (currentContextMap == NULL)
3521  {
3522  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3523  list_index);
3524  continue;
3525  }
3526  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3527  &hCard);
3528  if (currentChannelMap != NULL)
3529  {
3530  *targetContextMap = currentContextMap;
3531  *targetChannelMap = currentChannelMap;
3532  return SCARD_S_SUCCESS;
3533  }
3534  }
3535 
3536  return -1;
3537 }
3538 
3547 {
3548  LONG rv;
3549  struct stat statBuffer;
3550  char *socketName;
3551 
3552  socketName = getSocketName();
3553  rv = stat(socketName, &statBuffer);
3554 
3555  if (rv != 0)
3556  {
3557  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3558  socketName, strerror(errno));
3559  return SCARD_E_NO_SERVICE;
3560  }
3561 
3562  return SCARD_S_SUCCESS;
3563 }
3564 
3565 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3566 {
3567  int32_t dwClientID = currentContextMap->dwClientID;
3568  LONG rv;
3569 
3570  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3571  if (rv != SCARD_S_SUCCESS)
3572  return rv;
3573 
3574  /* Read a message from the server */
3575  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3576  if (rv != SCARD_S_SUCCESS)
3577  return rv;
3578 
3579  return SCARD_S_SUCCESS;
3580 }
3581 
3582 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3583 {
3584  int32_t dwClientID = currentContextMap->dwClientID;
3585  LONG rv;
3586 
3587  /* Get current reader states from server and register on event list */
3589  0, NULL);
3590  if (rv != SCARD_S_SUCCESS)
3591  return rv;
3592 
3593  /* Read a message from the server */
3594  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3595  return rv;
3596 }
3597 
3598 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3599 {
3600  int32_t dwClientID = currentContextMap->dwClientID;
3601  LONG rv;
3602  struct wait_reader_state_change waitStatusStruct = {0};
3603 
3604  /* ask server to remove us from the event list */
3606  dwClientID, 0, NULL);
3607  if (rv != SCARD_S_SUCCESS)
3608  return rv;
3609 
3610  /* This message can be the response to
3611  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3612  * cancel notification.
3613  * The server side ensures, that no more messages will be sent to
3614  * the client. */
3615 
3616  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3617  dwClientID);
3618  if (rv != SCARD_S_SUCCESS)
3619  return rv;
3620 
3621  /* if we received a cancel event the return value will be set
3622  * accordingly */
3623  rv = waitStatusStruct.rv;
3624 
3625  return rv;
3626 }
3627 
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 response from the server or vice-versa.
Definition: winscard_msg.c:195
pubReaderStatesList::readerState
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:56
SCardReleaseContext
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
Definition: winscard_clnt.c:688
SCardDisconnect
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard_clnt.c:1054
pubReaderStatesList::cardProtocol
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:61
debuglog.h
This handles debugging.
version_struct::minor
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:60
SCARD_STATE_EXCLUSIVE
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:274
SCARD_PROTOCOL_ANY
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:247
SCardEstablishContextTH
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
Definition: winscard_clnt.c:561
SCardGetAttrib
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard_clnt.c:2440
establish_struct
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:122
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:111
SCardGetContextTH
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
Definition: winscard_clnt.c:3364
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
pubReaderStatesList::eventCounter
uint32_t eventCounter
number of card events
Definition: eventhandler.h:55
SCARD_STATE_PRESENT
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:272
PCSCLITE_SHARING_LAST_CONTEXT
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:75
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:318
pubReaderStatesList
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:53
SYS_USleep
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:80
SCARD_STATE_UNAVAILABLE
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:270
SCardUnlockThread
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
Definition: winscard_clnt.c:401
PROTOCOL_VERSION_MAJOR
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
SCARD_STATE_INUSE
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:275
disconnect_struct
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:176
_psContextMap::cancellable
bool cancellable
We are in a cancellable call.
Definition: winscard_clnt.c:313
SCARD_CONTROL
@ SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:88
SCardGetContextValidity
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
Definition: winscard_clnt.c:415
SYS_GetEnv
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition: sys_unix.c:168
SCARD_ABSENT
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:259
SCardCancel
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
Definition: winscard_clnt.c:3141
SCARD_IO_REQUEST::cbPciLength
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
CMD_STOP_WAITING_READER_STATE_CHANGE
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:98
isExecuted
static bool isExecuted
Make sure the initialization code is executed only once.
Definition: winscard_clnt.c:345
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:464
SCARD_STATE_UNKNOWN
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:269
SCardListReaderGroups
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
Definition: winscard_clnt.c:3051
PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:79
SCARD_CONNECT
@ SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:82
sys_generic.h
This handles abstract system level calls.
SCARD_READERSTATE
Definition: pcsclite.h:68
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:258
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:173
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:211
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:234
SCARD_CANCEL
@ SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:91
SCARDHANDLE
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
MAX_BUFFER_SIZE_EXTENDED
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:299
_psContextMap
Represents an Application Context on the Client side.
Definition: winscard_clnt.c:308
SCardLockThread
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
Definition: winscard_clnt.c:391
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:250
connect_struct
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:145
CMD_WAIT_READER_STATE_CHANGE
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:97
status_struct
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:222
getset_struct
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:265
SCARD_SWALLOWED
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:261
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
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:93
SCARD_END_TRANSACTION
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:86
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:2981
SCardBeginTransaction
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
Definition: winscard_clnt.c:1144
_psContextMap::mMutex
pthread_mutex_t mMutex
Mutex for this context.
Definition: winscard_clnt.c:311
SCARD_E_NO_READERS_AVAILABLE
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:202
SCARD_RECONNECT
@ SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:83
begin_struct
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:188
version_struct
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:58
CMD_GET_READERS_STATE
@ CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:96
SCardCheckDaemonAvailability
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
Definition: winscard_clnt.c:3546
SCARD_STATE_IGNORE
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:267
clientMutex
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
Definition: winscard_clnt.c:353
_psChannelMap
Represents an Application Context Channel.
Definition: winscard_clnt.c:277
end_struct
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:199
winscard_msg.h
This defines some structures and #defines to be used over the transport layer.
SCARD_ESTABLISH_CONTEXT
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:79
SCARD_SET_ATTRIB
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:94
INFINITE
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:280
SCardRemoveContext
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
Definition: winscard_clnt.c:3375
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:285
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:276
MessageReceive
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:455
ClientSetupSession
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:119
SCARD_IO_REQUEST::dwProtocol
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
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:355
pcsc_stringify_error
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
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:955
pubReaderStatesList::cardAtr
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:59
SCARDCONTEXT
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
pubReaderStatesList::readerSharing
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:57
SCARD_BEGIN_TRANSACTION
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:85
SCARD_STATE_ATRMATCH
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:273
SCardIsValidContext
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
Definition: winscard_clnt.c:3231
MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:298
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:138
PROTOCOL_VERSION_MINOR
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
SCARD_STATE_CHANGED
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:268
version_struct::major
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:59
reconnect_struct
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:161
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:2861
SCARD_IO_REQUEST
Protocol Control Information (PCI)
Definition: pcsclite.h:80
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
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:80
SCARD_STATE_UNAWARE
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:266
SCardAddContext
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
Definition: winscard_clnt.c:3268
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:1389
SCARD_TRANSMIT
@ SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:87
_psContextMap::dwClientID
DWORD dwClientID
Client Connection ID.
Definition: winscard_clnt.c:309
SCARD_DISCONNECT
@ SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:84
pubReaderStatesList::cardAtrLength
_Atomic uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
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:2229
SCARD_STATUS
@ SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:89
SCARD_PRESENT
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:260
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:233
SCardGetAndLockContext
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
Definition: winscard_clnt.c:3336
SCardEndTransaction
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard_clnt.c:1245
CMD_VERSION
@ CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:95
_psContextMap::hContext
SCARDCONTEXT hContext
Application Context ID.
Definition: winscard_clnt.c:310
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:1681
SCARD_STATE_EMPTY
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:271
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:358
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:800
release_struct
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:134
PCSCLITE_SHARING_NO_CONTEXT
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:77
SCardSetAttrib
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard_clnt.c:2523
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:2680