1
2/*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004
8 *
9 */
10
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <unistd.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/time.h>
18#include <sys/resource.h>
19#include <sys/wait.h>
20#include <sys/stat.h>
21#include <sys/socket.h>
22#include <netdb.h>
23#include <pwd.h>
24#if (defined (__OpenBSD__) || defined (__FreeBSD__) || defined(__NetBSD__))
25#include <netinet/in.h>
26#endif
27#include <arpa/inet.h>
28#include <errno.h>
29#include <getopt.h>
30#include <sys/select.h>
31#include "trousers/tss.h"
32#include "trousers_types.h"
33#include "tcs_tsp.h"
34#include "tcs_utils.h"
35#include "tcs_int_literals.h"
36#include "capabilities.h"
37#include "tcslog.h"
38#include "tcsd_wrap.h"
39#include "tcsps.h"
40#include "tcsd.h"
41#include "req_mgr.h"
42
43struct tcsd_config tcsd_options;
44struct tpm_properties tpm_metrics;
45static volatile int hup = 0, term = 0;
46extern char *optarg;
47char *tcsd_config_file = NULL;
48
49struct srv_sock_info {
50	int sd;
51	int domain; // AF_INET or AF_INET6
52	socklen_t addr_len;
53};
54#define MAX_IP_PROTO 2
55#define INVALID_ADDR_STR "<Invalid client address>"
56
57static void close_server_socks(struct srv_sock_info *socks_info)
58{
59	int i, rv;
60
61	for (i=0; i < MAX_IP_PROTO; i++) {
62		if (socks_info[i].sd != -1) {
63			do {
64				rv = close(socks_info[i].sd);
65				if (rv == -1 && errno != EINTR) {
66					LogError("Error closing server socket descriptor - %s",
67							strerror(errno));
68					continue;
69				}
70			} while (rv == -1 && errno == EINTR);
71		}
72	}
73}
74
75static void
76tcsd_shutdown(struct srv_sock_info socks_info[])
77{
78	close_server_socks(socks_info);
79	/* order is important here:
80	 * allow all threads to complete their current request */
81	tcsd_threads_final();
82	PS_close_disk_cache();
83	auth_mgr_final();
84	(void)req_mgr_final();
85	conf_file_final(&tcsd_options);
86	EVENT_LOG_final();
87}
88
89static void
90tcsd_signal_term(int signal)
91{
92	term = 1;
93}
94
95void
96tcsd_signal_hup(int signal)
97{
98	hup = 1;
99}
100
101static TSS_RESULT
102signals_init(void)
103{
104	int rc;
105	sigset_t sigmask;
106	struct sigaction sa;
107
108	sigemptyset(&sigmask);
109	if ((rc = sigaddset(&sigmask, SIGTERM))) {
110		LogError("sigaddset: %s", strerror(errno));
111		return TCSERR(TSS_E_INTERNAL_ERROR);
112	}
113	if ((rc = sigaddset(&sigmask, SIGHUP))) {
114		LogError("sigaddset: %s", strerror(errno));
115		return TCSERR(TSS_E_INTERNAL_ERROR);
116	}
117
118	if ((rc = THREAD_SET_SIGNAL_MASK(SIG_UNBLOCK, &sigmask, NULL))) {
119		LogError("Setting thread signal mask: %s", strerror(rc));
120		return TCSERR(TSS_E_INTERNAL_ERROR);
121	}
122
123	sa.sa_flags = 0;
124	sigemptyset(&sa.sa_mask);
125	sa.sa_handler = tcsd_signal_term;
126	if ((rc = sigaction(SIGTERM, &sa, NULL))) {
127		LogError("signal SIGTERM not registered: %s", strerror(errno));
128		return TCSERR(TSS_E_INTERNAL_ERROR);
129	}
130
131	sa.sa_handler = tcsd_signal_hup;
132	if ((rc = sigaction(SIGHUP, &sa, NULL))) {
133		LogError("signal SIGHUP not registered: %s", strerror(errno));
134		return TCSERR(TSS_E_INTERNAL_ERROR);
135	}
136
137	return TSS_SUCCESS;
138}
139
140static TSS_RESULT
141tcsd_startup(void)
142{
143	TSS_RESULT result;
144
145#ifdef TSS_DEBUG
146	/* Set stdout to be unbuffered to match stderr and interleave output correctly */
147	setvbuf(stdout, (char *)NULL, _IONBF, 0);
148#endif
149
150	if ((result = signals_init()))
151		return result;
152
153	if ((result = conf_file_init(&tcsd_options)))
154		return result;
155
156	if ((result = tcsd_threads_init())) {
157		conf_file_final(&tcsd_options);
158		return result;
159	}
160
161	if ((result = req_mgr_init())) {
162		conf_file_final(&tcsd_options);
163		return result;
164	}
165
166	if ((result = ps_dirs_init())) {
167		conf_file_final(&tcsd_options);
168		(void)req_mgr_final();
169		return result;
170	}
171
172	result = PS_init_disk_cache();
173	if (result != TSS_SUCCESS) {
174		conf_file_final(&tcsd_options);
175		(void)req_mgr_final();
176		return result;
177	}
178
179	if ((result = get_tpm_metrics(&tpm_metrics))) {
180		conf_file_final(&tcsd_options);
181		PS_close_disk_cache();
182		(void)req_mgr_final();
183		return result;
184	}
185
186	/* must happen after get_tpm_metrics() */
187	if ((result = auth_mgr_init())) {
188		conf_file_final(&tcsd_options);
189		PS_close_disk_cache();
190		(void)req_mgr_final();
191		return result;
192	}
193
194	result = EVENT_LOG_init();
195	if (result != TSS_SUCCESS) {
196		auth_mgr_final();
197		conf_file_final(&tcsd_options);
198		PS_close_disk_cache();
199		(void)req_mgr_final();
200		return result;
201	}
202
203	result = owner_evict_init();
204	if (result != TSS_SUCCESS) {
205		auth_mgr_final();
206		conf_file_final(&tcsd_options);
207		PS_close_disk_cache();
208		(void)req_mgr_final();
209		return result;
210	}
211
212	return TSS_SUCCESS;
213}
214
215
216void
217usage(void)
218{
219	fprintf(stderr, "\tusage: tcsd [-f] [-e] [-c <config file> [-h]\n\n");
220	fprintf(stderr, "\t-f|--foreground\trun in the foreground. Logging goes to stderr "
221			"instead of syslog.\n");
222	fprintf(stderr, "\t-e| attempts to connect to software TPMs over TCP\n");
223	fprintf(stderr, "\t-c|--config\tpath to configuration file\n");
224	fprintf(stderr, "\t-h|--help\tdisplay this help message\n");
225	fprintf(stderr, "\n");
226}
227
228static TSS_RESULT
229reload_config(void)
230{
231	TSS_RESULT result;
232	hup = 0;
233
234	// FIXME: reload the config - work in progress
235	result = TSS_SUCCESS;
236
237	return result;
238}
239
240int setup_ipv4_socket(struct srv_sock_info ssi[])
241{
242	struct sockaddr_in serv_addr;
243	int sd, opt;
244
245	ssi->sd = -1;
246
247	// Initialization of IPv4 socket.
248	sd = socket(AF_INET, SOCK_STREAM, 0);
249	if (sd < 0) {
250		LogWarn("Failed IPv4 socket: %s", strerror(errno));
251		goto err;
252	}
253
254	memset(&serv_addr, 0, sizeof (serv_addr));
255	serv_addr.sin_family = AF_INET;
256	serv_addr.sin_port = htons(tcsd_options.port);
257
258	/* If no remote_ops are defined, restrict connections to localhost
259	 * only at the socket. */
260	if (tcsd_options.remote_ops[0] == 0)
261		serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
262	else
263		serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
264
265	opt = 1;
266	setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
267	if (bind(sd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
268		LogWarn("Failed IPv4 bind: %s", strerror(errno));
269		goto err;
270	}
271
272	if (listen(sd, TCSD_MAX_SOCKETS_QUEUED) < 0) {
273		LogWarn("Failed IPv4 listen: %s", strerror(errno));
274		goto err;
275	}
276
277	ssi->domain = AF_INET;
278	ssi->sd = sd;
279	ssi->addr_len = sizeof(serv_addr);
280
281	return 0;
282
283 err:
284	if (sd != -1)
285		close(sd);
286
287	return -1;
288}
289
290int setup_ipv6_socket(struct srv_sock_info *ssi)
291{
292	struct sockaddr_in6 serv6_addr;
293	int sd6, opt;
294
295	ssi->sd = -1;
296
297	sd6 = socket(AF_INET6, SOCK_STREAM, 0);
298	if (sd6 < 0) {
299		LogWarn("Failed IPv6 socket: %s", strerror(errno));
300		goto err;
301	}
302
303	memset(&serv6_addr, 0, sizeof (serv6_addr));
304	serv6_addr.sin6_family = AF_INET6;
305	serv6_addr.sin6_port = htons(tcsd_options.port);
306
307	/* If no remote_ops are defined, restrict connections to localhost
308	 * only at the socket. */
309	if (tcsd_options.remote_ops[0] == 0)
310		serv6_addr.sin6_addr = in6addr_loopback;
311	else
312		serv6_addr.sin6_addr = in6addr_any;
313
314#ifdef __linux__
315	/* Linux, by default, allows one socket to be used by both IP stacks
316	 * This option disables that behavior, so you must have one socket for
317	 * each IP protocol. */
318	opt = 1;
319	if(setsockopt(sd6, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) {
320		LogWarn("Could not set IPv6 socket option properly.\n");
321		goto err;
322	}
323#endif
324
325	opt = 1;
326	setsockopt(sd6, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
327	if (bind(sd6, (struct sockaddr *) &serv6_addr, sizeof (serv6_addr)) < 0) {
328		LogWarn("Failed IPv6 bind: %s", strerror(errno));
329		goto err;
330	}
331
332	if (listen(sd6, TCSD_MAX_SOCKETS_QUEUED) < 0) {
333		LogWarn("Failed IPv6 listen: %s", strerror(errno));
334		goto err;
335	}
336
337	ssi->domain = AF_INET6;
338	ssi->sd = sd6;
339	ssi->addr_len = sizeof(serv6_addr);
340
341	return 0;
342
343 err:
344	if (sd6 != -1)
345		close(sd6);
346
347	return -1;
348}
349
350int setup_server_sockets(struct srv_sock_info ssi[])
351{
352	int i=0;
353
354	ssi[0].sd = ssi[1].sd = -1;
355	// Only enqueue sockets successfully bound or that weren't disabled.
356	if (tcsd_options.disable_ipv4) {
357		LogWarn("IPv4 support disabled by configuration option");
358	} else {
359		if (setup_ipv4_socket(&ssi[i]) == 0)
360			i++;
361	}
362
363	if (tcsd_options.disable_ipv6) {
364		LogWarn("IPv6 support disabled by configuration option");
365	} else {
366		setup_ipv6_socket(&ssi[i]);
367	}
368
369	// It's only a failure if both sockets are unavailable.
370	if ((ssi[0].sd == -1) && (ssi[1].sd == -1)) {
371		return -1;
372	}
373
374	return 0;
375}
376
377char *fetch_hostname(struct sockaddr_storage *client_addr, socklen_t socklen)
378{
379	char buf[NI_MAXHOST];
380
381	if (getnameinfo((struct sockaddr *)client_addr, socklen, buf,
382						sizeof(buf), NULL, 0, 0) != 0) {
383		LogWarn("Could not retrieve client address info");
384		return NULL;
385	} else {
386		return strdup(buf);
387	}
388}
389
390void prepare_for_select(struct srv_sock_info *socks_info, int *num_fds,
391						fd_set *rdfd_set, int *nfds)
392{
393	int i;
394
395	FD_ZERO(rdfd_set);
396	*num_fds = 0;
397	*nfds = 0;
398	// Filter out socket descriptors in the queue that
399	// has the -1 value.
400	for (i=0; i < MAX_IP_PROTO; i++) {
401		if (socks_info[i].sd == -1)
402			break;
403
404		FD_SET(socks_info[i].sd, rdfd_set);
405		(*num_fds)++;
406		if (*nfds < socks_info[i].sd) // grab highest sd for select call
407			*nfds = socks_info[i].sd;
408	}
409}
410
411int
412main(int argc, char **argv)
413{
414	TSS_RESULT result;
415	int newsd, c, rv, option_index = 0;
416	int i;
417	socklen_t client_len;
418	char *hostname = NULL;
419	fd_set rdfd_set;
420	int num_fds = 0;
421	int nfds = 0;
422	int stor_errno;
423	sigset_t sigmask, termmask, oldsigmask;
424	struct sockaddr_storage client_addr;
425	struct srv_sock_info socks_info[MAX_IP_PROTO];
426	struct passwd *pwd;
427	struct option long_options[] = {
428		{"help", 0, NULL, 'h'},
429		{"foreground", 0, NULL, 'f'},
430		{"config", 1, NULL, 'c'},
431		{0, 0, 0, 0}
432	};
433
434	unsetenv("TCSD_USE_TCP_DEVICE");
435	while ((c = getopt_long(argc, argv, "fhec:", long_options, &option_index)) != -1) {
436		switch (c) {
437			case 'f':
438				setenv("TCSD_FOREGROUND", "1", 1);
439				break;
440			case 'c':
441				tcsd_config_file = optarg;
442				break;
443			case 'e':
444				setenv("TCSD_USE_TCP_DEVICE", "1", 1);
445				break;
446			case 'h':
447				/* fall through */
448			default:
449				usage();
450				return -1;
451				break;
452		}
453	}
454
455	if (!tcsd_config_file)
456		tcsd_config_file = TCSD_DEFAULT_CONFIG_FILE;
457
458	if ((result = tcsd_startup()))
459		return (int)result;
460
461#ifdef NOUSERCHECK
462    LogWarn("will not switch user or check for file permissions. "
463            "(Compiled with --disable-usercheck)");
464#else
465#ifndef SOLARIS
466	pwd = getpwnam(TSS_USER_NAME);
467	if (pwd == NULL) {
468		if (errno == 0) {
469			LogError("User \"%s\" not found, please add this user"
470					" manually.", TSS_USER_NAME);
471		} else {
472			LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno));
473		}
474		return TCSERR(TSS_E_INTERNAL_ERROR);
475	}
476	setuid(pwd->pw_uid);
477#endif
478#endif
479
480	if (setup_server_sockets(socks_info) == -1) {
481		LogError("Could not create sockets to listen to connections. Aborting...");
482		return -1;
483	}
484
485	if (getenv("TCSD_FOREGROUND") == NULL) {
486		if (daemon(0, 0) == -1) {
487			perror("daemon");
488			tcsd_shutdown(socks_info);
489			return -1;
490		}
491	}
492
493	LogInfo("%s: TCSD up and running.", PACKAGE_STRING);
494
495	sigemptyset(&sigmask);
496	sigaddset(&sigmask, SIGTERM);
497	sigaddset(&sigmask, SIGHUP);
498
499	sigemptyset(&termmask);
500	sigaddset(&termmask, SIGTERM);
501
502	do {
503		prepare_for_select(socks_info, &num_fds, &rdfd_set, &nfds);
504		// Sanity check
505		if (num_fds == 0) {
506			LogError("No server sockets available to listen connections. Aborting...");
507			return -1;
508		}
509
510		// Block TERM and HUP signals to prevent race condition
511		if (sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask) == -1) {
512			LogError("Error setting interrupt mask before accept");
513		}
514
515		// TERM and HUP are blocked here, so its safe to test flags.
516		if (hup) {
517			// Config reading can be slow, so unmask SIGTERM.
518			if (sigprocmask(SIG_UNBLOCK, &termmask, NULL) == -1) {
519				LogError("Error unblocking SIGTERM before config reload");
520			}
521			if (reload_config() != TSS_SUCCESS)
522				LogError("Failed reloading config");
523			if (sigprocmask(SIG_BLOCK, &termmask, NULL) == -1) {
524				LogError("Error blocking SIGTERM after config reload");
525			}
526		}
527		if (term)
528			break;
529
530		// Select IPv4 and IPv6 socket descriptors with appropriate sigmask.
531		LogDebug("Waiting for connections");
532		rv = pselect(nfds+1, &rdfd_set, NULL, NULL, NULL, &oldsigmask);
533		stor_errno = errno; // original mask must be set ASAP, so store errno.
534		if (sigprocmask(SIG_SETMASK, &oldsigmask, NULL) == -1) {
535			LogError("Error reseting signal mask to the original configuration.");
536		}
537		if (rv == -1) {
538			if (stor_errno != EINTR) {
539				LogError("Error monitoring server socket descriptors.");
540				return -1;
541			}
542			continue;
543		}
544
545		for (i=0; i < num_fds; i++) { // accept connections from all IP versions (with valid sd)
546			if (!FD_ISSET(socks_info[i].sd, &rdfd_set)) {
547				continue;
548			}
549			client_len = socks_info[i].addr_len;
550			newsd = accept(socks_info[i].sd, (struct sockaddr *) &client_addr, &client_len);
551			if (newsd < 0) {
552				if (errno != EINTR)
553					LogError("Failed accept: %s", strerror(errno));
554				continue;
555			}
556			LogDebug("accepted socket %i", newsd);
557
558			hostname = fetch_hostname(&client_addr, client_len);
559			if (hostname == NULL)
560				hostname=INVALID_ADDR_STR;
561
562			tcsd_thread_create(newsd, hostname);
563			hostname = NULL;
564		} // for (i=0; i < MAX_IP_PROTO; i++)
565	} while (term ==0);
566
567	/* To close correctly, we must receive a SIGTERM */
568	tcsd_shutdown(socks_info);
569	return 0;
570}
571