47 #include <sys/types.h>
63 #include "sd-daemon.h"
69 #include "configfile.h"
80 static char Init = TRUE;
82 char SocketActivated = FALSE;
83 static int ExitValue = EXIT_FAILURE;
84 int HPForceReaderPolling = 0;
85 static int pipefd[] = {-1, -1};
86 char Add_Serial_In_Name = TRUE;
87 char Add_Interface_In_Name = TRUE;
92 static void at_exit(
void);
93 static void clean_temp_files(
void);
94 static void signal_reload(
int sig);
95 static void signal_trap(
int);
96 static void print_version (
void);
97 static void print_usage (
char const *
const);
119 (void)HPStopHotPluggables();
125 EHDeinitializeEventStructures();
126 ContextsDeinitialize();
134 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
138 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
150 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
160 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
167 int main(
int argc,
char **argv)
170 char setToForeground;
172 char *newReaderConfig;
173 struct stat fStatBuf;
174 int customMaxThreadCounter = 0;
175 int customMaxReaderHandles = 0;
176 int customMaxThreadCardHandles = 0;
178 int limited_rights = FALSE;
180 #ifdef HAVE_GETOPT_LONG
181 int option_index = 0;
182 static struct option long_options[] = {
183 {
"config", 1, NULL,
'c'},
184 {
"foreground", 0, NULL,
'f'},
185 {
"color", 0, NULL,
'T'},
186 {
"help", 0, NULL,
'h'},
187 {
"version", 0, NULL,
'v'},
188 {
"apdu", 0, NULL,
'a'},
189 {
"debug", 0, NULL,
'd'},
190 {
"info", 0, NULL, 0},
191 {
"error", 0, NULL,
'e'},
192 {
"critical", 0, NULL,
'C'},
193 {
"hotplug", 0, NULL,
'H'},
194 {
"force-reader-polling", optional_argument, NULL, 0},
195 {
"max-thread", 1, NULL,
't'},
196 {
"max-card-handle-per-thread", 1, NULL,
's'},
197 {
"max-card-handle-per-reader", 1, NULL,
'r'},
198 {
"auto-exit", 0, NULL,
'x'},
199 {
"reader-name-no-serial", 0, NULL,
'S'},
200 {
"reader-name-no-interface", 0, NULL,
'I'},
204 #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI"
206 newReaderConfig = NULL;
207 setToForeground = FALSE;
215 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
216 printf(
" in pcsclite.h (%s) does not match the release version number\n",
218 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
227 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
230 limited_rights = (getgid() != getegid()) && (getuid() != 0);
235 #ifdef HAVE_GETOPT_LONG
236 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
238 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
241 #ifdef HAVE_GETOPT_LONG
243 if (strcmp(long_options[option_index].name,
244 "force-reader-polling") == 0)
245 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
251 Log1(PCSC_LOG_CRITICAL,
"Can't use a user specified config file");
254 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
255 newReaderConfig = optarg;
259 setToForeground = TRUE;
261 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
263 "pcscd set to foreground with debug send to stdout");
267 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
268 Log1(PCSC_LOG_INFO,
"Force colored logs");
272 DebugLogSetLevel(PCSC_LOG_DEBUG);
276 DebugLogSetLevel(PCSC_LOG_ERROR);
280 DebugLogSetLevel(PCSC_LOG_CRITICAL);
284 print_usage (argv[0]);
294 Log1(PCSC_LOG_CRITICAL,
"Can't log APDU (restricted)");
297 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
302 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
307 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
308 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
309 customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
310 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
311 customMaxThreadCounter);
315 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
316 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
317 customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
318 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
319 customMaxReaderHandles);
323 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
324 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
325 customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
326 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
327 customMaxThreadCardHandles);
332 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
333 TIME_BEFORE_SUICIDE);
337 Add_Serial_In_Name = FALSE;
341 Add_Interface_In_Name = FALSE;
345 print_usage (argv[0]);
353 printf(
"Unknown option: %s\n", argv[optind]);
354 print_usage(argv[0]);
361 rv = sd_listen_fds(0);
364 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
371 SocketActivated = TRUE;
372 Log1(PCSC_LOG_INFO,
"Started by systemd");
375 SocketActivated = FALSE;
382 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
385 if (rv == 0 && !SocketActivated)
392 pid = GetDaemonPid();
397 return SendHotplugSignal();
402 Log1(PCSC_LOG_CRITICAL,
403 "file " PCSCLITE_CSOCK_NAME
" already exists.");
404 Log2(PCSC_LOG_CRITICAL,
405 "Another pcscd (pid: %d) seems to be running.", pid);
417 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
425 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
426 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
434 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
443 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
450 if (!setToForeground)
455 if (pipe(pipefd) == -1)
457 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
464 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
470 fd = open(
"/dev/null", O_RDWR);
473 dup2(fd, STDIN_FILENO);
474 dup2(fd, STDOUT_FILENO);
475 dup2(fd, STDERR_FILENO);
492 ret = read(pipefd[0], &buf, 1);
513 (void)signal(SIGQUIT, signal_trap);
514 (void)signal(SIGTERM, signal_trap);
515 (void)signal(SIGINT, signal_trap);
518 (void)signal(SIGALRM, signal_trap);
524 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
526 rv = mkdir(PCSCLITE_IPC_DIR, mode);
527 if ((rv != 0) && (errno != EEXIST))
529 Log2(PCSC_LOG_CRITICAL,
530 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
537 (void)chmod(PCSCLITE_IPC_DIR, mode);
543 rv = RFAllocateReaderSpace(customMaxReaderHandles);
553 rv = RFStartSerialReaders(newReaderConfig);
556 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
563 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
569 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
579 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
581 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
584 char pid[PID_ASCII_SIZE];
587 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
588 rr = write(f, pid, strlen(pid) + 1);
591 Log2(PCSC_LOG_CRITICAL,
592 "writing " PCSCLITE_RUN_PID
" failed: %s",
600 (void)chmod(PCSCLITE_RUN_PID, mode);
603 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
615 (void)signal(SIGUSR1, signal_reload);
627 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
634 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
638 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
642 (void)signal(SIGPIPE, SIG_IGN);
643 (void)signal(SIGHUP, SIG_IGN);
646 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
650 rv = HPSearchHotPluggables();
656 rv = HPRegisterForHotplugEvents();
659 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
663 RFWaitForReaderInit();
678 rr = write(pipefd[1], &buf, 1);
681 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
688 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
692 static void at_exit(
void)
694 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
705 r = write(pipefd[1], &buf, 1);
708 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
716 static void clean_temp_files(
void)
720 if (!SocketActivated)
722 rv =
remove(PCSCLITE_CSOCK_NAME);
724 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
728 rv =
remove(PCSCLITE_RUN_PID);
730 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
734 static void signal_reload(
int sig)
736 (void)signal(SIGUSR1, signal_reload);
744 HPReCheckSerialReaders();
748 static void signal_trap(
int sig)
750 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
756 Log1(PCSC_LOG_INFO,
"Direct suicide");
763 ExitValue = EXIT_SUCCESS;
767 if (AraKiri == FALSE)
769 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
777 Log1(PCSC_LOG_INFO,
"Suicide during init");
784 static int lives = 2;
790 Log1(PCSC_LOG_INFO,
"Forced suicide");
796 static void print_version (
void)
798 printf(
"%s version %s.\n", PACKAGE, VERSION);
799 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
800 printf(
"Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
801 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
802 printf(
"Report bugs to <muscle@lists.musclecard.com>.\n");
804 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
807 static void print_usage (
char const *
const progname)
809 printf(
"Usage: %s options\n", progname);
810 printf(
"Options:\n");
811 #ifdef HAVE_GETOPT_LONG
812 printf(
" -a, --apdu log APDU commands and results\n");
813 printf(
" -c, --config path to reader.conf\n");
814 printf(
" -f, --foreground run in foreground (no daemon),\n");
815 printf(
" send logs to stdout instead of syslog\n");
816 printf(
" -T, --color force use of colored logs\n");
817 printf(
" -h, --help display usage information\n");
818 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
819 printf(
" -v, --version display the program version number\n");
820 printf(
" -d, --debug display lower level debug messages\n");
821 printf(
" --info display info level debug messages\n");
822 printf(
" -e --error display error level debug messages (default level)\n");
823 printf(
" -C --critical display critical only level debug messages\n");
824 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
825 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
826 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
827 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
828 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
829 printf(
" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
830 printf(
" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
832 printf(
" -a log APDU commands and results\n");
833 printf(
" -c path to reader.conf\n");
834 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
835 printf(
" -T force use of colored logs\n");
836 printf(
" -d display debug messages.\n");
837 printf(
" -e display error messages (default level).\n");
838 printf(
" -C display critical messages.\n");
839 printf(
" -h display usage information\n");
840 printf(
" -H ask the daemon to rescan the available readers\n");
841 printf(
" -v display the program version number\n");
842 printf(
" -t maximum number of threads\n");
843 printf(
" -s maximum number of card handle per thread\n");
844 printf(
" -r maximum number of card handle per reader\n");
845 printf(
" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
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.
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx