1/*
2 *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 *  @APPLE_LICENSE_HEADER_START@
5 *
6 *  This file contains Original Code and/or Modifications of Original Code
7 *  as defined in and that are subject to the Apple Public Source License
8 *  Version 2.0 (the 'License'). You may not use this file except in
9 *  compliance with the License. Please obtain a copy of the License at
10 *  http://www.opensource.apple.com/apsl/ and read it before using this
11 *  file.
12 *
13 *  The Original Code and all software distributed under the License are
14 *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 *  Please see the License for the specific language governing rights and
19 *  limitations under the License.
20 *
21 *  @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 *  pcscdaemon.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 1999-2005
33 *  David Corcoran <corcoran@linuxnet.com>
34 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
35 *
36 * $Id: pcscdaemon.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
37 */
38
39/**
40 * @file
41 * @brief This is the main pcscd daemon.
42 *
43 * The function \c main() starts up the communication environment.\n
44 * Then an endless loop is calld to look for Client connections. For each
45 * Client connection a call to \c CreateContextThread() is done.
46 */
47
48#include "config.h"
49#include <time.h>
50#include <syslog.h>
51#include <signal.h>
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <sys/errno.h>
55#include <stdio.h>
56#include <unistd.h>
57#include <stdlib.h>
58#include <string.h>
59#ifdef HAVE_GETOPT_H
60#include <getopt.h>
61#endif
62
63#include "wintypes.h"
64#include "pcsclite.h"
65#include "debuglog.h"
66#include "winscard_msg.h"
67#include "winscard_svc.h"
68#include "sys_generic.h"
69#include "thread_generic.h"
70#include "hotplug.h"
71#include "readerfactory.h"
72#include "configfile.h"
73#include "powermgt_generic.h"
74
75#include <security_utilities/debugging.h>
76
77char AraKiri = 0;
78static char Init = 1;
79int HPForceReaderPolling = 0;
80
81char **globalArgv;
82
83/*
84 * Some internal functions
85 */
86void SVCServiceRunLoop(void);
87void SVCClientCleanup(psharedSegmentMsg);
88void at_exit(void);
89void clean_temp_files(void);
90void signal_reload(int sig);
91void signal_trap(int);
92void print_version (void);
93void print_usage (char const * const);
94int ProcessHotplugRequest();
95
96PCSCLITE_MUTEX usbNotifierMutex;
97
98#ifdef USE_RUN_PID
99pid_t GetDaemonPid(void);
100pid_t GetDaemonPid(void)
101{
102	FILE *f;
103	pid_t pid;
104
105	/* pids are only 15 bits but 4294967296
106	 * (32 bits in case of a new system use it) is on 10 bytes
107	 */
108	if ((f = fopen(USE_RUN_PID, "rb")) != NULL)
109	{
110#define PID_ASCII_SIZE 11
111		char pid_ascii[PID_ASCII_SIZE];
112
113		fgets(pid_ascii, PID_ASCII_SIZE, f);
114		fclose(f);
115
116		pid = atoi(pid_ascii);
117	}
118	else
119	{
120		Log2(PCSC_LOG_CRITICAL, "Can't open " USE_RUN_PID ": %s",
121			strerror(errno));
122		return -1;
123	}
124
125	return pid;
126} /* GetDaemonPid */
127#endif
128
129int SendHotplugSignal(void)
130{
131#ifdef USE_RUN_PID
132	pid_t pid;
133
134	pid = GetDaemonPid();
135
136	if (pid != -1)
137	{
138		Log2(PCSC_LOG_INFO, "Send hotplug signal to pcscd (pid=%d)", pid);
139		if (kill(pid, SIGUSR1) < 0)
140		{
141			Log3(PCSC_LOG_CRITICAL, "Can't signal pcscd (pid=%d): %s",
142				pid, strerror(errno));
143			return EXIT_FAILURE ;
144		}
145	}
146#endif
147
148	return EXIT_SUCCESS;
149} /* SendHotplugSignal */
150
151int ProcessHotplugRequest()
152{
153#ifdef USE_RUN_PID
154
155	/* read the pid file to get the old pid and test if the old pcscd is
156	 * still running
157	 */
158	if (GetDaemonPid() != -1)
159		return SendHotplugSignal();
160
161	Log1(PCSC_LOG_CRITICAL, "file " USE_RUN_PID " does not exist");
162	Log1(PCSC_LOG_CRITICAL,	"Perhaps pcscd is not running?");
163#else
164	struct stat tmpStat;
165	if (SYS_Stat(PCSCLITE_CSOCK_NAME, &tmpStat) == 0)	// socket file exists, so maybe pcscd is running
166		return SendHotplugSignal();
167	Log1(PCSC_LOG_CRITICAL, "pcscd was not configured with --enable-runpid=FILE");
168#endif
169	Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
170	return EXIT_FAILURE;
171}
172
173/*
174 * Cleans up messages still on the queue when a client dies
175 */
176void SVCClientCleanup(psharedSegmentMsg msgStruct)
177{
178	/*
179	 * May be implemented in future releases
180	 */
181}
182
183/**
184 * @brief The Server's Message Queue Listener function.
185 *
186 * An endless loop calls the function \c SHMProcessEventsServer() to check for
187 * messages sent by clients.
188 * If the message is valid, \c CreateContextThread() is called to serve this
189 * request.
190 */
191void SVCServiceRunLoop(void)
192{
193	int rsp;
194	LONG rv;
195	DWORD dwClientID;	/* Connection ID used to reference the Client */
196
197	rsp = 0;
198	rv = 0;
199
200	/*
201	 * Initialize the comm structure
202	 */
203	rsp = SHMInitializeCommonSegment();
204
205	if (rsp == -1)
206	{
207		Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
208		exit(-1);
209	}
210
211	/*
212	 * Initialize the contexts structure
213	 */
214	rv = ContextsInitialize();
215
216	if (rv == -1)
217	{
218		Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
219		exit(-1);
220	}
221
222	/*
223	 * Solaris sends a SIGALRM and it is annoying
224	 */
225
226	signal(SIGALRM, SIG_IGN);
227	signal(SIGPIPE, SIG_IGN);
228	signal(SIGHUP, SIG_IGN);	/* needed for Solaris. The signal is sent
229				 * when the shell is existed */
230
231	/*
232	 * This function always returns zero
233	 */
234	rsp = SYS_MutexInit(&usbNotifierMutex);
235
236	/*
237	 * Set up the search for USB/PCMCIA devices
238	 */
239	HPSearchHotPluggables();
240	HPRegisterForHotplugEvents();
241
242	/*
243	 * Set up the power management callback routine
244	 */
245//	PMRegisterForPowerEvents();
246
247	while (1)
248	{
249		switch (rsp = SHMProcessEventsServer(&dwClientID, 0))
250		{
251
252		case 0:
253			Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
254			rv = CreateContextThread(&dwClientID);
255
256 			if (rv != SCARD_S_SUCCESS)
257			{
258				Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
259				AraKiri = 1;
260			}
261
262			break;
263
264		case 2:
265			/*
266			 * timeout in SHMProcessEventsServer(): do nothing
267			 * this is used to catch the Ctrl-C signal at some time when
268			 * nothing else happens
269			 */
270			break;
271
272		case -1:
273			Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
274			break;
275
276		case -2:
277			/* Nothing to do in case of a syscall interrupted
278			 * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
279			 * We just try again */
280			break;
281
282		default:
283			Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
284				rsp);
285			break;
286		}
287
288		if (AraKiri)
289		{
290			/* stop the hotpug thread and waits its exit */
291			Log1(PCSC_LOG_ERROR, "Preparing to exit...");
292			HPStopHotPluggables();
293			SYS_Sleep(1);
294
295			/* now stop all the drivers */
296			RFCleanupReaders(1);
297		}
298	}
299}
300
301int main(int argc, char **argv)
302{
303	int rv;
304	char setToForeground;
305	char HotPlug;
306	char *newReaderConfig;
307	struct stat fStatBuf;
308	int opt;
309#ifdef HAVE_GETOPT_LONG
310	int option_index = 0;
311	static struct option long_options[] = {
312		{"config", 1, 0, 'c'},
313		{"foreground", 0, 0, 'f'},
314		{"help", 0, 0, 'h'},
315		{"version", 0, 0, 'v'},
316		{"apdu", 0, 0, 'a'},
317		{"debug", 0, 0, 'd'},
318		{"info", 0, 0, 0},
319		{"error", 0, 0, 'e'},
320		{"critical", 0, 0, 'C'},
321		{"hotplug", 0, 0, 'H'},
322		{"force-reader-polling", optional_argument, 0, 0},
323		{0, 0, 0, 0}
324	};
325#endif
326#define OPT_STRING "c:fdhvaeCH"
327
328	rv = 0;
329	newReaderConfig = NULL;
330	setToForeground = 0;
331	HotPlug = 0;
332	globalArgv = argv;
333
334	/*
335	 * test the version
336	 */
337	if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
338	{
339		printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
340		printf("  in pcsclite.h (%s) does not match the release version number\n",
341			PCSCLITE_VERSION_NUMBER);
342		printf("  generated in config.h (%s) (see configure.in).\n", VERSION);
343
344		return EXIT_FAILURE;
345	}
346
347	/*
348	 * By default we create a daemon (not connected to any output)
349	 * The log will go to wherever securityd log output goes.
350	 */
351	DebugLogSetLogType(DEBUGLOG_NO_DEBUG);
352
353	/*
354	 * Handle any command line arguments
355	 */
356#ifdef  HAVE_GETOPT_LONG
357	while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
358#else
359	while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
360#endif
361		switch (opt) {
362#ifdef  HAVE_GETOPT_LONG
363			case 0:
364				if (strcmp(long_options[option_index].name,
365					"force-reader-polling") == 0)
366					HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
367				break;
368#endif
369			case 'c':
370				Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
371				newReaderConfig = optarg;
372				break;
373
374			case 'f':
375				setToForeground = 1;
376				/* debug to stderr instead of default syslog */
377				Log1(PCSC_LOG_INFO,
378					"pcscd set to foreground with debug send to stderr");
379				break;
380
381			case 'd':
382				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
383				DebugLogSetLevel(PCSC_LOG_DEBUG);
384				break;
385
386			case 'e':
387				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
388				DebugLogSetLevel(PCSC_LOG_ERROR);
389				break;
390
391			case 'C':
392				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
393				DebugLogSetLevel(PCSC_LOG_CRITICAL);
394				break;
395
396			case 'h':
397				print_usage (argv[0]);
398				return EXIT_SUCCESS;
399
400			case 'v':
401				print_version ();
402				return EXIT_SUCCESS;
403
404			case 'a':
405				DebugLogSetCategory(DEBUG_CATEGORY_APDU);
406				break;
407
408			case 'H':
409				/* debug to stderr instead of default syslog */
410				DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
411				HotPlug = 1;
412				break;
413
414			default:
415				print_usage (argv[0]);
416				return EXIT_FAILURE;
417		}
418
419	}
420
421	if (argv[optind])
422	{
423		printf("Unknown option: %s\n\n", argv[optind]);
424		print_usage(argv[0]);
425		return EXIT_SUCCESS;
426	}
427
428	/*
429		If this run of pcscd has the hotplug option, just send a signal to the
430		running one and exit
431	*/
432
433	if (HotPlug)
434		return ProcessHotplugRequest();
435
436	/*
437	 * test the presence of /var/run/pcsc.comm
438	 */
439
440	rv = SYS_Stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
441
442	if (rv == 0)
443	{
444#ifdef USE_RUN_PID
445		pid_t pid;
446
447		/* read the pid file to get the old pid and test if the old pcscd is
448		 * still running
449		 */
450		pid = GetDaemonPid();
451
452		if (pid != -1)
453		{
454			if (kill(pid, 0) == 0)
455			{
456				Log2(PCSC_LOG_CRITICAL,
457					"Another pcscd (pid: %d) seems to be running.", pid);
458				Log1(PCSC_LOG_CRITICAL,
459					"Remove " USE_RUN_PID " if pcscd is not running to clear this message.");
460				return EXIT_FAILURE;
461			}
462			else
463				/* the old pcscd is dead. Do some cleanup */
464				clean_temp_files();
465		}
466#else
467		{
468			Log1(PCSC_LOG_CRITICAL,
469				"file " PCSCLITE_CSOCK_NAME " already exists.");
470			Log1(PCSC_LOG_CRITICAL,
471				"Maybe another pcscd is running?");
472			Log1(PCSC_LOG_CRITICAL,
473				"Remove " PCSCLITE_CSOCK_NAME "if pcscd is not running to clear this message.");
474			return EXIT_FAILURE;
475		}
476#endif
477	}
478
479	/*
480	 * If this is set to one the user has asked it not to fork
481	 */
482	if (!setToForeground)
483	{
484		if (SYS_Daemon(0, 0))
485			Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
486				strerror(errno));
487	}
488
489	/*
490	 * cleanly remove /tmp/pcsc when exiting
491	 */
492	signal(SIGQUIT, signal_trap);
493	signal(SIGTERM, signal_trap);
494	signal(SIGINT, signal_trap);
495	signal(SIGHUP, signal_trap);
496
497#ifdef USE_RUN_PID
498	/*
499	 * Record our pid to make it easier
500	 * to kill the correct pcscd
501	 */
502	{
503		FILE *f;
504
505		if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
506		{
507			fprintf(f, "%u\n", (unsigned) getpid());
508			fclose(f);
509		}
510	}
511#endif
512
513	/*
514	 * If PCSCLITE_IPC_DIR does not exist then create it
515	 */
516	rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
517	if (rv < 0)
518	{
519		rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
520		if (rv != 0)
521		{
522			Log2(PCSC_LOG_CRITICAL,
523				"cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
524			return EXIT_FAILURE;
525		}
526	}
527
528	/* cleanly remove /var/run/pcsc.* files when exiting */
529	if (atexit(at_exit))
530		Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
531
532	/*
533	 * Allocate memory for reader structures
534	 */
535	RFAllocateReaderSpace();
536
537	/*
538		Grab the information from the reader.conf. If a file has been specified
539		and there is any error, consider it fatal. If no file was explicitly
540		specified, ignore if file not present.
541
542		 DBUpdateReaders returns:
543
544		 1	if config file can't be opened
545		 -1	if config file is broken
546		 0	if all good
547
548		We skip this step if running in 64 bit mode, as serial readers are considered
549		legacy code.
550	*/
551
552	rv = RFStartSerialReaders(newReaderConfig?newReaderConfig:PCSCLITE_READER_CONFIG);
553	if (rv == -1)
554	{
555		Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
556				strerror(errno));
557		at_exit();
558	}
559	else
560	if ((rv == 1) && newReaderConfig)
561	{
562		Log3(PCSC_LOG_CRITICAL, "file %s can't be opened: %s",
563				 newReaderConfig, strerror(errno));
564		at_exit();
565	}
566
567	/*
568	 * Set the default globals
569	 */
570	g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
571	g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
572	g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
573
574	Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
575
576	/*
577	 * post initialistion
578	 */
579	Init = 0;
580
581	/*
582	 * signal_trap() does just set a global variable used by the main loop
583	 */
584	signal(SIGQUIT, signal_trap);
585	signal(SIGTERM, signal_trap);
586	signal(SIGINT, signal_trap);
587	signal(SIGHUP, signal_trap);
588
589	signal(SIGUSR1, signal_reload);
590
591	SVCServiceRunLoop();
592
593	Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
594	return EXIT_FAILURE;
595}
596
597void at_exit(void)
598{
599	Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
600
601	clean_temp_files();
602
603	SYS_Exit(EXIT_SUCCESS);
604}
605
606void clean_temp_files(void)
607{
608	int rv;
609
610	rv = SYS_Unlink(PCSCLITE_CSOCK_NAME);
611	if (rv != 0)
612		Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s",
613			strerror(errno));
614
615#ifdef USE_RUN_PID
616	rv = SYS_Unlink(USE_RUN_PID);
617	if (rv != 0)
618		Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s",
619			strerror(errno));
620#endif
621}
622
623void signal_reload(int sig)
624{
625	static int rescan_ongoing = 0;
626
627	if (AraKiri)
628		return;
629
630	Log1(PCSC_LOG_INFO, "Reload serial configuration");
631	if (rescan_ongoing)
632	{
633		Log1(PCSC_LOG_INFO, "Rescan already ongoing");
634		return;
635	}
636
637	rescan_ongoing = 0;
638
639	HPReCheckSerialReaders();
640
641	rescan_ongoing = 0;
642	Log1(PCSC_LOG_INFO, "End reload serial configuration");
643} /* signal_reload */
644
645void signal_trap(int sig)
646{
647	/* the signal handler is called several times for the same Ctrl-C */
648	if (AraKiri == 0)
649	{
650		Log1(PCSC_LOG_INFO, "Preparing for suicide");
651		AraKiri = 1;
652
653		/* if still in the init/loading phase the AraKiri will not be
654		 * seen by the main event loop
655		 */
656		if (Init)
657		{
658			Log1(PCSC_LOG_INFO, "Suicide during init");
659			at_exit();
660		}
661	}
662}
663
664#if MAX_OS_X_VERSION_MIN_REQUIRED <= MAX_OS_X_VERSION_10_5
665	#include <spawn.h>
666	#include <err.h>
667	#include <CoreFoundation/CFBundle.h>
668	#include <CoreFoundation/CFNumber.h>
669#endif
670
671extern char **environ;
672void print_version (void)
673{
674	printf("%s version %s.\n",  PACKAGE, VERSION);
675	printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
676	printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
677	printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
678	printf("Portions Copyright (C) 2000-2007 by Apple Inc.\n");
679	printf("Report bugs to <sclinux@linuxnet.com>.\n");
680}
681
682void print_usage (char const * const progname)
683{
684	printf("Usage: %s options\n", progname);
685	printf("Options:\n");
686#ifdef HAVE_GETOPT_LONG
687	printf("  -a, --apdu		log APDU commands and results\n");
688	printf("  -c, --config		path to reader.conf\n");
689	printf("  -f, --foreground	run in foreground (no daemon),\n");
690	printf("			send logs to stderr instead of syslog\n");
691	printf("  -h, --help		display usage information\n");
692	printf("  -H, --hotplug		ask the daemon to rescan the available readers\n");
693	printf("  -v, --version		display the program version number\n");
694	printf("  -d, --debug	 	display lower level debug messages\n");
695	printf("      --info	 	display info level debug messages (default level)\n");
696	printf("  -e  --error	 	display error level debug messages\n");
697	printf("  -C  --critical 	display critical only level debug messages\n");
698	printf("  --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
699#else
700	printf("  -a    log APDU commands and results\n");
701	printf("  -c 	path to reader.conf\n");
702	printf("  -f	run in foreground (no daemon), send logs to stderr instead of syslog\n");
703	printf("  -d 	display debug messages. Output may be:\n");
704	printf("  -h 	display usage information\n");
705	printf("  -H	ask the daemon to rescan the avaiable readers\n");
706	printf("  -v 	display the program version number\n");
707#endif
708}
709
710