pcsc-lite  1.8.3
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 5864 2011-07-09 11:37:48Z 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 
151  (void)pthread_mutex_lock(&contextsList_lock);
152  listSize = list_size(&contextsList);
153  (void)pthread_mutex_unlock(&contextsList_lock);
154 
155  if (listSize >= contextMaxThreadCounter)
156  {
157  Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
158  goto error;
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 error;
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 error;
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 error;
196  }
197 
198  (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
199 
200  (void)pthread_mutex_lock(&contextsList_lock);
201  lrv = list_append(&contextsList, newContext);
202  (void)pthread_mutex_unlock(&contextsList_lock);
203  if (lrv < 0)
204  {
205  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
206  lrv);
207  list_destroy(&(newContext->cardsList));
208  goto error;
209  }
210 
211  rv = ThreadCreate(&(newContext->pthThread), THREAD_ATTR_DETACHED,
212  (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
213  if (rv)
214  {
215  int lrv2;
216 
217  Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
218  (void)pthread_mutex_lock(&contextsList_lock);
219  lrv2 = list_delete(&contextsList, newContext);
220  (void)pthread_mutex_unlock(&contextsList_lock);
221  if (lrv2 < 0)
222  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
223  list_destroy(&(newContext->cardsList));
224  goto error;
225  }
226 
227  /* disable any suicide alarm */
228  if (AutoExit)
229  alarm(0);
230 
231  return SCARD_S_SUCCESS;
232 
233 error:
234  if (newContext)
235  free(newContext);
236  (void)close(*pdwClientID);
237  return SCARD_E_NO_MEMORY;
238 }
239 
240 /*
241  * A list of local functions used to keep track of clients and their
242  * connections
243  */
244 
253 #ifndef NO_LOG
254 static const char *CommandsText[] = {
255  "NULL",
256  "ESTABLISH_CONTEXT", /* 0x01 */
257  "RELEASE_CONTEXT",
258  "LIST_READERS",
259  "CONNECT",
260  "RECONNECT", /* 0x05 */
261  "DISCONNECT",
262  "BEGIN_TRANSACTION",
263  "END_TRANSACTION",
264  "TRANSMIT",
265  "CONTROL", /* 0x0A */
266  "STATUS",
267  "GET_STATUS_CHANGE",
268  "CANCEL",
269  "CANCEL_TRANSACTION",
270  "GET_ATTRIB", /* 0x0F */
271  "SET_ATTRIB",
272  "CMD_VERSION",
273  "CMD_GET_READERS_STATE",
274  "CMD_WAIT_READER_STATE_CHANGE",
275  "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
276  "NULL"
277 };
278 #endif
279 
280 #define READ_BODY(v) \
281  if (header.size != sizeof(v)) { goto wrong_length; } \
282  ret = MessageReceive(&v, sizeof(v), filedes); \
283  if (ret != SCARD_S_SUCCESS) { Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); goto exit; }
284 
285 #define WRITE_BODY(v) \
286  WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
287 #define WRITE_BODY_WITH_COMMAND(command, v) \
288  Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
289  ret = MessageSend(&v, sizeof(v), filedes);
290 
291 static void ContextThread(LPVOID newContext)
292 {
293  SCONTEXT * threadContext = (SCONTEXT *) newContext;
294  int32_t filedes = threadContext->dwClientID;
295 
296  Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
297  threadContext->dwClientID, threadContext);
298 
299  while (1)
300  {
301  struct rxHeader header;
302  int32_t ret = MessageReceive(&header, sizeof(header), filedes);
303 
304  if (ret != SCARD_S_SUCCESS)
305  {
306  /* Clean up the dead client */
307  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
309  goto exit;
310  }
311 
312  if ((header.command > CMD_ENUM_FIRST)
313  && (header.command < CMD_ENUM_LAST))
314  Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
315  CommandsText[header.command], filedes);
316 
317  switch (header.command)
318  {
319  /* pcsc-lite client/server protocol version */
320  case CMD_VERSION:
321  {
322  struct version_struct veStr;
323 
324  READ_BODY(veStr)
325 
326  Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
327  veStr.major, veStr.minor);
328 
329  veStr.rv = SCARD_S_SUCCESS;
330 
331  /* client and server use different protocol */
332  if ((veStr.major != PROTOCOL_VERSION_MAJOR)
333  || (veStr.minor != PROTOCOL_VERSION_MINOR))
334  {
335  Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d",
336  veStr.major, veStr.minor);
337  Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d",
338  PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
339  veStr.rv = SCARD_E_NO_SERVICE;
340  }
341 
342  /* set the server protocol version */
343  veStr.major = PROTOCOL_VERSION_MAJOR;
344  veStr.minor = PROTOCOL_VERSION_MINOR;
345 
346  /* send back the response */
347  WRITE_BODY(veStr)
348  }
349  break;
350 
352  {
353  /* nothing to read */
354 
355 #ifdef USE_USB
356  /* wait until all readers are ready */
357  RFWaitForReaderInit();
358 #endif
359 
360  /* dump the readers state */
361  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
362  }
363  break;
364 
366  {
367  struct wait_reader_state_change waStr;
368 
369  READ_BODY(waStr)
370 
371  /* add the client fd to the list */
372  EHRegisterClientForEvent(filedes);
373 
374  /* We do not send anything here.
375  * Either the client will timeout or the server will
376  * answer if an event occurs */
377  }
378  break;
379 
381  {
382  struct wait_reader_state_change waStr;
383 
384  READ_BODY(waStr)
385 
386  /* add the client fd to the list */
387  waStr.rv = EHUnregisterClientForEvent(filedes);
388 
389  WRITE_BODY(waStr)
390  }
391  break;
392 
394  {
395  struct establish_struct esStr;
396  SCARDCONTEXT hContext;
397 
398  READ_BODY(esStr)
399 
400  hContext = esStr.hContext;
401  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
402  &hContext);
403  esStr.hContext = hContext;
404 
405  if (esStr.rv == SCARD_S_SUCCESS)
406  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
407 
408  WRITE_BODY(esStr)
409  }
410  break;
411 
413  {
414  struct release_struct reStr;
415 
416  READ_BODY(reStr)
417 
418  reStr.rv = SCardReleaseContext(reStr.hContext);
419 
420  if (reStr.rv == SCARD_S_SUCCESS)
421  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
422 
423  WRITE_BODY(reStr)
424  }
425  break;
426 
427  case SCARD_CONNECT:
428  {
429  struct connect_struct coStr;
430  SCARDHANDLE hCard;
431  DWORD dwActiveProtocol;
432 
433  READ_BODY(coStr)
434 
435  hCard = coStr.hCard;
436  dwActiveProtocol = coStr.dwActiveProtocol;
437 
438  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
439  coStr.dwShareMode, coStr.dwPreferredProtocols,
440  &hCard, &dwActiveProtocol);
441 
442  coStr.hCard = hCard;
443  coStr.dwActiveProtocol = dwActiveProtocol;
444 
445  if (coStr.rv == SCARD_S_SUCCESS)
446  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
447  threadContext);
448 
449  WRITE_BODY(coStr)
450  }
451  break;
452 
453  case SCARD_RECONNECT:
454  {
455  struct reconnect_struct rcStr;
456  DWORD dwActiveProtocol;
457 
458  READ_BODY(rcStr)
459 
460  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
461  goto exit;
462 
463  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
464  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
465  &dwActiveProtocol);
466  rcStr.dwActiveProtocol = dwActiveProtocol;
467 
468  WRITE_BODY(rcStr)
469  }
470  break;
471 
472  case SCARD_DISCONNECT:
473  {
474  struct disconnect_struct diStr;
475 
476  READ_BODY(diStr)
477 
478  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
479  goto exit;
480 
481  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
482 
483  if (SCARD_S_SUCCESS == diStr.rv)
484  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
485 
486  WRITE_BODY(diStr)
487  }
488  break;
489 
491  {
492  struct begin_struct beStr;
493 
494  READ_BODY(beStr)
495 
496  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
497  goto exit;
498 
499  beStr.rv = SCardBeginTransaction(beStr.hCard);
500 
501  WRITE_BODY(beStr)
502  }
503  break;
504 
506  {
507  struct end_struct enStr;
508 
509  READ_BODY(enStr)
510 
511  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
512  goto exit;
513 
514  enStr.rv = SCardEndTransaction(enStr.hCard,
515  enStr.dwDisposition);
516 
517  WRITE_BODY(enStr)
518  }
519  break;
520 
521  case SCARD_CANCEL:
522  {
523  struct cancel_struct caStr;
524  SCONTEXT * psTargetContext = NULL;
525  READ_BODY(caStr)
526 
527  /* find the client */
528  (void)pthread_mutex_lock(&contextsList_lock);
529  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
530  &(caStr.hContext));
531  (void)pthread_mutex_unlock(&contextsList_lock);
532  if (psTargetContext != NULL)
533  {
534  uint32_t fd = psTargetContext->dwClientID;
535  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
536  }
537  else
538  caStr.rv = SCARD_E_INVALID_HANDLE;
539 
540  WRITE_BODY(caStr)
541  }
542  break;
543 
544  case SCARD_STATUS:
545  {
546  struct status_struct stStr;
547 
548  READ_BODY(stStr)
549 
550  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
551  goto exit;
552 
553  /* only hCard and return value are used by the client */
554  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
555  NULL, 0, NULL);
556 
557  WRITE_BODY(stStr)
558  }
559  break;
560 
561  case SCARD_TRANSMIT:
562  {
563  struct transmit_struct trStr;
564  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
565  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
566  SCARD_IO_REQUEST ioSendPci;
567  SCARD_IO_REQUEST ioRecvPci;
568  DWORD cbRecvLength;
569 
570  READ_BODY(trStr)
571 
572  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
573  goto exit;
574 
575  /* avoids buffer overflow */
576  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
577  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
578  goto buffer_overflow;
579 
580  /* read sent buffer */
581  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
582  if (ret != SCARD_S_SUCCESS)
583  {
584  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
585  goto exit;
586  }
587 
588  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
589  ioSendPci.cbPciLength = trStr.ioSendPciLength;
590  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
591  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
592  cbRecvLength = trStr.pcbRecvLength;
593 
594  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
595  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
596  pbRecvBuffer, &cbRecvLength);
597 
598  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
599  trStr.ioSendPciLength = ioSendPci.cbPciLength;
600  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
601  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
602  trStr.pcbRecvLength = cbRecvLength;
603 
604  WRITE_BODY(trStr)
605 
606  /* write received buffer */
607  if (SCARD_S_SUCCESS == trStr.rv)
608  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
609  }
610  break;
611 
612  case SCARD_CONTROL:
613  {
614  struct control_struct ctStr;
615  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
616  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
617  DWORD dwBytesReturned;
618 
619  READ_BODY(ctStr)
620 
621  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
622  goto exit;
623 
624  /* avoids buffer overflow */
625  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
626  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
627  {
628  goto buffer_overflow;
629  }
630 
631  /* read sent buffer */
632  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
633  if (ret != SCARD_S_SUCCESS)
634  {
635  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
636  goto exit;
637  }
638 
639  dwBytesReturned = ctStr.dwBytesReturned;
640 
641  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
642  pbSendBuffer, ctStr.cbSendLength,
643  pbRecvBuffer, ctStr.cbRecvLength,
644  &dwBytesReturned);
645 
646  ctStr.dwBytesReturned = dwBytesReturned;
647 
648  WRITE_BODY(ctStr)
649 
650  /* write received buffer */
651  if (SCARD_S_SUCCESS == ctStr.rv)
652  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
653  }
654  break;
655 
656  case SCARD_GET_ATTRIB:
657  {
658  struct getset_struct gsStr;
659  DWORD cbAttrLen;
660 
661  READ_BODY(gsStr)
662 
663  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
664  goto exit;
665 
666  /* avoids buffer overflow */
667  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
668  goto buffer_overflow;
669 
670  cbAttrLen = gsStr.cbAttrLen;
671 
672  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
673  gsStr.pbAttr, &cbAttrLen);
674 
675  gsStr.cbAttrLen = cbAttrLen;
676 
677  WRITE_BODY(gsStr)
678  }
679  break;
680 
681  case SCARD_SET_ATTRIB:
682  {
683  struct getset_struct gsStr;
684 
685  READ_BODY(gsStr)
686 
687  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
688  goto exit;
689 
690  /* avoids buffer overflow */
691  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
692  goto buffer_overflow;
693 
694  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
695  gsStr.pbAttr, gsStr.cbAttrLen);
696 
697  WRITE_BODY(gsStr)
698  }
699  break;
700 
701  default:
702  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
703  goto exit;
704  }
705 
706  /* MessageSend() failed */
707  if (ret != SCARD_S_SUCCESS)
708  {
709  /* Clean up the dead client */
710  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
711  goto exit;
712  }
713  }
714 
715 buffer_overflow:
716  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
717  goto exit;
718 wrong_length:
719  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
720 exit:
721  (void)close(filedes);
722  (void)MSGCleanupClient(threadContext);
723  (void)pthread_exit((LPVOID) NULL);
724 }
725 
726 LONG MSGSignalClient(uint32_t filedes, LONG rv)
727 {
728  uint32_t ret;
729  struct wait_reader_state_change waStr;
730 
731  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
732 
733  waStr.rv = rv;
734  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr)
735 
736  return ret;
737 } /* MSGSignalClient */
738 
739 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
740 {
741  threadContext->hContext = hContext;
742  return SCARD_S_SUCCESS;
743 }
744 
745 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
746 {
747  LONG rv;
748  int lrv;
749 
750  if (threadContext->hContext != hContext)
751  return SCARD_E_INVALID_VALUE;
752 
753  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
754  while (list_size(&(threadContext->cardsList)) != 0)
755  {
756  READER_CONTEXT * rContext = NULL;
757  SCARDHANDLE hCard, hLockId;
758  void *ptr;
759 
760  /*
761  * Disconnect each of these just in case
762  */
763  ptr = list_get_at(&(threadContext->cardsList), 0);
764  if (NULL == ptr)
765  {
766  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
767  continue;
768  }
769  hCard = *(int32_t *)ptr;
770 
771  /*
772  * Unlock the sharing
773  */
774  rv = RFReaderInfoById(hCard, &rContext);
775  if (rv != SCARD_S_SUCCESS)
776  {
777  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
778  return rv;
779  }
780 
781  hLockId = rContext->hLockId;
782  rContext->hLockId = 0;
783 
784  if (hCard != hLockId)
785  {
786  /*
787  * if the card is locked by someone else we do not reset it
788  * and simulate a card removal
789  */
791  }
792  else
793  {
794  /*
795  * We will use SCardStatus to see if the card has been
796  * reset there is no need to reset each time
797  * Disconnect is called
798  */
799  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
800  }
801 
802  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
803  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
804  else
805  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
806 
807  /* Remove entry from the list */
808  lrv = list_delete_at(&(threadContext->cardsList), 0);
809  if (lrv < 0)
810  Log2(PCSC_LOG_CRITICAL,
811  "list_delete_at failed with return value: %d", lrv);
812  }
813  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
814  list_destroy(&(threadContext->cardsList));
815 
816  /* We only mark the context as no longer in use.
817  * The memory is freed in MSGCleanupCLient() */
818  threadContext->hContext = 0;
819 
820  return SCARD_S_SUCCESS;
821 }
822 
823 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
824  SCONTEXT * threadContext)
825 {
826  if (threadContext->hContext == hContext)
827  {
828  /*
829  * Find an empty spot to put the hCard value
830  */
831  int listLength, lrv;
832 
833  listLength = list_size(&(threadContext->cardsList));
834  if (listLength >= contextMaxCardHandles)
835  {
836  Log4(PCSC_LOG_DEBUG,
837  "Too many card handles for thread context @%p: %d (max is %d)"
838  "Restart pcscd with --max-card-handle-per-thread value",
839  threadContext, listLength, contextMaxCardHandles);
840  return SCARD_E_NO_MEMORY;
841  }
842 
843  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
844  lrv = list_append(&(threadContext->cardsList), &hCard);
845  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
846  if (lrv < 0)
847  {
848  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
849  lrv);
850  return SCARD_E_NO_MEMORY;
851  }
852  return SCARD_S_SUCCESS;
853  }
854 
855  return SCARD_E_INVALID_VALUE;
856 }
857 
858 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
859 {
860  int lrv;
861 
862  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
863  lrv = list_delete(&(threadContext->cardsList), &hCard);
864  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
865  if (lrv < 0)
866  {
867  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
868  return SCARD_E_INVALID_VALUE;
869  }
870 
871  return SCARD_S_SUCCESS;
872 }
873 
874 
875 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
876  SCONTEXT * threadContext)
877 {
878  int list_index = 0;
879 
880  if (0 == threadContext->hContext)
881  {
882  /* the handle is no more valid. After SCardReleaseContext() for
883  * example */
884  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
885  return -1;
886  }
887 
888  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
889  list_index = list_locate(&(threadContext->cardsList), &hCard);
890  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
891  if (list_index >= 0)
892  return 0;
893 
894  /* Must be a rogue client, debug log and sleep a couple of seconds */
895  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
896  (void)SYS_Sleep(2);
897 
898  return -1;
899 }
900 
901 
902 /* Should be called just prior to exiting the thread as it de-allocates
903  * the thread memory strucutres
904  */
905 static LONG MSGCleanupClient(SCONTEXT * threadContext)
906 {
907  int lrv;
908  int listSize;
909 
910  if (threadContext->hContext != 0)
911  {
912  (void)SCardReleaseContext(threadContext->hContext);
913  (void)MSGRemoveContext(threadContext->hContext, threadContext);
914  }
915 
916  Log3(PCSC_LOG_DEBUG,
917  "Thread is stopping: dwClientID=%d, threadContext @%p",
918  threadContext->dwClientID, threadContext);
919 
920  /* Clear the struct to ensure that we detect
921  * access to de-allocated memory
922  * Hopefully the compiler won't optimise it out */
923  memset((void*) threadContext, 0, sizeof(SCONTEXT));
924  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
925 
926  (void)pthread_mutex_lock(&contextsList_lock);
927  lrv = list_delete(&contextsList, threadContext);
928  listSize = list_size(&contextsList);
929  (void)pthread_mutex_unlock(&contextsList_lock);
930  if (lrv < 0)
931  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
932 
933  free(threadContext);
934 
935  /* start a suicide alarm */
936  if (AutoExit && (listSize < 1))
937  {
938  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
939  TIME_BEFORE_SUICIDE);
940  alarm(TIME_BEFORE_SUICIDE);
941  }
942 
943  return 0;
944 }