pcsc-lite  2.5.0
winscard_svc.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
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-2025
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 #include <stdbool.h>
56 
57 #include "pcscd.h"
58 #include "winscard.h"
59 #include "debuglog.h"
60 #include "winscard_msg.h"
61 #include "winscard_svc.h"
62 #include "sys_generic.h"
63 #include "utils.h"
64 #include "readerfactory.h"
65 #include "eventhandler.h"
66 #include "simclist.h"
67 #include "auth.h"
68 
75 extern bool AutoExit;
76 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
77 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
78 
80 pthread_mutex_t contextsList_lock;
82 struct _psContext
83 {
84  int32_t hContext;
85  list_t cardsList;
86  pthread_mutex_t cardsList_lock;
87  uint32_t dwClientID;
88  pthread_t pthThread;
89 };
90 typedef struct _psContext SCONTEXT;
91 
92 static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *);
93 static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *);
94 static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *);
95 static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *);
96 static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *);
97 static void MSGCleanupClient(SCONTEXT *);
98 
99 static void * ContextThread(LPVOID pdwIndex);
100 
101 extern int pcsclite_max_reader_context;
102 extern READER_CONTEXT ** sReadersContexts;
103 extern int16_t ReaderEvents;
104 
105 static int contextsListhContext_seeker(const void *el, const void *key)
106 {
107  const SCONTEXT * currentContext = (SCONTEXT *)el;
108 
109  if ((el == NULL) || (key == NULL))
110  {
111  Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%p, key=%p",
112  el, key);
113  return 0;
114  }
115 
116  if (currentContext->hContext == *(int32_t *)key)
117  return 1;
118  return 0;
119 }
120 
121 LONG ContextsInitialize(int customMaxThreadCounter,
122  int customMaxThreadCardHandles)
123 {
124  int lrv = 0;
125 
126  if (customMaxThreadCounter != 0)
127  contextMaxThreadCounter = customMaxThreadCounter;
128 
129  if (customMaxThreadCardHandles != 0)
130  contextMaxCardHandles = customMaxThreadCardHandles;
131 
132  lrv = list_init(&contextsList);
133  if (lrv < 0)
134  {
135  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
136  return -1;
137  }
138  lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
139  if (lrv < 0)
140  {
141  Log2(PCSC_LOG_CRITICAL,
142  "list_attributes_seeker failed with return value: %d", lrv);
143  return -1;
144  }
145 
146  (void)pthread_mutex_init(&contextsList_lock, NULL);
147 
148  return 1;
149 }
150 
151 void ContextsDeinitialize(void)
152 {
153  int listSize;
154  (void)pthread_mutex_lock(&contextsList_lock);
155  listSize = list_size(&contextsList);
156 #ifdef NO_LOG
157  (void)listSize;
158 #endif
159  Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize);
160 
161  /* terminate all the client threads */
162  int rv = list_iterator_start(&contextsList);
163  if (0 == rv)
164  Log1(PCSC_LOG_ERROR, "list_iterator_start failed");
165  else
166  {
167  while (list_iterator_hasnext(&contextsList))
168  {
169  SCONTEXT * elt = list_iterator_next(&contextsList);
170  Log3(PCSC_LOG_DEBUG, "Cancel dwClientID=%d hContext: %p",
171  elt->dwClientID, elt);
173  close(elt->dwClientID);
174  Log2(PCSC_LOG_DEBUG, "Waiting client: %d", elt->dwClientID);
175  pthread_join(elt->pthThread, NULL);
176  Log2(PCSC_LOG_INFO, "Client %d terminated", elt->dwClientID);
177  }
178  }
179  list_destroy(&contextsList);
180  (void)pthread_mutex_unlock(&contextsList_lock);
181 }
182 
193 LONG CreateContextThread(uint32_t *pdwClientID)
194 {
195  int rv;
196  int lrv;
197  int listSize;
198  SCONTEXT * newContext = NULL;
199  LONG retval = SCARD_E_NO_MEMORY;
200 
201  (void)pthread_mutex_lock(&contextsList_lock);
202 
203  listSize = list_size(&contextsList);
204  if (listSize >= contextMaxThreadCounter)
205  {
206  Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
207  goto out;
208  }
209 
210  /* Create the context for this thread. */
211  newContext = malloc(sizeof(*newContext));
212  if (NULL == newContext)
213  {
214  Log1(PCSC_LOG_CRITICAL, "Could not allocate new context");
215  goto out;
216  }
217  memset(newContext, 0, sizeof(*newContext));
218 
219  newContext->dwClientID = *pdwClientID;
220 
221  /* Initialise the list of card contexts */
222  lrv = list_init(&newContext->cardsList);
223  if (lrv < 0)
224  {
225  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
226  goto out;
227  }
228 
229  /* request to store copies, and provide the metric function */
230  list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
231 
232  /* Adding a comparator
233  * The stored type is SCARDHANDLE (long) but has only 32 bits
234  * useful even on a 64-bit CPU since the API between pcscd and
235  * libpcscliter uses "int32_t hCard;"
236  */
237  lrv = list_attributes_comparator(&newContext->cardsList,
238  list_comparator_int32_t);
239  if (lrv != 0)
240  {
241  Log2(PCSC_LOG_CRITICAL,
242  "list_attributes_comparator failed with return value: %d", lrv);
243  list_destroy(&newContext->cardsList);
244  goto out;
245  }
246 
247  (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
248 
249  lrv = list_append(&contextsList, newContext);
250  if (lrv < 0)
251  {
252  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
253  lrv);
254  list_destroy(&newContext->cardsList);
255  goto out;
256  }
257 
258  rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED,
259  (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
260  if (rv)
261  {
262  int lrv2;
263 
264  Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
265  lrv2 = list_delete(&contextsList, newContext);
266  if (lrv2 < 0)
267  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
268  list_destroy(&newContext->cardsList);
269  goto out;
270  }
271 
272  /* disable any exit alarm */
273  if (AutoExit)
274  alarm(0);
275 
276  retval = SCARD_S_SUCCESS;
277 
278 out:
279  (void)pthread_mutex_unlock(&contextsList_lock);
280 
281  if (retval != SCARD_S_SUCCESS)
282  {
283  if (newContext)
284  free(newContext);
285  (void)close(*pdwClientID);
286  }
287 
288  return retval;
289 }
290 
291 /*
292  * A list of local functions used to keep track of clients and their
293  * connections
294  */
295 
304 #ifndef NO_LOG
305 static const char *CommandsText[] = {
306  "NULL",
307  "ESTABLISH_CONTEXT", /* 0x01 */
308  "RELEASE_CONTEXT",
309  "LIST_READERS",
310  "CONNECT",
311  "RECONNECT", /* 0x05 */
312  "DISCONNECT",
313  "BEGIN_TRANSACTION",
314  "END_TRANSACTION",
315  "TRANSMIT",
316  "CONTROL", /* 0x0A */
317  "STATUS",
318  "GET_STATUS_CHANGE",
319  "CANCEL",
320  "CANCEL_TRANSACTION",
321  "GET_ATTRIB", /* 0x0F */
322  "SET_ATTRIB",
323  "CMD_VERSION",
324  "CMD_GET_READERS_STATE",
325  "CMD_WAIT_READER_STATE_CHANGE",
326  "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
327  "CMD_GET_READER_EVENTS",
328  "CMD_GET_READERS_STATE_SIZE",
329  "CMD_GET_READERS_STATE_ARRAY",
330  "NULL"
331 };
332 #endif
333 
334 #define READ_BODY(v) \
335  do { \
336  if (header.size != sizeof(v)) \
337  goto wrong_length; \
338  ret = MessageReceive(&v, sizeof(v), filedes); \
339  if (ret != SCARD_S_SUCCESS) { \
340  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
341  goto exit; \
342  } \
343  } while (0)
344 
345 #define WRITE_BODY(v) \
346  WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
347 #define WRITE_BODY_WITH_COMMAND(command, v) \
348  do { \
349  LogRv4(PCSC_LOG_DEBUG, v.rv, "%s for client %d", command, filedes); \
350  ret = MessageSend(&v, sizeof(v), filedes); \
351  } while (0)
352 
353 static void * ContextThread(LPVOID newContext)
354 {
355  SCONTEXT * threadContext = (SCONTEXT *) newContext;
356  int32_t filedes = threadContext->dwClientID;
357  bool old_reader_state_api = false;
358 
359  if (IsClientAuthorized(filedes, "access_pcsc", NULL) == 0)
360  {
361  Log1(PCSC_LOG_CRITICAL, "Rejected unauthorized PC/SC client");
362  goto exit;
363  }
364  else
365  {
366  Log1(PCSC_LOG_DEBUG, "Authorized PC/SC client");
367  }
368 
369  Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
370  threadContext->dwClientID, threadContext);
371 
372  while (1)
373  {
374  struct rxHeader header;
375  int32_t ret = MessageReceive(&header, sizeof(header), filedes);
376 
377  if (ret != SCARD_S_SUCCESS)
378  {
379  /* Clean up the dead client */
380  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
382  goto exit;
383  }
384 
385  if ((header.command > CMD_ENUM_FIRST)
386  && (header.command < CMD_ENUM_LAST))
387  Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
388  CommandsText[header.command], filedes);
389 
390  switch (header.command)
391  {
392  /* pcsc-lite client/server protocol version */
393  case CMD_VERSION:
394  {
395  struct version_struct veStr;
396 
397  READ_BODY(veStr);
398 
399  Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
400  veStr.major, veStr.minor);
401 
402  veStr.rv = SCARD_S_SUCCESS;
403 
404  /* client and server use different protocol */
405  if ((veStr.major != PROTOCOL_VERSION_MAJOR)
406  || (veStr.minor != PROTOCOL_VERSION_MINOR))
407  {
408  Log1(PCSC_LOG_CRITICAL,
409  "Communication protocol mismatch!");
410  Log3(PCSC_LOG_ERROR, "Client protocol is %d:%d",
411  veStr.major, veStr.minor);
412  Log3(PCSC_LOG_ERROR, "Server protocol is %d:%d",
414 
415  /* the protocol major corresponds and the minior
416  * indicates the protocol is just old enough */
417  if (PROTOCOL_VERSION_MAJOR == veStr.major
419  && veStr.minor < PROTOCOL_VERSION_MINOR)
420  {
421  Log1(PCSC_LOG_INFO, "Enable backward compatibility");
422  old_reader_state_api = true;
423  }
424  else
425  /* any other case is unsupported */
426  veStr.rv = SCARD_E_SERVICE_STOPPED;
427  }
428 
429  /* set the server protocol version */
430  veStr.major = PROTOCOL_VERSION_MAJOR;
431  veStr.minor = PROTOCOL_VERSION_MINOR;
432 
433  /* send back the response */
434  WRITE_BODY(veStr);
435  }
436  break;
437 
439  {
440  /* nothing to read */
441 
442 #ifdef USE_USB
443  /* wait until all readers are ready */
444  RFWaitForReaderInit();
445 #endif
446 
447  MSGSendReaderStates(filedes, true);
448  }
449  break;
450 
452  {
453  /* nothing to read */
454 
455 #ifdef USE_USB
456  /* wait until all readers are ready */
457  RFWaitForReaderInit();
458 #endif
459 
460  /* add the client fd to the list and dump the readers state */
461  EHRegisterClientForEvent(filedes);
462  if (old_reader_state_api)
463  MSGSendReaderStates(filedes, true);
464  }
465  break;
466 
468  {
469  struct wait_reader_state_change waStr =
470  {
471  .timeOut = 0,
472  .rv = SCARD_S_SUCCESS
473  };
474  LONG rv;
475 
476  /* remove the client fd from the list */
477  rv = EHUnregisterClientForEvent(filedes);
478 
479  /* send the response only if the client was still in the
480  * list */
481  if (rv != SCARD_F_INTERNAL_ERROR)
482  {
483  waStr.rv = rv;
484  WRITE_BODY(waStr);
485  }
486  }
487  break;
488 
490  {
491  /* nothing to read */
492 
493  struct get_reader_events readerEvents =
494  {
495  .readerEvents = ReaderEvents,
496  .rv = SCARD_S_SUCCESS
497  };
498 
499  WRITE_BODY(readerEvents);
500  }
501  break;
502 
503  case CMD_GET_READERS_STATE_SIZE:
504  {
505  /* nothing to read */
506  int32_t array_size = pcsclite_max_reader_context;
507 
508  MessageSend(&array_size, sizeof(array_size), filedes);
509  }
510  break;
511 
513  {
514  /* nothing to read */
515 
516 #ifdef USE_USB
517  /* wait until all readers are ready */
518  RFWaitForReaderInit();
519 #endif
520 
521  MSGSendReaderStates(filedes, false);
522  }
523  break;
524 
526  {
527  struct establish_struct esStr;
528  SCARDCONTEXT hContext;
529 
530  READ_BODY(esStr);
531 
532  hContext = esStr.hContext;
533  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
534  &hContext);
535  esStr.hContext = hContext;
536 
537  if (esStr.rv == SCARD_S_SUCCESS)
538  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
539 
540  WRITE_BODY(esStr);
541  }
542  break;
543 
545  {
546  struct release_struct reStr;
547 
548  READ_BODY(reStr);
549 
550  reStr.rv = SCardReleaseContext(reStr.hContext);
551 
552  if (reStr.rv == SCARD_S_SUCCESS)
553  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
554 
555  WRITE_BODY(reStr);
556  }
557  break;
558 
559  case SCARD_CONNECT:
560  {
561  struct connect_struct coStr;
562  SCARDHANDLE hCard;
563  DWORD dwActiveProtocol;
564 
565  READ_BODY(coStr);
566 
567  coStr.szReader[sizeof(coStr.szReader)-1] = 0;
568  hCard = coStr.hCard;
569  dwActiveProtocol = coStr.dwActiveProtocol;
570 
571  if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
572  {
573  Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
574 
575  coStr.rv = SCARD_W_SECURITY_VIOLATION;
576  hCard = -1;
577  dwActiveProtocol = -1;
578  }
579  else
580  {
581  Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
582 
583  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
584  coStr.dwShareMode, coStr.dwPreferredProtocols,
585  &hCard, &dwActiveProtocol);
586  }
587 
588  coStr.hCard = hCard;
589  coStr.dwActiveProtocol = dwActiveProtocol;
590 
591  if (coStr.rv == SCARD_S_SUCCESS)
592  {
593  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
594  threadContext);
595 
596  /* if storing the hCard fails we disconnect */
597  if (coStr.rv != SCARD_S_SUCCESS)
598  SCardDisconnect(coStr.hCard, SCARD_LEAVE_CARD);
599  }
600 
601  WRITE_BODY(coStr);
602  }
603  break;
604 
605  case SCARD_RECONNECT:
606  {
607  struct reconnect_struct rcStr;
608  DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
609 
610  READ_BODY(rcStr);
611 
612  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
613  goto exit;
614 
615  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
616  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
617  &dwActiveProtocol);
618  rcStr.dwActiveProtocol = dwActiveProtocol;
619 
620  WRITE_BODY(rcStr);
621  }
622  break;
623 
624  case SCARD_DISCONNECT:
625  {
626  struct disconnect_struct diStr;
627 
628  READ_BODY(diStr);
629 
630  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
631  goto exit;
632 
633  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
634 
635  if (SCARD_S_SUCCESS == diStr.rv)
636  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
637 
638  WRITE_BODY(diStr);
639  }
640  break;
641 
643  {
644  struct begin_struct beStr;
645 
646  READ_BODY(beStr);
647 
648  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
649  goto exit;
650 
651  beStr.rv = SCardBeginTransaction(beStr.hCard);
652 
653  WRITE_BODY(beStr);
654  }
655  break;
656 
658  {
659  struct end_struct enStr;
660 
661  READ_BODY(enStr);
662 
663  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
664  goto exit;
665 
666  enStr.rv = SCardEndTransaction(enStr.hCard,
667  enStr.dwDisposition);
668 
669  WRITE_BODY(enStr);
670  }
671  break;
672 
673  case SCARD_CANCEL:
674  {
675  struct cancel_struct caStr;
676  SCONTEXT * psTargetContext = NULL;
677 
678  READ_BODY(caStr);
679 
680  /* find the client */
681  (void)pthread_mutex_lock(&contextsList_lock);
682  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
683  &caStr.hContext);
684  (void)pthread_mutex_unlock(&contextsList_lock);
685 
686  /* default value = error */
687  caStr.rv = SCARD_E_INVALID_HANDLE;
688 
689  if (psTargetContext != NULL)
690  {
691  uint32_t fd = psTargetContext->dwClientID;
692  LONG rv;
693 
694  /* the client should not receive the event
695  * notification now the waiting has been cancelled */
697 
698  /* signal the client only if it was still waiting */
699  if (SCARD_S_SUCCESS == rv)
700  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
701  else
702  caStr.rv = SCARD_S_SUCCESS;
703  }
704 
705  WRITE_BODY(caStr);
706  }
707  break;
708 
709  case SCARD_STATUS:
710  {
711  struct status_struct stStr;
712 
713  READ_BODY(stStr);
714 
715  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
716  goto exit;
717 
718  /* only hCard and return value are used by the client */
719  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
720  NULL, 0, NULL);
721 
722  WRITE_BODY(stStr);
723  }
724  break;
725 
726  case SCARD_TRANSMIT:
727  {
728  struct transmit_struct trStr;
729  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
730  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
731  SCARD_IO_REQUEST ioSendPci;
732  SCARD_IO_REQUEST ioRecvPci;
733  DWORD cbRecvLength;
734 
735  READ_BODY(trStr);
736 
737  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
738  goto exit;
739 
740  /* avoids buffer overflow */
741  if (trStr.cbSendLength > sizeof(pbSendBuffer))
742  goto buffer_overflow;
743 
744  /* read sent buffer */
745  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
746  if (ret != SCARD_S_SUCCESS)
747  {
748  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
749  goto exit;
750  }
751 
752  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
753  ioSendPci.cbPciLength = trStr.ioSendPciLength;
754  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
755  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
756  cbRecvLength = sizeof pbRecvBuffer;
757 
758  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
759  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
760  pbRecvBuffer, &cbRecvLength);
761 
762  if (cbRecvLength > trStr.pcbRecvLength)
763  /* The client buffer is not large enough.
764  * The pbRecvBuffer buffer will NOT be sent a few
765  * lines below. So no buffer overflow is expected. */
766  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
767 
768  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
769  trStr.ioSendPciLength = ioSendPci.cbPciLength;
770  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
771  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
772  trStr.pcbRecvLength = cbRecvLength;
773 
774  WRITE_BODY(trStr);
775 
776  /* write received buffer */
777  if (SCARD_S_SUCCESS == trStr.rv)
778  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
779  }
780  break;
781 
782  case SCARD_CONTROL:
783  {
784  struct control_struct ctStr;
785  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
786  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
787  DWORD dwBytesReturned;
788 
789  READ_BODY(ctStr);
790 
791  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
792  goto exit;
793 
794  /* avoids buffer overflow */
795  if (ctStr.cbSendLength > sizeof(pbSendBuffer))
796  {
797  goto buffer_overflow;
798  }
799 
800  /* read sent buffer */
801  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
802  if (ret != SCARD_S_SUCCESS)
803  {
804  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
805  goto exit;
806  }
807 
808  dwBytesReturned = ctStr.dwBytesReturned;
809 
810  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
811  pbSendBuffer, ctStr.cbSendLength,
812  pbRecvBuffer, sizeof pbRecvBuffer,
813  &dwBytesReturned);
814 
815  if (dwBytesReturned > ctStr.cbRecvLength)
816  /* The client buffer is not large enough.
817  * The pbRecvBuffer buffer will NOT be sent a few
818  * lines below. So no buffer overflow is expected. */
819  ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
820 
821  ctStr.dwBytesReturned = dwBytesReturned;
822 
823  WRITE_BODY(ctStr);
824 
825  /* write received buffer */
826  if (SCARD_S_SUCCESS == ctStr.rv)
827  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
828  }
829  break;
830 
831  case SCARD_GET_ATTRIB:
832  {
833  struct getset_struct gsStr;
834  DWORD cbAttrLen;
835 
836  READ_BODY(gsStr);
837 
838  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
839  goto exit;
840 
841  /* avoids buffer overflow */
842  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
843  goto buffer_overflow;
844 
845  cbAttrLen = gsStr.cbAttrLen;
846 
847  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
848  gsStr.pbAttr, &cbAttrLen);
849 
850  gsStr.cbAttrLen = cbAttrLen;
851 
852  WRITE_BODY(gsStr);
853  }
854  break;
855 
856  case SCARD_SET_ATTRIB:
857  {
858  struct getset_struct gsStr;
859 
860  READ_BODY(gsStr);
861 
862  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
863  goto exit;
864 
865  /* avoids buffer overflow */
866  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
867  goto buffer_overflow;
868 
869  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
870  gsStr.pbAttr, gsStr.cbAttrLen);
871 
872  WRITE_BODY(gsStr);
873  }
874  break;
875 
876  default:
877  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
878  goto exit;
879  }
880 
881  /* MessageSend() failed */
882  if (ret != SCARD_S_SUCCESS)
883  {
884  /* Clean up the dead client */
885  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
886  goto exit;
887  }
888  }
889 
890 buffer_overflow:
891  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
892  goto exit;
893 wrong_length:
894  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
895 exit:
896  (void)close(filedes);
897  MSGCleanupClient(threadContext);
898  (void)pthread_exit((LPVOID) NULL);
899 }
900 
901 LONG MSGSignalClient(uint32_t filedes, LONG rv)
902 {
903  uint32_t ret;
904  struct wait_reader_state_change waStr =
905  {
906  .timeOut = 0,
907  .rv = SCARD_S_SUCCESS
908  };
909 
910  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
911 
912  waStr.rv = rv;
913  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
914 
915  return ret;
916 } /* MSGSignalClient */
917 
918 LONG MSGSendReaderStates(uint32_t filedes, bool old_api)
919 {
920  uint32_t ret = SCARD_S_SUCCESS;
921 
922  Log2(PCSC_LOG_DEBUG, "Send reader states: %d", filedes);
923 
924  int length = pcsclite_max_reader_context;
925  if (old_api)
926  {
927  if (length > PCSCLITE_MAX_READERS_CONTEXTS)
929  }
930 
931  /* dump the readers state */
932  for (int i=0; i<length; i++)
933  {
934  ret = MessageSend(&sReadersContexts[i]->readerState,
935  sizeof(READER_STATE), filedes);
936  }
937 
938  if (old_api)
939  {
940  /* complete the list */
941  if (length < PCSCLITE_MAX_READERS_CONTEXTS)
942  {
943  READER_STATE readerState = { 0 };
944  for (int i=length; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
945  ret = MessageSend(&readerState,
946  sizeof(READER_STATE), filedes);
947  }
948  }
949 
950  return ret;
951 }
952 
953 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
954 {
955  threadContext->hContext = hContext;
956  return SCARD_S_SUCCESS;
957 }
958 
959 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
960 {
961  LONG rv;
962  int lrv;
963 
964  if (0 == threadContext->hContext)
965  {
966  Log1(PCSC_LOG_ERROR, "Invalidated handle");
967  return SCARD_E_INVALID_HANDLE;
968  }
969 
970  if (threadContext->hContext != hContext)
971  return SCARD_E_INVALID_VALUE;
972 
973  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
974  while (list_size(&threadContext->cardsList) != 0)
975  {
976  READER_CONTEXT * rContext = NULL;
977  SCARDHANDLE hCard;
978  void *ptr;
979 
980  /*
981  * Disconnect each of these just in case
982  */
983  ptr = list_get_at(&threadContext->cardsList, 0);
984  if (NULL == ptr)
985  {
986  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
987  continue;
988  }
989  hCard = *(int32_t *)ptr;
990 
991  /*
992  * Unlock the sharing. If the reader or handle already
993  * disappeared, skip the disconnection part and just delete the
994  * orphan handle.
995  */
996  rv = RFReaderInfoById(hCard, &rContext);
997  if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INVALID_VALUE
999  {
1000  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1001  return rv;
1002  }
1003 
1004  if (rContext)
1005  {
1006  if (0 == rContext->hLockId)
1007  {
1008  /* no lock. Just leave the card */
1009  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
1010  }
1011  else
1012  {
1013  if (hCard != rContext->hLockId)
1014  {
1015  /*
1016  * if the card is locked by someone else we do not reset it
1017  */
1018 
1019  /* decrement card use */
1020  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
1021  }
1022  else
1023  {
1024  /* release the lock */
1025  rContext->hLockId = 0;
1026 
1027  /*
1028  * We will use SCardStatus to see if the card has been
1029  * reset there is no need to reset each time
1030  * Disconnect is called
1031  */
1032  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
1033 
1034  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
1035  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
1036  else
1037  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
1038  }
1039  }
1040  }
1041 
1042  /* Remove entry from the list */
1043  lrv = list_delete_at(&threadContext->cardsList, 0);
1044  if (lrv < 0)
1045  Log2(PCSC_LOG_CRITICAL,
1046  "list_delete_at failed with return value: %d", lrv);
1047 
1048  if (rContext) {
1049  UNREF_READER(rContext)
1050  }
1051  }
1052  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1053 
1054  /* We only mark the context as no longer in use.
1055  * The memory is freed in MSGCleanupCLient() */
1056  threadContext->hContext = 0;
1057 
1058  return SCARD_S_SUCCESS;
1059 }
1060 
1061 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
1062  SCONTEXT * threadContext)
1063 {
1064  LONG retval = SCARD_E_INVALID_VALUE;
1065 
1066  if (0 == threadContext->hContext)
1067  {
1068  Log1(PCSC_LOG_ERROR, "Invalidated handle");
1069  return SCARD_E_INVALID_HANDLE;
1070  }
1071 
1072  if (threadContext->hContext == hContext)
1073  {
1074  /*
1075  * Find an empty spot to put the hCard value
1076  */
1077  int listLength;
1078 
1079  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1080 
1081  listLength = list_size(&threadContext->cardsList);
1082  if (listLength >= contextMaxCardHandles)
1083  {
1084  Log4(PCSC_LOG_DEBUG,
1085  "Too many card handles for thread context @%p: %d (max is %d). "
1086  "Restart pcscd with --max-card-handle-per-thread value",
1087  threadContext, listLength, contextMaxCardHandles);
1088  retval = SCARD_E_NO_MEMORY;
1089  }
1090  else
1091  {
1092  int lrv;
1093 
1094  lrv = list_append(&threadContext->cardsList, &hCard);
1095  if (lrv < 0)
1096  {
1097  Log2(PCSC_LOG_CRITICAL,
1098  "list_append failed with return value: %d", lrv);
1099  retval = SCARD_E_NO_MEMORY;
1100  }
1101  else
1102  retval = SCARD_S_SUCCESS;
1103  }
1104 
1105  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1106  }
1107 
1108  return retval;
1109 }
1110 
1111 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
1112 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
1113 {
1114  int lrv;
1115 
1116  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1117  lrv = list_delete(&threadContext->cardsList, &hCard);
1118  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1119  if (lrv < 0)
1120  {
1121  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
1122  return SCARD_E_INVALID_VALUE;
1123  }
1124 
1125  return SCARD_S_SUCCESS;
1126 }
1127 
1128 
1129 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
1130  SCONTEXT * threadContext)
1131 {
1132  int list_index = 0;
1133 
1134  if (0 == threadContext->hContext)
1135  {
1136  /* the handle is no more valid. After SCardReleaseContext() for
1137  * example */
1138  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
1139  return -1;
1140  }
1141 
1142  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1143  list_index = list_locate(&threadContext->cardsList, &hCard);
1144  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1145  if (list_index >= 0)
1146  return 0;
1147 
1148  /* Must be a rogue client, debug log and sleep a couple of seconds */
1149  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1150  (void)SYS_Sleep(2);
1151 
1152  return -1;
1153 }
1154 
1155 
1156 /* Should be called just prior to exiting the thread as it de-allocates
1157  * the thread memory structures
1158  */
1159 static void MSGCleanupClient(SCONTEXT * threadContext)
1160 {
1161  int lrv;
1162  int listSize;
1163 
1164  if (threadContext->hContext != 0)
1165  {
1166  (void)SCardReleaseContext(threadContext->hContext);
1167  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1168  }
1169 
1170  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1171  list_destroy(&threadContext->cardsList);
1172  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1173 
1174  Log3(PCSC_LOG_DEBUG,
1175  "Thread is stopping: dwClientID=%d, threadContext @%p",
1176  threadContext->dwClientID, threadContext);
1177 
1178  /* Clear the struct to ensure that we detect
1179  * access to de-allocated memory
1180  * Hopefully the compiler won't optimise it out */
1181  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1182  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1183 
1184  (void)pthread_mutex_lock(&contextsList_lock);
1185  lrv = list_delete(&contextsList, threadContext);
1186  listSize = list_size(&contextsList);
1187  (void)pthread_mutex_unlock(&contextsList_lock);
1188  if (lrv < 0)
1189  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1190 
1191  free(threadContext);
1192 
1193  /* start an exit alarm */
1194  if (AutoExit && (listSize < 1))
1195  {
1196  Log2(PCSC_LOG_DEBUG, "Starting exit alarm in %d seconds",
1197  TIME_BEFORE_SUICIDE);
1198  alarm(TIME_BEFORE_SUICIDE);
1199  }
1200 
1201  return;
1202 }
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:89
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:151
list object
Definition: simclist.h:181
wait for a reader state change
Definition: winscard_msg.h:101
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:217
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:239
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:205
get the client/server protocol version
Definition: winscard_msg.h:99
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:193
pthread_t pthThread
Event polling thread's ID.
Definition: winscard_svc.c:88
used by SCardEstablishContext()
Definition: winscard_msg.h:83
used by SCardEndTransaction()
Definition: winscard_msg.h:90
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
#define SCARD_LEAVE_CARD
Do nothing on close.
Definition: pcsclite.h:253
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
Definition: pcsclite.h:222
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:62
get the readers state array
Definition: winscard_msg.h:105
used by SCardConnect()
Definition: winscard_msg.h:86
uint32_t dwClientID
Connection ID used to reference the Client.
Definition: winscard_svc.c:87
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:50
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:182
static list_t contextsList
Context tracking list.
Definition: winscard_svc.c:79
bool AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:74
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:140
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:194
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:128
_Atomic SCARDHANDLE hLockId
Lock Id.
Definition: readers.h:124
get the readers state
Definition: winscard_msg.h:100
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:61
header structure for client/server message data exchange.
Definition: winscard_msg.h:71
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
Definition: winscard_msg.c:461
used by SCardReleaseContext()
Definition: winscard_msg.h:84
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:228
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:167
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:119
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:285
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:271
This defines some structures and #defines to be used over the transport layer.
get the number of reader events
Definition: winscard_msg.h:103
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:117
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:217
used by SCardReconnect()
Definition: winscard_msg.h:87
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:299
used by SCardTransmit()
Definition: winscard_msg.h:91
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister a client If no client is found then do not log an error.
Definition: eventhandler.c:81
This handles card insertion/removal events, updates ATR, protocol, and status information.
stop waiting for a reader state change
Definition: winscard_msg.h:102
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:219
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:240
#define SCARD_RESET_CARD
Reset on close.
Definition: pcsclite.h:254
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:305
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: readers.h:49
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
#define PROTOCOL_VERSION_MINOR_SERVER_BACKWARD
Minor version the server also supports.
Definition: winscard_msg.h:56
used by SCardControl()
Definition: winscard_msg.h:92
int pcsclite_max_reader_context
Area used to read status information about the readers.
Definition: readerfactory.c:70
Protocol Control Information (PCI)
Definition: pcsclite.h:79
used by SCardSetAttrib()
Definition: winscard_msg.h:98
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:357
used by SCardDisconnect()
Definition: winscard_msg.h:88
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:256
This keeps track of a list of currently available reader structures.
used by SCardGetAttrib()
Definition: winscard_msg.h:97
used by SCardCancel()
Definition: winscard_msg.h:95
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
pthread_mutex_t cardsList_lock
lock for the above list
Definition: winscard_svc.c:86
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition: pcsclite.h:167
pthread_mutex_t contextsList_lock
lock for the above list
Definition: winscard_svc.c:80
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
used by SCardStatus()
Definition: winscard_msg.h:93
This handles smart card reader communications.
This handles debugging.