pcsc-lite 2.0.1
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 *
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#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;
75static bool Init = true;
76bool AutoExit = false;
77bool SocketActivated = false;
78static int ExitValue = EXIT_FAILURE;
79int HPForceReaderPolling = 0;
80bool disable_polkit = false;
81static int pipefd[] = {-1, -1};
82static int signal_handler_fd[] = {-1, -1};
83bool Add_Serial_In_Name = true;
84bool Add_Interface_In_Name = true;
85
86/*
87 * Some internal functions
88 */
89static void at_exit(void);
90static void clean_temp_files(void);
91static void signal_trap(int);
92static void print_version(void);
93static void print_usage(char const * const);
94
103static 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
176static 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
257int 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 */
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
807static 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
831static 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
849static 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
858static 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
871static 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
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.
bool AutoExit
Represents an Application Context on the Server side.
Definition pcscdaemon.c:76
static void * signal_thread(void *arg)
thread dedicated to handle signals
Definition pcscdaemon.c:176
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
Definition pcscdaemon.c:103
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_VERSION_NUMBER
Current version.
Definition pcsclite.h:282
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition pcsclite.h:284
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:166
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:138
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.