pcsc-lite  1.8.20
winscard_svc.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@musclecard.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 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 
17 1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20  notice, this list of conditions and the following disclaimer in the
21  documentation and/or other materials provided with the distribution.
22 3. The name of the author may not be used to endorse or promote products
23  derived from this software without specific prior written permission.
24 
25 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
47 #include "config.h"
48 #include <time.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <stddef.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <pthread.h>
55 
56 #include "pcscd.h"
57 #include "winscard.h"
58 #include "debuglog.h"
59 #include "winscard_msg.h"
60 #include "winscard_svc.h"
61 #include "sys_generic.h"
62 #include "utils.h"
63 #include "readerfactory.h"
64 #include "eventhandler.h"
65 #include "simclist.h"
66 #include "auth.h"
67 
74 extern char AutoExit;
75 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
76 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
77 
79 pthread_mutex_t contextsList_lock;
81 struct _psContext
82 {
83  int32_t hContext;
84  list_t cardsList;
85  pthread_mutex_t cardsList_lock;
86  uint32_t dwClientID;
87  pthread_t pthThread;
88 };
89 typedef struct _psContext SCONTEXT;
90 
91 static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *);
92 static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *);
93 static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *);
94 static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *);
95 static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *);
96 static LONG MSGCleanupClient(SCONTEXT *);
97 
98 static void ContextThread(LPVOID pdwIndex);
99 
101 
102 static int contextsListhContext_seeker(const void *el, const void *key)
103 {
104  const SCONTEXT * currentContext = (SCONTEXT *)el;
105 
106  if ((el == NULL) || (key == NULL))
107  {
108  Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%p, key=%p",
109  el, key);
110  return 0;
111  }
112 
113  if (currentContext->hContext == *(int32_t *)key)
114  return 1;
115  return 0;
116 }
117 
118 LONG ContextsInitialize(int customMaxThreadCounter,
119  int customMaxThreadCardHandles)
120 {
121  int lrv = 0;
122 
123  if (customMaxThreadCounter != 0)
124  contextMaxThreadCounter = customMaxThreadCounter;
125 
126  if (customMaxThreadCardHandles != 0)
127  contextMaxCardHandles = customMaxThreadCardHandles;
128 
129  lrv = list_init(&contextsList);
130  if (lrv < 0)
131  {
132  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
133  return -1;
134  }
135  lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
136  if (lrv < 0)
137  {
138  Log2(PCSC_LOG_CRITICAL,
139  "list_attributes_seeker failed with return value: %d", lrv);
140  return -1;
141  }
142 
143  (void)pthread_mutex_init(&contextsList_lock, NULL);
144 
145  return 1;
146 }
147 
148 void ContextsDeinitialize(void)
149 {
150  int listSize;
151  listSize = list_size(&contextsList);
152  Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize);
153  /* This is currently a no-op. It should terminate the threads properly. */
154 
155  list_destroy(&contextsList);
156 }
157 
168 LONG CreateContextThread(uint32_t *pdwClientID)
169 {
170  int rv;
171  int lrv;
172  int listSize;
173  SCONTEXT * newContext = NULL;
174  LONG retval = SCARD_E_NO_MEMORY;
175 
176  (void)pthread_mutex_lock(&contextsList_lock);
177 
178  listSize = list_size(&contextsList);
179  if (listSize >= contextMaxThreadCounter)
180  {
181  Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
182  goto out;
183  }
184 
185  /* Create the context for this thread. */
186  newContext = malloc(sizeof(*newContext));
187  if (NULL == newContext)
188  {
189  Log1(PCSC_LOG_CRITICAL, "Could not allocate new context");
190  goto out;
191  }
192  memset(newContext, 0, sizeof(*newContext));
193 
194  newContext->dwClientID = *pdwClientID;
195 
196  /* Initialise the list of card contexts */
197  lrv = list_init(&newContext->cardsList);
198  if (lrv < 0)
199  {
200  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
201  goto out;
202  }
203 
204  /* request to store copies, and provide the metric function */
205  list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
206 
207  /* Adding a comparator
208  * The stored type is SCARDHANDLE (long) but has only 32 bits
209  * usefull even on a 64-bit CPU since the API between pcscd and
210  * libpcscliter uses "int32_t hCard;"
211  */
212  lrv = list_attributes_comparator(&newContext->cardsList,
213  list_comparator_int32_t);
214  if (lrv != 0)
215  {
216  Log2(PCSC_LOG_CRITICAL,
217  "list_attributes_comparator failed with return value: %d", lrv);
218  list_destroy(&newContext->cardsList);
219  goto out;
220  }
221 
222  (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
223 
224  lrv = list_append(&contextsList, newContext);
225  if (lrv < 0)
226  {
227  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
228  lrv);
229  list_destroy(&newContext->cardsList);
230  goto out;
231  }
232 
233  rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED,
234  (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
235  if (rv)
236  {
237  int lrv2;
238 
239  Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
240  lrv2 = list_delete(&contextsList, newContext);
241  if (lrv2 < 0)
242  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
243  list_destroy(&newContext->cardsList);
244  goto out;
245  }
246 
247  /* disable any suicide alarm */
248  if (AutoExit)
249  alarm(0);
250 
251  retval = SCARD_S_SUCCESS;
252 
253 out:
254  (void)pthread_mutex_unlock(&contextsList_lock);
255 
256  if (retval != SCARD_S_SUCCESS)
257  {
258  if (newContext)
259  free(newContext);
260  (void)close(*pdwClientID);
261  }
262 
263  return retval;
264 }
265 
266 /*
267  * A list of local functions used to keep track of clients and their
268  * connections
269  */
270 
279 #ifndef NO_LOG
280 static const char *CommandsText[] = {
281  "NULL",
282  "ESTABLISH_CONTEXT", /* 0x01 */
283  "RELEASE_CONTEXT",
284  "LIST_READERS",
285  "CONNECT",
286  "RECONNECT", /* 0x05 */
287  "DISCONNECT",
288  "BEGIN_TRANSACTION",
289  "END_TRANSACTION",
290  "TRANSMIT",
291  "CONTROL", /* 0x0A */
292  "STATUS",
293  "GET_STATUS_CHANGE",
294  "CANCEL",
295  "CANCEL_TRANSACTION",
296  "GET_ATTRIB", /* 0x0F */
297  "SET_ATTRIB",
298  "CMD_VERSION",
299  "CMD_GET_READERS_STATE",
300  "CMD_WAIT_READER_STATE_CHANGE",
301  "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
302  "NULL"
303 };
304 #endif
305 
306 #define READ_BODY(v) \
307  do { \
308  if (header.size != sizeof(v)) \
309  goto wrong_length; \
310  ret = MessageReceive(&v, sizeof(v), filedes); \
311  if (ret != SCARD_S_SUCCESS) { \
312  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
313  goto exit; \
314  } \
315  } while (0)
316 
317 #define WRITE_BODY(v) \
318  WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
319 #define WRITE_BODY_WITH_COMMAND(command, v) \
320  do { \
321  Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
322  ret = MessageSend(&v, sizeof(v), filedes); \
323  } while (0)
324 
325 static void ContextThread(LPVOID newContext)
326 {
327  SCONTEXT * threadContext = (SCONTEXT *) newContext;
328  int32_t filedes = threadContext->dwClientID;
329 
330  if (IsClientAuthorized(filedes, "access_pcsc", NULL) == 0)
331  {
332  Log1(PCSC_LOG_CRITICAL, "Rejected unauthorized PC/SC client");
333  goto exit;
334  }
335  else
336  {
337  Log1(PCSC_LOG_DEBUG, "Authorized PC/SC client");
338  }
339 
340  Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
341  threadContext->dwClientID, threadContext);
342 
343  while (1)
344  {
345  struct rxHeader header;
346  int32_t ret = MessageReceive(&header, sizeof(header), filedes);
347 
348  if (ret != SCARD_S_SUCCESS)
349  {
350  /* Clean up the dead client */
351  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
353  goto exit;
354  }
355 
356  if ((header.command > CMD_ENUM_FIRST)
357  && (header.command < CMD_ENUM_LAST))
358  Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
359  CommandsText[header.command], filedes);
360 
361  switch (header.command)
362  {
363  /* pcsc-lite client/server protocol version */
364  case CMD_VERSION:
365  {
366  struct version_struct veStr;
367 
368  READ_BODY(veStr);
369 
370  Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
371  veStr.major, veStr.minor);
372 
373  veStr.rv = SCARD_S_SUCCESS;
374 
375  /* client and server use different protocol */
376  if ((veStr.major != PROTOCOL_VERSION_MAJOR)
377  || (veStr.minor != PROTOCOL_VERSION_MINOR))
378  {
379  Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d",
380  veStr.major, veStr.minor);
381  Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d",
383  veStr.rv = SCARD_E_NO_SERVICE;
384  }
385 
386  /* set the server protocol version */
389 
390  /* send back the response */
391  WRITE_BODY(veStr);
392  }
393  break;
394 
396  {
397  /* nothing to read */
398 
399 #ifdef USE_USB
400  /* wait until all readers are ready */
401  RFWaitForReaderInit();
402 #endif
403 
404  /* dump the readers state */
405  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
406  }
407  break;
408 
410  {
411  struct wait_reader_state_change waStr;
412 
413  READ_BODY(waStr);
414 
415  /* add the client fd to the list */
416  EHRegisterClientForEvent(filedes);
417 
418  /* We do not send anything here.
419  * Either the client will timeout or the server will
420  * answer if an event occurs */
421  }
422  break;
423 
425  {
426  struct wait_reader_state_change waStr;
427 
428  READ_BODY(waStr);
429 
430  /* remove the client fd from the list */
431  waStr.rv = EHUnregisterClientForEvent(filedes);
432 
433  /* send the response only if the client was still in the
434  * list */
435  if (waStr.rv != SCARD_F_INTERNAL_ERROR)
436  WRITE_BODY(waStr);
437  }
438  break;
439 
441  {
442  struct establish_struct esStr;
443  SCARDCONTEXT hContext;
444 
445  READ_BODY(esStr);
446 
447  hContext = esStr.hContext;
448  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
449  &hContext);
450  esStr.hContext = hContext;
451 
452  if (esStr.rv == SCARD_S_SUCCESS)
453  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
454 
455  WRITE_BODY(esStr);
456  }
457  break;
458 
460  {
461  struct release_struct reStr;
462 
463  READ_BODY(reStr);
464 
465  reStr.rv = SCardReleaseContext(reStr.hContext);
466 
467  if (reStr.rv == SCARD_S_SUCCESS)
468  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
469 
470  WRITE_BODY(reStr);
471  }
472  break;
473 
474  case SCARD_CONNECT:
475  {
476  struct connect_struct coStr;
477  SCARDHANDLE hCard;
478  DWORD dwActiveProtocol;
479 
480  READ_BODY(coStr);
481 
482  coStr.szReader[sizeof(coStr.szReader)-1] = 0;
483  hCard = coStr.hCard;
484  dwActiveProtocol = coStr.dwActiveProtocol;
485 
486  if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
487  {
488  Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
489  goto exit;
490  }
491  else
492  {
493  Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
494  }
495 
496  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
497  coStr.dwShareMode, coStr.dwPreferredProtocols,
498  &hCard, &dwActiveProtocol);
499 
500  coStr.hCard = hCard;
501  coStr.dwActiveProtocol = dwActiveProtocol;
502 
503  if (coStr.rv == SCARD_S_SUCCESS)
504  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
505  threadContext);
506 
507  WRITE_BODY(coStr);
508  }
509  break;
510 
511  case SCARD_RECONNECT:
512  {
513  struct reconnect_struct rcStr;
514  DWORD dwActiveProtocol;
515 
516  READ_BODY(rcStr);
517 
518  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
519  goto exit;
520 
521  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
522  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
523  &dwActiveProtocol);
524  rcStr.dwActiveProtocol = dwActiveProtocol;
525 
526  WRITE_BODY(rcStr);
527  }
528  break;
529 
530  case SCARD_DISCONNECT:
531  {
532  struct disconnect_struct diStr;
533 
534  READ_BODY(diStr);
535 
536  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
537  goto exit;
538 
539  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
540 
541  if (SCARD_S_SUCCESS == diStr.rv)
542  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
543 
544  WRITE_BODY(diStr);
545  }
546  break;
547 
549  {
550  struct begin_struct beStr;
551 
552  READ_BODY(beStr);
553 
554  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
555  goto exit;
556 
557  beStr.rv = SCardBeginTransaction(beStr.hCard);
558 
559  WRITE_BODY(beStr);
560  }
561  break;
562 
564  {
565  struct end_struct enStr;
566 
567  READ_BODY(enStr);
568 
569  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
570  goto exit;
571 
572  enStr.rv = SCardEndTransaction(enStr.hCard,
573  enStr.dwDisposition);
574 
575  WRITE_BODY(enStr);
576  }
577  break;
578 
579  case SCARD_CANCEL:
580  {
581  struct cancel_struct caStr;
582  SCONTEXT * psTargetContext = NULL;
583  READ_BODY(caStr);
584 
585  /* find the client */
586  (void)pthread_mutex_lock(&contextsList_lock);
587  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
588  &caStr.hContext);
589  (void)pthread_mutex_unlock(&contextsList_lock);
590  if (psTargetContext != NULL)
591  {
592  uint32_t fd = psTargetContext->dwClientID;
593  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
594 
595  /* the client should not receive the event
596  * notification now the waiting has been cancelled */
598  }
599  else
600  caStr.rv = SCARD_E_INVALID_HANDLE;
601 
602  WRITE_BODY(caStr);
603  }
604  break;
605 
606  case SCARD_STATUS:
607  {
608  struct status_struct stStr;
609 
610  READ_BODY(stStr);
611 
612  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
613  goto exit;
614 
615  /* only hCard and return value are used by the client */
616  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
617  NULL, 0, NULL);
618 
619  WRITE_BODY(stStr);
620  }
621  break;
622 
623  case SCARD_TRANSMIT:
624  {
625  struct transmit_struct trStr;
626  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
627  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
628  SCARD_IO_REQUEST ioSendPci;
629  SCARD_IO_REQUEST ioRecvPci;
630  DWORD cbRecvLength;
631 
632  READ_BODY(trStr);
633 
634  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
635  goto exit;
636 
637  /* avoids buffer overflow */
638  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
639  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
640  goto buffer_overflow;
641 
642  /* read sent buffer */
643  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
644  if (ret != SCARD_S_SUCCESS)
645  {
646  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
647  goto exit;
648  }
649 
650  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
651  ioSendPci.cbPciLength = trStr.ioSendPciLength;
652  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
653  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
654  cbRecvLength = sizeof pbRecvBuffer;
655 
656  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
657  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
658  pbRecvBuffer, &cbRecvLength);
659 
660  if (cbRecvLength > trStr.pcbRecvLength)
661  /* The client buffer is not large enough.
662  * The pbRecvBuffer buffer will NOT be sent a few
663  * lines bellow. So no buffer overflow is expected. */
664  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
665 
666  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
667  trStr.ioSendPciLength = ioSendPci.cbPciLength;
668  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
669  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
670  trStr.pcbRecvLength = cbRecvLength;
671 
672  WRITE_BODY(trStr);
673 
674  /* write received buffer */
675  if (SCARD_S_SUCCESS == trStr.rv)
676  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
677  }
678  break;
679 
680  case SCARD_CONTROL:
681  {
682  struct control_struct ctStr;
683  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
684  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
685  DWORD dwBytesReturned;
686 
687  READ_BODY(ctStr);
688 
689  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
690  goto exit;
691 
692  /* avoids buffer overflow */
693  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
694  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
695  {
696  goto buffer_overflow;
697  }
698 
699  /* read sent buffer */
700  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
701  if (ret != SCARD_S_SUCCESS)
702  {
703  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
704  goto exit;
705  }
706 
707  dwBytesReturned = ctStr.dwBytesReturned;
708 
709  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
710  pbSendBuffer, ctStr.cbSendLength,
711  pbRecvBuffer, ctStr.cbRecvLength,
712  &dwBytesReturned);
713 
714  ctStr.dwBytesReturned = dwBytesReturned;
715 
716  WRITE_BODY(ctStr);
717 
718  /* write received buffer */
719  if (SCARD_S_SUCCESS == ctStr.rv)
720  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
721  }
722  break;
723 
724  case SCARD_GET_ATTRIB:
725  {
726  struct getset_struct gsStr;
727  DWORD cbAttrLen;
728 
729  READ_BODY(gsStr);
730 
731  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
732  goto exit;
733 
734  /* avoids buffer overflow */
735  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
736  goto buffer_overflow;
737 
738  cbAttrLen = gsStr.cbAttrLen;
739 
740  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
741  gsStr.pbAttr, &cbAttrLen);
742 
743  gsStr.cbAttrLen = cbAttrLen;
744 
745  WRITE_BODY(gsStr);
746  }
747  break;
748 
749  case SCARD_SET_ATTRIB:
750  {
751  struct getset_struct gsStr;
752 
753  READ_BODY(gsStr);
754 
755  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
756  goto exit;
757 
758  /* avoids buffer overflow */
759  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
760  goto buffer_overflow;
761 
762  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
763  gsStr.pbAttr, gsStr.cbAttrLen);
764 
765  WRITE_BODY(gsStr);
766  }
767  break;
768 
769  default:
770  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
771  goto exit;
772  }
773 
774  /* MessageSend() failed */
775  if (ret != SCARD_S_SUCCESS)
776  {
777  /* Clean up the dead client */
778  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
779  goto exit;
780  }
781  }
782 
783 buffer_overflow:
784  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
785  goto exit;
786 wrong_length:
787  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
788 exit:
789  (void)close(filedes);
790  (void)MSGCleanupClient(threadContext);
791  (void)pthread_exit((LPVOID) NULL);
792 }
793 
794 LONG MSGSignalClient(uint32_t filedes, LONG rv)
795 {
796  uint32_t ret;
797  struct wait_reader_state_change waStr;
798 
799  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
800 
801  waStr.rv = rv;
802  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
803 
804  return ret;
805 } /* MSGSignalClient */
806 
807 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
808 {
809  threadContext->hContext = hContext;
810  return SCARD_S_SUCCESS;
811 }
812 
813 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
814 {
815  LONG rv;
816  int lrv;
817 
818  if (0 == threadContext->hContext)
819  {
820  Log1(PCSC_LOG_ERROR, "Invalidated handle");
821  return SCARD_E_INVALID_HANDLE;
822  }
823 
824  if (threadContext->hContext != hContext)
825  return SCARD_E_INVALID_VALUE;
826 
827  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
828  while (list_size(&threadContext->cardsList) != 0)
829  {
830  READER_CONTEXT * rContext = NULL;
831  SCARDHANDLE hCard, hLockId;
832  void *ptr;
833 
834  /*
835  * Disconnect each of these just in case
836  */
837  ptr = list_get_at(&threadContext->cardsList, 0);
838  if (NULL == ptr)
839  {
840  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
841  continue;
842  }
843  hCard = *(int32_t *)ptr;
844 
845  /*
846  * Unlock the sharing
847  */
848  rv = RFReaderInfoById(hCard, &rContext);
849  if (rv != SCARD_S_SUCCESS)
850  {
851  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
852  return rv;
853  }
854 
855  hLockId = rContext->hLockId;
856  rContext->hLockId = 0;
857 
858  if (hCard != hLockId)
859  {
860  /*
861  * if the card is locked by someone else we do not reset it
862  * and simulate a card removal
863  */
865  }
866  else
867  {
868  /*
869  * We will use SCardStatus to see if the card has been
870  * reset there is no need to reset each time
871  * Disconnect is called
872  */
873  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
874  }
875 
876  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
877  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
878  else
879  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
880 
881  /* Remove entry from the list */
882  lrv = list_delete_at(&threadContext->cardsList, 0);
883  if (lrv < 0)
884  Log2(PCSC_LOG_CRITICAL,
885  "list_delete_at failed with return value: %d", lrv);
886 
887  UNREF_READER(rContext)
888  }
889  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
890 
891  /* We only mark the context as no longer in use.
892  * The memory is freed in MSGCleanupCLient() */
893  threadContext->hContext = 0;
894 
895  return SCARD_S_SUCCESS;
896 }
897 
898 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
899  SCONTEXT * threadContext)
900 {
901  LONG retval = SCARD_E_INVALID_VALUE;
902 
903  if (0 == threadContext->hContext)
904  {
905  Log1(PCSC_LOG_ERROR, "Invalidated handle");
906  return SCARD_E_INVALID_HANDLE;
907  }
908 
909  if (threadContext->hContext == hContext)
910  {
911  /*
912  * Find an empty spot to put the hCard value
913  */
914  int listLength;
915 
916  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
917 
918  listLength = list_size(&threadContext->cardsList);
919  if (listLength >= contextMaxCardHandles)
920  {
921  Log4(PCSC_LOG_DEBUG,
922  "Too many card handles for thread context @%p: %d (max is %d)"
923  "Restart pcscd with --max-card-handle-per-thread value",
924  threadContext, listLength, contextMaxCardHandles);
925  retval = SCARD_E_NO_MEMORY;
926  }
927  else
928  {
929  int lrv;
930 
931  lrv = list_append(&threadContext->cardsList, &hCard);
932  if (lrv < 0)
933  {
934  Log2(PCSC_LOG_CRITICAL,
935  "list_append failed with return value: %d", lrv);
936  retval = SCARD_E_NO_MEMORY;
937  }
938  else
939  retval = SCARD_S_SUCCESS;
940  }
941 
942  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
943  }
944 
945  return retval;
946 }
947 
948 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
949 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
950 {
951  int lrv;
952 
953  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
954  lrv = list_delete(&threadContext->cardsList, &hCard);
955  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
956  if (lrv < 0)
957  {
958  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
959  return SCARD_E_INVALID_VALUE;
960  }
961 
962  return SCARD_S_SUCCESS;
963 }
964 
965 
966 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
967  SCONTEXT * threadContext)
968 {
969  int list_index = 0;
970 
971  if (0 == threadContext->hContext)
972  {
973  /* the handle is no more valid. After SCardReleaseContext() for
974  * example */
975  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
976  return -1;
977  }
978 
979  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
980  list_index = list_locate(&threadContext->cardsList, &hCard);
981  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
982  if (list_index >= 0)
983  return 0;
984 
985  /* Must be a rogue client, debug log and sleep a couple of seconds */
986  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
987  (void)SYS_Sleep(2);
988 
989  return -1;
990 }
991 
992 
993 /* Should be called just prior to exiting the thread as it de-allocates
994  * the thread memory strucutres
995  */
996 static LONG MSGCleanupClient(SCONTEXT * threadContext)
997 {
998  int lrv;
999  int listSize;
1000 
1001  if (threadContext->hContext != 0)
1002  {
1003  (void)SCardReleaseContext(threadContext->hContext);
1004  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1005  }
1006 
1007  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1008  list_destroy(&threadContext->cardsList);
1009  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1010 
1011  Log3(PCSC_LOG_DEBUG,
1012  "Thread is stopping: dwClientID=%d, threadContext @%p",
1013  threadContext->dwClientID, threadContext);
1014 
1015  /* Clear the struct to ensure that we detect
1016  * access to de-allocated memory
1017  * Hopefully the compiler won't optimise it out */
1018  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1019  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1020 
1021  (void)pthread_mutex_lock(&contextsList_lock);
1022  lrv = list_delete(&contextsList, threadContext);
1023  listSize = list_size(&contextsList);
1024  (void)pthread_mutex_unlock(&contextsList_lock);
1025  if (lrv < 0)
1026  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1027 
1028  free(threadContext);
1029 
1030  /* start a suicide alarm */
1031  if (AutoExit && (listSize < 1))
1032  {
1033  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1034  TIME_BEFORE_SUICIDE);
1035  alarm(TIME_BEFORE_SUICIDE);
1036  }
1037 
1038  return 0;
1039 }
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:101
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
list object
Definition: simclist.h:181
wait for a reader state change
Definition: winscard_msg.h:94
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
volatile SCARDHANDLE hLockId
Lock Id.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
get the client/server protocol version
Definition: winscard_msg.h:92
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:168
pthread_t pthThread
Event polling thread&#39;s ID.
Definition: winscard_svc.c:87
used by SCardEstablishContext()
Definition: winscard_msg.h:76
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:57
used by SCardEndTransaction()
Definition: winscard_msg.h:83
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:195
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:67
#define SCARD_LEAVE_CARD
Do nothing on close.
Definition: pcsclite.h:252
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
used by SCardConnect()
Definition: winscard_msg.h:79
uint32_t dwClientID
Connection ID used to reference the Client.
Definition: winscard_svc.c:86
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:47
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
static list_t contextsList
Context tracking list.
Definition: winscard_svc.c:78
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard.c:1374
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard.c:825
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
get the readers state
Definition: winscard_msg.h:93
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
header structure for client/server message data exchange.
Definition: winscard_msg.h:64
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:449
used by SCardReleaseContext()
Definition: winscard_msg.h:77
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
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:107
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:216
used by SCardReconnect()
Definition: winscard_msg.h:80
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:524
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
used by SCardTransmit()
Definition: winscard_msg.h:84
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:81
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:79
This handles card insertion/removal events, updates ATR, protocol, and status information.
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:231
stop waiting for a reader state change
Definition: winscard_msg.h:95
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard.c:1449
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:218
#define SCARD_RESET_CARD
Reset on close.
Definition: pcsclite.h:253
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
static const char * CommandsText[]
Handles messages received from Clients.
Definition: winscard_svc.c:280
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:49
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
Definition: winscard.c:1055
used by SCardControl()
Definition: winscard_msg.h:85
This keeps a list of defines for pcsc-lite.
Protocol Control Information (PCI)
Definition: pcsclite.h:79
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:1315
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:48
used by SCardSetAttrib()
Definition: winscard_msg.h:91
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:351
used by SCardDisconnect()
Definition: winscard_msg.h:81
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:246
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:90
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:1252
used by SCardCancel()
Definition: winscard_msg.h:88
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:56
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard.c:1097
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:1499
pthread_mutex_t cardsList_lock
lock for the above list
Definition: winscard_svc.c:85
pthread_mutex_t contextsList_lock
lock for the above list
Definition: winscard_svc.c:79
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:86
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:220
This handles debugging.