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