pcsc-lite  1.9.4
pcscdaemon.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 1999-2002
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2002-2018
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
42 #include "config.h"
43 #include <time.h>
44 #include <signal.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #ifdef HAVE_GETOPT_H
54 #include <getopt.h>
55 #endif
56 #ifdef USE_LIBSYSTEMD
57 #include <systemd/sd-daemon.h>
58 #endif
59 
60 #include "misc.h"
61 #include "pcsclite.h"
62 #include "pcscd.h"
63 #include "debuglog.h"
64 #include "winscard_msg.h"
65 #include "winscard_svc.h"
66 #include "sys_generic.h"
67 #include "hotplug.h"
68 #include "readerfactory.h"
69 #include "configfile.h"
70 #include "utils.h"
71 #include "eventhandler.h"
72 
73 #ifndef TRUE
74 #define TRUE 1
75 #define FALSE 0
76 #endif
77 
78 char AraKiri = FALSE;
79 static char Init = TRUE;
80 char AutoExit = FALSE;
81 char SocketActivated = FALSE;
82 static int ExitValue = EXIT_FAILURE;
83 int HPForceReaderPolling = 0;
84 char disable_polkit = FALSE;
85 static int pipefd[] = {-1, -1};
86 static int signal_handler_fd[] = {-1, -1};
87 char Add_Serial_In_Name = TRUE;
88 char Add_Interface_In_Name = TRUE;
89 
90 /*
91  * Some internal functions
92  */
93 static void at_exit(void);
94 static void clean_temp_files(void);
95 static void signal_trap(int);
96 static void print_version(void);
97 static void print_usage(char const * const);
98 
107 static void SVCServiceRunLoop(void)
108 {
109  int rsp;
110  LONG rv;
111  uint32_t dwClientID; /* Connection ID used to reference the Client */
112 
113  while (TRUE)
114  {
115  if (AraKiri)
116  {
117  /* stop the hotpug thread and waits its exit */
118 #ifdef USE_USB
119  (void)HPStopHotPluggables();
120 #endif
121  (void)SYS_Sleep(1);
122 
123  /* now stop all the drivers */
124  RFCleanupReaders();
125  EHDeinitializeEventStructures();
126  ContextsDeinitialize();
127  at_exit();
128  }
129 
130  switch (rsp = ProcessEventsServer(&dwClientID))
131  {
132 
133  case 0:
134  Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
135  rv = CreateContextThread(&dwClientID);
136 
137  if (rv != SCARD_S_SUCCESS)
138  Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
139  break;
140 
141  case 2:
142  /*
143  * timeout in ProcessEventsServer(): do nothing
144  * this is used to catch the Ctrl-C signal at some time when
145  * nothing else happens
146  */
147  break;
148 
149  case -1:
150  Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
151  break;
152 
153  case -2:
154  /* Nothing to do in case of a syscall interrupted
155  * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
156  * We just try again */
157 
158  /* we wait a bit so that the signal handler thread can do
159  * its job and set AraKiri if needed */
160  SYS_USleep(1000);
161  break;
162 
163  default:
164  Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
165  rsp);
166  break;
167  }
168  }
169 }
170 
178 static void *signal_thread(void *arg)
179 {
180  (void)arg;
181 
182  while (TRUE)
183  {
184  int r;
185  int sig;
186 
187  r = read(signal_handler_fd[0], &sig, sizeof sig);
188  if (r < 0)
189  {
190  Log2(PCSC_LOG_ERROR, "read failed: %s", strerror(errno));
191  return NULL;
192  }
193 
194  Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
195 
196  /* signal for hotplug */
197  if (SIGUSR1 == sig)
198  {
199 #ifdef USE_USB
200  if (! AraKiri)
201  HPReCheckSerialReaders();
202 #endif
203  /* Reenable the signal handler.
204  * This is needed on Solaris and HPUX. */
205  (void)signal(SIGUSR1, signal_trap);
206 
207  continue;
208  }
209 
210  /* do not wait if asked to terminate
211  * avoids waiting after the reader(s) in shutdown for example */
212  if (SIGTERM == sig)
213  {
214  Log1(PCSC_LOG_INFO, "Direct suicide");
215  ExitValue = EXIT_SUCCESS;
216  at_exit();
217  }
218 
219  if (SIGALRM == sig)
220  {
221  /* normal exit without error */
222  ExitValue = EXIT_SUCCESS;
223  }
224 
225  /* the signal handler is called several times for the same Ctrl-C */
226  if (AraKiri == FALSE)
227  {
228  Log1(PCSC_LOG_INFO, "Preparing for suicide");
229  AraKiri = TRUE;
230 
231  /* if still in the init/loading phase the AraKiri will not be
232  * seen by the main event loop
233  */
234  if (Init)
235  {
236  Log1(PCSC_LOG_INFO, "Suicide during init");
237  at_exit();
238  }
239  }
240  else
241  {
242  /* if pcscd do not want to die */
243  static int lives = 2;
244 
245  lives--;
246  /* no live left. Something is blocking the normal death. */
247  if (0 == lives)
248  {
249  Log1(PCSC_LOG_INFO, "Forced suicide");
250  at_exit();
251  }
252  }
253  }
254 
255  return NULL;
256 }
257 
258 
259 int main(int argc, char **argv)
260 {
261  int rv;
262  char setToForeground;
263  char HotPlug;
264  char *newReaderConfig;
265  struct stat fStatBuf;
266  int customMaxThreadCounter = 0;
267  int customMaxReaderHandles = 0;
268  int customMaxThreadCardHandles = 0;
269  int opt;
270  int r;
271 #ifdef HAVE_GETOPT_LONG
272  int option_index = 0;
273  static struct option long_options[] = {
274  {"config", 1, NULL, 'c'},
275  {"foreground", 0, NULL, 'f'},
276  {"color", 0, NULL, 'T'},
277  {"help", 0, NULL, 'h'},
278  {"version", 0, NULL, 'v'},
279  {"apdu", 0, NULL, 'a'},
280  {"debug", 0, NULL, 'd'},
281  {"info", 0, NULL, 'i'},
282  {"error", 0, NULL, 'e'},
283  {"critical", 0, NULL, 'C'},
284  {"hotplug", 0, NULL, 'H'},
285  {"force-reader-polling", optional_argument, NULL, 0},
286  {"max-thread", 1, NULL, 't'},
287  {"max-card-handle-per-thread", 1, NULL, 's'},
288  {"max-card-handle-per-reader", 1, NULL, 'r'},
289  {"auto-exit", 0, NULL, 'x'},
290  {"reader-name-no-serial", 0, NULL, 'S'},
291  {"reader-name-no-interface", 0, NULL, 'I'},
292  {"disable-polkit", 0, NULL, 1},
293  {NULL, 0, NULL, 0}
294  };
295 #endif
296 #define OPT_STRING "c:fTdhvaieCHt:r:s:xSI"
297 
298  newReaderConfig = NULL;
299  setToForeground = FALSE;
300  HotPlug = FALSE;
301 
302  /*
303  * test the version
304  */
305  if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
306  {
307  printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
308  printf(" in pcsclite.h (%s) does not match the release version number\n",
310  printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
311 
312  return EXIT_FAILURE;
313  }
314 
315  /* Init the PRNG */
316  SYS_InitRandom();
317 
318  /*
319  * By default we create a daemon (not connected to any output)
320  * so log to syslog to have error messages.
321  */
322  DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
323 
324  /*
325  * Handle any command line arguments
326  */
327 #ifdef HAVE_GETOPT_LONG
328  while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
329 #else
330  while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
331 #endif
332  switch (opt) {
333 #ifdef HAVE_GETOPT_LONG
334  case 0:
335  if (strcmp(long_options[option_index].name,
336  "force-reader-polling") == 0)
337  HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
338  break;
339  case 1:
340  if (strcmp(long_options[option_index].name,
341  "disable-polkit") == 0)
342  disable_polkit = TRUE;
343  break;
344 #endif
345  case 'c':
346  Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
347  newReaderConfig = optarg;
348  break;
349 
350  case 'f':
351  setToForeground = TRUE;
352  /* debug to stdout instead of default syslog */
353  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
354  Log1(PCSC_LOG_INFO,
355  "pcscd set to foreground with debug send to stdout");
356  break;
357 
358  case 'T':
359  DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
360  Log1(PCSC_LOG_INFO, "Force colored logs");
361  break;
362 
363  case 'd':
364  DebugLogSetLevel(PCSC_LOG_DEBUG);
365  break;
366 
367  case 'i':
368  DebugLogSetLevel(PCSC_LOG_INFO);
369  break;
370 
371  case 'e':
372  DebugLogSetLevel(PCSC_LOG_ERROR);
373  break;
374 
375  case 'C':
376  DebugLogSetLevel(PCSC_LOG_CRITICAL);
377  break;
378 
379  case 'h':
380  print_usage (argv[0]);
381  return EXIT_SUCCESS;
382 
383  case 'v':
384  print_version ();
385  return EXIT_SUCCESS;
386 
387  case 'a':
388  DebugLogSetCategory(DEBUG_CATEGORY_APDU);
389  break;
390 
391  case 'H':
392  /* debug to stdout instead of default syslog */
393  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
394  HotPlug = TRUE;
395  break;
396 
397  case 't':
398  customMaxThreadCounter = optarg ? atoi(optarg) : 0;
399  Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
400  customMaxThreadCounter);
401  break;
402 
403  case 'r':
404  customMaxReaderHandles = optarg ? atoi(optarg) : 0;
405  Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
406  customMaxReaderHandles);
407  break;
408 
409  case 's':
410  customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
411  Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
412  customMaxThreadCardHandles);
413  break;
414 
415  case 'x':
416  AutoExit = TRUE;
417  Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
418  TIME_BEFORE_SUICIDE);
419  break;
420 
421  case 'S':
422  Add_Serial_In_Name = FALSE;
423  break;
424 
425  case 'I':
426  Add_Interface_In_Name = FALSE;
427  break;
428 
429  default:
430  print_usage (argv[0]);
431  return EXIT_FAILURE;
432  }
433 
434  }
435 
436  if (argv[optind])
437  {
438  printf("Unknown option: %s\n", argv[optind]);
439  print_usage(argv[0]);
440  return EXIT_FAILURE;
441  }
442 
443 #ifdef USE_LIBSYSTEMD
444  /*
445  * Check if systemd passed us any file descriptors
446  */
447  rv = sd_listen_fds(0);
448  if (rv > 1)
449  {
450  Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
451  return EXIT_FAILURE;
452  }
453  else
454  {
455  if (rv == 1)
456  {
457  SocketActivated = TRUE;
458  Log1(PCSC_LOG_INFO, "Started by systemd");
459  }
460  else
461  SocketActivated = FALSE;
462  }
463 #endif
464 
465  /*
466  * test the presence of /var/run/pcscd/pcscd.comm
467  */
468 
469  rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
470 
471  /* if the file exist and pcscd was _not_ started by systemd */
472  if (rv == 0 && !SocketActivated)
473  {
474  pid_t pid;
475 
476  /* read the pid file to get the old pid and test if the old pcscd is
477  * still running
478  */
479  pid = GetDaemonPid();
480 
481  if (pid != -1)
482  {
483  if (HotPlug)
484  return SendHotplugSignal();
485 
486  rv = kill(pid, 0);
487  if (0 == rv)
488  {
489  Log1(PCSC_LOG_CRITICAL,
490  "file " PCSCLITE_CSOCK_NAME " already exists.");
491  Log2(PCSC_LOG_CRITICAL,
492  "Another pcscd (pid: %ld) seems to be running.", (long)pid);
493  return EXIT_FAILURE;
494  }
495  else
496  if (ESRCH == errno)
497  {
498  /* the old pcscd is dead. make some cleanup */
499  clean_temp_files();
500  }
501  else
502  {
503  /* permission denied or other error */
504  Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
505  return EXIT_FAILURE;
506  }
507  }
508  else
509  {
510  if (HotPlug)
511  {
512  Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
513  Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
514  return EXIT_FAILURE;
515  }
516  }
517  }
518  else
519  if (HotPlug)
520  {
521  Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
522  return EXIT_FAILURE;
523  }
524 
525  /* like in daemon(3): changes the current working directory to the
526  * root ("/") */
527  r = chdir("/");
528  if (r < 0)
529  {
530  Log2(PCSC_LOG_CRITICAL, "chdir() failed: %s", strerror(errno));
531  return EXIT_FAILURE;
532  }
533 
534  /*
535  * If this is set to one the user has asked it not to fork
536  */
537  if (!setToForeground)
538  {
539  int pid;
540  int fd;
541 
542  if (pipe(pipefd) == -1)
543  {
544  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
545  return EXIT_FAILURE;
546  }
547 
548  pid = fork();
549  if (-1 == pid)
550  {
551  Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
552  return EXIT_FAILURE;
553  }
554 
555  /* like in daemon(3): redirect standard input, standard output
556  * and standard error to /dev/null */
557  fd = open("/dev/null", O_RDWR);
558  if (fd != -1)
559  {
560  dup2(fd, STDIN_FILENO);
561  dup2(fd, STDOUT_FILENO);
562  dup2(fd, STDERR_FILENO);
563 
564  /* do not close stdin, stdout or stderr */
565  if (fd > 2)
566  close(fd);
567  }
568 
569  if (pid)
570  /* in the father */
571  {
572  char buf;
573  int ret;
574 
575  /* close write side */
576  close(pipefd[1]);
577 
578  /* wait for the son to write the return code */
579  ret = read(pipefd[0], &buf, 1);
580  if (ret <= 0)
581  return 2;
582 
583  close(pipefd[0]);
584 
585  /* exit code */
586  return buf;
587  }
588  else
589  /* in the son */
590  {
591  /* close read side */
592  close(pipefd[0]);
593  }
594  }
595 
596  /*
597  * cleanly remove /var/run/pcscd/files when exiting
598  * signal_trap() does just set a global variable used by the main loop
599  */
600  (void)signal(SIGQUIT, signal_trap);
601  (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
602  (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
603 
604  /* exits on SIGALARM to allow pcscd to suicide if not used */
605  (void)signal(SIGALRM, signal_trap);
606 
607  if (pipe(signal_handler_fd) == -1)
608  {
609  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
610  return EXIT_FAILURE;
611  }
612 
613  pthread_t signal_handler_thread;
614  rv = pthread_create(&signal_handler_thread, NULL, signal_thread, NULL);
615  if (rv)
616  {
617  Log2(PCSC_LOG_CRITICAL, "pthread_create failed: %s", strerror(rv));
618  return EXIT_FAILURE;
619  }
620 
621  /*
622  * If PCSCLITE_IPC_DIR does not exist then create it
623  */
624  {
625  int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
626 
627  rv = mkdir(PCSCLITE_IPC_DIR, mode);
628  if ((rv != 0) && (errno != EEXIST))
629  {
630  Log2(PCSC_LOG_CRITICAL,
631  "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
632  return EXIT_FAILURE;
633  }
634 
635  /* set mode so that the directory is world readable and
636  * executable even is umask is restrictive
637  * The directory containes files used by libpcsclite */
638  (void)chmod(PCSCLITE_IPC_DIR, mode);
639  }
640 
641  /*
642  * Allocate memory for reader structures
643  */
644  rv = RFAllocateReaderSpace(customMaxReaderHandles);
645  if (SCARD_S_SUCCESS != rv)
646  at_exit();
647 
648 #ifdef USE_SERIAL
649  /*
650  * Grab the information from the reader.conf
651  */
652  if (newReaderConfig)
653  {
654  rv = RFStartSerialReaders(newReaderConfig);
655  if (rv != 0)
656  {
657  Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
658  strerror(errno));
659  at_exit();
660  }
661  }
662  else
663  {
664  rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
665  if (rv == -1)
666  at_exit();
667  }
668 #endif
669 
670  Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
671 
672  /*
673  * Record our pid to make it easier
674  * to kill the correct pcscd
675  *
676  * Do not fork after this point or the stored pid will be wrong
677  */
678  {
679  int f;
680  int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
681 
682  f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
683  if (f != -1)
684  {
685  char pid[PID_ASCII_SIZE];
686  ssize_t rr;
687 
688  (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
689  rr = write(f, pid, strlen(pid) + 1);
690  if (rr < 0)
691  {
692  Log2(PCSC_LOG_CRITICAL,
693  "writing " PCSCLITE_RUN_PID " failed: %s",
694  strerror(errno));
695  }
696 
697  /* set mode so that the file is world readable even is umask is
698  * restrictive
699  * The file is used by libpcsclite */
700  (void)fchmod(f, mode);
701 
702  (void)close(f);
703  }
704  else
705  Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
706  strerror(errno));
707  }
708 
709  /*
710  * post initialistion
711  */
712  Init = FALSE;
713 
714  /*
715  * Hotplug rescan
716  */
717  (void)signal(SIGUSR1, signal_trap);
718 
719  /*
720  * Initialize the comm structure
721  */
722 #ifdef USE_LIBSYSTEMD
723  if (SocketActivated)
724  rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
725  else
726 #endif
727  rv = InitializeSocket();
728 
729  if (rv)
730  {
731  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
732  at_exit();
733  }
734 
735  /*
736  * Initialize the contexts structure
737  */
738  rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
739 
740  if (rv == -1)
741  {
742  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
743  at_exit();
744  }
745 
746  (void)signal(SIGPIPE, SIG_IGN);
747  (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
748  * when the shell is existed */
749 
750 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
751  /*
752  * Set up the search for USB/PCMCIA devices
753  */
754  rv = HPSearchHotPluggables();
755 #ifndef USE_SERIAL
756  if (rv)
757  at_exit();
758 #endif
759 
760  rv = HPRegisterForHotplugEvents();
761  if (rv)
762  {
763  Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
764  at_exit();
765  }
766 
767  RFWaitForReaderInit();
768 #endif
769 
770  /* initialisation succeeded */
771  if (pipefd[1] >= 0)
772  {
773  char buf = 0;
774  ssize_t rr;
775 
776  /* write a 0 (success) to father process */
777  rr = write(pipefd[1], &buf, 1);
778  if (rr < 0)
779  {
780  Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
781  }
782  close(pipefd[1]);
783  pipefd[1] = -1;
784  }
785 
787 
788  Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
789  return EXIT_FAILURE;
790 }
791 
792 static void at_exit(void)
793 {
794  Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
795 
796  clean_temp_files();
797 
798  if (pipefd[1] >= 0)
799  {
800  char buf;
801  ssize_t r;
802 
803  /* write the error code to father process */
804  buf = ExitValue;
805  r = write(pipefd[1], &buf, 1);
806  if (r < 0)
807  {
808  Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
809  }
810  close(pipefd[1]);
811  }
812 
813  exit(ExitValue);
814 }
815 
816 static void clean_temp_files(void)
817 {
818  int rv;
819 
820  if (!SocketActivated)
821  {
822  rv = remove(PCSCLITE_CSOCK_NAME);
823  if (rv != 0)
824  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
825  strerror(errno));
826  }
827 
828  rv = remove(PCSCLITE_RUN_PID);
829  if (rv != 0)
830  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
831  strerror(errno));
832 }
833 
834 static void signal_trap(int sig)
835 {
836  int r;
837 
838  r = write(signal_handler_fd[1], &sig, sizeof sig);
839  if (r < 0)
840  Log2(PCSC_LOG_ERROR, "write failed: %s", strerror(errno));
841 }
842 
843 static void print_version(void)
844 {
845  printf("%s version %s.\n", PACKAGE, VERSION);
846  printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
847  printf("Copyright (C) 2001-2018 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
848  printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
849  printf("Report bugs to <pcsclite-muscle@lists.infradead.org>.\n");
850 
851  printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
852 }
853 
854 static void print_usage(char const * const progname)
855 {
856  printf("Usage: %s options\n", progname);
857  printf("Options:\n");
858 #ifdef HAVE_GETOPT_LONG
859  printf(" -a, --apdu log APDU commands and results\n");
860  printf(" -c, --config path to reader.conf\n");
861  printf(" -f, --foreground run in foreground (no daemon),\n");
862  printf(" send logs to stdout instead of syslog\n");
863  printf(" -T, --color force use of colored logs\n");
864  printf(" -h, --help display usage information\n");
865  printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
866  printf(" -v, --version display the program version number\n");
867  printf(" -d, --debug display lower level debug messages\n");
868  printf(" -i, --info display info level debug messages\n");
869  printf(" -e --error display error level debug messages (default level)\n");
870  printf(" -C --critical display critical only level debug messages\n");
871  printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
872  printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
873  printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
874  printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
875  printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
876  printf(" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
877  printf(" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
878  printf(" --disable-polkit disable polkit support\n");
879 #else
880  printf(" -a log APDU commands and results\n");
881  printf(" -c path to reader.conf\n");
882  printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
883  printf(" -T force use of colored logs\n");
884  printf(" -d display debug messages.\n");
885  printf(" -i display info messages.\n");
886  printf(" -e display error messages (default level).\n");
887  printf(" -C display critical messages.\n");
888  printf(" -h display usage information\n");
889  printf(" -H ask the daemon to rescan the available readers\n");
890  printf(" -v display the program version number\n");
891  printf(" -t maximum number of threads\n");
892  printf(" -s maximum number of card handle per thread\n");
893  printf(" -r maximum number of card handle per reader\n");
894  printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
895 #endif
896 }
897 
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
This provides a search API for hot pluggble devices.
This keeps a list of defines for pcsc-lite.
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
Definition: pcscdaemon.c:107
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
static void * signal_thread(void *arg)
thread dedicated to handle signals
Definition: pcscdaemon.c:178
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_VERSION_NUMBER
Current version.
Definition: pcsclite.h:282
This keeps track of a list of currently available reader structures.
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
void SYS_InitRandom(void)
Initialize the random generator.
Definition: sys_unix.c:111
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
This defines some structures and #defines to be used over the transport layer.
INTERNAL int32_t InitializeSocket(void)
Prepares the communication channel used by the server to talk to the clients.
INTERNAL int32_t ProcessEventsServer(uint32_t *pdwClientID)
Looks for messages sent by clients.
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:171
This demarshalls functions over the message queue and keeps track of clients and their handles.