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