--- src/tcsd/svrside.c 2010-06-09 13:19:00.000000000 -0700
+++ src/tcsd/svrside.c 2012-04-19 11:27:31.232524632 -0700
@@ -27,6 +27,15 @@
#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
+#ifdef SOLARIS
+#include <priv.h>
+#include <fcntl.h>
+#endif
+#ifndef HAVE_DAEMON
+#include <fcntl.h>
+#include <syslog.h>
+#endif
+
#include "trousers/tss.h"
#include "trousers_types.h"
#include "tcs_tsp.h"
@@ -44,6 +53,10 @@
static volatile int hup = 0, term = 0;
extern char *optarg;
+#ifdef SOLARIS
+static int get_event_log_from_kernel(void);
+#endif
+
static void
tcsd_shutdown(void)
{
@@ -170,6 +183,10 @@
(void)req_mgr_final();
return result;
}
+#ifdef SOLARIS
+ /* Not fatal if this fails */
+ (void) get_event_log_from_kernel();
+#endif
result = owner_evict_init();
if (result != TSS_SUCCESS) {
@@ -208,13 +225,169 @@
}
+#ifdef SOLARIS
+
+extern int get_device_fd(void);
+
+#define TPM_IOCTL_GETEVTABLE 1
+struct tpm_evtable_ioblk {
+ uint32_t buflen;
+ caddr_t buf;
+};
+
+static int
+store_eventlog(char *filename, struct tpm_evtable_ioblk *evlog)
+{
+ int fd;
+ int bytes = 0;
+
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ if (fd == -1) {
+ LogError("Error opening logfile %s: %s", filename,
+ strerror(errno));
+ return (-1);
+ }
+ while (bytes < evlog->buflen) {
+ int n;
+ n = write(fd, evlog->buf, evlog->buflen - bytes);
+ if (n == -1 && errno != EAGAIN) {
+ LogError("Error writing logfile %s: %s",
+ filename, strerror(errno));
+ close(fd);
+ return (-1);
+ }
+ if (n != -1)
+ bytes += n;
+ }
+ close(fd);
+
+ return (0);
+}
+
+static int
+get_event_log_from_kernel(void)
+{
+ int fd = get_device_fd();
+ struct tpm_evtable_ioblk ioblk;
+
+ if (fd == -1)
+ return (-1);
+
+ (void) memset(&ioblk, 0, sizeof (ioblk));
+ if (ioctl(fd, TPM_IOCTL_GETEVTABLE, &ioblk)) {
+ LogDebug("Cannot get event log from kernel: %s",
+ strerror(errno));
+ return (-1);
+ }
+ if (ioblk.buflen == 0)
+ return (0);
+
+ ioblk.buf = calloc(1, ioblk.buflen);
+ if (ioblk.buf == NULL) {
+ return (-1);
+ }
+ if (ioctl(fd, TPM_IOCTL_GETEVTABLE, &ioblk)) {
+ free(ioblk.buf);
+ LogDebug("Cannot get event log from kernel: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ return (store_eventlog(tcsd_options.firmware_log_file, &ioblk));
+}
+
+/*
+ * For Solaris, make the tcsd privilege aware and drop
+ * risky privileges if they are not needed.
+ */
+static int
+drop_privs(void)
+{
+ priv_set_t *myprivs;
+ int rv;
+
+ /*
+ * Drop unneeded privs such as fork/exec.
+ *
+ * Get "basic" privs and remove the ones we don't want.
+ */
+ if ((myprivs = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ LogError("priv_str_to_set failed: %s", strerror(errno));
+ return (1);
+ } else {
+ (void) priv_delset(myprivs, PRIV_PROC_EXEC);
+ (void) priv_delset(myprivs, PRIV_PROC_FORK);
+ (void) priv_delset(myprivs, PRIV_FILE_LINK_ANY);
+ (void) priv_delset(myprivs, PRIV_PROC_INFO);
+ (void) priv_delset(myprivs, PRIV_PROC_SESSION);
+ (void) priv_delset(myprivs, PRIV_PROC_SETID);
+
+ /* for auditing */
+ (void) priv_addset(myprivs, PRIV_PROC_AUDIT);
+
+ if ((rv = setppriv(PRIV_SET, PRIV_PERMITTED, myprivs)))
+ return (rv);
+ if ((rv = setppriv(PRIV_SET, PRIV_LIMIT, myprivs)))
+ return (rv);
+ if ((rv = setppriv(PRIV_SET, PRIV_INHERITABLE, myprivs)))
+ return (rv);
+
+ (void) priv_freeset(myprivs);
+ }
+ return (0);
+}
+#endif /* SOLARIS */
+
+#ifndef HAVE_DAEMON
+static int
+daemon(int nochdir, int noclose) {
+ int rv, fd;
+
+ if (!noclose) {
+ closelog();
+ closefrom(0);
+ }
+
+ switch (fork()) {
+ case -1: /* failure: parent process */
+ return (-1);
+ case 0: /* success: child process */
+ break;
+ default: /* success: parent process */
+ exit (0);
+ }
+
+ /* Create a new SID for the child process */
+ if (setsid() == -1)
+ return (-1);
+ /* Prevent cwd from being left open and unremovable */
+ if (!nochdir)
+ (void) chdir("/");
+ (void) umask(0);
+ /* Redirect stdin, stdout, and stderr to /dev/null */
+ if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
+ (void) dup2(fd, STDIN_FILENO);
+ (void) dup2(fd, STDOUT_FILENO);
+ (void) dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close (fd);
+ }
+ return (0);
+}
+#endif /* !HAVE_DAEMON */
+
int
main(int argc, char **argv)
{
- struct sockaddr_in serv_addr, client_addr;
+ typedef union {
+ struct sockaddr_in in;
+ struct sockaddr_un un;
+ } sockaddr_un_in_t;
+ sockaddr_un_in_t serv_addr, client_addr;
+ int rv;
TSS_RESULT result;
int sd, newsd, c, option_index = 0;
- unsigned client_len;
+ unsigned client_len, serv_len;
char *hostname = NULL;
struct passwd *pwd;
struct hostent *client_hostent = NULL;
@@ -245,26 +418,50 @@
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;
- }
+ if (tcsd_options.port == 0) { /* UNIX Domain socket */
+ /* Use UNIX Domain socket instead of TCP/IP socket */
+ sd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sd < 0) {
+ LogError("Failed socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&serv_addr, 0, sizeof (serv_addr));
+ serv_addr.un.sun_family = AF_UNIX;
+ strncpy(serv_addr.un.sun_path, TCSD_DEFAULT_SOCKET,
+ sizeof (serv_addr.un.sun_path));
+ (void) unlink(TCSD_DEFAULT_SOCKET);
+
+ } else { /* TCP socket */
+ 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) {
+ memset(&serv_addr, 0, sizeof (serv_addr));
+ serv_addr.in.sin_family = AF_INET;
+ serv_addr.in.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.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else
+ serv_addr.in.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ c = 1;
+ setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &c, sizeof(c));
+ }
+
+ if (tcsd_options.port == 0) { /* UNIX Domain socket */
+ serv_len = (unsigned)sizeof(serv_addr.un);
+ client_len = (unsigned)sizeof(client_addr.un);
+ } else { /* TCP socket */
+ serv_len = (unsigned)sizeof(serv_addr.in);
+ client_len = (unsigned)sizeof(client_addr.in);
+ }
+ if (bind(sd, (struct sockaddr *) &serv_addr, serv_len) < 0) {
LogError("Failed bind: %s", strerror(errno));
return -1;
}
@@ -285,7 +482,6 @@
LogError("Failed listen: %s", strerror(errno));
return -1;
}
- client_len = (unsigned)sizeof(client_addr);
if (getenv("TCSD_FOREGROUND") == NULL) {
if (daemon(0, 0) == -1) {
@@ -295,6 +491,12 @@
}
}
+#ifdef SOLARIS
+ /* For Solaris, drop privileges for security. */
+ if ((rv = drop_privs()))
+ return (rv);
+#endif /* SOLARIS */
+
LogInfo("%s: TCSD up and running.", PACKAGE_STRING);
do {
newsd = accept(sd, (struct sockaddr *) &client_addr, &client_len);
@@ -314,20 +516,22 @@
}
LogDebug("accepted socket %i", newsd);
- if ((client_hostent = gethostbyaddr((char *) &client_addr.sin_addr,
- sizeof(client_addr.sin_addr),
+ if (tcsd_options.port != 0) { /* TCP socket */
+ if ((client_hostent = gethostbyaddr((char *) &client_addr.in.sin_addr,
+ sizeof(client_addr.in.sin_addr),
AF_INET)) == NULL) {
- char buf[16];
- uint32_t addr = htonl(client_addr.sin_addr.s_addr);
+ char buf[16];
+ uint32_t addr = htonl(client_addr.in.sin_addr.s_addr);
- snprintf(buf, 16, "%d.%d.%d.%d", (addr & 0xff000000) >> 24,
- (addr & 0x00ff0000) >> 16, (addr & 0x0000ff00) >> 8,
- addr & 0x000000ff);
+ 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);
+ 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);