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 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 */
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  struct wait_reader_state_change waStr;
415 
416  READ_BODY(waStr);
417 
418  /* add the client fd to the list */
419  EHRegisterClientForEvent(filedes);
420 
421  /* We do not send anything here.
422  * Either the client will timeout or the server will
423  * answer if an event occurs */
424  }
425  break;
426 
428  {
429  struct wait_reader_state_change waStr;
430 
431  READ_BODY(waStr);
432 
433  /* remove the client fd from the list */
434  waStr.rv = EHUnregisterClientForEvent(filedes);
435 
436  /* send the response only if the client was still in the
437  * list */
438  if (waStr.rv != SCARD_F_INTERNAL_ERROR)
439  WRITE_BODY(waStr);
440  }
441  break;
442 
444  {
445  struct establish_struct esStr;
446  SCARDCONTEXT hContext;
447 
448  READ_BODY(esStr);
449 
450  hContext = esStr.hContext;
451  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
452  &hContext);
453  esStr.hContext = hContext;
454 
455  if (esStr.rv == SCARD_S_SUCCESS)
456  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
457 
458  WRITE_BODY(esStr);
459  }
460  break;
461 
463  {
464  struct release_struct reStr;
465 
466  READ_BODY(reStr);
467 
468  reStr.rv = SCardReleaseContext(reStr.hContext);
469 
470  if (reStr.rv == SCARD_S_SUCCESS)
471  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
472 
473  WRITE_BODY(reStr);
474  }
475  break;
476 
477  case SCARD_CONNECT:
478  {
479  struct connect_struct coStr;
480  SCARDHANDLE hCard;
481  DWORD dwActiveProtocol;
482 
483  READ_BODY(coStr);
484 
485  coStr.szReader[sizeof(coStr.szReader)-1] = 0;
486  hCard = coStr.hCard;
487  dwActiveProtocol = coStr.dwActiveProtocol;
488 
489  if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
490  {
491  Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
492  goto exit;
493  }
494  else
495  {
496  Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
497  }
498 
499  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
500  coStr.dwShareMode, coStr.dwPreferredProtocols,
501  &hCard, &dwActiveProtocol);
502 
503  coStr.hCard = hCard;
504  coStr.dwActiveProtocol = dwActiveProtocol;
505 
506  if (coStr.rv == SCARD_S_SUCCESS)
507  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
508  threadContext);
509 
510  WRITE_BODY(coStr);
511  }
512  break;
513 
514  case SCARD_RECONNECT:
515  {
516  struct reconnect_struct rcStr;
517  DWORD dwActiveProtocol;
518 
519  READ_BODY(rcStr);
520 
521  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
522  goto exit;
523 
524  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
525  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
526  &dwActiveProtocol);
527  rcStr.dwActiveProtocol = dwActiveProtocol;
528 
529  WRITE_BODY(rcStr);
530  }
531  break;
532 
533  case SCARD_DISCONNECT:
534  {
535  struct disconnect_struct diStr;
536 
537  READ_BODY(diStr);
538 
539  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
540  goto exit;
541 
542  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
543 
544  if (SCARD_S_SUCCESS == diStr.rv)
545  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
546 
547  WRITE_BODY(diStr);
548  }
549  break;
550 
552  {
553  struct begin_struct beStr;
554 
555  READ_BODY(beStr);
556 
557  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
558  goto exit;
559 
560  beStr.rv = SCardBeginTransaction(beStr.hCard);
561 
562  WRITE_BODY(beStr);
563  }
564  break;
565 
567  {
568  struct end_struct enStr;
569 
570  READ_BODY(enStr);
571 
572  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
573  goto exit;
574 
575  enStr.rv = SCardEndTransaction(enStr.hCard,
576  enStr.dwDisposition);
577 
578  WRITE_BODY(enStr);
579  }
580  break;
581 
582  case SCARD_CANCEL:
583  {
584  struct cancel_struct caStr;
585  SCONTEXT * psTargetContext = NULL;
586 
587  READ_BODY(caStr);
588 
589  /* find the client */
590  (void)pthread_mutex_lock(&contextsList_lock);
591  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
592  &caStr.hContext);
593  (void)pthread_mutex_unlock(&contextsList_lock);
594 
595  /* default value = error */
596  caStr.rv = SCARD_E_INVALID_HANDLE;
597 
598  if (psTargetContext != NULL)
599  {
600  uint32_t fd = psTargetContext->dwClientID;
601  LONG rv;
602 
603  /* the client should not receive the event
604  * notification now the waiting has been cancelled */
606 
607  /* signal the client only if it was still waiting */
608  if (SCARD_S_SUCCESS == rv)
609  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
610  }
611 
612  WRITE_BODY(caStr);
613  }
614  break;
615 
616  case SCARD_STATUS:
617  {
618  struct status_struct stStr;
619 
620  READ_BODY(stStr);
621 
622  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
623  goto exit;
624 
625  /* only hCard and return value are used by the client */
626  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
627  NULL, 0, NULL);
628 
629  WRITE_BODY(stStr);
630  }
631  break;
632 
633  case SCARD_TRANSMIT:
634  {
635  struct transmit_struct trStr;
636  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
637  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
638  SCARD_IO_REQUEST ioSendPci;
639  SCARD_IO_REQUEST ioRecvPci;
640  DWORD cbRecvLength;
641 
642  READ_BODY(trStr);
643 
644  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
645  goto exit;
646 
647  /* avoids buffer overflow */
648  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
649  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
650  goto buffer_overflow;
651 
652  /* read sent buffer */
653  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
654  if (ret != SCARD_S_SUCCESS)
655  {
656  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
657  goto exit;
658  }
659 
660  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
661  ioSendPci.cbPciLength = trStr.ioSendPciLength;
662  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
663  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
664  cbRecvLength = sizeof pbRecvBuffer;
665 
666  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
667  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
668  pbRecvBuffer, &cbRecvLength);
669 
670  if (cbRecvLength > trStr.pcbRecvLength)
671  /* The client buffer is not large enough.
672  * The pbRecvBuffer buffer will NOT be sent a few
673  * lines bellow. So no buffer overflow is expected. */
674  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
675 
676  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
677  trStr.ioSendPciLength = ioSendPci.cbPciLength;
678  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
679  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
680  trStr.pcbRecvLength = cbRecvLength;
681 
682  WRITE_BODY(trStr);
683 
684  /* write received buffer */
685  if (SCARD_S_SUCCESS == trStr.rv)
686  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
687  }
688  break;
689 
690  case SCARD_CONTROL:
691  {
692  struct control_struct ctStr;
693  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
694  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
695  DWORD dwBytesReturned;
696 
697  READ_BODY(ctStr);
698 
699  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
700  goto exit;
701 
702  /* avoids buffer overflow */
703  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
704  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
705  {
706  goto buffer_overflow;
707  }
708 
709  /* read sent buffer */
710  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
711  if (ret != SCARD_S_SUCCESS)
712  {
713  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
714  goto exit;
715  }
716 
717  dwBytesReturned = ctStr.dwBytesReturned;
718 
719  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
720  pbSendBuffer, ctStr.cbSendLength,
721  pbRecvBuffer, sizeof pbRecvBuffer,
722  &dwBytesReturned);
723 
724  if (dwBytesReturned > ctStr.cbRecvLength)
725  /* The client buffer is not large enough.
726  * The pbRecvBuffer buffer will NOT be sent a few
727  * lines bellow. So no buffer overflow is expected. */
728  ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
729 
730  ctStr.dwBytesReturned = dwBytesReturned;
731 
732  WRITE_BODY(ctStr);
733 
734  /* write received buffer */
735  if (SCARD_S_SUCCESS == ctStr.rv)
736  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
737  }
738  break;
739 
740  case SCARD_GET_ATTRIB:
741  {
742  struct getset_struct gsStr;
743  DWORD cbAttrLen;
744 
745  READ_BODY(gsStr);
746 
747  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
748  goto exit;
749 
750  /* avoids buffer overflow */
751  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
752  goto buffer_overflow;
753 
754  cbAttrLen = gsStr.cbAttrLen;
755 
756  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
757  gsStr.pbAttr, &cbAttrLen);
758 
759  gsStr.cbAttrLen = cbAttrLen;
760 
761  WRITE_BODY(gsStr);
762  }
763  break;
764 
765  case SCARD_SET_ATTRIB:
766  {
767  struct getset_struct gsStr;
768 
769  READ_BODY(gsStr);
770 
771  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
772  goto exit;
773 
774  /* avoids buffer overflow */
775  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
776  goto buffer_overflow;
777 
778  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
779  gsStr.pbAttr, gsStr.cbAttrLen);
780 
781  WRITE_BODY(gsStr);
782  }
783  break;
784 
785  default:
786  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
787  goto exit;
788  }
789 
790  /* MessageSend() failed */
791  if (ret != SCARD_S_SUCCESS)
792  {
793  /* Clean up the dead client */
794  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
795  goto exit;
796  }
797  }
798 
799 buffer_overflow:
800  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
801  goto exit;
802 wrong_length:
803  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
804 exit:
805  (void)close(filedes);
806  MSGCleanupClient(threadContext);
807  (void)pthread_exit((LPVOID) NULL);
808 }
809 
810 LONG MSGSignalClient(uint32_t filedes, LONG rv)
811 {
812  uint32_t ret;
813  struct wait_reader_state_change waStr;
814 
815  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
816 
817  waStr.rv = rv;
818  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
819 
820  return ret;
821 } /* MSGSignalClient */
822 
823 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
824 {
825  threadContext->hContext = hContext;
826  return SCARD_S_SUCCESS;
827 }
828 
829 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
830 {
831  LONG rv;
832  int lrv;
833 
834  if (0 == threadContext->hContext)
835  {
836  Log1(PCSC_LOG_ERROR, "Invalidated handle");
837  return SCARD_E_INVALID_HANDLE;
838  }
839 
840  if (threadContext->hContext != hContext)
841  return SCARD_E_INVALID_VALUE;
842 
843  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
844  while (list_size(&threadContext->cardsList) != 0)
845  {
846  READER_CONTEXT * rContext = NULL;
847  SCARDHANDLE hCard, hLockId;
848  void *ptr;
849 
850  /*
851  * Disconnect each of these just in case
852  */
853  ptr = list_get_at(&threadContext->cardsList, 0);
854  if (NULL == ptr)
855  {
856  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
857  continue;
858  }
859  hCard = *(int32_t *)ptr;
860 
861  /*
862  * Unlock the sharing
863  */
864  rv = RFReaderInfoById(hCard, &rContext);
865  if (rv != SCARD_S_SUCCESS)
866  {
867  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
868  return rv;
869  }
870 
871  hLockId = rContext->hLockId;
872  rContext->hLockId = 0;
873 
874  if (hCard != hLockId)
875  {
876  /*
877  * if the card is locked by someone else we do not reset it
878  * and simulate a card removal
879  */
881  }
882  else
883  {
884  /*
885  * We will use SCardStatus to see if the card has been
886  * reset there is no need to reset each time
887  * Disconnect is called
888  */
889  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
890  }
891 
892  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
893  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
894  else
895  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
896 
897  /* Remove entry from the list */
898  lrv = list_delete_at(&threadContext->cardsList, 0);
899  if (lrv < 0)
900  Log2(PCSC_LOG_CRITICAL,
901  "list_delete_at failed with return value: %d", lrv);
902 
903  UNREF_READER(rContext)
904  }
905  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
906 
907  /* We only mark the context as no longer in use.
908  * The memory is freed in MSGCleanupCLient() */
909  threadContext->hContext = 0;
910 
911  return SCARD_S_SUCCESS;
912 }
913 
914 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
915  SCONTEXT * threadContext)
916 {
917  LONG retval = SCARD_E_INVALID_VALUE;
918 
919  if (0 == threadContext->hContext)
920  {
921  Log1(PCSC_LOG_ERROR, "Invalidated handle");
922  return SCARD_E_INVALID_HANDLE;
923  }
924 
925  if (threadContext->hContext == hContext)
926  {
927  /*
928  * Find an empty spot to put the hCard value
929  */
930  int listLength;
931 
932  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
933 
934  listLength = list_size(&threadContext->cardsList);
935  if (listLength >= contextMaxCardHandles)
936  {
937  Log4(PCSC_LOG_DEBUG,
938  "Too many card handles for thread context @%p: %d (max is %d)"
939  "Restart pcscd with --max-card-handle-per-thread value",
940  threadContext, listLength, contextMaxCardHandles);
941  retval = SCARD_E_NO_MEMORY;
942  }
943  else
944  {
945  int lrv;
946 
947  lrv = list_append(&threadContext->cardsList, &hCard);
948  if (lrv < 0)
949  {
950  Log2(PCSC_LOG_CRITICAL,
951  "list_append failed with return value: %d", lrv);
952  retval = SCARD_E_NO_MEMORY;
953  }
954  else
955  retval = SCARD_S_SUCCESS;
956  }
957 
958  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
959  }
960 
961  return retval;
962 }
963 
964 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
965 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
966 {
967  int lrv;
968 
969  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
970  lrv = list_delete(&threadContext->cardsList, &hCard);
971  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
972  if (lrv < 0)
973  {
974  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
975  return SCARD_E_INVALID_VALUE;
976  }
977 
978  return SCARD_S_SUCCESS;
979 }
980 
981 
982 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
983  SCONTEXT * threadContext)
984 {
985  int list_index = 0;
986 
987  if (0 == threadContext->hContext)
988  {
989  /* the handle is no more valid. After SCardReleaseContext() for
990  * example */
991  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
992  return -1;
993  }
994 
995  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
996  list_index = list_locate(&threadContext->cardsList, &hCard);
997  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
998  if (list_index >= 0)
999  return 0;
1000 
1001  /* Must be a rogue client, debug log and sleep a couple of seconds */
1002  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1003  (void)SYS_Sleep(2);
1004 
1005  return -1;
1006 }
1007 
1008 
1009 /* Should be called just prior to exiting the thread as it de-allocates
1010  * the thread memory strucutres
1011  */
1012 static void MSGCleanupClient(SCONTEXT * threadContext)
1013 {
1014  int lrv;
1015  int listSize;
1016 
1017  if (threadContext->hContext != 0)
1018  {
1019  (void)SCardReleaseContext(threadContext->hContext);
1020  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1021  }
1022 
1023  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1024  list_destroy(&threadContext->cardsList);
1025  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1026 
1027  Log3(PCSC_LOG_DEBUG,
1028  "Thread is stopping: dwClientID=%d, threadContext @%p",
1029  threadContext->dwClientID, threadContext);
1030 
1031  /* Clear the struct to ensure that we detect
1032  * access to de-allocated memory
1033  * Hopefully the compiler won't optimise it out */
1034  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1035  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1036 
1037  (void)pthread_mutex_lock(&contextsList_lock);
1038  lrv = list_delete(&contextsList, threadContext);
1039  listSize = list_size(&contextsList);
1040  (void)pthread_mutex_unlock(&contextsList_lock);
1041  if (lrv < 0)
1042  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1043 
1044  free(threadContext);
1045 
1046  /* start a suicide alarm */
1047  if (AutoExit && (listSize < 1))
1048  {
1049  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1050  TIME_BEFORE_SUICIDE);
1051  alarm(TIME_BEFORE_SUICIDE);
1052  }
1053 
1054  return;
1055 }
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:171
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:1364
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:826
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:452
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: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:81
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:78
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:1439
#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:1045
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:1305
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:354
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:1242
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:1087
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:1489
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.