pcsc-lite  1.8.17
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 
104 #include "config.h"
105 #include <stdlib.h>
106 #include <string.h>
107 #include <sys/types.h>
108 #include <fcntl.h>
109 #include <unistd.h>
110 #include <sys/un.h>
111 #include <errno.h>
112 #include <stddef.h>
113 #include <sys/time.h>
114 #include <pthread.h>
115 #include <sys/wait.h>
116 
117 #include "misc.h"
118 #include "pcscd.h"
119 #include "winscard.h"
120 #include "debuglog.h"
121 
122 #include "readerfactory.h"
123 #include "eventhandler.h"
124 #include "sys_generic.h"
125 #include "winscard_msg.h"
126 #include "utils.h"
127 
128 /* Display, on stderr, a trace of the WinSCard calls with arguments and
129  * results */
130 //#define DO_TRACE
131 
132 /* Profile the execution time of WinSCard calls */
133 //#define DO_PROFILE
134 
135 
137 #define SCARD_PROTOCOL_ANY_OLD 0x1000
138 
139 #ifndef TRUE
140 #define TRUE 1
141 #define FALSE 0
142 #endif
143 
144 static char sharing_shall_block = TRUE;
145 
146 #define COLOR_RED "\33[01;31m"
147 #define COLOR_GREEN "\33[32m"
148 #define COLOR_BLUE "\33[34m"
149 #define COLOR_MAGENTA "\33[35m"
150 #define COLOR_NORMAL "\33[0m"
151 
152 #ifdef DO_TRACE
153 
154 #include <stdio.h>
155 #include <stdarg.h>
156 
157 static void trace(const char *func, const char direction, const char *fmt, ...)
158 {
159  va_list args;
160 
161  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
162  direction, pthread_self(), func);
163 
164  fprintf(stderr, COLOR_MAGENTA);
165  va_start(args, fmt);
166  vfprintf(stderr, fmt, args);
167  va_end(args);
168 
169  fprintf(stderr, COLOR_NORMAL "\n");
170 }
171 
172 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
173 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
174 #else
175 #define API_TRACE_IN(...)
176 #define API_TRACE_OUT(...)
177 #endif
178 
179 #ifdef DO_PROFILE
180 
181 #define PROFILE_FILE "/tmp/pcsc_profile"
182 #include <stdio.h>
183 #include <sys/time.h>
184 
185 /* we can profile a maximum of 5 simultaneous calls */
186 #define MAX_THREADS 5
187 pthread_t threads[MAX_THREADS];
188 struct timeval profile_time_start[MAX_THREADS];
189 FILE *profile_fd;
190 char profile_tty;
191 
192 #define PROFILE_START profile_start();
193 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
194 
195 static void profile_start(void)
196 {
197  static char initialized = FALSE;
198  pthread_t t;
199  int i;
200 
201  if (!initialized)
202  {
203  char filename[80];
204 
205  initialized = TRUE;
206  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
207  profile_fd = fopen(filename, "a+");
208  if (NULL == profile_fd)
209  {
210  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
211  PROFILE_FILE, strerror(errno));
212  exit(-1);
213  }
214  fprintf(profile_fd, "\nStart a new profile\n");
215 
216  if (isatty(fileno(stderr)))
217  profile_tty = TRUE;
218  else
219  profile_tty = FALSE;
220  }
221 
222  t = pthread_self();
223  for (i=0; i<MAX_THREADS; i++)
224  if (pthread_equal(0, threads[i]))
225  {
226  threads[i] = t;
227  break;
228  }
229 
230  gettimeofday(&profile_time_start[i], NULL);
231 } /* profile_start */
232 
233 static void profile_end(const char *f, LONG rv)
234 {
235  struct timeval profile_time_end;
236  long d;
237  pthread_t t;
238  int i;
239 
240  gettimeofday(&profile_time_end, NULL);
241 
242  t = pthread_self();
243  for (i=0; i<MAX_THREADS; i++)
244  if (pthread_equal(t, threads[i]))
245  break;
246 
247  if (i>=MAX_THREADS)
248  {
249  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
250  return;
251  }
252 
253  d = time_sub(&profile_time_end, &profile_time_start[i]);
254 
255  /* free this entry */
256  threads[i] = 0;
257 
258  if (profile_tty)
259  {
260  if (rv != SCARD_S_SUCCESS)
261  fprintf(stderr,
262  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
263  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
264  f, d, rv, pcsc_stringify_error(rv));
265  else
266  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
267  COLOR_NORMAL "\n", f, d);
268  }
269  fprintf(profile_fd, "%s %ld\n", f, d);
270  fflush(profile_fd);
271 } /* profile_end */
272 
273 #else
274 #define PROFILE_START
275 #define PROFILE_END(rv)
276 #endif
277 
283 {
284  SCARDHANDLE hCard;
285  LPSTR readerName;
286 };
287 
288 typedef struct _psChannelMap CHANNEL_MAP;
289 
290 static int CHANNEL_MAP_seeker(const void *el, const void *key)
291 {
292  const CHANNEL_MAP * channelMap = el;
293 
294  if ((el == NULL) || (key == NULL))
295  {
296  Log3(PCSC_LOG_CRITICAL,
297  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
298  el, key);
299  return 0;
300  }
301 
302  if (channelMap->hCard == *(SCARDHANDLE *)key)
303  return 1;
304 
305  return 0;
306 }
307 
314 {
315  DWORD dwClientID;
317  pthread_mutex_t mMutex;
318  list_t channelMapList;
319  char cancellable;
320 };
321 typedef struct _psContextMap SCONTEXTMAP;
322 
323 static list_t contextMapList;
324 
325 static int SCONTEXTMAP_seeker(const void *el, const void *key)
326 {
327  const SCONTEXTMAP * contextMap = el;
328 
329  if ((el == NULL) || (key == NULL))
330  {
331  Log3(PCSC_LOG_CRITICAL,
332  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
333  el, key);
334  return 0;
335  }
336 
337  if (contextMap->hContext == *(SCARDCONTEXT *) key)
338  return 1;
339 
340  return 0;
341 }
342 
346 static short isExecuted = 0;
347 
348 
353 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
354 
359 
366 
367 
368 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
371 static LONG SCardRemoveContext(SCARDCONTEXT);
372 static LONG SCardCleanContext(SCONTEXTMAP *);
373 
374 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
375 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
376  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
377 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
378  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
379 static LONG SCardRemoveHandle(SCARDHANDLE);
380 
381 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
382  LPBYTE pbAttr, LPDWORD pcbAttrLen);
383 
384 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
385 
386 /*
387  * Thread safety functions
388  */
395 inline static LONG SCardLockThread(void)
396 {
397  return pthread_mutex_lock(&clientMutex);
398 }
399 
405 inline static LONG SCardUnlockThread(void)
406 {
407  return pthread_mutex_unlock(&clientMutex);
408 }
409 
410 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
411  /*@out@*/ LPSCARDCONTEXT);
412 
446 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
447  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
448 {
449  LONG rv;
450 
451  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
452  PROFILE_START
453 
454  /* Check if the server is running */
456  if (rv != SCARD_S_SUCCESS)
457  goto end;
458 
459  (void)SCardLockThread();
460  rv = SCardEstablishContextTH(dwScope, pvReserved1,
461  pvReserved2, phContext);
462  (void)SCardUnlockThread();
463 
464 end:
465  PROFILE_END(rv)
466  API_TRACE_OUT("%ld", *phContext)
467 
468  return rv;
469 }
470 
497 static LONG SCardEstablishContextTH(DWORD dwScope,
498  /*@unused@*/ LPCVOID pvReserved1,
499  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
500 {
501  LONG rv;
502  struct establish_struct scEstablishStruct;
503  uint32_t dwClientID = 0;
504 
505  (void)pvReserved1;
506  (void)pvReserved2;
507  if (phContext == NULL)
509  else
510  *phContext = 0;
511 
512  /*
513  * Do this only once:
514  * - Initialize context list.
515  */
516  if (isExecuted == 0)
517  {
518  int lrv;
519 
520  /* NOTE: The list will never be freed (No API call exists to
521  * "close all contexts".
522  * Applications which load and unload the library will leak
523  * the list's internal structures. */
524  lrv = list_init(&contextMapList);
525  if (lrv < 0)
526  {
527  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
528  lrv);
529  return SCARD_E_NO_MEMORY;
530  }
531 
532  lrv = list_attributes_seeker(&contextMapList,
533  SCONTEXTMAP_seeker);
534  if (lrv <0)
535  {
536  Log2(PCSC_LOG_CRITICAL,
537  "list_attributes_seeker failed with return value: %d", lrv);
538  list_destroy(&contextMapList);
539  return SCARD_E_NO_MEMORY;
540  }
541 
542  if (getenv("PCSCLITE_NO_BLOCKING"))
543  {
544  Log1(PCSC_LOG_INFO, "Disable shared blocking");
545  sharing_shall_block = FALSE;
546  }
547 
548  isExecuted = 1;
549  }
550 
551 
552  /* Establishes a connection to the server */
553  if (ClientSetupSession(&dwClientID) != 0)
554  {
555  return SCARD_E_NO_SERVICE;
556  }
557 
558  { /* exchange client/server protocol versions */
559  struct version_struct veStr;
560 
563  veStr.rv = SCARD_S_SUCCESS;
564 
565  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
566  &veStr);
567  if (rv != SCARD_S_SUCCESS)
568  return rv;
569 
570  /* Read a message from the server */
571  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
572  if (rv != SCARD_S_SUCCESS)
573  {
574  Log1(PCSC_LOG_CRITICAL,
575  "Your pcscd is too old and does not support CMD_VERSION");
576  return SCARD_F_COMM_ERROR;
577  }
578 
579  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
580  veStr.major, veStr.minor);
581 
582  if (veStr.rv != SCARD_S_SUCCESS)
583  return veStr.rv;
584  }
585 
586 again:
587  /*
588  * Try to establish an Application Context with the server
589  */
590  scEstablishStruct.dwScope = dwScope;
591  scEstablishStruct.hContext = 0;
592  scEstablishStruct.rv = SCARD_S_SUCCESS;
593 
595  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
596 
597  if (rv != SCARD_S_SUCCESS)
598  return rv;
599 
600  /*
601  * Read the response from the server
602  */
603  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
604  dwClientID);
605 
606  if (rv != SCARD_S_SUCCESS)
607  return rv;
608 
609  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
610  return scEstablishStruct.rv;
611 
612  /* check we do not reuse an existing hContext */
613  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
614  /* we do not need to release the allocated context since
615  * SCardReleaseContext() does nothing on the server side */
616  goto again;
617 
618  *phContext = scEstablishStruct.hContext;
619 
620  /*
621  * Allocate the new hContext - if allocator full return an error
622  */
623  rv = SCardAddContext(*phContext, dwClientID);
624 
625  return rv;
626 }
627 
650 {
651  LONG rv;
652  struct release_struct scReleaseStruct;
653  SCONTEXTMAP * currentContextMap;
654 
655  API_TRACE_IN("%ld", hContext)
656  PROFILE_START
657 
658  /*
659  * Make sure this context has been opened
660  * and get currentContextMap
661  */
662  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
663  if (NULL == currentContextMap)
664  {
666  goto error;
667  }
668 
669  scReleaseStruct.hContext = hContext;
670  scReleaseStruct.rv = SCARD_S_SUCCESS;
671 
673  currentContextMap->dwClientID,
674  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
675 
676  if (rv != SCARD_S_SUCCESS)
677  goto end;
678 
679  /*
680  * Read a message from the server
681  */
682  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
683  currentContextMap->dwClientID);
684 
685  if (rv != SCARD_S_SUCCESS)
686  goto end;
687 
688  rv = scReleaseStruct.rv;
689 end:
690  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
691 
692  /*
693  * Remove the local context from the stack
694  */
695  (void)SCardLockThread();
696  (void)SCardRemoveContext(hContext);
697  (void)SCardUnlockThread();
698 
699 error:
700  PROFILE_END(rv)
701  API_TRACE_OUT("")
702 
703  return rv;
704 }
705 
762 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
763  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
764  LPDWORD pdwActiveProtocol)
765 {
766  LONG rv;
767  struct connect_struct scConnectStruct;
768  SCONTEXTMAP * currentContextMap;
769 
770  PROFILE_START
771  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
772 
773  /*
774  * Check for NULL parameters
775  */
776  if (phCard == NULL || pdwActiveProtocol == NULL)
778  else
779  *phCard = 0;
780 
781  if (szReader == NULL)
782  return SCARD_E_UNKNOWN_READER;
783 
784  /*
785  * Check for uninitialized strings
786  */
787  if (strlen(szReader) > MAX_READERNAME)
788  return SCARD_E_INVALID_VALUE;
789 
790  /*
791  * Make sure this context has been opened
792  */
793  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
794  if (NULL == currentContextMap)
795  return SCARD_E_INVALID_HANDLE;
796 
797  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
798  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
799  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
800 
801  scConnectStruct.hContext = hContext;
802  scConnectStruct.dwShareMode = dwShareMode;
803  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
804  scConnectStruct.hCard = 0;
805  scConnectStruct.dwActiveProtocol = 0;
806  scConnectStruct.rv = SCARD_S_SUCCESS;
807 
808  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
809  sizeof(scConnectStruct), (void *) &scConnectStruct);
810 
811  if (rv != SCARD_S_SUCCESS)
812  goto end;
813 
814  /*
815  * Read a message from the server
816  */
817  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
818  currentContextMap->dwClientID);
819 
820  if (rv != SCARD_S_SUCCESS)
821  goto end;
822 
823  *phCard = scConnectStruct.hCard;
824  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
825 
826  if (scConnectStruct.rv == SCARD_S_SUCCESS)
827  {
828  /*
829  * Keep track of the handle locally
830  */
831  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
832  }
833  else
834  rv = scConnectStruct.rv;
835 
836 end:
837  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
838 
839  PROFILE_END(rv)
840  API_TRACE_OUT("%d", *pdwActiveProtocol)
841 
842  return rv;
843 }
844 
918 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
919  DWORD dwPreferredProtocols, DWORD dwInitialization,
920  LPDWORD pdwActiveProtocol)
921 {
922  LONG rv;
923  struct reconnect_struct scReconnectStruct;
924  SCONTEXTMAP * currentContextMap;
925  CHANNEL_MAP * pChannelMap;
926 
927  PROFILE_START
928  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
929 
930  if (pdwActiveProtocol == NULL)
932 
933  /* Retry loop for blocking behaviour */
934 retry:
935 
936  /*
937  * Make sure this handle has been opened
938  */
939  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
940  &pChannelMap);
941  if (rv == -1)
942  return SCARD_E_INVALID_HANDLE;
943 
944  scReconnectStruct.hCard = hCard;
945  scReconnectStruct.dwShareMode = dwShareMode;
946  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
947  scReconnectStruct.dwInitialization = dwInitialization;
948  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
949  scReconnectStruct.rv = SCARD_S_SUCCESS;
950 
951  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
952  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
953 
954  if (rv != SCARD_S_SUCCESS)
955  goto end;
956 
957  /*
958  * Read a message from the server
959  */
960  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
961  currentContextMap->dwClientID);
962 
963  if (rv != SCARD_S_SUCCESS)
964  goto end;
965 
966  rv = scReconnectStruct.rv;
967 
968  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
969  {
970  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
972  goto retry;
973  }
974 
975  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
976 
977 end:
978  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
979 
980  PROFILE_END(rv)
981  API_TRACE_OUT("%ld", *pdwActiveProtocol)
982 
983  return rv;
984 }
985 
1017 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1018 {
1019  LONG rv;
1020  struct disconnect_struct scDisconnectStruct;
1021  SCONTEXTMAP * currentContextMap;
1022  CHANNEL_MAP * pChannelMap;
1023 
1024  PROFILE_START
1025  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1026 
1027  /*
1028  * Make sure this handle has been opened
1029  */
1030  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1031  &pChannelMap);
1032  if (rv == -1)
1033  {
1035  goto error;
1036  }
1037 
1038  scDisconnectStruct.hCard = hCard;
1039  scDisconnectStruct.dwDisposition = dwDisposition;
1040  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1041 
1042  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1043  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1044 
1045  if (rv != SCARD_S_SUCCESS)
1046  goto end;
1047 
1048  /*
1049  * Read a message from the server
1050  */
1051  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1052  currentContextMap->dwClientID);
1053 
1054  if (rv != SCARD_S_SUCCESS)
1055  goto end;
1056 
1057  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1058  (void)SCardRemoveHandle(hCard);
1059  rv = scDisconnectStruct.rv;
1060 
1061 end:
1062  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1063 
1064 error:
1065  PROFILE_END(rv)
1066  API_TRACE_OUT("")
1067 
1068  return rv;
1069 }
1070 
1107 {
1108 
1109  LONG rv;
1110  struct begin_struct scBeginStruct;
1111  SCONTEXTMAP * currentContextMap;
1112  CHANNEL_MAP * pChannelMap;
1113 
1114  PROFILE_START
1115  API_TRACE_IN("%ld", hCard)
1116 
1117  /*
1118  * Query the server every so often until the sharing violation ends
1119  * and then hold the lock for yourself.
1120  */
1121 
1122  for(;;)
1123  {
1124  /*
1125  * Make sure this handle has been opened
1126  */
1127  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1128  &pChannelMap);
1129  if (rv == -1)
1130  return SCARD_E_INVALID_HANDLE;
1131 
1132  scBeginStruct.hCard = hCard;
1133  scBeginStruct.rv = SCARD_S_SUCCESS;
1134 
1136  currentContextMap->dwClientID,
1137  sizeof(scBeginStruct), (void *) &scBeginStruct);
1138 
1139  if (rv != SCARD_S_SUCCESS)
1140  break;
1141 
1142  /*
1143  * Read a message from the server
1144  */
1145  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1146  currentContextMap->dwClientID);
1147 
1148  if (rv != SCARD_S_SUCCESS)
1149  break;
1150 
1151  rv = scBeginStruct.rv;
1152 
1153  if (SCARD_E_SHARING_VIOLATION != rv)
1154  break;
1155 
1156  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1158  }
1159 
1160  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1161 
1162  PROFILE_END(rv)
1163  API_TRACE_OUT("")
1164 
1165  return rv;
1166 }
1167 
1207 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1208 {
1209  LONG rv;
1210  struct end_struct scEndStruct;
1211  int randnum;
1212  SCONTEXTMAP * currentContextMap;
1213  CHANNEL_MAP * pChannelMap;
1214 
1215  PROFILE_START
1216  API_TRACE_IN("%ld", hCard)
1217 
1218  /*
1219  * Make sure this handle has been opened
1220  */
1221  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1222  &pChannelMap);
1223  if (rv == -1)
1224  return SCARD_E_INVALID_HANDLE;
1225 
1226  scEndStruct.hCard = hCard;
1227  scEndStruct.dwDisposition = dwDisposition;
1228  scEndStruct.rv = SCARD_S_SUCCESS;
1229 
1231  currentContextMap->dwClientID,
1232  sizeof(scEndStruct), (void *) &scEndStruct);
1233 
1234  if (rv != SCARD_S_SUCCESS)
1235  goto end;
1236 
1237  /*
1238  * Read a message from the server
1239  */
1240  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1241  currentContextMap->dwClientID);
1242 
1243  if (rv != SCARD_S_SUCCESS)
1244  goto end;
1245 
1246  /*
1247  * This helps prevent starvation
1248  */
1249  randnum = SYS_RandomInt(1000, 10000);
1250  (void)SYS_USleep(randnum);
1251  rv = scEndStruct.rv;
1252 
1253 end:
1254  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1255 
1256  PROFILE_END(rv)
1257  API_TRACE_OUT("")
1258 
1259  return rv;
1260 }
1261 
1357 LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1358  LPDWORD pcchReaderLen, LPDWORD pdwState,
1359  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1360 {
1361  DWORD dwReaderLen, dwAtrLen;
1362  LONG rv;
1363  int i;
1364  struct status_struct scStatusStruct;
1365  SCONTEXTMAP * currentContextMap;
1366  CHANNEL_MAP * pChannelMap;
1367  char *r;
1368  char *bufReader = NULL;
1369  LPBYTE bufAtr = NULL;
1370  DWORD dummy = 0;
1371 
1372  PROFILE_START
1373 
1374  /* default output values */
1375  if (pdwState)
1376  *pdwState = 0;
1377 
1378  if (pdwProtocol)
1379  *pdwProtocol = 0;
1380 
1381  /* Check for NULL parameters */
1382  if (pcchReaderLen == NULL)
1383  pcchReaderLen = &dummy;
1384 
1385  if (pcbAtrLen == NULL)
1386  pcbAtrLen = &dummy;
1387 
1388  /* length passed from caller */
1389  dwReaderLen = *pcchReaderLen;
1390  dwAtrLen = *pcbAtrLen;
1391 
1392  *pcchReaderLen = 0;
1393  *pcbAtrLen = 0;
1394 
1395  /* Retry loop for blocking behaviour */
1396 retry:
1397 
1398  /*
1399  * Make sure this handle has been opened
1400  */
1401  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1402  &pChannelMap);
1403  if (rv == -1)
1404  return SCARD_E_INVALID_HANDLE;
1405 
1406  /* synchronize reader states with daemon */
1407  rv = getReaderStates(currentContextMap);
1408  if (rv != SCARD_S_SUCCESS)
1409  goto end;
1410 
1411  r = pChannelMap->readerName;
1412  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1413  {
1414  /* by default r == NULL */
1415  if (r && strcmp(r, readerStates[i].readerName) == 0)
1416  break;
1417  }
1418 
1419  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1420  {
1422  goto end;
1423  }
1424 
1425  /* initialise the structure */
1426  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1427  scStatusStruct.hCard = hCard;
1428 
1429  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1430  sizeof(scStatusStruct), (void *) &scStatusStruct);
1431 
1432  if (rv != SCARD_S_SUCCESS)
1433  goto end;
1434 
1435  /*
1436  * Read a message from the server
1437  */
1438  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1439  currentContextMap->dwClientID);
1440 
1441  if (rv != SCARD_S_SUCCESS)
1442  goto end;
1443 
1444  rv = scStatusStruct.rv;
1445 
1446  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1447  {
1448  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1450  goto retry;
1451  }
1452 
1453  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1454  {
1455  /*
1456  * An event must have occurred
1457  */
1458  goto end;
1459  }
1460 
1461  /*
1462  * Now continue with the client side SCardStatus
1463  */
1464 
1465  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1466  *pcbAtrLen = readerStates[i].cardAtrLength;
1467 
1468  if (pdwState)
1469  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1470 
1471  if (pdwProtocol)
1472  *pdwProtocol = readerStates[i].cardProtocol;
1473 
1474  if (SCARD_AUTOALLOCATE == dwReaderLen)
1475  {
1476  dwReaderLen = *pcchReaderLen;
1477  if (NULL == szReaderName)
1478  {
1480  goto end;
1481  }
1482  bufReader = malloc(dwReaderLen);
1483  if (NULL == bufReader)
1484  {
1485  rv = SCARD_E_NO_MEMORY;
1486  goto end;
1487  }
1488  *(char **)szReaderName = bufReader;
1489  }
1490  else
1491  bufReader = szReaderName;
1492 
1493  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1494  if (bufReader)
1495  {
1496  if (*pcchReaderLen > dwReaderLen)
1498 
1499  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1500  }
1501 
1502  if (SCARD_AUTOALLOCATE == dwAtrLen)
1503  {
1504  dwAtrLen = *pcbAtrLen;
1505  if (NULL == pbAtr)
1506  {
1508  goto end;
1509  }
1510  bufAtr = malloc(dwAtrLen);
1511  if (NULL == bufAtr)
1512  {
1513  rv = SCARD_E_NO_MEMORY;
1514  goto end;
1515  }
1516  *(LPBYTE *)pbAtr = bufAtr;
1517  }
1518  else
1519  bufAtr = pbAtr;
1520 
1521  if (bufAtr)
1522  {
1523  if (*pcbAtrLen > dwAtrLen)
1525 
1526  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1527  }
1528 
1529 end:
1530  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1531 
1532  PROFILE_END(rv)
1533 
1534  return rv;
1535 }
1536 
1640 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1641  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1642 {
1643  SCARD_READERSTATE *currReader;
1644  READER_STATE *rContext;
1645  long dwTime;
1646  DWORD dwBreakFlag = 0;
1647  unsigned int j;
1648  SCONTEXTMAP * currentContextMap;
1649  int currentReaderCount = 0;
1650  LONG rv = SCARD_S_SUCCESS;
1651 
1652  PROFILE_START
1653  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1654 #ifdef DO_TRACE
1655  for (j=0; j<cReaders; j++)
1656  {
1657  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1658  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1659  }
1660 #endif
1661 
1662  if ((rgReaderStates == NULL && cReaders > 0)
1663  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1664  {
1666  goto error;
1667  }
1668 
1669  /* Check the integrity of the reader states structures */
1670  for (j = 0; j < cReaders; j++)
1671  {
1672  if (rgReaderStates[j].szReader == NULL)
1673  return SCARD_E_INVALID_VALUE;
1674  }
1675 
1676  /* return if all readers are SCARD_STATE_IGNORE */
1677  if (cReaders > 0)
1678  {
1679  int nbNonIgnoredReaders = cReaders;
1680 
1681  for (j=0; j<cReaders; j++)
1682  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1683  nbNonIgnoredReaders--;
1684 
1685  if (0 == nbNonIgnoredReaders)
1686  {
1687  rv = SCARD_S_SUCCESS;
1688  goto error;
1689  }
1690  }
1691  else
1692  {
1693  /* reader list is empty */
1694  rv = SCARD_S_SUCCESS;
1695  goto error;
1696  }
1697 
1698  /*
1699  * Make sure this context has been opened
1700  */
1701  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
1702  if (NULL == currentContextMap)
1703  {
1705  goto error;
1706  }
1707 
1708  /* synchronize reader states with daemon */
1709  rv = getReaderStates(currentContextMap);
1710  if (rv != SCARD_S_SUCCESS)
1711  goto end;
1712 
1713  /* check all the readers are already known */
1714  for (j=0; j<cReaders; j++)
1715  {
1716  const char *readerName;
1717  int i;
1718 
1719  readerName = rgReaderStates[j].szReader;
1720  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1721  {
1722  if (strcmp(readerName, readerStates[i].readerName) == 0)
1723  break;
1724  }
1725 
1726  /* The requested reader name is not recognized */
1727  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1728  {
1729  /* PnP special reader? */
1730  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1731  {
1733  goto end;
1734  }
1735  }
1736  }
1737 
1738  /* Clear the event state for all readers */
1739  for (j = 0; j < cReaders; j++)
1740  rgReaderStates[j].dwEventState = 0;
1741 
1742  /* Now is where we start our event checking loop */
1743  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1744 
1745  /* Get the initial reader count on the system */
1746  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1747  if (readerStates[j].readerName[0] != '\0')
1748  currentReaderCount++;
1749 
1750  /* catch possible sign extension problems from 32 to 64-bits integers */
1751  if ((DWORD)-1 == dwTimeout)
1752  dwTimeout = INFINITE;
1753  if (INFINITE == dwTimeout)
1754  dwTime = 60*1000; /* "infinite" timeout */
1755  else
1756  dwTime = dwTimeout;
1757 
1758  j = 0;
1759  do
1760  {
1761  currReader = &rgReaderStates[j];
1762 
1763  /* Ignore for IGNORED readers */
1764  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1765  {
1766  const char *readerName;
1767  int i;
1768 
1769  /* Looks for correct readernames */
1770  readerName = currReader->szReader;
1771  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1772  {
1773  if (strcmp(readerName, readerStates[i].readerName) == 0)
1774  break;
1775  }
1776 
1777  /* The requested reader name is not recognized */
1778  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1779  {
1780  /* PnP special reader? */
1781  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1782  {
1783  int k, newReaderCount = 0;
1784 
1785  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1786  if (readerStates[k].readerName[0] != '\0')
1787  newReaderCount++;
1788 
1789  if (newReaderCount != currentReaderCount)
1790  {
1791  Log1(PCSC_LOG_INFO, "Reader list changed");
1792  currentReaderCount = newReaderCount;
1793 
1794  currReader->dwEventState |= SCARD_STATE_CHANGED;
1795  dwBreakFlag = 1;
1796  }
1797  }
1798  else
1799  {
1800  currReader->dwEventState =
1802  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1803  {
1804  currReader->dwEventState |= SCARD_STATE_CHANGED;
1805  /*
1806  * Spec says use SCARD_STATE_IGNORE but a removed USB
1807  * reader with eventState fed into currentState will
1808  * be ignored forever
1809  */
1810  dwBreakFlag = 1;
1811  }
1812  }
1813  }
1814  else
1815  {
1816  uint32_t readerState;
1817 
1818  /* The reader has come back after being away */
1819  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1820  {
1821  currReader->dwEventState |= SCARD_STATE_CHANGED;
1822  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1823  Log0(PCSC_LOG_DEBUG);
1824  dwBreakFlag = 1;
1825  }
1826 
1827  /* Set the reader status structure */
1828  rContext = &readerStates[i];
1829 
1830  /* Now we check all the Reader States */
1831  readerState = rContext->readerState;
1832 
1833  /* only if current state has an non null event counter */
1834  if (currReader->dwCurrentState & 0xFFFF0000)
1835  {
1836  unsigned int currentCounter;
1837 
1838  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1839 
1840  /* has the event counter changed since the last call? */
1841  if (rContext->eventCounter != currentCounter)
1842  {
1843  currReader->dwEventState |= SCARD_STATE_CHANGED;
1844  Log0(PCSC_LOG_DEBUG);
1845  dwBreakFlag = 1;
1846  }
1847  }
1848 
1849  /* add an event counter in the upper word of dwEventState */
1850  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1851  | (rContext->eventCounter << 16));
1852 
1853  /* Check if the reader is in the correct state */
1854  if (readerState & SCARD_UNKNOWN)
1855  {
1856  /* reader is in bad state */
1857  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1858  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1859  {
1860  /* App thinks reader is in good state and it is not */
1861  currReader->dwEventState |= SCARD_STATE_CHANGED;
1862  Log0(PCSC_LOG_DEBUG);
1863  dwBreakFlag = 1;
1864  }
1865  }
1866  else
1867  {
1868  /* App thinks reader in bad state but it is not */
1869  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1870  {
1871  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1872  currReader->dwEventState |= SCARD_STATE_CHANGED;
1873  Log0(PCSC_LOG_DEBUG);
1874  dwBreakFlag = 1;
1875  }
1876  }
1877 
1878  /* Check for card presence in the reader */
1879  if (readerState & SCARD_PRESENT)
1880  {
1881  /* card present but not yet powered up */
1882  if (0 == rContext->cardAtrLength)
1883  /* Allow the status thread to convey information */
1885 
1886  currReader->cbAtr = rContext->cardAtrLength;
1887  memcpy(currReader->rgbAtr, rContext->cardAtr,
1888  currReader->cbAtr);
1889  }
1890  else
1891  currReader->cbAtr = 0;
1892 
1893  /* Card is now absent */
1894  if (readerState & SCARD_ABSENT)
1895  {
1896  currReader->dwEventState |= SCARD_STATE_EMPTY;
1897  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1898  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1899  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1900  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1901  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1902  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1903  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1904  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1905 
1906  /* After present the rest are assumed */
1907  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1908  {
1909  currReader->dwEventState |= SCARD_STATE_CHANGED;
1910  Log0(PCSC_LOG_DEBUG);
1911  dwBreakFlag = 1;
1912  }
1913  }
1914  /* Card is now present */
1915  else if (readerState & SCARD_PRESENT)
1916  {
1917  currReader->dwEventState |= SCARD_STATE_PRESENT;
1918  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1919  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1920  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1921  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1922  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1923  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1924 
1925  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1926  {
1927  currReader->dwEventState |= SCARD_STATE_CHANGED;
1928  Log0(PCSC_LOG_DEBUG);
1929  dwBreakFlag = 1;
1930  }
1931 
1932  if (readerState & SCARD_SWALLOWED)
1933  {
1934  currReader->dwEventState |= SCARD_STATE_MUTE;
1935  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1936  {
1937  currReader->dwEventState |= SCARD_STATE_CHANGED;
1938  Log0(PCSC_LOG_DEBUG);
1939  dwBreakFlag = 1;
1940  }
1941  }
1942  else
1943  {
1944  /* App thinks card is mute but it is not */
1945  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1946  {
1947  currReader->dwEventState |= SCARD_STATE_CHANGED;
1948  Log0(PCSC_LOG_DEBUG);
1949  dwBreakFlag = 1;
1950  }
1951  }
1952  }
1953 
1954  /* Now figure out sharing modes */
1956  {
1957  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1958  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1959  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1960  {
1961  currReader->dwEventState |= SCARD_STATE_CHANGED;
1962  Log0(PCSC_LOG_DEBUG);
1963  dwBreakFlag = 1;
1964  }
1965  }
1966  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
1967  {
1968  /* A card must be inserted for it to be INUSE */
1969  if (readerState & SCARD_PRESENT)
1970  {
1971  currReader->dwEventState |= SCARD_STATE_INUSE;
1972  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1973  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
1974  {
1975  currReader->dwEventState |= SCARD_STATE_CHANGED;
1976  Log0(PCSC_LOG_DEBUG);
1977  dwBreakFlag = 1;
1978  }
1979  }
1980  }
1981  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
1982  {
1983  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1984  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1985 
1986  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1987  {
1988  currReader->dwEventState |= SCARD_STATE_CHANGED;
1989  Log0(PCSC_LOG_DEBUG);
1990  dwBreakFlag = 1;
1991  }
1992  else if (currReader-> dwCurrentState
1994  {
1995  currReader->dwEventState |= SCARD_STATE_CHANGED;
1996  Log0(PCSC_LOG_DEBUG);
1997  dwBreakFlag = 1;
1998  }
1999  }
2000 
2001  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2002  {
2003  /*
2004  * Break out of the while .. loop and return status
2005  * once all the status's for all readers is met
2006  */
2007  currReader->dwEventState |= SCARD_STATE_CHANGED;
2008  Log0(PCSC_LOG_DEBUG);
2009  dwBreakFlag = 1;
2010  }
2011  } /* End of SCARD_STATE_UNKNOWN */
2012  } /* End of SCARD_STATE_IGNORE */
2013 
2014  /* Counter and resetter */
2015  j++;
2016  if (j == cReaders)
2017  {
2018  /* go back to the first reader */
2019  j = 0;
2020 
2021  /* Declare all the break conditions */
2022 
2023  /* Break if UNAWARE is set and all readers have been checked */
2024  if (dwBreakFlag == 1)
2025  break;
2026 
2027  /* Only sleep once for each cycle of reader checks. */
2028  {
2029  struct wait_reader_state_change waitStatusStruct;
2030  struct timeval before, after;
2031 
2032  gettimeofday(&before, NULL);
2033 
2034  waitStatusStruct.timeOut = dwTime;
2035  waitStatusStruct.rv = SCARD_S_SUCCESS;
2036 
2037  /* another thread can do SCardCancel() */
2038  currentContextMap->cancellable = TRUE;
2039 
2041  currentContextMap->dwClientID,
2042  sizeof(waitStatusStruct), &waitStatusStruct);
2043 
2044  if (rv != SCARD_S_SUCCESS)
2045  goto end;
2046 
2047  /*
2048  * Read a message from the server
2049  */
2051  &waitStatusStruct, sizeof(waitStatusStruct),
2052  currentContextMap->dwClientID, dwTime);
2053 
2054  /* another thread can do SCardCancel() */
2055  currentContextMap->cancellable = FALSE;
2056 
2057  /* timeout */
2058  if (SCARD_E_TIMEOUT == rv)
2059  {
2060  /* ask server to remove us from the event list */
2062  currentContextMap->dwClientID,
2063  sizeof(waitStatusStruct), &waitStatusStruct);
2064 
2065  if (rv != SCARD_S_SUCCESS)
2066  goto end;
2067 
2068  /* Read a message from the server */
2069  rv = MessageReceive(&waitStatusStruct,
2070  sizeof(waitStatusStruct),
2071  currentContextMap->dwClientID);
2072 
2073  if (rv != SCARD_S_SUCCESS)
2074  goto end;
2075  }
2076 
2077  if (rv != SCARD_S_SUCCESS)
2078  goto end;
2079 
2080  /* an event occurs or SCardCancel() was called */
2081  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2082  {
2083  rv = waitStatusStruct.rv;
2084  goto end;
2085  }
2086 
2087  /* synchronize reader states with daemon */
2088  rv = getReaderStates(currentContextMap);
2089  if (rv != SCARD_S_SUCCESS)
2090  goto end;
2091 
2092  if (INFINITE != dwTimeout)
2093  {
2094  long int diff;
2095 
2096  gettimeofday(&after, NULL);
2097  diff = time_sub(&after, &before);
2098  dwTime -= diff/1000;
2099  }
2100  }
2101 
2102  if (dwTimeout != INFINITE)
2103  {
2104  /* If time is greater than timeout and all readers have been
2105  * checked
2106  */
2107  if (dwTime <= 0)
2108  {
2109  rv = SCARD_E_TIMEOUT;
2110  goto end;
2111  }
2112  }
2113  }
2114  }
2115  while (1);
2116 
2117 end:
2118  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2119 
2120  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2121 
2122 error:
2123  PROFILE_END(rv)
2124 #ifdef DO_TRACE
2125  for (j=0; j<cReaders; j++)
2126  {
2127  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2128  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2129  }
2130 #endif
2131 
2132  return rv;
2133 }
2134 
2185 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2186  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2187  LPDWORD lpBytesReturned)
2188 {
2189  LONG rv;
2190  struct control_struct scControlStruct;
2191  SCONTEXTMAP * currentContextMap;
2192  CHANNEL_MAP * pChannelMap;
2193 
2194  PROFILE_START
2195 
2196  /* 0 bytes received by default */
2197  if (NULL != lpBytesReturned)
2198  *lpBytesReturned = 0;
2199 
2200  /*
2201  * Make sure this handle has been opened
2202  */
2203  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2204  &pChannelMap);
2205  if (rv == -1)
2206  {
2207  PROFILE_END(SCARD_E_INVALID_HANDLE)
2208  return SCARD_E_INVALID_HANDLE;
2209  }
2210 
2211  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2212  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2213  {
2215  goto end;
2216  }
2217 
2218  scControlStruct.hCard = hCard;
2219  scControlStruct.dwControlCode = dwControlCode;
2220  scControlStruct.cbSendLength = cbSendLength;
2221  scControlStruct.cbRecvLength = cbRecvLength;
2222  scControlStruct.dwBytesReturned = 0;
2223  scControlStruct.rv = 0;
2224 
2225  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2226  sizeof(scControlStruct), &scControlStruct);
2227 
2228  if (rv != SCARD_S_SUCCESS)
2229  goto end;
2230 
2231  /* write the sent buffer */
2232  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2233  currentContextMap->dwClientID);
2234 
2235  if (rv != SCARD_S_SUCCESS)
2236  goto end;
2237 
2238  /*
2239  * Read a message from the server
2240  */
2241  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2242  currentContextMap->dwClientID);
2243 
2244  if (rv != SCARD_S_SUCCESS)
2245  goto end;
2246 
2247  if (SCARD_S_SUCCESS == scControlStruct.rv)
2248  {
2249  /* read the received buffer */
2250  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2251  currentContextMap->dwClientID);
2252 
2253  if (rv != SCARD_S_SUCCESS)
2254  goto end;
2255 
2256  }
2257 
2258  if (NULL != lpBytesReturned)
2259  *lpBytesReturned = scControlStruct.dwBytesReturned;
2260 
2261  rv = scControlStruct.rv;
2262 
2263 end:
2264  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2265 
2266  PROFILE_END(rv)
2267 
2268  return rv;
2269 }
2270 
2386 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2387  LPDWORD pcbAttrLen)
2388 {
2389  LONG ret;
2390  unsigned char *buf = NULL;
2391 
2392  PROFILE_START
2393 
2394  if (NULL == pcbAttrLen)
2395  {
2397  goto end;
2398  }
2399 
2400  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2401  {
2402  if (NULL == pbAttr)
2404 
2405  *pcbAttrLen = MAX_BUFFER_SIZE;
2406  buf = malloc(*pcbAttrLen);
2407  if (NULL == buf)
2408  {
2409  ret = SCARD_E_NO_MEMORY;
2410  goto end;
2411  }
2412 
2413  *(unsigned char **)pbAttr = buf;
2414  }
2415  else
2416  {
2417  buf = pbAttr;
2418 
2419  /* if only get the length */
2420  if (NULL == pbAttr)
2421  /* use a reasonable size */
2422  *pcbAttrLen = MAX_BUFFER_SIZE;
2423  }
2424 
2425  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2426  pcbAttrLen);
2427 
2428 end:
2429  PROFILE_END(ret)
2430 
2431  return ret;
2432 }
2433 
2469 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2470  DWORD cbAttrLen)
2471 {
2472  LONG ret;
2473 
2474  PROFILE_START
2475 
2476  if (NULL == pbAttr || 0 == cbAttrLen)
2478 
2479  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2480  &cbAttrLen);
2481 
2482  PROFILE_END(ret)
2483 
2484  return ret;
2485 }
2486 
2487 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2488  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2489 {
2490  LONG rv;
2491  struct getset_struct scGetSetStruct;
2492  SCONTEXTMAP * currentContextMap;
2493  CHANNEL_MAP * pChannelMap;
2494 
2495  /*
2496  * Make sure this handle has been opened
2497  */
2498  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2499  &pChannelMap);
2500  if (rv == -1)
2501  return SCARD_E_INVALID_HANDLE;
2502 
2503  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2504  {
2506  goto end;
2507  }
2508 
2509  scGetSetStruct.hCard = hCard;
2510  scGetSetStruct.dwAttrId = dwAttrId;
2511  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2512  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2513  if (SCARD_SET_ATTRIB == command)
2514  {
2515  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2516  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2517  }
2518  else
2519  /* we can get up to the communication buffer size */
2520  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2521 
2522  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2523  sizeof(scGetSetStruct), &scGetSetStruct);
2524 
2525  if (rv != SCARD_S_SUCCESS)
2526  goto end;
2527 
2528  /*
2529  * Read a message from the server
2530  */
2531  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2532  currentContextMap->dwClientID);
2533 
2534  if (rv != SCARD_S_SUCCESS)
2535  goto end;
2536 
2537  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2538  {
2539  /*
2540  * Copy and zero it so any secret information is not leaked
2541  */
2542  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2543  {
2544  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2545  * buffer overflow in the memcpy() bellow */
2546  DWORD correct_value = scGetSetStruct.cbAttrLen;
2547  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2548  *pcbAttrLen = correct_value;
2549 
2550  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2551  }
2552  else
2553  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2554 
2555  if (pbAttr)
2556  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2557 
2558  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2559  }
2560  rv = scGetSetStruct.rv;
2561 
2562 end:
2563  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2564 
2565  return rv;
2566 }
2567 
2626 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2627  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2628  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2629  LPDWORD pcbRecvLength)
2630 {
2631  LONG rv;
2632  SCONTEXTMAP * currentContextMap;
2633  CHANNEL_MAP * pChannelMap;
2634  struct transmit_struct scTransmitStruct;
2635 
2636  PROFILE_START
2637 
2638  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2639  pcbRecvLength == NULL || pioSendPci == NULL)
2641 
2642  /* Retry loop for blocking behaviour */
2643 retry:
2644 
2645  /*
2646  * Make sure this handle has been opened
2647  */
2648  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2649  &pChannelMap);
2650  if (rv == -1)
2651  {
2652  *pcbRecvLength = 0;
2653  PROFILE_END(SCARD_E_INVALID_HANDLE)
2654  return SCARD_E_INVALID_HANDLE;
2655  }
2656 
2657  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2658  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2659  {
2661  goto end;
2662  }
2663 
2664  scTransmitStruct.hCard = hCard;
2665  scTransmitStruct.cbSendLength = cbSendLength;
2666  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2667  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2668  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2669  scTransmitStruct.rv = SCARD_S_SUCCESS;
2670 
2671  if (pioRecvPci)
2672  {
2673  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2674  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2675  }
2676  else
2677  {
2678  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2679  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2680  }
2681 
2682  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2683  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2684 
2685  if (rv != SCARD_S_SUCCESS)
2686  goto end;
2687 
2688  /* write the sent buffer */
2689  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2690  currentContextMap->dwClientID);
2691 
2692  if (rv != SCARD_S_SUCCESS)
2693  goto end;
2694 
2695  /*
2696  * Read a message from the server
2697  */
2698  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2699  currentContextMap->dwClientID);
2700 
2701  if (rv != SCARD_S_SUCCESS)
2702  goto end;
2703 
2704  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2705  {
2706  /* read the received buffer */
2707  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2708  currentContextMap->dwClientID);
2709 
2710  if (rv != SCARD_S_SUCCESS)
2711  goto end;
2712 
2713  if (pioRecvPci)
2714  {
2715  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2716  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2717  }
2718  }
2719 
2720  rv = scTransmitStruct.rv;
2721 
2722  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2723  {
2724  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2726  goto retry;
2727  }
2728 
2729  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2730 
2731 end:
2732  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2733 
2734  PROFILE_END(rv)
2735 
2736  return rv;
2737 }
2738 
2792 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2793  LPSTR mszReaders, LPDWORD pcchReaders)
2794 {
2795  DWORD dwReadersLen = 0;
2796  int i;
2797  SCONTEXTMAP * currentContextMap;
2798  LONG rv = SCARD_S_SUCCESS;
2799  char *buf = NULL;
2800 
2801  (void)mszGroups;
2802  PROFILE_START
2803  API_TRACE_IN("%ld", hContext)
2804 
2805  /*
2806  * Check for NULL parameters
2807  */
2808  if (pcchReaders == NULL)
2810 
2811  /*
2812  * Make sure this context has been opened
2813  */
2814  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2815  if (NULL == currentContextMap)
2816  {
2817  PROFILE_END(SCARD_E_INVALID_HANDLE)
2818  return SCARD_E_INVALID_HANDLE;
2819  }
2820 
2821  /* synchronize reader states with daemon */
2822  rv = getReaderStates(currentContextMap);
2823  if (rv != SCARD_S_SUCCESS)
2824  goto end;
2825 
2826  dwReadersLen = 0;
2827  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2828  if (readerStates[i].readerName[0] != '\0')
2829  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2830 
2831  /* for the last NULL byte */
2832  dwReadersLen += 1;
2833 
2834  if (1 == dwReadersLen)
2835  {
2837  goto end;
2838  }
2839 
2840  if (SCARD_AUTOALLOCATE == *pcchReaders)
2841  {
2842  if (NULL == mszReaders)
2843  {
2845  goto end;
2846  }
2847  buf = malloc(dwReadersLen);
2848  if (NULL == buf)
2849  {
2850  rv = SCARD_E_NO_MEMORY;
2851  goto end;
2852  }
2853  *(char **)mszReaders = buf;
2854  }
2855  else
2856  {
2857  buf = mszReaders;
2858 
2859  /* not enough place to store the reader names */
2860  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2861  {
2863  goto end;
2864  }
2865  }
2866 
2867  if (mszReaders == NULL) /* text array not allocated */
2868  goto end;
2869 
2870  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2871  {
2872  if (readerStates[i].readerName[0] != '\0')
2873  {
2874  /*
2875  * Build the multi-string
2876  */
2877  strcpy(buf, readerStates[i].readerName);
2878  buf += strlen(readerStates[i].readerName)+1;
2879  }
2880  }
2881  *buf = '\0'; /* Add the last null */
2882 
2883 end:
2884  /* set the reader names length */
2885  *pcchReaders = dwReadersLen;
2886 
2887  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2888 
2889  PROFILE_END(rv)
2890  API_TRACE_OUT("%d", *pcchReaders)
2891 
2892  return rv;
2893 }
2894 
2908 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2909 {
2910  LONG rv = SCARD_S_SUCCESS;
2911  SCONTEXTMAP * currentContextMap;
2912 
2913  PROFILE_START
2914 
2915  /*
2916  * Make sure this context has been opened
2917  */
2918  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
2919  if (NULL == currentContextMap)
2920  return SCARD_E_INVALID_HANDLE;
2921 
2922  free((void *)pvMem);
2923 
2924  PROFILE_END(rv)
2925 
2926  return rv;
2927 }
2928 
2980 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2981  LPDWORD pcchGroups)
2982 {
2983  LONG rv = SCARD_S_SUCCESS;
2984  SCONTEXTMAP * currentContextMap;
2985  char *buf = NULL;
2986 
2987  PROFILE_START
2988 
2989  /* Multi-string with two trailing \0 */
2990  const char ReaderGroup[] = "SCard$DefaultReaders\0";
2991  const unsigned int dwGroups = sizeof(ReaderGroup);
2992 
2993  /*
2994  * Make sure this context has been opened
2995  */
2996  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2997  if (NULL == currentContextMap)
2998  return SCARD_E_INVALID_HANDLE;
2999 
3000  if (SCARD_AUTOALLOCATE == *pcchGroups)
3001  {
3002  if (NULL == mszGroups)
3003  {
3005  goto end;
3006  }
3007  buf = malloc(dwGroups);
3008  if (NULL == buf)
3009  {
3010  rv = SCARD_E_NO_MEMORY;
3011  goto end;
3012  }
3013  *(char **)mszGroups = buf;
3014  }
3015  else
3016  {
3017  buf = mszGroups;
3018 
3019  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3020  {
3022  goto end;
3023  }
3024  }
3025 
3026  if (buf)
3027  memcpy(buf, ReaderGroup, dwGroups);
3028 
3029 end:
3030  *pcchGroups = dwGroups;
3031 
3032  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3033 
3034  PROFILE_END(rv)
3035 
3036  return rv;
3037 }
3038 
3070 {
3071  SCONTEXTMAP * currentContextMap;
3072  LONG rv = SCARD_S_SUCCESS;
3073  uint32_t dwClientID = 0;
3074  struct cancel_struct scCancelStruct;
3075 
3076  PROFILE_START
3077  API_TRACE_IN("%ld", hContext)
3078 
3079  /*
3080  * Make sure this context has been opened
3081  */
3082  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3083  if (NULL == currentContextMap)
3084  {
3086  goto error;
3087  }
3088 
3089  if (! currentContextMap->cancellable)
3090  {
3091  rv = SCARD_S_SUCCESS;
3092  goto error;
3093  }
3094 
3095  /* create a new connection to the server */
3096  if (ClientSetupSession(&dwClientID) != 0)
3097  {
3098  rv = SCARD_E_NO_SERVICE;
3099  goto error;
3100  }
3101 
3102  scCancelStruct.hContext = hContext;
3103  scCancelStruct.rv = SCARD_S_SUCCESS;
3104 
3105  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3106  sizeof(scCancelStruct), (void *) &scCancelStruct);
3107 
3108  if (rv != SCARD_S_SUCCESS)
3109  goto end;
3110 
3111  /*
3112  * Read a message from the server
3113  */
3114  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3115 
3116  if (rv != SCARD_S_SUCCESS)
3117  goto end;
3118 
3119  rv = scCancelStruct.rv;
3120 end:
3121  ClientCloseSession(dwClientID);
3122 
3123 error:
3124  PROFILE_END(rv)
3125  API_TRACE_OUT("")
3126 
3127  return rv;
3128 }
3129 
3154 {
3155  LONG rv;
3156  SCONTEXTMAP * currentContextMap;
3157 
3158  PROFILE_START
3159  API_TRACE_IN("%ld", hContext)
3160 
3161  rv = SCARD_S_SUCCESS;
3162 
3163  /*
3164  * Make sure this context has been opened
3165  */
3166  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3167  if (currentContextMap == NULL)
3169 
3170  PROFILE_END(rv)
3171  API_TRACE_OUT("")
3172 
3173  return rv;
3174 }
3175 
3192 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3193 {
3194  int lrv;
3195  SCONTEXTMAP * newContextMap;
3196 
3197  newContextMap = malloc(sizeof(SCONTEXTMAP));
3198  if (NULL == newContextMap)
3199  return SCARD_E_NO_MEMORY;
3200 
3201  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3202  newContextMap->hContext = hContext;
3203  newContextMap->dwClientID = dwClientID;
3204  newContextMap->cancellable = FALSE;
3205 
3206  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3207 
3208  lrv = list_init(&newContextMap->channelMapList);
3209  if (lrv < 0)
3210  {
3211  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3212  goto error;
3213  }
3214 
3215  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3216  CHANNEL_MAP_seeker);
3217  if (lrv <0)
3218  {
3219  Log2(PCSC_LOG_CRITICAL,
3220  "list_attributes_seeker failed with return value: %d", lrv);
3221  list_destroy(&newContextMap->channelMapList);
3222  goto error;
3223  }
3224 
3225  lrv = list_append(&contextMapList, newContextMap);
3226  if (lrv < 0)
3227  {
3228  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3229  lrv);
3230  list_destroy(&newContextMap->channelMapList);
3231  goto error;
3232  }
3233 
3234  return SCARD_S_SUCCESS;
3235 
3236 error:
3237 
3238  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3239  free(newContextMap);
3240 
3241  return SCARD_E_NO_MEMORY;
3242 }
3243 
3258 {
3259  SCONTEXTMAP * currentContextMap;
3260 
3261  (void)SCardLockThread();
3262  currentContextMap = SCardGetContextTH(hContext);
3263 
3264  /* lock the context (if available) */
3265  if (lock && NULL != currentContextMap)
3266  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3267 
3268  (void)SCardUnlockThread();
3269 
3270  return currentContextMap;
3271 }
3272 
3286 {
3287  return list_seek(&contextMapList, &hContext);
3288 }
3289 
3299 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3300 {
3301  SCONTEXTMAP * currentContextMap;
3302  currentContextMap = SCardGetContextTH(hContext);
3303 
3304  if (NULL == currentContextMap)
3305  return SCARD_E_INVALID_HANDLE;
3306  else
3307  return SCardCleanContext(currentContextMap);
3308 }
3309 
3310 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3311 {
3312  int list_index, lrv;
3313  int listSize;
3314  CHANNEL_MAP * currentChannelMap;
3315 
3316  targetContextMap->hContext = 0;
3317  (void)ClientCloseSession(targetContextMap->dwClientID);
3318  targetContextMap->dwClientID = 0;
3319  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3320 
3321  listSize = list_size(&targetContextMap->channelMapList);
3322  for (list_index = 0; list_index < listSize; list_index++)
3323  {
3324  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3325  list_index);
3326  if (NULL == currentChannelMap)
3327  {
3328  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3329  list_index);
3330  continue;
3331  }
3332  else
3333  {
3334  free(currentChannelMap->readerName);
3335  free(currentChannelMap);
3336  }
3337 
3338  }
3339  list_destroy(&targetContextMap->channelMapList);
3340 
3341  lrv = list_delete(&contextMapList, targetContextMap);
3342  if (lrv < 0)
3343  {
3344  Log2(PCSC_LOG_CRITICAL,
3345  "list_delete failed with return value: %d", lrv);
3346  }
3347 
3348  free(targetContextMap);
3349 
3350  return SCARD_S_SUCCESS;
3351 }
3352 
3353 /*
3354  * Functions for managing hCard values returned from SCardConnect.
3355  */
3356 
3357 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3358  LPCSTR readerName)
3359 {
3360  CHANNEL_MAP * newChannelMap;
3361  int lrv = -1;
3362 
3363  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3364  if (NULL == newChannelMap)
3365  return SCARD_E_NO_MEMORY;
3366 
3367  newChannelMap->hCard = hCard;
3368  newChannelMap->readerName = strdup(readerName);
3369 
3370  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3371  if (lrv < 0)
3372  {
3373  free(newChannelMap->readerName);
3374  free(newChannelMap);
3375  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3376  lrv);
3377  return SCARD_E_NO_MEMORY;
3378  }
3379 
3380  return SCARD_S_SUCCESS;
3381 }
3382 
3383 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3384 {
3385  SCONTEXTMAP * currentContextMap;
3386  CHANNEL_MAP * currentChannelMap;
3387  int lrv;
3388  LONG rv;
3389 
3390  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3391  &currentChannelMap);
3392  if (rv == -1)
3393  return SCARD_E_INVALID_HANDLE;
3394 
3395  free(currentChannelMap->readerName);
3396 
3397  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3398  if (lrv < 0)
3399  {
3400  Log2(PCSC_LOG_CRITICAL,
3401  "list_delete failed with return value: %d", lrv);
3402  }
3403 
3404  free(currentChannelMap);
3405 
3406  return SCARD_S_SUCCESS;
3407 }
3408 
3409 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3410  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3411 {
3412  LONG rv;
3413 
3414  if (0 == hCard)
3415  return -1;
3416 
3417  (void)SCardLockThread();
3418  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3419  targetChannelMap);
3420 
3421  if (SCARD_S_SUCCESS == rv)
3422  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3423 
3424  (void)SCardUnlockThread();
3425 
3426  return rv;
3427 }
3428 
3429 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3430  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3431 {
3432  int listSize;
3433  int list_index;
3434  SCONTEXTMAP * currentContextMap;
3435  CHANNEL_MAP * currentChannelMap;
3436 
3437  /* Best to get the caller a crash early if we fail unsafely */
3438  *targetContextMap = NULL;
3439  *targetChannelMap = NULL;
3440 
3441  listSize = list_size(&contextMapList);
3442 
3443  for (list_index = 0; list_index < listSize; list_index++)
3444  {
3445  currentContextMap = list_get_at(&contextMapList, list_index);
3446  if (currentContextMap == NULL)
3447  {
3448  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3449  list_index);
3450  continue;
3451  }
3452  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3453  &hCard);
3454  if (currentChannelMap != NULL)
3455  {
3456  *targetContextMap = currentContextMap;
3457  *targetChannelMap = currentChannelMap;
3458  return SCARD_S_SUCCESS;
3459  }
3460  }
3461 
3462  return -1;
3463 }
3464 
3473 {
3474  LONG rv;
3475  struct stat statBuffer;
3476  char *socketName;
3477 
3478  socketName = getSocketName();
3479  rv = stat(socketName, &statBuffer);
3480 
3481  if (rv != 0)
3482  {
3483  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3484  socketName, strerror(errno));
3485  return SCARD_E_NO_SERVICE;
3486  }
3487 
3488  return SCARD_S_SUCCESS;
3489 }
3490 
3491 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3492 {
3493  int32_t dwClientID = currentContextMap->dwClientID;
3494  LONG rv;
3495 
3496  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3497  if (rv != SCARD_S_SUCCESS)
3498  return rv;
3499 
3500  /* Read a message from the server */
3501  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3502  if (rv != SCARD_S_SUCCESS)
3503  return rv;
3504 
3505  return SCARD_S_SUCCESS;
3506 }
3507 
#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
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
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:172
#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
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
PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:77
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:315
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
used by SCardEndTransaction()
Definition: winscard_msg.h:83
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT, int)
Get the index from the Application Context vector _psContextMap for the passed context.
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.
static LONG SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
static LONG SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
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 all pending blocking requests on the SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:83
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 the 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
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
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:449
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
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
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
static LONG SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
#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:351
used by SCardDisconnect()
Definition: winscard_msg.h:81
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
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275