diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/mail.local/locking.c | 4 | ||||
-rw-r--r-- | libexec/mail.local/mail.local.c | 73 | ||||
-rw-r--r-- | libexec/mail.local/mail.local.h | 6 |
3 files changed, 71 insertions, 12 deletions
diff --git a/libexec/mail.local/locking.c b/libexec/mail.local/locking.c index 191b2dfeed7..d63642c1828 100644 --- a/libexec/mail.local/locking.c +++ b/libexec/mail.local/locking.c @@ -1,4 +1,4 @@ -/* $OpenBSD: locking.c,v 1.12 2015/01/16 06:39:50 deraadt Exp $ */ +/* $OpenBSD: locking.c,v 1.13 2020/02/02 23:17:09 millert Exp $ */ /* * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> @@ -55,7 +55,7 @@ rellock(void) } int -getlock(char *name, struct passwd *pw) +getlock(const char *name, struct passwd *pw) { struct stat sb, fsb; int lfd=-1; diff --git a/libexec/mail.local/mail.local.c b/libexec/mail.local/mail.local.c index ddfaae20a0a..635b2558ee5 100644 --- a/libexec/mail.local/mail.local.c +++ b/libexec/mail.local/mail.local.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mail.local.c,v 1.36 2019/06/28 13:32:53 deraadt Exp $ */ +/* $OpenBSD: mail.local.c,v 1.37 2020/02/02 23:17:09 millert Exp $ */ /*- * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> @@ -34,6 +34,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/wait.h> #include <netinet/in.h> #include <syslog.h> #include <fcntl.h> @@ -46,6 +47,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <signal.h> #include "pathnames.h" #include "mail.local.h" @@ -92,8 +94,6 @@ main(int argc, char *argv[]) } else { if (!*argv) usage(); - if (geteuid() != 0) - merr(FATAL, "may only be run by the superuser"); } /* @@ -188,7 +188,7 @@ deliver(int fd, char *name, int lockfile) (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name); if (lockfile) { - lfd = getlock(name, pw); + lfd = lockspool(name, pw); if (lfd == -1) return (1); } @@ -270,10 +270,8 @@ retry: } bad: - if (lfd != -1) { - rellock(); - close(lfd); - } + if (lfd != -1) + unlockspool(); if (mbfd != -1) { (void)fsync(mbfd); /* Don't wait for update. */ @@ -328,6 +326,65 @@ notifybiff(char *msg) merr(NOTFATAL, "sendto biff: %s", strerror(errno)); } +static int lockfd = -1; +static pid_t lockpid = -1; + +int +lockspool(const char *name, struct passwd *pw) +{ + int pfd[2]; + char ch; + + if (geteuid() == 0) + return getlock(name, pw); + + /* If not privileged, open pipe to lockspool(1) instead */ + if (pipe2(pfd, O_CLOEXEC) == -1) { + merr(FATAL, "pipe: %s", strerror(errno)); + return -1; + } + + signal(SIGPIPE, SIG_IGN); + switch ((lockpid = fork())) { + case -1: + merr(FATAL, "fork: %s", strerror(errno)); + return -1; + case 0: + /* child */ + close(pfd[0]); + dup2(pfd[1], STDOUT_FILENO); + execl(_PATH_LOCKSPOOL, "lockspool", (char *)NULL); + merr(FATAL, "execl: lockspool: %s", strerror(errno)); + /* NOTREACHED */ + break; + default: + /* parent */ + close(pfd[1]); + lockfd = pfd[0]; + break; + } + + if (read(lockfd, &ch, 1) != 1 || ch != '1') { + unlockspool(); + merr(FATAL, "lockspool: unable to get lock"); + } + + return lockfd; +} + +void +unlockspool(void) +{ + if (lockpid != -1) { + waitpid(lockpid, NULL, 0); + lockpid = -1; + } else { + rellock(); + } + close(lockfd); + lockfd = -1; +} + void usage(void) { diff --git a/libexec/mail.local/mail.local.h b/libexec/mail.local/mail.local.h index 0377aa20364..92a0b78cf37 100644 --- a/libexec/mail.local/mail.local.h +++ b/libexec/mail.local/mail.local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mail.local.h,v 1.5 2006/04/01 22:48:57 deraadt Exp $ */ +/* $OpenBSD: mail.local.h,v 1.6 2020/02/02 23:17:09 millert Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -35,8 +35,10 @@ void baditem(char *); int deliver(int, char *, int); void merr(int, const char *, ...); -int getlock(char *, struct passwd *); +int getlock(const char *, struct passwd *); void notifybiff(char *); void rellock(void); int storemail(char *); +int lockspool(const char *, struct passwd *); +void unlockspool(void); void usage(void); |