pcsc-lite  1.8.8
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 6462 2012-09-13 17:11:32Z 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  UNREF_READER(rContext)
816  }
817  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
818  list_destroy(&threadContext->cardsList);
819 
820  /* We only mark the context as no longer in use.
821  * The memory is freed in MSGCleanupCLient() */
822  threadContext->hContext = 0;
823 
824  return SCARD_S_SUCCESS;
825 }
826 
827 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
828  SCONTEXT * threadContext)
829 {
830  LONG retval = SCARD_E_INVALID_VALUE;
831 
832  if (threadContext->hContext == hContext)
833  {
834  /*
835  * Find an empty spot to put the hCard value
836  */
837  int listLength, lrv;
838 
839  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
840 
841  listLength = list_size(&threadContext->cardsList);
842  if (listLength >= contextMaxCardHandles)
843  {
844  Log4(PCSC_LOG_DEBUG,
845  "Too many card handles for thread context @%p: %d (max is %d)"
846  "Restart pcscd with --max-card-handle-per-thread value",
847  threadContext, listLength, contextMaxCardHandles);
848  retval = SCARD_E_NO_MEMORY;
849  }
850  else
851  {
852  lrv = list_append(&threadContext->cardsList, &hCard);
853  if (lrv < 0)
854  {
855  Log2(PCSC_LOG_CRITICAL,
856  "list_append failed with return value: %d", lrv);
857  retval = SCARD_E_NO_MEMORY;
858  }
859  else
860  retval = SCARD_S_SUCCESS;
861  }
862 
863  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
864  }
865 
866  return retval;
867 }
868 
869 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
870 {
871  int lrv;
872 
873  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
874  lrv = list_delete(&threadContext->cardsList, &hCard);
875  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
876  if (lrv < 0)
877  {
878  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
879  return SCARD_E_INVALID_VALUE;
880  }
881 
882  return SCARD_S_SUCCESS;
883 }
884 
885 
886 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
887  SCONTEXT * threadContext)
888 {
889  int list_index = 0;
890 
891  if (0 == threadContext->hContext)
892  {
893  /* the handle is no more valid. After SCardReleaseContext() for
894  * example */
895  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
896  return -1;
897  }
898 
899  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
900  list_index = list_locate(&threadContext->cardsList, &hCard);
901  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
902  if (list_index >= 0)
903  return 0;
904 
905  /* Must be a rogue client, debug log and sleep a couple of seconds */
906  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
907  (void)SYS_Sleep(2);
908 
909  return -1;
910 }
911 
912 
913 /* Should be called just prior to exiting the thread as it de-allocates
914  * the thread memory strucutres
915  */
916 static LONG MSGCleanupClient(SCONTEXT * threadContext)
917 {
918  int lrv;
919  int listSize;
920 
921  if (threadContext->hContext != 0)
922  {
923  (void)SCardReleaseContext(threadContext->hContext);
924  (void)MSGRemoveContext(threadContext->hContext, threadContext);
925  }
926 
927  Log3(PCSC_LOG_DEBUG,
928  "Thread is stopping: dwClientID=%d, threadContext @%p",
929  threadContext->dwClientID, threadContext);
930 
931  /* Clear the struct to ensure that we detect
932  * access to de-allocated memory
933  * Hopefully the compiler won't optimise it out */
934  memset((void*) threadContext, 0, sizeof(SCONTEXT));
935  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
936 
937  (void)pthread_mutex_lock(&contextsList_lock);
938  lrv = list_delete(&contextsList, threadContext);
939  listSize = list_size(&contextsList);
940  (void)pthread_mutex_unlock(&contextsList_lock);
941  if (lrv < 0)
942  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
943 
944  free(threadContext);
945 
946  /* start a suicide alarm */
947  if (AutoExit && (listSize < 1))
948  {
949  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
950  TIME_BEFORE_SUICIDE);
951  alarm(TIME_BEFORE_SUICIDE);
952  }
953 
954  return 0;
955 }
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:81
used by SCardBeginTransaction()
Definition: winscard_msg.h:61
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:120
list object
Definition: simclist.h:181
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:82
wait for a reader state change
Definition: winscard_msg.h:73
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:186
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:208
volatile SCARDHANDLE hLockId
Lock Id.
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:174
get the client/server protocol version
Definition: winscard_msg.h:71
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:144
pthread_t pthThread
Event polling thread&#39;s ID.
Definition: winscard_svc.c:65
used by SCardEstablishContext()
Definition: winscard_msg.h:55
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:36
used by SCardEndTransaction()
Definition: winscard_msg.h:62
PCSC_API LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
Definition: winscard.c:173
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:61
#define SCARD_LEAVE_CARD
Do nothing on close.
Definition: pcsclite.h:163
This handles abstract system level calls.
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:57
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:109
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:44
used by SCardConnect()
Definition: winscard_msg.h:58
uint32_t dwClientID
Connection ID used to reference the Client.
Definition: winscard_svc.c:64
This demarshalls functions over the message queue and keeps track of clients and their handles...
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:26
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:151
static list_t contextsList
Context tracking list.
Definition: winscard_svc.c:56
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:83
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard.c:1349
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:109
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard.c:799
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:163
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:97
get the readers state
Definition: winscard_msg.h:72
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:33
header structure for client/server message data exchange.
Definition: winscard_msg.h:43
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:422
used by SCardReleaseContext()
Definition: winscard_msg.h:56
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:31
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:97
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:197
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:136
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:60
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:195
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:240
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:86
used by SCardReconnect()
Definition: winscard_msg.h:59
PCSC_API LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
Definition: winscard.c:497
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:209
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:63
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:61
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:136
PCSC_API LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
Definition: winscard.c:209
stop waiting for a reader state change
Definition: winscard_msg.h:74
PCSC_API LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
Definition: winscard.c:1227
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard.c:1425
#define SCARD_RESET_CARD
Reset on close.
Definition: pcsclite.h:164
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:34
static const char * CommandsText[]
Handles messages received from Clients.
Definition: winscard_svc.c:256
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:28
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
Definition: winscard.c:1049
used by SCardControl()
Definition: winscard_msg.h:64
This keeps a list of defines for pcsc-lite.
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:135
Protocol Control Information (PCI)
Definition: pcsclite.h:58
PCSC_API LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader...
Definition: winscard.c:1290
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:27
used by SCardSetAttrib()
Definition: winscard_msg.h:70
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:324
used by SCardDisconnect()
Definition: winscard_msg.h:60
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:86
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:225
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:69
used by SCardCancel()
Definition: winscard_msg.h:67
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:35
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard.c:1091
PCSC_API LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
Definition: winscard.c:1475
pthread_mutex_t cardsList_lock
lock for the above list
Definition: winscard_svc.c:63
pthread_mutex_t contextsList_lock
lock for the above list
Definition: winscard_svc.c:57
used by SCardStatus()
Definition: winscard_msg.h:65
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:80
This handles smart card reader communications.
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
Definition: winscard.c:198
This handles debugging.