50 #include <sys/types.h> 66 #include "sd-daemon.h" 72 #include "configfile.h" 83 static char Init = TRUE;
85 char SocketActivated = FALSE;
86 static int ExitValue = EXIT_FAILURE;
87 int HPForceReaderPolling = 0;
88 static int pipefd[] = {-1, -1};
89 char Add_Serial_In_Name = TRUE;
90 char Add_Interface_In_Name = TRUE;
95 static void at_exit(
void);
96 static void clean_temp_files(
void);
97 static void signal_reload(
int sig);
98 static void signal_trap(
int);
99 static void print_version (
void);
100 static void print_usage (
char const *
const);
122 (void)HPStopHotPluggables();
128 EHDeinitializeEventStructures();
129 ContextsDeinitialize();
137 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
141 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
153 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
163 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
170 int main(
int argc,
char **argv)
173 char setToForeground;
175 char *newReaderConfig;
176 struct stat fStatBuf;
177 int customMaxThreadCounter = 0;
178 int customMaxReaderHandles = 0;
179 int customMaxThreadCardHandles = 0;
181 int limited_rights = FALSE;
183 #ifdef HAVE_GETOPT_LONG 184 int option_index = 0;
185 static struct option long_options[] = {
186 {
"config", 1, NULL,
'c'},
187 {
"foreground", 0, NULL,
'f'},
188 {
"color", 0, NULL,
'T'},
189 {
"help", 0, NULL,
'h'},
190 {
"version", 0, NULL,
'v'},
191 {
"apdu", 0, NULL,
'a'},
192 {
"debug", 0, NULL,
'd'},
193 {
"info", 0, NULL, 0},
194 {
"error", 0, NULL,
'e'},
195 {
"critical", 0, NULL,
'C'},
196 {
"hotplug", 0, NULL,
'H'},
197 {
"force-reader-polling", optional_argument, NULL, 0},
198 {
"max-thread", 1, NULL,
't'},
199 {
"max-card-handle-per-thread", 1, NULL,
's'},
200 {
"max-card-handle-per-reader", 1, NULL,
'r'},
201 {
"auto-exit", 0, NULL,
'x'},
202 {
"reader-name-no-serial", 0, NULL,
'S'},
203 {
"reader-name-no-interface", 0, NULL,
'I'},
207 #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI" 209 newReaderConfig = NULL;
210 setToForeground = FALSE;
218 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
219 printf(
" in pcsclite.h (%s) does not match the release version number\n",
221 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
230 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
233 limited_rights = (getgid() != getegid()) && (getuid() != 0);
238 #ifdef HAVE_GETOPT_LONG 239 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
241 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
244 #ifdef HAVE_GETOPT_LONG 246 if (strcmp(long_options[option_index].name,
247 "force-reader-polling") == 0)
248 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
254 Log1(PCSC_LOG_CRITICAL,
"Can't use a user specified config file");
257 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
258 newReaderConfig = optarg;
262 setToForeground = TRUE;
264 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
266 "pcscd set to foreground with debug send to stdout");
270 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
271 Log1(PCSC_LOG_INFO,
"Force colored logs");
275 DebugLogSetLevel(PCSC_LOG_DEBUG);
279 DebugLogSetLevel(PCSC_LOG_ERROR);
283 DebugLogSetLevel(PCSC_LOG_CRITICAL);
287 print_usage (argv[0]);
297 Log1(PCSC_LOG_CRITICAL,
"Can't log APDU (restricted)");
300 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
305 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
310 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
311 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
312 customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
313 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
314 customMaxThreadCounter);
318 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
319 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
320 customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
321 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
322 customMaxReaderHandles);
326 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
327 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
328 customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
329 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
330 customMaxThreadCardHandles);
335 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
336 TIME_BEFORE_SUICIDE);
340 Add_Serial_In_Name = FALSE;
344 Add_Interface_In_Name = FALSE;
348 print_usage (argv[0]);
356 printf(
"Unknown option: %s\n", argv[optind]);
357 print_usage(argv[0]);
364 rv = sd_listen_fds(0);
367 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
374 SocketActivated = TRUE;
375 Log1(PCSC_LOG_INFO,
"Started by systemd");
378 SocketActivated = FALSE;
385 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
394 pid = GetDaemonPid();
399 return SendHotplugSignal();
404 Log1(PCSC_LOG_CRITICAL,
405 "file " PCSCLITE_CSOCK_NAME
" already exists.");
406 Log2(PCSC_LOG_CRITICAL,
407 "Another pcscd (pid: %d) seems to be running.", pid);
419 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
427 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
428 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
436 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
445 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
452 if (!setToForeground)
457 if (pipe(pipefd) == -1)
459 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
466 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
472 fd = open(
"/dev/null", O_RDWR);
475 dup2(fd, STDIN_FILENO);
476 dup2(fd, STDOUT_FILENO);
477 dup2(fd, STDERR_FILENO);
494 ret = read(pipefd[0], &buf, 1);
515 (void)signal(SIGQUIT, signal_trap);
516 (void)signal(SIGTERM, signal_trap);
517 (void)signal(SIGINT, signal_trap);
520 (void)signal(SIGALRM, signal_trap);
526 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
528 rv = mkdir(PCSCLITE_IPC_DIR, mode);
529 if ((rv != 0) && (errno != EEXIST))
531 Log2(PCSC_LOG_CRITICAL,
532 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
539 (void)chmod(PCSCLITE_IPC_DIR, mode);
545 rv = RFAllocateReaderSpace(customMaxReaderHandles);
555 rv = RFStartSerialReaders(newReaderConfig);
558 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
565 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
571 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
581 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
583 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
586 char pid[PID_ASCII_SIZE];
589 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
590 rr = write(f, pid, strlen(pid) + 1);
593 Log2(PCSC_LOG_CRITICAL,
594 "writing " PCSCLITE_RUN_PID
" failed: %s",
602 (void)chmod(PCSCLITE_RUN_PID, mode);
605 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
617 (void)signal(SIGUSR1, signal_reload);
629 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
636 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
640 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
644 (void)signal(SIGPIPE, SIG_IGN);
645 (void)signal(SIGHUP, SIG_IGN);
648 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB) 652 rv = HPSearchHotPluggables();
658 rv = HPRegisterForHotplugEvents();
661 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
665 RFWaitForReaderInit();
680 rr = write(pipefd[1], &buf, 1);
683 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
690 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
694 static void at_exit(
void)
696 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
707 r = write(pipefd[1], &buf, 1);
710 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
718 static void clean_temp_files(
void)
722 if (!SocketActivated)
724 rv =
remove(PCSCLITE_CSOCK_NAME);
726 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
730 rv =
remove(PCSCLITE_RUN_PID);
732 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
736 static void signal_reload(
int sig)
738 (void)signal(SIGUSR1, signal_reload);
746 HPReCheckSerialReaders();
750 static void signal_trap(
int sig)
752 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
758 Log1(PCSC_LOG_INFO,
"Direct suicide");
765 ExitValue = EXIT_SUCCESS;
769 if (AraKiri == FALSE)
771 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
779 Log1(PCSC_LOG_INFO,
"Suicide during init");
786 static int lives = 2;
792 Log1(PCSC_LOG_INFO,
"Forced suicide");
798 static void print_version (
void)
800 printf(
"%s version %s.\n", PACKAGE, VERSION);
801 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
802 printf(
"Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
803 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
804 printf(
"Report bugs to <muscle@lists.musclecard.com>.\n");
806 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
809 static void print_usage (
char const *
const progname)
811 printf(
"Usage: %s options\n", progname);
812 printf(
"Options:\n");
813 #ifdef HAVE_GETOPT_LONG 814 printf(
" -a, --apdu log APDU commands and results\n");
815 printf(
" -c, --config path to reader.conf\n");
816 printf(
" -f, --foreground run in foreground (no daemon),\n");
817 printf(
" send logs to stdout instead of syslog\n");
818 printf(
" -T, --color force use of colored logs\n");
819 printf(
" -h, --help display usage information\n");
820 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
821 printf(
" -v, --version display the program version number\n");
822 printf(
" -d, --debug display lower level debug messages\n");
823 printf(
" --info display info level debug messages\n");
824 printf(
" -e --error display error level debug messages (default level)\n");
825 printf(
" -C --critical display critical only level debug messages\n");
826 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
827 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
828 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
829 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
830 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
831 printf(
" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
832 printf(
" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
834 printf(
" -a log APDU commands and results\n");
835 printf(
" -c path to reader.conf\n");
836 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
837 printf(
" -T force use of colored logs\n");
838 printf(
" -d display debug messages.\n");
839 printf(
" -e display error messages (default level).\n");
840 printf(
" -C display critical messages.\n");
841 printf(
" -h display usage information\n");
842 printf(
" -H ask the daemon to rescan the available readers\n");
843 printf(
" -v display the program version number\n");
844 printf(
" -t maximum number of threads\n");
845 printf(
" -s maximum number of card handle per thread\n");
846 printf(
" -r maximum number of card handle per reader\n");
847 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