24 #include <sys/types.h>
40 #include "sd-daemon.h"
46 #include "configfile.h"
57 static char Init = TRUE;
59 char SocketActivated = FALSE;
60 static int ExitValue = EXIT_FAILURE;
61 int HPForceReaderPolling = 0;
62 static int pipefd[] = {-1, -1};
63 char Add_Serial_In_Name = TRUE;
64 char Add_Interface_In_Name = TRUE;
69 static void at_exit(
void);
70 static void clean_temp_files(
void);
71 static void signal_reload(
int sig);
72 static void signal_trap(
int);
73 static void print_version (
void);
74 static void print_usage (
char const *
const);
96 (void)HPStopHotPluggables();
102 EHDeinitializeEventStructures();
103 ContextsDeinitialize();
111 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
115 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
127 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
137 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
144 int main(
int argc,
char **argv)
147 char setToForeground;
149 char *newReaderConfig;
150 struct stat fStatBuf;
151 int customMaxThreadCounter = 0;
152 int customMaxReaderHandles = 0;
153 int customMaxThreadCardHandles = 0;
155 int limited_rights = FALSE;
157 #ifdef HAVE_GETOPT_LONG
158 int option_index = 0;
159 static struct option long_options[] = {
160 {
"config", 1, NULL,
'c'},
161 {
"foreground", 0, NULL,
'f'},
162 {
"color", 0, NULL,
'T'},
163 {
"help", 0, NULL,
'h'},
164 {
"version", 0, NULL,
'v'},
165 {
"apdu", 0, NULL,
'a'},
166 {
"debug", 0, NULL,
'd'},
167 {
"info", 0, NULL, 0},
168 {
"error", 0, NULL,
'e'},
169 {
"critical", 0, NULL,
'C'},
170 {
"hotplug", 0, NULL,
'H'},
171 {
"force-reader-polling", optional_argument, NULL, 0},
172 {
"max-thread", 1, NULL,
't'},
173 {
"max-card-handle-per-thread", 1, NULL,
's'},
174 {
"max-card-handle-per-reader", 1, NULL,
'r'},
175 {
"auto-exit", 0, NULL,
'x'},
176 {
"reader-name-no-serial", 0, NULL,
'S'},
177 {
"reader-name-no-interface", 0, NULL,
'I'},
181 #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI"
183 newReaderConfig = NULL;
184 setToForeground = FALSE;
192 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
193 printf(
" in pcsclite.h (%s) does not match the release version number\n",
195 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
204 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
207 limited_rights = (getgid() != getegid()) && (getuid() != 0);
212 #ifdef HAVE_GETOPT_LONG
213 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
215 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
218 #ifdef HAVE_GETOPT_LONG
220 if (strcmp(long_options[option_index].name,
221 "force-reader-polling") == 0)
222 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
228 Log1(PCSC_LOG_CRITICAL,
"Can't use a user specified config file");
231 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
232 newReaderConfig = optarg;
236 setToForeground = TRUE;
238 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
240 "pcscd set to foreground with debug send to stdout");
244 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
245 Log1(PCSC_LOG_INFO,
"Force colored logs");
249 DebugLogSetLevel(PCSC_LOG_DEBUG);
253 DebugLogSetLevel(PCSC_LOG_ERROR);
257 DebugLogSetLevel(PCSC_LOG_CRITICAL);
261 print_usage (argv[0]);
271 Log1(PCSC_LOG_CRITICAL,
"Can't log APDU (restricted)");
274 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
279 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
284 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
285 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
286 customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
287 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
288 customMaxThreadCounter);
292 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
293 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
294 customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
295 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
296 customMaxReaderHandles);
300 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
301 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
302 customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
303 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
304 customMaxThreadCardHandles);
309 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
310 TIME_BEFORE_SUICIDE);
314 Add_Serial_In_Name = FALSE;
318 Add_Interface_In_Name = FALSE;
322 print_usage (argv[0]);
330 printf(
"Unknown option: %s\n", argv[optind]);
331 print_usage(argv[0]);
338 rv = sd_listen_fds(0);
341 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
348 SocketActivated = TRUE;
349 Log1(PCSC_LOG_INFO,
"Started by systemd");
352 SocketActivated = FALSE;
359 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
368 pid = GetDaemonPid();
373 return SendHotplugSignal();
378 Log1(PCSC_LOG_CRITICAL,
379 "file " PCSCLITE_CSOCK_NAME
" already exists.");
380 Log2(PCSC_LOG_CRITICAL,
381 "Another pcscd (pid: %d) seems to be running.", pid);
393 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
401 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
402 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
410 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
419 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
426 if (!setToForeground)
431 if (pipe(pipefd) == -1)
433 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
440 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
446 fd = open(
"/dev/null", O_RDWR);
449 dup2(fd, STDIN_FILENO);
450 dup2(fd, STDOUT_FILENO);
451 dup2(fd, STDERR_FILENO);
468 ret = read(pipefd[0], &buf, 1);
489 (void)signal(SIGQUIT, signal_trap);
490 (void)signal(SIGTERM, signal_trap);
491 (void)signal(SIGINT, signal_trap);
494 (void)signal(SIGALRM, signal_trap);
500 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
502 rv = mkdir(PCSCLITE_IPC_DIR, mode);
503 if ((rv != 0) && (errno != EEXIST))
505 Log2(PCSC_LOG_CRITICAL,
506 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
513 (void)chmod(PCSCLITE_IPC_DIR, mode);
519 rv = RFAllocateReaderSpace(customMaxReaderHandles);
529 rv = RFStartSerialReaders(newReaderConfig);
532 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
539 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
545 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
555 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
557 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
560 char pid[PID_ASCII_SIZE];
563 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
564 rr = write(f, pid, strlen(pid) + 1);
567 Log2(PCSC_LOG_CRITICAL,
568 "writing " PCSCLITE_RUN_PID
" failed: %s",
576 (void)chmod(PCSCLITE_RUN_PID, mode);
579 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
591 (void)signal(SIGUSR1, signal_reload);
603 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
610 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
614 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
618 (void)signal(SIGPIPE, SIG_IGN);
619 (void)signal(SIGHUP, SIG_IGN);
622 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
626 rv = HPSearchHotPluggables();
632 rv = HPRegisterForHotplugEvents();
635 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
639 RFWaitForReaderInit();
654 rr = write(pipefd[1], &buf, 1);
657 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
664 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
668 static void at_exit(
void)
670 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
681 r = write(pipefd[1], &buf, 1);
684 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
692 static void clean_temp_files(
void)
696 if (!SocketActivated)
698 rv =
remove(PCSCLITE_CSOCK_NAME);
700 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
704 rv =
remove(PCSCLITE_RUN_PID);
706 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
710 static void signal_reload(
int sig)
712 (void)signal(SIGUSR1, signal_reload);
720 HPReCheckSerialReaders();
724 static void signal_trap(
int sig)
726 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
732 Log1(PCSC_LOG_INFO,
"Direct suicide");
739 ExitValue = EXIT_SUCCESS;
743 if (AraKiri == FALSE)
745 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
753 Log1(PCSC_LOG_INFO,
"Suicide during init");
760 static int lives = 2;
766 Log1(PCSC_LOG_INFO,
"Forced suicide");
772 static void print_version (
void)
774 printf(
"%s version %s.\n", PACKAGE, VERSION);
775 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
776 printf(
"Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
777 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
778 printf(
"Report bugs to <muscle@lists.musclecard.com>.\n");
780 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
783 static void print_usage (
char const *
const progname)
785 printf(
"Usage: %s options\n", progname);
786 printf(
"Options:\n");
787 #ifdef HAVE_GETOPT_LONG
788 printf(
" -a, --apdu log APDU commands and results\n");
789 printf(
" -c, --config path to reader.conf\n");
790 printf(
" -f, --foreground run in foreground (no daemon),\n");
791 printf(
" send logs to stdout instead of syslog\n");
792 printf(
" -T, --color force use of colored logs\n");
793 printf(
" -h, --help display usage information\n");
794 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
795 printf(
" -v, --version display the program version number\n");
796 printf(
" -d, --debug display lower level debug messages\n");
797 printf(
" --info display info level debug messages\n");
798 printf(
" -e --error display error level debug messages (default level)\n");
799 printf(
" -C --critical display critical only level debug messages\n");
800 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
801 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
802 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
803 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
804 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
805 printf(
" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
806 printf(
" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
808 printf(
" -a log APDU commands and results\n");
809 printf(
" -c path to reader.conf\n");
810 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
811 printf(
" -T force use of colored logs\n");
812 printf(
" -d display debug messages.\n");
813 printf(
" -e display error messages (default level).\n");
814 printf(
" -C display critical messages.\n");
815 printf(
" -h display usage information\n");
816 printf(
" -H ask the daemon to rescan the available readers\n");
817 printf(
" -v display the program version number\n");
818 printf(
" -t maximum number of threads\n");
819 printf(
" -s maximum number of card handle per thread\n");
820 printf(
" -r maximum number of card handle per reader\n");
821 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