pcsc-lite  1.8.24
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-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 void 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 #ifdef NO_LOG
153  (void)listSize;
154 #endif
155  Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize);
156  /* This is currently a no-op. It should terminate the threads properly. */
157 
158  list_destroy(&contextsList);
159 }
160 
171 LONG CreateContextThread(uint32_t *pdwClientID)
172 {
173  int rv;
174  int lrv;
175  int listSize;
176  SCONTEXT * newContext = NULL;
177  LONG retval = SCARD_E_NO_MEMORY;
178 
179  (void)pthread_mutex_lock(&contextsList_lock);
180 
181  listSize = list_size(&contextsList);
182  if (listSize >= contextMaxThreadCounter)
183  {
184  Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
185  goto out;
186  }
187 
188  /* Create the context for this thread. */
189  newContext = malloc(sizeof(*newContext));
190  if (NULL == newContext)
191  {
192  Log1(PCSC_LOG_CRITICAL, "Could not allocate new context");
193  goto out;
194  }
195  memset(newContext, 0, sizeof(*newContext));
196 
197  newContext->dwClientID = *pdwClientID;
198 
199  /* Initialise the list of card contexts */
200  lrv = list_init(&newContext->cardsList);
201  if (lrv < 0)
202  {
203  Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
204  goto out;
205  }
206 
207  /* request to store copies, and provide the metric function */
208  list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
209 
210  /* Adding a comparator
211  * The stored type is SCARDHANDLE (long) but has only 32 bits
212  * usefull even on a 64-bit CPU since the API between pcscd and
213  * libpcscliter uses "int32_t hCard;"
214  */
215  lrv = list_attributes_comparator(&newContext->cardsList,
216  list_comparator_int32_t);
217  if (lrv != 0)
218  {
219  Log2(PCSC_LOG_CRITICAL,
220  "list_attributes_comparator failed with return value: %d", lrv);
221  list_destroy(&newContext->cardsList);
222  goto out;
223  }
224 
225  (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
226 
227  lrv = list_append(&contextsList, newContext);
228  if (lrv < 0)
229  {
230  Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
231  lrv);
232  list_destroy(&newContext->cardsList);
233  goto out;
234  }
235 
236  rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED,
237  (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
238  if (rv)
239  {
240  int lrv2;
241 
242  Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
243  lrv2 = list_delete(&contextsList, newContext);
244  if (lrv2 < 0)
245  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
246  list_destroy(&newContext->cardsList);
247  goto out;
248  }
249 
250  /* disable any suicide alarm */
251  if (AutoExit)
252  alarm(0);
253 
254  retval = SCARD_S_SUCCESS;
255 
256 out:
257  (void)pthread_mutex_unlock(&contextsList_lock);
258 
259  if (retval != SCARD_S_SUCCESS)
260  {
261  if (newContext)
262  free(newContext);
263  (void)close(*pdwClientID);
264  }
265 
266  return retval;
267 }
268 
269 /*
270  * A list of local functions used to keep track of clients and their
271  * connections
272  */
273 
282 #ifndef NO_LOG
283 static const char *CommandsText[] = {
284  "NULL",
285  "ESTABLISH_CONTEXT", /* 0x01 */
286  "RELEASE_CONTEXT",
287  "LIST_READERS",
288  "CONNECT",
289  "RECONNECT", /* 0x05 */
290  "DISCONNECT",
291  "BEGIN_TRANSACTION",
292  "END_TRANSACTION",
293  "TRANSMIT",
294  "CONTROL", /* 0x0A */
295  "STATUS",
296  "GET_STATUS_CHANGE",
297  "CANCEL",
298  "CANCEL_TRANSACTION",
299  "GET_ATTRIB", /* 0x0F */
300  "SET_ATTRIB",
301  "CMD_VERSION",
302  "CMD_GET_READERS_STATE",
303  "CMD_WAIT_READER_STATE_CHANGE",
304  "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
305  "NULL"
306 };
307 #endif
308 
309 #define READ_BODY(v) \
310  do { \
311  if (header.size != sizeof(v)) \
312  goto wrong_length; \
313  ret = MessageReceive(&v, sizeof(v), filedes); \
314  if (ret != SCARD_S_SUCCESS) { \
315  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
316  goto exit; \
317  } \
318  } while (0)
319 
320 #define WRITE_BODY(v) \
321  WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
322 #define WRITE_BODY_WITH_COMMAND(command, v) \
323  do { \
324  Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
325  ret = MessageSend(&v, sizeof(v), filedes); \
326  } while (0)
327 
328 static void * ContextThread(LPVOID newContext)
329 {
330  SCONTEXT * threadContext = (SCONTEXT *) newContext;
331  int32_t filedes = threadContext->dwClientID;
332 
333  if (IsClientAuthorized(filedes, "access_pcsc", NULL) == 0)
334  {
335  Log1(PCSC_LOG_CRITICAL, "Rejected unauthorized PC/SC client");
336  goto exit;
337  }
338  else
339  {
340  Log1(PCSC_LOG_DEBUG, "Authorized PC/SC client");
341  }
342 
343  Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
344  threadContext->dwClientID, threadContext);
345 
346  while (1)
347  {
348  struct rxHeader header;
349  int32_t ret = MessageReceive(&header, sizeof(header), filedes);
350 
351  if (ret != SCARD_S_SUCCESS)
352  {
353  /* Clean up the dead client */
354  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
356  goto exit;
357  }
358 
359  if ((header.command > CMD_ENUM_FIRST)
360  && (header.command < CMD_ENUM_LAST))
361  Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
362  CommandsText[header.command], filedes);
363 
364  switch (header.command)
365  {
366  /* pcsc-lite client/server protocol version */
367  case CMD_VERSION:
368  {
369  struct version_struct veStr;
370 
371  READ_BODY(veStr);
372 
373  Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
374  veStr.major, veStr.minor);
375 
376  veStr.rv = SCARD_S_SUCCESS;
377 
378  /* client and server use different protocol */
379  if ((veStr.major != PROTOCOL_VERSION_MAJOR)
380  || (veStr.minor != PROTOCOL_VERSION_MINOR))
381  {
382  Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d",
383  veStr.major, veStr.minor);
384  Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d",
386  veStr.rv = SCARD_E_NO_SERVICE;
387  }
388 
389  /* set the server protocol version */
390  veStr.major = PROTOCOL_VERSION_MAJOR;
391  veStr.minor = PROTOCOL_VERSION_MINOR;
392 
393  /* send back the response */
394  WRITE_BODY(veStr);
395  }
396  break;
397 
399  {
400  /* nothing to read */
401 
402 #ifdef USE_USB
403  /* wait until all readers are ready */
404  RFWaitForReaderInit();
405 #endif
406 
407  /* dump the readers state */
408  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
409  }
410  break;
411 
413  {
414  /* nothing to read */
415 
416 #ifdef USE_USB
417  /* wait until all readers are ready */
418  RFWaitForReaderInit();
419 #endif
420 
421  /* add the client fd to the list and dump the readers state */
422  EHRegisterClientForEvent(filedes);
423  }
424  break;
425 
427  {
428  struct wait_reader_state_change waStr =
429  {
430  .timeOut = 0,
431  .rv = 0
432  };
433 
434  /* remove the client fd from the list */
435  waStr.rv = EHUnregisterClientForEvent(filedes);
436 
437  /* send the response only if the client was still in the
438  * list */
439  if (waStr.rv != SCARD_F_INTERNAL_ERROR)
440  WRITE_BODY(waStr);
441  }
442  break;
443 
445  {
446  struct establish_struct esStr;
447  SCARDCONTEXT hContext;
448 
449  READ_BODY(esStr);
450 
451  hContext = esStr.hContext;
452  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
453  &hContext);
454  esStr.hContext = hContext;
455 
456  if (esStr.rv == SCARD_S_SUCCESS)
457  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
458 
459  WRITE_BODY(esStr);
460  }
461  break;
462 
464  {
465  struct release_struct reStr;
466 
467  READ_BODY(reStr);
468 
469  reStr.rv = SCardReleaseContext(reStr.hContext);
470 
471  if (reStr.rv == SCARD_S_SUCCESS)
472  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
473 
474  WRITE_BODY(reStr);
475  }
476  break;
477 
478  case SCARD_CONNECT:
479  {
480  struct connect_struct coStr;
481  SCARDHANDLE hCard;
482  DWORD dwActiveProtocol;
483 
484  READ_BODY(coStr);
485 
486  coStr.szReader[sizeof(coStr.szReader)-1] = 0;
487  hCard = coStr.hCard;
488  dwActiveProtocol = coStr.dwActiveProtocol;
489 
490  if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
491  {
492  Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
493  goto exit;
494  }
495  else
496  {
497  Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
498  }
499 
500  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
501  coStr.dwShareMode, coStr.dwPreferredProtocols,
502  &hCard, &dwActiveProtocol);
503 
504  coStr.hCard = hCard;
505  coStr.dwActiveProtocol = dwActiveProtocol;
506 
507  if (coStr.rv == SCARD_S_SUCCESS)
508  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
509  threadContext);
510 
511  WRITE_BODY(coStr);
512  }
513  break;
514 
515  case SCARD_RECONNECT:
516  {
517  struct reconnect_struct rcStr;
518  DWORD dwActiveProtocol;
519 
520  READ_BODY(rcStr);
521 
522  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
523  goto exit;
524 
525  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
526  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
527  &dwActiveProtocol);
528  rcStr.dwActiveProtocol = dwActiveProtocol;
529 
530  WRITE_BODY(rcStr);
531  }
532  break;
533 
534  case SCARD_DISCONNECT:
535  {
536  struct disconnect_struct diStr;
537 
538  READ_BODY(diStr);
539 
540  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
541  goto exit;
542 
543  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
544 
545  if (SCARD_S_SUCCESS == diStr.rv)
546  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
547 
548  WRITE_BODY(diStr);
549  }
550  break;
551 
553  {
554  struct begin_struct beStr;
555 
556  READ_BODY(beStr);
557 
558  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
559  goto exit;
560 
561  beStr.rv = SCardBeginTransaction(beStr.hCard);
562 
563  WRITE_BODY(beStr);
564  }
565  break;
566 
568  {
569  struct end_struct enStr;
570 
571  READ_BODY(enStr);
572 
573  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
574  goto exit;
575 
576  enStr.rv = SCardEndTransaction(enStr.hCard,
577  enStr.dwDisposition);
578 
579  WRITE_BODY(enStr);
580  }
581  break;
582 
583  case SCARD_CANCEL:
584  {
585  struct cancel_struct caStr;
586  SCONTEXT * psTargetContext = NULL;
587 
588  READ_BODY(caStr);
589 
590  /* find the client */
591  (void)pthread_mutex_lock(&contextsList_lock);
592  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
593  &caStr.hContext);
594  (void)pthread_mutex_unlock(&contextsList_lock);
595 
596  /* default value = error */
597  caStr.rv = SCARD_E_INVALID_HANDLE;
598 
599  if (psTargetContext != NULL)
600  {
601  uint32_t fd = psTargetContext->dwClientID;
602  LONG rv;
603 
604  /* the client should not receive the event
605  * notification now the waiting has been cancelled */
607 
608  /* signal the client only if it was still waiting */
609  if (SCARD_S_SUCCESS == rv)
610  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
611  }
612 
613  WRITE_BODY(caStr);
614  }
615  break;
616 
617  case SCARD_STATUS:
618  {
619  struct status_struct stStr;
620 
621  READ_BODY(stStr);
622 
623  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
624  goto exit;
625 
626  /* only hCard and return value are used by the client */
627  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
628  NULL, 0, NULL);
629 
630  WRITE_BODY(stStr);
631  }
632  break;
633 
634  case SCARD_TRANSMIT:
635  {
636  struct transmit_struct trStr;
637  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
638  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
639  SCARD_IO_REQUEST ioSendPci;
640  SCARD_IO_REQUEST ioRecvPci;
641  DWORD cbRecvLength;
642 
643  READ_BODY(trStr);
644 
645  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
646  goto exit;
647 
648  /* avoids buffer overflow */
649  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
650  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
651  goto buffer_overflow;
652 
653  /* read sent buffer */
654  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
655  if (ret != SCARD_S_SUCCESS)
656  {
657  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
658  goto exit;
659  }
660 
661  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
662  ioSendPci.cbPciLength = trStr.ioSendPciLength;
663  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
664  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
665  cbRecvLength = sizeof pbRecvBuffer;
666 
667  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
668  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
669  pbRecvBuffer, &cbRecvLength);
670 
671  if (cbRecvLength > trStr.pcbRecvLength)
672  /* The client buffer is not large enough.
673  * The pbRecvBuffer buffer will NOT be sent a few
674  * lines bellow. So no buffer overflow is expected. */
675  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
676 
677  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
678  trStr.ioSendPciLength = ioSendPci.cbPciLength;
679  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
680  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
681  trStr.pcbRecvLength = cbRecvLength;
682 
683  WRITE_BODY(trStr);
684 
685  /* write received buffer */
686  if (SCARD_S_SUCCESS == trStr.rv)
687  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
688  }
689  break;
690 
691  case SCARD_CONTROL:
692  {
693  struct control_struct ctStr;
694  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
695  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
696  DWORD dwBytesReturned;
697 
698  READ_BODY(ctStr);
699 
700  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
701  goto exit;
702 
703  /* avoids buffer overflow */
704  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
705  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
706  {
707  goto buffer_overflow;
708  }
709 
710  /* read sent buffer */
711  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
712  if (ret != SCARD_S_SUCCESS)
713  {
714  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
715  goto exit;
716  }
717 
718  dwBytesReturned = ctStr.dwBytesReturned;
719 
720  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
721  pbSendBuffer, ctStr.cbSendLength,
722  pbRecvBuffer, sizeof pbRecvBuffer,
723  &dwBytesReturned);
724 
725  if (dwBytesReturned > ctStr.cbRecvLength)
726  /* The client buffer is not large enough.
727  * The pbRecvBuffer buffer will NOT be sent a few
728  * lines bellow. So no buffer overflow is expected. */
729  ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
730 
731  ctStr.dwBytesReturned = dwBytesReturned;
732 
733  WRITE_BODY(ctStr);
734 
735  /* write received buffer */
736  if (SCARD_S_SUCCESS == ctStr.rv)
737  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
738  }
739  break;
740 
741  case SCARD_GET_ATTRIB:
742  {
743  struct getset_struct gsStr;
744  DWORD cbAttrLen;
745 
746  READ_BODY(gsStr);
747 
748  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
749  goto exit;
750 
751  /* avoids buffer overflow */
752  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
753  goto buffer_overflow;
754 
755  cbAttrLen = gsStr.cbAttrLen;
756 
757  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
758  gsStr.pbAttr, &cbAttrLen);
759 
760  gsStr.cbAttrLen = cbAttrLen;
761 
762  WRITE_BODY(gsStr);
763  }
764  break;
765 
766  case SCARD_SET_ATTRIB:
767  {
768  struct getset_struct gsStr;
769 
770  READ_BODY(gsStr);
771 
772  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
773  goto exit;
774 
775  /* avoids buffer overflow */
776  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
777  goto buffer_overflow;
778 
779  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
780  gsStr.pbAttr, gsStr.cbAttrLen);
781 
782  WRITE_BODY(gsStr);
783  }
784  break;
785 
786  default:
787  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
788  goto exit;
789  }
790 
791  /* MessageSend() failed */
792  if (ret != SCARD_S_SUCCESS)
793  {
794  /* Clean up the dead client */
795  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
796  goto exit;
797  }
798  }
799 
800 buffer_overflow:
801  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
802  goto exit;
803 wrong_length:
804  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
805 exit:
806  (void)close(filedes);
807  MSGCleanupClient(threadContext);
808  (void)pthread_exit((LPVOID) NULL);
809 }
810 
811 LONG MSGSignalClient(uint32_t filedes, LONG rv)
812 {
813  uint32_t ret;
814  struct wait_reader_state_change waStr =
815  {
816  .timeOut = 0,
817  .rv = 0
818  };
819 
820  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
821 
822  waStr.rv = rv;
823  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
824 
825  return ret;
826 } /* MSGSignalClient */
827 
828 LONG MSGSendReaderStates(uint32_t filedes)
829 {
830  uint32_t ret;
831 
832  Log2(PCSC_LOG_DEBUG, "Send reader states: %d", filedes);
833 
834  /* dump the readers state */
835  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
836 
837  return ret;
838 }
839 
840 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
841 {
842  threadContext->hContext = hContext;
843  return SCARD_S_SUCCESS;
844 }
845 
846 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
847 {
848  LONG rv;
849  int lrv;
850 
851  if (0 == threadContext->hContext)
852  {
853  Log1(PCSC_LOG_ERROR, "Invalidated handle");
854  return SCARD_E_INVALID_HANDLE;
855  }
856 
857  if (threadContext->hContext != hContext)
858  return SCARD_E_INVALID_VALUE;
859 
860  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
861  while (list_size(&threadContext->cardsList) != 0)
862  {
863  READER_CONTEXT * rContext = NULL;
864  SCARDHANDLE hCard;
865  void *ptr;
866 
867  /*
868  * Disconnect each of these just in case
869  */
870  ptr = list_get_at(&threadContext->cardsList, 0);
871  if (NULL == ptr)
872  {
873  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
874  continue;
875  }
876  hCard = *(int32_t *)ptr;
877 
878  /*
879  * Unlock the sharing
880  */
881  rv = RFReaderInfoById(hCard, &rContext);
882  if (rv != SCARD_S_SUCCESS)
883  {
884  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
885  return rv;
886  }
887 
888  if (0 == rContext->hLockId)
889  {
890  /* no lock. Just leave the card */
891  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
892  }
893  else
894  {
895  if (hCard != rContext->hLockId)
896  {
897  /*
898  * if the card is locked by someone else we do not reset it
899  * and simulate a card removal
900  */
902 
903  /* decrement card use */
904  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
905  }
906  else
907  {
908  /* release the lock */
909  rContext->hLockId = 0;
910 
911  /*
912  * We will use SCardStatus to see if the card has been
913  * reset there is no need to reset each time
914  * Disconnect is called
915  */
916  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
917 
918  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
919  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
920  else
921  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
922  }
923  }
924 
925  /* Remove entry from the list */
926  lrv = list_delete_at(&threadContext->cardsList, 0);
927  if (lrv < 0)
928  Log2(PCSC_LOG_CRITICAL,
929  "list_delete_at failed with return value: %d", lrv);
930 
931  UNREF_READER(rContext)
932  }
933  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
934 
935  /* We only mark the context as no longer in use.
936  * The memory is freed in MSGCleanupCLient() */
937  threadContext->hContext = 0;
938 
939  return SCARD_S_SUCCESS;
940 }
941 
942 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
943  SCONTEXT * threadContext)
944 {
945  LONG retval = SCARD_E_INVALID_VALUE;
946 
947  if (0 == threadContext->hContext)
948  {
949  Log1(PCSC_LOG_ERROR, "Invalidated handle");
950  return SCARD_E_INVALID_HANDLE;
951  }
952 
953  if (threadContext->hContext == hContext)
954  {
955  /*
956  * Find an empty spot to put the hCard value
957  */
958  int listLength;
959 
960  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
961 
962  listLength = list_size(&threadContext->cardsList);
963  if (listLength >= contextMaxCardHandles)
964  {
965  Log4(PCSC_LOG_DEBUG,
966  "Too many card handles for thread context @%p: %d (max is %d)"
967  "Restart pcscd with --max-card-handle-per-thread value",
968  threadContext, listLength, contextMaxCardHandles);
969  retval = SCARD_E_NO_MEMORY;
970  }
971  else
972  {
973  int lrv;
974 
975  lrv = list_append(&threadContext->cardsList, &hCard);
976  if (lrv < 0)
977  {
978  Log2(PCSC_LOG_CRITICAL,
979  "list_append failed with return value: %d", lrv);
980  retval = SCARD_E_NO_MEMORY;
981  }
982  else
983  retval = SCARD_S_SUCCESS;
984  }
985 
986  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
987  }
988 
989  return retval;
990 }
991 
992 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
993 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
994 {
995  int lrv;
996 
997  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
998  lrv = list_delete(&threadContext->cardsList, &hCard);
999  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1000  if (lrv < 0)
1001  {
1002  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
1003  return SCARD_E_INVALID_VALUE;
1004  }
1005 
1006  return SCARD_S_SUCCESS;
1007 }
1008 
1009 
1010 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
1011  SCONTEXT * threadContext)
1012 {
1013  int list_index = 0;
1014 
1015  if (0 == threadContext->hContext)
1016  {
1017  /* the handle is no more valid. After SCardReleaseContext() for
1018  * example */
1019  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
1020  return -1;
1021  }
1022 
1023  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1024  list_index = list_locate(&threadContext->cardsList, &hCard);
1025  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1026  if (list_index >= 0)
1027  return 0;
1028 
1029  /* Must be a rogue client, debug log and sleep a couple of seconds */
1030  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1031  (void)SYS_Sleep(2);
1032 
1033  return -1;
1034 }
1035 
1036 
1037 /* Should be called just prior to exiting the thread as it de-allocates
1038  * the thread memory strucutres
1039  */
1040 static void MSGCleanupClient(SCONTEXT * threadContext)
1041 {
1042  int lrv;
1043  int listSize;
1044 
1045  if (threadContext->hContext != 0)
1046  {
1047  (void)SCardReleaseContext(threadContext->hContext);
1048  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1049  }
1050 
1051  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1052  list_destroy(&threadContext->cardsList);
1053  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1054 
1055  Log3(PCSC_LOG_DEBUG,
1056  "Thread is stopping: dwClientID=%d, threadContext @%p",
1057  threadContext->dwClientID, threadContext);
1058 
1059  /* Clear the struct to ensure that we detect
1060  * access to de-allocated memory
1061  * Hopefully the compiler won't optimise it out */
1062  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1063  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1064 
1065  (void)pthread_mutex_lock(&contextsList_lock);
1066  lrv = list_delete(&contextsList, threadContext);
1067  listSize = list_size(&contextsList);
1068  (void)pthread_mutex_unlock(&contextsList_lock);
1069  if (lrv < 0)
1070  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1071 
1072  free(threadContext);
1073 
1074  /* start a suicide alarm */
1075  if (AutoExit && (listSize < 1))
1076  {
1077  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1078  TIME_BEFORE_SUICIDE);
1079  alarm(TIME_BEFORE_SUICIDE);
1080  }
1081 
1082  return;
1083 }
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:103
#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:171
pthread_t pthThread
Event polling thread&#39;s ID.
Definition: winscard_svc.c:87
used by SCardEstablishContext()
Definition: winscard_msg.h:76
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
#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:1370
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:832
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:454
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
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:109
#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:525
#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:83
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
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:234
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:1445
#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:283
#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:1051
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:1311
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:356
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:1248
used by SCardCancel()
Definition: winscard_msg.h:88
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard.c:1093
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:1495
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.