58#include <systemd/sd-daemon.h>
70#include "configfile.h"
74_Atomic
bool AraKiri =
false;
75static bool Init =
true;
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;
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);
107 uint32_t dwClientID = 0;
115 (void)HPStopHotPluggables();
120 ContextsDeinitialize();
124 EHDeinitializeEventStructures();
132 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
136 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
148 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
162 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
185 r = read(signal_handler_fd[0], &sig,
sizeof sig);
188 Log2(PCSC_LOG_ERROR,
"read failed: %s", strerror(errno));
192 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
199 HPReCheckSerialReaders();
203 (void)signal(SIGUSR1, signal_trap);
212 Log1(PCSC_LOG_INFO,
"Direct suicide");
213 ExitValue = EXIT_SUCCESS;
220 ExitValue = EXIT_SUCCESS;
224 if (AraKiri ==
false)
226 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
234 Log1(PCSC_LOG_INFO,
"Suicide during init");
241 static int lives = 2;
247 Log1(PCSC_LOG_INFO,
"Forced suicide");
257int main(
int argc,
char **argv)
260 bool setToForeground;
263 char *newReaderConfig = NULL;
265 struct stat fStatBuf;
266 int customMaxThreadCounter = 0;
267 int customMaxReaderHandles = 0;
268 int customMaxThreadCardHandles = 0;
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},
296#define OPT_STRING "c:fTdhvaieCHt:r:s:xSI"
298 setToForeground =
false;
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);
321 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
326#ifdef HAVE_GETOPT_LONG
327 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
329 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
332#ifdef HAVE_GETOPT_LONG
334 if (strcmp(long_options[option_index].name,
335 "force-reader-polling") == 0)
336 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
339 if (strcmp(long_options[option_index].name,
340 "disable-polkit") == 0)
341 disable_polkit =
true;
346 Log2(PCSC_LOG_INFO,
"using new config directory: %s", optarg);
347 newReaderConfig = optarg;
352 setToForeground =
true;
354 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
356 "pcscd set to foreground with debug send to stdout");
360 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
361 Log1(PCSC_LOG_INFO,
"Force colored logs");
365 DebugLogSetLevel(PCSC_LOG_DEBUG);
369 DebugLogSetLevel(PCSC_LOG_INFO);
373 DebugLogSetLevel(PCSC_LOG_ERROR);
377 DebugLogSetLevel(PCSC_LOG_CRITICAL);
381 print_usage (argv[0]);
389 DebugLogSetCategory(DEBUG_CATEGORY_APDU);
394 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
399 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
400 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
401 customMaxThreadCounter);
405 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
406 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
407 customMaxReaderHandles);
411 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
412 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
413 customMaxThreadCardHandles);
418 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
419 TIME_BEFORE_SUICIDE);
423 Add_Serial_In_Name =
false;
427 Add_Interface_In_Name =
false;
431 print_usage (argv[0]);
439 printf(
"Unknown option: %s\n", argv[optind]);
440 print_usage(argv[0]);
448 rv = sd_listen_fds(0);
451 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
458 SocketActivated =
true;
459 Log1(PCSC_LOG_INFO,
"Started by systemd");
462 SocketActivated =
false;
470 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
473 if (rv == 0 && !SocketActivated)
480 pid = GetDaemonPid();
485 return SendHotplugSignal();
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);
505 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
513 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
514 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
522 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
531 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
538 if (!setToForeground)
543 if (pipe(pipefd) == -1)
545 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
552 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
558 fd = open(
"/dev/null", O_RDWR);
561 dup2(fd, STDIN_FILENO);
562 dup2(fd, STDOUT_FILENO);
563 dup2(fd, STDERR_FILENO);
580 ret = read(pipefd[0], &buf, 1);
601 (void)signal(SIGQUIT, signal_trap);
602 (void)signal(SIGTERM, signal_trap);
603 (void)signal(SIGINT, signal_trap);
606 (void)signal(SIGALRM, signal_trap);
608 if (pipe(signal_handler_fd) == -1)
610 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
614 pthread_t signal_handler_thread;
615 rv = pthread_create(&signal_handler_thread, NULL,
signal_thread, NULL);
618 Log2(PCSC_LOG_CRITICAL,
"pthread_create failed: %s", strerror(rv));
626 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
628 rv = mkdir(PCSCLITE_IPC_DIR, mode);
629 if ((rv != 0) && (errno != EEXIST))
631 Log2(PCSC_LOG_CRITICAL,
632 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
639 (void)chmod(PCSCLITE_IPC_DIR, mode);
645 rv = RFAllocateReaderSpace(customMaxReaderHandles);
655 rv = RFStartSerialReaders(newReaderConfig);
658 Log3(PCSC_LOG_CRITICAL,
"invalid directory %s: %s", newReaderConfig,
665 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
671 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
681 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
683 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
686 char pid[PID_ASCII_SIZE];
689 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
690 rr = write(f, pid, strlen(pid) + 1);
693 Log2(PCSC_LOG_CRITICAL,
694 "writing " PCSCLITE_RUN_PID
" failed: %s",
701 (void)fchmod(f, mode);
706 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
718 (void)signal(SIGUSR1, signal_trap);
725 rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
732 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
739 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
743 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
747 (void)signal(SIGPIPE, SIG_IGN);
748 (void)signal(SIGHUP, SIG_IGN);
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);
756#if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
760 rv = HPSearchHotPluggables(hpDirPath);
768 rv = HPRegisterForHotplugEvents(hpDirPath);
771 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
775 RFWaitForReaderInit();
785 rr = write(pipefd[1], &buf, 1);
788 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
796 Log2(PCSC_LOG_DEBUG,
"Starting suicide alarm in %d seconds",
797 TIME_BEFORE_SUICIDE);
798 alarm(TIME_BEFORE_SUICIDE);
803 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
807static void at_exit(
void)
809 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
820 r = write(pipefd[1], &buf, 1);
823 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
831static void clean_temp_files(
void)
835 if (!SocketActivated)
837 rv = remove(PCSCLITE_CSOCK_NAME);
839 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
843 rv = remove(PCSCLITE_RUN_PID);
845 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
849static void signal_trap(
int sig)
853 r = write(signal_handler_fd[1], &sig,
sizeof sig);
855 Log2(PCSC_LOG_ERROR,
"write failed: %s", strerror(errno));
858static void print_version(
void)
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");
866 printf(
"Enabled features:%s\n", PCSCLITE_FEATURES);
867 printf(
"MAX_READERNAME: %d, PCSCLITE_MAX_READERS_CONTEXTS: %d\n",
871static void print_usage(
char const *
const progname)
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");
878 printf(
" -c, --config new reader.conf.d path\n");
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");
899 printf(
" -a log APDU commands and results\n");
901 printf(
" -c new reader.conf.d path\n");
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);
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_S_SUCCESS
No error was encountered.
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.
static void * signal_thread(void *arg)
thread dedicated to handle signals
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_VERSION_NUMBER
Current version.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
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)
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
void SYS_InitRandom(void)
Initialize the random generator.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
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.