pcsc-lite  1.8.3
winscard_clnt.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 1999-2004
5  * David Corcoran <corcoran@linuxnet.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  * $Id: winscard_clnt.c 6105 2011-11-14 10:19:44Z rousseau $
16  */
17 
84 #include "config.h"
85 #include <stdlib.h>
86 #include <string.h>
87 #include <sys/types.h>
88 #include <fcntl.h>
89 #include <unistd.h>
90 #include <sys/un.h>
91 #include <errno.h>
92 #include <stddef.h>
93 #include <sys/time.h>
94 #include <pthread.h>
95 #include <sys/wait.h>
96 
97 #include "misc.h"
98 #include "pcscd.h"
99 #include "winscard.h"
100 #include "debuglog.h"
101 #include "strlcpycat.h"
102 
103 #include "readerfactory.h"
104 #include "eventhandler.h"
105 #include "sys_generic.h"
106 #include "winscard_msg.h"
107 #include "utils.h"
108 
109 /* Display, on stderr, a trace of the WinSCard calls with arguments and
110  * results */
111 #undef DO_TRACE
112 
113 /* Profile the execution time of WinSCard calls */
114 #undef DO_PROFILE
115 
116 
118 #define SCARD_PROTOCOL_ANY_OLD 0x1000
119 
120 #ifndef TRUE
121 #define TRUE 1
122 #define FALSE 0
123 #endif
124 
125 static char sharing_shall_block = TRUE;
126 
127 #define COLOR_RED "\33[01;31m"
128 #define COLOR_GREEN "\33[32m"
129 #define COLOR_BLUE "\33[34m"
130 #define COLOR_MAGENTA "\33[35m"
131 #define COLOR_NORMAL "\33[0m"
132 
133 #ifdef DO_TRACE
134 
135 #include <stdio.h>
136 #include <stdarg.h>
137 
138 static void trace(const char *func, const char direction, const char *fmt, ...)
139 {
140  va_list args;
141 
142  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
143  direction, pthread_self(), func);
144 
145  fprintf(stderr, COLOR_MAGENTA);
146  va_start(args, fmt);
147  vfprintf(stderr, fmt, args);
148  va_end(args);
149 
150  fprintf(stderr, COLOR_NORMAL "\n");
151 }
152 
153 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
154 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
155 #else
156 #define API_TRACE_IN(...)
157 #define API_TRACE_OUT(...)
158 #endif
159 
160 #ifdef DO_PROFILE
161 
162 #define PROFILE_FILE "/tmp/pcsc_profile"
163 #include <stdio.h>
164 #include <sys/time.h>
165 
166 /* we can profile a maximum of 5 simultaneous calls */
167 #define MAX_THREADS 5
168 pthread_t threads[MAX_THREADS];
169 struct timeval profile_time_start[MAX_THREADS];
170 FILE *profile_fd;
171 char profile_tty;
172 
173 #define PROFILE_START profile_start();
174 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
175 
176 static void profile_start(void)
177 {
178  static char initialized = FALSE;
179  pthread_t t;
180  int i;
181 
182  if (!initialized)
183  {
184  char filename[80];
185 
186  initialized = TRUE;
187  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
188  profile_fd = fopen(filename, "a+");
189  if (NULL == profile_fd)
190  {
191  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
192  PROFILE_FILE, strerror(errno));
193  exit(-1);
194  }
195  fprintf(profile_fd, "\nStart a new profile\n");
196 
197  if (isatty(fileno(stderr)))
198  profile_tty = TRUE;
199  else
200  profile_tty = FALSE;
201  }
202 
203  t = pthread_self();
204  for (i=0; i<MAX_THREADS; i++)
205  if (pthread_equal(0, threads[i]))
206  {
207  threads[i] = t;
208  break;
209  }
210 
211  gettimeofday(&profile_time_start[i], NULL);
212 } /* profile_start */
213 
214 static void profile_end(const char *f, LONG rv)
215 {
216  struct timeval profile_time_end;
217  long d;
218  pthread_t t;
219  int i;
220 
221  gettimeofday(&profile_time_end, NULL);
222 
223  t = pthread_self();
224  for (i=0; i<MAX_THREADS; i++)
225  if (pthread_equal(t, threads[i]))
226  break;
227 
228  if (i>=MAX_THREADS)
229  {
230  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
231  return;
232  }
233 
234  d = time_sub(&profile_time_end, &profile_time_start[i]);
235 
236  /* free this entry */
237  threads[i] = 0;
238 
239  if (profile_tty)
240  {
241  if (rv != SCARD_S_SUCCESS)
242  fprintf(stderr,
243  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
244  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
245  f, d, rv, pcsc_stringify_error(rv));
246  else
247  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
248  COLOR_NORMAL "\n", f, d);
249  }
250  fprintf(profile_fd, "%s %ld\n", f, d);
251  fflush(profile_fd);
252 } /* profile_end */
253 
254 #else
255 #define PROFILE_START
256 #define PROFILE_END(rv)
257 #endif
258 
264 {
265  SCARDHANDLE hCard;
266  LPSTR readerName;
267 };
268 
269 typedef struct _psChannelMap CHANNEL_MAP;
270 
271 static int CHANNEL_MAP_seeker(const void *el, const void *key)
272 {
273  const CHANNEL_MAP * channelMap = el;
274 
275  if ((el == NULL) || (key == NULL))
276  {
277  Log3(PCSC_LOG_CRITICAL,
278  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
279  el, key);
280  return 0;
281  }
282 
283  if (channelMap->hCard == *(SCARDHANDLE *)key)
284  return 1;
285 
286  return 0;
287 }
288 
295 {
296  DWORD dwClientID;
298  pthread_mutex_t * mMutex;
299  list_t channelMapList;
300  char cancellable;
301 };
302 typedef struct _psContextMap SCONTEXTMAP;
303 
304 static list_t contextMapList;
305 
306 static int SCONTEXTMAP_seeker(const void *el, const void *key)
307 {
308  const SCONTEXTMAP * contextMap = el;
309 
310  if ((el == NULL) || (key == NULL))
311  {
312  Log3(PCSC_LOG_CRITICAL,
313  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
314  el, key);
315  return 0;
316  }
317 
318  if (contextMap->hContext == *(SCARDCONTEXT *) key)
319  return 1;
320 
321  return 0;
322 }
323 
327 static short isExecuted = 0;
328 
329 
334 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
335 
340 
347 
348 
349 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
352 static LONG SCardRemoveContext(SCARDCONTEXT);
353 static LONG SCardCleanContext(SCONTEXTMAP *);
354 
355 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
356 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE,
357  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
358 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
359  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
360 static LONG SCardRemoveHandle(SCARDHANDLE);
361 
362 static void SCardInvalidateHandles(void);
363 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
364  LPBYTE pbAttr, LPDWORD pcbAttrLen);
365 
366 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
367 
368 /*
369  * Thread safety functions
370  */
377 inline static LONG SCardLockThread(void)
378 {
379  return pthread_mutex_lock(&clientMutex);
380 }
381 
387 inline static LONG SCardUnlockThread(void)
388 {
389  return pthread_mutex_unlock(&clientMutex);
390 }
391 
392 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
393  /*@out@*/ LPSCARDCONTEXT);
394 
428 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
429  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
430 {
431  LONG rv;
432  static int first_time = TRUE;
433 
434  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
435  PROFILE_START
436 
437  /* Some setup for the first execution */
438  if (first_time)
439  {
440  first_time = FALSE;
441 
442  /* Invalidate all the handles in the son after a fork */
443  pthread_atfork(NULL, NULL, SCardInvalidateHandles);
444  }
445 
446  /* Check if the server is running */
448  if (SCARD_E_INVALID_HANDLE == rv)
449  /* we reconnected to a daemon or we got called from a forked child */
451 
452  if (rv != SCARD_S_SUCCESS)
453  goto end;
454 
455  (void)SCardLockThread();
456  rv = SCardEstablishContextTH(dwScope, pvReserved1,
457  pvReserved2, phContext);
458  (void)SCardUnlockThread();
459 
460 end:
461  PROFILE_END(rv)
462  API_TRACE_OUT("%ld", *phContext)
463 
464  return rv;
465 }
466 
493 static LONG SCardEstablishContextTH(DWORD dwScope,
494  /*@unused@*/ LPCVOID pvReserved1,
495  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
496 {
497  LONG rv;
498  struct establish_struct scEstablishStruct;
499  uint32_t dwClientID = 0;
500 
501  (void)pvReserved1;
502  (void)pvReserved2;
503  if (phContext == NULL)
505  else
506  *phContext = 0;
507 
508  /*
509  * Do this only once:
510  * - Initialize context list.
511  */
512  if (isExecuted == 0)
513  {
514  int lrv;
515 
516  /* NOTE: The list will never be freed (No API call exists to
517  * "close all contexts".
518  * Applications which load and unload the library will leak
519  * the list's internal structures. */
520  lrv = list_init(&contextMapList);
521  if (lrv < 0)
522  {
523  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
524  lrv);
525  return SCARD_E_NO_MEMORY;
526  }
527 
528  lrv = list_attributes_seeker(&contextMapList,
529  SCONTEXTMAP_seeker);
530  if (lrv <0)
531  {
532  Log2(PCSC_LOG_CRITICAL,
533  "list_attributes_seeker failed with return value: %d", lrv);
534  list_destroy(&contextMapList);
535  return SCARD_E_NO_MEMORY;
536  }
537 
538  if (getenv("PCSCLITE_NO_BLOCKING"))
539  {
540  Log1(PCSC_LOG_INFO, "Disable shared blocking");
541  sharing_shall_block = FALSE;
542  }
543 
544  isExecuted = 1;
545  }
546 
547 
548  /* Establishes a connection to the server */
549  if (ClientSetupSession(&dwClientID) != 0)
550  {
551  return SCARD_E_NO_SERVICE;
552  }
553 
554  { /* exchange client/server protocol versions */
555  struct version_struct veStr;
556 
559  veStr.rv = SCARD_S_SUCCESS;
560 
561  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
562  &veStr);
563  if (rv != SCARD_S_SUCCESS)
564  return rv;
565 
566  /* Read a message from the server */
567  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
568  if (rv != SCARD_S_SUCCESS)
569  {
570  Log1(PCSC_LOG_CRITICAL,
571  "Your pcscd is too old and does not support CMD_VERSION");
572  return SCARD_F_COMM_ERROR;
573  }
574 
575  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
576  veStr.major, veStr.minor);
577 
578  if (veStr.rv != SCARD_S_SUCCESS)
579  return veStr.rv;
580  }
581 
582 again:
583  /*
584  * Try to establish an Application Context with the server
585  */
586  scEstablishStruct.dwScope = dwScope;
587  scEstablishStruct.hContext = 0;
588  scEstablishStruct.rv = SCARD_S_SUCCESS;
589 
591  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
592 
593  if (rv != SCARD_S_SUCCESS)
594  return rv;
595 
596  /*
597  * Read the response from the server
598  */
599  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
600  dwClientID);
601 
602  if (rv != SCARD_S_SUCCESS)
603  return rv;
604 
605  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
606  return scEstablishStruct.rv;
607 
608  /* check we do not reuse an existing hContext */
609  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
610  /* we do not need to release the allocated context since
611  * SCardReleaseContext() does nothing on the server side */
612  goto again;
613 
614  *phContext = scEstablishStruct.hContext;
615 
616  /*
617  * Allocate the new hContext - if allocator full return an error
618  */
619  rv = SCardAddContext(*phContext, dwClientID);
620 
621  return rv;
622 }
623 
646 {
647  LONG rv;
648  struct release_struct scReleaseStruct;
649  SCONTEXTMAP * currentContextMap;
650 
651  API_TRACE_IN("%ld", hContext)
652  PROFILE_START
653 
654  /*
655  * Make sure this context has been opened
656  * and get currentContextMap
657  */
658  currentContextMap = SCardGetContext(hContext);
659  if (NULL == currentContextMap)
660  {
662  goto error;
663  }
664 
665  (void)pthread_mutex_lock(currentContextMap->mMutex);
666 
667  /* check the context is still opened */
668  currentContextMap = SCardGetContext(hContext);
669  if (NULL == currentContextMap)
670  /* the context is now invalid
671  * -> another thread may have called SCardReleaseContext
672  * -> so the mMutex has been unlocked */
673  {
675  goto error;
676  }
677 
678  scReleaseStruct.hContext = hContext;
679  scReleaseStruct.rv = SCARD_S_SUCCESS;
680 
682  currentContextMap->dwClientID,
683  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
684 
685  if (rv != SCARD_S_SUCCESS)
686  goto end;
687 
688  /*
689  * Read a message from the server
690  */
691  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
692  currentContextMap->dwClientID);
693 
694  if (rv != SCARD_S_SUCCESS)
695  goto end;
696 
697  rv = scReleaseStruct.rv;
698 end:
699  (void)pthread_mutex_unlock(currentContextMap->mMutex);
700 
701  /*
702  * Remove the local context from the stack
703  */
704  (void)SCardLockThread();
705  (void)SCardRemoveContext(hContext);
706  (void)SCardUnlockThread();
707 
708 error:
709  PROFILE_END(rv)
710  API_TRACE_OUT("")
711 
712  return rv;
713 }
714 
771 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
772  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
773  LPDWORD pdwActiveProtocol)
774 {
775  LONG rv;
776  struct connect_struct scConnectStruct;
777  SCONTEXTMAP * currentContextMap;
778 
779  PROFILE_START
780  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
781 
782  /*
783  * Check for NULL parameters
784  */
785  if (phCard == NULL || pdwActiveProtocol == NULL)
787  else
788  *phCard = 0;
789 
790  if (szReader == NULL)
791  return SCARD_E_UNKNOWN_READER;
792 
793  /*
794  * Check for uninitialized strings
795  */
796  if (strlen(szReader) > MAX_READERNAME)
797  return SCARD_E_INVALID_VALUE;
798 
799  /*
800  * Make sure this context has been opened
801  */
802  currentContextMap = SCardGetContext(hContext);
803  if (NULL == currentContextMap)
804  return SCARD_E_INVALID_HANDLE;
805 
806  (void)pthread_mutex_lock(currentContextMap->mMutex);
807 
808  /* check the context is still opened */
809  currentContextMap = SCardGetContext(hContext);
810  if (NULL == currentContextMap)
811  /* the context is now invalid
812  * -> another thread may have called SCardReleaseContext
813  * -> so the mMutex has been unlocked */
814  return SCARD_E_INVALID_HANDLE;
815 
816  strlcpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
817 
818  scConnectStruct.hContext = hContext;
819  scConnectStruct.dwShareMode = dwShareMode;
820  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
821  scConnectStruct.hCard = 0;
822  scConnectStruct.dwActiveProtocol = 0;
823  scConnectStruct.rv = SCARD_S_SUCCESS;
824 
825  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
826  sizeof(scConnectStruct), (void *) &scConnectStruct);
827 
828  if (rv != SCARD_S_SUCCESS)
829  goto end;
830 
831  /*
832  * Read a message from the server
833  */
834  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
835  currentContextMap->dwClientID);
836 
837  if (rv != SCARD_S_SUCCESS)
838  goto end;
839 
840  *phCard = scConnectStruct.hCard;
841  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
842 
843  if (scConnectStruct.rv == SCARD_S_SUCCESS)
844  {
845  /*
846  * Keep track of the handle locally
847  */
848  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
849  }
850  else
851  rv = scConnectStruct.rv;
852 
853 end:
854  (void)pthread_mutex_unlock(currentContextMap->mMutex);
855 
856  PROFILE_END(rv)
857  API_TRACE_OUT("%d", *pdwActiveProtocol)
858 
859  return rv;
860 }
861 
935 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
936  DWORD dwPreferredProtocols, DWORD dwInitialization,
937  LPDWORD pdwActiveProtocol)
938 {
939  LONG rv;
940  struct reconnect_struct scReconnectStruct;
941  SCONTEXTMAP * currentContextMap;
942  CHANNEL_MAP * pChannelMap;
943 
944  PROFILE_START
945 
946  if (pdwActiveProtocol == NULL)
948 
949  /*
950  * Make sure this handle has been opened
951  */
952  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
953  &pChannelMap);
954  if (rv == -1)
955  return SCARD_E_INVALID_HANDLE;
956 
957  (void)pthread_mutex_lock(currentContextMap->mMutex);
958 
959  /* check the handle is still valid */
960  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
961  &pChannelMap);
962  if (rv == -1)
963  /* the handle is now invalid
964  * -> another thread may have called SCardReleaseContext
965  * -> so the mMutex has been unlocked */
966  return SCARD_E_INVALID_HANDLE;
967 
968  /* Retry loop for blocking behaviour */
969 retry:
970 
971  scReconnectStruct.hCard = hCard;
972  scReconnectStruct.dwShareMode = dwShareMode;
973  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
974  scReconnectStruct.dwInitialization = dwInitialization;
975  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
976  scReconnectStruct.rv = SCARD_S_SUCCESS;
977 
978  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
979  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
980 
981  if (rv != SCARD_S_SUCCESS)
982  goto end;
983 
984  /*
985  * Read a message from the server
986  */
987  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
988  currentContextMap->dwClientID);
989 
990  if (rv != SCARD_S_SUCCESS)
991  goto end;
992 
993  rv = scReconnectStruct.rv;
994 
995  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
996  {
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 
1008  return rv;
1009 }
1010 
1042 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1043 {
1044  LONG rv;
1045  struct disconnect_struct scDisconnectStruct;
1046  SCONTEXTMAP * currentContextMap;
1047  CHANNEL_MAP * pChannelMap;
1048 
1049  PROFILE_START
1050  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1051 
1052  /*
1053  * Make sure this handle has been opened
1054  */
1055  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1056  &pChannelMap);
1057  if (rv == -1)
1058  {
1060  goto error;
1061  }
1062 
1063  (void)pthread_mutex_lock(currentContextMap->mMutex);
1064 
1065  /* check the handle is still valid */
1066  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1067  &pChannelMap);
1068  if (rv == -1)
1069  /* the handle is now invalid
1070  * -> another thread may have called SCardReleaseContext
1071  * -> so the mMutex has been unlocked */
1072  {
1074  goto error;
1075  }
1076 
1077  scDisconnectStruct.hCard = hCard;
1078  scDisconnectStruct.dwDisposition = dwDisposition;
1079  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1080 
1081  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1082  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1083 
1084  if (rv != SCARD_S_SUCCESS)
1085  goto end;
1086 
1087  /*
1088  * Read a message from the server
1089  */
1090  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1091  currentContextMap->dwClientID);
1092 
1093  if (rv != SCARD_S_SUCCESS)
1094  goto end;
1095 
1096  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1097  (void)SCardRemoveHandle(hCard);
1098  rv = scDisconnectStruct.rv;
1099 
1100 end:
1101  (void)pthread_mutex_unlock(currentContextMap->mMutex);
1102 
1103 error:
1104  PROFILE_END(rv)
1105  API_TRACE_OUT("")
1106 
1107  return rv;
1108 }
1109 
1146 {
1147 
1148  LONG rv;
1149  struct begin_struct scBeginStruct;
1150  SCONTEXTMAP * currentContextMap;
1151  CHANNEL_MAP * pChannelMap;
1152 
1153  PROFILE_START
1154 
1155  /*
1156  * Make sure this handle has been opened
1157  */
1158  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1159  &pChannelMap);
1160  if (rv == -1)
1161  return SCARD_E_INVALID_HANDLE;
1162 
1163  (void)pthread_mutex_lock(currentContextMap->mMutex);
1164 
1165  /* check the handle is still valid */
1166  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1167  &pChannelMap);
1168  if (rv == -1)
1169  /* the handle is now invalid
1170  * -> another thread may have called SCardReleaseContext
1171  * -> so the mMutex has been unlocked */
1172  return SCARD_E_INVALID_HANDLE;
1173 
1174  scBeginStruct.hCard = hCard;
1175  scBeginStruct.rv = SCARD_S_SUCCESS;
1176 
1177  /*
1178  * Query the server every so often until the sharing violation ends
1179  * and then hold the lock for yourself.
1180  */
1181 
1182  do
1183  {
1185  currentContextMap->dwClientID,
1186  sizeof(scBeginStruct), (void *) &scBeginStruct);
1187 
1188  if (rv != SCARD_S_SUCCESS)
1189  goto end;
1190 
1191  /*
1192  * Read a message from the server
1193  */
1194  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1195  currentContextMap->dwClientID);
1196 
1197  if (rv != SCARD_S_SUCCESS)
1198  goto end;
1199 
1200  rv = scBeginStruct.rv;
1201  }
1202  while (SCARD_E_SHARING_VIOLATION == rv);
1203 
1204 end:
1205  (void)pthread_mutex_unlock(currentContextMap->mMutex);
1206 
1207  PROFILE_END(rv)
1208 
1209  return rv;
1210 }
1211 
1252 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1253 {
1254  LONG rv;
1255  struct end_struct scEndStruct;
1256  int randnum;
1257  SCONTEXTMAP * currentContextMap;
1258  CHANNEL_MAP * pChannelMap;
1259 
1260  PROFILE_START
1261 
1262  /*
1263  * Make sure this handle has been opened
1264  */
1265  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1266  &pChannelMap);
1267  if (rv == -1)
1268  return SCARD_E_INVALID_HANDLE;
1269 
1270  (void)pthread_mutex_lock(currentContextMap->mMutex);
1271 
1272  /* check the handle is still valid */
1273  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1274  &pChannelMap);
1275  if (rv == -1)
1276  /* the handle is now invalid
1277  * -> another thread may have called SCardReleaseContext
1278  * -> so the mMutex has been unlocked */
1279  return SCARD_E_INVALID_HANDLE;
1280 
1281  scEndStruct.hCard = hCard;
1282  scEndStruct.dwDisposition = dwDisposition;
1283  scEndStruct.rv = SCARD_S_SUCCESS;
1284 
1286  currentContextMap->dwClientID,
1287  sizeof(scEndStruct), (void *) &scEndStruct);
1288 
1289  if (rv != SCARD_S_SUCCESS)
1290  goto end;
1291 
1292  /*
1293  * Read a message from the server
1294  */
1295  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1296  currentContextMap->dwClientID);
1297 
1298  if (rv != SCARD_S_SUCCESS)
1299  goto end;
1300 
1301  /*
1302  * This helps prevent starvation
1303  */
1304  randnum = SYS_RandomInt(1000, 10000);
1305  (void)SYS_USleep(randnum);
1306  rv = scEndStruct.rv;
1307 
1308 end:
1309  (void)pthread_mutex_unlock(currentContextMap->mMutex);
1310 
1311  PROFILE_END(rv)
1312 
1313  return rv;
1314 }
1315 
1411 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
1412  LPDWORD pcchReaderLen, LPDWORD pdwState,
1413  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1414 {
1415  DWORD dwReaderLen, dwAtrLen;
1416  LONG rv;
1417  int i;
1418  struct status_struct scStatusStruct;
1419  SCONTEXTMAP * currentContextMap;
1420  CHANNEL_MAP * pChannelMap;
1421  char *r;
1422  char *bufReader = NULL;
1423  LPBYTE bufAtr = NULL;
1424  DWORD dummy = 0;
1425 
1426  PROFILE_START
1427 
1428  /* default output values */
1429  if (pdwState)
1430  *pdwState = 0;
1431 
1432  if (pdwProtocol)
1433  *pdwProtocol = 0;
1434 
1435  /* Check for NULL parameters */
1436  if (pcchReaderLen == NULL)
1437  pcchReaderLen = &dummy;
1438 
1439  if (pcbAtrLen == NULL)
1440  pcbAtrLen = &dummy;
1441 
1442  /* length passed from caller */
1443  dwReaderLen = *pcchReaderLen;
1444  dwAtrLen = *pcbAtrLen;
1445 
1446  *pcchReaderLen = 0;
1447  *pcbAtrLen = 0;
1448 
1449  /*
1450  * Make sure this handle has been opened
1451  */
1452  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1453  &pChannelMap);
1454  if (rv == -1)
1455  return SCARD_E_INVALID_HANDLE;
1456 
1457  (void)pthread_mutex_lock(currentContextMap->mMutex);
1458 
1459  /* check the handle is still valid */
1460  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1461  &pChannelMap);
1462  if (rv == -1)
1463  /* the handle is now invalid
1464  * -> another thread may have called SCardReleaseContext
1465  * -> so the mMutex has been unlocked */
1466  return SCARD_E_INVALID_HANDLE;
1467 
1468  /* synchronize reader states with daemon */
1469  rv = getReaderStates(currentContextMap);
1470  if (rv != SCARD_S_SUCCESS)
1471  goto end;
1472 
1473  r = pChannelMap->readerName;
1474  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1475  {
1476  /* by default r == NULL */
1477  if (r && strcmp(r, readerStates[i].readerName) == 0)
1478  break;
1479  }
1480 
1481  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1482  {
1484  goto end;
1485  }
1486 
1487  /* Retry loop for blocking behaviour */
1488 retry:
1489 
1490  /* initialise the structure */
1491  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1492  scStatusStruct.hCard = hCard;
1493 
1494  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1495  sizeof(scStatusStruct), (void *) &scStatusStruct);
1496 
1497  if (rv != SCARD_S_SUCCESS)
1498  goto end;
1499 
1500  /*
1501  * Read a message from the server
1502  */
1503  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1504  currentContextMap->dwClientID);
1505 
1506  if (rv != SCARD_S_SUCCESS)
1507  goto end;
1508 
1509  rv = scStatusStruct.rv;
1510 
1511  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1512  {
1514  goto retry;
1515  }
1516 
1517  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1518  {
1519  /*
1520  * An event must have occurred
1521  */
1522  goto end;
1523  }
1524 
1525  /*
1526  * Now continue with the client side SCardStatus
1527  */
1528 
1529  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1530  *pcbAtrLen = readerStates[i].cardAtrLength;
1531 
1532  if (pdwState)
1533  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1534 
1535  if (pdwProtocol)
1536  *pdwProtocol = readerStates[i].cardProtocol;
1537 
1538  if (SCARD_AUTOALLOCATE == dwReaderLen)
1539  {
1540  dwReaderLen = *pcchReaderLen;
1541  bufReader = malloc(dwReaderLen);
1542  if (NULL == bufReader)
1543  {
1544  rv = SCARD_E_NO_MEMORY;
1545  goto end;
1546  }
1547  if (NULL == mszReaderName)
1548  {
1550  goto end;
1551  }
1552  *(char **)mszReaderName = bufReader;
1553  }
1554  else
1555  bufReader = mszReaderName;
1556 
1557  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1558  if (bufReader)
1559  {
1560  if (*pcchReaderLen > dwReaderLen)
1562 
1563  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1564  }
1565 
1566  if (SCARD_AUTOALLOCATE == dwAtrLen)
1567  {
1568  dwAtrLen = *pcbAtrLen;
1569  bufAtr = malloc(dwAtrLen);
1570  if (NULL == bufAtr)
1571  {
1572  rv = SCARD_E_NO_MEMORY;
1573  goto end;
1574  }
1575  if (NULL == pbAtr)
1576  {
1578  goto end;
1579  }
1580  *(LPBYTE *)pbAtr = bufAtr;
1581  }
1582  else
1583  bufAtr = pbAtr;
1584 
1585  if (bufAtr)
1586  {
1587  if (*pcbAtrLen > dwAtrLen)
1589 
1590  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1591  }
1592 
1593 end:
1594  (void)pthread_mutex_unlock(currentContextMap->mMutex);
1595 
1596  PROFILE_END(rv)
1597 
1598  return rv;
1599 }
1600 
1694 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1695  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1696 {
1697  SCARD_READERSTATE *currReader;
1698  READER_STATE *rContext;
1699  long dwTime;
1700  DWORD dwBreakFlag = 0;
1701  unsigned int j;
1702  SCONTEXTMAP * currentContextMap;
1703  int currentReaderCount = 0;
1704  LONG rv = SCARD_S_SUCCESS;
1705 
1706  PROFILE_START
1707  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1708 #ifdef DO_TRACE
1709  for (j=0; j<cReaders; j++)
1710  {
1711  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1712  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1713  }
1714 #endif
1715 
1716  if ((rgReaderStates == NULL && cReaders > 0)
1717  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1718  {
1720  goto error;
1721  }
1722 
1723  /* Check the integrity of the reader states structures */
1724  for (j = 0; j < cReaders; j++)
1725  {
1726  if (rgReaderStates[j].szReader == NULL)
1727  return SCARD_E_INVALID_VALUE;
1728  }
1729 
1730  /* return if all readers are SCARD_STATE_IGNORE */
1731  if (cReaders > 0)
1732  {
1733  int nbNonIgnoredReaders = cReaders;
1734 
1735  for (j=0; j<cReaders; j++)
1736  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1737  nbNonIgnoredReaders--;
1738 
1739  if (0 == nbNonIgnoredReaders)
1740  {
1741  rv = SCARD_S_SUCCESS;
1742  goto error;
1743  }
1744  }
1745  else
1746  {
1747  /* reader list is empty */
1748  rv = SCARD_S_SUCCESS;
1749  goto error;
1750  }
1751 
1752  /*
1753  * Make sure this context has been opened
1754  */
1755  currentContextMap = SCardGetContext(hContext);
1756  if (NULL == currentContextMap)
1757  {
1759  goto error;
1760  }
1761 
1762  (void)pthread_mutex_lock(currentContextMap->mMutex);
1763 
1764  /* check the context is still opened */
1765  currentContextMap = SCardGetContext(hContext);
1766  if (NULL == currentContextMap)
1767  /* the context is now invalid
1768  * -> another thread may have called SCardReleaseContext
1769  * -> so the mMutex has been unlocked */
1770  {
1772  goto error;
1773  }
1774 
1775  /* synchronize reader states with daemon */
1776  rv = getReaderStates(currentContextMap);
1777  if (rv != SCARD_S_SUCCESS)
1778  goto end;
1779 
1780  /* check all the readers are already known */
1781  for (j=0; j<cReaders; j++)
1782  {
1783  const char *readerName;
1784  int i;
1785 
1786  readerName = rgReaderStates[j].szReader;
1787  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1788  {
1789  if (strcmp(readerName, readerStates[i].readerName) == 0)
1790  break;
1791  }
1792 
1793  /* The requested reader name is not recognized */
1794  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1795  {
1796  /* PnP special reader? */
1797  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1798  {
1800  goto end;
1801  }
1802  }
1803  }
1804 
1805  /* Clear the event state for all readers */
1806  for (j = 0; j < cReaders; j++)
1807  rgReaderStates[j].dwEventState = 0;
1808 
1809  /* Now is where we start our event checking loop */
1810  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1811 
1812  /* Get the initial reader count on the system */
1813  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1814  if (readerStates[j].readerName[0] != '\0')
1815  currentReaderCount++;
1816 
1817  /* catch possible sign extension problems from 32 to 64-bits integers */
1818  if ((DWORD)-1 == dwTimeout)
1819  dwTimeout = INFINITE;
1820  if (INFINITE == dwTimeout)
1821  dwTime = 60*1000; /* "infinite" timeout */
1822  else
1823  dwTime = dwTimeout;
1824 
1825  j = 0;
1826  do
1827  {
1828  currReader = &rgReaderStates[j];
1829 
1830  /* Ignore for IGNORED readers */
1831  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1832  {
1833  const char *readerName;
1834  int i;
1835 
1836  /* Looks for correct readernames */
1837  readerName = currReader->szReader;
1838  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1839  {
1840  if (strcmp(readerName, readerStates[i].readerName) == 0)
1841  break;
1842  }
1843 
1844  /* The requested reader name is not recognized */
1845  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1846  {
1847  /* PnP special reader? */
1848  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1849  {
1850  int k, newReaderCount = 0;
1851 
1852  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1853  if (readerStates[k].readerName[0] != '\0')
1854  newReaderCount++;
1855 
1856  if (newReaderCount != currentReaderCount)
1857  {
1858  Log1(PCSC_LOG_INFO, "Reader list changed");
1859  currentReaderCount = newReaderCount;
1860 
1861  currReader->dwEventState |= SCARD_STATE_CHANGED;
1862  dwBreakFlag = 1;
1863  }
1864  }
1865  else
1866  {
1867  currReader->dwEventState =
1869  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1870  {
1871  currReader->dwEventState |= SCARD_STATE_CHANGED;
1872  /*
1873  * Spec says use SCARD_STATE_IGNORE but a removed USB
1874  * reader with eventState fed into currentState will
1875  * be ignored forever
1876  */
1877  dwBreakFlag = 1;
1878  }
1879  }
1880  }
1881  else
1882  {
1883  uint32_t readerState;
1884 
1885  /* The reader has come back after being away */
1886  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1887  {
1888  currReader->dwEventState |= SCARD_STATE_CHANGED;
1889  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1890  Log0(PCSC_LOG_DEBUG);
1891  dwBreakFlag = 1;
1892  }
1893 
1894  /* Set the reader status structure */
1895  rContext = &readerStates[i];
1896 
1897  /* Now we check all the Reader States */
1898  readerState = rContext->readerState;
1899 
1900  /* only if current state has an non null event counter */
1901  if (currReader->dwCurrentState & 0xFFFF0000)
1902  {
1903  unsigned int currentCounter;
1904 
1905  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1906 
1907  /* has the event counter changed since the last call? */
1908  if (rContext->eventCounter != currentCounter)
1909  {
1910  currReader->dwEventState |= SCARD_STATE_CHANGED;
1911  Log0(PCSC_LOG_DEBUG);
1912  dwBreakFlag = 1;
1913  }
1914  }
1915 
1916  /* add an event counter in the upper word of dwEventState */
1917  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1918  | (rContext->eventCounter << 16));
1919 
1920  /* Check if the reader is in the correct state */
1921  if (readerState & SCARD_UNKNOWN)
1922  {
1923  /* reader is in bad state */
1924  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1925  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1926  {
1927  /* App thinks reader is in good state and it is not */
1928  currReader->dwEventState |= SCARD_STATE_CHANGED;
1929  Log0(PCSC_LOG_DEBUG);
1930  dwBreakFlag = 1;
1931  }
1932  }
1933  else
1934  {
1935  /* App thinks reader in bad state but it is not */
1936  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1937  {
1938  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1939  currReader->dwEventState |= SCARD_STATE_CHANGED;
1940  Log0(PCSC_LOG_DEBUG);
1941  dwBreakFlag = 1;
1942  }
1943  }
1944 
1945  /* Check for card presence in the reader */
1946  if (readerState & SCARD_PRESENT)
1947  {
1948  /* card present but not yet powered up */
1949  if (0 == rContext->cardAtrLength)
1950  /* Allow the status thread to convey information */
1952 
1953  currReader->cbAtr = rContext->cardAtrLength;
1954  memcpy(currReader->rgbAtr, rContext->cardAtr,
1955  currReader->cbAtr);
1956  }
1957  else
1958  currReader->cbAtr = 0;
1959 
1960  /* Card is now absent */
1961  if (readerState & SCARD_ABSENT)
1962  {
1963  currReader->dwEventState |= SCARD_STATE_EMPTY;
1964  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1965  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1966  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1967  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1968  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1969  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1970  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1971  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1972 
1973  /* After present the rest are assumed */
1974  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1975  {
1976  currReader->dwEventState |= SCARD_STATE_CHANGED;
1977  Log0(PCSC_LOG_DEBUG);
1978  dwBreakFlag = 1;
1979  }
1980  }
1981  /* Card is now present */
1982  else if (readerState & SCARD_PRESENT)
1983  {
1984  currReader->dwEventState |= SCARD_STATE_PRESENT;
1985  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1986  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1987  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1988  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1989  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1990  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1991 
1992  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1993  {
1994  currReader->dwEventState |= SCARD_STATE_CHANGED;
1995  Log0(PCSC_LOG_DEBUG);
1996  dwBreakFlag = 1;
1997  }
1998 
1999  if (readerState & SCARD_SWALLOWED)
2000  {
2001  currReader->dwEventState |= SCARD_STATE_MUTE;
2002  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2003  {
2004  currReader->dwEventState |= SCARD_STATE_CHANGED;
2005  Log0(PCSC_LOG_DEBUG);
2006  dwBreakFlag = 1;
2007  }
2008  }
2009  else
2010  {
2011  /* App thinks card is mute but it is not */
2012  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2013  {
2014  currReader->dwEventState |= SCARD_STATE_CHANGED;
2015  Log0(PCSC_LOG_DEBUG);
2016  dwBreakFlag = 1;
2017  }
2018  }
2019  }
2020 
2021  /* Now figure out sharing modes */
2023  {
2024  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2025  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2026  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2027  {
2028  currReader->dwEventState |= SCARD_STATE_CHANGED;
2029  Log0(PCSC_LOG_DEBUG);
2030  dwBreakFlag = 1;
2031  }
2032  }
2033  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2034  {
2035  /* A card must be inserted for it to be INUSE */
2036  if (readerState & SCARD_PRESENT)
2037  {
2038  currReader->dwEventState |= SCARD_STATE_INUSE;
2039  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2040  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2041  {
2042  currReader->dwEventState |= SCARD_STATE_CHANGED;
2043  Log0(PCSC_LOG_DEBUG);
2044  dwBreakFlag = 1;
2045  }
2046  }
2047  }
2048  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2049  {
2050  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2051  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2052 
2053  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2054  {
2055  currReader->dwEventState |= SCARD_STATE_CHANGED;
2056  Log0(PCSC_LOG_DEBUG);
2057  dwBreakFlag = 1;
2058  }
2059  else if (currReader-> dwCurrentState
2061  {
2062  currReader->dwEventState |= SCARD_STATE_CHANGED;
2063  Log0(PCSC_LOG_DEBUG);
2064  dwBreakFlag = 1;
2065  }
2066  }
2067 
2068  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2069  {
2070  /*
2071  * Break out of the while .. loop and return status
2072  * once all the status's for all readers is met
2073  */
2074  currReader->dwEventState |= SCARD_STATE_CHANGED;
2075  Log0(PCSC_LOG_DEBUG);
2076  dwBreakFlag = 1;
2077  }
2078  } /* End of SCARD_STATE_UNKNOWN */
2079  } /* End of SCARD_STATE_IGNORE */
2080 
2081  /* Counter and resetter */
2082  j++;
2083  if (j == cReaders)
2084  {
2085  /* go back to the first reader */
2086  j = 0;
2087 
2088  /* Declare all the break conditions */
2089 
2090  /* Break if UNAWARE is set and all readers have been checked */
2091  if (dwBreakFlag == 1)
2092  break;
2093 
2094  /* Only sleep once for each cycle of reader checks. */
2095  {
2096  struct wait_reader_state_change waitStatusStruct;
2097  struct timeval before, after;
2098 
2099  gettimeofday(&before, NULL);
2100 
2101  waitStatusStruct.timeOut = dwTime;
2102  waitStatusStruct.rv = SCARD_S_SUCCESS;
2103 
2104  /* another thread can do SCardCancel() */
2105  currentContextMap->cancellable = TRUE;
2106 
2108  currentContextMap->dwClientID,
2109  sizeof(waitStatusStruct), &waitStatusStruct);
2110 
2111  if (rv != SCARD_S_SUCCESS)
2112  goto end;
2113 
2114  /*
2115  * Read a message from the server
2116  */
2118  &waitStatusStruct, sizeof(waitStatusStruct),
2119  currentContextMap->dwClientID, dwTime);
2120 
2121  /* another thread can do SCardCancel() */
2122  currentContextMap->cancellable = FALSE;
2123 
2124  /* timeout */
2125  if (SCARD_E_TIMEOUT == rv)
2126  {
2127  /* ask server to remove us from the event list */
2129  currentContextMap->dwClientID,
2130  sizeof(waitStatusStruct), &waitStatusStruct);
2131 
2132  if (rv != SCARD_S_SUCCESS)
2133  goto end;
2134 
2135  /* Read a message from the server */
2136  rv = MessageReceive(&waitStatusStruct,
2137  sizeof(waitStatusStruct),
2138  currentContextMap->dwClientID);
2139 
2140  if (rv != SCARD_S_SUCCESS)
2141  goto end;
2142  }
2143 
2144  if (rv != SCARD_S_SUCCESS)
2145  goto end;
2146 
2147  /* an event occurs or SCardCancel() was called */
2148  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2149  {
2150  rv = waitStatusStruct.rv;
2151  goto end;
2152  }
2153 
2154  /* synchronize reader states with daemon */
2155  rv = getReaderStates(currentContextMap);
2156  if (rv != SCARD_S_SUCCESS)
2157  goto end;
2158 
2159  if (INFINITE != dwTimeout)
2160  {
2161  long int diff;
2162 
2163  gettimeofday(&after, NULL);
2164  diff = time_sub(&after, &before);
2165  dwTime -= diff/1000;
2166  }
2167  }
2168 
2169  if (dwTimeout != INFINITE)
2170  {
2171  /* If time is greater than timeout and all readers have been
2172  * checked
2173  */
2174  if (dwTime <= 0)
2175  {
2176  rv = SCARD_E_TIMEOUT;
2177  goto end;
2178  }
2179  }
2180  }
2181  }
2182  while (1);
2183 
2184 end:
2185  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2186 
2187  (void)pthread_mutex_unlock(currentContextMap->mMutex);
2188 
2189 error:
2190  PROFILE_END(rv)
2191 #ifdef DO_TRACE
2192  for (j=0; j<cReaders; j++)
2193  {
2194  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2195  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2196  }
2197 #endif
2198 
2199  return rv;
2200 }
2201 
2252 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2253  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2254  LPDWORD lpBytesReturned)
2255 {
2256  LONG rv;
2257  struct control_struct scControlStruct;
2258  SCONTEXTMAP * currentContextMap;
2259  CHANNEL_MAP * pChannelMap;
2260 
2261  PROFILE_START
2262 
2263  /* 0 bytes received by default */
2264  if (NULL != lpBytesReturned)
2265  *lpBytesReturned = 0;
2266 
2267  /*
2268  * Make sure this handle has been opened
2269  */
2270  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2271  &pChannelMap);
2272  if (rv == -1)
2273  {
2274  PROFILE_END(SCARD_E_INVALID_HANDLE)
2275  return SCARD_E_INVALID_HANDLE;
2276  }
2277 
2278  (void)pthread_mutex_lock(currentContextMap->mMutex);
2279 
2280  /* check the handle is still valid */
2281  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2282  &pChannelMap);
2283  if (rv == -1)
2284  /* the handle is now invalid
2285  * -> another thread may have called SCardReleaseContext
2286  * -> so the mMutex has been unlocked */
2287  return SCARD_E_INVALID_HANDLE;
2288 
2289  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2290  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2291  {
2293  goto end;
2294  }
2295 
2296  scControlStruct.hCard = hCard;
2297  scControlStruct.dwControlCode = dwControlCode;
2298  scControlStruct.cbSendLength = cbSendLength;
2299  scControlStruct.cbRecvLength = cbRecvLength;
2300  scControlStruct.dwBytesReturned = 0;
2301  scControlStruct.rv = 0;
2302 
2303  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2304  sizeof(scControlStruct), &scControlStruct);
2305 
2306  if (rv != SCARD_S_SUCCESS)
2307  goto end;
2308 
2309  /* write the sent buffer */
2310  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2311  currentContextMap->dwClientID);
2312 
2313  if (rv != SCARD_S_SUCCESS)
2314  goto end;
2315 
2316  /*
2317  * Read a message from the server
2318  */
2319  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2320  currentContextMap->dwClientID);
2321 
2322  if (rv != SCARD_S_SUCCESS)
2323  goto end;
2324 
2325  if (SCARD_S_SUCCESS == scControlStruct.rv)
2326  {
2327  /* read the received buffer */
2328  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2329  currentContextMap->dwClientID);
2330 
2331  if (rv != SCARD_S_SUCCESS)
2332  goto end;
2333 
2334  }
2335 
2336  if (NULL != lpBytesReturned)
2337  *lpBytesReturned = scControlStruct.dwBytesReturned;
2338 
2339  rv = scControlStruct.rv;
2340 
2341 end:
2342  (void)pthread_mutex_unlock(currentContextMap->mMutex);
2343 
2344  PROFILE_END(rv)
2345 
2346  return rv;
2347 }
2348 
2453 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2454  LPDWORD pcbAttrLen)
2455 {
2456  LONG ret;
2457  unsigned char *buf = NULL;
2458 
2459  PROFILE_START
2460 
2461  if (NULL == pcbAttrLen)
2462  {
2464  goto end;
2465  }
2466 
2467  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2468  {
2469  if (NULL == pbAttr)
2471 
2472  *pcbAttrLen = MAX_BUFFER_SIZE;
2473  buf = malloc(*pcbAttrLen);
2474  if (NULL == buf)
2475  {
2476  ret = SCARD_E_NO_MEMORY;
2477  goto end;
2478  }
2479 
2480  *(unsigned char **)pbAttr = buf;
2481  }
2482  else
2483  {
2484  buf = pbAttr;
2485 
2486  /* if only get the length */
2487  if (NULL == pbAttr)
2488  /* use a reasonable size */
2489  *pcbAttrLen = MAX_BUFFER_SIZE;
2490  }
2491 
2492  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2493  pcbAttrLen);
2494 
2495 end:
2496  PROFILE_END(ret)
2497 
2498  return ret;
2499 }
2500 
2536 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2537  DWORD cbAttrLen)
2538 {
2539  LONG ret;
2540 
2541  PROFILE_START
2542 
2543  if (NULL == pbAttr || 0 == cbAttrLen)
2545 
2546  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2547  &cbAttrLen);
2548 
2549  PROFILE_END(ret)
2550 
2551  return ret;
2552 }
2553 
2554 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2555  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2556 {
2557  LONG rv;
2558  struct getset_struct scGetSetStruct;
2559  SCONTEXTMAP * currentContextMap;
2560  CHANNEL_MAP * pChannelMap;
2561 
2562  /*
2563  * Make sure this handle has been opened
2564  */
2565  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2566  &pChannelMap);
2567  if (rv == -1)
2568  return SCARD_E_INVALID_HANDLE;
2569 
2570  (void)pthread_mutex_lock(currentContextMap->mMutex);
2571 
2572  /* check the handle is still valid */
2573  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2574  &pChannelMap);
2575  if (rv == -1)
2576  /* the handle is now invalid
2577  * -> another thread may have called SCardReleaseContext
2578  * -> so the mMutex has been unlocked */
2579  return SCARD_E_INVALID_HANDLE;
2580 
2581  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2582  {
2584  goto end;
2585  }
2586 
2587  scGetSetStruct.hCard = hCard;
2588  scGetSetStruct.dwAttrId = dwAttrId;
2589  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2590  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2591  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2592  if (SCARD_SET_ATTRIB == command)
2593  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2594 
2595  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2596  sizeof(scGetSetStruct), &scGetSetStruct);
2597 
2598  if (rv != SCARD_S_SUCCESS)
2599  goto end;
2600 
2601  /*
2602  * Read a message from the server
2603  */
2604  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2605  currentContextMap->dwClientID);
2606 
2607  if (rv != SCARD_S_SUCCESS)
2608  goto end;
2609 
2610  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2611  {
2612  /*
2613  * Copy and zero it so any secret information is not leaked
2614  */
2615  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2616  {
2617  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2618  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2619  }
2620  else
2621  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2622 
2623  if (pbAttr)
2624  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2625 
2626  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2627  }
2628  rv = scGetSetStruct.rv;
2629 
2630 end:
2631  (void)pthread_mutex_unlock(currentContextMap->mMutex);
2632 
2633  return rv;
2634 }
2635 
2694 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2695  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2696  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2697  LPDWORD pcbRecvLength)
2698 {
2699  LONG rv;
2700  SCONTEXTMAP * currentContextMap;
2701  CHANNEL_MAP * pChannelMap;
2702  struct transmit_struct scTransmitStruct;
2703 
2704  PROFILE_START
2705 
2706  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2707  pcbRecvLength == NULL || pioSendPci == NULL)
2709 
2710  /*
2711  * Make sure this handle has been opened
2712  */
2713  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2714  &pChannelMap);
2715  if (rv == -1)
2716  {
2717  *pcbRecvLength = 0;
2718  PROFILE_END(SCARD_E_INVALID_HANDLE)
2719  return SCARD_E_INVALID_HANDLE;
2720  }
2721 
2722  (void)pthread_mutex_lock(currentContextMap->mMutex);
2723 
2724  /* check the handle is still valid */
2725  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2726  &pChannelMap);
2727  if (rv == -1)
2728  /* the handle is now invalid
2729  * -> another thread may have called SCardReleaseContext
2730  * -> so the mMutex has been unlocked */
2731  return SCARD_E_INVALID_HANDLE;
2732 
2733  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2734  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2735  {
2737  goto end;
2738  }
2739 
2740  /* Retry loop for blocking behaviour */
2741 retry:
2742 
2743  scTransmitStruct.hCard = hCard;
2744  scTransmitStruct.cbSendLength = cbSendLength;
2745  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2746  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2747  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2748  scTransmitStruct.rv = SCARD_S_SUCCESS;
2749 
2750  if (pioRecvPci)
2751  {
2752  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2753  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2754  }
2755  else
2756  {
2757  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2758  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2759  }
2760 
2761  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2762  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2763 
2764  if (rv != SCARD_S_SUCCESS)
2765  goto end;
2766 
2767  /* write the sent buffer */
2768  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2769  currentContextMap->dwClientID);
2770 
2771  if (rv != SCARD_S_SUCCESS)
2772  goto end;
2773 
2774  /*
2775  * Read a message from the server
2776  */
2777  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2778  currentContextMap->dwClientID);
2779 
2780  if (rv != SCARD_S_SUCCESS)
2781  goto end;
2782 
2783  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2784  {
2785  /* read the received buffer */
2786  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2787  currentContextMap->dwClientID);
2788 
2789  if (rv != SCARD_S_SUCCESS)
2790  goto end;
2791 
2792  if (pioRecvPci)
2793  {
2794  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2795  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2796  }
2797  }
2798 
2799  rv = scTransmitStruct.rv;
2800 
2801  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2802  {
2804  goto retry;
2805  }
2806 
2807  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2808 
2809 end:
2810  (void)pthread_mutex_unlock(currentContextMap->mMutex);
2811 
2812  PROFILE_END(rv)
2813 
2814  return rv;
2815 }
2816 
2867 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2868  LPSTR mszReaders, LPDWORD pcchReaders)
2869 {
2870  DWORD dwReadersLen = 0;
2871  int i;
2872  SCONTEXTMAP * currentContextMap;
2873  LONG rv = SCARD_S_SUCCESS;
2874  char *buf = NULL;
2875 
2876  (void)mszGroups;
2877  PROFILE_START
2878  API_TRACE_IN("%ld", hContext)
2879 
2880  /*
2881  * Check for NULL parameters
2882  */
2883  if (pcchReaders == NULL)
2885 
2886  /*
2887  * Make sure this context has been opened
2888  */
2889  currentContextMap = SCardGetContext(hContext);
2890  if (NULL == currentContextMap)
2891  {
2892  PROFILE_END(SCARD_E_INVALID_HANDLE)
2893  return SCARD_E_INVALID_HANDLE;
2894  }
2895 
2896  (void)pthread_mutex_lock(currentContextMap->mMutex);
2897 
2898  /* check the context is still opened */
2899  currentContextMap = SCardGetContext(hContext);
2900  if (NULL == currentContextMap)
2901  /* the context is now invalid
2902  * -> another thread may have called SCardReleaseContext
2903  * -> so the mMutex has been unlocked */
2904  return SCARD_E_INVALID_HANDLE;
2905 
2906  /* synchronize reader states with daemon */
2907  rv = getReaderStates(currentContextMap);
2908  if (rv != SCARD_S_SUCCESS)
2909  goto end;
2910 
2911  dwReadersLen = 0;
2912  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2913  if (readerStates[i].readerName[0] != '\0')
2914  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2915 
2916  /* for the last NULL byte */
2917  dwReadersLen += 1;
2918 
2919  if (1 == dwReadersLen)
2920  {
2922  goto end;
2923  }
2924 
2925  if (SCARD_AUTOALLOCATE == *pcchReaders)
2926  {
2927  buf = malloc(dwReadersLen);
2928  if (NULL == buf)
2929  {
2930  rv = SCARD_E_NO_MEMORY;
2931  goto end;
2932  }
2933  if (NULL == mszReaders)
2934  {
2936  goto end;
2937  }
2938  *(char **)mszReaders = buf;
2939  }
2940  else
2941  {
2942  buf = mszReaders;
2943 
2944  /* not enough place to store the reader names */
2945  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2946  {
2948  goto end;
2949  }
2950  }
2951 
2952  if (mszReaders == NULL) /* text array not allocated */
2953  goto end;
2954 
2955  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2956  {
2957  if (readerStates[i].readerName[0] != '\0')
2958  {
2959  /*
2960  * Build the multi-string
2961  */
2962  strcpy(buf, readerStates[i].readerName);
2963  buf += strlen(readerStates[i].readerName)+1;
2964  }
2965  }
2966  *buf = '\0'; /* Add the last null */
2967 
2968 end:
2969  /* set the reader names length */
2970  *pcchReaders = dwReadersLen;
2971 
2972  (void)pthread_mutex_unlock(currentContextMap->mMutex);
2973 
2974  PROFILE_END(rv)
2975  API_TRACE_OUT("%d", *pcchReaders)
2976 
2977  return rv;
2978 }
2979 
2993 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2994 {
2995  LONG rv = SCARD_S_SUCCESS;
2996  SCONTEXTMAP * currentContextMap;
2997 
2998  PROFILE_START
2999 
3000  /*
3001  * Make sure this context has been opened
3002  */
3003  currentContextMap = SCardGetContext(hContext);
3004  if (NULL == currentContextMap)
3005  return SCARD_E_INVALID_HANDLE;
3006 
3007  free((void *)pvMem);
3008 
3009  PROFILE_END(rv)
3010 
3011  return rv;
3012 }
3013 
3065 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3066  LPDWORD pcchGroups)
3067 {
3068  LONG rv = SCARD_S_SUCCESS;
3069  SCONTEXTMAP * currentContextMap;
3070  char *buf = NULL;
3071 
3072  PROFILE_START
3073 
3074  /* Multi-string with two trailing \0 */
3075  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3076  const unsigned int dwGroups = sizeof(ReaderGroup);
3077 
3078  /*
3079  * Make sure this context has been opened
3080  */
3081  currentContextMap = SCardGetContext(hContext);
3082  if (NULL == currentContextMap)
3083  return SCARD_E_INVALID_HANDLE;
3084 
3085  (void)pthread_mutex_lock(currentContextMap->mMutex);
3086 
3087  /* check the context is still opened */
3088  currentContextMap = SCardGetContext(hContext);
3089  if (NULL == currentContextMap)
3090  /* the context is now invalid
3091  * -> another thread may have called SCardReleaseContext
3092  * -> so the mMutex has been unlocked */
3093  return SCARD_E_INVALID_HANDLE;
3094 
3095  if (SCARD_AUTOALLOCATE == *pcchGroups)
3096  {
3097  buf = malloc(dwGroups);
3098  if (NULL == buf)
3099  {
3100  rv = SCARD_E_NO_MEMORY;
3101  goto end;
3102  }
3103  if (NULL == mszGroups)
3104  {
3106  goto end;
3107  }
3108  *(char **)mszGroups = buf;
3109  }
3110  else
3111  {
3112  buf = mszGroups;
3113 
3114  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3115  {
3117  goto end;
3118  }
3119  }
3120 
3121  if (buf)
3122  memcpy(buf, ReaderGroup, dwGroups);
3123 
3124 end:
3125  *pcchGroups = dwGroups;
3126 
3127  (void)pthread_mutex_unlock(currentContextMap->mMutex);
3128 
3129  PROFILE_END(rv)
3130 
3131  return rv;
3132 }
3133 
3164 {
3165  SCONTEXTMAP * currentContextMap;
3166  LONG rv = SCARD_S_SUCCESS;
3167  uint32_t dwClientID = 0;
3168  struct cancel_struct scCancelStruct;
3169 
3170  PROFILE_START
3171  API_TRACE_IN("%ld", hContext)
3172 
3173  /*
3174  * Make sure this context has been opened
3175  */
3176  currentContextMap = SCardGetContext(hContext);
3177  if (NULL == currentContextMap)
3178  {
3180  goto error;
3181  }
3182 
3183  if (! currentContextMap->cancellable)
3184  {
3185  rv = SCARD_S_SUCCESS;
3186  goto error;
3187  }
3188 
3189  /* create a new connection to the server */
3190  if (ClientSetupSession(&dwClientID) != 0)
3191  {
3192  rv = SCARD_E_NO_SERVICE;
3193  goto error;
3194  }
3195 
3196  scCancelStruct.hContext = hContext;
3197  scCancelStruct.rv = SCARD_S_SUCCESS;
3198 
3199  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3200  sizeof(scCancelStruct), (void *) &scCancelStruct);
3201 
3202  if (rv != SCARD_S_SUCCESS)
3203  goto end;
3204 
3205  /*
3206  * Read a message from the server
3207  */
3208  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3209 
3210  if (rv != SCARD_S_SUCCESS)
3211  goto end;
3212 
3213  rv = scCancelStruct.rv;
3214 end:
3215  ClientCloseSession(dwClientID);
3216 
3217 error:
3218  PROFILE_END(rv)
3219  API_TRACE_OUT("")
3220 
3221  return rv;
3222 }
3223 
3248 {
3249  LONG rv;
3250  SCONTEXTMAP * currentContextMap;
3251 
3252  PROFILE_START
3253  API_TRACE_IN("%ld", hContext)
3254 
3255  rv = SCARD_S_SUCCESS;
3256 
3257  /*
3258  * Make sure this context has been opened
3259  */
3260  currentContextMap = SCardGetContext(hContext);
3261  if (currentContextMap == NULL)
3263 
3264  PROFILE_END(rv)
3265  API_TRACE_OUT("")
3266 
3267  return rv;
3268 }
3269 
3286 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3287 {
3288  int lrv;
3289  SCONTEXTMAP * newContextMap;
3290 
3291  newContextMap = malloc(sizeof(SCONTEXTMAP));
3292  if (NULL == newContextMap)
3293  return SCARD_E_NO_MEMORY;
3294 
3295  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3296  newContextMap->hContext = hContext;
3297  newContextMap->dwClientID = dwClientID;
3298  newContextMap->cancellable = FALSE;
3299 
3300  newContextMap->mMutex = malloc(sizeof(pthread_mutex_t));
3301  if (NULL == newContextMap->mMutex)
3302  {
3303  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXTMAP @%p", newContextMap);
3304  free(newContextMap);
3305  return SCARD_E_NO_MEMORY;
3306  }
3307  (void)pthread_mutex_init(newContextMap->mMutex, NULL);
3308 
3309  lrv = list_init(&(newContextMap->channelMapList));
3310  if (lrv < 0)
3311  {
3312  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3313  goto error;
3314  }
3315 
3316  lrv = list_attributes_seeker(&(newContextMap->channelMapList),
3317  CHANNEL_MAP_seeker);
3318  if (lrv <0)
3319  {
3320  Log2(PCSC_LOG_CRITICAL,
3321  "list_attributes_seeker failed with return value: %d", lrv);
3322  list_destroy(&(newContextMap->channelMapList));
3323  goto error;
3324  }
3325 
3326  lrv = list_append(&contextMapList, newContextMap);
3327  if (lrv < 0)
3328  {
3329  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3330  lrv);
3331  list_destroy(&(newContextMap->channelMapList));
3332  goto error;
3333  }
3334 
3335  return SCARD_S_SUCCESS;
3336 
3337 error:
3338 
3339  (void)pthread_mutex_destroy(newContextMap->mMutex);
3340  free(newContextMap->mMutex);
3341  free(newContextMap);
3342 
3343  return SCARD_E_NO_MEMORY;
3344 }
3345 
3359 {
3360  SCONTEXTMAP * currentContextMap;
3361 
3362  (void)SCardLockThread();
3363  currentContextMap = SCardGetContextTH(hContext);
3364  (void)SCardUnlockThread();
3365 
3366  return currentContextMap;
3367 }
3368 
3382 {
3383  return list_seek(&contextMapList, &hContext);
3384 }
3385 
3395 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3396 {
3397  SCONTEXTMAP * currentContextMap;
3398  currentContextMap = SCardGetContextTH(hContext);
3399 
3400  if (NULL == currentContextMap)
3401  return SCARD_E_INVALID_HANDLE;
3402  else
3403  return SCardCleanContext(currentContextMap);
3404 }
3405 
3406 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3407 {
3408  int list_index, lrv;
3409  int listSize;
3410  CHANNEL_MAP * currentChannelMap;
3411 
3412  targetContextMap->hContext = 0;
3413  (void)ClientCloseSession(targetContextMap->dwClientID);
3414  targetContextMap->dwClientID = 0;
3415  (void)pthread_mutex_destroy(targetContextMap->mMutex);
3416  free(targetContextMap->mMutex);
3417  targetContextMap->mMutex = NULL;
3418 
3419  listSize = list_size(&(targetContextMap->channelMapList));
3420  for (list_index = 0; list_index < listSize; list_index++)
3421  {
3422  currentChannelMap = list_get_at(&(targetContextMap->channelMapList),
3423  list_index);
3424  if (NULL == currentChannelMap)
3425  {
3426  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3427  list_index);
3428  continue;
3429  }
3430  else
3431  {
3432  free(currentChannelMap->readerName);
3433  free(currentChannelMap);
3434  }
3435 
3436  }
3437  list_destroy(&(targetContextMap->channelMapList));
3438 
3439  lrv = list_delete(&contextMapList, targetContextMap);
3440  if (lrv < 0)
3441  {
3442  Log2(PCSC_LOG_CRITICAL,
3443  "list_delete failed with return value: %d", lrv);
3444  }
3445 
3446  free(targetContextMap);
3447 
3448  return SCARD_S_SUCCESS;
3449 }
3450 
3451 /*
3452  * Functions for managing hCard values returned from SCardConnect.
3453  */
3454 
3455 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3456  LPCSTR readerName)
3457 {
3458  CHANNEL_MAP * newChannelMap;
3459  int lrv = -1;
3460 
3461  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3462  if (NULL == newChannelMap)
3463  return SCARD_E_NO_MEMORY;
3464 
3465  newChannelMap->hCard = hCard;
3466  newChannelMap->readerName = strdup(readerName);
3467 
3468  lrv = list_append(&(currentContextMap->channelMapList), newChannelMap);
3469  if (lrv < 0)
3470  {
3471  free(newChannelMap->readerName);
3472  free(newChannelMap);
3473  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3474  lrv);
3475  return SCARD_E_NO_MEMORY;
3476  }
3477 
3478  return SCARD_S_SUCCESS;
3479 }
3480 
3481 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3482 {
3483  SCONTEXTMAP * currentContextMap;
3484  CHANNEL_MAP * currentChannelMap;
3485  int lrv;
3486  LONG rv;
3487 
3488  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
3489  &currentChannelMap);
3490  if (rv == -1)
3491  return SCARD_E_INVALID_HANDLE;
3492 
3493  free(currentChannelMap->readerName);
3494 
3495  lrv = list_delete(&(currentContextMap->channelMapList), currentChannelMap);
3496  if (lrv < 0)
3497  {
3498  Log2(PCSC_LOG_CRITICAL,
3499  "list_delete failed with return value: %d", lrv);
3500  }
3501 
3502  free(currentChannelMap);
3503 
3504  return SCARD_S_SUCCESS;
3505 }
3506 
3507 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
3508  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3509 {
3510  LONG rv;
3511 
3512  if (0 == hCard)
3513  return -1;
3514 
3515  (void)SCardLockThread();
3516  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3517  targetChannelMap);
3518  (void)SCardUnlockThread();
3519 
3520  return rv;
3521 }
3522 
3523 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3524  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3525 {
3526  int listSize;
3527  int list_index;
3528  SCONTEXTMAP * currentContextMap;
3529  CHANNEL_MAP * currentChannelMap;
3530 
3531  /* Best to get the caller a crash early if we fail unsafely */
3532  *targetContextMap = NULL;
3533  *targetChannelMap = NULL;
3534 
3535  listSize = list_size(&contextMapList);
3536 
3537  for (list_index = 0; list_index < listSize; list_index++)
3538  {
3539  currentContextMap = list_get_at(&contextMapList, list_index);
3540  if (currentContextMap == NULL)
3541  {
3542  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3543  list_index);
3544  continue;
3545  }
3546  currentChannelMap = list_seek(&(currentContextMap->channelMapList),
3547  &hCard);
3548  if (currentChannelMap != NULL)
3549  {
3550  *targetContextMap = currentContextMap;
3551  *targetChannelMap = currentChannelMap;
3552  return SCARD_S_SUCCESS;
3553  }
3554  }
3555 
3556  return -1;
3557 }
3558 
3571 {
3572  LONG rv;
3573  struct stat statBuffer;
3574  char *socketName;
3575 
3576  socketName = getSocketName();
3577  rv = stat(socketName, &statBuffer);
3578 
3579  if (rv != 0)
3580  {
3581  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3582  socketName, strerror(errno));
3583  return SCARD_E_NO_SERVICE;
3584  }
3585 
3586  return SCARD_S_SUCCESS;
3587 }
3588 
3589 static void SCardInvalidateHandles(void)
3590 {
3591  /* invalid all handles */
3592  (void)SCardLockThread();
3593 
3594  while (list_size(&contextMapList) != 0)
3595  {
3596  SCONTEXTMAP * currentContextMap;
3597 
3598  currentContextMap = list_get_at(&contextMapList, 0);
3599  if (currentContextMap != NULL)
3600  (void)SCardCleanContext(currentContextMap);
3601  else
3602  Log1(PCSC_LOG_CRITICAL, "list_get_at returned NULL");
3603  }
3604 
3605  (void)SCardUnlockThread();
3606 }
3607 
3608 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3609 {
3610  int32_t dwClientID = currentContextMap->dwClientID;
3611  LONG rv;
3612 
3613  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3614  if (rv != SCARD_S_SUCCESS)
3615  return rv;
3616 
3617  /* Read a message from the server */
3618  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3619  if (rv != SCARD_S_SUCCESS)
3620  return rv;
3621 
3622  return SCARD_S_SUCCESS;
3623 }
3624