summaryrefslogtreecommitdiff
path: root/src/tcsd/svrside.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcsd/svrside.c')
-rw-r--r--src/tcsd/svrside.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/tcsd/svrside.c b/src/tcsd/svrside.c
new file mode 100644
index 0000000..08ca1c8
--- /dev/null
+++ b/src/tcsd/svrside.c
@@ -0,0 +1,355 @@
+
+/*
+ * Licensed Materials - Property of IBM
+ *
+ * trousers - An open source TCG Software Stack
+ *
+ * (C) Copyright International Business Machines Corp. 2004
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <pwd.h>
+#if (defined (__OpenBSD__) || defined (__FreeBSD__))
+#include <netinet/in.h>
+#endif
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include "trousers/tss.h"
+#include "trousers_types.h"
+#include "tcs_tsp.h"
+#include "tcs_utils.h"
+#include "tcs_int_literals.h"
+#include "capabilities.h"
+#include "tcslog.h"
+#include "tcsd_wrap.h"
+#include "tcsps.h"
+#include "tcsd.h"
+#include "req_mgr.h"
+
+struct tcsd_config tcsd_options;
+struct tpm_properties tpm_metrics;
+static volatile int hup = 0, term = 0;
+extern char *optarg;
+int sd;
+char *tcsd_config_file = NULL;
+
+static void
+tcsd_shutdown(void)
+{
+ /* order is important here:
+ * allow all threads to complete their current request */
+ tcsd_threads_final();
+ PS_close_disk_cache();
+ auth_mgr_final();
+ (void)req_mgr_final();
+ conf_file_final(&tcsd_options);
+ EVENT_LOG_final();
+}
+
+static void
+tcsd_signal_term(int signal)
+{
+ term = 1;
+ close(sd);
+}
+
+void
+tcsd_signal_hup(int signal)
+{
+ hup = 1;
+}
+
+static TSS_RESULT
+signals_init(void)
+{
+ int rc;
+ sigset_t sigmask;
+ struct sigaction sa;
+
+ sigemptyset(&sigmask);
+ if ((rc = sigaddset(&sigmask, SIGTERM))) {
+ LogError("sigaddset: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ if ((rc = sigaddset(&sigmask, SIGHUP))) {
+ LogError("sigaddset: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ if ((rc = THREAD_SET_SIGNAL_MASK(SIG_UNBLOCK, &sigmask, NULL))) {
+ LogError("Setting thread signal mask: %s", strerror(rc));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = tcsd_signal_term;
+ if ((rc = sigaction(SIGTERM, &sa, NULL))) {
+ LogError("signal SIGTERM not registered: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ sa.sa_handler = tcsd_signal_hup;
+ if ((rc = sigaction(SIGHUP, &sa, NULL))) {
+ LogError("signal SIGHUP not registered: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ return TSS_SUCCESS;
+}
+
+static TSS_RESULT
+tcsd_startup(void)
+{
+ TSS_RESULT result;
+
+#ifdef TSS_DEBUG
+ /* Set stdout to be unbuffered to match stderr and interleave output correctly */
+ setvbuf(stdout, (char *)NULL, _IONBF, 0);
+#endif
+
+ if ((result = signals_init()))
+ return result;
+
+ if ((result = conf_file_init(&tcsd_options)))
+ return result;
+
+ if ((result = tcsd_threads_init())) {
+ conf_file_final(&tcsd_options);
+ return result;
+ }
+
+ if ((result = req_mgr_init())) {
+ conf_file_final(&tcsd_options);
+ return result;
+ }
+
+ if ((result = ps_dirs_init())) {
+ conf_file_final(&tcsd_options);
+ (void)req_mgr_final();
+ return result;
+ }
+
+ result = PS_init_disk_cache();
+ if (result != TSS_SUCCESS) {
+ conf_file_final(&tcsd_options);
+ (void)req_mgr_final();
+ return result;
+ }
+
+ if ((result = get_tpm_metrics(&tpm_metrics))) {
+ conf_file_final(&tcsd_options);
+ PS_close_disk_cache();
+ (void)req_mgr_final();
+ return result;
+ }
+
+ /* must happen after get_tpm_metrics() */
+ if ((result = auth_mgr_init())) {
+ conf_file_final(&tcsd_options);
+ PS_close_disk_cache();
+ (void)req_mgr_final();
+ return result;
+ }
+
+ result = EVENT_LOG_init();
+ if (result != TSS_SUCCESS) {
+ auth_mgr_final();
+ conf_file_final(&tcsd_options);
+ PS_close_disk_cache();
+ (void)req_mgr_final();
+ return result;
+ }
+
+ result = owner_evict_init();
+ if (result != TSS_SUCCESS) {
+ auth_mgr_final();
+ conf_file_final(&tcsd_options);
+ PS_close_disk_cache();
+ (void)req_mgr_final();
+ return result;
+ }
+
+ return TSS_SUCCESS;
+}
+
+
+void
+usage(void)
+{
+ fprintf(stderr, "\tusage: tcsd [-f] [-e] [-c <config file> [-h]\n\n");
+ fprintf(stderr, "\t-f|--foreground\trun in the foreground. Logging goes to stderr "
+ "instead of syslog.\n");
+ fprintf(stderr, "\t-e| attempts to connect to software TPMs over TCP\n");
+ fprintf(stderr, "\t-c|--config\tpath to configuration file\n");
+ fprintf(stderr, "\t-h|--help\tdisplay this help message\n");
+ fprintf(stderr, "\n");
+}
+
+static TSS_RESULT
+reload_config(void)
+{
+ TSS_RESULT result;
+ hup = 0;
+
+ // FIXME: reload the config - work in progress
+ result = TSS_SUCCESS;
+
+ return result;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ struct sockaddr_in serv_addr, client_addr;
+ TSS_RESULT result;
+ int newsd, c, option_index = 0;
+ unsigned client_len;
+ char *hostname = NULL;
+ struct passwd *pwd;
+ struct hostent *client_hostent = NULL;
+ struct option long_options[] = {
+ {"help", 0, NULL, 'h'},
+ {"foreground", 0, NULL, 'f'},
+ {"config", 1, NULL, 'c'},
+ {0, 0, 0, 0}
+ };
+
+ unsetenv("TCSD_USE_TCP_DEVICE");
+ while ((c = getopt_long(argc, argv, "fhec:", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'f':
+ setenv("TCSD_FOREGROUND", "1", 1);
+ break;
+ case 'c':
+ tcsd_config_file = optarg;
+ break;
+ case 'e':
+ setenv("TCSD_USE_TCP_DEVICE", "1", 1);
+ break;
+ case 'h':
+ /* fall through */
+ default:
+ usage();
+ return -1;
+ break;
+ }
+ }
+
+ if (!tcsd_config_file)
+ tcsd_config_file = TCSD_DEFAULT_CONFIG_FILE;
+
+ if ((result = tcsd_startup()))
+ return (int)result;
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd < 0) {
+ LogError("Failed socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&serv_addr, 0, sizeof (serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(tcsd_options.port);
+
+ /* If no remote_ops are defined, restrict connections to localhost
+ * only at the socket. */
+ if (tcsd_options.remote_ops[0] == 0)
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ c = 1;
+ setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &c, sizeof(c));
+ if (bind(sd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
+ LogError("Failed bind: %s", strerror(errno));
+ return -1;
+ }
+#ifndef SOLARIS
+ pwd = getpwnam(TSS_USER_NAME);
+ if (pwd == NULL) {
+ if (errno == 0) {
+ LogError("User \"%s\" not found, please add this user"
+ " manually.", TSS_USER_NAME);
+ } else {
+ LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno));
+ }
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ setuid(pwd->pw_uid);
+#endif
+ if (listen(sd, TCSD_MAX_SOCKETS_QUEUED) < 0) {
+ LogError("Failed listen: %s", strerror(errno));
+ return -1;
+ }
+ client_len = (unsigned)sizeof(client_addr);
+
+ if (getenv("TCSD_FOREGROUND") == NULL) {
+ if (daemon(0, 0) == -1) {
+ perror("daemon");
+ tcsd_shutdown();
+ return -1;
+ }
+ }
+
+ LogInfo("%s: TCSD up and running.", PACKAGE_STRING);
+ do {
+ newsd = accept(sd, (struct sockaddr *) &client_addr, &client_len);
+ if (newsd < 0) {
+ if (errno == EINTR) {
+ if (term)
+ break;
+ else if (hup) {
+ if (reload_config() != TSS_SUCCESS)
+ LogError("Failed reloading config");
+ }
+ continue;
+ } else {
+ LogError("Failed accept: %s", strerror(errno));
+ continue;
+ }
+ }
+ LogDebug("accepted socket %i", newsd);
+
+ if ((client_hostent = gethostbyaddr((char *) &client_addr.sin_addr,
+ sizeof(client_addr.sin_addr),
+ AF_INET)) == NULL) {
+ char buf[16];
+ uint32_t addr = htonl(client_addr.sin_addr.s_addr);
+
+ snprintf(buf, 16, "%d.%d.%d.%d", (addr & 0xff000000) >> 24,
+ (addr & 0x00ff0000) >> 16, (addr & 0x0000ff00) >> 8,
+ addr & 0x000000ff);
+
+ LogWarn("Host name for connecting IP %s could not be resolved", buf);
+ hostname = strdup(buf);
+ } else {
+ hostname = strdup(client_hostent->h_name);
+ }
+
+ tcsd_thread_create(newsd, hostname);
+ hostname = NULL;
+ if (hup) {
+ if (reload_config() != TSS_SUCCESS)
+ LogError("Failed reloading config");
+ }
+ } while (term ==0);
+
+ /* To close correctly, we must receive a SIGTERM */
+ tcsd_shutdown();
+ return 0;
+}