From 3627177b5377c8e6830bc50bba1035c61de54277 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Tue, 2 Jan 2018 21:29:29 -0600 Subject: [PATCH 1/4] Initial work around adding privsep --- Makefile | 2 +- bsm.c | 5 +- bsmtrace.c | 9 +- bsmtrace.h | 1 + conf.c | 2 +- includes.h | 1 + privsep.c | 369 +++++++++++++++++++++++++++++++++++++++++++++++ privsep.h | 18 +++ privsep_fdpass.c | 123 ++++++++++++++++ privsep_fdpass.h | 7 + 10 files changed, 533 insertions(+), 4 deletions(-) create mode 100644 privsep.c create mode 100644 privsep.h create mode 100644 privsep_fdpass.c create mode 100644 privsep_fdpass.h diff --git a/Makefile b/Makefile index e2dad4a..9197dee 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC ?= cc CFLAGS = -Wall -g -DAUDITPIPE_GET_DROPS TARGETS = bsmtrace -OBJ = pipe.o y.tab.o bsm.o bsmtrace.o conf.o lex.yy.o log.o trigger.o fcache.o +OBJ = pipe.o y.tab.o bsm.o bsmtrace.o conf.o lex.yy.o log.o trigger.o fcache.o privsep_fdpass.o privsep.o PREFIX = /usr/local LIBS = -lbsm diff --git a/bsm.c b/bsm.c index bac3cae..cd6801c 100644 --- a/bsm.c +++ b/bsm.c @@ -46,6 +46,9 @@ bsm_match_event(struct bsm_state *bm, struct bsm_record_data *bd) */ aue = getauevnum(bd->br_event); if (aue == NULL) { + /* + * NB: this should not be fatal. + */ bsmtrace_error(0, "invalid event type: %d", bd->br_event); return (0); @@ -553,7 +556,7 @@ bsm_loop(char *atrail) if (strcmp(opts.aflag, "-") == 0) fp = stdin; else - fp = fopen(opts.aflag, "r"); + fp = priv_auditpipe_open(); if (fp == NULL) bsmtrace_error(1, "%s: %s", opts.aflag, strerror(errno)); if (strcmp(opts.aflag, DEFAULT_AUDIT_TRAIL) == 0) diff --git a/bsmtrace.c b/bsmtrace.c index 55003c5..a528c7c 100644 --- a/bsmtrace.c +++ b/bsmtrace.c @@ -153,7 +153,7 @@ main(int argc, char *argv[]) (void) signal(SIGCHLD, SIG_IGN); /* Ignore dying children */ (void) signal(SIGINT, bsmtrace_handle_sigint); set_default_settings(&opts); - while ((ch = getopt(argc, argv, "Fa:Bbdf:hil:p:v")) != -1) { + while ((ch = getopt(argc, argv, "Fa:Bbdf:hil:p:u:v")) != -1) { switch (ch) { case 'B': opts.Bflag = 1; @@ -182,14 +182,21 @@ main(int argc, char *argv[]) case 'v': (void) fprintf(stderr, "%s\n", BSMTRACE_VERSION); exit(0); + case 'u': + opts.uflag = optarg; + break; case 'h': default: usage(argv[0]); /* NOTREACHED */ } } + if (opts.uflag == NULL) { + bsmtrace_error(1, "failed to specify privsep user\n"); + } log_init_dir(); conf_load(opts.fflag); + priv_init(); if (!opts.Fflag) { ret = fork(); if (ret == -1) diff --git a/bsmtrace.h b/bsmtrace.h index 84e8c66..b54a135 100644 --- a/bsmtrace.h +++ b/bsmtrace.h @@ -39,6 +39,7 @@ struct g_conf { char *pflag; char *lflag; int logfd; + char *uflag; }; struct g_conf opts; diff --git a/conf.c b/conf.c index 08bf7e2..782ae12 100644 --- a/conf.c +++ b/conf.c @@ -90,7 +90,7 @@ conf_load(char *path) { FILE *f; - f = fopen(path, "r"); + f = fopen(opts.fflag, "r"); if (f == NULL) bsmtrace_error(1, "%s: %s", path, strerror(errno)); conffile = path; diff --git a/includes.h b/includes.h index dfa3960..14a187c 100644 --- a/includes.h +++ b/includes.h @@ -76,3 +76,4 @@ #include "log.h" #include "pipe.h" #include "trigger.h" +#include "privsep.h" diff --git a/privsep.c b/privsep.c new file mode 100644 index 0000000..4f76137 --- /dev/null +++ b/privsep.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2016 Christian S.J. Peron + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2003 Can Erkin Acar + * Copyright (c) 2003 Anil Madhavapeddy + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "includes.h" +#include "privsep.h" +#include "privsep_fdpass.h" + +#include + +volatile pid_t child_pid = -1; +int priv_fd = -1; +int priv_sep_on = 0; +int __real_open(const char *path, int flags, ...); + +volatile sig_atomic_t gotsig_chld = 0; + +/* Proto-types */ +static void sig_pass_to_chld(int); +static void sig_chld(int); + +static void +sig_chld(int sig) +{ + + gotsig_chld = 1; +} + +/* If priv parent gets a TERM or HUP, pass it through to child instead */ +static void +sig_pass_to_chld(int sig) +{ + int oerrno; + + oerrno = errno; + if (child_pid != -1) + (void) kill(child_pid, sig); + errno = oerrno; +} + +static void +priv_setuid(void) +{ + struct passwd *pwd; + + /* NB: getuid check is not sufficient for but leave it for now */ + if (getuid() != 0) + return; + pwd = getpwnam(opts.uflag); + if (pwd == NULL) { + bsmtrace_error(1, "failed to get privsep uid\n"); + } + if (initgroups(opts.uflag, pwd->pw_gid) == -1) { + bsmtrace_error(1, "initgroups failed: %s\n", + strerror(errno)); + } + if (setgid(pwd->pw_gid) == -1) { + bsmtrace_error(1, "setgid failed\n"); + } + if (setuid(pwd->pw_uid) == -1) { + bsmtrace_error(1, "setuid failed\n"); + } +} + +int +priv_init(void) +{ + int i, socks[2], cmd; + + for (i = 1; i < NSIG; i++) + signal(i, SIG_DFL); + /* Create sockets */ + if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) { + (void) fprintf(stderr, "socketpair: %s\n", strerror(errno)); + exit(1); + } + child_pid = fork(); + if (child_pid == -1) { + (void) fprintf(stderr, "fork: %s\n", strerror(errno)); + exit(1); + } + if (child_pid == 0) { + (void) close(socks[0]); +#ifdef __FreeBSD__ + priv_setuid(); + (void) fprintf(stdout, "Entering capability mode sandbox\n"); + if (cap_enter() == -1) { + (void) fprintf(stderr, "cap_enter failed: %s\n", + strerror(errno)); + exit(1); + } +#endif /* __FreeBSD__ */ +#ifdef linux + priv_setuid(); + (void) fprintf(stdout, "Entering seccomp BPF mode sandbox\n"); + seccomp_activate(); +#endif /* linux */ +#ifdef __APPLE__ + fprintf(stderr, "poor man's sandbox\n"); + if (chdir("/var/empty") == -1) { + bsmtrace_error(1, "failed to chdir to /var/empty\n"); + } + if (chroot(".") == -1) { + bsmtrace_error(1, "failed to chroot unprivileged process\n"); + } + priv_setuid(); +#endif + priv_fd = socks[1]; + priv_sep_on = 1; + return 0; + } + /* + * Pass ALRM/TERM/HUP/INT/QUIT through to child, and accept CHLD + */ + signal(SIGALRM, sig_pass_to_chld); + signal(SIGTERM, sig_pass_to_chld); + signal(SIGHUP, sig_pass_to_chld); + signal(SIGINT, sig_pass_to_chld); + signal(SIGQUIT, sig_pass_to_chld); + signal(SIGCHLD, sig_chld); + close(socks[1]); + while (!gotsig_chld) { + if (may_read(socks[0], &cmd, sizeof(int))) + break; + switch (cmd) { + case PRIV_GET_CONF_FD: + { + int fd, ecode; + + fd = open(opts.fflag, O_RDONLY); + if (fd == -1) { + (void) fprintf(stderr, "config open: %s\n", strerror(errno)); + ecode = errno; + } + send_fd(socks[0], fd); + if (fd == -1) { + must_write(socks[0], &ecode, sizeof(ecode)); + break; + } + close(fd); + printf("config fd sent\n"); + break; + } + case PRIV_GET_AUDITPIPE_FD: + { + int fd, ecode; + + fd = open(opts.aflag, O_RDONLY); + if (fd == -1) { + (void) fprintf(stderr, "error opening audit pipe: %s\n", + strerror(errno)); + ecode = errno; + } + send_fd(socks[0], fd); + if (fd == -1) { + must_write(socks[0], &ecode, sizeof(ecode)); + break; + } + close(fd); + printf("audit pipe fd sent\n"); + break; + } + case PRIV_GET_LOGDIR_FD: + default: + (void) fprintf(stderr, "got request for unknown priv\n"); + } + } + _exit(1); +} + +/* + * Read all data or return 1 for error. + */ +int +may_read(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = read(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + return (1); + default: + pos += res; + } + } + return (0); +} + +/* + * Read data with the assertion that it all must come through, or + * else abort the process. Based on atomicio() from openssh. + */ +void +must_read(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = read(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + _exit(0); + default: + pos += res; + } + } +} + +/* + * Write data with the assertion that it all has to be written, or + * else abort the process. Based on atomicio() from openssh. + */ +void +must_write(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = write(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + _exit(0); + default: + pos += res; + } + } +} + +/* + * Functions to be used by the non-privleged process + */ + +/* + * Grab a file to the configuration file which was passed in on + * the command line. + */ +FILE * +priv_config_open(void) +{ + FILE *fp; + int cmd, s, e; + + cmd = PRIV_GET_CONF_FD; + must_write(priv_fd, &cmd, sizeof(cmd)); + s = receive_fd(priv_fd); + if (s == -1) { + must_read(priv_fd, &e, sizeof(e)); + errno = e; + return (NULL); + } + fp = fdopen(s, "r"); + if (fp == NULL) { + (void) fprintf(stderr, "fdopen failed: %s\n", + strerror(errno)); + exit(1); + } + return (fp); +} + +/* + * Grab a file descriptor for the auditpipe(4) itself + */ +FILE * +priv_auditpipe_open(void) +{ + int cmd, s, e; + FILE *fp; + + cmd = PRIV_GET_AUDITPIPE_FD; + must_write(priv_fd, &cmd, sizeof(cmd)); + s = receive_fd(priv_fd); + if (s == -1) { + must_read(priv_fd, &e, sizeof(e)); + errno = e; + return (NULL); + } + fp = fdopen(s, "r"); + if (fp == NULL) { + bsmtrace_error(0, "failed to open audit pipe: %s\n", + strerror(errno)); + exit(1); + } + return (fp); +} + +/* + * Get a file descriptor to the logging directory that was passed in + * on the command line. bsmtrace will be able to rotate log files + * and create BSM dump files by way of openat(2). This is a much + * more safe alternative than giving bsmtrace access to the global + * file system namespace. + */ +int +priv_get_logdir_fd(void) +{ + int cmd, s, e; + + cmd = PRIV_GET_LOGDIR_FD; + must_write(priv_fd, &cmd, sizeof(cmd)); + s = receive_fd(priv_fd); + if (s == -1) { + must_read(priv_fd, &e, sizeof(e)); + errno = e; + return (-1); + } + return (s); +} diff --git a/privsep.h b/privsep.h new file mode 100644 index 0000000..9dce582 --- /dev/null +++ b/privsep.h @@ -0,0 +1,18 @@ +#ifndef PRIVSEP_DOT_H_ +#define PRIVSEP_DOT_H_ + +enum { + PRIV_NOP, + PRIV_GET_CONF_FD, + PRIV_GET_AUDITPIPE_FD, + PRIV_GET_LOGDIR_FD +}; + +int may_read(int, void *, size_t); +void must_read(int, void *, size_t); +void must_write(int, void *, size_t); +int priv_init(void); +FILE *priv_config_open(void); +FILE *priv_auditpipe_open(void); + +#endif /* PRIVSEP_DOT_H_ */ diff --git a/privsep_fdpass.c b/privsep_fdpass.c new file mode 100644 index 0000000..1e8ab96 --- /dev/null +++ b/privsep_fdpass.c @@ -0,0 +1,123 @@ +/* $OpenBSD: privsep_fdpass.c,v 1.5 2008/03/24 16:11:08 deraadt Exp $ */ + +/* + * Copyright 2001 Niels Provos + * All rights reserved. + * + * Copyright (c) 2002 Matthieu Herrb + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void +send_fd(int sock, int fd) +{ + struct msghdr msg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; + struct iovec vec; + int result = 0; + ssize_t n; + + memset(&msg, 0, sizeof(msg)); + if (fd >= 0) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + } else { + result = errno; + } + vec.iov_base = &result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + if ((n = sendmsg(sock, &msg, 0)) == -1) + (void) fprintf(stderr, "sendmsg: %s\n", strerror(errno)); + if (n != sizeof(int)) + (void) fprintf(stderr, "sendmsg: %s\n", strerror(errno)); +} + +int +receive_fd(int sock) +{ + struct msghdr msg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; + struct iovec vec; + ssize_t n; + int result; + int fd; + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = &result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + if ((n = recvmsg(sock, &msg, 0)) == -1) + (void) fprintf(stderr, "recvmsg: %s\n", strerror(errno)); + if (n != sizeof(int)) + (void) fprintf(stderr, "recvmsg: %s\n", strerror(errno)); + if (result == 0) { + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL) { + (void) fprintf(stderr, "%s: no message header", __func__); + return -1; + } + if (cmsg->cmsg_type != SCM_RIGHTS) + (void) fprintf(stderr, "%s: expected type %d got %d", __func__, + SCM_RIGHTS, cmsg->cmsg_type); + fd = (*(int *)CMSG_DATA(cmsg)); + return fd; + } else { + errno = result; + return -1; + } +} diff --git a/privsep_fdpass.h b/privsep_fdpass.h new file mode 100644 index 0000000..b6928ff --- /dev/null +++ b/privsep_fdpass.h @@ -0,0 +1,7 @@ +#ifndef PRIVSEP_FDPASS_DOT_H +#define PRIVSEP_FDPASS_DOT_H + +void send_fd(int, int); +int receive_fd(int); + +#endif From c4b2893145f2210b172e242d34e147d3c43770f9 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Tue, 2 Jan 2018 21:55:34 -0600 Subject: [PATCH 2/4] Move a few things around - Unconditionally create the pid file. Even though we are running in the foreground, we might be supervised by another process like a service manager - Enter privsep mode after we daemonize, if we daemonize --- bsmtrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bsmtrace.c b/bsmtrace.c index a528c7c..0082033 100644 --- a/bsmtrace.c +++ b/bsmtrace.c @@ -194,9 +194,9 @@ main(int argc, char *argv[]) if (opts.uflag == NULL) { bsmtrace_error(1, "failed to specify privsep user\n"); } + bsmtrace_write_pidfile(opts.pflag); log_init_dir(); conf_load(opts.fflag); - priv_init(); if (!opts.Fflag) { ret = fork(); if (ret == -1) @@ -219,9 +219,9 @@ main(int argc, char *argv[]) if (setsid() < 0) bsmtrace_error(1, "setsid failed: %s", strerror(errno)); - bsmtrace_write_pidfile(opts.pflag); daemonized = 1; } + priv_init(); bsm_loop(opts.aflag); return (0); } From ebd2cf2cbb60d6c6f9c7e25693181fa1fa7b1655 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Wed, 3 Jan 2018 23:03:38 -0600 Subject: [PATCH 3/4] Implement log rotatation --- bsmtrace.h | 1 + log.c | 52 ++++++++++++++++++++++++++++++++++------------------ privsep.c | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/bsmtrace.h b/bsmtrace.h index b54a135..77a91f4 100644 --- a/bsmtrace.h +++ b/bsmtrace.h @@ -40,6 +40,7 @@ struct g_conf { char *lflag; int logfd; char *uflag; + int log_dir_fd; }; struct g_conf opts; diff --git a/log.c b/log.c index 63b01f9..aee5346 100644 --- a/log.c +++ b/log.c @@ -31,11 +31,14 @@ #include "includes.h" #undef SYSLOG_NAMES +int rotate_log; + void log_init_dir(void) { char logpath[128]; struct stat sb; + mode_t flags; if (opts.lflag == NULL) return; @@ -52,14 +55,18 @@ log_init_dir(void) if (access(opts.lflag, W_OK | R_OK | X_OK) != 0) { bsmtrace_error(1, "%s: invalid permissions\n", opts.lflag); } - (void) sprintf(logpath, "%s/bsmtrace.log", opts.lflag); - opts.logfd = open(logpath, O_APPEND | O_WRONLY | O_CREAT); + opts.log_dir_fd = open(opts.lflag, O_RDONLY | O_DIRECTORY); + if (opts.log_dir_fd == -1) { + bsmtrace_error(1, "failed to open logging directory: %s\n", + strerror(errno)); + } + flags = S_IWUSR | S_IRUSR; + opts.logfd = openat(opts.log_dir_fd, "bsmtrace.log", O_APPEND | O_WRONLY | O_CREAT, flags); if (opts.logfd == -1) { bsmtrace_error(1, "open: %s failed: %s\n", logpath, strerror(errno)); } - debug_printf("logging directory and file initialized: %s\n", - logpath); + debug_printf("logging directory and file initialized"); } static char * @@ -126,7 +133,19 @@ log_bsm_txt_file(struct bsm_sequence *bs, struct bsm_record_data *br) ssize_t cc; char *ptr; size_t s; + mode_t flags; + if (rotate_log == 1) { + close(opts.logfd); + flags = S_IWUSR | S_IRUSR; + opts.logfd = openat(opts.log_dir_fd, "bsmtrace.log", + O_APPEND | O_WRONLY | O_CREAT, flags); + if (opts.logfd == -1) { + bsmtrace_error(1, "failed to rotate log: %s", + strerror(errno)); + } + rotate_log = 0; + } ptr = parse_bsm_generic(bs, br); if (ptr == NULL) return (-1); @@ -149,9 +168,8 @@ log_bsm_txt_file(struct bsm_sequence *bs, struct bsm_record_data *br) int log_bsm_file(struct bsm_sequence *bs, struct bsm_record_data *br) { - char path[MAXPATHLEN], dir[MAXPATHLEN]; - struct stat sb; - int fd, error; + char path[MAXPATHLEN]; + int fd; struct bsm_state *bm; char *src_basename; @@ -161,19 +179,17 @@ log_bsm_file(struct bsm_sequence *bs, struct bsm_record_data *br) src_basename = strrchr(opts.aflag, '/'); src_basename = (src_basename == NULL) ? opts.aflag : src_basename + 1; } - (void) snprintf(dir, MAXPATHLEN, - "%s/%s", opts.lflag, bs->bs_label); - error = stat(dir, &sb); - if (error < 0 && errno == ENOENT) { - if (mkdir(dir, S_IRWXU) < 0) - bsmtrace_error(1, "mkdir failed: %s", dir); - } else if (error < 0) - bsmtrace_error(1, "stat failed"); + if (mkdirat(opts.log_dir_fd, bs->bs_label, S_IRWXU) < 0) { + if (errno != EEXIST) { + bsmtrace_error(1, "mkdirat failed: %s: %s", bs->bs_label, + strerror(errno)); + } + } (void) sprintf(path, "%s/%d.%d.%lu", - dir, br->br_sec, br->br_usec, random()); - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + bs->bs_label, br->br_sec, br->br_usec, random()); + fd = openat(opts.log_dir_fd, path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd < 0) - bsmtrace_error(1, "open: %s: %s", path, strerror(errno)); + bsmtrace_error(1, "openat: %s: %s", path, strerror(errno)); /* * The logic here becomes a bit complex. We need to check to see if * this is a single state sequence, and if it is, log the BSM record diff --git a/privsep.c b/privsep.c index 4f76137..191b750 100644 --- a/privsep.c +++ b/privsep.c @@ -98,6 +98,13 @@ priv_setuid(void) if (pwd == NULL) { bsmtrace_error(1, "failed to get privsep uid\n"); } + /* + * Change the permissions associated with the logging directory. + */ + assert(opts.log_dir_fd != 0); + if (fchown(opts.log_dir_fd, pwd->pw_uid, pwd->pw_gid) == -1) { + bsmtrace_error(1, "unable to change logging direcotry ownership"); + } if (initgroups(opts.uflag, pwd->pw_gid) == -1) { bsmtrace_error(1, "initgroups failed: %s\n", strerror(errno)); @@ -110,6 +117,22 @@ priv_setuid(void) } } +static void +child_handle_signal(int sig) +{ + extern int rotate_log; + + switch (sig) { + case SIGHUP: + rotate_log = 1; + debug_printf("caught SIGHUP: will rotate log on next write\n"); + break; + /* + * Other signals? + */ + } +} + int priv_init(void) { @@ -128,6 +151,7 @@ priv_init(void) exit(1); } if (child_pid == 0) { + signal(SIGHUP, child_handle_signal); (void) close(socks[0]); #ifdef __FreeBSD__ priv_setuid(); @@ -367,3 +391,4 @@ priv_get_logdir_fd(void) } return (s); } + From f69c2f29d9c4fa0b114973ce7a077296a25c4b74 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Fri, 29 Jun 2018 09:29:14 -0500 Subject: [PATCH 4/4] Merge the bsmtrace_fatal/warn changes from master --- bsmtrace.c | 2 +- log.c | 4 ++-- privsep.c | 17 ++++++++--------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/bsmtrace.c b/bsmtrace.c index 7a05252..8fb7ef1 100644 --- a/bsmtrace.c +++ b/bsmtrace.c @@ -195,7 +195,7 @@ main(int argc, char *argv[]) } } if (opts.uflag == NULL) { - bsmtrace_error(1, "failed to specify privsep user\n"); + bsmtrace_fatal("failed to specify privsep user\n"); } bsmtrace_write_pidfile(opts.pflag); log_init_dir(); diff --git a/log.c b/log.c index 2af8cee..33a7572 100644 --- a/log.c +++ b/log.c @@ -57,7 +57,7 @@ log_init_dir(void) } opts.log_dir_fd = open(opts.lflag, O_RDONLY | O_DIRECTORY); if (opts.log_dir_fd == -1) { - bsmtrace_error(1, "failed to open logging directory: %s\n", + bsmtrace_fatal("failed to open logging directory: %s\n", strerror(errno)); } flags = S_IWUSR | S_IRUSR; @@ -141,7 +141,7 @@ log_bsm_txt_file(struct bsm_sequence *bs, struct bsm_record_data *br) opts.logfd = openat(opts.log_dir_fd, "bsmtrace.log", O_APPEND | O_WRONLY | O_CREAT, flags); if (opts.logfd == -1) { - bsmtrace_error(1, "failed to rotate log: %s", + bsmtrace_fatal("failed to rotate log: %s", strerror(errno)); } rotate_log = 0; diff --git a/privsep.c b/privsep.c index 191b750..d163527 100644 --- a/privsep.c +++ b/privsep.c @@ -96,24 +96,24 @@ priv_setuid(void) return; pwd = getpwnam(opts.uflag); if (pwd == NULL) { - bsmtrace_error(1, "failed to get privsep uid\n"); + bsmtrace_fatal("failed to get privsep uid\n"); } /* * Change the permissions associated with the logging directory. */ assert(opts.log_dir_fd != 0); if (fchown(opts.log_dir_fd, pwd->pw_uid, pwd->pw_gid) == -1) { - bsmtrace_error(1, "unable to change logging direcotry ownership"); + bsmtrace_fatal("unable to change logging direcotry ownership"); } if (initgroups(opts.uflag, pwd->pw_gid) == -1) { - bsmtrace_error(1, "initgroups failed: %s\n", + bsmtrace_fatal("initgroups failed: %s\n", strerror(errno)); } if (setgid(pwd->pw_gid) == -1) { - bsmtrace_error(1, "setgid failed\n"); + bsmtrace_fatal("setgid failed\n"); } if (setuid(pwd->pw_uid) == -1) { - bsmtrace_error(1, "setuid failed\n"); + bsmtrace_fatal("setuid failed\n"); } } @@ -170,10 +170,10 @@ priv_init(void) #ifdef __APPLE__ fprintf(stderr, "poor man's sandbox\n"); if (chdir("/var/empty") == -1) { - bsmtrace_error(1, "failed to chdir to /var/empty\n"); + bsmtrace_fatal("failed to chdir to /var/empty\n"); } if (chroot(".") == -1) { - bsmtrace_error(1, "failed to chroot unprivileged process\n"); + bsmtrace_fatal("failed to chroot unprivileged process\n"); } priv_setuid(); #endif @@ -362,7 +362,7 @@ priv_auditpipe_open(void) } fp = fdopen(s, "r"); if (fp == NULL) { - bsmtrace_error(0, "failed to open audit pipe: %s\n", + bsmtrace_fatal("failed to open audit pipe: %s\n", strerror(errno)); exit(1); } @@ -391,4 +391,3 @@ priv_get_logdir_fd(void) } return (s); } -