pcsc-lite  1.8.20
winscard_clnt.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
3  *
4  * Copyright (C) 1999-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2005
9  * Martin Paljak <martin@paljak.pri.ee>
10  * Copyright (C) 2002-2011
11  * Ludovic Rousseau <ludovic.rousseau@free.fr>
12  * Copyright (C) 2009
13  * Jean-Luc Giraud <jlgiraud@googlemail.com>
14  *
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
18 
19 1. Redistributions of source code must retain the above copyright
20  notice, this list of conditions and the following disclaimer.
21 2. Redistributions in binary form must reproduce the above copyright
22  notice, this list of conditions and the following disclaimer in the
23  documentation and/or other materials provided with the distribution.
24 3. The name of the author may not be used to endorse or promote products
25  derived from this software without specific prior written permission.
26 
27 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
105 #include "config.h"
106 #include <stdlib.h>
107 #include <string.h>
108 #include <sys/types.h>
109 #include <fcntl.h>
110 #include <unistd.h>
111 #include <sys/un.h>
112 #include <errno.h>
113 #include <stddef.h>
114 #include <sys/time.h>
115 #include <pthread.h>
116 #include <sys/wait.h>
117 
118 #include "misc.h"
119 #include "pcscd.h"
120 #include "winscard.h"
121 #include "debuglog.h"
122 
123 #include "readerfactory.h"
124 #include "eventhandler.h"
125 #include "sys_generic.h"
126 #include "winscard_msg.h"
127 #include "utils.h"
128 
129 /* Display, on stderr, a trace of the WinSCard calls with arguments and
130  * results */
131 //#define DO_TRACE
132 
133 /* Profile the execution time of WinSCard calls */
134 //#define DO_PROFILE
135 
136 
138 #define SCARD_PROTOCOL_ANY_OLD 0x1000
139 
140 #ifndef TRUE
141 #define TRUE 1
142 #define FALSE 0
143 #endif
144 
145 static char sharing_shall_block = TRUE;
146 
147 #define COLOR_RED "\33[01;31m"
148 #define COLOR_GREEN "\33[32m"
149 #define COLOR_BLUE "\33[34m"
150 #define COLOR_MAGENTA "\33[35m"
151 #define COLOR_NORMAL "\33[0m"
152 
153 #ifdef DO_TRACE
154 
155 #include <stdio.h>
156 #include <stdarg.h>
157 
158 static void trace(const char *func, const char direction, const char *fmt, ...)
159 {
160  va_list args;
161 
162  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163  direction, pthread_self(), func);
164 
165  fprintf(stderr, COLOR_MAGENTA);
166  va_start(args, fmt);
167  vfprintf(stderr, fmt, args);
168  va_end(args);
169 
170  fprintf(stderr, COLOR_NORMAL "\n");
171 }
172 
173 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175 #else
176 #define API_TRACE_IN(...)
177 #define API_TRACE_OUT(...)
178 #endif
179 
180 #ifdef DO_PROFILE
181 
182 #define PROFILE_FILE "/tmp/pcsc_profile"
183 #include <stdio.h>
184 #include <sys/time.h>
185 
186 /* we can profile a maximum of 5 simultaneous calls */
187 #define MAX_THREADS 5
188 pthread_t threads[MAX_THREADS];
189 struct timeval profile_time_start[MAX_THREADS];
190 FILE *profile_fd;
191 char profile_tty;
192 
193 #define PROFILE_START profile_start();
194 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195 
196 static void profile_start(void)
197 {
198  static char initialized = FALSE;
199  pthread_t t;
200  int i;
201 
202  if (!initialized)
203  {
204  char filename[80];
205 
206  initialized = TRUE;
207  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208  profile_fd = fopen(filename, "a+");
209  if (NULL == profile_fd)
210  {
211  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212  PROFILE_FILE, strerror(errno));
213  exit(-1);
214  }
215  fprintf(profile_fd, "\nStart a new profile\n");
216 
217  if (isatty(fileno(stderr)))
218  profile_tty = TRUE;
219  else
220  profile_tty = FALSE;
221  }
222 
223  t = pthread_self();
224  for (i=0; i<MAX_THREADS; i++)
225  if (pthread_equal(0, threads[i]))
226  {
227  threads[i] = t;
228  break;
229  }
230 
231  gettimeofday(&profile_time_start[i], NULL);
232 } /* profile_start */
233 
234 static void profile_end(const char *f, LONG rv)
235 {
236  struct timeval profile_time_end;
237  long d;
238  pthread_t t;
239  int i;
240 
241  gettimeofday(&profile_time_end, NULL);
242 
243  t = pthread_self();
244  for (i=0; i<MAX_THREADS; i++)
245  if (pthread_equal(t, threads[i]))
246  break;
247 
248  if (i>=MAX_THREADS)
249  {
250  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251  return;
252  }
253 
254  d = time_sub(&profile_time_end, &profile_time_start[i]);
255 
256  /* free this entry */
257  threads[i] = 0;
258 
259  if (profile_tty)
260  {
261  if (rv != SCARD_S_SUCCESS)
262  fprintf(stderr,
263  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265  f, d, rv, pcsc_stringify_error(rv));
266  else
267  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268  COLOR_NORMAL "\n", f, d);
269  }
270  fprintf(profile_fd, "%s %ld\n", f, d);
271  fflush(profile_fd);
272 } /* profile_end */
273 
274 #else
275 #define PROFILE_START
276 #define PROFILE_END(rv)
277 #endif
278 
284 {
285  SCARDHANDLE hCard;
286  LPSTR readerName;
287 };
288 
289 typedef struct _psChannelMap CHANNEL_MAP;
290 
291 static int CHANNEL_MAP_seeker(const void *el, const void *key)
292 {
293  const CHANNEL_MAP * channelMap = el;
294 
295  if ((el == NULL) || (key == NULL))
296  {
297  Log3(PCSC_LOG_CRITICAL,
298  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299  el, key);
300  return 0;
301  }
302 
303  if (channelMap->hCard == *(SCARDHANDLE *)key)
304  return 1;
305 
306  return 0;
307 }
308 
315 {
316  DWORD dwClientID;
318  pthread_mutex_t mMutex;
319  list_t channelMapList;
320  char cancellable;
321 };
322 typedef struct _psContextMap SCONTEXTMAP;
323 
324 static list_t contextMapList;
325 
326 static int SCONTEXTMAP_seeker(const void *el, const void *key)
327 {
328  const SCONTEXTMAP * contextMap = el;
329 
330  if ((el == NULL) || (key == NULL))
331  {
332  Log3(PCSC_LOG_CRITICAL,
333  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
334  el, key);
335  return 0;
336  }
337 
338  if (contextMap->hContext == *(SCARDCONTEXT *) key)
339  return 1;
340 
341  return 0;
342 }
343 
347 static short isExecuted = 0;
348 
349 
354 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
355 
360 
367 
368 
369 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
372 static LONG SCardRemoveContext(SCARDCONTEXT);
373 static LONG SCardCleanContext(SCONTEXTMAP *);
374 
375 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
376 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
377  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
378 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
379  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380 static LONG SCardRemoveHandle(SCARDHANDLE);
381 
382 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
383  LPBYTE pbAttr, LPDWORD pcbAttrLen);
384 
385 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
386 
387 /*
388  * Thread safety functions
389  */
396 inline static LONG SCardLockThread(void)
397 {
398  return pthread_mutex_lock(&clientMutex);
399 }
400 
406 inline static LONG SCardUnlockThread(void)
407 {
408  return pthread_mutex_unlock(&clientMutex);
409 }
410 
411 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
412  /*@out@*/ LPSCARDCONTEXT);
413 
447 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
448  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
449 {
450  LONG rv;
451 
452  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
453  PROFILE_START
454 
455  /* Check if the server is running */
457  if (rv != SCARD_S_SUCCESS)
458  goto end;
459 
460  (void)SCardLockThread();
461  rv = SCardEstablishContextTH(dwScope, pvReserved1,
462  pvReserved2, phContext);
463  (void)SCardUnlockThread();
464 
465 end:
466  PROFILE_END(rv)
467  API_TRACE_OUT("%ld", *phContext)
468 
469  return rv;
470 }
471 
498 static LONG SCardEstablishContextTH(DWORD dwScope,
499  /*@unused@*/ LPCVOID pvReserved1,
500  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
501 {
502  LONG rv;
503  struct establish_struct scEstablishStruct;
504  uint32_t dwClientID = 0;
505 
506  (void)pvReserved1;
507  (void)pvReserved2;
508  if (phContext == NULL)
510  else
511  *phContext = 0;
512 
513  /*
514  * Do this only once:
515  * - Initialize context list.
516  */
517  if (isExecuted == 0)
518  {
519  int lrv;
520 
521  /* NOTE: The list will never be freed (No API call exists to
522  * "close all contexts".
523  * Applications which load and unload the library will leak
524  * the list's internal structures. */
525  lrv = list_init(&contextMapList);
526  if (lrv < 0)
527  {
528  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
529  lrv);
530  return SCARD_E_NO_MEMORY;
531  }
532 
533  lrv = list_attributes_seeker(&contextMapList,
534  SCONTEXTMAP_seeker);
535  if (lrv <0)
536  {
537  Log2(PCSC_LOG_CRITICAL,
538  "list_attributes_seeker failed with return value: %d", lrv);
539  list_destroy(&contextMapList);
540  return SCARD_E_NO_MEMORY;
541  }
542 
543  if (getenv("PCSCLITE_NO_BLOCKING"))
544  {
545  Log1(PCSC_LOG_INFO, "Disable shared blocking");
546  sharing_shall_block = FALSE;
547  }
548 
549  isExecuted = 1;
550  }
551 
552 
553  /* Establishes a connection to the server */
554  if (ClientSetupSession(&dwClientID) != 0)
555  {
556  return SCARD_E_NO_SERVICE;
557  }
558 
559  { /* exchange client/server protocol versions */
560  struct version_struct veStr;
561 
564  veStr.rv = SCARD_S_SUCCESS;
565 
566  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
567  &veStr);
568  if (rv != SCARD_S_SUCCESS)
569  return rv;
570 
571  /* Read a message from the server */
572  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
573  if (rv != SCARD_S_SUCCESS)
574  {
575  Log1(PCSC_LOG_CRITICAL,
576  "Your pcscd is too old and does not support CMD_VERSION");
577  return SCARD_F_COMM_ERROR;
578  }
579 
580  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
581  veStr.major, veStr.minor);
582 
583  if (veStr.rv != SCARD_S_SUCCESS)
584  return veStr.rv;
585  }
586 
587 again:
588  /*
589  * Try to establish an Application Context with the server
590  */
591  scEstablishStruct.dwScope = dwScope;
592  scEstablishStruct.hContext = 0;
593  scEstablishStruct.rv = SCARD_S_SUCCESS;
594 
596  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
597 
598  if (rv != SCARD_S_SUCCESS)
599  return rv;
600 
601  /*
602  * Read the response from the server
603  */
604  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
605  dwClientID);
606 
607  if (rv != SCARD_S_SUCCESS)
608  return rv;
609 
610  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
611  return scEstablishStruct.rv;
612 
613  /* check we do not reuse an existing hContext */
614  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
615  /* we do not need to release the allocated context since
616  * SCardReleaseContext() does nothing on the server side */
617  goto again;
618 
619  *phContext = scEstablishStruct.hContext;
620 
621  /*
622  * Allocate the new hContext - if allocator full return an error
623  */
624  rv = SCardAddContext(*phContext, dwClientID);
625 
626  return rv;
627 }
628 
651 {
652  LONG rv;
653  struct release_struct scReleaseStruct;
654  SCONTEXTMAP * currentContextMap;
655 
656  API_TRACE_IN("%ld", hContext)
657  PROFILE_START
658 
659  /*
660  * Make sure this context has been opened
661  * and get currentContextMap
662  */
663  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
664  if (NULL == currentContextMap)
665  {
667  goto error;
668  }
669 
670  scReleaseStruct.hContext = hContext;
671  scReleaseStruct.rv = SCARD_S_SUCCESS;
672 
674  currentContextMap->dwClientID,
675  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
676 
677  if (rv != SCARD_S_SUCCESS)
678  goto end;
679 
680  /*
681  * Read a message from the server
682  */
683  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
684  currentContextMap->dwClientID);
685 
686  if (rv != SCARD_S_SUCCESS)
687  goto end;
688 
689  rv = scReleaseStruct.rv;
690 end:
691  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
692 
693  /*
694  * Remove the local context from the stack
695  */
696  (void)SCardLockThread();
697  (void)SCardRemoveContext(hContext);
698  (void)SCardUnlockThread();
699 
700 error:
701  PROFILE_END(rv)
702  API_TRACE_OUT("")
703 
704  return rv;
705 }
706 
762 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
763  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
764  LPDWORD pdwActiveProtocol)
765 {
766  LONG rv;
767  struct connect_struct scConnectStruct;
768  SCONTEXTMAP * currentContextMap;
769 
770  PROFILE_START
771  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
772 
773  /*
774  * Check for NULL parameters
775  */
776  if (phCard == NULL || pdwActiveProtocol == NULL)
778  else
779  *phCard = 0;
780 
781  if (szReader == NULL)
782  return SCARD_E_UNKNOWN_READER;
783 
784  /*
785  * Check for uninitialized strings
786  */
787  if (strlen(szReader) > MAX_READERNAME)
788  return SCARD_E_INVALID_VALUE;
789 
790  /*
791  * Make sure this context has been opened
792  */
793  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
794  if (NULL == currentContextMap)
795  return SCARD_E_INVALID_HANDLE;
796 
797  memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
798  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
799  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
800 
801  scConnectStruct.hContext = hContext;
802  scConnectStruct.dwShareMode = dwShareMode;
803  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
804  scConnectStruct.hCard = 0;
805  scConnectStruct.dwActiveProtocol = 0;
806  scConnectStruct.rv = SCARD_S_SUCCESS;
807 
808  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
809  sizeof(scConnectStruct), (void *) &scConnectStruct);
810 
811  if (rv != SCARD_S_SUCCESS)
812  goto end;
813 
814  /*
815  * Read a message from the server
816  */
817  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
818  currentContextMap->dwClientID);
819 
820  if (rv != SCARD_S_SUCCESS)
821  goto end;
822 
823  *phCard = scConnectStruct.hCard;
824  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
825 
826  if (scConnectStruct.rv == SCARD_S_SUCCESS)
827  {
828  /*
829  * Keep track of the handle locally
830  */
831  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
832  }
833  else
834  rv = scConnectStruct.rv;
835 
836 end:
837  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
838 
839  PROFILE_END(rv)
840  API_TRACE_OUT("%d", *pdwActiveProtocol)
841 
842  return rv;
843 }
844 
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 
1640 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1641  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1642 {
1643  SCARD_READERSTATE *currReader;
1644  READER_STATE *rContext;
1645  long dwTime;
1646  DWORD dwBreakFlag = 0;
1647  unsigned int j;
1648  SCONTEXTMAP * currentContextMap;
1649  int currentReaderCount = 0;
1650  LONG rv = SCARD_S_SUCCESS;
1651 
1652  PROFILE_START
1653  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1654 #ifdef DO_TRACE
1655  for (j=0; j<cReaders; j++)
1656  {
1657  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1658  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1659  }
1660 #endif
1661 
1662  if ((rgReaderStates == NULL && cReaders > 0)
1663  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1664  {
1666  goto error;
1667  }
1668 
1669  /* Check the integrity of the reader states structures */
1670  for (j = 0; j < cReaders; j++)
1671  {
1672  if (rgReaderStates[j].szReader == NULL)
1673  return SCARD_E_INVALID_VALUE;
1674  }
1675 
1676  /* return if all readers are SCARD_STATE_IGNORE */
1677  if (cReaders > 0)
1678  {
1679  int nbNonIgnoredReaders = cReaders;
1680 
1681  for (j=0; j<cReaders; j++)
1682  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1683  nbNonIgnoredReaders--;
1684 
1685  if (0 == nbNonIgnoredReaders)
1686  {
1687  rv = SCARD_S_SUCCESS;
1688  goto error;
1689  }
1690  }
1691  else
1692  {
1693  /* reader list is empty */
1694  rv = SCARD_S_SUCCESS;
1695  goto error;
1696  }
1697 
1698  /*
1699  * Make sure this context has been opened
1700  */
1701  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
1702  if (NULL == currentContextMap)
1703  {
1705  goto error;
1706  }
1707 
1708  /* synchronize reader states with daemon */
1709  rv = getReaderStates(currentContextMap);
1710  if (rv != SCARD_S_SUCCESS)
1711  goto end;
1712 
1713  /* check all the readers are already known */
1714  for (j=0; j<cReaders; j++)
1715  {
1716  const char *readerName;
1717  int i;
1718 
1719  readerName = rgReaderStates[j].szReader;
1720  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1721  {
1722  if (strcmp(readerName, readerStates[i].readerName) == 0)
1723  break;
1724  }
1725 
1726  /* The requested reader name is not recognized */
1727  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1728  {
1729  /* PnP special reader? */
1730  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1731  {
1733  goto end;
1734  }
1735  }
1736  }
1737 
1738  /* Clear the event state for all readers */
1739  for (j = 0; j < cReaders; j++)
1740  rgReaderStates[j].dwEventState = 0;
1741 
1742  /* Now is where we start our event checking loop */
1743  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1744 
1745  /* Get the initial reader count on the system */
1746  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1747  if (readerStates[j].readerName[0] != '\0')
1748  currentReaderCount++;
1749 
1750  /* catch possible sign extension problems from 32 to 64-bits integers */
1751  if ((DWORD)-1 == dwTimeout)
1752  dwTimeout = INFINITE;
1753  if (INFINITE == dwTimeout)
1754  dwTime = 60*1000; /* "infinite" timeout */
1755  else
1756  dwTime = dwTimeout;
1757 
1758  j = 0;
1759  do
1760  {
1761  currReader = &rgReaderStates[j];
1762 
1763  /* Ignore for IGNORED readers */
1764  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1765  {
1766  const char *readerName;
1767  int i;
1768 
1769  /* Looks for correct readernames */
1770  readerName = currReader->szReader;
1771  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1772  {
1773  if (strcmp(readerName, readerStates[i].readerName) == 0)
1774  break;
1775  }
1776 
1777  /* The requested reader name is not recognized */
1778  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1779  {
1780  /* PnP special reader? */
1781  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1782  {
1783  int k, newReaderCount = 0;
1784 
1785  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1786  if (readerStates[k].readerName[0] != '\0')
1787  newReaderCount++;
1788 
1789  if (newReaderCount != currentReaderCount)
1790  {
1791  Log1(PCSC_LOG_INFO, "Reader list changed");
1792  currentReaderCount = newReaderCount;
1793 
1794  currReader->dwEventState |= SCARD_STATE_CHANGED;
1795  dwBreakFlag = 1;
1796  }
1797  }
1798  else
1799  {
1800  currReader->dwEventState =
1802  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1803  {
1804  currReader->dwEventState |= SCARD_STATE_CHANGED;
1805  /*
1806  * Spec says use SCARD_STATE_IGNORE but a removed USB
1807  * reader with eventState fed into currentState will
1808  * be ignored forever
1809  */
1810  dwBreakFlag = 1;
1811  }
1812  }
1813  }
1814  else
1815  {
1816  uint32_t readerState;
1817 
1818  /* The reader has come back after being away */
1819  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1820  {
1821  currReader->dwEventState |= SCARD_STATE_CHANGED;
1822  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1823  Log0(PCSC_LOG_DEBUG);
1824  dwBreakFlag = 1;
1825  }
1826 
1827  /* Set the reader status structure */
1828  rContext = &readerStates[i];
1829 
1830  /* Now we check all the Reader States */
1831  readerState = rContext->readerState;
1832 
1833  /* only if current state has an non null event counter */
1834  if (currReader->dwCurrentState & 0xFFFF0000)
1835  {
1836  unsigned int currentCounter;
1837 
1838  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1839 
1840  /* has the event counter changed since the last call? */
1841  if (rContext->eventCounter != currentCounter)
1842  {
1843  currReader->dwEventState |= SCARD_STATE_CHANGED;
1844  Log0(PCSC_LOG_DEBUG);
1845  dwBreakFlag = 1;
1846  }
1847  }
1848 
1849  /* add an event counter in the upper word of dwEventState */
1850  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1851  | (rContext->eventCounter << 16));
1852 
1853  /* Check if the reader is in the correct state */
1854  if (readerState & SCARD_UNKNOWN)
1855  {
1856  /* reader is in bad state */
1857  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1858  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1859  {
1860  /* App thinks reader is in good state and it is not */
1861  currReader->dwEventState |= SCARD_STATE_CHANGED;
1862  Log0(PCSC_LOG_DEBUG);
1863  dwBreakFlag = 1;
1864  }
1865  }
1866  else
1867  {
1868  /* App thinks reader in bad state but it is not */
1869  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1870  {
1871  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1872  currReader->dwEventState |= SCARD_STATE_CHANGED;
1873  Log0(PCSC_LOG_DEBUG);
1874  dwBreakFlag = 1;
1875  }
1876  }
1877 
1878  /* Check for card presence in the reader */
1879  if (readerState & SCARD_PRESENT)
1880  {
1881  /* card present but not yet powered up */
1882  if (0 == rContext->cardAtrLength)
1883  /* Allow the status thread to convey information */
1885 
1886  currReader->cbAtr = rContext->cardAtrLength;
1887  memcpy(currReader->rgbAtr, rContext->cardAtr,
1888  currReader->cbAtr);
1889  }
1890  else
1891  currReader->cbAtr = 0;
1892 
1893  /* Card is now absent */
1894  if (readerState & SCARD_ABSENT)
1895  {
1896  currReader->dwEventState |= SCARD_STATE_EMPTY;
1897  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1898  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1899  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1900  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1901  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1902  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1903  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1904  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1905 
1906  /* After present the rest are assumed */
1907  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1908  {
1909  currReader->dwEventState |= SCARD_STATE_CHANGED;
1910  Log0(PCSC_LOG_DEBUG);
1911  dwBreakFlag = 1;
1912  }
1913  }
1914  /* Card is now present */
1915  else if (readerState & SCARD_PRESENT)
1916  {
1917  currReader->dwEventState |= SCARD_STATE_PRESENT;
1918  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1919  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1920  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1921  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1922  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1923  currReader->dwEventState &= ~SCARD_STATE_MUTE;
1924 
1925  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1926  {
1927  currReader->dwEventState |= SCARD_STATE_CHANGED;
1928  Log0(PCSC_LOG_DEBUG);
1929  dwBreakFlag = 1;
1930  }
1931 
1932  if (readerState & SCARD_SWALLOWED)
1933  {
1934  currReader->dwEventState |= SCARD_STATE_MUTE;
1935  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1936  {
1937  currReader->dwEventState |= SCARD_STATE_CHANGED;
1938  Log0(PCSC_LOG_DEBUG);
1939  dwBreakFlag = 1;
1940  }
1941  }
1942  else
1943  {
1944  /* App thinks card is mute but it is not */
1945  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1946  {
1947  currReader->dwEventState |= SCARD_STATE_CHANGED;
1948  Log0(PCSC_LOG_DEBUG);
1949  dwBreakFlag = 1;
1950  }
1951  }
1952  }
1953 
1954  /* Now figure out sharing modes */
1956  {
1957  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1958  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1959  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1960  {
1961  currReader->dwEventState |= SCARD_STATE_CHANGED;
1962  Log0(PCSC_LOG_DEBUG);
1963  dwBreakFlag = 1;
1964  }
1965  }
1966  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
1967  {
1968  /* A card must be inserted for it to be INUSE */
1969  if (readerState & SCARD_PRESENT)
1970  {
1971  currReader->dwEventState |= SCARD_STATE_INUSE;
1972  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1973  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
1974  {
1975  currReader->dwEventState |= SCARD_STATE_CHANGED;
1976  Log0(PCSC_LOG_DEBUG);
1977  dwBreakFlag = 1;
1978  }
1979  }
1980  }
1981  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
1982  {
1983  currReader->dwEventState &= ~SCARD_STATE_INUSE;
1984  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1985 
1986  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1987  {
1988  currReader->dwEventState |= SCARD_STATE_CHANGED;
1989  Log0(PCSC_LOG_DEBUG);
1990  dwBreakFlag = 1;
1991  }
1992  else if (currReader-> dwCurrentState
1994  {
1995  currReader->dwEventState |= SCARD_STATE_CHANGED;
1996  Log0(PCSC_LOG_DEBUG);
1997  dwBreakFlag = 1;
1998  }
1999  }
2000 
2001  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2002  {
2003  /*
2004  * Break out of the while .. loop and return status
2005  * once all the status's for all readers is met
2006  */
2007  currReader->dwEventState |= SCARD_STATE_CHANGED;
2008  Log0(PCSC_LOG_DEBUG);
2009  dwBreakFlag = 1;
2010  }
2011  } /* End of SCARD_STATE_UNKNOWN */
2012  } /* End of SCARD_STATE_IGNORE */
2013 
2014  /* Counter and resetter */
2015  j++;
2016  if (j == cReaders)
2017  {
2018  /* go back to the first reader */
2019  j = 0;
2020 
2021  /* Declare all the break conditions */
2022 
2023  /* Break if UNAWARE is set and all readers have been checked */
2024  if (dwBreakFlag == 1)
2025  break;
2026 
2027  /* Only sleep once for each cycle of reader checks. */
2028  {
2029  struct wait_reader_state_change waitStatusStruct;
2030  struct timeval before, after;
2031 
2032  gettimeofday(&before, NULL);
2033 
2034  waitStatusStruct.timeOut = dwTime;
2035  waitStatusStruct.rv = SCARD_S_SUCCESS;
2036 
2037  /* another thread can do SCardCancel() */
2038  currentContextMap->cancellable = TRUE;
2039 
2041  currentContextMap->dwClientID,
2042  sizeof(waitStatusStruct), &waitStatusStruct);
2043 
2044  if (rv != SCARD_S_SUCCESS)
2045  goto end;
2046 
2047  /*
2048  * Read a message from the server
2049  */
2051  &waitStatusStruct, sizeof(waitStatusStruct),
2052  currentContextMap->dwClientID, dwTime);
2053 
2054  /* another thread can do SCardCancel() */
2055  currentContextMap->cancellable = FALSE;
2056 
2057  /* timeout */
2058  if (SCARD_E_TIMEOUT == rv)
2059  {
2060  /* ask server to remove us from the event list */
2062  currentContextMap->dwClientID,
2063  sizeof(waitStatusStruct), &waitStatusStruct);
2064 
2065  if (rv != SCARD_S_SUCCESS)
2066  goto end;
2067 
2068  /* Read a message from the server */
2069  rv = MessageReceive(&waitStatusStruct,
2070  sizeof(waitStatusStruct),
2071  currentContextMap->dwClientID);
2072 
2073  if (rv != SCARD_S_SUCCESS)
2074  goto end;
2075  }
2076 
2077  if (rv != SCARD_S_SUCCESS)
2078  goto end;
2079 
2080  /* an event occurs or SCardCancel() was called */
2081  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2082  {
2083  rv = waitStatusStruct.rv;
2084  goto end;
2085  }
2086 
2087  /* synchronize reader states with daemon */
2088  rv = getReaderStates(currentContextMap);
2089  if (rv != SCARD_S_SUCCESS)
2090  goto end;
2091 
2092  if (INFINITE != dwTimeout)
2093  {
2094  long int diff;
2095 
2096  gettimeofday(&after, NULL);
2097  diff = time_sub(&after, &before);
2098  dwTime -= diff/1000;
2099  }
2100  }
2101 
2102  if (dwTimeout != INFINITE)
2103  {
2104  /* If time is greater than timeout and all readers have been
2105  * checked
2106  */
2107  if (dwTime <= 0)
2108  {
2109  rv = SCARD_E_TIMEOUT;
2110  goto end;
2111  }
2112  }
2113  }
2114  }
2115  while (1);
2116 
2117 end:
2118  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2119 
2120  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2121 
2122 error:
2123  PROFILE_END(rv)
2124 #ifdef DO_TRACE
2125  for (j=0; j<cReaders; j++)
2126  {
2127  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2128  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2129  }
2130 #endif
2131 
2132  return rv;
2133 }
2134 
2185 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2186  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2187  LPDWORD lpBytesReturned)
2188 {
2189  LONG rv;
2190  struct control_struct scControlStruct;
2191  SCONTEXTMAP * currentContextMap;
2192  CHANNEL_MAP * pChannelMap;
2193 
2194  PROFILE_START
2195 
2196  /* 0 bytes received by default */
2197  if (NULL != lpBytesReturned)
2198  *lpBytesReturned = 0;
2199 
2200  /*
2201  * Make sure this handle has been opened
2202  */
2203  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2204  &pChannelMap);
2205  if (rv == -1)
2206  {
2207  PROFILE_END(SCARD_E_INVALID_HANDLE)
2208  return SCARD_E_INVALID_HANDLE;
2209  }
2210 
2211  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2212  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2213  {
2215  goto end;
2216  }
2217 
2218  scControlStruct.hCard = hCard;
2219  scControlStruct.dwControlCode = dwControlCode;
2220  scControlStruct.cbSendLength = cbSendLength;
2221  scControlStruct.cbRecvLength = cbRecvLength;
2222  scControlStruct.dwBytesReturned = 0;
2223  scControlStruct.rv = 0;
2224 
2225  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2226  sizeof(scControlStruct), &scControlStruct);
2227 
2228  if (rv != SCARD_S_SUCCESS)
2229  goto end;
2230 
2231  /* write the sent buffer */
2232  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2233  currentContextMap->dwClientID);
2234 
2235  if (rv != SCARD_S_SUCCESS)
2236  goto end;
2237 
2238  /*
2239  * Read a message from the server
2240  */
2241  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2242  currentContextMap->dwClientID);
2243 
2244  if (rv != SCARD_S_SUCCESS)
2245  goto end;
2246 
2247  if (SCARD_S_SUCCESS == scControlStruct.rv)
2248  {
2249  /* read the received buffer */
2250  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2251  currentContextMap->dwClientID);
2252 
2253  if (rv != SCARD_S_SUCCESS)
2254  goto end;
2255 
2256  }
2257 
2258  if (NULL != lpBytesReturned)
2259  *lpBytesReturned = scControlStruct.dwBytesReturned;
2260 
2261  rv = scControlStruct.rv;
2262 
2263 end:
2264  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2265 
2266  PROFILE_END(rv)
2267 
2268  return rv;
2269 }
2270 
2386 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2387  LPDWORD pcbAttrLen)
2388 {
2389  LONG ret;
2390  unsigned char *buf = NULL;
2391 
2392  PROFILE_START
2393 
2394  if (NULL == pcbAttrLen)
2395  {
2397  goto end;
2398  }
2399 
2400  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2401  {
2402  if (NULL == pbAttr)
2404 
2405  *pcbAttrLen = MAX_BUFFER_SIZE;
2406  buf = malloc(*pcbAttrLen);
2407  if (NULL == buf)
2408  {
2409  ret = SCARD_E_NO_MEMORY;
2410  goto end;
2411  }
2412 
2413  *(unsigned char **)pbAttr = buf;
2414  }
2415  else
2416  {
2417  buf = pbAttr;
2418 
2419  /* if only get the length */
2420  if (NULL == pbAttr)
2421  /* use a reasonable size */
2422  *pcbAttrLen = MAX_BUFFER_SIZE;
2423  }
2424 
2425  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2426  pcbAttrLen);
2427 
2428 end:
2429  PROFILE_END(ret)
2430 
2431  return ret;
2432 }
2433 
2469 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2470  DWORD cbAttrLen)
2471 {
2472  LONG ret;
2473 
2474  PROFILE_START
2475 
2476  if (NULL == pbAttr || 0 == cbAttrLen)
2478 
2479  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2480  &cbAttrLen);
2481 
2482  PROFILE_END(ret)
2483 
2484  return ret;
2485 }
2486 
2487 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2488  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2489 {
2490  LONG rv;
2491  struct getset_struct scGetSetStruct;
2492  SCONTEXTMAP * currentContextMap;
2493  CHANNEL_MAP * pChannelMap;
2494 
2495  /*
2496  * Make sure this handle has been opened
2497  */
2498  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2499  &pChannelMap);
2500  if (rv == -1)
2501  return SCARD_E_INVALID_HANDLE;
2502 
2503  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2504  {
2506  goto end;
2507  }
2508 
2509  scGetSetStruct.hCard = hCard;
2510  scGetSetStruct.dwAttrId = dwAttrId;
2511  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2512  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2513  if (SCARD_SET_ATTRIB == command)
2514  {
2515  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2516  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2517  }
2518  else
2519  /* we can get up to the communication buffer size */
2520  scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2521 
2522  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2523  sizeof(scGetSetStruct), &scGetSetStruct);
2524 
2525  if (rv != SCARD_S_SUCCESS)
2526  goto end;
2527 
2528  /*
2529  * Read a message from the server
2530  */
2531  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2532  currentContextMap->dwClientID);
2533 
2534  if (rv != SCARD_S_SUCCESS)
2535  goto end;
2536 
2537  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2538  {
2539  /*
2540  * Copy and zero it so any secret information is not leaked
2541  */
2542  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2543  {
2544  /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2545  * buffer overflow in the memcpy() bellow */
2546  DWORD correct_value = scGetSetStruct.cbAttrLen;
2547  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2548  *pcbAttrLen = correct_value;
2549 
2550  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2551  }
2552  else
2553  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2554 
2555  if (pbAttr)
2556  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2557 
2558  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2559  }
2560  rv = scGetSetStruct.rv;
2561 
2562 end:
2563  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2564 
2565  return rv;
2566 }
2567 
2626 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2627  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2628  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2629  LPDWORD pcbRecvLength)
2630 {
2631  LONG rv;
2632  SCONTEXTMAP * currentContextMap;
2633  CHANNEL_MAP * pChannelMap;
2634  struct transmit_struct scTransmitStruct;
2635 
2636  PROFILE_START
2637 
2638  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2639  pcbRecvLength == NULL || pioSendPci == NULL)
2641 
2642  /* Retry loop for blocking behaviour */
2643 retry:
2644 
2645  /*
2646  * Make sure this handle has been opened
2647  */
2648  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2649  &pChannelMap);
2650  if (rv == -1)
2651  {
2652  *pcbRecvLength = 0;
2653  PROFILE_END(SCARD_E_INVALID_HANDLE)
2654  return SCARD_E_INVALID_HANDLE;
2655  }
2656 
2657  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2658  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2659  {
2661  goto end;
2662  }
2663 
2664  scTransmitStruct.hCard = hCard;
2665  scTransmitStruct.cbSendLength = cbSendLength;
2666  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2667  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2668  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2669  scTransmitStruct.rv = SCARD_S_SUCCESS;
2670 
2671  if (pioRecvPci)
2672  {
2673  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2674  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2675  }
2676  else
2677  {
2678  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2679  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2680  }
2681 
2682  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2683  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2684 
2685  if (rv != SCARD_S_SUCCESS)
2686  goto end;
2687 
2688  /* write the sent buffer */
2689  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2690  currentContextMap->dwClientID);
2691 
2692  if (rv != SCARD_S_SUCCESS)
2693  goto end;
2694 
2695  /*
2696  * Read a message from the server
2697  */
2698  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2699  currentContextMap->dwClientID);
2700 
2701  if (rv != SCARD_S_SUCCESS)
2702  goto end;
2703 
2704  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2705  {
2706  /* read the received buffer */
2707  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2708  currentContextMap->dwClientID);
2709 
2710  if (rv != SCARD_S_SUCCESS)
2711  goto end;
2712 
2713  if (pioRecvPci)
2714  {
2715  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2716  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2717  }
2718  }
2719 
2720  rv = scTransmitStruct.rv;
2721 
2722  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2723  {
2724  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2726  goto retry;
2727  }
2728 
2729  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2730 
2731 end:
2732  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2733 
2734  PROFILE_END(rv)
2735 
2736  return rv;
2737 }
2738 
2792 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2793  LPSTR mszReaders, LPDWORD pcchReaders)
2794 {
2795  DWORD dwReadersLen = 0;
2796  int i;
2797  SCONTEXTMAP * currentContextMap;
2798  LONG rv = SCARD_S_SUCCESS;
2799  char *buf = NULL;
2800 
2801  (void)mszGroups;
2802  PROFILE_START
2803  API_TRACE_IN("%ld", hContext)
2804 
2805  /*
2806  * Check for NULL parameters
2807  */
2808  if (pcchReaders == NULL)
2810 
2811  /*
2812  * Make sure this context has been opened
2813  */
2814  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2815  if (NULL == currentContextMap)
2816  {
2817  PROFILE_END(SCARD_E_INVALID_HANDLE)
2818  return SCARD_E_INVALID_HANDLE;
2819  }
2820 
2821  /* synchronize reader states with daemon */
2822  rv = getReaderStates(currentContextMap);
2823  if (rv != SCARD_S_SUCCESS)
2824  goto end;
2825 
2826  dwReadersLen = 0;
2827  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2828  if (readerStates[i].readerName[0] != '\0')
2829  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2830 
2831  /* for the last NULL byte */
2832  dwReadersLen += 1;
2833 
2834  if (1 == dwReadersLen)
2835  {
2837  goto end;
2838  }
2839 
2840  if (SCARD_AUTOALLOCATE == *pcchReaders)
2841  {
2842  if (NULL == mszReaders)
2843  {
2845  goto end;
2846  }
2847  buf = malloc(dwReadersLen);
2848  if (NULL == buf)
2849  {
2850  rv = SCARD_E_NO_MEMORY;
2851  goto end;
2852  }
2853  *(char **)mszReaders = buf;
2854  }
2855  else
2856  {
2857  buf = mszReaders;
2858 
2859  /* not enough place to store the reader names */
2860  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2861  {
2863  goto end;
2864  }
2865  }
2866 
2867  if (mszReaders == NULL) /* text array not allocated */
2868  goto end;
2869 
2870  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2871  {
2872  if (readerStates[i].readerName[0] != '\0')
2873  {
2874  /*
2875  * Build the multi-string
2876  */
2877  strcpy(buf, readerStates[i].readerName);
2878  buf += strlen(readerStates[i].readerName)+1;
2879  }
2880  }
2881  *buf = '\0'; /* Add the last null */
2882 
2883 end:
2884  /* set the reader names length */
2885  *pcchReaders = dwReadersLen;
2886 
2887  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2888 
2889  PROFILE_END(rv)
2890  API_TRACE_OUT("%d", *pcchReaders)
2891 
2892  return rv;
2893 }
2894 
2908 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2909 {
2910  LONG rv = SCARD_S_SUCCESS;
2911  SCONTEXTMAP * currentContextMap;
2912 
2913  PROFILE_START
2914 
2915  /*
2916  * Make sure this context has been opened
2917  */
2918  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
2919  if (NULL == currentContextMap)
2920  return SCARD_E_INVALID_HANDLE;
2921 
2922  free((void *)pvMem);
2923 
2924  PROFILE_END(rv)
2925 
2926  return rv;
2927 }
2928 
2980 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2981  LPDWORD pcchGroups)
2982 {
2983  LONG rv = SCARD_S_SUCCESS;
2984  SCONTEXTMAP * currentContextMap;
2985  char *buf = NULL;
2986 
2987  PROFILE_START
2988 
2989  /* Multi-string with two trailing \0 */
2990  const char ReaderGroup[] = "SCard$DefaultReaders\0";
2991  const unsigned int dwGroups = sizeof(ReaderGroup);
2992 
2993  /*
2994  * Make sure this context has been opened
2995  */
2996  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2997  if (NULL == currentContextMap)
2998  return SCARD_E_INVALID_HANDLE;
2999 
3000  if (SCARD_AUTOALLOCATE == *pcchGroups)
3001  {
3002  if (NULL == mszGroups)
3003  {
3005  goto end;
3006  }
3007  buf = malloc(dwGroups);
3008  if (NULL == buf)
3009  {
3010  rv = SCARD_E_NO_MEMORY;
3011  goto end;
3012  }
3013  *(char **)mszGroups = buf;
3014  }
3015  else
3016  {
3017  buf = mszGroups;
3018 
3019  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3020  {
3022  goto end;
3023  }
3024  }
3025 
3026  if (buf)
3027  memcpy(buf, ReaderGroup, dwGroups);
3028 
3029 end:
3030  *pcchGroups = dwGroups;
3031 
3032  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3033 
3034  PROFILE_END(rv)
3035 
3036  return rv;
3037 }
3038 
3070 {
3071  SCONTEXTMAP * currentContextMap;
3072  LONG rv = SCARD_S_SUCCESS;
3073  uint32_t dwClientID = 0;
3074  struct cancel_struct scCancelStruct;
3075 
3076  PROFILE_START
3077  API_TRACE_IN("%ld", hContext)
3078 
3079  /*
3080  * Make sure this context has been opened
3081  */
3082  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3083  if (NULL == currentContextMap)
3084  {
3086  goto error;
3087  }
3088 
3089  if (! currentContextMap->cancellable)
3090  {
3091  rv = SCARD_S_SUCCESS;
3092  goto error;
3093  }
3094 
3095  /* create a new connection to the server */
3096  if (ClientSetupSession(&dwClientID) != 0)
3097  {
3098  rv = SCARD_E_NO_SERVICE;
3099  goto error;
3100  }
3101 
3102  scCancelStruct.hContext = hContext;
3103  scCancelStruct.rv = SCARD_S_SUCCESS;
3104 
3105  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3106  sizeof(scCancelStruct), (void *) &scCancelStruct);
3107 
3108  if (rv != SCARD_S_SUCCESS)
3109  goto end;
3110 
3111  /*
3112  * Read a message from the server
3113  */
3114  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3115 
3116  if (rv != SCARD_S_SUCCESS)
3117  goto end;
3118 
3119  rv = scCancelStruct.rv;
3120 end:
3121  ClientCloseSession(dwClientID);
3122 
3123 error:
3124  PROFILE_END(rv)
3125  API_TRACE_OUT("")
3126 
3127  return rv;
3128 }
3129 
3154 {
3155  LONG rv;
3156  SCONTEXTMAP * currentContextMap;
3157 
3158  PROFILE_START
3159  API_TRACE_IN("%ld", hContext)
3160 
3161  rv = SCARD_S_SUCCESS;
3162 
3163  /*
3164  * Make sure this context has been opened
3165  */
3166  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3167  if (currentContextMap == NULL)
3169 
3170  PROFILE_END(rv)
3171  API_TRACE_OUT("")
3172 
3173  return rv;
3174 }
3175 
3192 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3193 {
3194  int lrv;
3195  SCONTEXTMAP * newContextMap;
3196 
3197  newContextMap = malloc(sizeof(SCONTEXTMAP));
3198  if (NULL == newContextMap)
3199  return SCARD_E_NO_MEMORY;
3200 
3201  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3202  newContextMap->hContext = hContext;
3203  newContextMap->dwClientID = dwClientID;
3204  newContextMap->cancellable = FALSE;
3205 
3206  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3207 
3208  lrv = list_init(&newContextMap->channelMapList);
3209  if (lrv < 0)
3210  {
3211  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3212  goto error;
3213  }
3214 
3215  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3216  CHANNEL_MAP_seeker);
3217  if (lrv <0)
3218  {
3219  Log2(PCSC_LOG_CRITICAL,
3220  "list_attributes_seeker failed with return value: %d", lrv);
3221  list_destroy(&newContextMap->channelMapList);
3222  goto error;
3223  }
3224 
3225  lrv = list_append(&contextMapList, newContextMap);
3226  if (lrv < 0)
3227  {
3228  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3229  lrv);
3230  list_destroy(&newContextMap->channelMapList);
3231  goto error;
3232  }
3233 
3234  return SCARD_S_SUCCESS;
3235 
3236 error:
3237 
3238  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3239  free(newContextMap);
3240 
3241  return SCARD_E_NO_MEMORY;
3242 }
3243 
3258 {
3259  SCONTEXTMAP * currentContextMap;
3260 
3261  (void)SCardLockThread();
3262  currentContextMap = SCardGetContextTH(hContext);
3263 
3264  /* lock the context (if available) */
3265  if (lock && NULL != currentContextMap)
3266  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3267 
3268  (void)SCardUnlockThread();
3269 
3270  return currentContextMap;
3271 }
3272 
3286 {
3287  return list_seek(&contextMapList, &hContext);
3288 }
3289 
3299 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3300 {
3301  SCONTEXTMAP * currentContextMap;
3302  currentContextMap = SCardGetContextTH(hContext);
3303 
3304  if (NULL == currentContextMap)
3305  return SCARD_E_INVALID_HANDLE;
3306  else
3307  return SCardCleanContext(currentContextMap);
3308 }
3309 
3310 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3311 {
3312  int list_index, lrv;
3313  int listSize;
3314  CHANNEL_MAP * currentChannelMap;
3315 
3316  targetContextMap->hContext = 0;
3317  (void)ClientCloseSession(targetContextMap->dwClientID);
3318  targetContextMap->dwClientID = 0;
3319  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3320 
3321  listSize = list_size(&targetContextMap->channelMapList);
3322  for (list_index = 0; list_index < listSize; list_index++)
3323  {
3324  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3325  list_index);
3326  if (NULL == currentChannelMap)
3327  {
3328  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3329  list_index);
3330  continue;
3331  }
3332  else
3333  {
3334  free(currentChannelMap->readerName);
3335  free(currentChannelMap);
3336  }
3337 
3338  }
3339  list_destroy(&targetContextMap->channelMapList);
3340 
3341  lrv = list_delete(&contextMapList, targetContextMap);
3342  if (lrv < 0)
3343  {
3344  Log2(PCSC_LOG_CRITICAL,
3345  "list_delete failed with return value: %d", lrv);
3346  }
3347 
3348  free(targetContextMap);
3349 
3350  return SCARD_S_SUCCESS;
3351 }
3352 
3353 /*
3354  * Functions for managing hCard values returned from SCardConnect.
3355  */
3356 
3357 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3358  LPCSTR readerName)
3359 {
3360  CHANNEL_MAP * newChannelMap;
3361  int lrv = -1;
3362 
3363  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3364  if (NULL == newChannelMap)
3365  return SCARD_E_NO_MEMORY;
3366 
3367  newChannelMap->hCard = hCard;
3368  newChannelMap->readerName = strdup(readerName);
3369 
3370  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3371  if (lrv < 0)
3372  {
3373  free(newChannelMap->readerName);
3374  free(newChannelMap);
3375  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3376  lrv);
3377  return SCARD_E_NO_MEMORY;
3378  }
3379 
3380  return SCARD_S_SUCCESS;
3381 }
3382 
3383 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3384 {
3385  SCONTEXTMAP * currentContextMap;
3386  CHANNEL_MAP * currentChannelMap;
3387  int lrv;
3388  LONG rv;
3389 
3390  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3391  &currentChannelMap);
3392  if (rv == -1)
3393  return SCARD_E_INVALID_HANDLE;
3394 
3395  free(currentChannelMap->readerName);
3396 
3397  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3398  if (lrv < 0)
3399  {
3400  Log2(PCSC_LOG_CRITICAL,
3401  "list_delete failed with return value: %d", lrv);
3402  }
3403 
3404  free(currentChannelMap);
3405 
3406  return SCARD_S_SUCCESS;
3407 }
3408 
3409 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3410  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3411 {
3412  LONG rv;
3413 
3414  if (0 == hCard)
3415  return -1;
3416 
3417  (void)SCardLockThread();
3418  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3419  targetChannelMap);
3420 
3421  if (SCARD_S_SUCCESS == rv)
3422  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3423 
3424  (void)SCardUnlockThread();
3425 
3426  return rv;
3427 }
3428 
3429 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3430  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3431 {
3432  int listSize;
3433  int list_index;
3434  SCONTEXTMAP * currentContextMap;
3435  CHANNEL_MAP * currentChannelMap;
3436 
3437  /* Best to get the caller a crash early if we fail unsafely */
3438  *targetContextMap = NULL;
3439  *targetChannelMap = NULL;
3440 
3441  listSize = list_size(&contextMapList);
3442 
3443  for (list_index = 0; list_index < listSize; list_index++)
3444  {
3445  currentContextMap = list_get_at(&contextMapList, list_index);
3446  if (currentContextMap == NULL)
3447  {
3448  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3449  list_index);
3450  continue;
3451  }
3452  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3453  &hCard);
3454  if (currentChannelMap != NULL)
3455  {
3456  *targetContextMap = currentContextMap;
3457  *targetChannelMap = currentChannelMap;
3458  return SCARD_S_SUCCESS;
3459  }
3460  }
3461 
3462  return -1;
3463 }
3464 
3473 {
3474  LONG rv;
3475  struct stat statBuffer;
3476  char *socketName;
3477 
3478  socketName = getSocketName();
3479  rv = stat(socketName, &statBuffer);
3480 
3481  if (rv != 0)
3482  {
3483  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3484  socketName, strerror(errno));
3485  return SCARD_E_NO_SERVICE;
3486  }
3487 
3488  return SCARD_S_SUCCESS;
3489 }
3490 
3491 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3492 {
3493  int32_t dwClientID = currentContextMap->dwClientID;
3494  LONG rv;
3495 
3496  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3497  if (rv != SCARD_S_SUCCESS)
3498  return rv;
3499 
3500  /* Read a message from the server */
3501  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3502  if (rv != SCARD_S_SUCCESS)
3503  return rv;
3504 
3505  return SCARD_S_SUCCESS;
3506 }
3507 
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:56
wait for a reader state change
Definition: winscard_msg.h:94
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:73
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:172
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
get the client/server protocol version
Definition: winscard_msg.h:92
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:77
static short isExecuted
Make sure the initialization code is executed only once.
used by SCardEstablishContext()
Definition: winscard_msg.h:76
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:315
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
used by SCardEndTransaction()
Definition: winscard_msg.h:83
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT, int)
Get the index from the Application Context vector _psContextMap for the passed context.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:53
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
This handles abstract system level calls.
static LONG SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
static LONG SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
used by SCardConnect()
Definition: winscard_msg.h:79
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:47
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes...
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels all pending blocking requests on the SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:75
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
Represents the an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
get the readers state
Definition: winscard_msg.h:93
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:449
used by SCardReleaseContext()
Definition: winscard_msg.h:77
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:109
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:107
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:272
used by SCardReconnect()
Definition: winscard_msg.h:80
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:136
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:84
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
Represents an Application Context Channel.
This handles card insertion/removal events, updates ATR, protocol, and status information.
SCARDCONTEXT hContext
Application Context ID.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
char cancellable
We are in a cancellable call.
stop waiting for a reader state change
Definition: winscard_msg.h:95
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:55
int SYS_RandomInt(int, int)
Generate a pseudo random number.
Definition: sys_unix.c:95
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
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