pcsc-lite  1.8.11
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 Changes to this license can be made only by the copyright author with
28 explicit written consent.
29 
30 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
31 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
34 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * $Id: winscard_clnt.c 6851 2014-02-14 15:43:32Z rousseau $
42  */
43 
104 #include "config.h"
105 #include <stdlib.h>
106 #include <string.h>
107 #include <sys/types.h>
108 #include <fcntl.h>
109 #include <unistd.h>
110 #include <sys/un.h>
111 #include <errno.h>
112 #include <stddef.h>
113 #include <sys/time.h>
114 #include <pthread.h>
115 #include <sys/wait.h>
116 
117 #include "misc.h"
118 #include "pcscd.h"
119 #include "winscard.h"
120 #include "debuglog.h"
121 #include "strlcpycat.h"
122 
123 #include "readerfactory.h"
124 #include "eventhandler.h"
125 #include "sys_generic.h"
126 #include "winscard_msg.h"
127 #include "utils.h"
128 
129 /* Display, on stderr, a trace of the WinSCard calls with arguments and
130  * results */
131 #undef DO_TRACE
132 
133 /* Profile the execution time of WinSCard calls */
134 #undef DO_PROFILE
135 
136 
138 #define SCARD_PROTOCOL_ANY_OLD 0x1000
139 
140 #ifndef TRUE
141 #define TRUE 1
142 #define FALSE 0
143 #endif
144 
145 static char sharing_shall_block = TRUE;
146 
147 #define COLOR_RED "\33[01;31m"
148 #define COLOR_GREEN "\33[32m"
149 #define COLOR_BLUE "\33[34m"
150 #define COLOR_MAGENTA "\33[35m"
151 #define COLOR_NORMAL "\33[0m"
152 
153 #ifdef DO_TRACE
154 
155 #include <stdio.h>
156 #include <stdarg.h>
157 
158 static void trace(const char *func, const char direction, const char *fmt, ...)
159 {
160  va_list args;
161 
162  fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163  direction, pthread_self(), func);
164 
165  fprintf(stderr, COLOR_MAGENTA);
166  va_start(args, fmt);
167  vfprintf(stderr, fmt, args);
168  va_end(args);
169 
170  fprintf(stderr, COLOR_NORMAL "\n");
171 }
172 
173 #define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174 #define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175 #else
176 #define API_TRACE_IN(...)
177 #define API_TRACE_OUT(...)
178 #endif
179 
180 #ifdef DO_PROFILE
181 
182 #define PROFILE_FILE "/tmp/pcsc_profile"
183 #include <stdio.h>
184 #include <sys/time.h>
185 
186 /* we can profile a maximum of 5 simultaneous calls */
187 #define MAX_THREADS 5
188 pthread_t threads[MAX_THREADS];
189 struct timeval profile_time_start[MAX_THREADS];
190 FILE *profile_fd;
191 char profile_tty;
192 
193 #define PROFILE_START profile_start();
194 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195 
196 static void profile_start(void)
197 {
198  static char initialized = FALSE;
199  pthread_t t;
200  int i;
201 
202  if (!initialized)
203  {
204  char filename[80];
205 
206  initialized = TRUE;
207  sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208  profile_fd = fopen(filename, "a+");
209  if (NULL == profile_fd)
210  {
211  fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212  PROFILE_FILE, strerror(errno));
213  exit(-1);
214  }
215  fprintf(profile_fd, "\nStart a new profile\n");
216 
217  if (isatty(fileno(stderr)))
218  profile_tty = TRUE;
219  else
220  profile_tty = FALSE;
221  }
222 
223  t = pthread_self();
224  for (i=0; i<MAX_THREADS; i++)
225  if (pthread_equal(0, threads[i]))
226  {
227  threads[i] = t;
228  break;
229  }
230 
231  gettimeofday(&profile_time_start[i], NULL);
232 } /* profile_start */
233 
234 static void profile_end(const char *f, LONG rv)
235 {
236  struct timeval profile_time_end;
237  long d;
238  pthread_t t;
239  int i;
240 
241  gettimeofday(&profile_time_end, NULL);
242 
243  t = pthread_self();
244  for (i=0; i<MAX_THREADS; i++)
245  if (pthread_equal(t, threads[i]))
246  break;
247 
248  if (i>=MAX_THREADS)
249  {
250  fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251  return;
252  }
253 
254  d = time_sub(&profile_time_end, &profile_time_start[i]);
255 
256  /* free this entry */
257  threads[i] = 0;
258 
259  if (profile_tty)
260  {
261  if (rv != SCARD_S_SUCCESS)
262  fprintf(stderr,
263  COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264  COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265  f, d, rv, pcsc_stringify_error(rv));
266  else
267  fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268  COLOR_NORMAL "\n", f, d);
269  }
270  fprintf(profile_fd, "%s %ld\n", f, d);
271  fflush(profile_fd);
272 } /* profile_end */
273 
274 #else
275 #define PROFILE_START
276 #define PROFILE_END(rv)
277 #endif
278 
284 {
285  SCARDHANDLE hCard;
286  LPSTR readerName;
287 };
288 
289 typedef struct _psChannelMap CHANNEL_MAP;
290 
291 static int CHANNEL_MAP_seeker(const void *el, const void *key)
292 {
293  const CHANNEL_MAP * channelMap = el;
294 
295  if ((el == NULL) || (key == NULL))
296  {
297  Log3(PCSC_LOG_CRITICAL,
298  "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299  el, key);
300  return 0;
301  }
302 
303  if (channelMap->hCard == *(SCARDHANDLE *)key)
304  return 1;
305 
306  return 0;
307 }
308 
315 {
316  DWORD dwClientID;
318  pthread_mutex_t mMutex;
319  list_t channelMapList;
320  char cancellable;
321 };
322 typedef struct _psContextMap SCONTEXTMAP;
323 
324 static list_t contextMapList;
325 
326 static int SCONTEXTMAP_seeker(const void *el, const void *key)
327 {
328  const SCONTEXTMAP * contextMap = el;
329 
330  if ((el == NULL) || (key == NULL))
331  {
332  Log3(PCSC_LOG_CRITICAL,
333  "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
334  el, key);
335  return 0;
336  }
337 
338  if (contextMap->hContext == *(SCARDCONTEXT *) key)
339  return 1;
340 
341  return 0;
342 }
343 
347 static short isExecuted = 0;
348 
349 
354 static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
355 
360 
367 
368 
369 static LONG SCardAddContext(SCARDCONTEXT, DWORD);
372 static LONG SCardRemoveContext(SCARDCONTEXT);
373 static LONG SCardCleanContext(SCONTEXTMAP *);
374 
375 static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
376 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE,
377  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
378 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
379  /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380 static LONG SCardRemoveHandle(SCARDHANDLE);
381 
382 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
383  LPBYTE pbAttr, LPDWORD pcbAttrLen);
384 
385 static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
386 
387 /*
388  * Thread safety functions
389  */
396 inline static LONG SCardLockThread(void)
397 {
398  return pthread_mutex_lock(&clientMutex);
399 }
400 
406 inline static LONG SCardUnlockThread(void)
407 {
408  return pthread_mutex_unlock(&clientMutex);
409 }
410 
411 static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
412  /*@out@*/ LPSCARDCONTEXT);
413 
447 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
448  LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
449 {
450  LONG rv;
451 
452  API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
453  PROFILE_START
454 
455  /* Check if the server is running */
457  if (SCARD_E_INVALID_HANDLE == rv)
458  /* we reconnected to a daemon or we got called from a forked child */
460 
461  if (rv != SCARD_S_SUCCESS)
462  goto end;
463 
464  (void)SCardLockThread();
465  rv = SCardEstablishContextTH(dwScope, pvReserved1,
466  pvReserved2, phContext);
467  (void)SCardUnlockThread();
468 
469 end:
470  PROFILE_END(rv)
471  API_TRACE_OUT("%ld", *phContext)
472 
473  return rv;
474 }
475 
502 static LONG SCardEstablishContextTH(DWORD dwScope,
503  /*@unused@*/ LPCVOID pvReserved1,
504  /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
505 {
506  LONG rv;
507  struct establish_struct scEstablishStruct;
508  uint32_t dwClientID = 0;
509 
510  (void)pvReserved1;
511  (void)pvReserved2;
512  if (phContext == NULL)
514  else
515  *phContext = 0;
516 
517  /*
518  * Do this only once:
519  * - Initialize context list.
520  */
521  if (isExecuted == 0)
522  {
523  int lrv;
524 
525  /* NOTE: The list will never be freed (No API call exists to
526  * "close all contexts".
527  * Applications which load and unload the library will leak
528  * the list's internal structures. */
529  lrv = list_init(&contextMapList);
530  if (lrv < 0)
531  {
532  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
533  lrv);
534  return SCARD_E_NO_MEMORY;
535  }
536 
537  lrv = list_attributes_seeker(&contextMapList,
538  SCONTEXTMAP_seeker);
539  if (lrv <0)
540  {
541  Log2(PCSC_LOG_CRITICAL,
542  "list_attributes_seeker failed with return value: %d", lrv);
543  list_destroy(&contextMapList);
544  return SCARD_E_NO_MEMORY;
545  }
546 
547  if (getenv("PCSCLITE_NO_BLOCKING"))
548  {
549  Log1(PCSC_LOG_INFO, "Disable shared blocking");
550  sharing_shall_block = FALSE;
551  }
552 
553  isExecuted = 1;
554  }
555 
556 
557  /* Establishes a connection to the server */
558  if (ClientSetupSession(&dwClientID) != 0)
559  {
560  return SCARD_E_NO_SERVICE;
561  }
562 
563  { /* exchange client/server protocol versions */
564  struct version_struct veStr;
565 
568  veStr.rv = SCARD_S_SUCCESS;
569 
570  rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
571  &veStr);
572  if (rv != SCARD_S_SUCCESS)
573  return rv;
574 
575  /* Read a message from the server */
576  rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
577  if (rv != SCARD_S_SUCCESS)
578  {
579  Log1(PCSC_LOG_CRITICAL,
580  "Your pcscd is too old and does not support CMD_VERSION");
581  return SCARD_F_COMM_ERROR;
582  }
583 
584  Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
585  veStr.major, veStr.minor);
586 
587  if (veStr.rv != SCARD_S_SUCCESS)
588  return veStr.rv;
589  }
590 
591 again:
592  /*
593  * Try to establish an Application Context with the server
594  */
595  scEstablishStruct.dwScope = dwScope;
596  scEstablishStruct.hContext = 0;
597  scEstablishStruct.rv = SCARD_S_SUCCESS;
598 
600  sizeof(scEstablishStruct), (void *) &scEstablishStruct);
601 
602  if (rv != SCARD_S_SUCCESS)
603  return rv;
604 
605  /*
606  * Read the response from the server
607  */
608  rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
609  dwClientID);
610 
611  if (rv != SCARD_S_SUCCESS)
612  return rv;
613 
614  if (scEstablishStruct.rv != SCARD_S_SUCCESS)
615  return scEstablishStruct.rv;
616 
617  /* check we do not reuse an existing hContext */
618  if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
619  /* we do not need to release the allocated context since
620  * SCardReleaseContext() does nothing on the server side */
621  goto again;
622 
623  *phContext = scEstablishStruct.hContext;
624 
625  /*
626  * Allocate the new hContext - if allocator full return an error
627  */
628  rv = SCardAddContext(*phContext, dwClientID);
629 
630  return rv;
631 }
632 
655 {
656  LONG rv;
657  struct release_struct scReleaseStruct;
658  SCONTEXTMAP * currentContextMap;
659 
660  API_TRACE_IN("%ld", hContext)
661  PROFILE_START
662 
663  /*
664  * Make sure this context has been opened
665  * and get currentContextMap
666  */
667  currentContextMap = SCardGetContext(hContext);
668  if (NULL == currentContextMap)
669  {
671  goto error;
672  }
673 
674  (void)pthread_mutex_lock(&currentContextMap->mMutex);
675 
676  /* check the context is still opened */
677  currentContextMap = SCardGetContext(hContext);
678  if (NULL == currentContextMap)
679  /* the hContext context is now invalid
680  * -> another thread may have called SCardReleaseContext
681  * so the mMutex has been unlocked */
682  {
684  goto error;
685  }
686 
687  scReleaseStruct.hContext = hContext;
688  scReleaseStruct.rv = SCARD_S_SUCCESS;
689 
691  currentContextMap->dwClientID,
692  sizeof(scReleaseStruct), (void *) &scReleaseStruct);
693 
694  if (rv != SCARD_S_SUCCESS)
695  goto end;
696 
697  /*
698  * Read a message from the server
699  */
700  rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
701  currentContextMap->dwClientID);
702 
703  if (rv != SCARD_S_SUCCESS)
704  goto end;
705 
706  rv = scReleaseStruct.rv;
707 end:
708  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
709 
710  /*
711  * Remove the local context from the stack
712  */
713  (void)SCardLockThread();
714  (void)SCardRemoveContext(hContext);
715  (void)SCardUnlockThread();
716 
717 error:
718  PROFILE_END(rv)
719  API_TRACE_OUT("")
720 
721  return rv;
722 }
723 
780 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
781  DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
782  LPDWORD pdwActiveProtocol)
783 {
784  LONG rv;
785  struct connect_struct scConnectStruct;
786  SCONTEXTMAP * currentContextMap;
787 
788  PROFILE_START
789  API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
790 
791  /*
792  * Check for NULL parameters
793  */
794  if (phCard == NULL || pdwActiveProtocol == NULL)
796  else
797  *phCard = 0;
798 
799  if (szReader == NULL)
800  return SCARD_E_UNKNOWN_READER;
801 
802  /*
803  * Check for uninitialized strings
804  */
805  if (strlen(szReader) > MAX_READERNAME)
806  return SCARD_E_INVALID_VALUE;
807 
808  /*
809  * Make sure this context has been opened
810  */
811  currentContextMap = SCardGetContext(hContext);
812  if (NULL == currentContextMap)
813  return SCARD_E_INVALID_HANDLE;
814 
815  (void)pthread_mutex_lock(&currentContextMap->mMutex);
816 
817  /* check the context is still opened */
818  currentContextMap = SCardGetContext(hContext);
819  if (NULL == currentContextMap)
820  /* the hContext context is now invalid
821  * -> another thread may have called SCardReleaseContext
822  * so the mMutex has been unlocked */
823  return SCARD_E_INVALID_HANDLE;
824 
825  strlcpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
826 
827  scConnectStruct.hContext = hContext;
828  scConnectStruct.dwShareMode = dwShareMode;
829  scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
830  scConnectStruct.hCard = 0;
831  scConnectStruct.dwActiveProtocol = 0;
832  scConnectStruct.rv = SCARD_S_SUCCESS;
833 
834  rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
835  sizeof(scConnectStruct), (void *) &scConnectStruct);
836 
837  if (rv != SCARD_S_SUCCESS)
838  goto end;
839 
840  /*
841  * Read a message from the server
842  */
843  rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
844  currentContextMap->dwClientID);
845 
846  if (rv != SCARD_S_SUCCESS)
847  goto end;
848 
849  *phCard = scConnectStruct.hCard;
850  *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
851 
852  if (scConnectStruct.rv == SCARD_S_SUCCESS)
853  {
854  /*
855  * Keep track of the handle locally
856  */
857  rv = SCardAddHandle(*phCard, currentContextMap, szReader);
858  }
859  else
860  rv = scConnectStruct.rv;
861 
862 end:
863  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
864 
865  PROFILE_END(rv)
866  API_TRACE_OUT("%d", *pdwActiveProtocol)
867 
868  return rv;
869 }
870 
944 LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
945  DWORD dwPreferredProtocols, DWORD dwInitialization,
946  LPDWORD pdwActiveProtocol)
947 {
948  LONG rv;
949  struct reconnect_struct scReconnectStruct;
950  SCONTEXTMAP * currentContextMap;
951  CHANNEL_MAP * pChannelMap;
952 
953  PROFILE_START
954 
955  if (pdwActiveProtocol == NULL)
957 
958  /*
959  * Make sure this handle has been opened
960  */
961  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
962  &pChannelMap);
963  if (rv == -1)
964  return SCARD_E_INVALID_HANDLE;
965 
966  /* Retry loop for blocking behaviour */
967 retry:
968 
969  (void)pthread_mutex_lock(&currentContextMap->mMutex);
970 
971  /* check the handle is still valid */
972  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
973  &pChannelMap);
974  if (rv == -1)
975  {
976  /* the hCard handle is now invalid
977  * -> another thread may have called SCardReleaseContext
978  * so the mMutex has been unlocked (and is now invalid)
979  * -> another thread may have called SCardDisconnect
980  * so the mMutex is STILL locked
981  * since we don't know just unlock the mutex */
982  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
983  return SCARD_E_INVALID_HANDLE;
984  }
985 
986  scReconnectStruct.hCard = hCard;
987  scReconnectStruct.dwShareMode = dwShareMode;
988  scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
989  scReconnectStruct.dwInitialization = dwInitialization;
990  scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
991  scReconnectStruct.rv = SCARD_S_SUCCESS;
992 
993  rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
994  sizeof(scReconnectStruct), (void *) &scReconnectStruct);
995 
996  if (rv != SCARD_S_SUCCESS)
997  goto end;
998 
999  /*
1000  * Read a message from the server
1001  */
1002  rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1003  currentContextMap->dwClientID);
1004 
1005  if (rv != SCARD_S_SUCCESS)
1006  goto end;
1007 
1008  rv = scReconnectStruct.rv;
1009 
1010  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1011  {
1012  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1014  goto retry;
1015  }
1016 
1017  *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1018 
1019 end:
1020  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1021 
1022  PROFILE_END(rv)
1023 
1024  return rv;
1025 }
1026 
1058 LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1059 {
1060  LONG rv;
1061  struct disconnect_struct scDisconnectStruct;
1062  SCONTEXTMAP * currentContextMap;
1063  CHANNEL_MAP * pChannelMap;
1064 
1065  PROFILE_START
1066  API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1067 
1068  /*
1069  * Make sure this handle has been opened
1070  */
1071  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1072  &pChannelMap);
1073  if (rv == -1)
1074  {
1076  goto error;
1077  }
1078 
1079  (void)pthread_mutex_lock(&currentContextMap->mMutex);
1080 
1081  /* check the handle is still valid */
1082  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1083  &pChannelMap);
1084  if (rv == -1)
1085  /* the hCard handle is now invalid
1086  * -> another thread may have called SCardReleaseContext
1087  * so the mMutex has been unlocked (and is now invalid)
1088  * -> another thread may have called SCardDisconnect
1089  * so the mMutex is STILL locked
1090  * since we don't know just unlock the mutex */
1091  {
1092  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1094  goto error;
1095  }
1096 
1097  scDisconnectStruct.hCard = hCard;
1098  scDisconnectStruct.dwDisposition = dwDisposition;
1099  scDisconnectStruct.rv = SCARD_S_SUCCESS;
1100 
1101  rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1102  sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1103 
1104  if (rv != SCARD_S_SUCCESS)
1105  goto end;
1106 
1107  /*
1108  * Read a message from the server
1109  */
1110  rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1111  currentContextMap->dwClientID);
1112 
1113  if (rv != SCARD_S_SUCCESS)
1114  goto end;
1115 
1116  if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1117  (void)SCardRemoveHandle(hCard);
1118  rv = scDisconnectStruct.rv;
1119 
1120 end:
1121  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1122 
1123 error:
1124  PROFILE_END(rv)
1125  API_TRACE_OUT("")
1126 
1127  return rv;
1128 }
1129 
1166 {
1167 
1168  LONG rv;
1169  struct begin_struct scBeginStruct;
1170  SCONTEXTMAP * currentContextMap;
1171  CHANNEL_MAP * pChannelMap;
1172 
1173  PROFILE_START
1174 
1175  /*
1176  * Make sure this handle has been opened
1177  */
1178  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1179  &pChannelMap);
1180  if (rv == -1)
1181  return SCARD_E_INVALID_HANDLE;
1182 
1183  /*
1184  * Query the server every so often until the sharing violation ends
1185  * and then hold the lock for yourself.
1186  */
1187 
1188  for(;;)
1189  {
1190  (void)pthread_mutex_lock(&currentContextMap->mMutex);
1191 
1192  /* check the handle is still valid */
1193  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1194  &pChannelMap);
1195  if (rv == -1)
1196  {
1197  /* the hCard handle is now invalid
1198  * -> another thread may have called SCardReleaseContext
1199  * so the mMutex has been unlocked (and is now invalid)
1200  * -> another thread may have called SCardDisconnect
1201  * so the mMutex is STILL locked
1202  * since we don't know just unlock the mutex */
1203  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1204  return SCARD_E_INVALID_HANDLE;
1205  }
1206 
1207  scBeginStruct.hCard = hCard;
1208  scBeginStruct.rv = SCARD_S_SUCCESS;
1209 
1211  currentContextMap->dwClientID,
1212  sizeof(scBeginStruct), (void *) &scBeginStruct);
1213 
1214  if (rv != SCARD_S_SUCCESS)
1215  break;
1216 
1217  /*
1218  * Read a message from the server
1219  */
1220  rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1221  currentContextMap->dwClientID);
1222 
1223  if (rv != SCARD_S_SUCCESS)
1224  break;
1225 
1226  rv = scBeginStruct.rv;
1227 
1228  if (SCARD_E_SHARING_VIOLATION != rv)
1229  break;
1230 
1231  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1233  }
1234 
1235  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1236 
1237  PROFILE_END(rv)
1238 
1239  return rv;
1240 }
1241 
1282 LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1283 {
1284  LONG rv;
1285  struct end_struct scEndStruct;
1286  int randnum;
1287  SCONTEXTMAP * currentContextMap;
1288  CHANNEL_MAP * pChannelMap;
1289 
1290  PROFILE_START
1291 
1292  /*
1293  * Make sure this handle has been opened
1294  */
1295  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1296  &pChannelMap);
1297  if (rv == -1)
1298  return SCARD_E_INVALID_HANDLE;
1299 
1300  (void)pthread_mutex_lock(&currentContextMap->mMutex);
1301 
1302  /* check the handle is still valid */
1303  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1304  &pChannelMap);
1305  if (rv == -1)
1306  {
1307  /* the hCard handle is now invalid
1308  * -> another thread may have called SCardReleaseContext
1309  * so the mMutex has been unlocked (and is now invalid)
1310  * -> another thread may have called SCardDisconnect
1311  * so the mMutex is STILL locked
1312  * since we don't know just unlock the mutex */
1313  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1314  return SCARD_E_INVALID_HANDLE;
1315  }
1316 
1317  scEndStruct.hCard = hCard;
1318  scEndStruct.dwDisposition = dwDisposition;
1319  scEndStruct.rv = SCARD_S_SUCCESS;
1320 
1322  currentContextMap->dwClientID,
1323  sizeof(scEndStruct), (void *) &scEndStruct);
1324 
1325  if (rv != SCARD_S_SUCCESS)
1326  goto end;
1327 
1328  /*
1329  * Read a message from the server
1330  */
1331  rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1332  currentContextMap->dwClientID);
1333 
1334  if (rv != SCARD_S_SUCCESS)
1335  goto end;
1336 
1337  /*
1338  * This helps prevent starvation
1339  */
1340  randnum = SYS_RandomInt(1000, 10000);
1341  (void)SYS_USleep(randnum);
1342  rv = scEndStruct.rv;
1343 
1344 end:
1345  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1346 
1347  PROFILE_END(rv)
1348 
1349  return rv;
1350 }
1351 
1447 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,
1448  LPDWORD pcchReaderLen, LPDWORD pdwState,
1449  LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1450 {
1451  DWORD dwReaderLen, dwAtrLen;
1452  LONG rv;
1453  int i;
1454  struct status_struct scStatusStruct;
1455  SCONTEXTMAP * currentContextMap;
1456  CHANNEL_MAP * pChannelMap;
1457  char *r;
1458  char *bufReader = NULL;
1459  LPBYTE bufAtr = NULL;
1460  DWORD dummy = 0;
1461 
1462  PROFILE_START
1463 
1464  /* default output values */
1465  if (pdwState)
1466  *pdwState = 0;
1467 
1468  if (pdwProtocol)
1469  *pdwProtocol = 0;
1470 
1471  /* Check for NULL parameters */
1472  if (pcchReaderLen == NULL)
1473  pcchReaderLen = &dummy;
1474 
1475  if (pcbAtrLen == NULL)
1476  pcbAtrLen = &dummy;
1477 
1478  /* length passed from caller */
1479  dwReaderLen = *pcchReaderLen;
1480  dwAtrLen = *pcbAtrLen;
1481 
1482  *pcchReaderLen = 0;
1483  *pcbAtrLen = 0;
1484 
1485  /*
1486  * Make sure this handle has been opened
1487  */
1488  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1489  &pChannelMap);
1490  if (rv == -1)
1491  return SCARD_E_INVALID_HANDLE;
1492 
1493  /* Retry loop for blocking behaviour */
1494 retry:
1495 
1496  (void)pthread_mutex_lock(&currentContextMap->mMutex);
1497 
1498  /* check the handle is still valid */
1499  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
1500  &pChannelMap);
1501  if (rv == -1)
1502  {
1503  /* the hCard handle is now invalid
1504  * -> another thread may have called SCardReleaseContext
1505  * so the mMutex has been unlocked (and is now invalid)
1506  * -> another thread may have called SCardDisconnect
1507  * so the mMutex is STILL locked
1508  * since we don't know just unlock the mutex */
1509  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1510  return SCARD_E_INVALID_HANDLE;
1511  }
1512 
1513  /* synchronize reader states with daemon */
1514  rv = getReaderStates(currentContextMap);
1515  if (rv != SCARD_S_SUCCESS)
1516  goto end;
1517 
1518  r = pChannelMap->readerName;
1519  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1520  {
1521  /* by default r == NULL */
1522  if (r && strcmp(r, readerStates[i].readerName) == 0)
1523  break;
1524  }
1525 
1526  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1527  {
1529  goto end;
1530  }
1531 
1532  /* initialise the structure */
1533  memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1534  scStatusStruct.hCard = hCard;
1535 
1536  rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1537  sizeof(scStatusStruct), (void *) &scStatusStruct);
1538 
1539  if (rv != SCARD_S_SUCCESS)
1540  goto end;
1541 
1542  /*
1543  * Read a message from the server
1544  */
1545  rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1546  currentContextMap->dwClientID);
1547 
1548  if (rv != SCARD_S_SUCCESS)
1549  goto end;
1550 
1551  rv = scStatusStruct.rv;
1552 
1553  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1554  {
1555  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1557  goto retry;
1558  }
1559 
1560  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1561  {
1562  /*
1563  * An event must have occurred
1564  */
1565  goto end;
1566  }
1567 
1568  /*
1569  * Now continue with the client side SCardStatus
1570  */
1571 
1572  *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1573  *pcbAtrLen = readerStates[i].cardAtrLength;
1574 
1575  if (pdwState)
1576  *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1577 
1578  if (pdwProtocol)
1579  *pdwProtocol = readerStates[i].cardProtocol;
1580 
1581  if (SCARD_AUTOALLOCATE == dwReaderLen)
1582  {
1583  dwReaderLen = *pcchReaderLen;
1584  if (NULL == mszReaderName)
1585  {
1587  goto end;
1588  }
1589  bufReader = malloc(dwReaderLen);
1590  if (NULL == bufReader)
1591  {
1592  rv = SCARD_E_NO_MEMORY;
1593  goto end;
1594  }
1595  *(char **)mszReaderName = bufReader;
1596  }
1597  else
1598  bufReader = mszReaderName;
1599 
1600  /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1601  if (bufReader)
1602  {
1603  if (*pcchReaderLen > dwReaderLen)
1605 
1606  strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1607  }
1608 
1609  if (SCARD_AUTOALLOCATE == dwAtrLen)
1610  {
1611  dwAtrLen = *pcbAtrLen;
1612  if (NULL == pbAtr)
1613  {
1615  goto end;
1616  }
1617  bufAtr = malloc(dwAtrLen);
1618  if (NULL == bufAtr)
1619  {
1620  rv = SCARD_E_NO_MEMORY;
1621  goto end;
1622  }
1623  *(LPBYTE *)pbAtr = bufAtr;
1624  }
1625  else
1626  bufAtr = pbAtr;
1627 
1628  if (bufAtr)
1629  {
1630  if (*pcbAtrLen > dwAtrLen)
1632 
1633  memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1634  }
1635 
1636 end:
1637  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1638 
1639  PROFILE_END(rv)
1640 
1641  return rv;
1642 }
1643 
1737 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1738  SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1739 {
1740  SCARD_READERSTATE *currReader;
1741  READER_STATE *rContext;
1742  long dwTime;
1743  DWORD dwBreakFlag = 0;
1744  unsigned int j;
1745  SCONTEXTMAP * currentContextMap;
1746  int currentReaderCount = 0;
1747  LONG rv = SCARD_S_SUCCESS;
1748 
1749  PROFILE_START
1750  API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1751 #ifdef DO_TRACE
1752  for (j=0; j<cReaders; j++)
1753  {
1754  API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1755  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1756  }
1757 #endif
1758 
1759  if ((rgReaderStates == NULL && cReaders > 0)
1760  || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1761  {
1763  goto error;
1764  }
1765 
1766  /* Check the integrity of the reader states structures */
1767  for (j = 0; j < cReaders; j++)
1768  {
1769  if (rgReaderStates[j].szReader == NULL)
1770  return SCARD_E_INVALID_VALUE;
1771  }
1772 
1773  /* return if all readers are SCARD_STATE_IGNORE */
1774  if (cReaders > 0)
1775  {
1776  int nbNonIgnoredReaders = cReaders;
1777 
1778  for (j=0; j<cReaders; j++)
1779  if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1780  nbNonIgnoredReaders--;
1781 
1782  if (0 == nbNonIgnoredReaders)
1783  {
1784  rv = SCARD_S_SUCCESS;
1785  goto error;
1786  }
1787  }
1788  else
1789  {
1790  /* reader list is empty */
1791  rv = SCARD_S_SUCCESS;
1792  goto error;
1793  }
1794 
1795  /*
1796  * Make sure this context has been opened
1797  */
1798  currentContextMap = SCardGetContext(hContext);
1799  if (NULL == currentContextMap)
1800  {
1802  goto error;
1803  }
1804 
1805  (void)pthread_mutex_lock(&currentContextMap->mMutex);
1806 
1807  /* check the context is still opened */
1808  currentContextMap = SCardGetContext(hContext);
1809  if (NULL == currentContextMap)
1810  /* the hContext context is now invalid
1811  * -> another thread may have called SCardReleaseContext
1812  * so the mMutex has been unlocked */
1813  {
1815  goto error;
1816  }
1817 
1818  /* synchronize reader states with daemon */
1819  rv = getReaderStates(currentContextMap);
1820  if (rv != SCARD_S_SUCCESS)
1821  goto end;
1822 
1823  /* check all the readers are already known */
1824  for (j=0; j<cReaders; j++)
1825  {
1826  const char *readerName;
1827  int i;
1828 
1829  readerName = rgReaderStates[j].szReader;
1830  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1831  {
1832  if (strcmp(readerName, readerStates[i].readerName) == 0)
1833  break;
1834  }
1835 
1836  /* The requested reader name is not recognized */
1837  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1838  {
1839  /* PnP special reader? */
1840  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1841  {
1843  goto end;
1844  }
1845  }
1846  }
1847 
1848  /* Clear the event state for all readers */
1849  for (j = 0; j < cReaders; j++)
1850  rgReaderStates[j].dwEventState = 0;
1851 
1852  /* Now is where we start our event checking loop */
1853  Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1854 
1855  /* Get the initial reader count on the system */
1856  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1857  if (readerStates[j].readerName[0] != '\0')
1858  currentReaderCount++;
1859 
1860  /* catch possible sign extension problems from 32 to 64-bits integers */
1861  if ((DWORD)-1 == dwTimeout)
1862  dwTimeout = INFINITE;
1863  if (INFINITE == dwTimeout)
1864  dwTime = 60*1000; /* "infinite" timeout */
1865  else
1866  dwTime = dwTimeout;
1867 
1868  j = 0;
1869  do
1870  {
1871  currReader = &rgReaderStates[j];
1872 
1873  /* Ignore for IGNORED readers */
1874  if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1875  {
1876  const char *readerName;
1877  int i;
1878 
1879  /* Looks for correct readernames */
1880  readerName = currReader->szReader;
1881  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1882  {
1883  if (strcmp(readerName, readerStates[i].readerName) == 0)
1884  break;
1885  }
1886 
1887  /* The requested reader name is not recognized */
1888  if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1889  {
1890  /* PnP special reader? */
1891  if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1892  {
1893  int k, newReaderCount = 0;
1894 
1895  for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1896  if (readerStates[k].readerName[0] != '\0')
1897  newReaderCount++;
1898 
1899  if (newReaderCount != currentReaderCount)
1900  {
1901  Log1(PCSC_LOG_INFO, "Reader list changed");
1902  currentReaderCount = newReaderCount;
1903 
1904  currReader->dwEventState |= SCARD_STATE_CHANGED;
1905  dwBreakFlag = 1;
1906  }
1907  }
1908  else
1909  {
1910  currReader->dwEventState =
1912  if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1913  {
1914  currReader->dwEventState |= SCARD_STATE_CHANGED;
1915  /*
1916  * Spec says use SCARD_STATE_IGNORE but a removed USB
1917  * reader with eventState fed into currentState will
1918  * be ignored forever
1919  */
1920  dwBreakFlag = 1;
1921  }
1922  }
1923  }
1924  else
1925  {
1926  uint32_t readerState;
1927 
1928  /* The reader has come back after being away */
1929  if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1930  {
1931  currReader->dwEventState |= SCARD_STATE_CHANGED;
1932  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1933  Log0(PCSC_LOG_DEBUG);
1934  dwBreakFlag = 1;
1935  }
1936 
1937  /* Set the reader status structure */
1938  rContext = &readerStates[i];
1939 
1940  /* Now we check all the Reader States */
1941  readerState = rContext->readerState;
1942 
1943  /* only if current state has an non null event counter */
1944  if (currReader->dwCurrentState & 0xFFFF0000)
1945  {
1946  unsigned int currentCounter;
1947 
1948  currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1949 
1950  /* has the event counter changed since the last call? */
1951  if (rContext->eventCounter != currentCounter)
1952  {
1953  currReader->dwEventState |= SCARD_STATE_CHANGED;
1954  Log0(PCSC_LOG_DEBUG);
1955  dwBreakFlag = 1;
1956  }
1957  }
1958 
1959  /* add an event counter in the upper word of dwEventState */
1960  currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1961  | (rContext->eventCounter << 16));
1962 
1963  /* Check if the reader is in the correct state */
1964  if (readerState & SCARD_UNKNOWN)
1965  {
1966  /* reader is in bad state */
1967  currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1968  if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1969  {
1970  /* App thinks reader is in good state and it is not */
1971  currReader->dwEventState |= SCARD_STATE_CHANGED;
1972  Log0(PCSC_LOG_DEBUG);
1973  dwBreakFlag = 1;
1974  }
1975  }
1976  else
1977  {
1978  /* App thinks reader in bad state but it is not */
1979  if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1980  {
1981  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1982  currReader->dwEventState |= SCARD_STATE_CHANGED;
1983  Log0(PCSC_LOG_DEBUG);
1984  dwBreakFlag = 1;
1985  }
1986  }
1987 
1988  /* Check for card presence in the reader */
1989  if (readerState & SCARD_PRESENT)
1990  {
1991  /* card present but not yet powered up */
1992  if (0 == rContext->cardAtrLength)
1993  /* Allow the status thread to convey information */
1995 
1996  currReader->cbAtr = rContext->cardAtrLength;
1997  memcpy(currReader->rgbAtr, rContext->cardAtr,
1998  currReader->cbAtr);
1999  }
2000  else
2001  currReader->cbAtr = 0;
2002 
2003  /* Card is now absent */
2004  if (readerState & SCARD_ABSENT)
2005  {
2006  currReader->dwEventState |= SCARD_STATE_EMPTY;
2007  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
2008  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2009  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2010  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2011  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2012  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
2013  currReader->dwEventState &= ~SCARD_STATE_MUTE;
2014  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2015 
2016  /* After present the rest are assumed */
2017  if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
2018  {
2019  currReader->dwEventState |= SCARD_STATE_CHANGED;
2020  Log0(PCSC_LOG_DEBUG);
2021  dwBreakFlag = 1;
2022  }
2023  }
2024  /* Card is now present */
2025  else if (readerState & SCARD_PRESENT)
2026  {
2027  currReader->dwEventState |= SCARD_STATE_PRESENT;
2028  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2029  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2030  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2031  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2032  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2033  currReader->dwEventState &= ~SCARD_STATE_MUTE;
2034 
2035  if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
2036  {
2037  currReader->dwEventState |= SCARD_STATE_CHANGED;
2038  Log0(PCSC_LOG_DEBUG);
2039  dwBreakFlag = 1;
2040  }
2041 
2042  if (readerState & SCARD_SWALLOWED)
2043  {
2044  currReader->dwEventState |= SCARD_STATE_MUTE;
2045  if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
2046  {
2047  currReader->dwEventState |= SCARD_STATE_CHANGED;
2048  Log0(PCSC_LOG_DEBUG);
2049  dwBreakFlag = 1;
2050  }
2051  }
2052  else
2053  {
2054  /* App thinks card is mute but it is not */
2055  if (currReader->dwCurrentState & SCARD_STATE_MUTE)
2056  {
2057  currReader->dwEventState |= SCARD_STATE_CHANGED;
2058  Log0(PCSC_LOG_DEBUG);
2059  dwBreakFlag = 1;
2060  }
2061  }
2062  }
2063 
2064  /* Now figure out sharing modes */
2066  {
2067  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2068  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2069  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2070  {
2071  currReader->dwEventState |= SCARD_STATE_CHANGED;
2072  Log0(PCSC_LOG_DEBUG);
2073  dwBreakFlag = 1;
2074  }
2075  }
2076  else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2077  {
2078  /* A card must be inserted for it to be INUSE */
2079  if (readerState & SCARD_PRESENT)
2080  {
2081  currReader->dwEventState |= SCARD_STATE_INUSE;
2082  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2083  if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2084  {
2085  currReader->dwEventState |= SCARD_STATE_CHANGED;
2086  Log0(PCSC_LOG_DEBUG);
2087  dwBreakFlag = 1;
2088  }
2089  }
2090  }
2091  else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2092  {
2093  currReader->dwEventState &= ~SCARD_STATE_INUSE;
2094  currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2095 
2096  if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2097  {
2098  currReader->dwEventState |= SCARD_STATE_CHANGED;
2099  Log0(PCSC_LOG_DEBUG);
2100  dwBreakFlag = 1;
2101  }
2102  else if (currReader-> dwCurrentState
2104  {
2105  currReader->dwEventState |= SCARD_STATE_CHANGED;
2106  Log0(PCSC_LOG_DEBUG);
2107  dwBreakFlag = 1;
2108  }
2109  }
2110 
2111  if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2112  {
2113  /*
2114  * Break out of the while .. loop and return status
2115  * once all the status's for all readers is met
2116  */
2117  currReader->dwEventState |= SCARD_STATE_CHANGED;
2118  Log0(PCSC_LOG_DEBUG);
2119  dwBreakFlag = 1;
2120  }
2121  } /* End of SCARD_STATE_UNKNOWN */
2122  } /* End of SCARD_STATE_IGNORE */
2123 
2124  /* Counter and resetter */
2125  j++;
2126  if (j == cReaders)
2127  {
2128  /* go back to the first reader */
2129  j = 0;
2130 
2131  /* Declare all the break conditions */
2132 
2133  /* Break if UNAWARE is set and all readers have been checked */
2134  if (dwBreakFlag == 1)
2135  break;
2136 
2137  /* Only sleep once for each cycle of reader checks. */
2138  {
2139  struct wait_reader_state_change waitStatusStruct;
2140  struct timeval before, after;
2141 
2142  gettimeofday(&before, NULL);
2143 
2144  waitStatusStruct.timeOut = dwTime;
2145  waitStatusStruct.rv = SCARD_S_SUCCESS;
2146 
2147  /* another thread can do SCardCancel() */
2148  currentContextMap->cancellable = TRUE;
2149 
2151  currentContextMap->dwClientID,
2152  sizeof(waitStatusStruct), &waitStatusStruct);
2153 
2154  if (rv != SCARD_S_SUCCESS)
2155  goto end;
2156 
2157  /*
2158  * Read a message from the server
2159  */
2161  &waitStatusStruct, sizeof(waitStatusStruct),
2162  currentContextMap->dwClientID, dwTime);
2163 
2164  /* another thread can do SCardCancel() */
2165  currentContextMap->cancellable = FALSE;
2166 
2167  /* timeout */
2168  if (SCARD_E_TIMEOUT == rv)
2169  {
2170  /* ask server to remove us from the event list */
2172  currentContextMap->dwClientID,
2173  sizeof(waitStatusStruct), &waitStatusStruct);
2174 
2175  if (rv != SCARD_S_SUCCESS)
2176  goto end;
2177 
2178  /* Read a message from the server */
2179  rv = MessageReceive(&waitStatusStruct,
2180  sizeof(waitStatusStruct),
2181  currentContextMap->dwClientID);
2182 
2183  if (rv != SCARD_S_SUCCESS)
2184  goto end;
2185  }
2186 
2187  if (rv != SCARD_S_SUCCESS)
2188  goto end;
2189 
2190  /* an event occurs or SCardCancel() was called */
2191  if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2192  {
2193  rv = waitStatusStruct.rv;
2194  goto end;
2195  }
2196 
2197  /* synchronize reader states with daemon */
2198  rv = getReaderStates(currentContextMap);
2199  if (rv != SCARD_S_SUCCESS)
2200  goto end;
2201 
2202  if (INFINITE != dwTimeout)
2203  {
2204  long int diff;
2205 
2206  gettimeofday(&after, NULL);
2207  diff = time_sub(&after, &before);
2208  dwTime -= diff/1000;
2209  }
2210  }
2211 
2212  if (dwTimeout != INFINITE)
2213  {
2214  /* If time is greater than timeout and all readers have been
2215  * checked
2216  */
2217  if (dwTime <= 0)
2218  {
2219  rv = SCARD_E_TIMEOUT;
2220  goto end;
2221  }
2222  }
2223  }
2224  }
2225  while (1);
2226 
2227 end:
2228  Log1(PCSC_LOG_DEBUG, "Event Loop End");
2229 
2230  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2231 
2232 error:
2233  PROFILE_END(rv)
2234 #ifdef DO_TRACE
2235  for (j=0; j<cReaders; j++)
2236  {
2237  API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2238  rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2239  }
2240 #endif
2241 
2242  return rv;
2243 }
2244 
2295 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2296  DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2297  LPDWORD lpBytesReturned)
2298 {
2299  LONG rv;
2300  struct control_struct scControlStruct;
2301  SCONTEXTMAP * currentContextMap;
2302  CHANNEL_MAP * pChannelMap;
2303 
2304  PROFILE_START
2305 
2306  /* 0 bytes received by default */
2307  if (NULL != lpBytesReturned)
2308  *lpBytesReturned = 0;
2309 
2310  /*
2311  * Make sure this handle has been opened
2312  */
2313  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2314  &pChannelMap);
2315  if (rv == -1)
2316  {
2317  PROFILE_END(SCARD_E_INVALID_HANDLE)
2318  return SCARD_E_INVALID_HANDLE;
2319  }
2320 
2321  (void)pthread_mutex_lock(&currentContextMap->mMutex);
2322 
2323  /* check the handle is still valid */
2324  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2325  &pChannelMap);
2326  if (rv == -1)
2327  {
2328  /* the hCard handle is now invalid
2329  * -> another thread may have called SCardReleaseContext
2330  * so the mMutex has been unlocked (and is now invalid)
2331  * -> another thread may have called SCardDisconnect
2332  * so the mMutex is STILL locked
2333  * since we don't know just unlock the mutex */
2334  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2335  return SCARD_E_INVALID_HANDLE;
2336  }
2337 
2338  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2339  || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2340  {
2342  goto end;
2343  }
2344 
2345  scControlStruct.hCard = hCard;
2346  scControlStruct.dwControlCode = dwControlCode;
2347  scControlStruct.cbSendLength = cbSendLength;
2348  scControlStruct.cbRecvLength = cbRecvLength;
2349  scControlStruct.dwBytesReturned = 0;
2350  scControlStruct.rv = 0;
2351 
2352  rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2353  sizeof(scControlStruct), &scControlStruct);
2354 
2355  if (rv != SCARD_S_SUCCESS)
2356  goto end;
2357 
2358  /* write the sent buffer */
2359  rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2360  currentContextMap->dwClientID);
2361 
2362  if (rv != SCARD_S_SUCCESS)
2363  goto end;
2364 
2365  /*
2366  * Read a message from the server
2367  */
2368  rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2369  currentContextMap->dwClientID);
2370 
2371  if (rv != SCARD_S_SUCCESS)
2372  goto end;
2373 
2374  if (SCARD_S_SUCCESS == scControlStruct.rv)
2375  {
2376  /* read the received buffer */
2377  rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2378  currentContextMap->dwClientID);
2379 
2380  if (rv != SCARD_S_SUCCESS)
2381  goto end;
2382 
2383  }
2384 
2385  if (NULL != lpBytesReturned)
2386  *lpBytesReturned = scControlStruct.dwBytesReturned;
2387 
2388  rv = scControlStruct.rv;
2389 
2390 end:
2391  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2392 
2393  PROFILE_END(rv)
2394 
2395  return rv;
2396 }
2397 
2502 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2503  LPDWORD pcbAttrLen)
2504 {
2505  LONG ret;
2506  unsigned char *buf = NULL;
2507 
2508  PROFILE_START
2509 
2510  if (NULL == pcbAttrLen)
2511  {
2513  goto end;
2514  }
2515 
2516  if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2517  {
2518  if (NULL == pbAttr)
2520 
2521  *pcbAttrLen = MAX_BUFFER_SIZE;
2522  buf = malloc(*pcbAttrLen);
2523  if (NULL == buf)
2524  {
2525  ret = SCARD_E_NO_MEMORY;
2526  goto end;
2527  }
2528 
2529  *(unsigned char **)pbAttr = buf;
2530  }
2531  else
2532  {
2533  buf = pbAttr;
2534 
2535  /* if only get the length */
2536  if (NULL == pbAttr)
2537  /* use a reasonable size */
2538  *pcbAttrLen = MAX_BUFFER_SIZE;
2539  }
2540 
2541  ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2542  pcbAttrLen);
2543 
2544 end:
2545  PROFILE_END(ret)
2546 
2547  return ret;
2548 }
2549 
2585 LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2586  DWORD cbAttrLen)
2587 {
2588  LONG ret;
2589 
2590  PROFILE_START
2591 
2592  if (NULL == pbAttr || 0 == cbAttrLen)
2594 
2595  ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2596  &cbAttrLen);
2597 
2598  PROFILE_END(ret)
2599 
2600  return ret;
2601 }
2602 
2603 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2604  LPBYTE pbAttr, LPDWORD pcbAttrLen)
2605 {
2606  LONG rv;
2607  struct getset_struct scGetSetStruct;
2608  SCONTEXTMAP * currentContextMap;
2609  CHANNEL_MAP * pChannelMap;
2610 
2611  /*
2612  * Make sure this handle has been opened
2613  */
2614  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2615  &pChannelMap);
2616  if (rv == -1)
2617  return SCARD_E_INVALID_HANDLE;
2618 
2619  (void)pthread_mutex_lock(&currentContextMap->mMutex);
2620 
2621  /* check the handle is still valid */
2622  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2623  &pChannelMap);
2624  if (rv == -1)
2625  {
2626  /* the hCard handle is now invalid
2627  * -> another thread may have called SCardReleaseContext
2628  * so the mMutex has been unlocked (and is now invalid)
2629  * -> another thread may have called SCardDisconnect
2630  * so the mMutex is STILL locked
2631  * since we don't know just unlock the mutex */
2632  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2633  return SCARD_E_INVALID_HANDLE;
2634  }
2635 
2636  if (*pcbAttrLen > MAX_BUFFER_SIZE)
2637  {
2639  goto end;
2640  }
2641 
2642  scGetSetStruct.hCard = hCard;
2643  scGetSetStruct.dwAttrId = dwAttrId;
2644  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2645  scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2646  memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2647  if (SCARD_SET_ATTRIB == command)
2648  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2649 
2650  rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2651  sizeof(scGetSetStruct), &scGetSetStruct);
2652 
2653  if (rv != SCARD_S_SUCCESS)
2654  goto end;
2655 
2656  /*
2657  * Read a message from the server
2658  */
2659  rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2660  currentContextMap->dwClientID);
2661 
2662  if (rv != SCARD_S_SUCCESS)
2663  goto end;
2664 
2665  if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2666  {
2667  /*
2668  * Copy and zero it so any secret information is not leaked
2669  */
2670  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2671  {
2672  scGetSetStruct.cbAttrLen = *pcbAttrLen;
2673  scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2674  }
2675  else
2676  *pcbAttrLen = scGetSetStruct.cbAttrLen;
2677 
2678  if (pbAttr)
2679  memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2680 
2681  memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2682  }
2683  rv = scGetSetStruct.rv;
2684 
2685 end:
2686  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2687 
2688  return rv;
2689 }
2690 
2749 LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2750  LPCBYTE pbSendBuffer, DWORD cbSendLength,
2751  SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2752  LPDWORD pcbRecvLength)
2753 {
2754  LONG rv;
2755  SCONTEXTMAP * currentContextMap;
2756  CHANNEL_MAP * pChannelMap;
2757  struct transmit_struct scTransmitStruct;
2758 
2759  PROFILE_START
2760 
2761  if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2762  pcbRecvLength == NULL || pioSendPci == NULL)
2764 
2765  /*
2766  * Make sure this handle has been opened
2767  */
2768  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2769  &pChannelMap);
2770  if (rv == -1)
2771  {
2772  *pcbRecvLength = 0;
2773  PROFILE_END(SCARD_E_INVALID_HANDLE)
2774  return SCARD_E_INVALID_HANDLE;
2775  }
2776 
2777  /* Retry loop for blocking behaviour */
2778 retry:
2779 
2780  (void)pthread_mutex_lock(&currentContextMap->mMutex);
2781 
2782  /* check the handle is still valid */
2783  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
2784  &pChannelMap);
2785  if (rv == -1)
2786  {
2787  /* the hCard handle is now invalid
2788  * -> another thread may have called SCardReleaseContext
2789  * so the mMutex has been unlocked (and is now invalid)
2790  * -> another thread may have called SCardDisconnect
2791  * so the mMutex is STILL locked
2792  * since we don't know just unlock the mutex */
2793  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2794  return SCARD_E_INVALID_HANDLE;
2795  }
2796 
2797  if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2798  || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2799  {
2801  goto end;
2802  }
2803 
2804  scTransmitStruct.hCard = hCard;
2805  scTransmitStruct.cbSendLength = cbSendLength;
2806  scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2807  scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2808  scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2809  scTransmitStruct.rv = SCARD_S_SUCCESS;
2810 
2811  if (pioRecvPci)
2812  {
2813  scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2814  scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2815  }
2816  else
2817  {
2818  scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2819  scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2820  }
2821 
2822  rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2823  sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2824 
2825  if (rv != SCARD_S_SUCCESS)
2826  goto end;
2827 
2828  /* write the sent buffer */
2829  rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2830  currentContextMap->dwClientID);
2831 
2832  if (rv != SCARD_S_SUCCESS)
2833  goto end;
2834 
2835  /*
2836  * Read a message from the server
2837  */
2838  rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2839  currentContextMap->dwClientID);
2840 
2841  if (rv != SCARD_S_SUCCESS)
2842  goto end;
2843 
2844  if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2845  {
2846  /* read the received buffer */
2847  rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2848  currentContextMap->dwClientID);
2849 
2850  if (rv != SCARD_S_SUCCESS)
2851  goto end;
2852 
2853  if (pioRecvPci)
2854  {
2855  pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2856  pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2857  }
2858  }
2859 
2860  rv = scTransmitStruct.rv;
2861 
2862  if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2863  {
2864  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2866  goto retry;
2867  }
2868 
2869  *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2870 
2871 end:
2872  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2873 
2874  PROFILE_END(rv)
2875 
2876  return rv;
2877 }
2878 
2929 LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2930  LPSTR mszReaders, LPDWORD pcchReaders)
2931 {
2932  DWORD dwReadersLen = 0;
2933  int i;
2934  SCONTEXTMAP * currentContextMap;
2935  LONG rv = SCARD_S_SUCCESS;
2936  char *buf = NULL;
2937 
2938  (void)mszGroups;
2939  PROFILE_START
2940  API_TRACE_IN("%ld", hContext)
2941 
2942  /*
2943  * Check for NULL parameters
2944  */
2945  if (pcchReaders == NULL)
2947 
2948  /*
2949  * Make sure this context has been opened
2950  */
2951  currentContextMap = SCardGetContext(hContext);
2952  if (NULL == currentContextMap)
2953  {
2954  PROFILE_END(SCARD_E_INVALID_HANDLE)
2955  return SCARD_E_INVALID_HANDLE;
2956  }
2957 
2958  (void)pthread_mutex_lock(&currentContextMap->mMutex);
2959 
2960  /* check the context is still opened */
2961  currentContextMap = SCardGetContext(hContext);
2962  if (NULL == currentContextMap)
2963  /* the hContext context is now invalid
2964  * -> another thread may have called SCardReleaseContext
2965  * -> so the mMutex has been unlocked */
2966  return SCARD_E_INVALID_HANDLE;
2967 
2968  /* synchronize reader states with daemon */
2969  rv = getReaderStates(currentContextMap);
2970  if (rv != SCARD_S_SUCCESS)
2971  goto end;
2972 
2973  dwReadersLen = 0;
2974  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2975  if (readerStates[i].readerName[0] != '\0')
2976  dwReadersLen += strlen(readerStates[i].readerName) + 1;
2977 
2978  /* for the last NULL byte */
2979  dwReadersLen += 1;
2980 
2981  if (1 == dwReadersLen)
2982  {
2984  goto end;
2985  }
2986 
2987  if (SCARD_AUTOALLOCATE == *pcchReaders)
2988  {
2989  if (NULL == mszReaders)
2990  {
2992  goto end;
2993  }
2994  buf = malloc(dwReadersLen);
2995  if (NULL == buf)
2996  {
2997  rv = SCARD_E_NO_MEMORY;
2998  goto end;
2999  }
3000  *(char **)mszReaders = buf;
3001  }
3002  else
3003  {
3004  buf = mszReaders;
3005 
3006  /* not enough place to store the reader names */
3007  if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3008  {
3010  goto end;
3011  }
3012  }
3013 
3014  if (mszReaders == NULL) /* text array not allocated */
3015  goto end;
3016 
3017  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
3018  {
3019  if (readerStates[i].readerName[0] != '\0')
3020  {
3021  /*
3022  * Build the multi-string
3023  */
3024  strcpy(buf, readerStates[i].readerName);
3025  buf += strlen(readerStates[i].readerName)+1;
3026  }
3027  }
3028  *buf = '\0'; /* Add the last null */
3029 
3030 end:
3031  /* set the reader names length */
3032  *pcchReaders = dwReadersLen;
3033 
3034  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3035 
3036  PROFILE_END(rv)
3037  API_TRACE_OUT("%d", *pcchReaders)
3038 
3039  return rv;
3040 }
3041 
3055 LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
3056 {
3057  LONG rv = SCARD_S_SUCCESS;
3058  SCONTEXTMAP * currentContextMap;
3059 
3060  PROFILE_START
3061 
3062  /*
3063  * Make sure this context has been opened
3064  */
3065  currentContextMap = SCardGetContext(hContext);
3066  if (NULL == currentContextMap)
3067  return SCARD_E_INVALID_HANDLE;
3068 
3069  free((void *)pvMem);
3070 
3071  PROFILE_END(rv)
3072 
3073  return rv;
3074 }
3075 
3127 LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3128  LPDWORD pcchGroups)
3129 {
3130  LONG rv = SCARD_S_SUCCESS;
3131  SCONTEXTMAP * currentContextMap;
3132  char *buf = NULL;
3133 
3134  PROFILE_START
3135 
3136  /* Multi-string with two trailing \0 */
3137  const char ReaderGroup[] = "SCard$DefaultReaders\0";
3138  const unsigned int dwGroups = sizeof(ReaderGroup);
3139 
3140  /*
3141  * Make sure this context has been opened
3142  */
3143  currentContextMap = SCardGetContext(hContext);
3144  if (NULL == currentContextMap)
3145  return SCARD_E_INVALID_HANDLE;
3146 
3147  (void)pthread_mutex_lock(&currentContextMap->mMutex);
3148 
3149  /* check the context is still opened */
3150  currentContextMap = SCardGetContext(hContext);
3151  if (NULL == currentContextMap)
3152  /* the hContext context is now invalid
3153  * -> another thread may have called SCardReleaseContext
3154  * -> so the mMutex has been unlocked */
3155  return SCARD_E_INVALID_HANDLE;
3156 
3157  if (SCARD_AUTOALLOCATE == *pcchGroups)
3158  {
3159  if (NULL == mszGroups)
3160  {
3162  goto end;
3163  }
3164  buf = malloc(dwGroups);
3165  if (NULL == buf)
3166  {
3167  rv = SCARD_E_NO_MEMORY;
3168  goto end;
3169  }
3170  *(char **)mszGroups = buf;
3171  }
3172  else
3173  {
3174  buf = mszGroups;
3175 
3176  if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3177  {
3179  goto end;
3180  }
3181  }
3182 
3183  if (buf)
3184  memcpy(buf, ReaderGroup, dwGroups);
3185 
3186 end:
3187  *pcchGroups = dwGroups;
3188 
3189  (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3190 
3191  PROFILE_END(rv)
3192 
3193  return rv;
3194 }
3195 
3226 {
3227  SCONTEXTMAP * currentContextMap;
3228  LONG rv = SCARD_S_SUCCESS;
3229  uint32_t dwClientID = 0;
3230  struct cancel_struct scCancelStruct;
3231 
3232  PROFILE_START
3233  API_TRACE_IN("%ld", hContext)
3234 
3235  /*
3236  * Make sure this context has been opened
3237  */
3238  currentContextMap = SCardGetContext(hContext);
3239  if (NULL == currentContextMap)
3240  {
3242  goto error;
3243  }
3244 
3245  if (! currentContextMap->cancellable)
3246  {
3247  rv = SCARD_S_SUCCESS;
3248  goto error;
3249  }
3250 
3251  /* create a new connection to the server */
3252  if (ClientSetupSession(&dwClientID) != 0)
3253  {
3254  rv = SCARD_E_NO_SERVICE;
3255  goto error;
3256  }
3257 
3258  scCancelStruct.hContext = hContext;
3259  scCancelStruct.rv = SCARD_S_SUCCESS;
3260 
3261  rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3262  sizeof(scCancelStruct), (void *) &scCancelStruct);
3263 
3264  if (rv != SCARD_S_SUCCESS)
3265  goto end;
3266 
3267  /*
3268  * Read a message from the server
3269  */
3270  rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3271 
3272  if (rv != SCARD_S_SUCCESS)
3273  goto end;
3274 
3275  rv = scCancelStruct.rv;
3276 end:
3277  ClientCloseSession(dwClientID);
3278 
3279 error:
3280  PROFILE_END(rv)
3281  API_TRACE_OUT("")
3282 
3283  return rv;
3284 }
3285 
3310 {
3311  LONG rv;
3312  SCONTEXTMAP * currentContextMap;
3313 
3314  PROFILE_START
3315  API_TRACE_IN("%ld", hContext)
3316 
3317  rv = SCARD_S_SUCCESS;
3318 
3319  /*
3320  * Make sure this context has been opened
3321  */
3322  currentContextMap = SCardGetContext(hContext);
3323  if (currentContextMap == NULL)
3325 
3326  PROFILE_END(rv)
3327  API_TRACE_OUT("")
3328 
3329  return rv;
3330 }
3331 
3348 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3349 {
3350  int lrv;
3351  SCONTEXTMAP * newContextMap;
3352 
3353  newContextMap = malloc(sizeof(SCONTEXTMAP));
3354  if (NULL == newContextMap)
3355  return SCARD_E_NO_MEMORY;
3356 
3357  Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3358  newContextMap->hContext = hContext;
3359  newContextMap->dwClientID = dwClientID;
3360  newContextMap->cancellable = FALSE;
3361 
3362  (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3363 
3364  lrv = list_init(&newContextMap->channelMapList);
3365  if (lrv < 0)
3366  {
3367  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3368  goto error;
3369  }
3370 
3371  lrv = list_attributes_seeker(&newContextMap->channelMapList,
3372  CHANNEL_MAP_seeker);
3373  if (lrv <0)
3374  {
3375  Log2(PCSC_LOG_CRITICAL,
3376  "list_attributes_seeker failed with return value: %d", lrv);
3377  list_destroy(&newContextMap->channelMapList);
3378  goto error;
3379  }
3380 
3381  lrv = list_append(&contextMapList, newContextMap);
3382  if (lrv < 0)
3383  {
3384  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3385  lrv);
3386  list_destroy(&newContextMap->channelMapList);
3387  goto error;
3388  }
3389 
3390  return SCARD_S_SUCCESS;
3391 
3392 error:
3393 
3394  (void)pthread_mutex_destroy(&newContextMap->mMutex);
3395  free(newContextMap);
3396 
3397  return SCARD_E_NO_MEMORY;
3398 }
3399 
3413 {
3414  SCONTEXTMAP * currentContextMap;
3415 
3416  (void)SCardLockThread();
3417  currentContextMap = SCardGetContextTH(hContext);
3418  (void)SCardUnlockThread();
3419 
3420  return currentContextMap;
3421 }
3422 
3436 {
3437  return list_seek(&contextMapList, &hContext);
3438 }
3439 
3449 static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3450 {
3451  SCONTEXTMAP * currentContextMap;
3452  currentContextMap = SCardGetContextTH(hContext);
3453 
3454  if (NULL == currentContextMap)
3455  return SCARD_E_INVALID_HANDLE;
3456  else
3457  return SCardCleanContext(currentContextMap);
3458 }
3459 
3460 static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
3461 {
3462  int list_index, lrv;
3463  int listSize;
3464  CHANNEL_MAP * currentChannelMap;
3465 
3466  targetContextMap->hContext = 0;
3467  (void)ClientCloseSession(targetContextMap->dwClientID);
3468  targetContextMap->dwClientID = 0;
3469  (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3470 
3471  listSize = list_size(&targetContextMap->channelMapList);
3472  for (list_index = 0; list_index < listSize; list_index++)
3473  {
3474  currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3475  list_index);
3476  if (NULL == currentChannelMap)
3477  {
3478  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3479  list_index);
3480  continue;
3481  }
3482  else
3483  {
3484  free(currentChannelMap->readerName);
3485  free(currentChannelMap);
3486  }
3487 
3488  }
3489  list_destroy(&targetContextMap->channelMapList);
3490 
3491  lrv = list_delete(&contextMapList, targetContextMap);
3492  if (lrv < 0)
3493  {
3494  Log2(PCSC_LOG_CRITICAL,
3495  "list_delete failed with return value: %d", lrv);
3496  }
3497 
3498  free(targetContextMap);
3499 
3500  return SCARD_S_SUCCESS;
3501 }
3502 
3503 /*
3504  * Functions for managing hCard values returned from SCardConnect.
3505  */
3506 
3507 static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3508  LPCSTR readerName)
3509 {
3510  CHANNEL_MAP * newChannelMap;
3511  int lrv = -1;
3512 
3513  newChannelMap = malloc(sizeof(CHANNEL_MAP));
3514  if (NULL == newChannelMap)
3515  return SCARD_E_NO_MEMORY;
3516 
3517  newChannelMap->hCard = hCard;
3518  newChannelMap->readerName = strdup(readerName);
3519 
3520  lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3521  if (lrv < 0)
3522  {
3523  free(newChannelMap->readerName);
3524  free(newChannelMap);
3525  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3526  lrv);
3527  return SCARD_E_NO_MEMORY;
3528  }
3529 
3530  return SCARD_S_SUCCESS;
3531 }
3532 
3533 static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3534 {
3535  SCONTEXTMAP * currentContextMap;
3536  CHANNEL_MAP * currentChannelMap;
3537  int lrv;
3538  LONG rv;
3539 
3540  rv = SCardGetContextAndChannelFromHandle(hCard, &currentContextMap,
3541  &currentChannelMap);
3542  if (rv == -1)
3543  return SCARD_E_INVALID_HANDLE;
3544 
3545  free(currentChannelMap->readerName);
3546 
3547  lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3548  if (lrv < 0)
3549  {
3550  Log2(PCSC_LOG_CRITICAL,
3551  "list_delete failed with return value: %d", lrv);
3552  }
3553 
3554  free(currentChannelMap);
3555 
3556  return SCARD_S_SUCCESS;
3557 }
3558 
3559 static LONG SCardGetContextAndChannelFromHandle(SCARDHANDLE hCard,
3560  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3561 {
3562  LONG rv;
3563 
3564  if (0 == hCard)
3565  return -1;
3566 
3567  (void)SCardLockThread();
3568  rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3569  targetChannelMap);
3570  (void)SCardUnlockThread();
3571 
3572  return rv;
3573 }
3574 
3575 static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3576  SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3577 {
3578  int listSize;
3579  int list_index;
3580  SCONTEXTMAP * currentContextMap;
3581  CHANNEL_MAP * currentChannelMap;
3582 
3583  /* Best to get the caller a crash early if we fail unsafely */
3584  *targetContextMap = NULL;
3585  *targetChannelMap = NULL;
3586 
3587  listSize = list_size(&contextMapList);
3588 
3589  for (list_index = 0; list_index < listSize; list_index++)
3590  {
3591  currentContextMap = list_get_at(&contextMapList, list_index);
3592  if (currentContextMap == NULL)
3593  {
3594  Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3595  list_index);
3596  continue;
3597  }
3598  currentChannelMap = list_seek(&currentContextMap->channelMapList,
3599  &hCard);
3600  if (currentChannelMap != NULL)
3601  {
3602  *targetContextMap = currentContextMap;
3603  *targetChannelMap = currentChannelMap;
3604  return SCARD_S_SUCCESS;
3605  }
3606  }
3607 
3608  return -1;
3609 }
3610 
3623 {
3624  LONG rv;
3625  struct stat statBuffer;
3626  char *socketName;
3627 
3628  socketName = getSocketName();
3629  rv = stat(socketName, &statBuffer);
3630 
3631  if (rv != 0)
3632  {
3633  Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3634  socketName, strerror(errno));
3635  return SCARD_E_NO_SERVICE;
3636  }
3637 
3638  return SCARD_S_SUCCESS;
3639 }
3640 
3641 static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3642 {
3643  int32_t dwClientID = currentContextMap->dwClientID;
3644  LONG rv;
3645 
3646  rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3647  if (rv != SCARD_S_SUCCESS)
3648  return rv;
3649 
3650  /* Read a message from the server */
3651  rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3652  if (rv != SCARD_S_SUCCESS)
3653  return rv;
3654 
3655  return SCARD_S_SUCCESS;
3656 }
3657 
used by SCardBeginTransaction()
Definition: winscard_msg.h:87
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:146
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:61
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:99
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:212
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:234
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:206
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:200
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:129
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:78
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:171
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:234
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:207
get the client/server protocol version
Definition: winscard_msg.h:97
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:203
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:194
PCSC_API char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:82
static short isExecuted
Make sure the initialization code is executed only once.
used by SCardEstablishContext()
Definition: winscard_msg.h:81
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:314
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:62
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:125
used by SCardEndTransaction()
Definition: winscard_msg.h:88
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:87
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:58
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:110
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:204
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:135
uint32_t eventCounter
number of card events
Definition: eventhandler.h:56
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:153
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:84
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:179
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:177
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:109
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:196
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:135
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:88
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:189
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:80
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:216
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:205
Represents the an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:123
get the readers state
Definition: winscard_msg.h:98
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:35
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:171
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:59
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:448
used by SCardReleaseContext()
Definition: winscard_msg.h:82
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:57
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:123
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:223
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:162
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:86
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:114
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:221
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:266
prototypes of strlcpy()/strlcat() imported from OpenBSD
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:208
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:112
DWORD dwClientID
Client Connection ID.
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:178
#define SCARD_STATE_ATRMATCH
ATR matches card.
Definition: pcsclite.h:209
used by SCardReconnect()
Definition: winscard_msg.h:85
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:140
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:235
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:89
#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:183
char cancellable
We are in a cancellable call.
stop waiting for a reader state change
Definition: winscard_msg.h:100
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:210
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:197
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:60
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:60
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:116
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:54
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:90
This keeps a list of defines for pcsc-lite.
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:180
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:211
Protocol Control Information (PCI)
Definition: pcsclite.h:84
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:117
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:195
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:62
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:53
used by SCardSetAttrib()
Definition: winscard_msg.h:96
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:350
used by SCardDisconnect()
Definition: winscard_msg.h:86
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:112
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:251
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:95
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
pthread_mutex_t mMutex
Mutex for this context.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:57
used by SCardCancel()
Definition: winscard_msg.h:93
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:114
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:76
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:61
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:115
used by SCardStatus()
Definition: winscard_msg.h:91
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:106
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:192
This handles debugging.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:116
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:202
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:212