pcsc-lite  1.8.15
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 #undef DO_TRACE
131 
132 /* Profile the execution time of WinSCard calls */
133 #undef 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  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
798  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
799 
800  scConnectStruct.hContext = hContext;
801  scConnectStruct.dwShareMode = dwShareMode;
802  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
803  scConnectStruct.hCard = 0;
804  scConnectStruct.dwActiveProtocol = 0;
805  scConnectStruct.rv = SCARD_S_SUCCESS;
806 
807  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
808  sizeof(scConnectStruct), (void *) &scConnectStruct);
809 
810  if (rv != SCARD_S_SUCCESS)
811  goto end;
812 
813  /*
814  * Read a message from the server
815  */
816  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
817  currentContextMap->dwClientID);
818 
819  if (rv != SCARD_S_SUCCESS)
820  goto end;
821 
822  *phCard = scConnectStruct.hCard;
823  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
824 
825  if (scConnectStruct.rv == SCARD_S_SUCCESS)
826  {
827  /*
828  * Keep track of the handle locally
829  */
830  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
831  }
832  else
833  rv = scConnectStruct.rv;
834 
835 end:
836  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
837 
838  PROFILE_END(rv)
839  API_TRACE_OUT("%d", *pdwActiveProtocol)
840 
841  return rv;
842 }
843 
917 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
918  DWORD dwPreferredProtocols, DWORD dwInitialization,
919  LPDWORD pdwActiveProtocol)
920 {
921  LONG rv;
922  struct reconnect_struct scReconnectStruct;
923  SCONTEXTMAP * currentContextMap;
924  CHANNEL_MAP * pChannelMap;
925 
926  PROFILE_START
927  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
928 
929  if (pdwActiveProtocol == NULL)
931 
932  /* Retry loop for blocking behaviour */
933 retry:
934 
935  /*
936  * Make sure this handle has been opened
937  */
938  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
939  &pChannelMap);
940  if (rv == -1)
941  return SCARD_E_INVALID_HANDLE;
942 
943  scReconnectStruct.hCard = hCard;
944  scReconnectStruct.dwShareMode = dwShareMode;
945  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
946  scReconnectStruct.dwInitialization = dwInitialization;
947  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
948  scReconnectStruct.rv = SCARD_S_SUCCESS;
949 
950  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
951  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
952 
953  if (rv != SCARD_S_SUCCESS)
954  goto end;
955 
956  /*
957  * Read a message from the server
958  */
959  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
960  currentContextMap->dwClientID);
961 
962  if (rv != SCARD_S_SUCCESS)
963  goto end;
964 
965  rv = scReconnectStruct.rv;
966 
967  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
968  {
969  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
971  goto retry;
972  }
973 
974  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
975 
976 end:
977  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
978 
979  PROFILE_END(rv)
980  API_TRACE_OUT("%ld", *pdwActiveProtocol)
981 
982  return rv;
983 }
984 
1016 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1017 {
1018  LONG rv;
1019  struct disconnect_struct scDisconnectStruct;
1020  SCONTEXTMAP * currentContextMap;
1021  CHANNEL_MAP * pChannelMap;
1022 
1023  PROFILE_START
1024  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1025 
1026  /*
1027  * Make sure this handle has been opened
1028  */
1029  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1030  &pChannelMap);
1031  if (rv == -1)
1032  {
1034  goto error;
1035  }
1036 
1037  scDisconnectStruct.hCard = hCard;
1038  scDisconnectStruct.dwDisposition = dwDisposition;
1039  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1040 
1041  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1042  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1043 
1044  if (rv != SCARD_S_SUCCESS)
1045  goto end;
1046 
1047  /*
1048  * Read a message from the server
1049  */
1050  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1051  currentContextMap->dwClientID);
1052 
1053  if (rv != SCARD_S_SUCCESS)
1054  goto end;
1055 
1056  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1057  (void)SCardRemoveHandle(hCard);
1058  rv = scDisconnectStruct.rv;
1059 
1060 end:
1061  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1062 
1063 error:
1064  PROFILE_END(rv)
1065  API_TRACE_OUT("")
1066 
1067  return rv;
1068 }
1069 
1106 {
1107 
1108  LONG rv;
1109  struct begin_struct scBeginStruct;
1110  SCONTEXTMAP * currentContextMap;
1111  CHANNEL_MAP * pChannelMap;
1112 
1113  PROFILE_START
1114  API_TRACE_IN("%ld", hCard)
1115 
1116  /*
1117  * Query the server every so often until the sharing violation ends
1118  * and then hold the lock for yourself.
1119  */
1120 
1121  for(;;)
1122  {
1123  /*
1124  * Make sure this handle has been opened
1125  */
1126  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1127  &pChannelMap);
1128  if (rv == -1)
1129  return SCARD_E_INVALID_HANDLE;
1130 
1131  scBeginStruct.hCard = hCard;
1132  scBeginStruct.rv = SCARD_S_SUCCESS;
1133 
1135  currentContextMap->dwClientID,
1136  sizeof(scBeginStruct), (void *) &scBeginStruct);
1137 
1138  if (rv != SCARD_S_SUCCESS)
1139  break;
1140 
1141  /*
1142  * Read a message from the server
1143  */
1144  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1145  currentContextMap->dwClientID);
1146 
1147  if (rv != SCARD_S_SUCCESS)
1148  break;
1149 
1150  rv = scBeginStruct.rv;
1151 
1152  if (SCARD_E_SHARING_VIOLATION != rv)
1153  break;
1154 
1155  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1157  }
1158 
1159  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1160 
1161  PROFILE_END(rv)
1162  API_TRACE_OUT("")
1163 
1164  return rv;
1165 }
1166 
1206 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1207 {
1208  LONG rv;
1209  struct end_struct scEndStruct;
1210  int randnum;
1211  SCONTEXTMAP * currentContextMap;
1212  CHANNEL_MAP * pChannelMap;
1213 
1214  PROFILE_START
1215  API_TRACE_IN("%ld", hCard)
1216 
1217  /*
1218  * Make sure this handle has been opened
1219  */
1220  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1221  &pChannelMap);
1222  if (rv == -1)
1223  return SCARD_E_INVALID_HANDLE;
1224 
1225  scEndStruct.hCard = hCard;
1226  scEndStruct.dwDisposition = dwDisposition;
1227  scEndStruct.rv = SCARD_S_SUCCESS;
1228 
1230  currentContextMap->dwClientID,
1231  sizeof(scEndStruct), (void *) &scEndStruct);
1232 
1233  if (rv != SCARD_S_SUCCESS)
1234  goto end;
1235 
1236  /*
1237  * Read a message from the server
1238  */
1239  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1240  currentContextMap->dwClientID);
1241 
1242  if (rv != SCARD_S_SUCCESS)
1243  goto end;
1244 
1245  /*
1246  * This helps prevent starvation
1247  */
1248  randnum = SYS_RandomInt(1000, 10000);
1249  (void)SYS_USleep(randnum);
1250  rv = scEndStruct.rv;
1251 
1252 end:
1253  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1254 
1255  PROFILE_END(rv)
1256  API_TRACE_OUT("")
1257 
1258  return rv;
1259 }
1260 
1356 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
1357  LPDWORD pcchReaderLen, LPDWORD pdwState,
1358  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1359 {
1360  DWORD dwReaderLen, dwAtrLen;
1361  LONG rv;
1362  int i;
1363  struct status_struct scStatusStruct;
1364  SCONTEXTMAP * currentContextMap;
1365  CHANNEL_MAP * pChannelMap;
1366  char *r;
1367  char *bufReader = NULL;
1368  LPBYTE bufAtr = NULL;
1369  DWORD dummy = 0;
1370 
1371  PROFILE_START
1372 
1373  /* default output values */
1374  if (pdwState)
1375  *pdwState = 0;
1376 
1377  if (pdwProtocol)
1378  *pdwProtocol = 0;
1379 
1380  /* Check for NULL parameters */
1381  if (pcchReaderLen == NULL)
1382  pcchReaderLen = &dummy;
1383 
1384  if (pcbAtrLen == NULL)
1385  pcbAtrLen = &dummy;
1386 
1387  /* length passed from caller */
1388  dwReaderLen = *pcchReaderLen;
1389  dwAtrLen = *pcbAtrLen;
1390 
1391  *pcchReaderLen = 0;
1392  *pcbAtrLen = 0;
1393 
1394  /* Retry loop for blocking behaviour */
1395 retry:
1396 
1397  /*
1398  * Make sure this handle has been opened
1399  */
1400  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1401  &pChannelMap);
1402  if (rv == -1)
1403  return SCARD_E_INVALID_HANDLE;
1404 
1405  /* synchronize reader states with daemon */
1406  rv = getReaderStates(currentContextMap);
1407  if (rv != SCARD_S_SUCCESS)
1408  goto end;
1409 
1410  r = pChannelMap->readerName;
1411  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1412  {
1413  /* by default r == NULL */
1414  if (r && strcmp(r, readerStates[i].readerName) == 0)
1415  break;
1416  }
1417 
1418  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1419  {
1421  goto end;
1422  }
1423 
1424  /* initialise the structure */
1425  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1426  scStatusStruct.hCard = hCard;
1427 
1428  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1429  sizeof(scStatusStruct), (void *) &scStatusStruct);
1430 
1431  if (rv != SCARD_S_SUCCESS)
1432  goto end;
1433 
1434  /*
1435  * Read a message from the server
1436  */
1437  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1438  currentContextMap->dwClientID);
1439 
1440  if (rv != SCARD_S_SUCCESS)
1441  goto end;
1442 
1443  rv = scStatusStruct.rv;
1444 
1445  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1446  {
1447  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1449  goto retry;
1450  }
1451 
1452  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1453  {
1454  /*
1455  * An event must have occurred
1456  */
1457  goto end;
1458  }
1459 
1460  /*
1461  * Now continue with the client side SCardStatus
1462  */
1463 
1464  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1465  *pcbAtrLen = readerStates[i].cardAtrLength;
1466 
1467  if (pdwState)
1468  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1469 
1470  if (pdwProtocol)
1471  *pdwProtocol = readerStates[i].cardProtocol;
1472 
1473  if (SCARD_AUTOALLOCATE == dwReaderLen)
1474  {
1475  dwReaderLen = *pcchReaderLen;
1476  if (NULL == mszReaderName)
1477  {
1479  goto end;
1480  }
1481  bufReader = malloc(dwReaderLen);
1482  if (NULL == bufReader)
1483  {
1484  rv = SCARD_E_NO_MEMORY;
1485  goto end;
1486  }
1487  *(char **)mszReaderName = bufReader;
1488  }
1489  else
1490  bufReader = mszReaderName;
1491 
1492  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1493  if (bufReader)
1494  {
1495  if (*pcchReaderLen > dwReaderLen)
1497 
1498  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1499  }
1500 
1501  if (SCARD_AUTOALLOCATE == dwAtrLen)
1502  {
1503  dwAtrLen = *pcbAtrLen;
1504  if (NULL == pbAtr)
1505  {
1507  goto end;
1508  }
1509  bufAtr = malloc(dwAtrLen);
1510  if (NULL == bufAtr)
1511  {
1512  rv = SCARD_E_NO_MEMORY;
1513  goto end;
1514  }
1515  *(LPBYTE *)pbAtr = bufAtr;
1516  }
1517  else
1518  bufAtr = pbAtr;
1519 
1520  if (bufAtr)
1521  {
1522  if (*pcbAtrLen > dwAtrLen)
1524 
1525  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1526  }
1527 
1528 end:
1529  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1530 
1531  PROFILE_END(rv)
1532 
1533  return rv;
1534 }
1535 
1629 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1630  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1631 {
1632  SCARD_READERSTATE *currReader;
1633  READER_STATE *rContext;
1634  long dwTime;
1635  DWORD dwBreakFlag = 0;
1636  unsigned int j;
1637  SCONTEXTMAP * currentContextMap;
1638  int currentReaderCount = 0;
1639  LONG rv = SCARD_S_SUCCESS;
1640 
1641  PROFILE_START
1642  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1643 #ifdef DO_TRACE
1644  for (j=0; j<cReaders; j++)
1645  {
1646  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1647  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1648  }
1649 #endif
1650 
1651  if ((rgReaderStates == NULL && cReaders > 0)
1652  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1653  {
1655  goto error;
1656  }
1657 
1658  /* Check the integrity of the reader states structures */
1659  for (j = 0; j < cReaders; j++)
1660  {
1661  if (rgReaderStates[j].szReader == NULL)
1662  return SCARD_E_INVALID_VALUE;
1663  }
1664 
1665  /* return if all readers are SCARD_STATE_IGNORE */
1666  if (cReaders > 0)
1667  {
1668  int nbNonIgnoredReaders = cReaders;
1669 
1670  for (j=0; j<cReaders; j++)
1671  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1672  nbNonIgnoredReaders--;
1673 
1674  if (0 == nbNonIgnoredReaders)
1675  {
1676  rv = SCARD_S_SUCCESS;
1677  goto error;
1678  }
1679  }
1680  else
1681  {
1682  /* reader list is empty */
1683  rv = SCARD_S_SUCCESS;
1684  goto error;
1685  }
1686 
1687  /*
1688  * Make sure this context has been opened
1689  */
1690  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
1691  if (NULL == currentContextMap)
1692  {
1694  goto error;
1695  }
1696 
1697  /* synchronize reader states with daemon */
1698  rv = getReaderStates(currentContextMap);
1699  if (rv != SCARD_S_SUCCESS)
1700  goto end;
1701 
1702  /* check all the readers are already known */
1703  for (j=0; j<cReaders; j++)
1704  {
1705  const char *readerName;
1706  int i;
1707 
1708  readerName = rgReaderStates[j].szReader;
1709  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1710  {
1711  if (strcmp(readerName, readerStates[i].readerName) == 0)
1712  break;
1713  }
1714 
1715  /* The requested reader name is not recognized */
1716  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1717  {
1718  /* PnP special reader? */
1719  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1720  {
1722  goto end;
1723  }
1724  }
1725  }
1726 
1727  /* Clear the event state for all readers */
1728  for (j = 0; j < cReaders; j++)
1729  rgReaderStates[j].dwEventState = 0;
1730 
1731  /* Now is where we start our event checking loop */
1732  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1733 
1734  /* Get the initial reader count on the system */
1735  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1736  if (readerStates[j].readerName[0] != '\0')
1737  currentReaderCount++;
1738 
1739  /* catch possible sign extension problems from 32 to 64-bits integers */
1740  if ((DWORD)-1 == dwTimeout)
1741  dwTimeout = INFINITE;
1742  if (INFINITE == dwTimeout)
1743  dwTime = 60*1000; /* "infinite" timeout */
1744  else
1745  dwTime = dwTimeout;
1746 
1747  j = 0;
1748  do
1749  {
1750  currReader = &rgReaderStates[j];
1751 
1752  /* Ignore for IGNORED readers */
1753  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1754  {
1755  const char *readerName;
1756  int i;
1757 
1758  /* Looks for correct readernames */
1759  readerName = currReader->szReader;
1760  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1761  {
1762  if (strcmp(readerName, readerStates[i].readerName) == 0)
1763  break;
1764  }
1765 
1766  /* The requested reader name is not recognized */
1767  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1768  {
1769  /* PnP special reader? */
1770  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1771  {
1772  int k, newReaderCount = 0;
1773 
1774  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1775  if (readerStates[k].readerName[0] != '\0')
1776  newReaderCount++;
1777 
1778  if (newReaderCount != currentReaderCount)
1779  {
1780  Log1(PCSC_LOG_INFO, "Reader list changed");
1781  currentReaderCount = newReaderCount;
1782 
1783  currReader->dwEventState |= SCARD_STATE_CHANGED;
1784  dwBreakFlag = 1;
1785  }
1786  }
1787  else
1788  {
1789  currReader->dwEventState =
1791  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1792  {
1793  currReader->dwEventState |= SCARD_STATE_CHANGED;
1794  /*
1795  * Spec says use SCARD_STATE_IGNORE but a removed USB
1796  * reader with eventState fed into currentState will
1797  * be ignored forever
1798  */
1799  dwBreakFlag = 1;
1800  }
1801  }
1802  }
1803  else
1804  {
1805  uint32_t readerState;
1806 
1807  /* The reader has come back after being away */
1808  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1809  {
1810  currReader->dwEventState |= SCARD_STATE_CHANGED;
1811  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1812  Log0(PCSC_LOG_DEBUG);
1813  dwBreakFlag = 1;
1814  }
1815 
1816  /* Set the reader status structure */
1817  rContext = &readerStates[i];
1818 
1819  /* Now we check all the Reader States */
1820  readerState = rContext->readerState;
1821 
1822  /* only if current state has an non null event counter */
1823  if (currReader->dwCurrentState & 0xFFFF0000)
1824  {
1825  unsigned int currentCounter;
1826 
1827  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1828 
1829  /* has the event counter changed since the last call? */
1830  if (rContext->eventCounter != currentCounter)
1831  {
1832  currReader->dwEventState |= SCARD_STATE_CHANGED;
1833  Log0(PCSC_LOG_DEBUG);
1834  dwBreakFlag = 1;
1835  }
1836  }
1837 
1838  /* add an event counter in the upper word of dwEventState */
1839  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1840  | (rContext->eventCounter << 16));
1841 
1842  /* Check if the reader is in the correct state */
1843  if (readerState & SCARD_UNKNOWN)
1844  {
1845  /* reader is in bad state */
1846  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1847  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1848  {
1849  /* App thinks reader is in good state and it is not */
1850  currReader->dwEventState |= SCARD_STATE_CHANGED;
1851  Log0(PCSC_LOG_DEBUG);
1852  dwBreakFlag = 1;
1853  }
1854  }
1855  else
1856  {
1857  /* App thinks reader in bad state but it is not */
1858  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1859  {
1860  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1861  currReader->dwEventState |= SCARD_STATE_CHANGED;
1862  Log0(PCSC_LOG_DEBUG);
1863  dwBreakFlag = 1;
1864  }
1865  }
1866 
1867  /* Check for card presence in the reader */
1868  if (readerState & SCARD_PRESENT)
1869  {
1870  /* card present but not yet powered up */
1871  if (0 == rContext->cardAtrLength)
1872  /* Allow the status thread to convey information */
1874 
1875  currReader->cbAtr = rContext->cardAtrLength;
1876  memcpy(currReader->rgbAtr, rContext->cardAtr,
1877  currReader->cbAtr);
1878  }
1879  else
1880  currReader->cbAtr = 0;
1881 
1882  /* Card is now absent */
1883  if (readerState & SCARD_ABSENT)
1884  {
1885  currReader->dwEventState |= SCARD_STATE_EMPTY;
1886  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1887  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1888  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1889  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1890  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1891  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1892  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1893  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1894 
1895  /* After present the rest are assumed */
1896  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1897  {
1898  currReader->dwEventState |= SCARD_STATE_CHANGED;
1899  Log0(PCSC_LOG_DEBUG);
1900  dwBreakFlag = 1;
1901  }
1902  }
1903  /* Card is now present */
1904  else if (readerState & SCARD_PRESENT)
1905  {
1906  currReader->dwEventState |= SCARD_STATE_PRESENT;
1907  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1908  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1909  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1910  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1911  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1912  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1913 
1914  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1915  {
1916  currReader->dwEventState |= SCARD_STATE_CHANGED;
1917  Log0(PCSC_LOG_DEBUG);
1918  dwBreakFlag = 1;
1919  }
1920 
1921  if (readerState & SCARD_SWALLOWED)
1922  {
1923  currReader->dwEventState |= SCARD_STATE_MUTE;
1924  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1925  {
1926  currReader->dwEventState |= SCARD_STATE_CHANGED;
1927  Log0(PCSC_LOG_DEBUG);
1928  dwBreakFlag = 1;
1929  }
1930  }
1931  else
1932  {
1933  /* App thinks card is mute but it is not */
1934  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1935  {
1936  currReader->dwEventState |= SCARD_STATE_CHANGED;
1937  Log0(PCSC_LOG_DEBUG);
1938  dwBreakFlag = 1;
1939  }
1940  }
1941  }
1942 
1943  /* Now figure out sharing modes */
1945  {
1946  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1947  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1948  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1949  {
1950  currReader->dwEventState |= SCARD_STATE_CHANGED;
1951  Log0(PCSC_LOG_DEBUG);
1952  dwBreakFlag = 1;
1953  }
1954  }
1955  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
1956  {
1957  /* A card must be inserted for it to be INUSE */
1958  if (readerState & SCARD_PRESENT)
1959  {
1960  currReader->dwEventState |= SCARD_STATE_INUSE;
1961  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1962  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
1963  {
1964  currReader->dwEventState |= SCARD_STATE_CHANGED;
1965  Log0(PCSC_LOG_DEBUG);
1966  dwBreakFlag = 1;
1967  }
1968  }
1969  }
1970  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
1971  {
1972  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1973  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1974 
1975  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1976  {
1977  currReader->dwEventState |= SCARD_STATE_CHANGED;
1978  Log0(PCSC_LOG_DEBUG);
1979  dwBreakFlag = 1;
1980  }
1981  else if (currReader-> dwCurrentState
1983  {
1984  currReader->dwEventState |= SCARD_STATE_CHANGED;
1985  Log0(PCSC_LOG_DEBUG);
1986  dwBreakFlag = 1;
1987  }
1988  }
1989 
1990  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
1991  {
1992  /*
1993  * Break out of the while .. loop and return status
1994  * once all the status's for all readers is met
1995  */
1996  currReader->dwEventState |= SCARD_STATE_CHANGED;
1997  Log0(PCSC_LOG_DEBUG);
1998  dwBreakFlag = 1;
1999  }
2000  } /* End of SCARD_STATE_UNKNOWN */
2001  } /* End of SCARD_STATE_IGNORE */
2002 
2003  /* Counter and resetter */
2004  j++;
2005  if (j == cReaders)
2006  {
2007  /* go back to the first reader */
2008  j = 0;
2009 
2010  /* Declare all the break conditions */
2011 
2012  /* Break if UNAWARE is set and all readers have been checked */
2013  if (dwBreakFlag == 1)
2014  break;
2015 
2016  /* Only sleep once for each cycle of reader checks. */
2017  {
2018  struct wait_reader_state_change waitStatusStruct;
2019  struct timeval before, after;
2020 
2021  gettimeofday(&before, NULL);
2022 
2023  waitStatusStruct.timeOut = dwTime;
2024  waitStatusStruct.rv = SCARD_S_SUCCESS;
2025 
2026  /* another thread can do SCardCancel() */
2027  currentContextMap->cancellable = TRUE;
2028 
2030  currentContextMap->dwClientID,
2031  sizeof(waitStatusStruct), &waitStatusStruct);
2032 
2033  if (rv != SCARD_S_SUCCESS)
2034  goto end;
2035 
2036  /*
2037  * Read a message from the server
2038  */
2040  &waitStatusStruct, sizeof(waitStatusStruct),
2041  currentContextMap->dwClientID, dwTime);
2042 
2043  /* another thread can do SCardCancel() */
2044  currentContextMap->cancellable = FALSE;
2045 
2046  /* timeout */
2047  if (SCARD_E_TIMEOUT == rv)
2048  {
2049  /* ask server to remove us from the event list */
2051  currentContextMap->dwClientID,
2052  sizeof(waitStatusStruct), &waitStatusStruct);
2053 
2054  if (rv != SCARD_S_SUCCESS)
2055  goto end;
2056 
2057  /* Read a message from the server */
2058  rv = MessageReceive(&waitStatusStruct,
2059  sizeof(waitStatusStruct),
2060  currentContextMap->dwClientID);
2061 
2062  if (rv != SCARD_S_SUCCESS)
2063  goto end;
2064  }
2065 
2066  if (rv != SCARD_S_SUCCESS)
2067  goto end;
2068 
2069  /* an event occurs or SCardCancel() was called */
2070  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2071  {
2072  rv = waitStatusStruct.rv;
2073  goto end;
2074  }
2075 
2076  /* synchronize reader states with daemon */
2077  rv = getReaderStates(currentContextMap);
2078  if (rv != SCARD_S_SUCCESS)
2079  goto end;
2080 
2081  if (INFINITE != dwTimeout)
2082  {
2083  long int diff;
2084 
2085  gettimeofday(&after, NULL);
2086  diff = time_sub(&after, &before);
2087  dwTime -= diff/1000;
2088  }
2089  }
2090 
2091  if (dwTimeout != INFINITE)
2092  {
2093  /* If time is greater than timeout and all readers have been
2094  * checked
2095  */
2096  if (dwTime <= 0)
2097  {
2098  rv = SCARD_E_TIMEOUT;
2099  goto end;
2100  }
2101  }
2102  }
2103  }
2104  while (1);
2105 
2106 end:
2107  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2108 
2109  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2110 
2111 error:
2112  PROFILE_END(rv)
2113 #ifdef DO_TRACE
2114  for (j=0; j<cReaders; j++)
2115  {
2116  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2117  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2118  }
2119 #endif
2120 
2121  return rv;
2122 }
2123 
2174 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2175  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2176  LPDWORD lpBytesReturned)
2177 {
2178  LONG rv;
2179  struct control_struct scControlStruct;
2180  SCONTEXTMAP * currentContextMap;
2181  CHANNEL_MAP * pChannelMap;
2182 
2183  PROFILE_START
2184 
2185  /* 0 bytes received by default */
2186  if (NULL != lpBytesReturned)
2187  *lpBytesReturned = 0;
2188 
2189  /*
2190  * Make sure this handle has been opened
2191  */
2192  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2193  &pChannelMap);
2194  if (rv == -1)
2195  {
2196  PROFILE_END(SCARD_E_INVALID_HANDLE)
2197  return SCARD_E_INVALID_HANDLE;
2198  }
2199 
2200  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2201  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2202  {
2204  goto end;
2205  }
2206 
2207  scControlStruct.hCard = hCard;
2208  scControlStruct.dwControlCode = dwControlCode;
2209  scControlStruct.cbSendLength = cbSendLength;
2210  scControlStruct.cbRecvLength = cbRecvLength;
2211  scControlStruct.dwBytesReturned = 0;
2212  scControlStruct.rv = 0;
2213 
2214  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2215  sizeof(scControlStruct), &scControlStruct);
2216 
2217  if (rv != SCARD_S_SUCCESS)
2218  goto end;
2219 
2220  /* write the sent buffer */
2221  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2222  currentContextMap->dwClientID);
2223 
2224  if (rv != SCARD_S_SUCCESS)
2225  goto end;
2226 
2227  /*
2228  * Read a message from the server
2229  */
2230  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2231  currentContextMap->dwClientID);
2232 
2233  if (rv != SCARD_S_SUCCESS)
2234  goto end;
2235 
2236  if (SCARD_S_SUCCESS == scControlStruct.rv)
2237  {
2238  /* read the received buffer */
2239  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2240  currentContextMap->dwClientID);
2241 
2242  if (rv != SCARD_S_SUCCESS)
2243  goto end;
2244 
2245  }
2246 
2247  if (NULL != lpBytesReturned)
2248  *lpBytesReturned = scControlStruct.dwBytesReturned;
2249 
2250  rv = scControlStruct.rv;
2251 
2252 end:
2253  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2254 
2255  PROFILE_END(rv)
2256 
2257  return rv;
2258 }
2259 
2364 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2365  LPDWORD pcbAttrLen)
2366 {
2367  LONG ret;
2368  unsigned char *buf = NULL;
2369 
2370  PROFILE_START
2371 
2372  if (NULL == pcbAttrLen)
2373  {
2375  goto end;
2376  }
2377 
2378  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2379  {
2380  if (NULL == pbAttr)
2382 
2383  *pcbAttrLen = MAX_BUFFER_SIZE;
2384  buf = malloc(*pcbAttrLen);
2385  if (NULL == buf)
2386  {
2387  ret = SCARD_E_NO_MEMORY;
2388  goto end;
2389  }
2390 
2391  *(unsigned char **)pbAttr = buf;
2392  }
2393  else
2394  {
2395  buf = pbAttr;
2396 
2397  /* if only get the length */
2398  if (NULL == pbAttr)
2399  /* use a reasonable size */
2400  *pcbAttrLen = MAX_BUFFER_SIZE;
2401  }
2402 
2403  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2404  pcbAttrLen);
2405 
2406 end:
2407  PROFILE_END(ret)
2408 
2409  return ret;
2410 }
2411 
2447 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2448  DWORD cbAttrLen)
2449 {
2450  LONG ret;
2451 
2452  PROFILE_START
2453 
2454  if (NULL == pbAttr || 0 == cbAttrLen)
2456 
2457  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2458  &cbAttrLen);
2459 
2460  PROFILE_END(ret)
2461 
2462  return ret;
2463 }
2464 
2465 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2466  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2467 {
2468  LONG rv;
2469  struct getset_struct scGetSetStruct;
2470  SCONTEXTMAP * currentContextMap;
2471  CHANNEL_MAP * pChannelMap;
2472 
2473  /*
2474  * Make sure this handle has been opened
2475  */
2476  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2477  &pChannelMap);
2478  if (rv == -1)
2479  return SCARD_E_INVALID_HANDLE;
2480 
2481  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2482  {
2484  goto end;
2485  }
2486 
2487  scGetSetStruct.hCard = hCard;
2488  scGetSetStruct.dwAttrId = dwAttrId;
2489  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2490  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2491  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2492  if (SCARD_SET_ATTRIB == command)
2493  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2494 
2495  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2496  sizeof(scGetSetStruct), &scGetSetStruct);
2497 
2498  if (rv != SCARD_S_SUCCESS)
2499  goto end;
2500 
2501  /*
2502  * Read a message from the server
2503  */
2504  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2505  currentContextMap->dwClientID);
2506 
2507  if (rv != SCARD_S_SUCCESS)
2508  goto end;
2509 
2510  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2511  {
2512  /*
2513  * Copy and zero it so any secret information is not leaked
2514  */
2515  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2516  {
2517  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2518  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2519  }
2520  else
2521  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2522 
2523  if (pbAttr)
2524  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2525 
2526  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2527  }
2528  rv = scGetSetStruct.rv;
2529 
2530 end:
2531  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2532 
2533  return rv;
2534 }
2535 
2594 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2595  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2596  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2597  LPDWORD pcbRecvLength)
2598 {
2599  LONG rv;
2600  SCONTEXTMAP * currentContextMap;
2601  CHANNEL_MAP * pChannelMap;
2602  struct transmit_struct scTransmitStruct;
2603 
2604  PROFILE_START
2605 
2606  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2607  pcbRecvLength == NULL || pioSendPci == NULL)
2609 
2610  /* Retry loop for blocking behaviour */
2611 retry:
2612 
2613  /*
2614  * Make sure this handle has been opened
2615  */
2616  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2617  &pChannelMap);
2618  if (rv == -1)
2619  {
2620  *pcbRecvLength = 0;
2621  PROFILE_END(SCARD_E_INVALID_HANDLE)
2622  return SCARD_E_INVALID_HANDLE;
2623  }
2624 
2625  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2626  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2627  {
2629  goto end;
2630  }
2631 
2632  scTransmitStruct.hCard = hCard;
2633  scTransmitStruct.cbSendLength = cbSendLength;
2634  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2635  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2636  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2637  scTransmitStruct.rv = SCARD_S_SUCCESS;
2638 
2639  if (pioRecvPci)
2640  {
2641  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2642  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2643  }
2644  else
2645  {
2646  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2647  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2648  }
2649 
2650  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2651  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2652 
2653  if (rv != SCARD_S_SUCCESS)
2654  goto end;
2655 
2656  /* write the sent buffer */
2657  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2658  currentContextMap->dwClientID);
2659 
2660  if (rv != SCARD_S_SUCCESS)
2661  goto end;
2662 
2663  /*
2664  * Read a message from the server
2665  */
2666  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2667  currentContextMap->dwClientID);
2668 
2669  if (rv != SCARD_S_SUCCESS)
2670  goto end;
2671 
2672  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2673  {
2674  /* read the received buffer */
2675  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2676  currentContextMap->dwClientID);
2677 
2678  if (rv != SCARD_S_SUCCESS)
2679  goto end;
2680 
2681  if (pioRecvPci)
2682  {
2683  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2684  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2685  }
2686  }
2687 
2688  rv = scTransmitStruct.rv;
2689 
2690  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2691  {
2692  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2694  goto retry;
2695  }
2696 
2697  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2698 
2699 end:
2700  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2701 
2702  PROFILE_END(rv)
2703 
2704  return rv;
2705 }
2706 
2760 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2761  LPSTR mszReaders, LPDWORD pcchReaders)
2762 {
2763  DWORD dwReadersLen = 0;
2764  int i;
2765  SCONTEXTMAP * currentContextMap;
2766  LONG rv = SCARD_S_SUCCESS;
2767  char *buf = NULL;
2768 
2769  (void)mszGroups;
2770  PROFILE_START
2771  API_TRACE_IN("%ld", hContext)
2772 
2773  /*
2774  * Check for NULL parameters
2775  */
2776  if (pcchReaders == NULL)
2778 
2779  /*
2780  * Make sure this context has been opened
2781  */
2782  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2783  if (NULL == currentContextMap)
2784  {
2785  PROFILE_END(SCARD_E_INVALID_HANDLE)
2786  return SCARD_E_INVALID_HANDLE;
2787  }
2788 
2789  /* synchronize reader states with daemon */
2790  rv = getReaderStates(currentContextMap);
2791  if (rv != SCARD_S_SUCCESS)
2792  goto end;
2793 
2794  dwReadersLen = 0;
2795  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2796  if (readerStates[i].readerName[0] != '\0')
2797  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2798 
2799  /* for the last NULL byte */
2800  dwReadersLen += 1;
2801 
2802  if (1 == dwReadersLen)
2803  {
2805  goto end;
2806  }
2807 
2808  if (SCARD_AUTOALLOCATE == *pcchReaders)
2809  {
2810  if (NULL == mszReaders)
2811  {
2813  goto end;
2814  }
2815  buf = malloc(dwReadersLen);
2816  if (NULL == buf)
2817  {
2818  rv = SCARD_E_NO_MEMORY;
2819  goto end;
2820  }
2821  *(char **)mszReaders = buf;
2822  }
2823  else
2824  {
2825  buf = mszReaders;
2826 
2827  /* not enough place to store the reader names */
2828  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2829  {
2831  goto end;
2832  }
2833  }
2834 
2835  if (mszReaders == NULL) /* text array not allocated */
2836  goto end;
2837 
2838  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2839  {
2840  if (readerStates[i].readerName[0] != '\0')
2841  {
2842  /*
2843  * Build the multi-string
2844  */
2845  strcpy(buf, readerStates[i].readerName);
2846  buf += strlen(readerStates[i].readerName)+1;
2847  }
2848  }
2849  *buf = '\0'; /* Add the last null */
2850 
2851 end:
2852  /* set the reader names length */
2853  *pcchReaders = dwReadersLen;
2854 
2855  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2856 
2857  PROFILE_END(rv)
2858  API_TRACE_OUT("%d", *pcchReaders)
2859 
2860  return rv;
2861 }
2862 
2876 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2877 {
2878  LONG rv = SCARD_S_SUCCESS;
2879  SCONTEXTMAP * currentContextMap;
2880 
2881  PROFILE_START
2882 
2883  /*
2884  * Make sure this context has been opened
2885  */
2886  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
2887  if (NULL == currentContextMap)
2888  return SCARD_E_INVALID_HANDLE;
2889 
2890  free((void *)pvMem);
2891 
2892  PROFILE_END(rv)
2893 
2894  return rv;
2895 }
2896 
2948 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2949  LPDWORD pcchGroups)
2950 {
2951  LONG rv = SCARD_S_SUCCESS;
2952  SCONTEXTMAP * currentContextMap;
2953  char *buf = NULL;
2954 
2955  PROFILE_START
2956 
2957  /* Multi-string with two trailing \0 */
2958  const char ReaderGroup[] = "SCard$DefaultReaders\0";
2959  const unsigned int dwGroups = sizeof(ReaderGroup);
2960 
2961  /*
2962  * Make sure this context has been opened
2963  */
2964  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2965  if (NULL == currentContextMap)
2966  return SCARD_E_INVALID_HANDLE;
2967 
2968  if (SCARD_AUTOALLOCATE == *pcchGroups)
2969  {
2970  if (NULL == mszGroups)
2971  {
2973  goto end;
2974  }
2975  buf = malloc(dwGroups);
2976  if (NULL == buf)
2977  {
2978  rv = SCARD_E_NO_MEMORY;
2979  goto end;
2980  }
2981  *(char **)mszGroups = buf;
2982  }
2983  else
2984  {
2985  buf = mszGroups;
2986 
2987  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
2988  {
2990  goto end;
2991  }
2992  }
2993 
2994  if (buf)
2995  memcpy(buf, ReaderGroup, dwGroups);
2996 
2997 end:
2998  *pcchGroups = dwGroups;
2999 
3000  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3001 
3002  PROFILE_END(rv)
3003 
3004  return rv;
3005 }
3006 
3037 {
3038  SCONTEXTMAP * currentContextMap;
3039  LONG rv = SCARD_S_SUCCESS;
3040  uint32_t dwClientID = 0;
3041  struct cancel_struct scCancelStruct;
3042 
3043  PROFILE_START
3044  API_TRACE_IN("%ld", hContext)
3045 
3046  /*
3047  * Make sure this context has been opened
3048  */
3049  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3050  if (NULL == currentContextMap)
3051  {
3053  goto error;
3054  }
3055 
3056  if (! currentContextMap->cancellable)
3057  {
3058  rv = SCARD_S_SUCCESS;
3059  goto error;
3060  }
3061 
3062  /* create a new connection to the server */
3063  if (ClientSetupSession(&dwClientID) != 0)
3064  {
3065  rv = SCARD_E_NO_SERVICE;
3066  goto error;
3067  }
3068 
3069  scCancelStruct.hContext = hContext;
3070  scCancelStruct.rv = SCARD_S_SUCCESS;
3071 
3072  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3073  sizeof(scCancelStruct), (void *) &scCancelStruct);
3074 
3075  if (rv != SCARD_S_SUCCESS)
3076  goto end;
3077 
3078  /*
3079  * Read a message from the server
3080  */
3081  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3082 
3083  if (rv != SCARD_S_SUCCESS)
3084  goto end;
3085 
3086  rv = scCancelStruct.rv;
3087 end:
3088  ClientCloseSession(dwClientID);
3089 
3090 error:
3091  PROFILE_END(rv)
3092  API_TRACE_OUT("")
3093 
3094  return rv;
3095 }
3096 
3121 {
3122  LONG rv;
3123  SCONTEXTMAP * currentContextMap;
3124 
3125  PROFILE_START
3126  API_TRACE_IN("%ld", hContext)
3127 
3128  rv = SCARD_S_SUCCESS;
3129 
3130  /*
3131  * Make sure this context has been opened
3132  */
3133  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3134  if (currentContextMap == NULL)
3136 
3137  PROFILE_END(rv)
3138  API_TRACE_OUT("")
3139 
3140  return rv;
3141 }
3142 
3159 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3160 {
3161  int lrv;
3162  SCONTEXTMAP * newContextMap;
3163 
3164  newContextMap = malloc(sizeof(SCONTEXTMAP));
3165  if (NULL == newContextMap)
3166  return SCARD_E_NO_MEMORY;
3167 
3168  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3169  newContextMap->hContext = hContext;
3170  newContextMap->dwClientID = dwClientID;
3171  newContextMap->cancellable = FALSE;
3172 
3173  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3174 
3175  lrv = list_init(&newContextMap->channelMapList);
3176  if (lrv < 0)
3177  {
3178  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3179  goto error;
3180  }
3181 
3182  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3183  CHANNEL_MAP_seeker);
3184  if (lrv <0)
3185  {
3186  Log2(PCSC_LOG_CRITICAL,
3187  "list_attributes_seeker failed with return value: %d", lrv);
3188  list_destroy(&newContextMap->channelMapList);
3189  goto error;
3190  }
3191 
3192  lrv = list_append(&contextMapList, newContextMap);
3193  if (lrv < 0)
3194  {
3195  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3196  lrv);
3197  list_destroy(&newContextMap->channelMapList);
3198  goto error;
3199  }
3200 
3201  return SCARD_S_SUCCESS;
3202 
3203 error:
3204 
3205  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3206  free(newContextMap);
3207 
3208  return SCARD_E_NO_MEMORY;
3209 }
3210 
3225 {
3226  SCONTEXTMAP * currentContextMap;
3227 
3228  (void)SCardLockThread();
3229  currentContextMap = SCardGetContextTH(hContext);
3230 
3231  /* lock the context (if available) */
3232  if (lock && NULL != currentContextMap)
3233  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3234 
3235  (void)SCardUnlockThread();
3236 
3237  return currentContextMap;
3238 }
3239 
3253 {
3254  return list_seek(&contextMapList, &hContext);
3255 }
3256 
3266 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3267 {
3268  SCONTEXTMAP * currentContextMap;
3269  currentContextMap = SCardGetContextTH(hContext);
3270 
3271  if (NULL == currentContextMap)
3272  return SCARD_E_INVALID_HANDLE;
3273  else
3274  return SCardCleanContext(currentContextMap);
3275 }
3276 
3277 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3278 {
3279  int list_index, lrv;
3280  int listSize;
3281  CHANNEL_MAP * currentChannelMap;
3282 
3283  targetContextMap->hContext = 0;
3284  (void)ClientCloseSession(targetContextMap->dwClientID);
3285  targetContextMap->dwClientID = 0;
3286  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3287 
3288  listSize = list_size(&targetContextMap->channelMapList);
3289  for (list_index = 0; list_index < listSize; list_index++)
3290  {
3291  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3292  list_index);
3293  if (NULL == currentChannelMap)
3294  {
3295  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3296  list_index);
3297  continue;
3298  }
3299  else
3300  {
3301  free(currentChannelMap->readerName);
3302  free(currentChannelMap);
3303  }
3304 
3305  }
3306  list_destroy(&targetContextMap->channelMapList);
3307 
3308  lrv = list_delete(&contextMapList, targetContextMap);
3309  if (lrv < 0)
3310  {
3311  Log2(PCSC_LOG_CRITICAL,
3312  "list_delete failed with return value: %d", lrv);
3313  }
3314 
3315  free(targetContextMap);
3316 
3317  return SCARD_S_SUCCESS;
3318 }
3319 
3320 /*
3321  * Functions for managing hCard values returned from SCardConnect.
3322  */
3323 
3324 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3325  LPCSTR readerName)
3326 {
3327  CHANNEL_MAP * newChannelMap;
3328  int lrv = -1;
3329 
3330  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3331  if (NULL == newChannelMap)
3332  return SCARD_E_NO_MEMORY;
3333 
3334  newChannelMap->hCard = hCard;
3335  newChannelMap->readerName = strdup(readerName);
3336 
3337  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3338  if (lrv < 0)
3339  {
3340  free(newChannelMap->readerName);
3341  free(newChannelMap);
3342  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3343  lrv);
3344  return SCARD_E_NO_MEMORY;
3345  }
3346 
3347  return SCARD_S_SUCCESS;
3348 }
3349 
3350 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3351 {
3352  SCONTEXTMAP * currentContextMap;
3353  CHANNEL_MAP * currentChannelMap;
3354  int lrv;
3355  LONG rv;
3356 
3357  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3358  &currentChannelMap);
3359  if (rv == -1)
3360  return SCARD_E_INVALID_HANDLE;
3361 
3362  free(currentChannelMap->readerName);
3363 
3364  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3365  if (lrv < 0)
3366  {
3367  Log2(PCSC_LOG_CRITICAL,
3368  "list_delete failed with return value: %d", lrv);
3369  }
3370 
3371  free(currentChannelMap);
3372 
3373  return SCARD_S_SUCCESS;
3374 }
3375 
3376 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3377  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3378 {
3379  LONG rv;
3380 
3381  if (0 == hCard)
3382  return -1;
3383 
3384  (void)SCardLockThread();
3385  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3386  targetChannelMap);
3387 
3388  if (SCARD_S_SUCCESS == rv)
3389  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3390 
3391  (void)SCardUnlockThread();
3392 
3393  return rv;
3394 }
3395 
3396 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3397  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3398 {
3399  int listSize;
3400  int list_index;
3401  SCONTEXTMAP * currentContextMap;
3402  CHANNEL_MAP * currentChannelMap;
3403 
3404  /* Best to get the caller a crash early if we fail unsafely */
3405  *targetContextMap = NULL;
3406  *targetChannelMap = NULL;
3407 
3408  listSize = list_size(&contextMapList);
3409 
3410  for (list_index = 0; list_index < listSize; list_index++)
3411  {
3412  currentContextMap = list_get_at(&contextMapList, list_index);
3413  if (currentContextMap == NULL)
3414  {
3415  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3416  list_index);
3417  continue;
3418  }
3419  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3420  &hCard);
3421  if (currentChannelMap != NULL)
3422  {
3423  *targetContextMap = currentContextMap;
3424  *targetChannelMap = currentChannelMap;
3425  return SCARD_S_SUCCESS;
3426  }
3427  }
3428 
3429  return -1;
3430 }
3431 
3440 {
3441  LONG rv;
3442  struct stat statBuffer;
3443  char *socketName;
3444 
3445  socketName = getSocketName();
3446  rv = stat(socketName, &statBuffer);
3447 
3448  if (rv != 0)
3449  {
3450  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3451  socketName, strerror(errno));
3452  return SCARD_E_NO_SERVICE;
3453  }
3454 
3455  return SCARD_S_SUCCESS;
3456 }
3457 
3458 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3459 {
3460  int32_t dwClientID = currentContextMap->dwClientID;
3461  LONG rv;
3462 
3463  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3464  if (rv != SCARD_S_SUCCESS)
3465  return rv;
3466 
3467  /* Read a message from the server */
3468  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3469  if (rv != SCARD_S_SUCCESS)
3470  return rv;
3471 
3472  return SCARD_S_SUCCESS;
3473 }
3474 
#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:268
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:296
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:269
#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:265
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:256
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:266
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:241
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:258
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:278
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:267
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:56
#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:283
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:270
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:240
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:271
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:135
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:297
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:55
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:245
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 SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
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:272
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:259
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:242
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:273
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:257
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.
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:264
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:274