pcsc-lite  1.8.6
winscard_svc.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@linuxnet.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2002-2011
9  * Ludovic Rousseau <ludovic.rousseau@free.fr>
10  * Copyright (C) 2009
11  * Jean-Luc Giraud <jlgiraud@googlemail.com>
12  *
13  * $Id: winscard_svc.c 6444 2012-08-24 08:10:23Z rousseau $
14  */
15 
26 #include "config.h"
27 #include <time.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <pthread.h>
34 
35 #include "pcscd.h"
36 #include "winscard.h"
37 #include "debuglog.h"
38 #include "winscard_msg.h"
39 #include "winscard_svc.h"
40 #include "sys_generic.h"
41 #include "utils.h"
42 #include "readerfactory.h"
43 #include "eventhandler.h"
44 #include "simclist.h"
45 
52 extern char AutoExit;
53 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
54 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
55 
57 pthread_mutex_t contextsList_lock;
59 struct _psContext
60 {
61  int32_t hContext;
62  list_t cardsList;
63  pthread_mutex_t cardsList_lock;
64  uint32_t dwClientID;
65  pthread_t pthThread;
66 };
67 typedef struct _psContext SCONTEXT;
68 
69 static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *);
70 static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *);
71 static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *);
72 static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *);
73 static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *);
74 static LONG MSGCleanupClient(SCONTEXT *);
75 
76 static void ContextThread(LPVOID pdwIndex);
77 
79 
80 static int contextsListhContext_seeker(const void *el, const void *key)
81 {
82  const SCONTEXT * currentContext = (SCONTEXT *)el;
83 
84  if ((el == NULL) || (key == NULL))
85  {
86  Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%p, key=%p",
87  el, key);
88  return 0;
89  }
90 
91  if (currentContext->hContext == *(int32_t *)key)
92  return 1;
93  return 0;
94 }
95 
96 LONG ContextsInitialize(int customMaxThreadCounter,
97  int customMaxThreadCardHandles)
98 {
99  int lrv = 0;
100 
101  if (customMaxThreadCounter != 0)
102  contextMaxThreadCounter = customMaxThreadCounter;
103 
104  if (customMaxThreadCardHandles != 0)
105  contextMaxCardHandles = customMaxThreadCardHandles;
106 
107  lrv = list_init(&contextsList);
108  if (lrv < 0)
109  {
110  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
111  return -1;
112  }
113  lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
114  if (lrv < 0)
115  {
116  Log2(PCSC_LOG_CRITICAL,
117  "list_attributes_seeker failed with return value: %d", lrv);
118  return -1;
119  }
120 
121  (void)pthread_mutex_init(&contextsList_lock, NULL);
122 
123  return 1;
124 }
125 
126 void ContextsDeinitialize(void)
127 {
128  int listSize;
129  listSize = list_size(&contextsList);
130  Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize);
131  /* This is currently a no-op. It should terminate the threads properly. */
132 }
133 
144 LONG CreateContextThread(uint32_t *pdwClientID)
145 {
146  int rv;
147  int lrv;
148  int listSize;
149  SCONTEXT * newContext = NULL;
150  LONG retval = SCARD_E_NO_MEMORY;
151 
152  (void)pthread_mutex_lock(&contextsList_lock);
153 
154  listSize = list_size(&contextsList);
155  if (listSize >= contextMaxThreadCounter)
156  {
157  Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
158  goto out;
159  }
160 
161  /* Create the context for this thread. */
162  newContext = malloc(sizeof(*newContext));
163  if (NULL == newContext)
164  {
165  Log1(PCSC_LOG_CRITICAL, "Could not allocate new context");
166  goto out;
167  }
168  memset(newContext, 0, sizeof(*newContext));
169 
170  newContext->dwClientID = *pdwClientID;
171 
172  /* Initialise the list of card contexts */
173  lrv = list_init(&newContext->cardsList);
174  if (lrv < 0)
175  {
176  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
177  goto out;
178  }
179 
180  /* request to store copies, and provide the metric function */
181  list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
182 
183  /* Adding a comparator
184  * The stored type is SCARDHANDLE (long) but has only 32 bits
185  * usefull even on a 64-bit CPU since the API between pcscd and
186  * libpcscliter uses "int32_t hCard;"
187  */
188  lrv = list_attributes_comparator(&newContext->cardsList,
189  list_comparator_int32_t);
190  if (lrv != 0)
191  {
192  Log2(PCSC_LOG_CRITICAL,
193  "list_attributes_comparator failed with return value: %d", lrv);
194  list_destroy(&newContext->cardsList);
195  goto out;
196  }
197 
198  (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
199 
200  lrv = list_append(&contextsList, newContext);
201  if (lrv < 0)
202  {
203  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
204  lrv);
205  list_destroy(&newContext->cardsList);
206  goto out;
207  }
208 
209  rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED,
210  (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
211  if (rv)
212  {
213  int lrv2;
214 
215  Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
216  lrv2 = list_delete(&contextsList, newContext);
217  if (lrv2 < 0)
218  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
219  list_destroy(&newContext->cardsList);
220  goto out;
221  }
222 
223  /* disable any suicide alarm */
224  if (AutoExit)
225  alarm(0);
226 
227  retval = SCARD_S_SUCCESS;
228 
229 out:
230  (void)pthread_mutex_unlock(&contextsList_lock);
231 
232  if (retval != SCARD_S_SUCCESS)
233  {
234  if (newContext)
235  free(newContext);
236  (void)close(*pdwClientID);
237  }
238 
239  return retval;
240 }
241 
242 /*
243  * A list of local functions used to keep track of clients and their
244  * connections
245  */
246 
255 #ifndef NO_LOG
256 static const char *CommandsText[] = {
257  "NULL",
258  "ESTABLISH_CONTEXT", /* 0x01 */
259  "RELEASE_CONTEXT",
260  "LIST_READERS",
261  "CONNECT",
262  "RECONNECT", /* 0x05 */
263  "DISCONNECT",
264  "BEGIN_TRANSACTION",
265  "END_TRANSACTION",
266  "TRANSMIT",
267  "CONTROL", /* 0x0A */
268  "STATUS",
269  "GET_STATUS_CHANGE",
270  "CANCEL",
271  "CANCEL_TRANSACTION",
272  "GET_ATTRIB", /* 0x0F */
273  "SET_ATTRIB",
274  "CMD_VERSION",
275  "CMD_GET_READERS_STATE",
276  "CMD_WAIT_READER_STATE_CHANGE",
277  "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
278  "NULL"
279 };
280 #endif
281 
282 #define READ_BODY(v) \
283  if (header.size != sizeof(v)) { goto wrong_length; } \
284  ret = MessageReceive(&v, sizeof(v), filedes); \
285  if (ret != SCARD_S_SUCCESS) { Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); goto exit; }
286 
287 #define WRITE_BODY(v) \
288  WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
289 #define WRITE_BODY_WITH_COMMAND(command, v) \
290  Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
291  ret = MessageSend(&v, sizeof(v), filedes);
292 
293 static void ContextThread(LPVOID newContext)
294 {
295  SCONTEXT * threadContext = (SCONTEXT *) newContext;
296  int32_t filedes = threadContext->dwClientID;
297 
298  Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
299  threadContext->dwClientID, threadContext);
300 
301  while (1)
302  {
303  struct rxHeader header;
304  int32_t ret = MessageReceive(&header, sizeof(header), filedes);
305 
306  if (ret != SCARD_S_SUCCESS)
307  {
308  /* Clean up the dead client */
309  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
311  goto exit;
312  }
313 
314  if ((header.command > CMD_ENUM_FIRST)
315  && (header.command < CMD_ENUM_LAST))
316  Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
317  CommandsText[header.command], filedes);
318 
319  switch (header.command)
320  {
321  /* pcsc-lite client/server protocol version */
322  case CMD_VERSION:
323  {
324  struct version_struct veStr;
325 
326  READ_BODY(veStr)
327 
328  Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
329  veStr.major, veStr.minor);
330 
331  veStr.rv = SCARD_S_SUCCESS;
332 
333  /* client and server use different protocol */
334  if ((veStr.major != PROTOCOL_VERSION_MAJOR)
335  || (veStr.minor != PROTOCOL_VERSION_MINOR))
336  {
337  Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d",
338  veStr.major, veStr.minor);
339  Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d",
340  PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
341  veStr.rv = SCARD_E_NO_SERVICE;
342  }
343 
344  /* set the server protocol version */
345  veStr.major = PROTOCOL_VERSION_MAJOR;
346  veStr.minor = PROTOCOL_VERSION_MINOR;
347 
348  /* send back the response */
349  WRITE_BODY(veStr)
350  }
351  break;
352 
354  {
355  /* nothing to read */
356 
357 #ifdef USE_USB
358  /* wait until all readers are ready */
359  RFWaitForReaderInit();
360 #endif
361 
362  /* dump the readers state */
363  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
364  }
365  break;
366 
368  {
369  struct wait_reader_state_change waStr;
370 
371  READ_BODY(waStr)
372 
373  /* add the client fd to the list */
374  EHRegisterClientForEvent(filedes);
375 
376  /* We do not send anything here.
377  * Either the client will timeout or the server will
378  * answer if an event occurs */
379  }
380  break;
381 
383  {
384  struct wait_reader_state_change waStr;
385 
386  READ_BODY(waStr)
387 
388  /* add the client fd to the list */
389  waStr.rv = EHUnregisterClientForEvent(filedes);
390 
391  WRITE_BODY(waStr)
392  }
393  break;
394 
396  {
397  struct establish_struct esStr;
398  SCARDCONTEXT hContext;
399 
400  READ_BODY(esStr)
401 
402  hContext = esStr.hContext;
403  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
404  &hContext);
405  esStr.hContext = hContext;
406 
407  if (esStr.rv == SCARD_S_SUCCESS)
408  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
409 
410  WRITE_BODY(esStr)
411  }
412  break;
413 
415  {
416  struct release_struct reStr;
417 
418  READ_BODY(reStr)
419 
420  reStr.rv = SCardReleaseContext(reStr.hContext);
421 
422  if (reStr.rv == SCARD_S_SUCCESS)
423  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
424 
425  WRITE_BODY(reStr)
426  }
427  break;
428 
429  case SCARD_CONNECT:
430  {
431  struct connect_struct coStr;
432  SCARDHANDLE hCard;
433  DWORD dwActiveProtocol;
434 
435  READ_BODY(coStr)
436 
437  hCard = coStr.hCard;
438  dwActiveProtocol = coStr.dwActiveProtocol;
439 
440  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
441  coStr.dwShareMode, coStr.dwPreferredProtocols,
442  &hCard, &dwActiveProtocol);
443 
444  coStr.hCard = hCard;
445  coStr.dwActiveProtocol = dwActiveProtocol;
446 
447  if (coStr.rv == SCARD_S_SUCCESS)
448  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
449  threadContext);
450 
451  WRITE_BODY(coStr)
452  }
453  break;
454 
455  case SCARD_RECONNECT:
456  {
457  struct reconnect_struct rcStr;
458  DWORD dwActiveProtocol;
459 
460  READ_BODY(rcStr)
461 
462  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
463  goto exit;
464 
465  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
466  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
467  &dwActiveProtocol);
468  rcStr.dwActiveProtocol = dwActiveProtocol;
469 
470  WRITE_BODY(rcStr)
471  }
472  break;
473 
474  case SCARD_DISCONNECT:
475  {
476  struct disconnect_struct diStr;
477 
478  READ_BODY(diStr)
479 
480  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
481  goto exit;
482 
483  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
484 
485  if (SCARD_S_SUCCESS == diStr.rv)
486  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
487 
488  WRITE_BODY(diStr)
489  }
490  break;
491 
493  {
494  struct begin_struct beStr;
495 
496  READ_BODY(beStr)
497 
498  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
499  goto exit;
500 
501  beStr.rv = SCardBeginTransaction(beStr.hCard);
502 
503  WRITE_BODY(beStr)
504  }
505  break;
506 
508  {
509  struct end_struct enStr;
510 
511  READ_BODY(enStr)
512 
513  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
514  goto exit;
515 
516  enStr.rv = SCardEndTransaction(enStr.hCard,
517  enStr.dwDisposition);
518 
519  WRITE_BODY(enStr)
520  }
521  break;
522 
523  case SCARD_CANCEL:
524  {
525  struct cancel_struct caStr;
526  SCONTEXT * psTargetContext = NULL;
527  READ_BODY(caStr)
528 
529  /* find the client */
530  (void)pthread_mutex_lock(&contextsList_lock);
531  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
532  &caStr.hContext);
533  (void)pthread_mutex_unlock(&contextsList_lock);
534  if (psTargetContext != NULL)
535  {
536  uint32_t fd = psTargetContext->dwClientID;
537  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
538  }
539  else
540  caStr.rv = SCARD_E_INVALID_HANDLE;
541 
542  WRITE_BODY(caStr)
543  }
544  break;
545 
546  case SCARD_STATUS:
547  {
548  struct status_struct stStr;
549 
550  READ_BODY(stStr)
551 
552  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
553  goto exit;
554 
555  /* only hCard and return value are used by the client */
556  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
557  NULL, 0, NULL);
558 
559  WRITE_BODY(stStr)
560  }
561  break;
562 
563  case SCARD_TRANSMIT:
564  {
565  struct transmit_struct trStr;
566  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
567  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
568  SCARD_IO_REQUEST ioSendPci;
569  SCARD_IO_REQUEST ioRecvPci;
570  DWORD cbRecvLength;
571 
572  READ_BODY(trStr)
573 
574  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
575  goto exit;
576 
577  /* avoids buffer overflow */
578  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
579  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
580  goto buffer_overflow;
581 
582  /* read sent buffer */
583  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
584  if (ret != SCARD_S_SUCCESS)
585  {
586  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
587  goto exit;
588  }
589 
590  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
591  ioSendPci.cbPciLength = trStr.ioSendPciLength;
592  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
593  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
594  cbRecvLength = trStr.pcbRecvLength;
595 
596  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
597  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
598  pbRecvBuffer, &cbRecvLength);
599 
600  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
601  trStr.ioSendPciLength = ioSendPci.cbPciLength;
602  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
603  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
604  trStr.pcbRecvLength = cbRecvLength;
605 
606  WRITE_BODY(trStr)
607 
608  /* write received buffer */
609  if (SCARD_S_SUCCESS == trStr.rv)
610  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
611  }
612  break;
613 
614  case SCARD_CONTROL:
615  {
616  struct control_struct ctStr;
617  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
618  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
619  DWORD dwBytesReturned;
620 
621  READ_BODY(ctStr)
622 
623  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
624  goto exit;
625 
626  /* avoids buffer overflow */
627  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
628  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
629  {
630  goto buffer_overflow;
631  }
632 
633  /* read sent buffer */
634  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
635  if (ret != SCARD_S_SUCCESS)
636  {
637  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
638  goto exit;
639  }
640 
641  dwBytesReturned = ctStr.dwBytesReturned;
642 
643  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
644  pbSendBuffer, ctStr.cbSendLength,
645  pbRecvBuffer, ctStr.cbRecvLength,
646  &dwBytesReturned);
647 
648  ctStr.dwBytesReturned = dwBytesReturned;
649 
650  WRITE_BODY(ctStr)
651 
652  /* write received buffer */
653  if (SCARD_S_SUCCESS == ctStr.rv)
654  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
655  }
656  break;
657 
658  case SCARD_GET_ATTRIB:
659  {
660  struct getset_struct gsStr;
661  DWORD cbAttrLen;
662 
663  READ_BODY(gsStr)
664 
665  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
666  goto exit;
667 
668  /* avoids buffer overflow */
669  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
670  goto buffer_overflow;
671 
672  cbAttrLen = gsStr.cbAttrLen;
673 
674  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
675  gsStr.pbAttr, &cbAttrLen);
676 
677  gsStr.cbAttrLen = cbAttrLen;
678 
679  WRITE_BODY(gsStr)
680  }
681  break;
682 
683  case SCARD_SET_ATTRIB:
684  {
685  struct getset_struct gsStr;
686 
687  READ_BODY(gsStr)
688 
689  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
690  goto exit;
691 
692  /* avoids buffer overflow */
693  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
694  goto buffer_overflow;
695 
696  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
697  gsStr.pbAttr, gsStr.cbAttrLen);
698 
699  WRITE_BODY(gsStr)
700  }
701  break;
702 
703  default:
704  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
705  goto exit;
706  }
707 
708  /* MessageSend() failed */
709  if (ret != SCARD_S_SUCCESS)
710  {
711  /* Clean up the dead client */
712  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
713  goto exit;
714  }
715  }
716 
717 buffer_overflow:
718  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
719  goto exit;
720 wrong_length:
721  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
722 exit:
723  (void)close(filedes);
724  (void)MSGCleanupClient(threadContext);
725  (void)pthread_exit((LPVOID) NULL);
726 }
727 
728 LONG MSGSignalClient(uint32_t filedes, LONG rv)
729 {
730  uint32_t ret;
731  struct wait_reader_state_change waStr;
732 
733  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
734 
735  waStr.rv = rv;
736  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr)
737 
738  return ret;
739 } /* MSGSignalClient */
740 
741 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
742 {
743  threadContext->hContext = hContext;
744  return SCARD_S_SUCCESS;
745 }
746 
747 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
748 {
749  LONG rv;
750  int lrv;
751 
752  if (threadContext->hContext != hContext)
753  return SCARD_E_INVALID_VALUE;
754 
755  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
756  while (list_size(&threadContext->cardsList) != 0)
757  {
758  READER_CONTEXT * rContext = NULL;
759  SCARDHANDLE hCard, hLockId;
760  void *ptr;
761 
762  /*
763  * Disconnect each of these just in case
764  */
765  ptr = list_get_at(&threadContext->cardsList, 0);
766  if (NULL == ptr)
767  {
768  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
769  continue;
770  }
771  hCard = *(int32_t *)ptr;
772 
773  /*
774  * Unlock the sharing
775  */
776  rv = RFReaderInfoById(hCard, &rContext);
777  if (rv != SCARD_S_SUCCESS)
778  {
779  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
780  return rv;
781  }
782 
783  hLockId = rContext->hLockId;
784  rContext->hLockId = 0;
785 
786  if (hCard != hLockId)
787  {
788  /*
789  * if the card is locked by someone else we do not reset it
790  * and simulate a card removal
791  */
793  }
794  else
795  {
796  /*
797  * We will use SCardStatus to see if the card has been
798  * reset there is no need to reset each time
799  * Disconnect is called
800  */
801  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
802  }
803 
804  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
805  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
806  else
807  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
808 
809  /* Remove entry from the list */
810  lrv = list_delete_at(&threadContext->cardsList, 0);
811  if (lrv < 0)
812  Log2(PCSC_LOG_CRITICAL,
813  "list_delete_at failed with return value: %d", lrv);
814  }
815  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
816  list_destroy(&threadContext->cardsList);
817 
818  /* We only mark the context as no longer in use.
819  * The memory is freed in MSGCleanupCLient() */
820  threadContext->hContext = 0;
821 
822  return SCARD_S_SUCCESS;
823 }
824 
825 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
826  SCONTEXT * threadContext)
827 {
828  LONG retval = SCARD_E_INVALID_VALUE;
829 
830  if (threadContext->hContext == hContext)
831  {
832  /*
833  * Find an empty spot to put the hCard value
834  */
835  int listLength, lrv;
836 
837  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
838 
839  listLength = list_size(&threadContext->cardsList);
840  if (listLength >= contextMaxCardHandles)
841  {
842  Log4(PCSC_LOG_DEBUG,
843  "Too many card handles for thread context @%p: %d (max is %d)"
844  "Restart pcscd with --max-card-handle-per-thread value",
845  threadContext, listLength, contextMaxCardHandles);
846  retval = SCARD_E_NO_MEMORY;
847  }
848  else
849  {
850  lrv = list_append(&threadContext->cardsList, &hCard);
851  if (lrv < 0)
852  {
853  Log2(PCSC_LOG_CRITICAL,
854  "list_append failed with return value: %d", lrv);
855  retval = SCARD_E_NO_MEMORY;
856  }
857  retval = SCARD_S_SUCCESS;
858  }
859 
860  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
861  }
862 
863  return retval;
864 }
865 
866 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
867 {
868  int lrv;
869 
870  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
871  lrv = list_delete(&threadContext->cardsList, &hCard);
872  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
873  if (lrv < 0)
874  {
875  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
876  return SCARD_E_INVALID_VALUE;
877  }
878 
879  return SCARD_S_SUCCESS;
880 }
881 
882 
883 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
884  SCONTEXT * threadContext)
885 {
886  int list_index = 0;
887 
888  if (0 == threadContext->hContext)
889  {
890  /* the handle is no more valid. After SCardReleaseContext() for
891  * example */
892  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
893  return -1;
894  }
895 
896  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
897  list_index = list_locate(&threadContext->cardsList, &hCard);
898  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
899  if (list_index >= 0)
900  return 0;
901 
902  /* Must be a rogue client, debug log and sleep a couple of seconds */
903  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
904  (void)SYS_Sleep(2);
905 
906  return -1;
907 }
908 
909 
910 /* Should be called just prior to exiting the thread as it de-allocates
911  * the thread memory strucutres
912  */
913 static LONG MSGCleanupClient(SCONTEXT * threadContext)
914 {
915  int lrv;
916  int listSize;
917 
918  if (threadContext->hContext != 0)
919  {
920  (void)SCardReleaseContext(threadContext->hContext);
921  (void)MSGRemoveContext(threadContext->hContext, threadContext);
922  }
923 
924  Log3(PCSC_LOG_DEBUG,
925  "Thread is stopping: dwClientID=%d, threadContext @%p",
926  threadContext->dwClientID, threadContext);
927 
928  /* Clear the struct to ensure that we detect
929  * access to de-allocated memory
930  * Hopefully the compiler won't optimise it out */
931  memset((void*) threadContext, 0, sizeof(SCONTEXT));
932  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
933 
934  (void)pthread_mutex_lock(&contextsList_lock);
935  lrv = list_delete(&contextsList, threadContext);
936  listSize = list_size(&contextsList);
937  (void)pthread_mutex_unlock(&contextsList_lock);
938  if (lrv < 0)
939  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
940 
941  free(threadContext);
942 
943  /* start a suicide alarm */
944  if (AutoExit && (listSize < 1))
945  {
946  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
947  TIME_BEFORE_SUICIDE);
948  alarm(TIME_BEFORE_SUICIDE);
949  }
950 
951  return 0;
952 }