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