pcsc-lite  1.8.13
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: winscard_svc.c 7004 2014-10-02 09:26:36Z rousseau $
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 = trStr.pcbRecvLength;
642 
643  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
644  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
645  pbRecvBuffer, &cbRecvLength);
646 
647  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
648  trStr.ioSendPciLength = ioSendPci.cbPciLength;
649  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
650  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
651  trStr.pcbRecvLength = cbRecvLength;
652 
653  WRITE_BODY(trStr)
654 
655  /* write received buffer */
656  if (SCARD_S_SUCCESS == trStr.rv)
657  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
658  }
659  break;
660 
661  case SCARD_CONTROL:
662  {
663  struct control_struct ctStr;
664  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
665  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
666  DWORD dwBytesReturned;
667 
668  READ_BODY(ctStr)
669 
670  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
671  goto exit;
672 
673  /* avoids buffer overflow */
674  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
675  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
676  {
677  goto buffer_overflow;
678  }
679 
680  /* read sent buffer */
681  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
682  if (ret != SCARD_S_SUCCESS)
683  {
684  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
685  goto exit;
686  }
687 
688  dwBytesReturned = ctStr.dwBytesReturned;
689 
690  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
691  pbSendBuffer, ctStr.cbSendLength,
692  pbRecvBuffer, ctStr.cbRecvLength,
693  &dwBytesReturned);
694 
695  ctStr.dwBytesReturned = dwBytesReturned;
696 
697  WRITE_BODY(ctStr)
698 
699  /* write received buffer */
700  if (SCARD_S_SUCCESS == ctStr.rv)
701  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
702  }
703  break;
704 
705  case SCARD_GET_ATTRIB:
706  {
707  struct getset_struct gsStr;
708  DWORD cbAttrLen;
709 
710  READ_BODY(gsStr)
711 
712  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
713  goto exit;
714 
715  /* avoids buffer overflow */
716  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
717  goto buffer_overflow;
718 
719  cbAttrLen = gsStr.cbAttrLen;
720 
721  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
722  gsStr.pbAttr, &cbAttrLen);
723 
724  gsStr.cbAttrLen = cbAttrLen;
725 
726  WRITE_BODY(gsStr)
727  }
728  break;
729 
730  case SCARD_SET_ATTRIB:
731  {
732  struct getset_struct gsStr;
733 
734  READ_BODY(gsStr)
735 
736  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
737  goto exit;
738 
739  /* avoids buffer overflow */
740  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
741  goto buffer_overflow;
742 
743  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
744  gsStr.pbAttr, gsStr.cbAttrLen);
745 
746  WRITE_BODY(gsStr)
747  }
748  break;
749 
750  default:
751  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
752  goto exit;
753  }
754 
755  /* MessageSend() failed */
756  if (ret != SCARD_S_SUCCESS)
757  {
758  /* Clean up the dead client */
759  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
760  goto exit;
761  }
762  }
763 
764 buffer_overflow:
765  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
766  goto exit;
767 wrong_length:
768  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
769 exit:
770  (void)close(filedes);
771  (void)MSGCleanupClient(threadContext);
772  (void)pthread_exit((LPVOID) NULL);
773 }
774 
775 LONG MSGSignalClient(uint32_t filedes, LONG rv)
776 {
777  uint32_t ret;
778  struct wait_reader_state_change waStr;
779 
780  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
781 
782  waStr.rv = rv;
783  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr)
784 
785  return ret;
786 } /* MSGSignalClient */
787 
788 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
789 {
790  threadContext->hContext = hContext;
791  return SCARD_S_SUCCESS;
792 }
793 
794 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
795 {
796  LONG rv;
797  int lrv;
798 
799  if (threadContext->hContext != hContext)
800  return SCARD_E_INVALID_VALUE;
801 
802  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
803  while (list_size(&threadContext->cardsList) != 0)
804  {
805  READER_CONTEXT * rContext = NULL;
806  SCARDHANDLE hCard, hLockId;
807  void *ptr;
808 
809  /*
810  * Disconnect each of these just in case
811  */
812  ptr = list_get_at(&threadContext->cardsList, 0);
813  if (NULL == ptr)
814  {
815  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
816  continue;
817  }
818  hCard = *(int32_t *)ptr;
819 
820  /*
821  * Unlock the sharing
822  */
823  rv = RFReaderInfoById(hCard, &rContext);
824  if (rv != SCARD_S_SUCCESS)
825  {
826  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
827  return rv;
828  }
829 
830  hLockId = rContext->hLockId;
831  rContext->hLockId = 0;
832 
833  if (hCard != hLockId)
834  {
835  /*
836  * if the card is locked by someone else we do not reset it
837  * and simulate a card removal
838  */
840  }
841  else
842  {
843  /*
844  * We will use SCardStatus to see if the card has been
845  * reset there is no need to reset each time
846  * Disconnect is called
847  */
848  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
849  }
850 
851  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
852  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
853  else
854  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
855 
856  /* Remove entry from the list */
857  lrv = list_delete_at(&threadContext->cardsList, 0);
858  if (lrv < 0)
859  Log2(PCSC_LOG_CRITICAL,
860  "list_delete_at failed with return value: %d", lrv);
861 
862  UNREF_READER(rContext)
863  }
864  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
865  list_destroy(&threadContext->cardsList);
866 
867  /* We only mark the context as no longer in use.
868  * The memory is freed in MSGCleanupCLient() */
869  threadContext->hContext = 0;
870 
871  return SCARD_S_SUCCESS;
872 }
873 
874 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
875  SCONTEXT * threadContext)
876 {
877  LONG retval = SCARD_E_INVALID_VALUE;
878 
879  if (threadContext->hContext == hContext)
880  {
881  /*
882  * Find an empty spot to put the hCard value
883  */
884  int listLength;
885 
886  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
887 
888  listLength = list_size(&threadContext->cardsList);
889  if (listLength >= contextMaxCardHandles)
890  {
891  Log4(PCSC_LOG_DEBUG,
892  "Too many card handles for thread context @%p: %d (max is %d)"
893  "Restart pcscd with --max-card-handle-per-thread value",
894  threadContext, listLength, contextMaxCardHandles);
895  retval = SCARD_E_NO_MEMORY;
896  }
897  else
898  {
899  int lrv;
900 
901  lrv = list_append(&threadContext->cardsList, &hCard);
902  if (lrv < 0)
903  {
904  Log2(PCSC_LOG_CRITICAL,
905  "list_append failed with return value: %d", lrv);
906  retval = SCARD_E_NO_MEMORY;
907  }
908  else
909  retval = SCARD_S_SUCCESS;
910  }
911 
912  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
913  }
914 
915  return retval;
916 }
917 
918 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
919 {
920  int lrv;
921 
922  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
923  lrv = list_delete(&threadContext->cardsList, &hCard);
924  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
925  if (lrv < 0)
926  {
927  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
928  return SCARD_E_INVALID_VALUE;
929  }
930 
931  return SCARD_S_SUCCESS;
932 }
933 
934 
935 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
936  SCONTEXT * threadContext)
937 {
938  int list_index = 0;
939 
940  if (0 == threadContext->hContext)
941  {
942  /* the handle is no more valid. After SCardReleaseContext() for
943  * example */
944  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
945  return -1;
946  }
947 
948  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
949  list_index = list_locate(&threadContext->cardsList, &hCard);
950  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
951  if (list_index >= 0)
952  return 0;
953 
954  /* Must be a rogue client, debug log and sleep a couple of seconds */
955  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
956  (void)SYS_Sleep(2);
957 
958  return -1;
959 }
960 
961 
962 /* Should be called just prior to exiting the thread as it de-allocates
963  * the thread memory strucutres
964  */
965 static LONG MSGCleanupClient(SCONTEXT * threadContext)
966 {
967  int lrv;
968  int listSize;
969 
970  if (threadContext->hContext != 0)
971  {
972  (void)SCardReleaseContext(threadContext->hContext);
973  (void)MSGRemoveContext(threadContext->hContext, threadContext);
974  }
975 
976  Log3(PCSC_LOG_DEBUG,
977  "Thread is stopping: dwClientID=%d, threadContext @%p",
978  threadContext->dwClientID, threadContext);
979 
980  /* Clear the struct to ensure that we detect
981  * access to de-allocated memory
982  * Hopefully the compiler won't optimise it out */
983  memset((void*) threadContext, 0, sizeof(SCONTEXT));
984  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
985 
986  (void)pthread_mutex_lock(&contextsList_lock);
987  lrv = list_delete(&contextsList, threadContext);
988  listSize = list_size(&contextsList);
989  (void)pthread_mutex_unlock(&contextsList_lock);
990  if (lrv < 0)
991  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
992 
993  free(threadContext);
994 
995  /* start a suicide alarm */
996  if (AutoExit && (listSize < 1))
997  {
998  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
999  TIME_BEFORE_SUICIDE);
1000  alarm(TIME_BEFORE_SUICIDE);
1001  }
1002 
1003  return 0;
1004 }
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:104
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:196
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:1378
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:821
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:449
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:520
#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:84
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:232
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:1256
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard.c:1454
#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:1071
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:1319
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:351
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
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:1113
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:1504
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:221
This handles debugging.