pcsc-lite  1.8.20
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 
1445  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
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 */
1757  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
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 */
1808  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
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  /* another thread can do SCardCancel() */
2085  currentContextMap->cancellable = FALSE;
2086 
2087  /* timeout */
2088  if (SCARD_E_TIMEOUT == rv)
2089  {
2090  /* ask server to remove us from the event list */
2092  currentContextMap->dwClientID,
2093  sizeof(waitStatusStruct), &waitStatusStruct);
2094 
2095  if (rv != SCARD_S_SUCCESS)
2096  goto end;
2097 
2098  /* Read a message from the server */
2099  rv = MessageReceive(&waitStatusStruct,
2100  sizeof(waitStatusStruct),
2101  currentContextMap->dwClientID);
2102 
2103  if (rv != SCARD_S_SUCCESS)
2104  goto end;
2105  }
2106 
2107  if (rv != SCARD_S_SUCCESS)
2108  goto end;
2109 
2110  /* an event occurs or SCardCancel() was called */
2111  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2112  {
2113  rv = waitStatusStruct.rv;
2114  goto end;
2115  }
2116 
2117  /* synchronize reader states with daemon */
2118  rv = getReaderStates(currentContextMap);
2119  if (rv != SCARD_S_SUCCESS)
2120  goto end;
2121 
2122  if (INFINITE != dwTimeout)
2123  {
2124  long int diff;
2125 
2126  gettimeofday(&after, NULL);
2127  diff = time_sub(&after, &before);
2128  dwTime -= diff/1000;
2129  }
2130  }
2131 
2132  if (dwTimeout != INFINITE)
2133  {
2134  /* If time is greater than timeout and all readers have been
2135  * checked
2136  */
2137  if (dwTime <= 0)
2138  {
2139  rv = SCARD_E_TIMEOUT;
2140  goto end;
2141  }
2142  }
2143  }
2144  }
2145  while (1);
2146 
2147 end:
2148  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2149 
2150  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2151 
2152 error:
2153  PROFILE_END(rv)
2154 #ifdef DO_TRACE
2155  for (j=0; j<cReaders; j++)
2156  {
2157  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2158  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2159  }
2160 #endif
2161 
2162  return rv;
2163 }
2164 
2215 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2216  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2217  LPDWORD lpBytesReturned)
2218 {
2219  LONG rv;
2220  struct control_struct scControlStruct;
2221  SCONTEXTMAP * currentContextMap;
2222  CHANNEL_MAP * pChannelMap;
2223 
2224  PROFILE_START
2225 
2226  /* 0 bytes received by default */
2227  if (NULL != lpBytesReturned)
2228  *lpBytesReturned = 0;
2229 
2230  /*
2231  * Make sure this handle has been opened
2232  */
2233  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2234  &pChannelMap);
2235  if (rv == -1)
2236  {
2237  PROFILE_END(SCARD_E_INVALID_HANDLE)
2238  return SCARD_E_INVALID_HANDLE;
2239  }
2240 
2241  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2242  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2243  {
2245  goto end;
2246  }
2247 
2248  scControlStruct.hCard = hCard;
2249  scControlStruct.dwControlCode = dwControlCode;
2250  scControlStruct.cbSendLength = cbSendLength;
2251  scControlStruct.cbRecvLength = cbRecvLength;
2252  scControlStruct.dwBytesReturned = 0;
2253  scControlStruct.rv = 0;
2254 
2255  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2256  sizeof(scControlStruct), &scControlStruct);
2257 
2258  if (rv != SCARD_S_SUCCESS)
2259  goto end;
2260 
2261  /* write the sent buffer */
2262  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2263  currentContextMap->dwClientID);
2264 
2265  if (rv != SCARD_S_SUCCESS)
2266  goto end;
2267 
2268  /*
2269  * Read a message from the server
2270  */
2271  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2272  currentContextMap->dwClientID);
2273 
2274  if (rv != SCARD_S_SUCCESS)
2275  goto end;
2276 
2277  if (SCARD_S_SUCCESS == scControlStruct.rv)
2278  {
2279  /* read the received buffer */
2280  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2281  currentContextMap->dwClientID);
2282 
2283  if (rv != SCARD_S_SUCCESS)
2284  goto end;
2285 
2286  }
2287 
2288  if (NULL != lpBytesReturned)
2289  *lpBytesReturned = scControlStruct.dwBytesReturned;
2290 
2291  rv = scControlStruct.rv;
2292 
2293 end:
2294  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2295 
2296  PROFILE_END(rv)
2297 
2298  return rv;
2299 }
2300 
2416 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2417  LPDWORD pcbAttrLen)
2418 {
2419  LONG ret;
2420  unsigned char *buf = NULL;
2421 
2422  PROFILE_START
2423 
2424  if (NULL == pcbAttrLen)
2425  {
2427  goto end;
2428  }
2429 
2430  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2431  {
2432  if (NULL == pbAttr)
2434 
2435  *pcbAttrLen = MAX_BUFFER_SIZE;
2436  buf = malloc(*pcbAttrLen);
2437  if (NULL == buf)
2438  {
2439  ret = SCARD_E_NO_MEMORY;
2440  goto end;
2441  }
2442 
2443  *(unsigned char **)pbAttr = buf;
2444  }
2445  else
2446  {
2447  buf = pbAttr;
2448 
2449  /* if only get the length */
2450  if (NULL == pbAttr)
2451  /* use a reasonable size */
2452  *pcbAttrLen = MAX_BUFFER_SIZE;
2453  }
2454 
2455  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2456  pcbAttrLen);
2457 
2458 end:
2459  PROFILE_END(ret)
2460 
2461  return ret;
2462 }
2463 
2499 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2500  DWORD cbAttrLen)
2501 {
2502  LONG ret;
2503 
2504  PROFILE_START
2505 
2506  if (NULL == pbAttr || 0 == cbAttrLen)
2508 
2509  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2510  &cbAttrLen);
2511 
2512  PROFILE_END(ret)
2513 
2514  return ret;
2515 }
2516 
2517 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2518  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2519 {
2520  LONG rv;
2521  struct getset_struct scGetSetStruct;
2522  SCONTEXTMAP * currentContextMap;
2523  CHANNEL_MAP * pChannelMap;
2524 
2525  /*
2526  * Make sure this handle has been opened
2527  */
2528  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2529  &pChannelMap);
2530  if (rv == -1)
2531  return SCARD_E_INVALID_HANDLE;
2532 
2533  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2534  {
2536  goto end;
2537  }
2538 
2539  scGetSetStruct.hCard = hCard;
2540  scGetSetStruct.dwAttrId = dwAttrId;
2541  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2542  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2543  if (SCARD_SET_ATTRIB == command)
2544  {
2545  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2546  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2547  }
2548  else
2549  /* we can get up to the communication buffer size */
2550  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2551 
2552  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2553  sizeof(scGetSetStruct), &scGetSetStruct);
2554 
2555  if (rv != SCARD_S_SUCCESS)
2556  goto end;
2557 
2558  /*
2559  * Read a message from the server
2560  */
2561  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2562  currentContextMap->dwClientID);
2563 
2564  if (rv != SCARD_S_SUCCESS)
2565  goto end;
2566 
2567  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2568  {
2569  /*
2570  * Copy and zero it so any secret information is not leaked
2571  */
2572  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2573  {
2574  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2575  * buffer overflow in the memcpy() bellow */
2576  DWORD correct_value = scGetSetStruct.cbAttrLen;
2577  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2578  *pcbAttrLen = correct_value;
2579 
2580  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2581  }
2582  else
2583  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2584 
2585  if (pbAttr)
2586  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2587 
2588  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2589  }
2590  rv = scGetSetStruct.rv;
2591 
2592 end:
2593  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2594 
2595  return rv;
2596 }
2597 
2656 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2657  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2658  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2659  LPDWORD pcbRecvLength)
2660 {
2661  LONG rv;
2662  SCONTEXTMAP * currentContextMap;
2663  CHANNEL_MAP * pChannelMap;
2664  struct transmit_struct scTransmitStruct;
2665 
2666  PROFILE_START
2667 
2668  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2669  pcbRecvLength == NULL || pioSendPci == NULL)
2671 
2672  /* Retry loop for blocking behaviour */
2673 retry:
2674 
2675  /*
2676  * Make sure this handle has been opened
2677  */
2678  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2679  &pChannelMap);
2680  if (rv == -1)
2681  {
2682  *pcbRecvLength = 0;
2683  PROFILE_END(SCARD_E_INVALID_HANDLE)
2684  return SCARD_E_INVALID_HANDLE;
2685  }
2686 
2687  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2688  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2689  {
2691  goto end;
2692  }
2693 
2694  scTransmitStruct.hCard = hCard;
2695  scTransmitStruct.cbSendLength = cbSendLength;
2696  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2697  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2698  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2699  scTransmitStruct.rv = SCARD_S_SUCCESS;
2700 
2701  if (pioRecvPci)
2702  {
2703  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2704  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2705  }
2706  else
2707  {
2708  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2709  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2710  }
2711 
2712  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2713  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2714 
2715  if (rv != SCARD_S_SUCCESS)
2716  goto end;
2717 
2718  /* write the sent buffer */
2719  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2720  currentContextMap->dwClientID);
2721 
2722  if (rv != SCARD_S_SUCCESS)
2723  goto end;
2724 
2725  /*
2726  * Read a message from the server
2727  */
2728  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2729  currentContextMap->dwClientID);
2730 
2731  if (rv != SCARD_S_SUCCESS)
2732  goto end;
2733 
2734  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2735  {
2736  /* read the received buffer */
2737  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2738  currentContextMap->dwClientID);
2739 
2740  if (rv != SCARD_S_SUCCESS)
2741  goto end;
2742 
2743  if (pioRecvPci)
2744  {
2745  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2746  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2747  }
2748  }
2749 
2750  rv = scTransmitStruct.rv;
2751 
2752  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2753  {
2754  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2756  goto retry;
2757  }
2758 
2759  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2760 
2761 end:
2762  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2763 
2764  PROFILE_END(rv)
2765 
2766  return rv;
2767 }
2768 
2831 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2832  LPSTR mszReaders, LPDWORD pcchReaders)
2833 {
2834  DWORD dwReadersLen = 0;
2835  int i;
2836  SCONTEXTMAP * currentContextMap;
2837  LONG rv = SCARD_S_SUCCESS;
2838  char *buf = NULL;
2839 
2840  (void)mszGroups;
2841  PROFILE_START
2842  API_TRACE_IN("%ld", hContext)
2843 
2844  /*
2845  * Check for NULL parameters
2846  */
2847  if (pcchReaders == NULL)
2849 
2850  /*
2851  * Make sure this context has been opened
2852  */
2853  currentContextMap = SCardGetAndLockContext(hContext);
2854  if (NULL == currentContextMap)
2855  {
2856  PROFILE_END(SCARD_E_INVALID_HANDLE)
2857  return SCARD_E_INVALID_HANDLE;
2858  }
2859 
2860  /* synchronize reader states with daemon */
2861  rv = getReaderStates(currentContextMap);
2862  if (rv != SCARD_S_SUCCESS)
2863  goto end;
2864 
2865  dwReadersLen = 0;
2866  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2867  if (readerStates[i].readerName[0] != '\0')
2868  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2869 
2870  /* for the last NULL byte */
2871  dwReadersLen += 1;
2872 
2873  if (1 == dwReadersLen)
2874  {
2876  goto end;
2877  }
2878 
2879  if (SCARD_AUTOALLOCATE == *pcchReaders)
2880  {
2881  if (NULL == mszReaders)
2882  {
2884  goto end;
2885  }
2886  buf = malloc(dwReadersLen);
2887  if (NULL == buf)
2888  {
2889  rv = SCARD_E_NO_MEMORY;
2890  goto end;
2891  }
2892  *(char **)mszReaders = buf;
2893  }
2894  else
2895  {
2896  buf = mszReaders;
2897 
2898  /* not enough place to store the reader names */
2899  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2900  {
2902  goto end;
2903  }
2904  }
2905 
2906  if (mszReaders == NULL) /* text array not allocated */
2907  goto end;
2908 
2909  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2910  {
2911  if (readerStates[i].readerName[0] != '\0')
2912  {
2913  /*
2914  * Build the multi-string
2915  */
2916  strcpy(buf, readerStates[i].readerName);
2917  buf += strlen(readerStates[i].readerName)+1;
2918  }
2919  }
2920  *buf = '\0'; /* Add the last null */
2921 
2922 end:
2923  /* set the reader names length */
2924  *pcchReaders = dwReadersLen;
2925 
2926  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2927 
2928  PROFILE_END(rv)
2929  API_TRACE_OUT("%d", *pcchReaders)
2930 
2931  return rv;
2932 }
2933 
2947 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2948 {
2949  LONG rv = SCARD_S_SUCCESS;
2950 
2951  PROFILE_START
2952 
2953  /*
2954  * Make sure this context has been opened
2955  */
2956  if (! SCardGetContextValidity(hContext))
2957  return SCARD_E_INVALID_HANDLE;
2958 
2959  free((void *)pvMem);
2960 
2961  PROFILE_END(rv)
2962 
2963  return rv;
2964 }
2965 
3017 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3018  LPDWORD pcchGroups)
3019 {
3020  LONG rv = SCARD_S_SUCCESS;
3021  SCONTEXTMAP * currentContextMap;
3022  char *buf = NULL;
3023 
3024  PROFILE_START
3025 
3026  /* Multi-string with two trailing \0 */
3027  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3028  const unsigned int dwGroups = sizeof(ReaderGroup);
3029 
3030  /*
3031  * Make sure this context has been opened
3032  */
3033  currentContextMap = SCardGetAndLockContext(hContext);
3034  if (NULL == currentContextMap)
3035  return SCARD_E_INVALID_HANDLE;
3036 
3037  if (SCARD_AUTOALLOCATE == *pcchGroups)
3038  {
3039  if (NULL == mszGroups)
3040  {
3042  goto end;
3043  }
3044  buf = malloc(dwGroups);
3045  if (NULL == buf)
3046  {
3047  rv = SCARD_E_NO_MEMORY;
3048  goto end;
3049  }
3050  *(char **)mszGroups = buf;
3051  }
3052  else
3053  {
3054  buf = mszGroups;
3055 
3056  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3057  {
3059  goto end;
3060  }
3061  }
3062 
3063  if (buf)
3064  memcpy(buf, ReaderGroup, dwGroups);
3065 
3066 end:
3067  *pcchGroups = dwGroups;
3068 
3069  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3070 
3071  PROFILE_END(rv)
3072 
3073  return rv;
3074 }
3075 
3108 {
3109  SCONTEXTMAP * currentContextMap;
3110  LONG rv = SCARD_S_SUCCESS;
3111  uint32_t dwClientID = 0;
3112  struct cancel_struct scCancelStruct;
3113  char cancellable;
3114 
3115  PROFILE_START
3116  API_TRACE_IN("%ld", hContext)
3117 
3118  /*
3119  * Make sure this context has been opened
3120  */
3121  currentContextMap = SCardGetAndLockContext(hContext);
3122  if (NULL == currentContextMap)
3123  {
3125  goto error;
3126  }
3127 
3128  cancellable = currentContextMap->cancellable;
3129  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3130 
3131  if (! cancellable)
3132  {
3133  rv = SCARD_S_SUCCESS;
3134  goto error;
3135  }
3136 
3137  /* create a new connection to the server */
3138  if (ClientSetupSession(&dwClientID) != 0)
3139  {
3140  rv = SCARD_E_NO_SERVICE;
3141  goto error;
3142  }
3143 
3144  scCancelStruct.hContext = hContext;
3145  scCancelStruct.rv = SCARD_S_SUCCESS;
3146 
3147  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3148  sizeof(scCancelStruct), (void *) &scCancelStruct);
3149 
3150  if (rv != SCARD_S_SUCCESS)
3151  goto end;
3152 
3153  /*
3154  * Read a message from the server
3155  */
3156  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3157 
3158  if (rv != SCARD_S_SUCCESS)
3159  goto end;
3160 
3161  rv = scCancelStruct.rv;
3162 end:
3163  ClientCloseSession(dwClientID);
3164 
3165 error:
3166  PROFILE_END(rv)
3167  API_TRACE_OUT("")
3168 
3169  return rv;
3170 }
3171 
3196 {
3197  LONG rv;
3198 
3199  PROFILE_START
3200  API_TRACE_IN("%ld", hContext)
3201 
3202  rv = SCARD_S_SUCCESS;
3203 
3204  /*
3205  * Make sure this context has been opened
3206  */
3207  if (! SCardGetContextValidity(hContext))
3209 
3210  PROFILE_END(rv)
3211  API_TRACE_OUT("")
3212 
3213  return rv;
3214 }
3215 
3232 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3233 {
3234  int lrv;
3235  SCONTEXTMAP * newContextMap;
3236 
3237  newContextMap = malloc(sizeof(SCONTEXTMAP));
3238  if (NULL == newContextMap)
3239  return SCARD_E_NO_MEMORY;
3240 
3241  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3242  newContextMap->hContext = hContext;
3243  newContextMap->dwClientID = dwClientID;
3244  newContextMap->cancellable = FALSE;
3245 
3246  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3247 
3248  lrv = list_init(&newContextMap->channelMapList);
3249  if (lrv < 0)
3250  {
3251  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3252  goto error;
3253  }
3254 
3255  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3256  CHANNEL_MAP_seeker);
3257  if (lrv <0)
3258  {
3259  Log2(PCSC_LOG_CRITICAL,
3260  "list_attributes_seeker failed with return value: %d", lrv);
3261  list_destroy(&newContextMap->channelMapList);
3262  goto error;
3263  }
3264 
3265  lrv = list_append(&contextMapList, newContextMap);
3266  if (lrv < 0)
3267  {
3268  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3269  lrv);
3270  list_destroy(&newContextMap->channelMapList);
3271  goto error;
3272  }
3273 
3274  return SCARD_S_SUCCESS;
3275 
3276 error:
3277 
3278  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3279  free(newContextMap);
3280 
3281  return SCARD_E_NO_MEMORY;
3282 }
3283 
3301 {
3302  SCONTEXTMAP * currentContextMap;
3303 
3304  SCardLockThread();
3305  currentContextMap = SCardGetContextTH(hContext);
3306 
3307  /* lock the context (if available) */
3308  if (NULL != currentContextMap)
3309  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3310 
3312 
3313  return currentContextMap;
3314 }
3315 
3329 {
3330  return list_seek(&contextMapList, &hContext);
3331 }
3332 
3342 static void SCardRemoveContext(SCARDCONTEXT hContext)
3343 {
3344  SCONTEXTMAP * currentContextMap;
3345  currentContextMap = SCardGetContextTH(hContext);
3346 
3347  if (NULL != currentContextMap)
3348  SCardCleanContext(currentContextMap);
3349 }
3350 
3351 static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3352 {
3353  int list_index, lrv;
3354  int listSize;
3355  CHANNEL_MAP * currentChannelMap;
3356 
3357  targetContextMap->hContext = 0;
3358  ClientCloseSession(targetContextMap->dwClientID);
3359  targetContextMap->dwClientID = 0;
3360  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3361 
3362  listSize = list_size(&targetContextMap->channelMapList);
3363  for (list_index = 0; list_index < listSize; list_index++)
3364  {
3365  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3366  list_index);
3367  if (NULL == currentChannelMap)
3368  {
3369  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3370  list_index);
3371  continue;
3372  }
3373  else
3374  {
3375  free(currentChannelMap->readerName);
3376  free(currentChannelMap);
3377  }
3378 
3379  }
3380  list_destroy(&targetContextMap->channelMapList);
3381 
3382  lrv = list_delete(&contextMapList, targetContextMap);
3383  if (lrv < 0)
3384  {
3385  Log2(PCSC_LOG_CRITICAL,
3386  "list_delete failed with return value: %d", lrv);
3387  }
3388 
3389  free(targetContextMap);
3390 
3391  return;
3392 }
3393 
3394 /*
3395  * Functions for managing hCard values returned from SCardConnect.
3396  */
3397 
3398 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3399  LPCSTR readerName)
3400 {
3401  CHANNEL_MAP * newChannelMap;
3402  int lrv = -1;
3403 
3404  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3405  if (NULL == newChannelMap)
3406  return SCARD_E_NO_MEMORY;
3407 
3408  newChannelMap->hCard = hCard;
3409  newChannelMap->readerName = strdup(readerName);
3410 
3411  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3412  if (lrv < 0)
3413  {
3414  free(newChannelMap->readerName);
3415  free(newChannelMap);
3416  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3417  lrv);
3418  return SCARD_E_NO_MEMORY;
3419  }
3420 
3421  return SCARD_S_SUCCESS;
3422 }
3423 
3424 static void SCardRemoveHandle(SCARDHANDLE hCard)
3425 {
3426  SCONTEXTMAP * currentContextMap;
3427  CHANNEL_MAP * currentChannelMap;
3428  int lrv;
3429  LONG rv;
3430 
3431  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3432  &currentChannelMap);
3433  if (rv == -1)
3434  return;
3435 
3436  free(currentChannelMap->readerName);
3437 
3438  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3439  if (lrv < 0)
3440  {
3441  Log2(PCSC_LOG_CRITICAL,
3442  "list_delete failed with return value: %d", lrv);
3443  }
3444 
3445  free(currentChannelMap);
3446 
3447  return;
3448 }
3449 
3450 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3451  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3452 {
3453  LONG rv;
3454 
3455  if (0 == hCard)
3456  return -1;
3457 
3458  SCardLockThread();
3459  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3460  targetChannelMap);
3461 
3462  if (SCARD_S_SUCCESS == rv)
3463  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3464 
3466 
3467  return rv;
3468 }
3469 
3470 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3471  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3472 {
3473  int listSize;
3474  int list_index;
3475  SCONTEXTMAP * currentContextMap;
3476  CHANNEL_MAP * currentChannelMap;
3477 
3478  /* Best to get the caller a crash early if we fail unsafely */
3479  *targetContextMap = NULL;
3480  *targetChannelMap = NULL;
3481 
3482  listSize = list_size(&contextMapList);
3483 
3484  for (list_index = 0; list_index < listSize; list_index++)
3485  {
3486  currentContextMap = list_get_at(&contextMapList, list_index);
3487  if (currentContextMap == NULL)
3488  {
3489  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3490  list_index);
3491  continue;
3492  }
3493  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3494  &hCard);
3495  if (currentChannelMap != NULL)
3496  {
3497  *targetContextMap = currentContextMap;
3498  *targetChannelMap = currentChannelMap;
3499  return SCARD_S_SUCCESS;
3500  }
3501  }
3502 
3503  return -1;
3504 }
3505 
3514 {
3515  LONG rv;
3516  struct stat statBuffer;
3517  char *socketName;
3518 
3519  socketName = getSocketName();
3520  rv = stat(socketName, &statBuffer);
3521 
3522  if (rv != 0)
3523  {
3524  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3525  socketName, strerror(errno));
3526  return SCARD_E_NO_SERVICE;
3527  }
3528 
3529  return SCARD_S_SUCCESS;
3530 }
3531 
3532 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3533 {
3534  int32_t dwClientID = currentContextMap->dwClientID;
3535  LONG rv;
3536 
3537  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3538  if (rv != SCARD_S_SUCCESS)
3539  return rv;
3540 
3541  /* Read a message from the server */
3542  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3543  if (rv != SCARD_S_SUCCESS)
3544  return rv;
3545 
3546  return SCARD_S_SUCCESS;
3547 }
3548 
#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