--- trousers-0.3.11.2/src/tspi/rpc/hosttable.c.orig +++ trousers-0.3.11.2/src/tspi/rpc/hosttable.c @@ -21,7 +21,7 @@ static struct host_table *ht = NULL; -TSS_RESULT +static TSS_RESULT host_table_init() { ht = calloc(1, sizeof(struct host_table)); @@ -35,9 +35,8 @@ return TSS_SUCCESS; } -#ifdef SOLARIS -#pragma init(_init) -void _init(void) +#ifdef SOLARIS && defined(__SUNPRO_C)) +static void my_init(void) #else void __attribute__ ((constructor)) my_init(void) #endif @@ -46,11 +45,14 @@ __tspi_obj_list_init(); } -void +static void host_table_final() { struct host_table_entry *hte, *next = NULL; + if (ht == NULL) /* no host table to free */ + return; + MUTEX_LOCK(ht->lock); for (hte = ht->entries; hte; hte = next) { @@ -69,9 +71,8 @@ ht = NULL; } -#ifdef SOLARIS -#pragma fini(_fini) -void _fini(void) +#ifdef SOLARIS && defined(__SUNPRO_C)) +static void my_fini(void) #else void __attribute__ ((destructor)) my_fini(void) #endif @@ -79,6 +80,11 @@ host_table_final(); } +#ifdef SOLARIS +#pragma init(my_init) +#pragma fini(my_fini) +#endif + TSS_RESULT __tspi_add_table_entry(TSS_HCONTEXT tspContext, BYTE *host, int type, struct host_table_entry **ret) { --- trousers-0.3.11.2/src/tcsd/Makefile.am.orig +++ trousers-0.3.11.2/src/tcsd/Makefile.am @@ -2,7 +2,7 @@ tcsd_CFLAGS=-DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include -fPIE -DPIE tcsd_LDADD=${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@ -tcsd_LDFLAGS=-pie -Wl,-z,relro -Wl,-z,now +tcsd_LDFLAGS=-Wl,-z,now tcsd_SOURCES=svrside.c tcsd_conf.c tcsd_threads.c platform.c --- trousers-0.3.11.2/src/tcsd/Makefile.in.orig +++ trousers-0.3.11.2/src/tcsd/Makefile.in @@ -64,7 +64,7 @@ mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(sbindir)" +am__installdirs = "$(DESTDIR)$(libdir)" PROGRAMS = $(sbin_PROGRAMS) am_tcsd_OBJECTS = tcsd-svrside.$(OBJEXT) tcsd-tcsd_conf.$(OBJEXT) \ tcsd-tcsd_threads.$(OBJEXT) tcsd-platform.$(OBJEXT) @@ -212,7 +212,7 @@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ -sbindir = @sbindir@ +sbindir = @libdir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ @@ -227,8 +227,9 @@ tcsd_CFLAGS = -DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" \ -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include \ -fPIE -DPIE $(am__append_1) $(am__append_2) -tcsd_LDADD = ${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@ -tcsd_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now +tcsd_LDADD = ${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a \ + -lpthread -lbsm -lscf -lresolv @CRYPTOLIB@ +tcsd_LDFLAGS = -Wl,-z,now tcsd_SOURCES = svrside.c tcsd_conf.c tcsd_threads.c platform.c all: all-am --- trousers-0.3.11.2/src/include/tcsd.h.orig +++ trousers-0.3.11.2/src/include/tcsd.h @@ -48,15 +48,25 @@ of this TCS System */ }; +#ifdef SOLARIS +#define TCSD_DEFAULT_CONFIG_FILE "/etc/security/tcsd.conf" +#else #define TCSD_DEFAULT_CONFIG_FILE ETC_PREFIX "/tcsd.conf" +#endif extern char *tcsd_config_file; #define TSS_USER_NAME "tss" #define TSS_GROUP_NAME "tss" #define TCSD_DEFAULT_MAX_THREADS 10 +#ifdef SOLARIS +#define TCSD_DEFAULT_SYSTEM_PS_DIR "/var/tpm/system" +#define TCSD_DEFAULT_SYSTEM_PS_FILE "/var/tpm/system/system.data" +#define TCSD_DEFAULT_SOCKET "/var/tpm/tcsd-socket" +#else #define TCSD_DEFAULT_SYSTEM_PS_FILE VAR_PREFIX "/lib/tpm/system.data" #define TCSD_DEFAULT_SYSTEM_PS_DIR VAR_PREFIX "/lib/tpm" +#endif /* SOLARIS */ #define TCSD_DEFAULT_FIRMWARE_LOG_FILE "/sys/kernel/security/tpm0/binary_bios_measurements" #define TCSD_DEFAULT_KERNEL_LOG_FILE "/sys/kernel/security/ima/binary_runtime_measurements" #define TCSD_DEFAULT_FIRMWARE_PCRS 0x00000000 --- trousers-0.3.11.2/src/include/tspps.h.orig +++ trousers-0.3.11.2/src/include/tspps.h @@ -13,13 +13,17 @@ #define PASSWD_BUFSIZE 4096 +#ifdef SOLARIS +#define TSS_USER_PS_DIR "/var/user/" +#else #define TSS_USER_PS_DIR ".trousers" +#endif #define TSS_USER_PS_FILE "user.data" TSS_RESULT get_file(int *); int put_file(int); -inline TSS_RESULT read_data(int, void *, UINT32); -inline TSS_RESULT write_data(int, void *, UINT32); +TSS_RESULT read_data(int, void *, UINT32); +TSS_RESULT write_data(int, void *, UINT32); UINT32 psfile_get_num_keys(int); TSS_RESULT psfile_get_parent_uuid_by_uuid(int, TSS_UUID *, TSS_UUID *); TSS_RESULT psfile_remove_key_by_uuid(int, TSS_UUID *); --- trousers-0.3.11.2/src/tcsd/svrside.c.orig +++ trousers-0.3.11.2/src/tcsd/svrside.c @@ -27,6 +27,15 @@ #include #include #include +#ifdef SOLARIS +#include +#include +#endif +#ifndef HAVE_DAEMON +#include +#include +#endif + #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" @@ -46,6 +55,10 @@ int sd; char *tcsd_config_file = NULL; +#ifdef SOLARIS +static int get_event_log_from_kernel(void); +#endif + static void tcsd_shutdown(void) { @@ -173,6 +186,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) { @@ -211,16 +228,171 @@ return result; } +#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; + unsigned 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 newsd, c, option_index = 0; - unsigned client_len; + unsigned client_len, serv_len; char *hostname = NULL; - struct passwd *pwd; + struct passwd *pwd = NULL; struct hostent *client_hostent = NULL; struct option long_options[] = { {"help", 0, NULL, 'h'}, @@ -256,26 +428,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; } @@ -296,7 +492,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) { @@ -306,6 +501,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); @@ -325,20 +526,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); --- trousers-0.3.11.2/src/tspi/rpc/tcstp/rpc.c.orig +++ trousers-0.3.11.2/src/tspi/rpc/tcstp/rpc.c @@ -342,41 +342,68 @@ BYTE *buffer; TSS_RESULT result; - struct sockaddr_in addr; - struct hostent *hEnt = NULL; + if (get_port() == 0) { /* use UNIX Domain socket */ + struct sockaddr_un addr; - sd = socket(PF_INET, SOCK_STREAM, 0); - if (sd == -1) { - LogError("socket: %s", strerror(errno)); - result = TSPERR(TSS_E_COMM_FAILURE); - goto err_exit; - } - __tspi_memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(get_port()); - - LogDebug("Sending TSP packet to host %s.", hte->hostname); - - /* try to resolve by hostname first */ - hEnt = gethostbyname((char *)hte->hostname); - if (hEnt == NULL) { - /* if by hostname fails, try by dot notation */ - if (inet_aton((char *)hte->hostname, &addr.sin_addr) == 0) { - LogError("hostname %s does not resolve to a valid address.", hte->hostname); - result = TSPERR(TSS_E_CONNECTION_FAILED); + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd == -1) { + LogError("socket(PF_UNIX): %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } - } else { - memcpy(&addr.sin_addr, hEnt->h_addr_list[0], 4); - } - LogDebug("Connecting to %s", inet_ntoa(addr.sin_addr)); + __tspi_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, TCSD_DEFAULT_SOCKET, + sizeof(addr.sun_path)); + + LogDebug("Connecting to UNIX Domain socket %s", + TCSD_DEFAULT_SOCKET); + + if (connect(sd, (struct sockaddr *) &addr, sizeof (addr))) { + LogError("connect: %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); + goto err_exit; + } + + } else { /* use TCP socket */ + struct sockaddr_in addr; + struct hostent *hEnt = NULL; + + sd = socket(PF_INET, SOCK_STREAM, 0); + if (sd == -1) { + LogError("socket: %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); + goto err_exit; + } + + __tspi_memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(get_port()); + + LogDebug("Sending TSP packet to host %s.", hte->hostname); + + /* try to resolve by hostname first */ + hEnt = gethostbyname((char *)hte->hostname); + if (hEnt == NULL) { + /* if by hostname fails, try by dot notation */ + if (inet_aton((char *)hte->hostname, &addr.sin_addr) == 0) { + LogError("hostname %s does not resolve to a valid address.", hte->hostname); + result = TSPERR(TSS_E_CONNECTION_FAILED); + goto err_exit; + } + } else { + memcpy(&addr.sin_addr, hEnt->h_addr_list[0], 4); + } + + LogDebug("Connecting to %s", inet_ntoa(addr.sin_addr)); - if (connect(sd, (struct sockaddr *) &addr, sizeof (addr))) { - LogError("connect: %s", strerror(errno)); - result = TSPERR(TSS_E_COMM_FAILURE); - goto err_exit; + if (connect(sd, (struct sockaddr *) &addr, sizeof (addr))) { + LogError("connect: %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); + goto err_exit; + } } if (send_to_socket(sd, hte->comm.buf, hte->comm.hdr.packet_size) < 0) {