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