diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/syslogd/privsep.c | 110 | ||||
-rw-r--r-- | usr.sbin/syslogd/syslogd.c | 46 |
2 files changed, 139 insertions, 17 deletions
diff --git a/usr.sbin/syslogd/privsep.c b/usr.sbin/syslogd/privsep.c index 64e22cbc17c..01f3d1d9c1b 100644 --- a/usr.sbin/syslogd/privsep.c +++ b/usr.sbin/syslogd/privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.c,v 1.28 2006/07/09 14:42:27 millert Exp $ */ +/* $OpenBSD: privsep.c,v 1.29 2007/02/20 11:24:32 henning Exp $ */ /* * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> @@ -63,6 +63,7 @@ enum priv_state { enum cmd_types { PRIV_OPEN_TTY, /* open terminal or console device */ PRIV_OPEN_LOG, /* open logfile for appending */ + PRIV_OPEN_PIPE, /* fork & exec child that gets logs on stdin */ PRIV_OPEN_UTMP, /* open utmp for reading only */ PRIV_OPEN_CONFIG, /* open config file for reading only */ PRIV_CONFIG_MODIFIED, /* check if config file has been modified */ @@ -86,6 +87,8 @@ struct logname { static TAILQ_HEAD(, logname) lognames; static void check_log_name(char *, size_t); +static int open_file(char *); +static int open_pipe(char *); static void check_tty_name(char *, size_t); static void increase_state(int); static void sig_pass_to_chld(int); @@ -220,7 +223,9 @@ priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[]) break; case PRIV_OPEN_LOG: - dprintf("[priv]: msg PRIV_OPEN_LOG received\n"); + case PRIV_OPEN_PIPE: + dprintf("[priv]: msg PRIV_OPEN_%s received\n", + cmd == PRIV_OPEN_PIPE ? "PIPE" : "LOG"); /* Expecting: length, path */ must_read(socks[0], &path_len, sizeof(size_t)); if (path_len == 0 || path_len > sizeof(path)) @@ -228,7 +233,14 @@ priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[]) must_read(socks[0], &path, path_len); path[path_len - 1] = '\0'; check_log_name(path, path_len); - fd = open(path, O_WRONLY|O_APPEND|O_NONBLOCK, 0); + + if (cmd == PRIV_OPEN_LOG) + fd = open_file(path); + else if (cmd == PRIV_OPEN_PIPE) + fd = open_pipe(path); + else + errx(1, "invalid cmd"); + send_fd(socks[0], fd); if (fd < 0) warnx("priv_open_log failed"); @@ -353,6 +365,84 @@ priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[]) _exit(1); } +static int +open_file(char *path) +{ + /* must not start with | */ + if (path[0] == '|') + return (-1); + + return (open(path, O_WRONLY|O_APPEND|O_NONBLOCK, 0)); +} + +static int +open_pipe(char *cmd) +{ + char *argp[] = {"sh", "-c", NULL, NULL}; + struct passwd *pw; + int fd[2]; + int bsize, flags; + pid_t pid; + + /* skip over leading | and whitespace */ + if (cmd[0] != '|') + return (-1); + for(cmd++; *cmd && *cmd == ' '; cmd++) + ; /* nothing */ + if (!*cmd) + return (-1); + + argp[2] = cmd; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1) { + logerror("open_pipe"); + return (-1); + } + + /* make the fd on syslogd's side nonblocking */ + if ((flags = fcntl(fd[1], F_GETFL, 0)) == -1) { + logerror("fcntl"); + return (-1); + } + flags |= O_NONBLOCK; + if ((flags = fcntl(fd[1], F_SETFL, flags)) == -1) { + logerror("fcntl"); + return (-1); + } + + switch (pid = fork()) { + case -1: + logerror("fork error"); + return (-1); + case 0: + break; + default: + close(fd[0]); + return (fd[1]); + } + + close(fd[1]); + + /* grow receive buffer */ + bsize = 65535; + while (bsize > 0 && setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, + &bsize, sizeof(bsize)) == -1) + bsize /= 2; + + if ((pw = getpwnam("_syslogd")) == NULL) + errx(1, "unknown user _syslogd"); + if (setgroups(1, &pw->pw_gid) == -1 || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) + err(1, "failure dropping privs"); + endpwent(); + + if (dup2(fd[0], STDIN_FILENO) == -1) + err(1, "dup2 failed"); + if (execv("/bin/sh", argp) == -1) + err(1, "execv %s", cmd); +} + /* Check that the terminal device is ok, and if not, rewrite to /dev/null. * Either /dev/console or /dev/tty* are allowed. */ @@ -468,7 +558,10 @@ priv_open_log(const char *lognam) return -1; path_len = strlen(path) + 1; - cmd = PRIV_OPEN_LOG; + if (lognam[0] == '|') + cmd = PRIV_OPEN_PIPE; + else + cmd = PRIV_OPEN_LOG; must_write(priv_fd, &cmd, sizeof(int)); must_write(priv_fd, &path_len, sizeof(size_t)); must_write(priv_fd, path, path_len); @@ -654,7 +747,14 @@ sig_pass_to_chld(int sig) static void sig_got_chld(int sig) { - if (cur_state < STATE_QUIT) + pid_t pid; + + do { + pid = waitpid(WAIT_ANY, NULL, WNOHANG); + } while (pid == -1 && errno == EINTR); + + if (pid == child_pid && + cur_state < STATE_QUIT) cur_state = STATE_QUIT; } diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 5ccd8c68c75..fac3bb08849 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syslogd.c,v 1.94 2007/01/03 13:25:20 mpf Exp $ */ +/* $OpenBSD: syslogd.c,v 1.95 2007/02/20 11:24:32 henning Exp $ */ /* * Copyright (c) 1983, 1988, 1993, 1994 @@ -39,7 +39,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; #else -static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.94 2007/01/03 13:25:20 mpf Exp $"; +static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.95 2007/02/20 11:24:32 henning Exp $"; #endif #endif /* not lint */ @@ -183,10 +183,12 @@ int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ #define F_USERS 5 /* list of users */ #define F_WALL 6 /* everyone logged on */ #define F_MEMBUF 7 /* memory buffer */ +#define F_PIPE 8 /* pipe to external program */ -char *TypeNames[8] = { +char *TypeNames[9] = { "UNUSED", "FILE", "TTY", "CONSOLE", - "FORW", "USERS", "WALL", "MEMBUF" + "FORW", "USERS", "WALL", "MEMBUF", + "PIPE" }; struct filed *Files; @@ -897,8 +899,9 @@ fprintlog(struct filed *f, int flags, char *msg) case F_TTY: case F_FILE: + case F_PIPE: dprintf(" %s\n", f->f_un.f_fname); - if (f->f_type != F_FILE) { + if (f->f_type != F_FILE && f->f_type != F_PIPE) { v->iov_base = "\r\n"; v->iov_len = 2; } else { @@ -920,7 +923,8 @@ fprintlog(struct filed *f, int flags, char *msg) */ break; } else if ((e == EIO || e == EBADF) && - f->f_type != F_FILE && !retryonce) { + f->f_type != F_FILE && f->f_type != F_PIPE && + !retryonce) { f->f_file = priv_open_tty(f->f_un.f_fname); retryonce = 1; if (f->f_file < 0) { @@ -928,6 +932,15 @@ fprintlog(struct filed *f, int flags, char *msg) logerror(f->f_un.f_fname); } else goto again; + } else if ((e == EPIPE || e == EBADF) && + f->f_type == F_PIPE && !retryonce) { + f->f_file = priv_open_log(f->f_un.f_fname); + retryonce = 1; + if (f->f_file < 0) { + f->f_type = F_UNUSED; + logerror(f->f_un.f_fname); + } else + goto again; } else { f->f_type = F_UNUSED; f->f_file = -1; @@ -1163,6 +1176,7 @@ init(void) case F_FILE: case F_TTY: case F_CONSOLE: + case F_PIPE: (void)close(f->f_file); break; case F_FORW: @@ -1250,6 +1264,7 @@ init(void) case F_FILE: case F_TTY: case F_CONSOLE: + case F_PIPE: printf("%s", f->f_un.f_fname); break; @@ -1282,7 +1297,7 @@ init(void) (p1 == p2 || (p1 != NULL && p2 != NULL && strcmp(p1, p2) == 0)) /* - * Spot a line with a duplicate file, console, tty, or membuf target. + * Spot a line with a duplicate file, pipe, console, tty, or membuf target. */ struct filed * find_dup(struct filed *f) @@ -1296,6 +1311,7 @@ find_dup(struct filed *f) case F_FILE: case F_TTY: case F_CONSOLE: + case F_PIPE: if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 && progmatches(list->f_program, f->f_program)) return (list); @@ -1441,6 +1457,7 @@ cfline(char *line, char *prog) break; case '/': + case '|': (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); d = find_dup(f); if (d != NULL) { @@ -1465,11 +1482,16 @@ cfline(char *line, char *prog) else f->f_type = F_TTY; } else { - f->f_type = F_FILE; - /* Clear O_NONBLOCK flag on f->f_file */ - if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { - i &= ~O_NONBLOCK; - fcntl(f->f_file, F_SETFL, i); + if (*p == '|') + f->f_type = F_PIPE; + else { + f->f_type = F_FILE; + + /* Clear O_NONBLOCK flag on f->f_file */ + if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { + i &= ~O_NONBLOCK; + fcntl(f->f_file, F_SETFL, i); + } } } break; |