pcsc-lite  1.8.16
winscard_clnt.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
3  *
4  * Copyright (C) 1999-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2005
9  * Martin Paljak <martin@paljak.pri.ee>
10  * Copyright (C) 2002-2011
11  * Ludovic Rousseau <ludovic.rousseau@free.fr>
12  * Copyright (C) 2009
13  * Jean-Luc Giraud <jlgiraud@googlemail.com>
14  *
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
18 
19 1. Redistributions of source code must retain the above copyright
20  notice, this list of conditions and the following disclaimer.
21 2. Redistributions in binary form must reproduce the above copyright
22  notice, this list of conditions and the following disclaimer in the
23  documentation and/or other materials provided with the distribution.
24 3. The name of the author may not be used to endorse or promote products
25  derived from this software without specific prior written permission.
26 
27 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
104 #include "config.h"
105 #include <stdlib.h>
106 #include <string.h>
107 #include <sys/types.h>
108 #include <fcntl.h>
109 #include <unistd.h>
110 #include <sys/un.h>
111 #include <errno.h>
112 #include <stddef.h>
113 #include <sys/time.h>
114 #include <pthread.h>
115 #include <sys/wait.h>
116 
117 #include "misc.h"
118 #include "pcscd.h"
119 #include "winscard.h"
120 #include "debuglog.h"
121 
122 #include "readerfactory.h"
123 #include "eventhandler.h"
124 #include "sys_generic.h"
125 #include "winscard_msg.h"
126 #include "utils.h"
127 
128 /* Display, on stderr, a trace of the WinSCard calls with arguments and
129  * results */
130 //#define DO_TRACE
131 
132 /* Profile the execution time of WinSCard calls */
133 //#define DO_PROFILE
134 
135 
137 #define SCARD_PROTOCOL_ANY_OLD 0x1000
138 
139 #ifndef TRUE
140 #define TRUE 1
141 #define FALSE 0
142 #endif
143 
144 static char sharing_shall_block = TRUE;
145 
146 #define COLOR_RED "\33[01;31m"
147 #define COLOR_GREEN "\33[32m"
148 #define COLOR_BLUE "\33[34m"
149 #define COLOR_MAGENTA "\33[35m"
150 #define COLOR_NORMAL "\33[0m"
151 
152 #ifdef DO_TRACE
153 
154 #include <stdio.h>
155 #include <stdarg.h>
156 
157 static void trace(const char *func, const char direction, const char *fmt, ...)
158 {
159  va_list args;
160 
161  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
162  direction, pthread_self(), func);
163 
164  fprintf(stderr, COLOR_MAGENTA);
165  va_start(args, fmt);
166  vfprintf(stderr, fmt, args);
167  va_end(args);
168 
169  fprintf(stderr, COLOR_NORMAL "\n");
170 }
171 
172 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
173 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
174 #else
175 #define API_TRACE_IN(...)
176 #define API_TRACE_OUT(...)
177 #endif
178 
179 #ifdef DO_PROFILE
180 
181 #define PROFILE_FILE "/tmp/pcsc_profile"
182 #include <stdio.h>
183 #include <sys/time.h>
184 
185 /* we can profile a maximum of 5 simultaneous calls */
186 #define MAX_THREADS 5
187 pthread_t threads[MAX_THREADS];
188 struct timeval profile_time_start[MAX_THREADS];
189 FILE *profile_fd;
190 char profile_tty;
191 
192 #define PROFILE_START profile_start();
193 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
194 
195 static void profile_start(void)
196 {
197  static char initialized = FALSE;
198  pthread_t t;
199  int i;
200 
201  if (!initialized)
202  {
203  char filename[80];
204 
205  initialized = TRUE;
206  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
207  profile_fd = fopen(filename, "a+");
208  if (NULL == profile_fd)
209  {
210  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
211  PROFILE_FILE, strerror(errno));
212  exit(-1);
213  }
214  fprintf(profile_fd, "\nStart a new profile\n");
215 
216  if (isatty(fileno(stderr)))
217  profile_tty = TRUE;
218  else
219  profile_tty = FALSE;
220  }
221 
222  t = pthread_self();
223  for (i=0; i<MAX_THREADS; i++)
224  if (pthread_equal(0, threads[i]))
225  {
226  threads[i] = t;
227  break;
228  }
229 
230  gettimeofday(&profile_time_start[i], NULL);
231 } /* profile_start */
232 
233 static void profile_end(const char *f, LONG rv)
234 {
235  struct timeval profile_time_end;
236  long d;
237  pthread_t t;
238  int i;
239 
240  gettimeofday(&profile_time_end, NULL);
241 
242  t = pthread_self();
243  for (i=0; i<MAX_THREADS; i++)
244  if (pthread_equal(t, threads[i]))
245  break;
246 
247  if (i>=MAX_THREADS)
248  {
249  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
250  return;
251  }
252 
253  d = time_sub(&profile_time_end, &profile_time_start[i]);
254 
255  /* free this entry */
256  threads[i] = 0;
257 
258  if (profile_tty)
259  {
260  if (rv != SCARD_S_SUCCESS)
261  fprintf(stderr,
262  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
263  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
264  f, d, rv, pcsc_stringify_error(rv));
265  else
266  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
267  COLOR_NORMAL "\n", f, d);
268  }
269  fprintf(profile_fd, "%s %ld\n", f, d);
270  fflush(profile_fd);
271 } /* profile_end */
272 
273 #else
274 #define PROFILE_START
275 #define PROFILE_END(rv)
276 #endif
277 
283 {
284  SCARDHANDLE hCard;
285  LPSTR readerName;
286 };
287 
288 typedef struct _psChannelMap CHANNEL_MAP;
289 
290 static int CHANNEL_MAP_seeker(const void *el, const void *key)
291 {
292  const CHANNEL_MAP * channelMap = el;
293 
294  if ((el == NULL) || (key == NULL))
295  {
296  Log3(PCSC_LOG_CRITICAL,
297  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
298  el, key);
299  return 0;
300  }
301 
302  if (channelMap->hCard == *(SCARDHANDLE *)key)
303  return 1;
304 
305  return 0;
306 }
307 
314 {
315  DWORD dwClientID;
317  pthread_mutex_t mMutex;
318  list_t channelMapList;
319  char cancellable;
320 };
321 typedef struct _psContextMap SCONTEXTMAP;
322 
323 static list_t contextMapList;
324 
325 static int SCONTEXTMAP_seeker(const void *el, const void *key)
326 {
327  const SCONTEXTMAP * contextMap = el;
328 
329  if ((el == NULL) || (key == NULL))
330  {
331  Log3(PCSC_LOG_CRITICAL,
332  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
333  el, key);
334  return 0;
335  }
336 
337  if (contextMap->hContext == *(SCARDCONTEXT *) key)
338  return 1;
339 
340  return 0;
341 }
342 
346 static short isExecuted = 0;
347 
348 
353 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
354 
359 
366 
367 
368 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
371 static LONG SCardRemoveContext(SCARDCONTEXT);
372 static LONG SCardCleanContext(SCONTEXTMAP *);
373 
374 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
375 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
376  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
377 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
378  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
379 static LONG SCardRemoveHandle(SCARDHANDLE);
380 
381 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
382  LPBYTE pbAttr, LPDWORD pcbAttrLen);
383 
384 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
385 
386 /*
387  * Thread safety functions
388  */
395 inline static LONG SCardLockThread(void)
396 {
397  return pthread_mutex_lock(&clientMutex);
398 }
399 
405 inline static LONG SCardUnlockThread(void)
406 {
407  return pthread_mutex_unlock(&clientMutex);
408 }
409 
410 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
411  /*@out@*/ LPSCARDCONTEXT);
412 
446 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
447  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
448 {
449  LONG rv;
450 
451  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
452  PROFILE_START
453 
454  /* Check if the server is running */
456  if (rv != SCARD_S_SUCCESS)
457  goto end;
458 
459  (void)SCardLockThread();
460  rv = SCardEstablishContextTH(dwScope, pvReserved1,
461  pvReserved2, phContext);
462  (void)SCardUnlockThread();
463 
464 end:
465  PROFILE_END(rv)
466  API_TRACE_OUT("%ld", *phContext)
467 
468  return rv;
469 }
470 
497 static LONG SCardEstablishContextTH(DWORD dwScope,
498  /*@unused@*/ LPCVOID pvReserved1,
499  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
500 {
501  LONG rv;
502  struct establish_struct scEstablishStruct;
503  uint32_t dwClientID = 0;
504 
505  (void)pvReserved1;
506  (void)pvReserved2;
507  if (phContext == NULL)
509  else
510  *phContext = 0;
511 
512  /*
513  * Do this only once:
514  * - Initialize context list.
515  */
516  if (isExecuted == 0)
517  {
518  int lrv;
519 
520  /* NOTE: The list will never be freed (No API call exists to
521  * "close all contexts".
522  * Applications which load and unload the library will leak
523  * the list's internal structures. */
524  lrv = list_init(&contextMapList);
525  if (lrv < 0)
526  {
527  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
528  lrv);
529  return SCARD_E_NO_MEMORY;
530  }
531 
532  lrv = list_attributes_seeker(&contextMapList,
533  SCONTEXTMAP_seeker);
534  if (lrv <0)
535  {
536  Log2(PCSC_LOG_CRITICAL,
537  "list_attributes_seeker failed with return value: %d", lrv);
538  list_destroy(&contextMapList);
539  return SCARD_E_NO_MEMORY;
540  }
541 
542  if (getenv("PCSCLITE_NO_BLOCKING"))
543  {
544  Log1(PCSC_LOG_INFO, "Disable shared blocking");
545  sharing_shall_block = FALSE;
546  }
547 
548  isExecuted = 1;
549  }
550 
551 
552  /* Establishes a connection to the server */
553  if (ClientSetupSession(&dwClientID) != 0)
554  {
555  return SCARD_E_NO_SERVICE;
556  }
557 
558  { /* exchange client/server protocol versions */
559  struct version_struct veStr;
560 
563  veStr.rv = SCARD_S_SUCCESS;
564 
565  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
566  &veStr);
567  if (rv != SCARD_S_SUCCESS)
568  return rv;
569 
570  /* Read a message from the server */
571  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
572  if (rv != SCARD_S_SUCCESS)
573  {
574  Log1(PCSC_LOG_CRITICAL,
575  "Your pcscd is too old and does not support CMD_VERSION");
576  return SCARD_F_COMM_ERROR;
577  }
578 
579  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
580  veStr.major, veStr.minor);
581 
582  if (veStr.rv != SCARD_S_SUCCESS)
583  return veStr.rv;
584  }
585 
586 again:
587  /*
588  * Try to establish an Application Context with the server
589  */
590  scEstablishStruct.dwScope = dwScope;
591  scEstablishStruct.hContext = 0;
592  scEstablishStruct.rv = SCARD_S_SUCCESS;
593 
595  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
596 
597  if (rv != SCARD_S_SUCCESS)
598  return rv;
599 
600  /*
601  * Read the response from the server
602  */
603  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
604  dwClientID);
605 
606  if (rv != SCARD_S_SUCCESS)
607  return rv;
608 
609  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
610  return scEstablishStruct.rv;
611 
612  /* check we do not reuse an existing hContext */
613  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
614  /* we do not need to release the allocated context since
615  * SCardReleaseContext() does nothing on the server side */
616  goto again;
617 
618  *phContext = scEstablishStruct.hContext;
619 
620  /*
621  * Allocate the new hContext - if allocator full return an error
622  */
623  rv = SCardAddContext(*phContext, dwClientID);
624 
625  return rv;
626 }
627 
650 {
651  LONG rv;
652  struct release_struct scReleaseStruct;
653  SCONTEXTMAP * currentContextMap;
654 
655  API_TRACE_IN("%ld", hContext)
656  PROFILE_START
657 
658  /*
659  * Make sure this context has been opened
660  * and get currentContextMap
661  */
662  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
663  if (NULL == currentContextMap)
664  {
666  goto error;
667  }
668 
669  scReleaseStruct.hContext = hContext;
670  scReleaseStruct.rv = SCARD_S_SUCCESS;
671 
673  currentContextMap->dwClientID,
674  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
675 
676  if (rv != SCARD_S_SUCCESS)
677  goto end;
678 
679  /*
680  * Read a message from the server
681  */
682  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
683  currentContextMap->dwClientID);
684 
685  if (rv != SCARD_S_SUCCESS)
686  goto end;
687 
688  rv = scReleaseStruct.rv;
689 end:
690  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
691 
692  /*
693  * Remove the local context from the stack
694  */
695  (void)SCardLockThread();
696  (void)SCardRemoveContext(hContext);
697  (void)SCardUnlockThread();
698 
699 error:
700  PROFILE_END(rv)
701  API_TRACE_OUT("")
702 
703  return rv;
704 }
705 
762 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
763  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
764  LPDWORD pdwActiveProtocol)
765 {
766  LONG rv;
767  struct connect_struct scConnectStruct;
768  SCONTEXTMAP * currentContextMap;
769 
770  PROFILE_START
771  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
772 
773  /*
774  * Check for NULL parameters
775  */
776  if (phCard == NULL || pdwActiveProtocol == NULL)
778  else
779  *phCard = 0;
780 
781  if (szReader == NULL)
782  return SCARD_E_UNKNOWN_READER;
783 
784  /*
785  * Check for uninitialized strings
786  */
787  if (strlen(szReader) > MAX_READERNAME)
788  return SCARD_E_INVALID_VALUE;
789 
790  /*
791  * Make sure this context has been opened
792  */
793  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
794  if (NULL == currentContextMap)
795  return SCARD_E_INVALID_HANDLE;
796 
797  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 szReaderName,
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 == szReaderName)
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 **)szReaderName = bufReader;
1488  }
1489  else
1490  bufReader = szReaderName;
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 
1631 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1632  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1633 {
1634  SCARD_READERSTATE *currReader;
1635  READER_STATE *rContext;
1636  long dwTime;
1637  DWORD dwBreakFlag = 0;
1638  unsigned int j;
1639  SCONTEXTMAP * currentContextMap;
1640  int currentReaderCount = 0;
1641  LONG rv = SCARD_S_SUCCESS;
1642 
1643  PROFILE_START
1644  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1645 #ifdef DO_TRACE
1646  for (j=0; j<cReaders; j++)
1647  {
1648  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1649  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1650  }
1651 #endif
1652 
1653  if ((rgReaderStates == NULL && cReaders > 0)
1654  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1655  {
1657  goto error;
1658  }
1659 
1660  /* Check the integrity of the reader states structures */
1661  for (j = 0; j < cReaders; j++)
1662  {
1663  if (rgReaderStates[j].szReader == NULL)
1664  return SCARD_E_INVALID_VALUE;
1665  }
1666 
1667  /* return if all readers are SCARD_STATE_IGNORE */
1668  if (cReaders > 0)
1669  {
1670  int nbNonIgnoredReaders = cReaders;
1671 
1672  for (j=0; j<cReaders; j++)
1673  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1674  nbNonIgnoredReaders--;
1675 
1676  if (0 == nbNonIgnoredReaders)
1677  {
1678  rv = SCARD_S_SUCCESS;
1679  goto error;
1680  }
1681  }
1682  else
1683  {
1684  /* reader list is empty */
1685  rv = SCARD_S_SUCCESS;
1686  goto error;
1687  }
1688 
1689  /*
1690  * Make sure this context has been opened
1691  */
1692  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
1693  if (NULL == currentContextMap)
1694  {
1696  goto error;
1697  }
1698 
1699  /* synchronize reader states with daemon */
1700  rv = getReaderStates(currentContextMap);
1701  if (rv != SCARD_S_SUCCESS)
1702  goto end;
1703 
1704  /* check all the readers are already known */
1705  for (j=0; j<cReaders; j++)
1706  {
1707  const char *readerName;
1708  int i;
1709 
1710  readerName = rgReaderStates[j].szReader;
1711  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1712  {
1713  if (strcmp(readerName, readerStates[i].readerName) == 0)
1714  break;
1715  }
1716 
1717  /* The requested reader name is not recognized */
1718  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1719  {
1720  /* PnP special reader? */
1721  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1722  {
1724  goto end;
1725  }
1726  }
1727  }
1728 
1729  /* Clear the event state for all readers */
1730  for (j = 0; j < cReaders; j++)
1731  rgReaderStates[j].dwEventState = 0;
1732 
1733  /* Now is where we start our event checking loop */
1734  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1735 
1736  /* Get the initial reader count on the system */
1737  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1738  if (readerStates[j].readerName[0] != '\0')
1739  currentReaderCount++;
1740 
1741  /* catch possible sign extension problems from 32 to 64-bits integers */
1742  if ((DWORD)-1 == dwTimeout)
1743  dwTimeout = INFINITE;
1744  if (INFINITE == dwTimeout)
1745  dwTime = 60*1000; /* "infinite" timeout */
1746  else
1747  dwTime = dwTimeout;
1748 
1749  j = 0;
1750  do
1751  {
1752  currReader = &rgReaderStates[j];
1753 
1754  /* Ignore for IGNORED readers */
1755  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1756  {
1757  const char *readerName;
1758  int i;
1759 
1760  /* Looks for correct readernames */
1761  readerName = currReader->szReader;
1762  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1763  {
1764  if (strcmp(readerName, readerStates[i].readerName) == 0)
1765  break;
1766  }
1767 
1768  /* The requested reader name is not recognized */
1769  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1770  {
1771  /* PnP special reader? */
1772  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1773  {
1774  int k, newReaderCount = 0;
1775 
1776  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1777  if (readerStates[k].readerName[0] != '\0')
1778  newReaderCount++;
1779 
1780  if (newReaderCount != currentReaderCount)
1781  {
1782  Log1(PCSC_LOG_INFO, "Reader list changed");
1783  currentReaderCount = newReaderCount;
1784 
1785  currReader->dwEventState |= SCARD_STATE_CHANGED;
1786  dwBreakFlag = 1;
1787  }
1788  }
1789  else
1790  {
1791  currReader->dwEventState =
1793  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1794  {
1795  currReader->dwEventState |= SCARD_STATE_CHANGED;
1796  /*
1797  * Spec says use SCARD_STATE_IGNORE but a removed USB
1798  * reader with eventState fed into currentState will
1799  * be ignored forever
1800  */
1801  dwBreakFlag = 1;
1802  }
1803  }
1804  }
1805  else
1806  {
1807  uint32_t readerState;
1808 
1809  /* The reader has come back after being away */
1810  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1811  {
1812  currReader->dwEventState |= SCARD_STATE_CHANGED;
1813  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1814  Log0(PCSC_LOG_DEBUG);
1815  dwBreakFlag = 1;
1816  }
1817 
1818  /* Set the reader status structure */
1819  rContext = &readerStates[i];
1820 
1821  /* Now we check all the Reader States */
1822  readerState = rContext->readerState;
1823 
1824  /* only if current state has an non null event counter */
1825  if (currReader->dwCurrentState & 0xFFFF0000)
1826  {
1827  unsigned int currentCounter;
1828 
1829  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1830 
1831  /* has the event counter changed since the last call? */
1832  if (rContext->eventCounter != currentCounter)
1833  {
1834  currReader->dwEventState |= SCARD_STATE_CHANGED;
1835  Log0(PCSC_LOG_DEBUG);
1836  dwBreakFlag = 1;
1837  }
1838  }
1839 
1840  /* add an event counter in the upper word of dwEventState */
1841  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1842  | (rContext->eventCounter << 16));
1843 
1844  /* Check if the reader is in the correct state */
1845  if (readerState & SCARD_UNKNOWN)
1846  {
1847  /* reader is in bad state */
1848  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1849  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1850  {
1851  /* App thinks reader is in good state and it is not */
1852  currReader->dwEventState |= SCARD_STATE_CHANGED;
1853  Log0(PCSC_LOG_DEBUG);
1854  dwBreakFlag = 1;
1855  }
1856  }
1857  else
1858  {
1859  /* App thinks reader in bad state but it is not */
1860  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1861  {
1862  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1863  currReader->dwEventState |= SCARD_STATE_CHANGED;
1864  Log0(PCSC_LOG_DEBUG);
1865  dwBreakFlag = 1;
1866  }
1867  }
1868 
1869  /* Check for card presence in the reader */
1870  if (readerState & SCARD_PRESENT)
1871  {
1872  /* card present but not yet powered up */
1873  if (0 == rContext->cardAtrLength)
1874  /* Allow the status thread to convey information */
1876 
1877  currReader->cbAtr = rContext->cardAtrLength;
1878  memcpy(currReader->rgbAtr, rContext->cardAtr,
1879  currReader->cbAtr);
1880  }
1881  else
1882  currReader->cbAtr = 0;
1883 
1884  /* Card is now absent */
1885  if (readerState & SCARD_ABSENT)
1886  {
1887  currReader->dwEventState |= SCARD_STATE_EMPTY;
1888  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1889  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1890  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1891  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1892  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1893  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1894  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1895  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1896 
1897  /* After present the rest are assumed */
1898  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1899  {
1900  currReader->dwEventState |= SCARD_STATE_CHANGED;
1901  Log0(PCSC_LOG_DEBUG);
1902  dwBreakFlag = 1;
1903  }
1904  }
1905  /* Card is now present */
1906  else if (readerState & SCARD_PRESENT)
1907  {
1908  currReader->dwEventState |= SCARD_STATE_PRESENT;
1909  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1910  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1911  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1912  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1913  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1914  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1915 
1916  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1917  {
1918  currReader->dwEventState |= SCARD_STATE_CHANGED;
1919  Log0(PCSC_LOG_DEBUG);
1920  dwBreakFlag = 1;
1921  }
1922 
1923  if (readerState & SCARD_SWALLOWED)
1924  {
1925  currReader->dwEventState |= SCARD_STATE_MUTE;
1926  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1927  {
1928  currReader->dwEventState |= SCARD_STATE_CHANGED;
1929  Log0(PCSC_LOG_DEBUG);
1930  dwBreakFlag = 1;
1931  }
1932  }
1933  else
1934  {
1935  /* App thinks card is mute but it is not */
1936  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1937  {
1938  currReader->dwEventState |= SCARD_STATE_CHANGED;
1939  Log0(PCSC_LOG_DEBUG);
1940  dwBreakFlag = 1;
1941  }
1942  }
1943  }
1944 
1945  /* Now figure out sharing modes */
1947  {
1948  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1949  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1950  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1951  {
1952  currReader->dwEventState |= SCARD_STATE_CHANGED;
1953  Log0(PCSC_LOG_DEBUG);
1954  dwBreakFlag = 1;
1955  }
1956  }
1957  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
1958  {
1959  /* A card must be inserted for it to be INUSE */
1960  if (readerState & SCARD_PRESENT)
1961  {
1962  currReader->dwEventState |= SCARD_STATE_INUSE;
1963  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1964  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
1965  {
1966  currReader->dwEventState |= SCARD_STATE_CHANGED;
1967  Log0(PCSC_LOG_DEBUG);
1968  dwBreakFlag = 1;
1969  }
1970  }
1971  }
1972  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
1973  {
1974  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1975  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1976 
1977  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1978  {
1979  currReader->dwEventState |= SCARD_STATE_CHANGED;
1980  Log0(PCSC_LOG_DEBUG);
1981  dwBreakFlag = 1;
1982  }
1983  else if (currReader-> dwCurrentState
1985  {
1986  currReader->dwEventState |= SCARD_STATE_CHANGED;
1987  Log0(PCSC_LOG_DEBUG);
1988  dwBreakFlag = 1;
1989  }
1990  }
1991 
1992  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
1993  {
1994  /*
1995  * Break out of the while .. loop and return status
1996  * once all the status's for all readers is met
1997  */
1998  currReader->dwEventState |= SCARD_STATE_CHANGED;
1999  Log0(PCSC_LOG_DEBUG);
2000  dwBreakFlag = 1;
2001  }
2002  } /* End of SCARD_STATE_UNKNOWN */
2003  } /* End of SCARD_STATE_IGNORE */
2004 
2005  /* Counter and resetter */
2006  j++;
2007  if (j == cReaders)
2008  {
2009  /* go back to the first reader */
2010  j = 0;
2011 
2012  /* Declare all the break conditions */
2013 
2014  /* Break if UNAWARE is set and all readers have been checked */
2015  if (dwBreakFlag == 1)
2016  break;
2017 
2018  /* Only sleep once for each cycle of reader checks. */
2019  {
2020  struct wait_reader_state_change waitStatusStruct;
2021  struct timeval before, after;
2022 
2023  gettimeofday(&before, NULL);
2024 
2025  waitStatusStruct.timeOut = dwTime;
2026  waitStatusStruct.rv = SCARD_S_SUCCESS;
2027 
2028  /* another thread can do SCardCancel() */
2029  currentContextMap->cancellable = TRUE;
2030 
2032  currentContextMap->dwClientID,
2033  sizeof(waitStatusStruct), &waitStatusStruct);
2034 
2035  if (rv != SCARD_S_SUCCESS)
2036  goto end;
2037 
2038  /*
2039  * Read a message from the server
2040  */
2042  &waitStatusStruct, sizeof(waitStatusStruct),
2043  currentContextMap->dwClientID, dwTime);
2044 
2045  /* another thread can do SCardCancel() */
2046  currentContextMap->cancellable = FALSE;
2047 
2048  /* timeout */
2049  if (SCARD_E_TIMEOUT == rv)
2050  {
2051  /* ask server to remove us from the event list */
2053  currentContextMap->dwClientID,
2054  sizeof(waitStatusStruct), &waitStatusStruct);
2055 
2056  if (rv != SCARD_S_SUCCESS)
2057  goto end;
2058 
2059  /* Read a message from the server */
2060  rv = MessageReceive(&waitStatusStruct,
2061  sizeof(waitStatusStruct),
2062  currentContextMap->dwClientID);
2063 
2064  if (rv != SCARD_S_SUCCESS)
2065  goto end;
2066  }
2067 
2068  if (rv != SCARD_S_SUCCESS)
2069  goto end;
2070 
2071  /* an event occurs or SCardCancel() was called */
2072  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2073  {
2074  rv = waitStatusStruct.rv;
2075  goto end;
2076  }
2077 
2078  /* synchronize reader states with daemon */
2079  rv = getReaderStates(currentContextMap);
2080  if (rv != SCARD_S_SUCCESS)
2081  goto end;
2082 
2083  if (INFINITE != dwTimeout)
2084  {
2085  long int diff;
2086 
2087  gettimeofday(&after, NULL);
2088  diff = time_sub(&after, &before);
2089  dwTime -= diff/1000;
2090  }
2091  }
2092 
2093  if (dwTimeout != INFINITE)
2094  {
2095  /* If time is greater than timeout and all readers have been
2096  * checked
2097  */
2098  if (dwTime <= 0)
2099  {
2100  rv = SCARD_E_TIMEOUT;
2101  goto end;
2102  }
2103  }
2104  }
2105  }
2106  while (1);
2107 
2108 end:
2109  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2110 
2111  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2112 
2113 error:
2114  PROFILE_END(rv)
2115 #ifdef DO_TRACE
2116  for (j=0; j<cReaders; j++)
2117  {
2118  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2119  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2120  }
2121 #endif
2122 
2123  return rv;
2124 }
2125 
2176 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2177  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2178  LPDWORD lpBytesReturned)
2179 {
2180  LONG rv;
2181  struct control_struct scControlStruct;
2182  SCONTEXTMAP * currentContextMap;
2183  CHANNEL_MAP * pChannelMap;
2184 
2185  PROFILE_START
2186 
2187  /* 0 bytes received by default */
2188  if (NULL != lpBytesReturned)
2189  *lpBytesReturned = 0;
2190 
2191  /*
2192  * Make sure this handle has been opened
2193  */
2194  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2195  &pChannelMap);
2196  if (rv == -1)
2197  {
2198  PROFILE_END(SCARD_E_INVALID_HANDLE)
2199  return SCARD_E_INVALID_HANDLE;
2200  }
2201 
2202  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2203  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2204  {
2206  goto end;
2207  }
2208 
2209  scControlStruct.hCard = hCard;
2210  scControlStruct.dwControlCode = dwControlCode;
2211  scControlStruct.cbSendLength = cbSendLength;
2212  scControlStruct.cbRecvLength = cbRecvLength;
2213  scControlStruct.dwBytesReturned = 0;
2214  scControlStruct.rv = 0;
2215 
2216  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2217  sizeof(scControlStruct), &scControlStruct);
2218 
2219  if (rv != SCARD_S_SUCCESS)
2220  goto end;
2221 
2222  /* write the sent buffer */
2223  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2224  currentContextMap->dwClientID);
2225 
2226  if (rv != SCARD_S_SUCCESS)
2227  goto end;
2228 
2229  /*
2230  * Read a message from the server
2231  */
2232  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2233  currentContextMap->dwClientID);
2234 
2235  if (rv != SCARD_S_SUCCESS)
2236  goto end;
2237 
2238  if (SCARD_S_SUCCESS == scControlStruct.rv)
2239  {
2240  /* read the received buffer */
2241  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2242  currentContextMap->dwClientID);
2243 
2244  if (rv != SCARD_S_SUCCESS)
2245  goto end;
2246 
2247  }
2248 
2249  if (NULL != lpBytesReturned)
2250  *lpBytesReturned = scControlStruct.dwBytesReturned;
2251 
2252  rv = scControlStruct.rv;
2253 
2254 end:
2255  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2256 
2257  PROFILE_END(rv)
2258 
2259  return rv;
2260 }
2261 
2368 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2369  LPDWORD pcbAttrLen)
2370 {
2371  LONG ret;
2372  unsigned char *buf = NULL;
2373 
2374  PROFILE_START
2375 
2376  if (NULL == pcbAttrLen)
2377  {
2379  goto end;
2380  }
2381 
2382  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2383  {
2384  if (NULL == pbAttr)
2386 
2387  *pcbAttrLen = MAX_BUFFER_SIZE;
2388  buf = malloc(*pcbAttrLen);
2389  if (NULL == buf)
2390  {
2391  ret = SCARD_E_NO_MEMORY;
2392  goto end;
2393  }
2394 
2395  *(unsigned char **)pbAttr = buf;
2396  }
2397  else
2398  {
2399  buf = pbAttr;
2400 
2401  /* if only get the length */
2402  if (NULL == pbAttr)
2403  /* use a reasonable size */
2404  *pcbAttrLen = MAX_BUFFER_SIZE;
2405  }
2406 
2407  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2408  pcbAttrLen);
2409 
2410 end:
2411  PROFILE_END(ret)
2412 
2413  return ret;
2414 }
2415 
2451 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2452  DWORD cbAttrLen)
2453 {
2454  LONG ret;
2455 
2456  PROFILE_START
2457 
2458  if (NULL == pbAttr || 0 == cbAttrLen)
2460 
2461  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2462  &cbAttrLen);
2463 
2464  PROFILE_END(ret)
2465 
2466  return ret;
2467 }
2468 
2469 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2470  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2471 {
2472  LONG rv;
2473  struct getset_struct scGetSetStruct;
2474  SCONTEXTMAP * currentContextMap;
2475  CHANNEL_MAP * pChannelMap;
2476 
2477  /*
2478  * Make sure this handle has been opened
2479  */
2480  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2481  &pChannelMap);
2482  if (rv == -1)
2483  return SCARD_E_INVALID_HANDLE;
2484 
2485  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2486  {
2488  goto end;
2489  }
2490 
2491  scGetSetStruct.hCard = hCard;
2492  scGetSetStruct.dwAttrId = dwAttrId;
2493  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2494  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2495  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2496  if (SCARD_SET_ATTRIB == command)
2497  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2498 
2499  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2500  sizeof(scGetSetStruct), &scGetSetStruct);
2501 
2502  if (rv != SCARD_S_SUCCESS)
2503  goto end;
2504 
2505  /*
2506  * Read a message from the server
2507  */
2508  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2509  currentContextMap->dwClientID);
2510 
2511  if (rv != SCARD_S_SUCCESS)
2512  goto end;
2513 
2514  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2515  {
2516  /*
2517  * Copy and zero it so any secret information is not leaked
2518  */
2519  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2520  {
2521  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2522  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2523  }
2524  else
2525  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2526 
2527  if (pbAttr)
2528  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2529 
2530  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2531  }
2532  rv = scGetSetStruct.rv;
2533 
2534 end:
2535  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2536 
2537  return rv;
2538 }
2539 
2598 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2599  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2600  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2601  LPDWORD pcbRecvLength)
2602 {
2603  LONG rv;
2604  SCONTEXTMAP * currentContextMap;
2605  CHANNEL_MAP * pChannelMap;
2606  struct transmit_struct scTransmitStruct;
2607 
2608  PROFILE_START
2609 
2610  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2611  pcbRecvLength == NULL || pioSendPci == NULL)
2613 
2614  /* Retry loop for blocking behaviour */
2615 retry:
2616 
2617  /*
2618  * Make sure this handle has been opened
2619  */
2620  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2621  &pChannelMap);
2622  if (rv == -1)
2623  {
2624  *pcbRecvLength = 0;
2625  PROFILE_END(SCARD_E_INVALID_HANDLE)
2626  return SCARD_E_INVALID_HANDLE;
2627  }
2628 
2629  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2630  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2631  {
2633  goto end;
2634  }
2635 
2636  scTransmitStruct.hCard = hCard;
2637  scTransmitStruct.cbSendLength = cbSendLength;
2638  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2639  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2640  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2641  scTransmitStruct.rv = SCARD_S_SUCCESS;
2642 
2643  if (pioRecvPci)
2644  {
2645  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2646  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2647  }
2648  else
2649  {
2650  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2651  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2652  }
2653 
2654  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2655  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2656 
2657  if (rv != SCARD_S_SUCCESS)
2658  goto end;
2659 
2660  /* write the sent buffer */
2661  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2662  currentContextMap->dwClientID);
2663 
2664  if (rv != SCARD_S_SUCCESS)
2665  goto end;
2666 
2667  /*
2668  * Read a message from the server
2669  */
2670  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2671  currentContextMap->dwClientID);
2672 
2673  if (rv != SCARD_S_SUCCESS)
2674  goto end;
2675 
2676  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2677  {
2678  /* read the received buffer */
2679  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2680  currentContextMap->dwClientID);
2681 
2682  if (rv != SCARD_S_SUCCESS)
2683  goto end;
2684 
2685  if (pioRecvPci)
2686  {
2687  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2688  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2689  }
2690  }
2691 
2692  rv = scTransmitStruct.rv;
2693 
2694  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2695  {
2696  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2698  goto retry;
2699  }
2700 
2701  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2702 
2703 end:
2704  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2705 
2706  PROFILE_END(rv)
2707 
2708  return rv;
2709 }
2710 
2764 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2765  LPSTR mszReaders, LPDWORD pcchReaders)
2766 {
2767  DWORD dwReadersLen = 0;
2768  int i;
2769  SCONTEXTMAP * currentContextMap;
2770  LONG rv = SCARD_S_SUCCESS;
2771  char *buf = NULL;
2772 
2773  (void)mszGroups;
2774  PROFILE_START
2775  API_TRACE_IN("%ld", hContext)
2776 
2777  /*
2778  * Check for NULL parameters
2779  */
2780  if (pcchReaders == NULL)
2782 
2783  /*
2784  * Make sure this context has been opened
2785  */
2786  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2787  if (NULL == currentContextMap)
2788  {
2789  PROFILE_END(SCARD_E_INVALID_HANDLE)
2790  return SCARD_E_INVALID_HANDLE;
2791  }
2792 
2793  /* synchronize reader states with daemon */
2794  rv = getReaderStates(currentContextMap);
2795  if (rv != SCARD_S_SUCCESS)
2796  goto end;
2797 
2798  dwReadersLen = 0;
2799  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2800  if (readerStates[i].readerName[0] != '\0')
2801  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2802 
2803  /* for the last NULL byte */
2804  dwReadersLen += 1;
2805 
2806  if (1 == dwReadersLen)
2807  {
2809  goto end;
2810  }
2811 
2812  if (SCARD_AUTOALLOCATE == *pcchReaders)
2813  {
2814  if (NULL == mszReaders)
2815  {
2817  goto end;
2818  }
2819  buf = malloc(dwReadersLen);
2820  if (NULL == buf)
2821  {
2822  rv = SCARD_E_NO_MEMORY;
2823  goto end;
2824  }
2825  *(char **)mszReaders = buf;
2826  }
2827  else
2828  {
2829  buf = mszReaders;
2830 
2831  /* not enough place to store the reader names */
2832  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2833  {
2835  goto end;
2836  }
2837  }
2838 
2839  if (mszReaders == NULL) /* text array not allocated */
2840  goto end;
2841 
2842  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2843  {
2844  if (readerStates[i].readerName[0] != '\0')
2845  {
2846  /*
2847  * Build the multi-string
2848  */
2849  strcpy(buf, readerStates[i].readerName);
2850  buf += strlen(readerStates[i].readerName)+1;
2851  }
2852  }
2853  *buf = '\0'; /* Add the last null */
2854 
2855 end:
2856  /* set the reader names length */
2857  *pcchReaders = dwReadersLen;
2858 
2859  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2860 
2861  PROFILE_END(rv)
2862  API_TRACE_OUT("%d", *pcchReaders)
2863 
2864  return rv;
2865 }
2866 
2880 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2881 {
2882  LONG rv = SCARD_S_SUCCESS;
2883  SCONTEXTMAP * currentContextMap;
2884 
2885  PROFILE_START
2886 
2887  /*
2888  * Make sure this context has been opened
2889  */
2890  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
2891  if (NULL == currentContextMap)
2892  return SCARD_E_INVALID_HANDLE;
2893 
2894  free((void *)pvMem);
2895 
2896  PROFILE_END(rv)
2897 
2898  return rv;
2899 }
2900 
2952 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2953  LPDWORD pcchGroups)
2954 {
2955  LONG rv = SCARD_S_SUCCESS;
2956  SCONTEXTMAP * currentContextMap;
2957  char *buf = NULL;
2958 
2959  PROFILE_START
2960 
2961  /* Multi-string with two trailing \0 */
2962  const char ReaderGroup[] = "SCard$DefaultReaders\0";
2963  const unsigned int dwGroups = sizeof(ReaderGroup);
2964 
2965  /*
2966  * Make sure this context has been opened
2967  */
2968  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2969  if (NULL == currentContextMap)
2970  return SCARD_E_INVALID_HANDLE;
2971 
2972  if (SCARD_AUTOALLOCATE == *pcchGroups)
2973  {
2974  if (NULL == mszGroups)
2975  {
2977  goto end;
2978  }
2979  buf = malloc(dwGroups);
2980  if (NULL == buf)
2981  {
2982  rv = SCARD_E_NO_MEMORY;
2983  goto end;
2984  }
2985  *(char **)mszGroups = buf;
2986  }
2987  else
2988  {
2989  buf = mszGroups;
2990 
2991  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
2992  {
2994  goto end;
2995  }
2996  }
2997 
2998  if (buf)
2999  memcpy(buf, ReaderGroup, dwGroups);
3000 
3001 end:
3002  *pcchGroups = dwGroups;
3003 
3004  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3005 
3006  PROFILE_END(rv)
3007 
3008  return rv;
3009 }
3010 
3042 {
3043  SCONTEXTMAP * currentContextMap;
3044  LONG rv = SCARD_S_SUCCESS;
3045  uint32_t dwClientID = 0;
3046  struct cancel_struct scCancelStruct;
3047 
3048  PROFILE_START
3049  API_TRACE_IN("%ld", hContext)
3050 
3051  /*
3052  * Make sure this context has been opened
3053  */
3054  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3055  if (NULL == currentContextMap)
3056  {
3058  goto error;
3059  }
3060 
3061  if (! currentContextMap->cancellable)
3062  {
3063  rv = SCARD_S_SUCCESS;
3064  goto error;
3065  }
3066 
3067  /* create a new connection to the server */
3068  if (ClientSetupSession(&dwClientID) != 0)
3069  {
3070  rv = SCARD_E_NO_SERVICE;
3071  goto error;
3072  }
3073 
3074  scCancelStruct.hContext = hContext;
3075  scCancelStruct.rv = SCARD_S_SUCCESS;
3076 
3077  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3078  sizeof(scCancelStruct), (void *) &scCancelStruct);
3079 
3080  if (rv != SCARD_S_SUCCESS)
3081  goto end;
3082 
3083  /*
3084  * Read a message from the server
3085  */
3086  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3087 
3088  if (rv != SCARD_S_SUCCESS)
3089  goto end;
3090 
3091  rv = scCancelStruct.rv;
3092 end:
3093  ClientCloseSession(dwClientID);
3094 
3095 error:
3096  PROFILE_END(rv)
3097  API_TRACE_OUT("")
3098 
3099  return rv;
3100 }
3101 
3126 {
3127  LONG rv;
3128  SCONTEXTMAP * currentContextMap;
3129 
3130  PROFILE_START
3131  API_TRACE_IN("%ld", hContext)
3132 
3133  rv = SCARD_S_SUCCESS;
3134 
3135  /*
3136  * Make sure this context has been opened
3137  */
3138  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3139  if (currentContextMap == NULL)
3141 
3142  PROFILE_END(rv)
3143  API_TRACE_OUT("")
3144 
3145  return rv;
3146 }
3147 
3164 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3165 {
3166  int lrv;
3167  SCONTEXTMAP * newContextMap;
3168 
3169  newContextMap = malloc(sizeof(SCONTEXTMAP));
3170  if (NULL == newContextMap)
3171  return SCARD_E_NO_MEMORY;
3172 
3173  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3174  newContextMap->hContext = hContext;
3175  newContextMap->dwClientID = dwClientID;
3176  newContextMap->cancellable = FALSE;
3177 
3178  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3179 
3180  lrv = list_init(&newContextMap->channelMapList);
3181  if (lrv < 0)
3182  {
3183  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3184  goto error;
3185  }
3186 
3187  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3188  CHANNEL_MAP_seeker);
3189  if (lrv <0)
3190  {
3191  Log2(PCSC_LOG_CRITICAL,
3192  "list_attributes_seeker failed with return value: %d", lrv);
3193  list_destroy(&newContextMap->channelMapList);
3194  goto error;
3195  }
3196 
3197  lrv = list_append(&contextMapList, newContextMap);
3198  if (lrv < 0)
3199  {
3200  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3201  lrv);
3202  list_destroy(&newContextMap->channelMapList);
3203  goto error;
3204  }
3205 
3206  return SCARD_S_SUCCESS;
3207 
3208 error:
3209 
3210  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3211  free(newContextMap);
3212 
3213  return SCARD_E_NO_MEMORY;
3214 }
3215 
3230 {
3231  SCONTEXTMAP * currentContextMap;
3232 
3233  (void)SCardLockThread();
3234  currentContextMap = SCardGetContextTH(hContext);
3235 
3236  /* lock the context (if available) */
3237  if (lock && NULL != currentContextMap)
3238  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3239 
3240  (void)SCardUnlockThread();
3241 
3242  return currentContextMap;
3243 }
3244 
3258 {
3259  return list_seek(&contextMapList, &hContext);
3260 }
3261 
3271 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3272 {
3273  SCONTEXTMAP * currentContextMap;
3274  currentContextMap = SCardGetContextTH(hContext);
3275 
3276  if (NULL == currentContextMap)
3277  return SCARD_E_INVALID_HANDLE;
3278  else
3279  return SCardCleanContext(currentContextMap);
3280 }
3281 
3282 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3283 {
3284  int list_index, lrv;
3285  int listSize;
3286  CHANNEL_MAP * currentChannelMap;
3287 
3288  targetContextMap->hContext = 0;
3289  (void)ClientCloseSession(targetContextMap->dwClientID);
3290  targetContextMap->dwClientID = 0;
3291  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3292 
3293  listSize = list_size(&targetContextMap->channelMapList);
3294  for (list_index = 0; list_index < listSize; list_index++)
3295  {
3296  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3297  list_index);
3298  if (NULL == currentChannelMap)
3299  {
3300  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3301  list_index);
3302  continue;
3303  }
3304  else
3305  {
3306  free(currentChannelMap->readerName);
3307  free(currentChannelMap);
3308  }
3309 
3310  }
3311  list_destroy(&targetContextMap->channelMapList);
3312 
3313  lrv = list_delete(&contextMapList, targetContextMap);
3314  if (lrv < 0)
3315  {
3316  Log2(PCSC_LOG_CRITICAL,
3317  "list_delete failed with return value: %d", lrv);
3318  }
3319 
3320  free(targetContextMap);
3321 
3322  return SCARD_S_SUCCESS;
3323 }
3324 
3325 /*
3326  * Functions for managing hCard values returned from SCardConnect.
3327  */
3328 
3329 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3330  LPCSTR readerName)
3331 {
3332  CHANNEL_MAP * newChannelMap;
3333  int lrv = -1;
3334 
3335  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3336  if (NULL == newChannelMap)
3337  return SCARD_E_NO_MEMORY;
3338 
3339  newChannelMap->hCard = hCard;
3340  newChannelMap->readerName = strdup(readerName);
3341 
3342  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3343  if (lrv < 0)
3344  {
3345  free(newChannelMap->readerName);
3346  free(newChannelMap);
3347  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3348  lrv);
3349  return SCARD_E_NO_MEMORY;
3350  }
3351 
3352  return SCARD_S_SUCCESS;
3353 }
3354 
3355 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3356 {
3357  SCONTEXTMAP * currentContextMap;
3358  CHANNEL_MAP * currentChannelMap;
3359  int lrv;
3360  LONG rv;
3361 
3362  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3363  &currentChannelMap);
3364  if (rv == -1)
3365  return SCARD_E_INVALID_HANDLE;
3366 
3367  free(currentChannelMap->readerName);
3368 
3369  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3370  if (lrv < 0)
3371  {
3372  Log2(PCSC_LOG_CRITICAL,
3373  "list_delete failed with return value: %d", lrv);
3374  }
3375 
3376  free(currentChannelMap);
3377 
3378  return SCARD_S_SUCCESS;
3379 }
3380 
3381 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3382  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3383 {
3384  LONG rv;
3385 
3386  if (0 == hCard)
3387  return -1;
3388 
3389  (void)SCardLockThread();
3390  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3391  targetChannelMap);
3392 
3393  if (SCARD_S_SUCCESS == rv)
3394  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3395 
3396  (void)SCardUnlockThread();
3397 
3398  return rv;
3399 }
3400 
3401 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3402  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3403 {
3404  int listSize;
3405  int list_index;
3406  SCONTEXTMAP * currentContextMap;
3407  CHANNEL_MAP * currentChannelMap;
3408 
3409  /* Best to get the caller a crash early if we fail unsafely */
3410  *targetContextMap = NULL;
3411  *targetChannelMap = NULL;
3412 
3413  listSize = list_size(&contextMapList);
3414 
3415  for (list_index = 0; list_index < listSize; list_index++)
3416  {
3417  currentContextMap = list_get_at(&contextMapList, list_index);
3418  if (currentContextMap == NULL)
3419  {
3420  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3421  list_index);
3422  continue;
3423  }
3424  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3425  &hCard);
3426  if (currentChannelMap != NULL)
3427  {
3428  *targetContextMap = currentContextMap;
3429  *targetChannelMap = currentChannelMap;
3430  return SCARD_S_SUCCESS;
3431  }
3432  }
3433 
3434  return -1;
3435 }
3436 
3445 {
3446  LONG rv;
3447  struct stat statBuffer;
3448  char *socketName;
3449 
3450  socketName = getSocketName();
3451  rv = stat(socketName, &statBuffer);
3452 
3453  if (rv != 0)
3454  {
3455  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3456  socketName, strerror(errno));
3457  return SCARD_E_NO_SERVICE;
3458  }
3459 
3460  return SCARD_S_SUCCESS;
3461 }
3462 
3463 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3464 {
3465  int32_t dwClientID = currentContextMap->dwClientID;
3466  LONG rv;
3467 
3468  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3469  if (rv != SCARD_S_SUCCESS)
3470  return rv;
3471 
3472  /* Read a message from the server */
3473  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3474  if (rv != SCARD_S_SUCCESS)
3475  return rv;
3476 
3477  return SCARD_S_SUCCESS;
3478 }
3479 
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:56
wait for a reader state change
Definition: winscard_msg.h:94
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:73
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:172
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
get the client/server protocol version
Definition: winscard_msg.h:92
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:77
static short isExecuted
Make sure the initialization code is executed only once.
used by SCardEstablishContext()
Definition: winscard_msg.h:76
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:315
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
used by SCardEndTransaction()
Definition: winscard_msg.h:83
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT, int)
Get the index from the Application Context vector _psContextMap for the passed context.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:53
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
This handles abstract system level calls.
static LONG SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
static LONG SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
used by SCardConnect()
Definition: winscard_msg.h:79
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:47
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes...
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels all pending blocking requests on the SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:83
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:75
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
Represents the an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
get the readers state
Definition: winscard_msg.h:93
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:449
used by SCardReleaseContext()
Definition: winscard_msg.h:77
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:109
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:107
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:272
used by SCardReconnect()
Definition: winscard_msg.h:80
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:135
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:84
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
Represents an Application Context Channel.
This handles card insertion/removal events, updates ATR, protocol, and status information.
SCARDCONTEXT hContext
Application Context ID.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
char cancellable
We are in a cancellable call.
stop waiting for a reader state change
Definition: winscard_msg.h:95
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:55
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
static LONG SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:117
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:49
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
used by SCardControl()
Definition: winscard_msg.h:85
This keeps a list of defines for pcsc-lite.
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:243
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:274
Protocol Control Information (PCI)
Definition: pcsclite.h:79
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader...
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:57
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:48
used by SCardSetAttrib()
Definition: winscard_msg.h:91
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:351
used by SCardDisconnect()
Definition: winscard_msg.h:81
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:246
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:90
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
pthread_mutex_t mMutex
Mutex for this context.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:52
used by SCardCancel()
Definition: winscard_msg.h:88
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:71
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:56
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:86
This handles smart card reader communications.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:193
This handles debugging.
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:265
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275