45 #include <sys/types.h>
61 #include "sd-daemon.h"
67 #include "configfile.h"
78 static char Init = TRUE;
80 char SocketActivated = FALSE;
81 static int ExitValue = EXIT_FAILURE;
82 int HPForceReaderPolling = 0;
83 static int pipefd[] = {-1, -1};
84 char Add_Serial_In_Name = TRUE;
85 char Add_Interface_In_Name = TRUE;
90 static void at_exit(
void);
91 static void clean_temp_files(
void);
92 static void signal_reload(
int sig);
93 static void signal_trap(
int);
94 static void print_version (
void);
95 static void print_usage (
char const *
const);
117 (void)HPStopHotPluggables();
123 EHDeinitializeEventStructures();
124 ContextsDeinitialize();
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");
158 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
165 int main(
int argc,
char **argv)
168 char setToForeground;
170 char *newReaderConfig;
171 struct stat fStatBuf;
172 int customMaxThreadCounter = 0;
173 int customMaxReaderHandles = 0;
174 int customMaxThreadCardHandles = 0;
176 int limited_rights = FALSE;
178 #ifdef HAVE_GETOPT_LONG
179 int option_index = 0;
180 static struct option long_options[] = {
181 {
"config", 1, NULL,
'c'},
182 {
"foreground", 0, NULL,
'f'},
183 {
"color", 0, NULL,
'T'},
184 {
"help", 0, NULL,
'h'},
185 {
"version", 0, NULL,
'v'},
186 {
"apdu", 0, NULL,
'a'},
187 {
"debug", 0, NULL,
'd'},
188 {
"info", 0, NULL, 0},
189 {
"error", 0, NULL,
'e'},
190 {
"critical", 0, NULL,
'C'},
191 {
"hotplug", 0, NULL,
'H'},
192 {
"force-reader-polling", optional_argument, NULL, 0},
193 {
"max-thread", 1, NULL,
't'},
194 {
"max-card-handle-per-thread", 1, NULL,
's'},
195 {
"max-card-handle-per-reader", 1, NULL,
'r'},
196 {
"auto-exit", 0, NULL,
'x'},
197 {
"reader-name-no-serial", 0, NULL,
'S'},
198 {
"reader-name-no-interface", 0, NULL,
'I'},
202 #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI"
204 newReaderConfig = NULL;
205 setToForeground = FALSE;
213 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
214 printf(
" in pcsclite.h (%s) does not match the release version number\n",
216 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
225 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
228 limited_rights = (getgid() != getegid()) && (getuid() != 0);
233 #ifdef HAVE_GETOPT_LONG
234 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
236 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
239 #ifdef HAVE_GETOPT_LONG
241 if (strcmp(long_options[option_index].name,
242 "force-reader-polling") == 0)
243 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
249 Log1(PCSC_LOG_CRITICAL,
"Can't use a user specified config file");
252 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
253 newReaderConfig = optarg;
257 setToForeground = TRUE;
259 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
261 "pcscd set to foreground with debug send to stdout");
265 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
266 Log1(PCSC_LOG_INFO,
"Force colored logs");
270 DebugLogSetLevel(PCSC_LOG_DEBUG);
274 DebugLogSetLevel(PCSC_LOG_ERROR);
278 DebugLogSetLevel(PCSC_LOG_CRITICAL);
282 print_usage (argv[0]);
292 Log1(PCSC_LOG_CRITICAL,
"Can't log APDU (restricted)");
295 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
300 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
305 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
306 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
307 customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
308 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
309 customMaxThreadCounter);
313 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
314 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
315 customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
316 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
317 customMaxReaderHandles);
321 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
322 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
323 customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
324 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
325 customMaxThreadCardHandles);
330 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
331 TIME_BEFORE_SUICIDE);
335 Add_Serial_In_Name = FALSE;
339 Add_Interface_In_Name = FALSE;
343 print_usage (argv[0]);
351 printf(
"Unknown option: %s\n", argv[optind]);
352 print_usage(argv[0]);
359 rv = sd_listen_fds(0);
362 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
369 SocketActivated = TRUE;
370 Log1(PCSC_LOG_INFO,
"Started by systemd");
373 SocketActivated = FALSE;
380 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
383 if (rv == 0 && !SocketActivated)
390 pid = GetDaemonPid();
395 return SendHotplugSignal();
400 Log1(PCSC_LOG_CRITICAL,
401 "file " PCSCLITE_CSOCK_NAME
" already exists.");
402 Log2(PCSC_LOG_CRITICAL,
403 "Another pcscd (pid: %d) seems to be running.", pid);
415 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
423 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
424 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
432 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
441 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
448 if (!setToForeground)
453 if (pipe(pipefd) == -1)
455 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
462 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
468 fd = open(
"/dev/null", O_RDWR);
471 dup2(fd, STDIN_FILENO);
472 dup2(fd, STDOUT_FILENO);
473 dup2(fd, STDERR_FILENO);
490 ret = read(pipefd[0], &buf, 1);
511 (void)signal(SIGQUIT, signal_trap);
512 (void)signal(SIGTERM, signal_trap);
513 (void)signal(SIGINT, signal_trap);
516 (void)signal(SIGALRM, signal_trap);
522 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
524 rv = mkdir(PCSCLITE_IPC_DIR, mode);
525 if ((rv != 0) && (errno != EEXIST))
527 Log2(PCSC_LOG_CRITICAL,
528 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
535 (void)chmod(PCSCLITE_IPC_DIR, mode);
541 rv = RFAllocateReaderSpace(customMaxReaderHandles);
551 rv = RFStartSerialReaders(newReaderConfig);
554 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
561 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
567 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
577 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
579 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
582 char pid[PID_ASCII_SIZE];
585 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
586 rr = write(f, pid, strlen(pid) + 1);
589 Log2(PCSC_LOG_CRITICAL,
590 "writing " PCSCLITE_RUN_PID
" failed: %s",
598 (void)chmod(PCSCLITE_RUN_PID, mode);
601 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
613 (void)signal(SIGUSR1, signal_reload);
625 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
632 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
636 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
640 (void)signal(SIGPIPE, SIG_IGN);
641 (void)signal(SIGHUP, SIG_IGN);
644 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
648 rv = HPSearchHotPluggables();
654 rv = HPRegisterForHotplugEvents();
657 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
661 RFWaitForReaderInit();
676 rr = write(pipefd[1], &buf, 1);
679 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
687 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
691 static void at_exit(
void)
693 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
704 r = write(pipefd[1], &buf, 1);
707 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
715 static void clean_temp_files(
void)
719 if (!SocketActivated)
721 rv =
remove(PCSCLITE_CSOCK_NAME);
723 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
727 rv =
remove(PCSCLITE_RUN_PID);
729 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
733 static void signal_reload(
int sig)
735 (void)signal(SIGUSR1, signal_reload);
743 HPReCheckSerialReaders();
747 static void signal_trap(
int sig)
749 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
755 Log1(PCSC_LOG_INFO,
"Direct suicide");
762 ExitValue = EXIT_SUCCESS;
766 if (AraKiri == FALSE)
768 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
776 Log1(PCSC_LOG_INFO,
"Suicide during init");
783 static int lives = 2;
789 Log1(PCSC_LOG_INFO,
"Forced suicide");
795 static void print_version (
void)
797 printf(
"%s version %s.\n", PACKAGE, VERSION);
798 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
799 printf(
"Copyright (C) 2001-2015 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
800 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
801 printf(
"Report bugs to <pcsclite-muscle@lists.alioth.debian.org>.\n");
803 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
806 static void print_usage (
char const *
const progname)
808 printf(
"Usage: %s options\n", progname);
809 printf(
"Options:\n");
810 #ifdef HAVE_GETOPT_LONG
811 printf(
" -a, --apdu log APDU commands and results\n");
812 printf(
" -c, --config path to reader.conf\n");
813 printf(
" -f, --foreground run in foreground (no daemon),\n");
814 printf(
" send logs to stdout instead of syslog\n");
815 printf(
" -T, --color force use of colored logs\n");
816 printf(
" -h, --help display usage information\n");
817 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
818 printf(
" -v, --version display the program version number\n");
819 printf(
" -d, --debug display lower level debug messages\n");
820 printf(
" --info display info level debug messages\n");
821 printf(
" -e --error display error level debug messages (default level)\n");
822 printf(
" -C --critical display critical only level debug messages\n");
823 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
824 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
825 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
826 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
827 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
828 printf(
" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
829 printf(
" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
831 printf(
" -a log APDU commands and results\n");
832 printf(
" -c path to reader.conf\n");
833 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
834 printf(
" -T force use of colored logs\n");
835 printf(
" -d display debug messages.\n");
836 printf(
" -e display error messages (default level).\n");
837 printf(
" -C display critical messages.\n");
838 printf(
" -h display usage information\n");
839 printf(
" -H ask the daemon to rescan the available readers\n");
840 printf(
" -v display the program version number\n");
841 printf(
" -t maximum number of threads\n");
842 printf(
" -s maximum number of card handle per thread\n");
843 printf(
" -r maximum number of card handle per reader\n");
844 printf(
" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
#define SCARD_S_SUCCESS
No error was encountered.
INTERNAL int32_t ListenExistingSocket(int fd)
Acquires a socket passed in from systemd.
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
This handles power management routines.
This handles abstract system level calls.
char AutoExit
Represents an Application Context on the Server side.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
This demarshalls functions over the message queue and keeps track of clients and their handles...
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.
ULONG PMRegisterForPowerEvents(void)
Registers for Power Management callbacks.
This handles card insertion/removal events, updates ATR, protocol, and status information.
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
This keeps a list of defines for pcsc-lite.
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.