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