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