diff options
author | 2020-02-10 22:16:16 +0100 | |
---|---|---|
committer | 2020-02-24 18:30:03 +0100 | |
commit | 31af3f6f44f8a9d49b6cd376bf7568b4183ec237 (patch) | |
tree | b3d0620cb1d629319c0caae4835f59c6289b29d9 /contrib | |
parent | errata diff from OpenBSD (diff) | |
download | OpenSMTPD-31af3f6f44f8a9d49b6cd376bf7568b4183ec237.tar.xz OpenSMTPD-31af3f6f44f8a9d49b6cd376bf7568b4183ec237.zip |
add lockspool and update mail.local
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/libexec/Makefile.am | 2 | ||||
-rw-r--r-- | contrib/libexec/lockspool/Makefile | 10 | ||||
-rw-r--r-- | contrib/libexec/lockspool/Makefile.am | 19 | ||||
-rw-r--r-- | contrib/libexec/lockspool/locking.c | 181 | ||||
-rw-r--r-- | contrib/libexec/lockspool/lockspool.1 | 77 | ||||
-rw-r--r-- | contrib/libexec/lockspool/lockspool.c | 124 | ||||
-rw-r--r-- | contrib/libexec/mail.local/locking.c | 33 | ||||
-rw-r--r-- | contrib/libexec/mail.local/mail.local.c | 158 | ||||
-rw-r--r-- | contrib/libexec/mail.local/mail.local.h | 10 |
9 files changed, 536 insertions, 78 deletions
diff --git a/contrib/libexec/Makefile.am b/contrib/libexec/Makefile.am index 6079ae6a..0e3a271f 100644 --- a/contrib/libexec/Makefile.am +++ b/contrib/libexec/Makefile.am @@ -1 +1 @@ -SUBDIRS = mail.local encrypt +SUBDIRS = mail.local lockspool encrypt diff --git a/contrib/libexec/lockspool/Makefile b/contrib/libexec/lockspool/Makefile new file mode 100644 index 00000000..63928844 --- /dev/null +++ b/contrib/libexec/lockspool/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 1998/08/15 21:02:22 millert Exp $ + +PROG= lockspool +SRCS= lockspool.c locking.c +BINOWN= root +BINMODE=4555 +CFLAGS+=-I${.CURDIR}/../mail.local +.PATH: ${.CURDIR}/../mail.local + +.include <bsd.prog.mk> diff --git a/contrib/libexec/lockspool/Makefile.am b/contrib/libexec/lockspool/Makefile.am new file mode 100644 index 00000000..114ad2b4 --- /dev/null +++ b/contrib/libexec/lockspool/Makefile.am @@ -0,0 +1,19 @@ +pkglibexec_PROGRAMS = lockspool + +lockspool_SOURCES = lockspool.c +lockspool_SOURCES += locking.c + +EXTRA_DIST = mail.local.h pathnames.h + +AM_CPPFLAGS = -I$(top_srcdir)/openbsd-compat -I$(top_srcdir)/mail.local + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + +install-exec-hook: $(CONFIGFILES) $(MANPAGES) + chown root $(DESTDIR)$(pkglibexecdir)/lockspool || true + chmod 1555 $(DESTDIR)$(pkglibexecdir)/lockspool || true + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/contrib/libexec/lockspool/locking.c b/contrib/libexec/lockspool/locking.c new file mode 100644 index 00000000..e4922dd6 --- /dev/null +++ b/contrib/libexec/lockspool/locking.c @@ -0,0 +1,181 @@ +/* $OpenBSD: locking.c,v 1.14 2020/02/09 14:59:20 millert Exp $ */ + +/* + * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> + * Copyright (c) 1996-1998 David Mazieres <dm@lcs.mit.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHORS 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 "includes.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pwd.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "pathnames.h" +#include "mail.local.h" + +static char lpath[PATH_MAX]; + +void +rellock(void) +{ + + if (lpath[0]) + unlink(lpath); +} + +int +getlock(const char *name, struct passwd *pw) +{ + struct stat sb, fsb; + int lfd=-1; + char buf[8*1024]; + int tries = 0; + + (void)snprintf(lpath, sizeof lpath, "%s/%s.lock", + _PATH_MAILDIR, name); + + if (stat(_PATH_MAILDIR, &sb) != -1 && + (sb.st_mode & S_IWOTH) == S_IWOTH) { + /* + * We have a writeable spool, deal with it as + * securely as possible. + */ + time_t ctim = -1; + + seteuid(pw->pw_uid); + if (lstat(lpath, &sb) != -1) + ctim = sb.st_ctime; + while (1) { + /* + * Deal with existing user.lock files + * or directories or symbolic links that + * should not be here. + */ + if (readlink(lpath, buf, sizeof buf-1) != -1) { + if (lstat(lpath, &sb) != -1 && + S_ISLNK(sb.st_mode)) { + seteuid(sb.st_uid); + unlink(lpath); + seteuid(pw->pw_uid); + } + goto again; + } + if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK, + S_IRUSR|S_IWUSR)) != -1) + break; +again: + if (tries > 10) { + mwarn("%s: %s", lpath, strerror(errno)); + seteuid(0); + return(-1); + } + if (tries > 9 && + (lfd = open(lpath, O_WRONLY|O_EXLOCK, 0)) != -1) { + if (fstat(lfd, &fsb) != -1 && + lstat(lpath, &sb) != -1) { + if (fsb.st_dev == sb.st_dev && + fsb.st_ino == sb.st_ino && + ctim == fsb.st_ctime ) { + seteuid(fsb.st_uid); + baditem(lpath); + seteuid(pw->pw_uid); + } + } + close(lfd); + } + sleep(1U << tries); + tries++; + continue; + } + seteuid(0); + } else { + /* + * Only root can write the spool directory. + */ + while (1) { + if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL, + S_IRUSR|S_IWUSR)) != -1) + break; + if (tries > 9) { + mwarn("%s: %s", lpath, strerror(errno)); + return(-1); + } + sleep(1U << tries); + tries++; + } + } + return(lfd); +} + +void +baditem(char *path) +{ + char npath[PATH_MAX]; + int fd; + + if (unlink(path) == 0) + return; + snprintf(npath, sizeof npath, "%s/mailXXXXXXXXXX", _PATH_MAILDIR); + if ((fd = mkstemp(npath)) == -1) + return; + close(fd); + if (rename(path, npath) == -1) + unlink(npath); + else + mwarn("nasty spool item %s renamed to %s", path, npath); + /* XXX if we fail to rename, another attempt will happen later */ +} + +void +mwarn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); +} + +void +merr(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + exit(eval); +} diff --git a/contrib/libexec/lockspool/lockspool.1 b/contrib/libexec/lockspool/lockspool.1 new file mode 100644 index 00000000..ea5524bf --- /dev/null +++ b/contrib/libexec/lockspool/lockspool.1 @@ -0,0 +1,77 @@ +.\" $OpenBSD: lockspool.1,v 1.14 2019/01/25 00:19:26 millert Exp $ +.\" +.\" Copyright (c) 1998 Todd C. Miller <millert@openbsd.org> +.\" +.\" 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. +.\" +.Dd $Mdocdate: January 25 2019 $ +.Dt LOCKSPOOL 1 +.Os +.Sh NAME +.Nm lockspool +.Nd lock user's system mailbox +.Sh SYNOPSIS +.Nm lockspool +.Op Ar username +.Sh DESCRIPTION +.Nm +is useful for a client mail program to attain proper locking. +.Nm +obtains a +.Pa username.lock +for the calling user and retains it until stdin is closed or a signal like +.Dv SIGINT , +.Dv SIGTERM , +or +.Dv SIGHUP +is received. +Additionally, the superuser may specify the name of a user in order +to lock a different mailbox. +.Pp +If +.Nm +is able to create the lock file, +.Dq 1 +is written to stdout, otherwise +.Dq 0 +is written and an error message is written to stderr. +.Nm +will try up to 10 times to get the lock (sleeping +for a short period in between tries). +.Pp +Typical usage is for a user mail agent (such as +.Xr mail 1 ) +to open a pipe to +.Nm +when it needs to lock the user's mail spool. +Closing the pipe will cause +.Nm +to release the lock. +.Sh FILES +.Bl -tag -width /var/mail/username.lock -compact +.It Pa /var/mail/username.lock +user's mail lock file +.El +.Sh EXIT STATUS +The +.Nm +utility exits 0 on success, and 1 if an error occurs. +.Sh SEE ALSO +.Xr mail 1 , +.Xr mail.local 8 , +.Xr smtpd 8 +.Sh HISTORY +The +.Nm +program appeared in +.Ox 2.4 . diff --git a/contrib/libexec/lockspool/lockspool.c b/contrib/libexec/lockspool/lockspool.c new file mode 100644 index 00000000..65de8ce7 --- /dev/null +++ b/contrib/libexec/lockspool/lockspool.c @@ -0,0 +1,124 @@ +/* $OpenBSD: lockspool.c,v 1.21 2020/02/09 14:59:20 millert Exp $ */ + +/* + * Copyright (c) 1998 Theo de Raadt <deraadt@theos.com> + * Copyright (c) 1998 Todd C. Miller <millert@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 ``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 AUTHORS 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 "includes.h" + +#include <signal.h> +#include <pwd.h> +#include <syslog.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <paths.h> +#include <stdlib.h> +#include <poll.h> +#include <err.h> + +#include "mail.local.h" + +void unhold(int); +void usage(void); + +extern char *__progname; + +int +main(int argc, char *argv[]) +{ + struct passwd *pw; + struct pollfd pfd; + ssize_t nread; + char *from, c; + int holdfd; + +#ifdef HAVE_UNVEIL + if (unveil(_PATH_MAILDIR, "rwc") == -1) + err(1, "unveil"); +#endif +#ifdef HAVE_PLEDGE + if (pledge("stdio rpath wpath getpw cpath fattr", NULL) == -1) + err(1, "pledge"); +#endif + + openlog(__progname, LOG_PERROR, LOG_MAIL); + + if (argc != 1 && argc != 2) + usage(); + if (argc == 2 && getuid() != 0) + merr(1, "you must be root to lock someone else's spool"); + + signal(SIGTERM, unhold); + signal(SIGINT, unhold); + signal(SIGHUP, unhold); + signal(SIGPIPE, unhold); + + if (argc == 2) + pw = getpwnam(argv[1]); + else + pw = getpwuid(getuid()); + if (pw == NULL) + exit (1); + from = pw->pw_name; + + holdfd = getlock(from, pw); + if (holdfd == -1) { + write(STDOUT_FILENO, "0\n", 2); + exit (1); + } + write(STDOUT_FILENO, "1\n", 2); + + /* wait for the other end of the pipe to close, then release the lock */ + pfd.fd = STDIN_FILENO; + pfd.events = POLLIN; + do { + if (poll(&pfd, 1, INFTIM) == -1) { + if (errno != EINTR) + break; + } + do { + nread = read(STDIN_FILENO, &c, 1); + } while (nread == 1 || (nread == -1 && errno == EINTR)); + } while (nread == -1 && errno == EAGAIN); + rellock(); + exit (0); +} + +/*ARGSUSED*/ +void +unhold(int signo) +{ + + rellock(); + _exit(0); +} + +void +usage(void) +{ + + merr(1, "usage: %s [username]", __progname); +} diff --git a/contrib/libexec/mail.local/locking.c b/contrib/libexec/mail.local/locking.c index db2e2091..85a48d5e 100644 --- a/contrib/libexec/mail.local/locking.c +++ b/contrib/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.14 2020/02/09 14:59:20 millert Exp $ */ /* * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> @@ -58,7 +58,7 @@ rellock(void) } int -getlock(char *name, struct passwd *pw) +getlock(const char *name, struct passwd *pw) { struct stat sb, fsb; int lfd=-1; @@ -94,19 +94,12 @@ getlock(char *name, struct passwd *pw) } goto again; } -#ifndef O_EXLOCK -#define O_EXLOCK 0 -#endif if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK, S_IRUSR|S_IWUSR)) != -1) break; -#ifndef O_EXLOCK - /* XXX : do something! */ -#endif again: if (tries > 10) { - merr(NOTFATAL, "%s: %s", lpath, - strerror(errno)); + mwarn("%s: %s", lpath, strerror(errno)); seteuid(0); return(-1); } @@ -138,7 +131,7 @@ again: S_IRUSR|S_IWUSR)) != -1) break; if (tries > 9) { - merr(NOTFATAL, "%s: %s", lpath, strerror(errno)); + mwarn("%s: %s", lpath, strerror(errno)); return(-1); } sleep(1U << tries); @@ -163,19 +156,27 @@ baditem(char *path) if (rename(path, npath) == -1) unlink(npath); else - merr(NOTFATAL, "nasty spool item %s renamed to %s", - path, npath); + mwarn("nasty spool item %s renamed to %s", path, npath); /* XXX if we fail to rename, another attempt will happen later */ } void -merr(int isfatal, const char *fmt, ...) +mwarn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsyslog(LOG_ERR, fmt, ap); va_end(ap); - if (isfatal) - exit(1); +} + +void +merr(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + exit(eval); } diff --git a/contrib/libexec/mail.local/mail.local.c b/contrib/libexec/mail.local/mail.local.c index c11ea907..a574b3fe 100644 --- a/contrib/libexec/mail.local/mail.local.c +++ b/contrib/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.39 2020/02/09 14:59:20 millert Exp $ */ /*- * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> @@ -37,7 +37,9 @@ #include <sys/stat.h> #include <sys/socket.h> +#include <sys/wait.h> #include <netinet/in.h> +#include <sysexits.h> #include <syslog.h> #include <fcntl.h> #include <netdb.h> @@ -49,6 +51,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <signal.h> #include "pathnames.h" #include "mail.local.h" @@ -56,21 +59,21 @@ int main(int argc, char *argv[]) { struct passwd *pw; - int ch, fd, eval, lockfile=1, holdme=0; + int ch, fd, eval, lockfile=1; uid_t uid; char *from; openlog("mail.local", LOG_PERROR, LOG_MAIL); from = NULL; - while ((ch = getopt(argc, argv, "lLdf:r:H")) != -1) + while ((ch = getopt(argc, argv, "lLdf:r:")) != -1) switch (ch) { case 'd': /* backward compatible */ break; case 'f': case 'r': /* backward compatible */ if (from) - merr(FATAL, "multiple -f options"); + merr(EX_USAGE, "multiple -f options"); from = optarg; break; case 'l': @@ -79,25 +82,14 @@ main(int argc, char *argv[]) case 'L': lockfile=0; break; - case 'H': - holdme=1; - break; default: usage(); } argc -= optind; argv += optind; - /* Support -H flag for backwards compat */ - if (holdme) { - execl(_PATH_LOCKSPOOL, "lockspool", (char *)NULL); - merr(FATAL, "execl: lockspool: %s", strerror(errno)); - } else { - if (!*argv) - usage(); - if (geteuid() != 0) - merr(FATAL, "may only be run by the superuser"); - } + if (!*argv) + usage(); /* * If from not specified, use the name from getlogin() if the @@ -110,8 +102,10 @@ main(int argc, char *argv[]) from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; fd = storemail(from); - for (eval = 0; *argv; ++argv) - eval |= deliver(fd, *argv, lockfile); + for (eval = 0; *argv; ++argv) { + if ((ch = deliver(fd, *argv, lockfile)) != 0) + eval = ch; + } exit(eval); } @@ -125,9 +119,9 @@ storemail(char *from) char *line, *tbuf; if ((tbuf = strdup(_PATH_LOCTMP)) == NULL) - merr(FATAL, "unable to allocate memory"); + merr(EX_OSERR, "unable to allocate memory"); if ((fd = mkstemp(tbuf)) == -1 || !(fp = fdopen(fd, "w+"))) - merr(FATAL, "unable to open temporary file"); + merr(EX_OSERR, "unable to open temporary file"); (void)unlink(tbuf); free(tbuf); @@ -141,7 +135,7 @@ storemail(char *from) else { /* No trailing newline, so alloc space and copy */ if ((tbuf = malloc(len + 1)) == NULL) - merr(FATAL, "unable to allocate memory"); + merr(EX_OSERR, "unable to allocate memory"); memcpy(tbuf, line, len); tbuf[len] = '\0'; line = tbuf; @@ -164,7 +158,7 @@ storemail(char *from) (void)putc('\n', fp); (void)fflush(fp); if (ferror(fp)) - merr(FATAL, "temporary file write error"); + merr(EX_OSERR, "temporary file write error"); return(fd); } @@ -173,7 +167,7 @@ deliver(int fd, char *name, int lockfile) { struct stat sb, fsb; struct passwd *pw; - int mbfd=-1, rval=1, lfd=-1; + int mbfd=-1, lfd=-1, rval=EX_OSERR; char biffmsg[100], buf[8*1024], path[PATH_MAX]; off_t curoff; size_t off; @@ -184,28 +178,25 @@ deliver(int fd, char *name, int lockfile) * handled in the sendmail aliases file. */ if (!(pw = getpwnam(name))) { - merr(NOTFATAL, "unknown name: %s", name); - return(1); + mwarn("unknown name: %s", name); + return(EX_NOUSER); } (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); + return(EX_OSERR); } /* after this point, always exit via bad to remove lockfile */ retry: if (lstat(path, &sb)) { if (errno != ENOENT) { - merr(NOTFATAL, "%s: %s", path, strerror(errno)); + mwarn("%s: %s", path, strerror(errno)); goto bad; } -#ifndef O_EXLOCK -#define O_EXLOCK 0 -#endif if ((mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|O_EXLOCK, S_IRUSR|S_IWUSR)) == -1) { #ifndef HAVE_O_EXLOCK @@ -215,7 +206,8 @@ retry: /* file appeared since lstat */ goto retry; } else { - merr(NOTFATAL, "%s: %s", path, strerror(errno)); + mwarn("%s: %s", path, strerror(errno)); + rval = EX_CANTCREAT; goto bad; } } @@ -226,32 +218,32 @@ retry: * was a reason for doing so. */ if (fchown(mbfd, pw->pw_uid, pw->pw_gid) == -1) { - merr(NOTFATAL, "chown %u:%u: %s", - pw->pw_uid, pw->pw_gid, name); + mwarn("chown %u:%u: %s", pw->pw_uid, pw->pw_gid, name); goto bad; } } else { if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) { - merr(NOTFATAL, "%s: linked or special file", path); + mwarn("%s: linked or special file", path); goto bad; } if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK, S_IRUSR|S_IWUSR)) == -1) { - merr(NOTFATAL, "%s: %s", path, strerror(errno)); + mwarn("%s: %s", path, strerror(errno)); goto bad; } if (fstat(mbfd, &fsb) == -1) { /* relating error to path may be bad style */ - merr(NOTFATAL, "%s: %s", path, strerror(errno)); + mwarn("%s: %s", path, strerror(errno)); goto bad; } if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) { - merr(NOTFATAL, "%s: changed after open", path); + mwarn("%s: changed after open", path); goto bad; } /* paranoia? */ if (fsb.st_nlink != 1 || !S_ISREG(fsb.st_mode)) { - merr(NOTFATAL, "%s: linked or special file", path); + mwarn("%s: linked or special file", path); + rval = EX_CANTCREAT; goto bad; } } @@ -259,14 +251,14 @@ retry: curoff = lseek(mbfd, 0, SEEK_END); (void)snprintf(biffmsg, sizeof biffmsg, "%s@%lld\n", name, curoff); if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - merr(NOTFATAL, "temporary file: %s", strerror(errno)); + mwarn("temporary file: %s", strerror(errno)); goto bad; } while ((nr = read(fd, buf, sizeof(buf))) > 0) - for (off = 0; off < (size_t)nr; off += nw) + for (off = 0; off < nr; off += nw) if ((nw = write(mbfd, buf + off, nr - off)) == -1) { - merr(NOTFATAL, "%s: %s", path, strerror(errno)); + mwarn("%s: %s", path, strerror(errno)); (void)ftruncate(mbfd, curoff); goto bad; } @@ -275,14 +267,12 @@ retry: rval = 0; } else { (void)ftruncate(mbfd, curoff); - merr(FATAL, "temporary file: %s", strerror(errno)); + mwarn("temporary file: %s", strerror(errno)); } bad: - if (lfd != -1) { - rellock(); - close(lfd); - } + if (lfd != -1) + unlockspool(); if (mbfd != -1) { (void)fsync(mbfd); /* Don't wait for update. */ @@ -301,7 +291,6 @@ notifybiff(char *msg) struct addrinfo hints, *res; static int f = -1; size_t len; - ssize_t slen; int error; if (res0 == NULL) { @@ -313,8 +302,7 @@ notifybiff(char *msg) if (error) { /* Be silent if biff service not available. */ if (error != EAI_SERVICE) { - merr(NOTFATAL, "localhost: %s", - gai_strerror(error)); + mwarn("localhost: %s", gai_strerror(error)); } return; } @@ -329,18 +317,76 @@ notifybiff(char *msg) } } if (f == -1) { - merr(NOTFATAL, "socket: %s", strerror(errno)); + mwarn("socket: %s", strerror(errno)); return; } len = strlen(msg) + 1; /* XXX */ - slen = sendto(f, msg, len, 0, res->ai_addr, res->ai_addrlen); - if (slen == -1 || (size_t)slen != len) - merr(NOTFATAL, "sendto biff: %s", strerror(errno)); + if (sendto(f, msg, len, 0, res->ai_addr, res->ai_addrlen) != len) + mwarn("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(EX_OSERR, "pipe: %s", strerror(errno)); + return -1; + } + + signal(SIGPIPE, SIG_IGN); + switch ((lockpid = fork())) { + case -1: + merr(EX_OSERR, "fork: %s", strerror(errno)); + return -1; + case 0: + /* child */ + close(pfd[0]); + dup2(pfd[1], STDOUT_FILENO); + execl(_PATH_LOCKSPOOL, "lockspool", (char *)NULL); + merr(EX_OSERR, "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(EX_OSERR, "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) { - merr(FATAL, "usage: mail.local [-Ll] [-f from] user ..."); + merr(EX_USAGE, "usage: mail.local [-Ll] [-f from] user ..."); } diff --git a/contrib/libexec/mail.local/mail.local.h b/contrib/libexec/mail.local/mail.local.h index 0377aa20..bc3137cb 100644 --- a/contrib/libexec/mail.local/mail.local.h +++ b/contrib/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.7 2020/02/09 14:59:21 millert Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -29,14 +29,14 @@ * SUCH DAMAGE. */ -#define FATAL 1 -#define NOTFATAL 0 - void baditem(char *); int deliver(int, char *, int); void merr(int, const char *, ...); -int getlock(char *, struct passwd *); +void mwarn(const char *, ...); +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); |