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