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