pcsc-lite  1.8.14
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  * $Id$
39  */
40 
106 #include "config.h"
107 #include <stdlib.h>
108 #include <string.h>
109 #include <sys/types.h>
110 #include <fcntl.h>
111 #include <unistd.h>
112 #include <sys/un.h>
113 #include <errno.h>
114 #include <stddef.h>
115 #include <sys/time.h>
116 #include <pthread.h>
117 #include <sys/wait.h>
118 
119 #include "misc.h"
120 #include "pcscd.h"
121 #include "winscard.h"
122 #include "debuglog.h"
123 
124 #include "readerfactory.h"
125 #include "eventhandler.h"
126 #include "sys_generic.h"
127 #include "winscard_msg.h"
128 #include "utils.h"
129 
130 /* Display, on stderr, a trace of the WinSCard calls with arguments and
131  * results */
132 #undef DO_TRACE
133 
134 /* Profile the execution time of WinSCard calls */
135 #undef DO_PROFILE
136 
137 
139 #define SCARD_PROTOCOL_ANY_OLD 0x1000
140 
141 #ifndef TRUE
142 #define TRUE 1
143 #define FALSE 0
144 #endif
145 
146 static char sharing_shall_block = TRUE;
147 
148 #define COLOR_RED "\33[01;31m"
149 #define COLOR_GREEN "\33[32m"
150 #define COLOR_BLUE "\33[34m"
151 #define COLOR_MAGENTA "\33[35m"
152 #define COLOR_NORMAL "\33[0m"
153 
154 #ifdef DO_TRACE
155 
156 #include <stdio.h>
157 #include <stdarg.h>
158 
159 static void trace(const char *func, const char direction, const char *fmt, ...)
160 {
161  va_list args;
162 
163  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
164  direction, pthread_self(), func);
165 
166  fprintf(stderr, COLOR_MAGENTA);
167  va_start(args, fmt);
168  vfprintf(stderr, fmt, args);
169  va_end(args);
170 
171  fprintf(stderr, COLOR_NORMAL "\n");
172 }
173 
174 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
175 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
176 #else
177 #define API_TRACE_IN(...)
178 #define API_TRACE_OUT(...)
179 #endif
180 
181 #ifdef DO_PROFILE
182 
183 #define PROFILE_FILE "/tmp/pcsc_profile"
184 #include <stdio.h>
185 #include <sys/time.h>
186 
187 /* we can profile a maximum of 5 simultaneous calls */
188 #define MAX_THREADS 5
189 pthread_t threads[MAX_THREADS];
190 struct timeval profile_time_start[MAX_THREADS];
191 FILE *profile_fd;
192 char profile_tty;
193 
194 #define PROFILE_START profile_start();
195 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
196 
197 static void profile_start(void)
198 {
199  static char initialized = FALSE;
200  pthread_t t;
201  int i;
202 
203  if (!initialized)
204  {
205  char filename[80];
206 
207  initialized = TRUE;
208  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
209  profile_fd = fopen(filename, "a+");
210  if (NULL == profile_fd)
211  {
212  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
213  PROFILE_FILE, strerror(errno));
214  exit(-1);
215  }
216  fprintf(profile_fd, "\nStart a new profile\n");
217 
218  if (isatty(fileno(stderr)))
219  profile_tty = TRUE;
220  else
221  profile_tty = FALSE;
222  }
223 
224  t = pthread_self();
225  for (i=0; i<MAX_THREADS; i++)
226  if (pthread_equal(0, threads[i]))
227  {
228  threads[i] = t;
229  break;
230  }
231 
232  gettimeofday(&profile_time_start[i], NULL);
233 } /* profile_start */
234 
235 static void profile_end(const char *f, LONG rv)
236 {
237  struct timeval profile_time_end;
238  long d;
239  pthread_t t;
240  int i;
241 
242  gettimeofday(&profile_time_end, NULL);
243 
244  t = pthread_self();
245  for (i=0; i<MAX_THREADS; i++)
246  if (pthread_equal(t, threads[i]))
247  break;
248 
249  if (i>=MAX_THREADS)
250  {
251  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
252  return;
253  }
254 
255  d = time_sub(&profile_time_end, &profile_time_start[i]);
256 
257  /* free this entry */
258  threads[i] = 0;
259 
260  if (profile_tty)
261  {
262  if (rv != SCARD_S_SUCCESS)
263  fprintf(stderr,
264  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
265  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
266  f, d, rv, pcsc_stringify_error(rv));
267  else
268  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
269  COLOR_NORMAL "\n", f, d);
270  }
271  fprintf(profile_fd, "%s %ld\n", f, d);
272  fflush(profile_fd);
273 } /* profile_end */
274 
275 #else
276 #define PROFILE_START
277 #define PROFILE_END(rv)
278 #endif
279 
285 {
286  SCARDHANDLE hCard;
287  LPSTR readerName;
288 };
289 
290 typedef struct _psChannelMap CHANNEL_MAP;
291 
292 static int CHANNEL_MAP_seeker(const void *el, const void *key)
293 {
294  const CHANNEL_MAP * channelMap = el;
295 
296  if ((el == NULL) || (key == NULL))
297  {
298  Log3(PCSC_LOG_CRITICAL,
299  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
300  el, key);
301  return 0;
302  }
303 
304  if (channelMap->hCard == *(SCARDHANDLE *)key)
305  return 1;
306 
307  return 0;
308 }
309 
316 {
317  DWORD dwClientID;
319  pthread_mutex_t mMutex;
320  list_t channelMapList;
321  char cancellable;
322 };
323 typedef struct _psContextMap SCONTEXTMAP;
324 
325 static list_t contextMapList;
326 
327 static int SCONTEXTMAP_seeker(const void *el, const void *key)
328 {
329  const SCONTEXTMAP * contextMap = el;
330 
331  if ((el == NULL) || (key == NULL))
332  {
333  Log3(PCSC_LOG_CRITICAL,
334  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
335  el, key);
336  return 0;
337  }
338 
339  if (contextMap->hContext == *(SCARDCONTEXT *) key)
340  return 1;
341 
342  return 0;
343 }
344 
348 static short isExecuted = 0;
349 
350 
355 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
356 
361 
368 
369 
370 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
373 static LONG SCardRemoveContext(SCARDCONTEXT);
374 static LONG SCardCleanContext(SCONTEXTMAP *);
375 
376 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
377 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
378  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
379 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
380  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
381 static LONG SCardRemoveHandle(SCARDHANDLE);
382 
383 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
384  LPBYTE pbAttr, LPDWORD pcbAttrLen);
385 
386 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
387 
388 /*
389  * Thread safety functions
390  */
397 inline static LONG SCardLockThread(void)
398 {
399  return pthread_mutex_lock(&clientMutex);
400 }
401 
407 inline static LONG SCardUnlockThread(void)
408 {
409  return pthread_mutex_unlock(&clientMutex);
410 }
411 
412 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
413  /*@out@*/ LPSCARDCONTEXT);
414 
448 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
449  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
450 {
451  LONG rv;
452 
453  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
454  PROFILE_START
455 
456  /* Check if the server is running */
458  if (rv != SCARD_S_SUCCESS)
459  goto end;
460 
461  (void)SCardLockThread();
462  rv = SCardEstablishContextTH(dwScope, pvReserved1,
463  pvReserved2, phContext);
464  (void)SCardUnlockThread();
465 
466 end:
467  PROFILE_END(rv)
468  API_TRACE_OUT("%ld", *phContext)
469 
470  return rv;
471 }
472 
499 static LONG SCardEstablishContextTH(DWORD dwScope,
500  /*@unused@*/ LPCVOID pvReserved1,
501  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
502 {
503  LONG rv;
504  struct establish_struct scEstablishStruct;
505  uint32_t dwClientID = 0;
506 
507  (void)pvReserved1;
508  (void)pvReserved2;
509  if (phContext == NULL)
511  else
512  *phContext = 0;
513 
514  /*
515  * Do this only once:
516  * - Initialize context list.
517  */
518  if (isExecuted == 0)
519  {
520  int lrv;
521 
522  /* NOTE: The list will never be freed (No API call exists to
523  * "close all contexts".
524  * Applications which load and unload the library will leak
525  * the list's internal structures. */
526  lrv = list_init(&contextMapList);
527  if (lrv < 0)
528  {
529  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
530  lrv);
531  return SCARD_E_NO_MEMORY;
532  }
533 
534  lrv = list_attributes_seeker(&contextMapList,
535  SCONTEXTMAP_seeker);
536  if (lrv <0)
537  {
538  Log2(PCSC_LOG_CRITICAL,
539  "list_attributes_seeker failed with return value: %d", lrv);
540  list_destroy(&contextMapList);
541  return SCARD_E_NO_MEMORY;
542  }
543 
544  if (getenv("PCSCLITE_NO_BLOCKING"))
545  {
546  Log1(PCSC_LOG_INFO, "Disable shared blocking");
547  sharing_shall_block = FALSE;
548  }
549 
550  isExecuted = 1;
551  }
552 
553 
554  /* Establishes a connection to the server */
555  if (ClientSetupSession(&dwClientID) != 0)
556  {
557  return SCARD_E_NO_SERVICE;
558  }
559 
560  { /* exchange client/server protocol versions */
561  struct version_struct veStr;
562 
565  veStr.rv = SCARD_S_SUCCESS;
566 
567  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
568  &veStr);
569  if (rv != SCARD_S_SUCCESS)
570  return rv;
571 
572  /* Read a message from the server */
573  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
574  if (rv != SCARD_S_SUCCESS)
575  {
576  Log1(PCSC_LOG_CRITICAL,
577  "Your pcscd is too old and does not support CMD_VERSION");
578  return SCARD_F_COMM_ERROR;
579  }
580 
581  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
582  veStr.major, veStr.minor);
583 
584  if (veStr.rv != SCARD_S_SUCCESS)
585  return veStr.rv;
586  }
587 
588 again:
589  /*
590  * Try to establish an Application Context with the server
591  */
592  scEstablishStruct.dwScope = dwScope;
593  scEstablishStruct.hContext = 0;
594  scEstablishStruct.rv = SCARD_S_SUCCESS;
595 
597  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
598 
599  if (rv != SCARD_S_SUCCESS)
600  return rv;
601 
602  /*
603  * Read the response from the server
604  */
605  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
606  dwClientID);
607 
608  if (rv != SCARD_S_SUCCESS)
609  return rv;
610 
611  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
612  return scEstablishStruct.rv;
613 
614  /* check we do not reuse an existing hContext */
615  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
616  /* we do not need to release the allocated context since
617  * SCardReleaseContext() does nothing on the server side */
618  goto again;
619 
620  *phContext = scEstablishStruct.hContext;
621 
622  /*
623  * Allocate the new hContext - if allocator full return an error
624  */
625  rv = SCardAddContext(*phContext, dwClientID);
626 
627  return rv;
628 }
629 
652 {
653  LONG rv;
654  struct release_struct scReleaseStruct;
655  SCONTEXTMAP * currentContextMap;
656 
657  API_TRACE_IN("%ld", hContext)
658  PROFILE_START
659 
660  /*
661  * Make sure this context has been opened
662  * and get currentContextMap
663  */
664  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
665  if (NULL == currentContextMap)
666  {
668  goto error;
669  }
670 
671  scReleaseStruct.hContext = hContext;
672  scReleaseStruct.rv = SCARD_S_SUCCESS;
673 
675  currentContextMap->dwClientID,
676  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
677 
678  if (rv != SCARD_S_SUCCESS)
679  goto end;
680 
681  /*
682  * Read a message from the server
683  */
684  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
685  currentContextMap->dwClientID);
686 
687  if (rv != SCARD_S_SUCCESS)
688  goto end;
689 
690  rv = scReleaseStruct.rv;
691 end:
692  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
693 
694  /*
695  * Remove the local context from the stack
696  */
697  (void)SCardLockThread();
698  (void)SCardRemoveContext(hContext);
699  (void)SCardUnlockThread();
700 
701 error:
702  PROFILE_END(rv)
703  API_TRACE_OUT("")
704 
705  return rv;
706 }
707 
764 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
765  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
766  LPDWORD pdwActiveProtocol)
767 {
768  LONG rv;
769  struct connect_struct scConnectStruct;
770  SCONTEXTMAP * currentContextMap;
771 
772  PROFILE_START
773  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
774 
775  /*
776  * Check for NULL parameters
777  */
778  if (phCard == NULL || pdwActiveProtocol == NULL)
780  else
781  *phCard = 0;
782 
783  if (szReader == NULL)
784  return SCARD_E_UNKNOWN_READER;
785 
786  /*
787  * Check for uninitialized strings
788  */
789  if (strlen(szReader) > MAX_READERNAME)
790  return SCARD_E_INVALID_VALUE;
791 
792  /*
793  * Make sure this context has been opened
794  */
795  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
796  if (NULL == currentContextMap)
797  return SCARD_E_INVALID_HANDLE;
798 
799  strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
800  scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
801 
802  scConnectStruct.hContext = hContext;
803  scConnectStruct.dwShareMode = dwShareMode;
804  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
805  scConnectStruct.hCard = 0;
806  scConnectStruct.dwActiveProtocol = 0;
807  scConnectStruct.rv = SCARD_S_SUCCESS;
808 
809  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
810  sizeof(scConnectStruct), (void *) &scConnectStruct);
811 
812  if (rv != SCARD_S_SUCCESS)
813  goto end;
814 
815  /*
816  * Read a message from the server
817  */
818  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
819  currentContextMap->dwClientID);
820 
821  if (rv != SCARD_S_SUCCESS)
822  goto end;
823 
824  *phCard = scConnectStruct.hCard;
825  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
826 
827  if (scConnectStruct.rv == SCARD_S_SUCCESS)
828  {
829  /*
830  * Keep track of the handle locally
831  */
832  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
833  }
834  else
835  rv = scConnectStruct.rv;
836 
837 end:
838  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
839 
840  PROFILE_END(rv)
841  API_TRACE_OUT("%d", *pdwActiveProtocol)
842 
843  return rv;
844 }
845 
919 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
920  DWORD dwPreferredProtocols, DWORD dwInitialization,
921  LPDWORD pdwActiveProtocol)
922 {
923  LONG rv;
924  struct reconnect_struct scReconnectStruct;
925  SCONTEXTMAP * currentContextMap;
926  CHANNEL_MAP * pChannelMap;
927 
928  PROFILE_START
929  API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
930 
931  if (pdwActiveProtocol == NULL)
933 
934  /* Retry loop for blocking behaviour */
935 retry:
936 
937  /*
938  * Make sure this handle has been opened
939  */
940  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
941  &pChannelMap);
942  if (rv == -1)
943  return SCARD_E_INVALID_HANDLE;
944 
945  scReconnectStruct.hCard = hCard;
946  scReconnectStruct.dwShareMode = dwShareMode;
947  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
948  scReconnectStruct.dwInitialization = dwInitialization;
949  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
950  scReconnectStruct.rv = SCARD_S_SUCCESS;
951 
952  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
953  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
954 
955  if (rv != SCARD_S_SUCCESS)
956  goto end;
957 
958  /*
959  * Read a message from the server
960  */
961  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
962  currentContextMap->dwClientID);
963 
964  if (rv != SCARD_S_SUCCESS)
965  goto end;
966 
967  rv = scReconnectStruct.rv;
968 
969  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
970  {
971  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
973  goto retry;
974  }
975 
976  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
977 
978 end:
979  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
980 
981  PROFILE_END(rv)
982  API_TRACE_OUT("%ld", *pdwActiveProtocol)
983 
984  return rv;
985 }
986 
1018 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1019 {
1020  LONG rv;
1021  struct disconnect_struct scDisconnectStruct;
1022  SCONTEXTMAP * currentContextMap;
1023  CHANNEL_MAP * pChannelMap;
1024 
1025  PROFILE_START
1026  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1027 
1028  /*
1029  * Make sure this handle has been opened
1030  */
1031  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1032  &pChannelMap);
1033  if (rv == -1)
1034  {
1036  goto error;
1037  }
1038 
1039  scDisconnectStruct.hCard = hCard;
1040  scDisconnectStruct.dwDisposition = dwDisposition;
1041  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1042 
1043  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1044  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1045 
1046  if (rv != SCARD_S_SUCCESS)
1047  goto end;
1048 
1049  /*
1050  * Read a message from the server
1051  */
1052  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1053  currentContextMap->dwClientID);
1054 
1055  if (rv != SCARD_S_SUCCESS)
1056  goto end;
1057 
1058  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1059  (void)SCardRemoveHandle(hCard);
1060  rv = scDisconnectStruct.rv;
1061 
1062 end:
1063  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1064 
1065 error:
1066  PROFILE_END(rv)
1067  API_TRACE_OUT("")
1068 
1069  return rv;
1070 }
1071 
1108 {
1109 
1110  LONG rv;
1111  struct begin_struct scBeginStruct;
1112  SCONTEXTMAP * currentContextMap;
1113  CHANNEL_MAP * pChannelMap;
1114 
1115  PROFILE_START
1116  API_TRACE_IN("%ld", hCard)
1117 
1118  /*
1119  * Query the server every so often until the sharing violation ends
1120  * and then hold the lock for yourself.
1121  */
1122 
1123  for(;;)
1124  {
1125  /*
1126  * Make sure this handle has been opened
1127  */
1128  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1129  &pChannelMap);
1130  if (rv == -1)
1131  return SCARD_E_INVALID_HANDLE;
1132 
1133  scBeginStruct.hCard = hCard;
1134  scBeginStruct.rv = SCARD_S_SUCCESS;
1135 
1137  currentContextMap->dwClientID,
1138  sizeof(scBeginStruct), (void *) &scBeginStruct);
1139 
1140  if (rv != SCARD_S_SUCCESS)
1141  break;
1142 
1143  /*
1144  * Read a message from the server
1145  */
1146  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1147  currentContextMap->dwClientID);
1148 
1149  if (rv != SCARD_S_SUCCESS)
1150  break;
1151 
1152  rv = scBeginStruct.rv;
1153 
1154  if (SCARD_E_SHARING_VIOLATION != rv)
1155  break;
1156 
1157  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1159  }
1160 
1161  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1162 
1163  PROFILE_END(rv)
1164  API_TRACE_OUT("")
1165 
1166  return rv;
1167 }
1168 
1208 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1209 {
1210  LONG rv;
1211  struct end_struct scEndStruct;
1212  int randnum;
1213  SCONTEXTMAP * currentContextMap;
1214  CHANNEL_MAP * pChannelMap;
1215 
1216  PROFILE_START
1217  API_TRACE_IN("%ld", hCard)
1218 
1219  /*
1220  * Make sure this handle has been opened
1221  */
1222  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1223  &pChannelMap);
1224  if (rv == -1)
1225  return SCARD_E_INVALID_HANDLE;
1226 
1227  scEndStruct.hCard = hCard;
1228  scEndStruct.dwDisposition = dwDisposition;
1229  scEndStruct.rv = SCARD_S_SUCCESS;
1230 
1232  currentContextMap->dwClientID,
1233  sizeof(scEndStruct), (void *) &scEndStruct);
1234 
1235  if (rv != SCARD_S_SUCCESS)
1236  goto end;
1237 
1238  /*
1239  * Read a message from the server
1240  */
1241  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1242  currentContextMap->dwClientID);
1243 
1244  if (rv != SCARD_S_SUCCESS)
1245  goto end;
1246 
1247  /*
1248  * This helps prevent starvation
1249  */
1250  randnum = SYS_RandomInt(1000, 10000);
1251  (void)SYS_USleep(randnum);
1252  rv = scEndStruct.rv;
1253 
1254 end:
1255  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1256 
1257  PROFILE_END(rv)
1258  API_TRACE_OUT("")
1259 
1260  return rv;
1261 }
1262 
1358 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
1359  LPDWORD pcchReaderLen, LPDWORD pdwState,
1360  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1361 {
1362  DWORD dwReaderLen, dwAtrLen;
1363  LONG rv;
1364  int i;
1365  struct status_struct scStatusStruct;
1366  SCONTEXTMAP * currentContextMap;
1367  CHANNEL_MAP * pChannelMap;
1368  char *r;
1369  char *bufReader = NULL;
1370  LPBYTE bufAtr = NULL;
1371  DWORD dummy = 0;
1372 
1373  PROFILE_START
1374 
1375  /* default output values */
1376  if (pdwState)
1377  *pdwState = 0;
1378 
1379  if (pdwProtocol)
1380  *pdwProtocol = 0;
1381 
1382  /* Check for NULL parameters */
1383  if (pcchReaderLen == NULL)
1384  pcchReaderLen = &dummy;
1385 
1386  if (pcbAtrLen == NULL)
1387  pcbAtrLen = &dummy;
1388 
1389  /* length passed from caller */
1390  dwReaderLen = *pcchReaderLen;
1391  dwAtrLen = *pcbAtrLen;
1392 
1393  *pcchReaderLen = 0;
1394  *pcbAtrLen = 0;
1395 
1396  /* Retry loop for blocking behaviour */
1397 retry:
1398 
1399  /*
1400  * Make sure this handle has been opened
1401  */
1402  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1403  &pChannelMap);
1404  if (rv == -1)
1405  return SCARD_E_INVALID_HANDLE;
1406 
1407  /* synchronize reader states with daemon */
1408  rv = getReaderStates(currentContextMap);
1409  if (rv != SCARD_S_SUCCESS)
1410  goto end;
1411 
1412  r = pChannelMap->readerName;
1413  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1414  {
1415  /* by default r == NULL */
1416  if (r && strcmp(r, readerStates[i].readerName) == 0)
1417  break;
1418  }
1419 
1420  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1421  {
1423  goto end;
1424  }
1425 
1426  /* initialise the structure */
1427  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1428  scStatusStruct.hCard = hCard;
1429 
1430  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1431  sizeof(scStatusStruct), (void *) &scStatusStruct);
1432 
1433  if (rv != SCARD_S_SUCCESS)
1434  goto end;
1435 
1436  /*
1437  * Read a message from the server
1438  */
1439  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1440  currentContextMap->dwClientID);
1441 
1442  if (rv != SCARD_S_SUCCESS)
1443  goto end;
1444 
1445  rv = scStatusStruct.rv;
1446 
1447  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1448  {
1449  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1451  goto retry;
1452  }
1453 
1454  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1455  {
1456  /*
1457  * An event must have occurred
1458  */
1459  goto end;
1460  }
1461 
1462  /*
1463  * Now continue with the client side SCardStatus
1464  */
1465 
1466  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1467  *pcbAtrLen = readerStates[i].cardAtrLength;
1468 
1469  if (pdwState)
1470  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1471 
1472  if (pdwProtocol)
1473  *pdwProtocol = readerStates[i].cardProtocol;
1474 
1475  if (SCARD_AUTOALLOCATE == dwReaderLen)
1476  {
1477  dwReaderLen = *pcchReaderLen;
1478  if (NULL == mszReaderName)
1479  {
1481  goto end;
1482  }
1483  bufReader = malloc(dwReaderLen);
1484  if (NULL == bufReader)
1485  {
1486  rv = SCARD_E_NO_MEMORY;
1487  goto end;
1488  }
1489  *(char **)mszReaderName = bufReader;
1490  }
1491  else
1492  bufReader = mszReaderName;
1493 
1494  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1495  if (bufReader)
1496  {
1497  if (*pcchReaderLen > dwReaderLen)
1499 
1500  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1501  }
1502 
1503  if (SCARD_AUTOALLOCATE == dwAtrLen)
1504  {
1505  dwAtrLen = *pcbAtrLen;
1506  if (NULL == pbAtr)
1507  {
1509  goto end;
1510  }
1511  bufAtr = malloc(dwAtrLen);
1512  if (NULL == bufAtr)
1513  {
1514  rv = SCARD_E_NO_MEMORY;
1515  goto end;
1516  }
1517  *(LPBYTE *)pbAtr = bufAtr;
1518  }
1519  else
1520  bufAtr = pbAtr;
1521 
1522  if (bufAtr)
1523  {
1524  if (*pcbAtrLen > dwAtrLen)
1526 
1527  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1528  }
1529 
1530 end:
1531  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1532 
1533  PROFILE_END(rv)
1534 
1535  return rv;
1536 }
1537 
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 
2366 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2367  LPDWORD pcbAttrLen)
2368 {
2369  LONG ret;
2370  unsigned char *buf = NULL;
2371 
2372  PROFILE_START
2373 
2374  if (NULL == pcbAttrLen)
2375  {
2377  goto end;
2378  }
2379 
2380  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2381  {
2382  if (NULL == pbAttr)
2384 
2385  *pcbAttrLen = MAX_BUFFER_SIZE;
2386  buf = malloc(*pcbAttrLen);
2387  if (NULL == buf)
2388  {
2389  ret = SCARD_E_NO_MEMORY;
2390  goto end;
2391  }
2392 
2393  *(unsigned char **)pbAttr = buf;
2394  }
2395  else
2396  {
2397  buf = pbAttr;
2398 
2399  /* if only get the length */
2400  if (NULL == pbAttr)
2401  /* use a reasonable size */
2402  *pcbAttrLen = MAX_BUFFER_SIZE;
2403  }
2404 
2405  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2406  pcbAttrLen);
2407 
2408 end:
2409  PROFILE_END(ret)
2410 
2411  return ret;
2412 }
2413 
2449 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2450  DWORD cbAttrLen)
2451 {
2452  LONG ret;
2453 
2454  PROFILE_START
2455 
2456  if (NULL == pbAttr || 0 == cbAttrLen)
2458 
2459  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2460  &cbAttrLen);
2461 
2462  PROFILE_END(ret)
2463 
2464  return ret;
2465 }
2466 
2467 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2468  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2469 {
2470  LONG rv;
2471  struct getset_struct scGetSetStruct;
2472  SCONTEXTMAP * currentContextMap;
2473  CHANNEL_MAP * pChannelMap;
2474 
2475  /*
2476  * Make sure this handle has been opened
2477  */
2478  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2479  &pChannelMap);
2480  if (rv == -1)
2481  return SCARD_E_INVALID_HANDLE;
2482 
2483  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2484  {
2486  goto end;
2487  }
2488 
2489  scGetSetStruct.hCard = hCard;
2490  scGetSetStruct.dwAttrId = dwAttrId;
2491  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2492  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2493  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2494  if (SCARD_SET_ATTRIB == command)
2495  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2496 
2497  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2498  sizeof(scGetSetStruct), &scGetSetStruct);
2499 
2500  if (rv != SCARD_S_SUCCESS)
2501  goto end;
2502 
2503  /*
2504  * Read a message from the server
2505  */
2506  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2507  currentContextMap->dwClientID);
2508 
2509  if (rv != SCARD_S_SUCCESS)
2510  goto end;
2511 
2512  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2513  {
2514  /*
2515  * Copy and zero it so any secret information is not leaked
2516  */
2517  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2518  {
2519  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2520  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2521  }
2522  else
2523  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2524 
2525  if (pbAttr)
2526  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2527 
2528  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2529  }
2530  rv = scGetSetStruct.rv;
2531 
2532 end:
2533  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2534 
2535  return rv;
2536 }
2537 
2596 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2597  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2598  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2599  LPDWORD pcbRecvLength)
2600 {
2601  LONG rv;
2602  SCONTEXTMAP * currentContextMap;
2603  CHANNEL_MAP * pChannelMap;
2604  struct transmit_struct scTransmitStruct;
2605 
2606  PROFILE_START
2607 
2608  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2609  pcbRecvLength == NULL || pioSendPci == NULL)
2611 
2612  /* Retry loop for blocking behaviour */
2613 retry:
2614 
2615  /*
2616  * Make sure this handle has been opened
2617  */
2618  rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2619  &pChannelMap);
2620  if (rv == -1)
2621  {
2622  *pcbRecvLength = 0;
2623  PROFILE_END(SCARD_E_INVALID_HANDLE)
2624  return SCARD_E_INVALID_HANDLE;
2625  }
2626 
2627  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2628  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2629  {
2631  goto end;
2632  }
2633 
2634  scTransmitStruct.hCard = hCard;
2635  scTransmitStruct.cbSendLength = cbSendLength;
2636  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2637  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2638  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2639  scTransmitStruct.rv = SCARD_S_SUCCESS;
2640 
2641  if (pioRecvPci)
2642  {
2643  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2644  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2645  }
2646  else
2647  {
2648  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2649  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2650  }
2651 
2652  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2653  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2654 
2655  if (rv != SCARD_S_SUCCESS)
2656  goto end;
2657 
2658  /* write the sent buffer */
2659  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2660  currentContextMap->dwClientID);
2661 
2662  if (rv != SCARD_S_SUCCESS)
2663  goto end;
2664 
2665  /*
2666  * Read a message from the server
2667  */
2668  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2669  currentContextMap->dwClientID);
2670 
2671  if (rv != SCARD_S_SUCCESS)
2672  goto end;
2673 
2674  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2675  {
2676  /* read the received buffer */
2677  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2678  currentContextMap->dwClientID);
2679 
2680  if (rv != SCARD_S_SUCCESS)
2681  goto end;
2682 
2683  if (pioRecvPci)
2684  {
2685  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2686  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2687  }
2688  }
2689 
2690  rv = scTransmitStruct.rv;
2691 
2692  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2693  {
2694  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2696  goto retry;
2697  }
2698 
2699  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2700 
2701 end:
2702  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2703 
2704  PROFILE_END(rv)
2705 
2706  return rv;
2707 }
2708 
2762 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2763  LPSTR mszReaders, LPDWORD pcchReaders)
2764 {
2765  DWORD dwReadersLen = 0;
2766  int i;
2767  SCONTEXTMAP * currentContextMap;
2768  LONG rv = SCARD_S_SUCCESS;
2769  char *buf = NULL;
2770 
2771  (void)mszGroups;
2772  PROFILE_START
2773  API_TRACE_IN("%ld", hContext)
2774 
2775  /*
2776  * Check for NULL parameters
2777  */
2778  if (pcchReaders == NULL)
2780 
2781  /*
2782  * Make sure this context has been opened
2783  */
2784  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2785  if (NULL == currentContextMap)
2786  {
2787  PROFILE_END(SCARD_E_INVALID_HANDLE)
2788  return SCARD_E_INVALID_HANDLE;
2789  }
2790 
2791  /* synchronize reader states with daemon */
2792  rv = getReaderStates(currentContextMap);
2793  if (rv != SCARD_S_SUCCESS)
2794  goto end;
2795 
2796  dwReadersLen = 0;
2797  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2798  if (readerStates[i].readerName[0] != '\0')
2799  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2800 
2801  /* for the last NULL byte */
2802  dwReadersLen += 1;
2803 
2804  if (1 == dwReadersLen)
2805  {
2807  goto end;
2808  }
2809 
2810  if (SCARD_AUTOALLOCATE == *pcchReaders)
2811  {
2812  if (NULL == mszReaders)
2813  {
2815  goto end;
2816  }
2817  buf = malloc(dwReadersLen);
2818  if (NULL == buf)
2819  {
2820  rv = SCARD_E_NO_MEMORY;
2821  goto end;
2822  }
2823  *(char **)mszReaders = buf;
2824  }
2825  else
2826  {
2827  buf = mszReaders;
2828 
2829  /* not enough place to store the reader names */
2830  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2831  {
2833  goto end;
2834  }
2835  }
2836 
2837  if (mszReaders == NULL) /* text array not allocated */
2838  goto end;
2839 
2840  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2841  {
2842  if (readerStates[i].readerName[0] != '\0')
2843  {
2844  /*
2845  * Build the multi-string
2846  */
2847  strcpy(buf, readerStates[i].readerName);
2848  buf += strlen(readerStates[i].readerName)+1;
2849  }
2850  }
2851  *buf = '\0'; /* Add the last null */
2852 
2853 end:
2854  /* set the reader names length */
2855  *pcchReaders = dwReadersLen;
2856 
2857  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2858 
2859  PROFILE_END(rv)
2860  API_TRACE_OUT("%d", *pcchReaders)
2861 
2862  return rv;
2863 }
2864 
2878 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2879 {
2880  LONG rv = SCARD_S_SUCCESS;
2881  SCONTEXTMAP * currentContextMap;
2882 
2883  PROFILE_START
2884 
2885  /*
2886  * Make sure this context has been opened
2887  */
2888  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
2889  if (NULL == currentContextMap)
2890  return SCARD_E_INVALID_HANDLE;
2891 
2892  free((void *)pvMem);
2893 
2894  PROFILE_END(rv)
2895 
2896  return rv;
2897 }
2898 
2950 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2951  LPDWORD pcchGroups)
2952 {
2953  LONG rv = SCARD_S_SUCCESS;
2954  SCONTEXTMAP * currentContextMap;
2955  char *buf = NULL;
2956 
2957  PROFILE_START
2958 
2959  /* Multi-string with two trailing \0 */
2960  const char ReaderGroup[] = "SCard$DefaultReaders\0";
2961  const unsigned int dwGroups = sizeof(ReaderGroup);
2962 
2963  /*
2964  * Make sure this context has been opened
2965  */
2966  currentContextMap = SCardGetAndLockContext(hContext, TRUE);
2967  if (NULL == currentContextMap)
2968  return SCARD_E_INVALID_HANDLE;
2969 
2970  if (SCARD_AUTOALLOCATE == *pcchGroups)
2971  {
2972  if (NULL == mszGroups)
2973  {
2975  goto end;
2976  }
2977  buf = malloc(dwGroups);
2978  if (NULL == buf)
2979  {
2980  rv = SCARD_E_NO_MEMORY;
2981  goto end;
2982  }
2983  *(char **)mszGroups = buf;
2984  }
2985  else
2986  {
2987  buf = mszGroups;
2988 
2989  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
2990  {
2992  goto end;
2993  }
2994  }
2995 
2996  if (buf)
2997  memcpy(buf, ReaderGroup, dwGroups);
2998 
2999 end:
3000  *pcchGroups = dwGroups;
3001 
3002  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3003 
3004  PROFILE_END(rv)
3005 
3006  return rv;
3007 }
3008 
3039 {
3040  SCONTEXTMAP * currentContextMap;
3041  LONG rv = SCARD_S_SUCCESS;
3042  uint32_t dwClientID = 0;
3043  struct cancel_struct scCancelStruct;
3044 
3045  PROFILE_START
3046  API_TRACE_IN("%ld", hContext)
3047 
3048  /*
3049  * Make sure this context has been opened
3050  */
3051  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3052  if (NULL == currentContextMap)
3053  {
3055  goto error;
3056  }
3057 
3058  if (! currentContextMap->cancellable)
3059  {
3060  rv = SCARD_S_SUCCESS;
3061  goto error;
3062  }
3063 
3064  /* create a new connection to the server */
3065  if (ClientSetupSession(&dwClientID) != 0)
3066  {
3067  rv = SCARD_E_NO_SERVICE;
3068  goto error;
3069  }
3070 
3071  scCancelStruct.hContext = hContext;
3072  scCancelStruct.rv = SCARD_S_SUCCESS;
3073 
3074  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3075  sizeof(scCancelStruct), (void *) &scCancelStruct);
3076 
3077  if (rv != SCARD_S_SUCCESS)
3078  goto end;
3079 
3080  /*
3081  * Read a message from the server
3082  */
3083  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3084 
3085  if (rv != SCARD_S_SUCCESS)
3086  goto end;
3087 
3088  rv = scCancelStruct.rv;
3089 end:
3090  ClientCloseSession(dwClientID);
3091 
3092 error:
3093  PROFILE_END(rv)
3094  API_TRACE_OUT("")
3095 
3096  return rv;
3097 }
3098 
3123 {
3124  LONG rv;
3125  SCONTEXTMAP * currentContextMap;
3126 
3127  PROFILE_START
3128  API_TRACE_IN("%ld", hContext)
3129 
3130  rv = SCARD_S_SUCCESS;
3131 
3132  /*
3133  * Make sure this context has been opened
3134  */
3135  currentContextMap = SCardGetAndLockContext(hContext, FALSE);
3136  if (currentContextMap == NULL)
3138 
3139  PROFILE_END(rv)
3140  API_TRACE_OUT("")
3141 
3142  return rv;
3143 }
3144 
3161 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3162 {
3163  int lrv;
3164  SCONTEXTMAP * newContextMap;
3165 
3166  newContextMap = malloc(sizeof(SCONTEXTMAP));
3167  if (NULL == newContextMap)
3168  return SCARD_E_NO_MEMORY;
3169 
3170  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3171  newContextMap->hContext = hContext;
3172  newContextMap->dwClientID = dwClientID;
3173  newContextMap->cancellable = FALSE;
3174 
3175  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3176 
3177  lrv = list_init(&newContextMap->channelMapList);
3178  if (lrv < 0)
3179  {
3180  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3181  goto error;
3182  }
3183 
3184  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3185  CHANNEL_MAP_seeker);
3186  if (lrv <0)
3187  {
3188  Log2(PCSC_LOG_CRITICAL,
3189  "list_attributes_seeker failed with return value: %d", lrv);
3190  list_destroy(&newContextMap->channelMapList);
3191  goto error;
3192  }
3193 
3194  lrv = list_append(&contextMapList, newContextMap);
3195  if (lrv < 0)
3196  {
3197  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3198  lrv);
3199  list_destroy(&newContextMap->channelMapList);
3200  goto error;
3201  }
3202 
3203  return SCARD_S_SUCCESS;
3204 
3205 error:
3206 
3207  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3208  free(newContextMap);
3209 
3210  return SCARD_E_NO_MEMORY;
3211 }
3212 
3226 {
3227  SCONTEXTMAP * currentContextMap;
3228 
3229  (void)SCardLockThread();
3230  currentContextMap = SCardGetContextTH(hContext);
3231 
3232  /* lock the context (if available) */
3233  if (lock && NULL != currentContextMap)
3234  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3235 
3236  (void)SCardUnlockThread();
3237 
3238  return currentContextMap;
3239 }
3240 
3254 {
3255  return list_seek(&contextMapList, &hContext);
3256 }
3257 
3267 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3268 {
3269  SCONTEXTMAP * currentContextMap;
3270  currentContextMap = SCardGetContextTH(hContext);
3271 
3272  if (NULL == currentContextMap)
3273  return SCARD_E_INVALID_HANDLE;
3274  else
3275  return SCardCleanContext(currentContextMap);
3276 }
3277 
3278 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3279 {
3280  int list_index, lrv;
3281  int listSize;
3282  CHANNEL_MAP * currentChannelMap;
3283 
3284  targetContextMap->hContext = 0;
3285  (void)ClientCloseSession(targetContextMap->dwClientID);
3286  targetContextMap->dwClientID = 0;
3287  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3288 
3289  listSize = list_size(&targetContextMap->channelMapList);
3290  for (list_index = 0; list_index < listSize; list_index++)
3291  {
3292  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3293  list_index);
3294  if (NULL == currentChannelMap)
3295  {
3296  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3297  list_index);
3298  continue;
3299  }
3300  else
3301  {
3302  free(currentChannelMap->readerName);
3303  free(currentChannelMap);
3304  }
3305 
3306  }
3307  list_destroy(&targetContextMap->channelMapList);
3308 
3309  lrv = list_delete(&contextMapList, targetContextMap);
3310  if (lrv < 0)
3311  {
3312  Log2(PCSC_LOG_CRITICAL,
3313  "list_delete failed with return value: %d", lrv);
3314  }
3315 
3316  free(targetContextMap);
3317 
3318  return SCARD_S_SUCCESS;
3319 }
3320 
3321 /*
3322  * Functions for managing hCard values returned from SCardConnect.
3323  */
3324 
3325 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3326  LPCSTR readerName)
3327 {
3328  CHANNEL_MAP * newChannelMap;
3329  int lrv = -1;
3330 
3331  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3332  if (NULL == newChannelMap)
3333  return SCARD_E_NO_MEMORY;
3334 
3335  newChannelMap->hCard = hCard;
3336  newChannelMap->readerName = strdup(readerName);
3337 
3338  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3339  if (lrv < 0)
3340  {
3341  free(newChannelMap->readerName);
3342  free(newChannelMap);
3343  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3344  lrv);
3345  return SCARD_E_NO_MEMORY;
3346  }
3347 
3348  return SCARD_S_SUCCESS;
3349 }
3350 
3351 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3352 {
3353  SCONTEXTMAP * currentContextMap;
3354  CHANNEL_MAP * currentChannelMap;
3355  int lrv;
3356  LONG rv;
3357 
3358  rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3359  &currentChannelMap);
3360  if (rv == -1)
3361  return SCARD_E_INVALID_HANDLE;
3362 
3363  free(currentChannelMap->readerName);
3364 
3365  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3366  if (lrv < 0)
3367  {
3368  Log2(PCSC_LOG_CRITICAL,
3369  "list_delete failed with return value: %d", lrv);
3370  }
3371 
3372  free(currentChannelMap);
3373 
3374  return SCARD_S_SUCCESS;
3375 }
3376 
3377 static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3378  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3379 {
3380  LONG rv;
3381 
3382  if (0 == hCard)
3383  return -1;
3384 
3385  (void)SCardLockThread();
3386  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3387  targetChannelMap);
3388 
3389  if (SCARD_S_SUCCESS == rv)
3390  (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3391 
3392  (void)SCardUnlockThread();
3393 
3394  return rv;
3395 }
3396 
3397 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3398  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3399 {
3400  int listSize;
3401  int list_index;
3402  SCONTEXTMAP * currentContextMap;
3403  CHANNEL_MAP * currentChannelMap;
3404 
3405  /* Best to get the caller a crash early if we fail unsafely */
3406  *targetContextMap = NULL;
3407  *targetChannelMap = NULL;
3408 
3409  listSize = list_size(&contextMapList);
3410 
3411  for (list_index = 0; list_index < listSize; list_index++)
3412  {
3413  currentContextMap = list_get_at(&contextMapList, list_index);
3414  if (currentContextMap == NULL)
3415  {
3416  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3417  list_index);
3418  continue;
3419  }
3420  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3421  &hCard);
3422  if (currentChannelMap != NULL)
3423  {
3424  *targetContextMap = currentContextMap;
3425  *targetChannelMap = currentChannelMap;
3426  return SCARD_S_SUCCESS;
3427  }
3428  }
3429 
3430  return -1;
3431 }
3432 
3441 {
3442  LONG rv;
3443  struct stat statBuffer;
3444  char *socketName;
3445 
3446  socketName = getSocketName();
3447  rv = stat(socketName, &statBuffer);
3448 
3449  if (rv != 0)
3450  {
3451  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3452  socketName, strerror(errno));
3453  return SCARD_E_NO_SERVICE;
3454  }
3455 
3456  return SCARD_S_SUCCESS;
3457 }
3458 
3459 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3460 {
3461  int32_t dwClientID = currentContextMap->dwClientID;
3462  LONG rv;
3463 
3464  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3465  if (rv != SCARD_S_SUCCESS)
3466  return rv;
3467 
3468  /* Read a message from the server */
3469  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3470  if (rv != SCARD_S_SUCCESS)
3471  return rv;
3472 
3473  return SCARD_S_SUCCESS;
3474 }
3475 
used by SCardBeginTransaction()
Definition: winscard_msg.h:84
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:143
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:58
wait for a reader state change
Definition: winscard_msg.h:96
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:209
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:231
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:203
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:197
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:126
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:75
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:174
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:231
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:204
get the client/server protocol version
Definition: winscard_msg.h:94
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:200
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:191
PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:79
static short isExecuted
Make sure the initialization code is executed only once.
used by SCardEstablishContext()
Definition: winscard_msg.h:78
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:317
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:59
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:122
used by SCardEndTransaction()
Definition: winscard_msg.h:85
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:84
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:55
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:107
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:201
This handles abstract system level calls.
static LONG SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:132
uint32_t eventCounter
number of card events
Definition: eventhandler.h:53
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:150
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:81
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:49
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:176
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:174
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...
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:106
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:193
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:132
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:85
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:186
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:77
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:213
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:202
Represents the an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:120
get the readers state
Definition: winscard_msg.h:95
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:58
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:168
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:56
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:451
used by SCardReleaseContext()
Definition: winscard_msg.h:79
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:54
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:120
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:220
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:159
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:83
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:111
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:218
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:263
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:205
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:109
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:175
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:206
used by SCardReconnect()
Definition: winscard_msg.h:82
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:137
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:232
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:86
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:57
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:180
char cancellable
We are in a cancellable call.
stop waiting for a reader state change
Definition: winscard_msg.h:97
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:207
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:194
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:57
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:57
static LONG SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
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:119
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:51
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:87
This keeps a list of defines for pcsc-lite.
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:177
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:208
Protocol Control Information (PCI)
Definition: pcsclite.h:81
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_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:114
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:192
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:59
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:50
used by SCardSetAttrib()
Definition: winscard_msg.h:93
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:353
used by SCardDisconnect()
Definition: winscard_msg.h:83
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:109
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:248
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:92
pthread_mutex_t mMutex
Mutex for this context.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:54
used by SCardCancel()
Definition: winscard_msg.h:90
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:111
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:73
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:58
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_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:112
used by SCardStatus()
Definition: winscard_msg.h:88
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:103
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:195
This handles debugging.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:113
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:199
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:209