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