pcsc-lite  2.5.0
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-2025
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 "eventhandler.h"
125 #include "sys_generic.h"
126 #include "winscard_msg.h"
127 #include "utils.h"
128 
129 /* Display, on stderr, a trace of the WinSCard calls with arguments and
130  * results */
131 //#define DO_TRACE
132 
133 /* Profile the execution time of WinSCard calls */
134 //#define DO_PROFILE
135 
136 
137 static bool sharing_shall_block = true;
138 static int Protocol_version;
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  fprintf(stderr,
255  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
256  COLOR_BLUE "0x%08lX" COLOR_NORMAL "\n",
257  f, d, rv);
258  }
259  fprintf(profile_fd, "%s %ld\n", f, d);
260  fflush(profile_fd);
261 } /* profile_end */
262 
263 #else
264 #define PROFILE_START
265 #define PROFILE_END(rv)
266 #endif
267 
273 {
274  SCARDHANDLE hCard;
275  LPSTR readerName;
276 };
277 
278 typedef struct _psChannelMap CHANNEL_MAP;
279 
280 static int CHANNEL_MAP_seeker(const void *el, const void *key)
281 {
282  const CHANNEL_MAP * channelMap = el;
283 
284  if ((el == NULL) || (key == NULL))
285  {
286  Log3(PCSC_LOG_CRITICAL,
287  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
288  el, key);
289  return 0;
290  }
291 
292  if (channelMap->hCard == *(SCARDHANDLE *)key)
293  return 1;
294 
295  return 0;
296 }
297 
304 {
305  DWORD dwClientID;
307  pthread_mutex_t mMutex;
308  list_t channelMapList;
309  bool cancellable;
310 };
316 typedef struct _psContextMap SCONTEXTMAP;
317 
318 static list_t contextMapList;
319 pthread_mutex_t contextMapList_lock;
321 static int SCONTEXTMAP_seeker(const void *el, const void *key)
322 {
323  const SCONTEXTMAP * contextMap = el;
324 
325  if ((el == NULL) || (key == NULL))
326  {
327  Log3(PCSC_LOG_CRITICAL,
328  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
329  el, key);
330  return 0;
331  }
332 
333  if (contextMap->hContext == *(SCARDCONTEXT *) key)
334  return 1;
335 
336  return 0;
337 }
338 
342 static bool isExecuted = false;
343 static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
344 
345 
350 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
351 
356 static READER_STATE * readerStates = NULL;
357 static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
358 
359 
360 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
363 static void SCardRemoveContext(SCARDCONTEXT);
364 static void SCardCleanContext(SCONTEXTMAP *);
365 
366 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
367 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
368  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
369 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
370  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
371 static void SCardRemoveHandle(SCARDHANDLE);
372 
373 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
374  LPBYTE pbAttr, LPDWORD pcbAttrLen);
375 
376 static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents);
377 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
378 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
379 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
380 
381 /*
382  * Thread safety functions
383  */
390 inline static void SCardLockThread(void)
391 {
392  pthread_mutex_lock(&clientMutex);
393 }
394 
400 inline static void SCardUnlockThread(void)
401 {
402  pthread_mutex_unlock(&clientMutex);
403 }
404 
415 {
416  SCONTEXTMAP * currentContextMap;
417 
418  SCardLockThread();
419  currentContextMap = SCardGetContextTH(hContext);
421 
422  return currentContextMap != NULL;
423 }
424 
425 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
426  /*@out@*/ LPSCARDCONTEXT);
427 
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  (void)pthread_mutex_lock(&contextMapList_lock);
493  list_destroy(&contextMapList);
494  (void)pthread_mutex_unlock(&contextMapList_lock);
495 
496  (void)pthread_mutex_destroy(&contextMapList_lock);
497 }
498 #endif
499 
500 /*
501  * Do this only once:
502  * - Initialize context list.
503  */
504 static void init_lib(void)
505 {
506  int lrv;
507 
508  /* NOTE: The list will be freed only if DESTRUCTOR is defined.
509  * Applications which load and unload the library may leak
510  * the list's internal structures. */
511  lrv = list_init(&contextMapList);
512  if (lrv < 0)
513  {
514  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
515  lrv);
516  return;
517  }
518 
519  lrv = list_attributes_seeker(&contextMapList,
520  SCONTEXTMAP_seeker);
521  if (lrv <0)
522  {
523  Log2(PCSC_LOG_CRITICAL,
524  "list_attributes_seeker failed with return value: %d", lrv);
525  list_destroy(&contextMapList);
526  return;
527  }
528 
529  if (SYS_GetEnv("PCSCLITE_NO_BLOCKING"))
530  {
531  Log1(PCSC_LOG_INFO, "Disable shared blocking");
532  sharing_shall_block = false;
533  }
534 
535  (void)pthread_mutex_init(&contextMapList_lock, NULL);
536 
537  isExecuted = true;
538 }
539 
567 static LONG SCardEstablishContextTH(DWORD dwScope,
568  /*@unused@*/ LPCVOID pvReserved1,
569  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
570 {
571  LONG rv;
572  struct establish_struct scEstablishStruct;
573  uint32_t dwClientID = 0;
574  struct version_struct veStr;
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 
595 
596 connect_again:
597  /* exchange client/server protocol versions */
598 
599  veStr.rv = SCARD_S_SUCCESS;
600 
601  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
602  &veStr);
603  if (rv != SCARD_S_SUCCESS)
604  goto cleanup;
605 
606  /* Read a message from the server */
607  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
608  if (rv != SCARD_S_SUCCESS)
609  {
610  Log1(PCSC_LOG_CRITICAL,
611  "Your pcscd is too old and does not support CMD_VERSION");
612  goto cleanup;
613  }
614 
615  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
616  veStr.major, veStr.minor);
617  Log3(PCSC_LOG_INFO, "Client is protocol version %d:%d",
619 
620  if (SCARD_E_SERVICE_STOPPED == veStr.rv)
621  {
622  /* server complained about our protocol version? */
623  if (PROTOCOL_VERSION_MAJOR == veStr.major)
624  {
626  {
627  /* try again with the protocol version proposed by
628  * the server */
629  Log1(PCSC_LOG_INFO, "Using backward compatibility");
630  goto connect_again;
631  }
632  }
633  }
634 
635  if (veStr.rv != SCARD_S_SUCCESS)
636  {
637  rv = veStr.rv;
638  goto cleanup;
639  }
640 
641  /* store protocol version of the server */
642  Protocol_version = veStr.major * 1000 + veStr.minor;
643 
644 again:
645  /*
646  * Try to establish an Application Context with the server
647  */
648  scEstablishStruct.dwScope = dwScope;
649  scEstablishStruct.hContext = 0;
650  scEstablishStruct.rv = SCARD_S_SUCCESS;
651 
653  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
654 
655  if (rv != SCARD_S_SUCCESS)
656  goto cleanup;
657 
658  /*
659  * Read the response from the server
660  */
661  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
662  dwClientID);
663 
664  if (rv != SCARD_S_SUCCESS)
665  goto cleanup;
666 
667  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
668  {
669  rv = scEstablishStruct.rv;
670  goto cleanup;
671  }
672 
673  /* check we do not reuse an existing hContext */
674  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
675  /* we do not need to release the allocated context since
676  * SCardReleaseContext() does nothing on the server side */
677  goto again;
678 
679  *phContext = scEstablishStruct.hContext;
680 
681  /*
682  * Allocate the new hContext - if allocator full return an error
683  */
684  rv = SCardAddContext(*phContext, dwClientID);
685 
686  return rv;
687 
688 cleanup:
689  ClientCloseSession(dwClientID);
690 
691  return rv;
692 }
693 
716 {
717  LONG rv;
718  struct release_struct scReleaseStruct;
719  SCONTEXTMAP * currentContextMap;
720 
721  API_TRACE_IN("%ld", hContext)
722  PROFILE_START
723 
724  /*
725  * Make sure this context has been opened
726  * and get currentContextMap
727  */
728  currentContextMap = SCardGetAndLockContext(hContext);
729  if (NULL == currentContextMap)
730  {
732  goto error;
733  }
734 
735  scReleaseStruct.hContext = hContext;
736  scReleaseStruct.rv = SCARD_S_SUCCESS;
737 
739  currentContextMap->dwClientID,
740  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
741 
742  if (rv != SCARD_S_SUCCESS)
743  goto end;
744 
745  /*
746  * Read a message from the server
747  */
748  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
749  currentContextMap->dwClientID);
750 
751  if (rv != SCARD_S_SUCCESS)
752  goto end;
753 
754  rv = scReleaseStruct.rv;
755 end:
756  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
757 
758  /*
759  * Remove the local context from the stack
760  */
761  SCardLockThread();
762  SCardRemoveContext(hContext);
764 
765 error:
766  PROFILE_END(rv)
767  API_TRACE_OUT("")
768 
769  return rv;
770 }
771 
827 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
828  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
829  LPDWORD pdwActiveProtocol)
830 {
831  LONG rv;
832  struct connect_struct scConnectStruct;
833  SCONTEXTMAP * currentContextMap;
834 
835  PROFILE_START
836  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
837 
838  /*
839  * Check for NULL parameters
840  */
841  if (phCard == NULL || pdwActiveProtocol == NULL)
843  else
844  *phCard = 0;
845 
846  if (szReader == NULL)
847  return SCARD_E_UNKNOWN_READER;
848 
849  /*
850  * Check for uninitialized strings
851  */
852  if (strlen(szReader) > MAX_READERNAME)
853  return SCARD_E_INVALID_VALUE;
854 
855  /*
856  * Make sure this context has been opened
857  */
858  currentContextMap = SCardGetAndLockContext(hContext);
859  if (NULL == currentContextMap)
860  return SCARD_E_INVALID_HANDLE;
861 
862  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
863  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
864  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
865 
866  scConnectStruct.hContext = hContext;
867  scConnectStruct.dwShareMode = dwShareMode;
868  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
869  scConnectStruct.hCard = 0;
870  scConnectStruct.dwActiveProtocol = 0;
871  scConnectStruct.rv = SCARD_S_SUCCESS;
872 
873  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
874  sizeof(scConnectStruct), (void *) &scConnectStruct);
875 
876  if (rv != SCARD_S_SUCCESS)
877  goto end;
878 
879  /*
880  * Read a message from the server
881  */
882  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
883  currentContextMap->dwClientID);
884 
885  if (rv != SCARD_S_SUCCESS)
886  goto end;
887 
888  *phCard = scConnectStruct.hCard;
889  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
890 
891  if (scConnectStruct.rv == SCARD_S_SUCCESS)
892  {
893  /*
894  * Keep track of the handle locally
895  */
896  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
897  }
898  else
899  rv = scConnectStruct.rv;
900 
901 end:
902  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
903 
904  PROFILE_END(rv)
905  API_TRACE_OUT("%d", *pdwActiveProtocol)
906 
907  return rv;
908 }
909 
982 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
983  DWORD dwPreferredProtocols, DWORD dwInitialization,
984  LPDWORD pdwActiveProtocol)
985 {
986  LONG rv;
987  struct reconnect_struct scReconnectStruct;
988  SCONTEXTMAP * currentContextMap;
989  CHANNEL_MAP * pChannelMap;
990 
991  PROFILE_START
992  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
993 
994  if (pdwActiveProtocol == NULL)
996 
997  /* Retry loop for blocking behaviour */
998 retry:
999 
1000  /*
1001  * Make sure this handle has been opened
1002  */
1003  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1004  &pChannelMap);
1005  if (rv == -1)
1006  return SCARD_E_INVALID_HANDLE;
1007 
1008  scReconnectStruct.hCard = hCard;
1009  scReconnectStruct.dwShareMode = dwShareMode;
1010  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
1011  scReconnectStruct.dwInitialization = dwInitialization;
1012  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
1013  scReconnectStruct.rv = SCARD_S_SUCCESS;
1014 
1015  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
1016  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
1017 
1018  if (rv != SCARD_S_SUCCESS)
1019  goto end;
1020 
1021  /*
1022  * Read a message from the server
1023  */
1024  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1025  currentContextMap->dwClientID);
1026 
1027  if (rv != SCARD_S_SUCCESS)
1028  goto end;
1029 
1030  rv = scReconnectStruct.rv;
1031 
1032  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1033  {
1034  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1035  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1036  goto retry;
1037  }
1038 
1039  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1040 
1041 end:
1042  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1043 
1044  PROFILE_END(rv)
1045  API_TRACE_OUT("%ld", *pdwActiveProtocol)
1046 
1047  return rv;
1048 }
1049 
1081 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1082 {
1083  LONG rv;
1084  struct disconnect_struct scDisconnectStruct;
1085  SCONTEXTMAP * currentContextMap;
1086  CHANNEL_MAP * pChannelMap;
1087 
1088  PROFILE_START
1089  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1090 
1091  /*
1092  * Make sure this handle has been opened
1093  */
1094  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1095  &pChannelMap);
1096  if (rv == -1)
1097  {
1099  goto error;
1100  }
1101 
1102  scDisconnectStruct.hCard = hCard;
1103  scDisconnectStruct.dwDisposition = dwDisposition;
1104  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1105 
1106  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1107  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1108 
1109  if (rv != SCARD_S_SUCCESS)
1110  goto end;
1111 
1112  /*
1113  * Read a message from the server
1114  */
1115  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1116  currentContextMap->dwClientID);
1117 
1118  if (rv != SCARD_S_SUCCESS)
1119  goto end;
1120 
1121  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1122  SCardRemoveHandle(hCard);
1123  rv = scDisconnectStruct.rv;
1124 
1125 end:
1126  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1127 
1128 error:
1129  PROFILE_END(rv)
1130  API_TRACE_OUT("")
1131 
1132  return rv;
1133 }
1134 
1172 {
1173 
1174  LONG rv;
1175  struct begin_struct scBeginStruct;
1176  SCONTEXTMAP * currentContextMap;
1177  CHANNEL_MAP * pChannelMap;
1178 
1179  PROFILE_START
1180  API_TRACE_IN("%ld", hCard)
1181 
1182  /*
1183  * Query the server every so often until the sharing violation ends
1184  * and then hold the lock for yourself.
1185  */
1186 
1187  for(;;)
1188  {
1189  /*
1190  * Make sure this handle has been opened
1191  */
1192  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1193  &pChannelMap);
1194  if (rv == -1)
1195  return SCARD_E_INVALID_HANDLE;
1196 
1197  scBeginStruct.hCard = hCard;
1198  scBeginStruct.rv = SCARD_S_SUCCESS;
1199 
1201  currentContextMap->dwClientID,
1202  sizeof(scBeginStruct), (void *) &scBeginStruct);
1203 
1204  if (rv != SCARD_S_SUCCESS)
1205  break;
1206 
1207  /*
1208  * Read a message from the server
1209  */
1210  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1211  currentContextMap->dwClientID);
1212 
1213  if (rv != SCARD_S_SUCCESS)
1214  break;
1215 
1216  rv = scBeginStruct.rv;
1217 
1218  if (SCARD_E_SHARING_VIOLATION != rv)
1219  break;
1220 
1221  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1222  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1223  }
1224 
1225  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1226 
1227  PROFILE_END(rv)
1228  API_TRACE_OUT("")
1229 
1230  return rv;
1231 }
1232 
1272 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1273 {
1274  LONG rv;
1275  struct end_struct scEndStruct;
1276  SCONTEXTMAP * currentContextMap;
1277  CHANNEL_MAP * pChannelMap;
1278 
1279  PROFILE_START
1280  API_TRACE_IN("%ld", hCard)
1281 
1282  /*
1283  * Make sure this handle has been opened
1284  */
1285  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1286  &pChannelMap);
1287  if (rv == -1)
1288  return SCARD_E_INVALID_HANDLE;
1289 
1290  scEndStruct.hCard = hCard;
1291  scEndStruct.dwDisposition = dwDisposition;
1292  scEndStruct.rv = SCARD_S_SUCCESS;
1293 
1295  currentContextMap->dwClientID,
1296  sizeof(scEndStruct), (void *) &scEndStruct);
1297 
1298  if (rv != SCARD_S_SUCCESS)
1299  goto end;
1300 
1301  /*
1302  * Read a message from the server
1303  */
1304  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1305  currentContextMap->dwClientID);
1306 
1307  if (rv != SCARD_S_SUCCESS)
1308  goto end;
1309 
1310  rv = scEndStruct.rv;
1311 
1312 end:
1313  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1314 
1315  PROFILE_END(rv)
1316  API_TRACE_OUT("")
1317 
1318  return rv;
1319 }
1320 
1416 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1417  LPDWORD pcchReaderLen, LPDWORD pdwState,
1418  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1419 {
1420  DWORD dwReaderLen, dwAtrLen;
1421  LONG rv;
1422  int i;
1423  struct status_struct scStatusStruct;
1424  SCONTEXTMAP * currentContextMap;
1425  CHANNEL_MAP * pChannelMap;
1426  char *r;
1427  char *bufReader = NULL;
1428  LPBYTE bufAtr = NULL;
1429  DWORD dummy = 0;
1430 
1431  PROFILE_START
1432 
1433  /* default output values */
1434  if (pdwState)
1435  *pdwState = 0;
1436 
1437  if (pdwProtocol)
1438  *pdwProtocol = 0;
1439 
1440  /* Check for NULL parameters */
1441  if (pcchReaderLen == NULL)
1442  pcchReaderLen = &dummy;
1443 
1444  if (pcbAtrLen == NULL)
1445  pcbAtrLen = &dummy;
1446 
1447  /* length passed from caller */
1448  dwReaderLen = *pcchReaderLen;
1449  dwAtrLen = *pcbAtrLen;
1450 
1451  *pcchReaderLen = 0;
1452  *pcbAtrLen = 0;
1453 
1454  /* Retry loop for blocking behaviour */
1455 retry:
1456 
1457  /*
1458  * Make sure this handle has been opened
1459  */
1460  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1461  &pChannelMap);
1462  if (rv == -1)
1463  return SCARD_E_INVALID_HANDLE;
1464 
1465  /* lock access to readerStates[] */
1466  (void)pthread_mutex_lock(&readerStatesMutex);
1467 
1468  /* synchronize reader states with daemon */
1469  rv = getReaderStates(currentContextMap);
1470  if (rv != SCARD_S_SUCCESS)
1471  goto end;
1472 
1473  r = pChannelMap->readerName;
1474  for (i = 0; i < pcsclite_max_reader_context; i++)
1475  {
1476  /* by default r == NULL */
1477  if (r && strcmp(r, readerStates[i].readerName) == 0)
1478  break;
1479  }
1480 
1481  if (i == pcsclite_max_reader_context)
1482  {
1484  goto end;
1485  }
1486 
1487  /* initialise the structure */
1488  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1489  scStatusStruct.hCard = hCard;
1490 
1491  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1492  sizeof(scStatusStruct), (void *) &scStatusStruct);
1493 
1494  if (rv != SCARD_S_SUCCESS)
1495  goto end;
1496 
1497  /*
1498  * Read a message from the server
1499  */
1500  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1501  currentContextMap->dwClientID);
1502 
1503  if (rv != SCARD_S_SUCCESS)
1504  goto end;
1505 
1506  rv = scStatusStruct.rv;
1507 
1508  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1509  {
1510  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1511  (void)pthread_mutex_unlock(&readerStatesMutex);
1512  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
1513  goto retry;
1514  }
1515 
1516  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1517  {
1518  /*
1519  * An event must have occurred
1520  */
1521  goto end;
1522  }
1523 
1524  /*
1525  * Now continue with the client side SCardStatus
1526  */
1527 
1528  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1529  *pcbAtrLen = readerStates[i].cardAtrLength;
1530 
1531  if (pdwState)
1532  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1533 
1534  if (pdwProtocol)
1535  *pdwProtocol = readerStates[i].cardProtocol;
1536 
1537  if (SCARD_AUTOALLOCATE == dwReaderLen)
1538  {
1539  dwReaderLen = *pcchReaderLen;
1540  if (NULL == szReaderName)
1541  {
1543  goto end;
1544  }
1545  bufReader = malloc(dwReaderLen);
1546  if (NULL == bufReader)
1547  {
1548  rv = SCARD_E_NO_MEMORY;
1549  goto end;
1550  }
1551  *(char **)szReaderName = bufReader;
1552  }
1553  else
1554  bufReader = szReaderName;
1555 
1556  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1557  if (bufReader)
1558  {
1559  if (*pcchReaderLen > dwReaderLen)
1561 
1562  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1563  }
1564 
1565  if (SCARD_AUTOALLOCATE == dwAtrLen)
1566  {
1567  dwAtrLen = *pcbAtrLen;
1568  if (NULL == pbAtr)
1569  {
1571  goto end;
1572  }
1573  bufAtr = malloc(dwAtrLen);
1574  if (NULL == bufAtr)
1575  {
1576  rv = SCARD_E_NO_MEMORY;
1577  goto end;
1578  }
1579  *(LPBYTE *)pbAtr = bufAtr;
1580  }
1581  else
1582  bufAtr = pbAtr;
1583 
1584  if (bufAtr)
1585  {
1586  if (*pcbAtrLen > dwAtrLen)
1588 
1589  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1590  }
1591 
1592 end:
1593  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1594  (void)pthread_mutex_unlock(&readerStatesMutex);
1595 
1596  PROFILE_END(rv)
1597 
1598  return rv;
1599 }
1600 
1712 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1713  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1714 {
1715  SCARD_READERSTATE *currReader;
1716  READER_STATE *rContext;
1717  long dwTime;
1718  DWORD dwBreakFlag = 0;
1719  unsigned int j;
1720  SCONTEXTMAP * currentContextMap;
1721  int currentReaderCount = 0;
1722  LONG rv = SCARD_S_SUCCESS;
1723  int pnp_reader = -1;
1724 
1725  PROFILE_START
1726  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1727 #ifdef DO_TRACE
1728  for (j=0; j<cReaders; j++)
1729  {
1730  API_TRACE_IN("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1731  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1732  rgReaderStates[j].cbAtr)
1733  }
1734 #endif
1735 
1736  if (rgReaderStates == NULL && cReaders > 0)
1737  {
1739  goto error;
1740  }
1741 
1742  /* Check the integrity of the reader states structures */
1743  for (j = 0; j < cReaders; j++)
1744  {
1745  if (rgReaderStates[j].szReader == NULL)
1746  return SCARD_E_INVALID_VALUE;
1747  }
1748 
1749  /* return if all readers are SCARD_STATE_IGNORE */
1750  if (cReaders > 0)
1751  {
1752  int nbNonIgnoredReaders = cReaders;
1753 
1754  for (j=0; j<cReaders; j++)
1755  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1756  nbNonIgnoredReaders--;
1757 
1758  if (0 == nbNonIgnoredReaders)
1759  {
1760  rv = SCARD_S_SUCCESS;
1761  goto error;
1762  }
1763  }
1764  else
1765  {
1766  /* reader list is empty */
1767  rv = SCARD_S_SUCCESS;
1768  goto error;
1769  }
1770 
1771  /*
1772  * Make sure this context has been opened
1773  */
1774  currentContextMap = SCardGetAndLockContext(hContext);
1775  if (NULL == currentContextMap)
1776  {
1778  goto error;
1779  }
1780 
1781  /* lock access to readerStates[] */
1782  (void)pthread_mutex_lock(&readerStatesMutex);
1783 
1784  /* synchronize reader states with daemon */
1785  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1786 
1787  if (rv != SCARD_S_SUCCESS)
1788  {
1789  (void)pthread_mutex_unlock(&readerStatesMutex);
1790  goto end;
1791  }
1792 
1793  /* check all the readers are already known */
1794  for (j=0; j<cReaders; j++)
1795  {
1796  const char *readerName;
1797  int i;
1798 
1799  readerName = rgReaderStates[j].szReader;
1800  for (i = 0; i < pcsclite_max_reader_context; i++)
1801  {
1802  if (strcmp(readerName, readerStates[i].readerName) == 0)
1803  break;
1804  }
1805 
1806  /* The requested reader name is not recognized */
1807  if (i == pcsclite_max_reader_context)
1808  {
1809  /* PnP special reader? */
1810  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1811  {
1813  (void)pthread_mutex_unlock(&readerStatesMutex);
1814  goto end;
1815  }
1816  else
1817  pnp_reader = j;
1818  }
1819  }
1820  (void)pthread_mutex_unlock(&readerStatesMutex);
1821 
1822  /* Clear the event state for all readers */
1823  for (j = 0; j < cReaders; j++)
1824  rgReaderStates[j].dwEventState = 0;
1825 
1826  /* Now is where we start our event checking loop */
1827  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1828 
1829  /* index of the PnP readerin rgReaderStates[] */
1830  if (pnp_reader >= 0)
1831  {
1832  int readerEvents;
1833  currReader = &rgReaderStates[pnp_reader];
1834 
1835  /* PnP special reader */
1836  if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1837  {
1838  int previousReaderEvents = currReader->dwCurrentState >> 16;
1839 
1840  // store readerEvents in .dwEventState high word
1841  currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1842  if (
1843  /* the value has changed since the last call */
1844  (previousReaderEvents != readerEvents)
1845  /* backward compatibility: only if we had a non-null
1846  * reader events value */
1847  && previousReaderEvents)
1848  {
1849  currReader->dwEventState |= SCARD_STATE_CHANGED;
1850  rv = SCARD_S_SUCCESS;
1851  dwBreakFlag = 1;
1852  }
1853  }
1854  }
1855 
1856  /* Get the initial reader count on the system */
1857  for (int k=0; k < pcsclite_max_reader_context; k++)
1858  if (readerStates[k].readerName[0] != '\0')
1859  currentReaderCount++;
1860 
1861  /* catch possible sign extension problems from 32 to 64-bits integers */
1862  if ((DWORD)-1 == dwTimeout)
1863  dwTimeout = INFINITE;
1864  if (INFINITE == dwTimeout)
1865  dwTime = 60*1000; /* "infinite" timeout */
1866  else
1867  dwTime = dwTimeout;
1868 
1869  j = 0;
1870  do
1871  {
1872  currReader = &rgReaderStates[j];
1873 
1874  /* Ignore for IGNORED readers */
1875  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1876  {
1877  const char *readerName;
1878  int i;
1879 
1880  /* lock access to readerStates[] */
1881  (void)pthread_mutex_lock(&readerStatesMutex);
1882 
1883  /* Looks for correct readernames */
1884  readerName = currReader->szReader;
1885  for (i = 0; i < pcsclite_max_reader_context; i++)
1886  {
1887  if (strcmp(readerName, readerStates[i].readerName) == 0)
1888  break;
1889  }
1890 
1891  /* The requested reader name is not recognized */
1892  if (i == pcsclite_max_reader_context)
1893  {
1894  /* PnP special reader? */
1895  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1896  {
1897  int k, newReaderCount = 0;
1898 
1899  for (k=0; k < pcsclite_max_reader_context; k++)
1900  if (readerStates[k].readerName[0] != '\0')
1901  newReaderCount++;
1902 
1903  if (newReaderCount != currentReaderCount)
1904  {
1905  int readerEvents;
1906 
1907  Log1(PCSC_LOG_INFO, "Reader list changed");
1908  currentReaderCount = newReaderCount;
1909 
1910  if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1911  {
1912  // store readerEvents in .dwEventState high word
1913  currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1914  }
1915 
1916  currReader->dwEventState |= SCARD_STATE_CHANGED;
1917  dwBreakFlag = 1;
1918  }
1919  }
1920  else
1921  {
1922  currReader->dwEventState =
1924  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1925  {
1926  currReader->dwEventState |= SCARD_STATE_CHANGED;
1927  /*
1928  * Spec says use SCARD_STATE_IGNORE but a removed USB
1929  * reader with eventState fed into currentState will
1930  * be ignored forever
1931  */
1932  dwBreakFlag = 1;
1933  }
1934  }
1935  }
1936  else
1937  {
1938  uint32_t readerState;
1939 
1940  /* The reader has come back after being away */
1941  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1942  {
1943  currReader->dwEventState |= SCARD_STATE_CHANGED;
1944  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1945  Log0(PCSC_LOG_DEBUG);
1946  dwBreakFlag = 1;
1947  }
1948 
1949  /* Set the reader status structure */
1950  rContext = &readerStates[i];
1951 
1952  /* Now we check all the Reader States */
1953  readerState = rContext->readerState;
1954 
1955  /* only if current state has an non null event counter */
1956  if (currReader->dwCurrentState & 0xFFFF0000)
1957  {
1958  unsigned int currentCounter;
1959 
1960  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1961 
1962  /* has the event counter changed since the last call? */
1963  if (rContext->eventCounter != currentCounter)
1964  {
1965  currReader->dwEventState |= SCARD_STATE_CHANGED;
1966  Log0(PCSC_LOG_DEBUG);
1967  dwBreakFlag = 1;
1968  }
1969  }
1970 
1971  /* add an event counter in the upper word of dwEventState */
1972  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1973  | (rContext->eventCounter << 16));
1974 
1975  /* Check if the reader is in the correct state */
1976  if (readerState & SCARD_UNKNOWN)
1977  {
1978  /* reader is in bad state */
1979  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1980  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1981  {
1982  /* App thinks reader is in good state and it is not */
1983  currReader->dwEventState |= SCARD_STATE_CHANGED;
1984  Log0(PCSC_LOG_DEBUG);
1985  dwBreakFlag = 1;
1986  }
1987  }
1988  else
1989  {
1990  /* App thinks reader in bad state but it is not */
1991  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1992  {
1993  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1994  currReader->dwEventState |= SCARD_STATE_CHANGED;
1995  Log0(PCSC_LOG_DEBUG);
1996  dwBreakFlag = 1;
1997  }
1998  }
1999 
2000  /* Check for card presence in the reader */
2001  if (readerState & SCARD_PRESENT)
2002  {
2003 #ifndef DISABLE_AUTO_POWER_ON
2004  /* card present but not yet powered up */
2005  if (0 == rContext->cardAtrLength)
2006  /* Allow the status thread to convey information */
2007  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2008 #endif
2009 
2010  currReader->cbAtr = rContext->cardAtrLength;
2011  memcpy(currReader->rgbAtr, rContext->cardAtr,
2012  currReader->cbAtr);
2013  }
2014  else
2015  currReader->cbAtr = 0;
2016 
2017  /* Card is now absent */
2018  if (readerState & SCARD_ABSENT)
2019  {
2020  currReader->dwEventState |= SCARD_STATE_EMPTY;
2021  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
2022  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2023  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2024  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2025  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2026  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
2027  currReader->dwEventState &= ~SCARD_STATE_MUTE;
2028  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2029 
2030  /* After present the rest are assumed */
2031  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2032  {
2033  currReader->dwEventState |= SCARD_STATE_CHANGED;
2034  Log0(PCSC_LOG_DEBUG);
2035  dwBreakFlag = 1;
2036  }
2037  }
2038  /* Card is now present */
2039  else if (readerState & SCARD_PRESENT)
2040  {
2041  currReader->dwEventState |= SCARD_STATE_PRESENT;
2042  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2043  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2044  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2045  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2046  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2047  currReader->dwEventState &= ~SCARD_STATE_MUTE;
2048 
2049  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2050  {
2051  currReader->dwEventState |= SCARD_STATE_CHANGED;
2052  Log0(PCSC_LOG_DEBUG);
2053  dwBreakFlag = 1;
2054  }
2055 
2056  if (readerState & SCARD_SWALLOWED)
2057  {
2058  currReader->dwEventState |= SCARD_STATE_MUTE;
2059  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2060  {
2061  currReader->dwEventState |= SCARD_STATE_CHANGED;
2062  Log0(PCSC_LOG_DEBUG);
2063  dwBreakFlag = 1;
2064  }
2065  }
2066  else
2067  {
2068  /* App thinks card is mute but it is not */
2069  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2070  {
2071  currReader->dwEventState |= SCARD_STATE_CHANGED;
2072  Log0(PCSC_LOG_DEBUG);
2073  dwBreakFlag = 1;
2074  }
2075  }
2076  }
2077 
2078  /* Now figure out sharing modes */
2080  {
2081  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2082  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2083  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2084  {
2085  currReader->dwEventState |= SCARD_STATE_CHANGED;
2086  Log0(PCSC_LOG_DEBUG);
2087  dwBreakFlag = 1;
2088  }
2089  }
2090  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2091  {
2092  /* A card must be inserted for it to be INUSE */
2093  if (readerState & SCARD_PRESENT)
2094  {
2095  currReader->dwEventState |= SCARD_STATE_INUSE;
2096  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2097  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2098  {
2099  currReader->dwEventState |= SCARD_STATE_CHANGED;
2100  Log0(PCSC_LOG_DEBUG);
2101  dwBreakFlag = 1;
2102  }
2103  }
2104  }
2105  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2106  {
2107  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2108  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2109 
2110  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2111  {
2112  currReader->dwEventState |= SCARD_STATE_CHANGED;
2113  Log0(PCSC_LOG_DEBUG);
2114  dwBreakFlag = 1;
2115  }
2116  else if (currReader-> dwCurrentState
2118  {
2119  currReader->dwEventState |= SCARD_STATE_CHANGED;
2120  Log0(PCSC_LOG_DEBUG);
2121  dwBreakFlag = 1;
2122  }
2123  }
2124 
2125  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2126  {
2127  /*
2128  * Break out of the while .. loop and return status
2129  * once all the status's for all readers is met
2130  */
2131  currReader->dwEventState |= SCARD_STATE_CHANGED;
2132  Log0(PCSC_LOG_DEBUG);
2133  dwBreakFlag = 1;
2134  }
2135  } /* End of SCARD_STATE_UNKNOWN */
2136 
2137  (void)pthread_mutex_unlock(&readerStatesMutex);
2138  } /* End of SCARD_STATE_IGNORE */
2139 
2140  /* Counter and resetter */
2141  j++;
2142  if (j == cReaders)
2143  {
2144  /* go back to the first reader */
2145  j = 0;
2146 
2147  /* Declare all the break conditions */
2148 
2149  /* Break if UNAWARE is set and all readers have been checked */
2150  if (dwBreakFlag == 1)
2151  break;
2152 
2153  /* Only sleep once for each cycle of reader checks. */
2154  {
2155  struct wait_reader_state_change waitStatusStruct = {0};
2156  struct timeval before, after;
2157 
2158  gettimeofday(&before, NULL);
2159 
2160  waitStatusStruct.rv = SCARD_S_SUCCESS;
2161 
2162  /* another thread can do SCardCancel() */
2163  currentContextMap->cancellable = true;
2164 
2165  /*
2166  * Read a message from the server
2167  */
2169  &waitStatusStruct, sizeof(waitStatusStruct),
2170  currentContextMap->dwClientID, dwTime);
2171 
2172  /* SCardCancel() will return immediately with success
2173  * because something changed on the daemon side. */
2174  currentContextMap->cancellable = false;
2175 
2176  /* timeout */
2177  if (SCARD_E_TIMEOUT == rv)
2178  {
2179  /* ask server to remove us from the event list */
2180  rv = unregisterFromEvents(currentContextMap);
2181  }
2182 
2183  if (rv != SCARD_S_SUCCESS)
2184  goto end;
2185 
2186  /* an event occurs or SCardCancel() was called */
2187  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2188  {
2189  rv = waitStatusStruct.rv;
2190  goto end;
2191  }
2192 
2193  /* synchronize reader states with daemon */
2194  (void)pthread_mutex_lock(&readerStatesMutex);
2195  rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2196  (void)pthread_mutex_unlock(&readerStatesMutex);
2197  if (rv != SCARD_S_SUCCESS)
2198  goto end;
2199 
2200  if (INFINITE != dwTimeout)
2201  {
2202  long int diff;
2203 
2204  gettimeofday(&after, NULL);
2205  diff = time_sub(&after, &before);
2206  dwTime -= diff/1000;
2207  }
2208  }
2209 
2210  if (dwTimeout != INFINITE)
2211  {
2212  /* If time is greater than timeout and all readers have been
2213  * checked
2214  */
2215  if (dwTime <= 0)
2216  {
2217  rv = SCARD_E_TIMEOUT;
2218  goto end;
2219  }
2220  }
2221  }
2222  }
2223  while (1);
2224 
2225 end:
2226  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2227 
2228  /* if SCardCancel() has been used then the client is already
2229  * unregistered */
2230  if (SCARD_E_CANCELLED != rv)
2231  (void)unregisterFromEvents(currentContextMap);
2232 
2233  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2234 
2235 error:
2236  PROFILE_END(rv)
2237 #ifdef DO_TRACE
2238  for (j=0; j<cReaders; j++)
2239  {
2240  API_TRACE_OUT("[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2241  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2242  rgReaderStates[j].cbAtr)
2243  }
2244 #endif
2245 
2246  return rv;
2247 }
2248 
2299 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2300  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2301  LPDWORD lpBytesReturned)
2302 {
2303  LONG rv;
2304  struct control_struct scControlStruct;
2305  SCONTEXTMAP * currentContextMap;
2306  CHANNEL_MAP * pChannelMap;
2307 
2308  PROFILE_START
2309 
2310  /* 0 bytes received by default */
2311  if (NULL != lpBytesReturned)
2312  *lpBytesReturned = 0;
2313 
2314  /*
2315  * Make sure this handle has been opened
2316  */
2317  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2318  &pChannelMap);
2319  if (rv == -1)
2320  {
2321  PROFILE_END(SCARD_E_INVALID_HANDLE)
2322  return SCARD_E_INVALID_HANDLE;
2323  }
2324 
2325  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2326  {
2328  goto end;
2329  }
2330 
2331  scControlStruct.hCard = hCard;
2332  scControlStruct.dwControlCode = dwControlCode;
2333  scControlStruct.cbSendLength = cbSendLength;
2334  scControlStruct.cbRecvLength = cbRecvLength;
2335  scControlStruct.dwBytesReturned = 0;
2336  scControlStruct.rv = 0;
2337 
2338  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2339  sizeof(scControlStruct), &scControlStruct);
2340 
2341  if (rv != SCARD_S_SUCCESS)
2342  goto end;
2343 
2344  /* write the sent buffer */
2345  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2346  currentContextMap->dwClientID);
2347 
2348  if (rv != SCARD_S_SUCCESS)
2349  goto end;
2350 
2351  /*
2352  * Read a message from the server
2353  */
2354  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2355  currentContextMap->dwClientID);
2356 
2357  if (rv != SCARD_S_SUCCESS)
2358  goto end;
2359 
2360  if (SCARD_S_SUCCESS == scControlStruct.rv)
2361  {
2362  if (scControlStruct.dwBytesReturned > cbRecvLength)
2363  {
2364  if (NULL != lpBytesReturned)
2365  *lpBytesReturned = scControlStruct.dwBytesReturned;
2367  goto end;
2368  }
2369 
2370  /* read the received buffer */
2371  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2372  currentContextMap->dwClientID);
2373 
2374  if (rv != SCARD_S_SUCCESS)
2375  goto end;
2376 
2377  }
2378 
2379  if (NULL != lpBytesReturned)
2380  *lpBytesReturned = scControlStruct.dwBytesReturned;
2381 
2382  rv = scControlStruct.rv;
2383 
2384 end:
2385  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2386 
2387  PROFILE_END(rv)
2388 
2389  return rv;
2390 }
2391 
2510 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2511  LPDWORD pcbAttrLen)
2512 {
2513  LONG ret;
2514  unsigned char *buf = NULL;
2515 
2516  PROFILE_START
2517 
2518  if (NULL == pcbAttrLen)
2519  {
2521  goto end;
2522  }
2523 
2524  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2525  {
2526  if (NULL == pbAttr)
2528 
2529  *pcbAttrLen = MAX_BUFFER_SIZE;
2530  buf = malloc(*pcbAttrLen);
2531  if (NULL == buf)
2532  {
2533  ret = SCARD_E_NO_MEMORY;
2534  goto end;
2535  }
2536 
2537  *(unsigned char **)pbAttr = buf;
2538  }
2539  else
2540  {
2541  buf = pbAttr;
2542 
2543  /* if only get the length */
2544  if (NULL == pbAttr)
2545  /* use a reasonable size */
2546  *pcbAttrLen = MAX_BUFFER_SIZE;
2547  }
2548 
2549  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2550  pcbAttrLen);
2551 
2552 end:
2553  PROFILE_END(ret)
2554 
2555  return ret;
2556 }
2557 
2593 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2594  DWORD cbAttrLen)
2595 {
2596  LONG ret;
2597 
2598  PROFILE_START
2599 
2600  if (NULL == pbAttr || 0 == cbAttrLen)
2602 
2603  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2604  &cbAttrLen);
2605 
2606  PROFILE_END(ret)
2607 
2608  return ret;
2609 }
2610 
2611 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2612  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2613 {
2614  LONG rv;
2615  struct getset_struct scGetSetStruct;
2616  SCONTEXTMAP * currentContextMap;
2617  CHANNEL_MAP * pChannelMap;
2618 
2619  /*
2620  * Make sure this handle has been opened
2621  */
2622  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2623  &pChannelMap);
2624  if (rv == -1)
2625  return SCARD_E_INVALID_HANDLE;
2626 
2627  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2628  {
2630  goto end;
2631  }
2632 
2633  scGetSetStruct.hCard = hCard;
2634  scGetSetStruct.dwAttrId = dwAttrId;
2635  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2636  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2637  if (SCARD_SET_ATTRIB == command)
2638  {
2639  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2640  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2641  }
2642  else
2643  /* we can get up to the communication buffer size */
2644  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2645 
2646  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2647  sizeof(scGetSetStruct), &scGetSetStruct);
2648 
2649  if (rv != SCARD_S_SUCCESS)
2650  goto end;
2651 
2652  /*
2653  * Read a message from the server
2654  */
2655  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2656  currentContextMap->dwClientID);
2657 
2658  if (rv != SCARD_S_SUCCESS)
2659  goto end;
2660 
2661  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2662  {
2663  /*
2664  * Copy and zero it so any secret information is not leaked
2665  */
2666  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2667  {
2668  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2669  * buffer overflow in the memcpy() below */
2670  DWORD correct_value = scGetSetStruct.cbAttrLen;
2671  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2672  *pcbAttrLen = correct_value;
2673 
2674  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2675  }
2676  else
2677  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2678 
2679  if (pbAttr)
2680  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2681 
2682  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2683  }
2684  rv = scGetSetStruct.rv;
2685 
2686 end:
2687  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2688 
2689  return rv;
2690 }
2691 
2750 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2751  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2752  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2753  LPDWORD pcbRecvLength)
2754 {
2755  LONG rv;
2756  SCONTEXTMAP * currentContextMap;
2757  CHANNEL_MAP * pChannelMap;
2758  struct transmit_struct scTransmitStruct;
2759 
2760  PROFILE_START
2761 
2762  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2763  pcbRecvLength == NULL || pioSendPci == NULL)
2765 
2766  /* Retry loop for blocking behaviour */
2767 retry:
2768 
2769  /*
2770  * Make sure this handle has been opened
2771  */
2772  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2773  &pChannelMap);
2774  if (rv == -1)
2775  {
2776  *pcbRecvLength = 0;
2777  PROFILE_END(SCARD_E_INVALID_HANDLE)
2778  return SCARD_E_INVALID_HANDLE;
2779  }
2780 
2781  if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2782  {
2784  goto end;
2785  }
2786 
2787  scTransmitStruct.hCard = hCard;
2788  scTransmitStruct.cbSendLength = cbSendLength;
2789  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2790  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2791  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2792  scTransmitStruct.rv = SCARD_S_SUCCESS;
2793 
2794  if (pioRecvPci)
2795  {
2796  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2797  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2798  }
2799  else
2800  {
2801  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2802  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2803  }
2804 
2805  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2806  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2807 
2808  if (rv != SCARD_S_SUCCESS)
2809  goto end;
2810 
2811  /* write the sent buffer */
2812  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2813  currentContextMap->dwClientID);
2814 
2815  if (rv != SCARD_S_SUCCESS)
2816  goto end;
2817 
2818  /*
2819  * Read a message from the server
2820  */
2821  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2822  currentContextMap->dwClientID);
2823 
2824  if (rv != SCARD_S_SUCCESS)
2825  goto end;
2826 
2827  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2828  {
2829  if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2830  {
2831  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2833  goto end;
2834  }
2835 
2836  /* read the received buffer */
2837  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2838  currentContextMap->dwClientID);
2839 
2840  if (rv != SCARD_S_SUCCESS)
2841  goto end;
2842 
2843  if (pioRecvPci)
2844  {
2845  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2846  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2847  }
2848  }
2849 
2850  rv = scTransmitStruct.rv;
2851 
2852  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2853  {
2854  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2855  (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
2856  goto retry;
2857  }
2858 
2859  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2860 
2861 end:
2862  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2863 
2864  PROFILE_END(rv)
2865 
2866  return rv;
2867 }
2868 
2935 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2936  LPSTR mszReaders, LPDWORD pcchReaders)
2937 {
2938  DWORD dwReadersLen = 0;
2939  int i;
2940  SCONTEXTMAP * currentContextMap;
2941  LONG rv = SCARD_S_SUCCESS;
2942  char *buf = NULL;
2943 
2944  (void)mszGroups;
2945  PROFILE_START
2946  API_TRACE_IN("%ld", hContext)
2947 
2948  /*
2949  * Check for NULL parameters
2950  */
2951  if (pcchReaders == NULL)
2953 
2954  /*
2955  * Make sure this context has been opened
2956  */
2957  currentContextMap = SCardGetAndLockContext(hContext);
2958  if (NULL == currentContextMap)
2959  {
2960  PROFILE_END(SCARD_E_INVALID_HANDLE)
2961  return SCARD_E_INVALID_HANDLE;
2962  }
2963 
2964  /* lock access to readerStates[] */
2965  (void)pthread_mutex_lock(&readerStatesMutex);
2966 
2967  /* synchronize reader states with daemon */
2968  rv = getReaderStates(currentContextMap);
2969  if (rv != SCARD_S_SUCCESS)
2970  goto end;
2971 
2972  dwReadersLen = 0;
2973  for (i = 0; i < pcsclite_max_reader_context; i++)
2974  if (readerStates[i].readerName[0] != '\0')
2975  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2976 
2977  /* for the last NULL byte */
2978  dwReadersLen += 1;
2979 
2980  if (1 == dwReadersLen)
2981  {
2983  goto end;
2984  }
2985 
2986  if (SCARD_AUTOALLOCATE == *pcchReaders)
2987  {
2988  if (NULL == mszReaders)
2989  {
2991  goto end;
2992  }
2993  buf = malloc(dwReadersLen);
2994  if (NULL == buf)
2995  {
2996  rv = SCARD_E_NO_MEMORY;
2997  goto end;
2998  }
2999  *(char **)mszReaders = buf;
3000  }
3001  else
3002  {
3003  buf = mszReaders;
3004 
3005  /* not enough place to store the reader names */
3006  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3007  {
3009  goto end;
3010  }
3011  }
3012 
3013  if (mszReaders == NULL) /* text array not allocated */
3014  goto end;
3015 
3016  for (i = 0; i < pcsclite_max_reader_context; i++)
3017  {
3018  if (readerStates[i].readerName[0] != '\0')
3019  {
3020  /*
3021  * Build the multi-string
3022  */
3023  strcpy(buf, readerStates[i].readerName);
3024  buf += strlen(readerStates[i].readerName)+1;
3025  }
3026  }
3027  *buf = '\0'; /* Add the last null */
3028 
3029 end:
3030  /* set the reader names length */
3031  *pcchReaders = dwReadersLen;
3032 
3033  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3034  (void)pthread_mutex_unlock(&readerStatesMutex);
3035 
3036  PROFILE_END(rv)
3037  API_TRACE_OUT("%d", *pcchReaders)
3038 
3039  return rv;
3040 }
3041 
3055 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3056 {
3057  LONG rv = SCARD_S_SUCCESS;
3058 
3059  PROFILE_START
3060 
3061  /*
3062  * Make sure this context has been opened
3063  */
3064  if (! SCardGetContextValidity(hContext))
3065  return SCARD_E_INVALID_HANDLE;
3066 
3067  free((void *)pvMem);
3068 
3069  PROFILE_END(rv)
3070 
3071  return rv;
3072 }
3073 
3125 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3126  LPDWORD pcchGroups)
3127 {
3128  LONG rv = SCARD_S_SUCCESS;
3129  SCONTEXTMAP * currentContextMap;
3130  char *buf = NULL;
3131 
3132  PROFILE_START
3133 
3134  /* Multi-string with two trailing \0 */
3135  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3136  const unsigned int dwGroups = sizeof(ReaderGroup);
3137 
3138  /*
3139  * Make sure this context has been opened
3140  */
3141  currentContextMap = SCardGetAndLockContext(hContext);
3142  if (NULL == currentContextMap)
3143  return SCARD_E_INVALID_HANDLE;
3144 
3145  if (SCARD_AUTOALLOCATE == *pcchGroups)
3146  {
3147  if (NULL == mszGroups)
3148  {
3150  goto end;
3151  }
3152  buf = malloc(dwGroups);
3153  if (NULL == buf)
3154  {
3155  rv = SCARD_E_NO_MEMORY;
3156  goto end;
3157  }
3158  *(char **)mszGroups = buf;
3159  }
3160  else
3161  {
3162  buf = mszGroups;
3163 
3164  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3165  {
3167  goto end;
3168  }
3169  }
3170 
3171  if (buf)
3172  memcpy(buf, ReaderGroup, dwGroups);
3173 
3174 end:
3175  *pcchGroups = dwGroups;
3176 
3177  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3178 
3179  PROFILE_END(rv)
3180 
3181  return rv;
3182 }
3183 
3216 {
3217  SCONTEXTMAP * currentContextMap;
3218  LONG rv = SCARD_S_SUCCESS;
3219  uint32_t dwClientID = 0;
3220  struct cancel_struct scCancelStruct;
3221  bool cancellable;
3222 
3223  PROFILE_START
3224  API_TRACE_IN("%ld", hContext)
3225 
3226  /*
3227  * Make sure this context has been opened
3228  */
3229  (void)SCardLockThread();
3230  currentContextMap = SCardGetContextTH(hContext);
3231 
3232  if (NULL == currentContextMap)
3233  {
3234  (void)SCardUnlockThread();
3236  goto error;
3237  }
3238  cancellable = currentContextMap->cancellable;
3239  (void)SCardUnlockThread();
3240 
3241  if (! cancellable)
3242  {
3243  rv = SCARD_S_SUCCESS;
3244  goto error;
3245  }
3246 
3247  /* create a new connection to the server */
3248  if (ClientSetupSession(&dwClientID) != 0)
3249  {
3250  rv = SCARD_E_NO_SERVICE;
3251  goto error;
3252  }
3253 
3254  scCancelStruct.hContext = hContext;
3255  scCancelStruct.rv = SCARD_S_SUCCESS;
3256 
3257  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3258  sizeof(scCancelStruct), (void *) &scCancelStruct);
3259 
3260  if (rv != SCARD_S_SUCCESS)
3261  goto end;
3262 
3263  /*
3264  * Read a message from the server
3265  */
3266  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3267 
3268  if (rv != SCARD_S_SUCCESS)
3269  goto end;
3270 
3271  rv = scCancelStruct.rv;
3272 end:
3273  ClientCloseSession(dwClientID);
3274 
3275 error:
3276  PROFILE_END(rv)
3277  API_TRACE_OUT("")
3278 
3279  return rv;
3280 }
3281 
3306 {
3307  LONG rv;
3308 
3309  PROFILE_START
3310  API_TRACE_IN("%ld", hContext)
3311 
3312  rv = SCARD_S_SUCCESS;
3313 
3314  /*
3315  * Make sure this context has been opened
3316  */
3317  if (! SCardGetContextValidity(hContext))
3319 
3320  PROFILE_END(rv)
3321  API_TRACE_OUT("")
3322 
3323  return rv;
3324 }
3325 
3342 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3343 {
3344  int lrv;
3345  SCONTEXTMAP * newContextMap;
3346 
3347  newContextMap = malloc(sizeof(SCONTEXTMAP));
3348  if (NULL == newContextMap)
3349  return SCARD_E_NO_MEMORY;
3350 
3351  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3352  newContextMap->hContext = hContext;
3353  newContextMap->dwClientID = dwClientID;
3354  newContextMap->cancellable = false;
3355 
3356  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3357 
3358  lrv = list_init(&newContextMap->channelMapList);
3359  if (lrv < 0)
3360  {
3361  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3362  goto error;
3363  }
3364 
3365  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3366  CHANNEL_MAP_seeker);
3367  if (lrv <0)
3368  {
3369  Log2(PCSC_LOG_CRITICAL,
3370  "list_attributes_seeker failed with return value: %d", lrv);
3371  list_destroy(&newContextMap->channelMapList);
3372  goto error;
3373  }
3374 
3375  (void)pthread_mutex_lock(&contextMapList_lock);
3376  lrv = list_append(&contextMapList, newContextMap);
3377  (void)pthread_mutex_unlock(&contextMapList_lock);
3378  if (lrv < 0)
3379  {
3380  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3381  lrv);
3382  list_destroy(&newContextMap->channelMapList);
3383  goto error;
3384  }
3385 
3386  return SCARD_S_SUCCESS;
3387 
3388 error:
3389 
3390  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3391  free(newContextMap);
3392 
3393  return SCARD_E_NO_MEMORY;
3394 }
3395 
3413 {
3414  SCONTEXTMAP * currentContextMap;
3415 
3416  SCardLockThread();
3417  currentContextMap = SCardGetContextTH(hContext);
3418 
3419  /* lock the context (if available) */
3420  if (NULL != currentContextMap)
3421  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3422 
3424 
3425  return currentContextMap;
3426 }
3427 
3441 {
3442  SCONTEXTMAP * currentContextMap;
3443 
3444  (void)pthread_mutex_lock(&contextMapList_lock);
3445  currentContextMap = list_seek(&contextMapList, &hContext);
3446  (void)pthread_mutex_unlock(&contextMapList_lock);
3447 
3448  return currentContextMap;
3449 }
3450 
3457 static void SCardRemoveContext(SCARDCONTEXT hContext)
3458 {
3459  SCONTEXTMAP * currentContextMap;
3460  currentContextMap = SCardGetContextTH(hContext);
3461 
3462  if (NULL != currentContextMap)
3463  SCardCleanContext(currentContextMap);
3464 }
3465 
3466 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3467 {
3468  int list_index, lrv;
3469  int listSize;
3470  CHANNEL_MAP * currentChannelMap;
3471 
3472  targetContextMap->hContext = 0;
3473  ClientCloseSession(targetContextMap->dwClientID);
3474  targetContextMap->dwClientID = 0;
3475  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3476 
3477  listSize = list_size(&targetContextMap->channelMapList);
3478  for (list_index = 0; list_index < listSize; list_index++)
3479  {
3480  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3481  list_index);
3482  if (NULL == currentChannelMap)
3483  {
3484  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3485  list_index);
3486  continue;
3487  }
3488  else
3489  {
3490  free(currentChannelMap->readerName);
3491  free(currentChannelMap);
3492  }
3493 
3494  }
3495  list_destroy(&targetContextMap->channelMapList);
3496 
3497  (void)pthread_mutex_lock(&contextMapList_lock);
3498  lrv = list_delete(&contextMapList, targetContextMap);
3499  (void)pthread_mutex_unlock(&contextMapList_lock);
3500  if (lrv < 0)
3501  {
3502  Log2(PCSC_LOG_CRITICAL,
3503  "list_delete failed with return value: %d", lrv);
3504  }
3505 
3506  free(targetContextMap);
3507 
3508  return;
3509 }
3510 
3511 /*
3512  * Functions for managing hCard values returned from SCardConnect.
3513  */
3514 
3515 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3516  LPCSTR readerName)
3517 {
3518  CHANNEL_MAP * newChannelMap;
3519  int lrv = -1;
3520 
3521  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3522  if (NULL == newChannelMap)
3523  return SCARD_E_NO_MEMORY;
3524 
3525  newChannelMap->hCard = hCard;
3526  newChannelMap->readerName = strdup(readerName);
3527 
3528  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3529  if (lrv < 0)
3530  {
3531  free(newChannelMap->readerName);
3532  free(newChannelMap);
3533  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3534  lrv);
3535  return SCARD_E_NO_MEMORY;
3536  }
3537 
3538  return SCARD_S_SUCCESS;
3539 }
3540 
3541 static void SCardRemoveHandle(SCARDHANDLE hCard)
3542 {
3543  SCONTEXTMAP * currentContextMap;
3544  CHANNEL_MAP * currentChannelMap;
3545  int lrv;
3546  LONG rv;
3547 
3548  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3549  &currentChannelMap);
3550  if (rv == -1)
3551  return;
3552 
3553  free(currentChannelMap->readerName);
3554 
3555  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3556  if (lrv < 0)
3557  {
3558  Log2(PCSC_LOG_CRITICAL,
3559  "list_delete failed with return value: %d", lrv);
3560  }
3561 
3562  free(currentChannelMap);
3563 
3564  return;
3565 }
3566 
3567 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3568  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3569 {
3570  LONG rv;
3571 
3572  if (0 == hCard)
3573  return -1;
3574 
3575  SCardLockThread();
3576  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3577  targetChannelMap);
3578 
3579  if (SCARD_S_SUCCESS == rv)
3580  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3581 
3583 
3584  return rv;
3585 }
3586 
3587 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3588  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3589 {
3590  LONG rv = -1;
3591  int listSize;
3592  int list_index;
3593  SCONTEXTMAP * currentContextMap;
3594  CHANNEL_MAP * currentChannelMap;
3595 
3596  /* Best to get the caller a crash early if we fail unsafely */
3597  *targetContextMap = NULL;
3598  *targetChannelMap = NULL;
3599 
3600  (void)pthread_mutex_lock(&contextMapList_lock);
3601  listSize = list_size(&contextMapList);
3602 
3603  for (list_index = 0; list_index < listSize; list_index++)
3604  {
3605  currentContextMap = list_get_at(&contextMapList, list_index);
3606  if (currentContextMap == NULL)
3607  {
3608  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3609  list_index);
3610  continue;
3611  }
3612  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3613  &hCard);
3614  if (currentChannelMap != NULL)
3615  {
3616  *targetContextMap = currentContextMap;
3617  *targetChannelMap = currentChannelMap;
3618  rv = SCARD_S_SUCCESS;
3619  break;
3620  }
3621  }
3622 
3623  (void)pthread_mutex_unlock(&contextMapList_lock);
3624 
3625  return rv;
3626 }
3627 
3636 {
3637  LONG rv;
3638  struct stat statBuffer;
3639  char *socketName;
3640 
3641  socketName = getSocketName();
3642  rv = stat(socketName, &statBuffer);
3643 
3644  if (rv != 0)
3645  {
3646  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3647  socketName, strerror(errno));
3648  return SCARD_E_NO_SERVICE;
3649  }
3650 
3651  return SCARD_S_SUCCESS;
3652 }
3653 
3654 static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents)
3655 {
3656  int32_t dwClientID = currentContextMap->dwClientID;
3657  LONG rv;
3658  struct get_reader_events get_reader_events = {0};
3659 
3660  /* CMD_GET_READER_EVENTS was added in protocol 4:5 */
3661  if (Protocol_version < 4005)
3663 
3664  rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL);
3665  if (rv != SCARD_S_SUCCESS)
3666  return rv;
3667 
3668  /* Read a message from the server */
3669  rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID);
3670  if (rv != SCARD_S_SUCCESS)
3671  return rv;
3672 
3673  *readerEvents = get_reader_events.readerEvents;
3674 
3675  return SCARD_S_SUCCESS;
3676 }
3677 
3678 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3679 {
3680  int32_t dwClientID = currentContextMap->dwClientID;
3681  LONG rv;
3682  int32_t array_size;
3683 
3684  if (Protocol_version <= 4005)
3685  /* protocol up to 4:5 used a fixed size */
3686  array_size = PCSCLITE_MAX_READERS_CONTEXTS;
3687  else
3688  {
3689  rv = MessageSendWithHeader(CMD_GET_READERS_STATE_SIZE, dwClientID, 0, NULL);
3690  if (rv != SCARD_S_SUCCESS)
3691  return rv;
3692 
3693  /* Read a message from the server */
3694  rv = MessageReceive(&array_size, sizeof(array_size), dwClientID);
3695  if (rv != SCARD_S_SUCCESS)
3696  return rv;
3697  }
3698 
3699  if (array_size > pcsclite_max_reader_context)
3700  {
3701  /* need to resize */
3702  readerStates = realloc(readerStates, array_size * sizeof(readerStates[0]));
3703  if (NULL == readerStates)
3705  pcsclite_max_reader_context = array_size;
3706  }
3707 
3708  if (array_size != pcsclite_max_reader_context)
3709  {
3710  /* Should never happen */
3712  }
3713 
3714  if (Protocol_version <= 4005)
3715  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3716  else
3717  rv = MessageSendWithHeader(CMD_GET_READERS_STATE_ARRAY, dwClientID, 0, NULL);
3718  if (rv != SCARD_S_SUCCESS)
3719  return rv;
3720 
3721  /* Read a message from the server */
3722  rv = MessageReceive(readerStates, array_size * sizeof(readerStates[0]), dwClientID);
3723  if (rv != SCARD_S_SUCCESS)
3724  return rv;
3725 
3726  return SCARD_S_SUCCESS;
3727 }
3728 
3729 static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3730 {
3731  int32_t dwClientID = currentContextMap->dwClientID;
3732  LONG rv;
3733 
3734  /* Get current reader states from server and register on event list */
3736  0, NULL);
3737  if (rv != SCARD_S_SUCCESS)
3738  return rv;
3739 
3740  if (Protocol_version <= 4005)
3741  {
3742  /* This should not happen
3743  * pcsclite_max_reader_context should be set to the backward
3744  * compatible value from a previous call to getReaderStates()
3745  * called from SCardStatus() or SCardListReaders() */
3746  if (pcsclite_max_reader_context != PCSCLITE_MAX_READERS_CONTEXTS)
3747  return SCARD_E_NO_SERVICE;
3748 
3749  rv = MessageReceive(readerStates, pcsclite_max_reader_context * sizeof(readerStates[0]), dwClientID);
3750  return rv;
3751  }
3752  else
3753  return getReaderStates(currentContextMap);
3754 }
3755 
3756 static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3757 {
3758  int32_t dwClientID = currentContextMap->dwClientID;
3759  LONG rv;
3760  struct wait_reader_state_change waitStatusStruct = {0};
3761 
3762  /* ask server to remove us from the event list */
3764  dwClientID, 0, NULL);
3765  if (rv != SCARD_S_SUCCESS)
3766  return rv;
3767 
3768  /* This message can be the response to
3769  * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3770  * cancel notification.
3771  * The server side ensures, that no more messages will be sent to
3772  * the client. */
3773 
3774  rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3775  dwClientID);
3776  if (rv != SCARD_S_SUCCESS)
3777  return rv;
3778 
3779  /* if we received a cancel event the return value will be set
3780  * accordingly */
3781  rv = waitStatusStruct.rv;
3782 
3783  return rv;
3784 }
3785 
#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:89
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:151
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:101
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:217
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:239
#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:205
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:60
#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
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: readers.h:56
get the client/server protocol version
Definition: winscard_msg.h:99
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
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:83
#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:320
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:64
used by SCardEndTransaction()
Definition: winscard_msg.h:90
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.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition: sys_unix.c:168
#define PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD
Minor version the client also supports.
Definition: winscard_msg.h:54
get the readers state array
Definition: winscard_msg.h:105
used by SCardConnect()
Definition: winscard_msg.h:86
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:182
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:140
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:194
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:62
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:128
get the readers state
Definition: winscard_msg.h:100
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:234
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:61
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:461
used by SCardReleaseContext()
Definition: winscard_msg.h:84
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
pthread_mutex_t contextMapList_lock
lock for the above list
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:228
#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:167
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:271
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:272
This defines some structures and #defines to be used over the transport layer.
get the number of reader events
Definition: winscard_msg.h:103
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:117
DWORD dwClientID
Client Connection ID.
#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:87
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
used by SCardTransmit()
Definition: winscard_msg.h:91
Represents an Application Context Channel.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: readers.h:58
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:102
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.
uint32_t readerState
SCARD_* bit field.
Definition: readers.h:53
#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...
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:121
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: readers.h:49
#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.
_Atomic uint32_t cardAtrLength
ATR length.
Definition: readers.h:57
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:92
#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
used by SCardSetAttrib()
Definition: winscard_msg.h:98
#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:357
used by SCardDisconnect()
Definition: winscard_msg.h:88
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:256
used by SCardGetAttrib()
Definition: winscard_msg.h:97
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.
used by SCardCancel()
Definition: winscard_msg.h:95
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:58
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:63
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().
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: readers.h:54
uint32_t eventCounter
number of card events
Definition: readers.h:52
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
Definition: pcsclite.h:171
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition: pcsclite.h:167
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:93
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:197
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.
int pcsclite_max_reader_context
Area used to read status information about the readers.
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:276