diff options
Diffstat (limited to 'contrib/libexec/mail.local')
-rw-r--r-- | contrib/libexec/mail.local/Makefile.am | 22 | ||||
-rw-r--r-- | contrib/libexec/mail.local/locking.c | 182 | ||||
-rw-r--r-- | contrib/libexec/mail.local/mail.local.8 | 183 | ||||
-rw-r--r-- | contrib/libexec/mail.local/mail.local.c | 392 | ||||
-rw-r--r-- | contrib/libexec/mail.local/mail.local.h | 42 | ||||
-rw-r--r-- | contrib/libexec/mail.local/pathnames.h | 38 |
6 files changed, 859 insertions, 0 deletions
diff --git a/contrib/libexec/mail.local/Makefile.am b/contrib/libexec/mail.local/Makefile.am new file mode 100644 index 00000000..bd5211a2 --- /dev/null +++ b/contrib/libexec/mail.local/Makefile.am @@ -0,0 +1,22 @@ +pkglibexec_PROGRAMS = mail.local + +mail_local_SOURCES = mail.local.c +mail_local_SOURCES += locking.c +mail_local_SOURCES += $(top_srcdir)/smtpd/log.c + +EXTRA_DIST = mail.local.h pathnames.h + +AM_CPPFLAGS = -I$(top_srcdir)/openbsd-compat -DPATH_LIBEXEC=\"$(pkglibexecdir)\" + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd.a + +LDADD = $(LIBCOMPAT) + +# need to define _GNU_SOURCE to get: +# EAI_NODATA defined +# {v,}asprintf +# setres{g,u}id +#CFLAGS += -D_GNU_SOURCE + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/contrib/libexec/mail.local/locking.c b/contrib/libexec/mail.local/locking.c new file mode 100644 index 00000000..85a48d5e --- /dev/null +++ b/contrib/libexec/mail.local/locking.c @@ -0,0 +1,182 @@ +/* $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/mail.local/mail.local.8 b/contrib/libexec/mail.local/mail.local.8 new file mode 100644 index 00000000..330a4473 --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.8 @@ -0,0 +1,183 @@ +.\" $OpenBSD: mail.local.8,v 1.31 2014/09/16 21:28:51 jmc Exp $ +.\" Copyright (c) 1990 The Regents of the University of California. +.\" 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. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" from: @(#)mail.local.8 6.8 (Berkeley) 4/27/91 +.\" +.Dd $Mdocdate: September 16 2014 $ +.Dt MAIL.LOCAL 8 +.Os +.Sh NAME +.Nm mail.local +.Nd store mail in a mailbox +.Sh SYNOPSIS +.Nm mail.local +.Op Fl Ll +.Op Fl f Ar from +.Ar user ... +.Sh DESCRIPTION +.Nm +reads the standard input up to an end-of-file and appends it to each +.Ar user Ns 's +.Pa mail +file. +The +.Ar user +must be a valid user name. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar from +Specify the sender's name. +.It Fl L +Don't create a +.Pa username.lock +file while locking the spool. +.It Fl l +For compatibility, request that files named +.Pa username.lock +be used for locking. +(This is the default behavior.) +.El +.Pp +Individual mail messages in the mailbox are delimited by an empty +line followed by a line beginning with the string +.Dq "From\&\ " . +A line containing the string +.Dq "From\&\ " , +the sender's name and a timestamp is prepended to each delivered mail message. +A blank line is appended to each message. +A greater-than character +.Pq Ql > +is prepended to any line in the message which could be mistaken for a +.Dq "From\&\ " +delimiter line. +.Pp +Significant efforts have been made to ensure that +.Nm +acts as securely as possible if the spool directory is mode 1777 or 755. +The default of mode 755 is more secure, but it prevents mail clients from using +.Pa username.lock +style locking. +The use of 1777 is more flexible in an NFS shared-spool environment, +so many sites use it. +However, it does carry some risks, such as attackers filling the spool disk. +Some of these problems may be alleviated +by making the spool a separate filesystem, and placing quotas on it. +The use of any mode other than 1777 and 755 for the spool directory is +recommended against but may work properly. +.Pp +The mailbox is always locked using +.Xr flock 2 +while mail is appended. +Unless the +.Fl L +flag is specified, a +.Pa username.lock +file is also used. +.Pp +If the +.Xr biff 1 +service is returned by +.Xr getservbyname 3 , +the biff server is notified of delivered mail. +.Sh ENVIRONMENT +.Bl -tag -width indent +.It Ev TZ +Used to set the appropriate time zone on the timestamp. +.El +.Sh FILES +.Bl -tag -width /tmp/local.XXXXXXXXXX -compact +.It Pa /tmp/local.XXXXXXXXXX +temporary files +.It Pa /var/mail/user +user's mailbox directory +.El +.Sh EXIT STATUS +.Ex -std mail.local +.Sh SEE ALSO +.Xr biff 1 , +.Xr mail 1 , +.Xr flock 2 , +.Xr getservbyname 3 , +.Xr comsat 8 , +.Xr smtpd 8 +.Sh HISTORY +A superset of +.Nm +(handling mailbox reading as well as mail delivery) appeared in +.At v7 +as the program +.Xr mail 1 . +.Sh BUGS +Using quotas in +.Pa /var/mail +can be problematic if using +.Xr sendmail 8 +as an MTA, +since it asks +.Nm +to deliver a message to multiple recipients if possible. +This causes problems in a quota environment since a message may be +delivered to some users but not others due to disk quotas. +Even though the message was delivered to some of the recipients, +.Nm +will exit with an exit code > 0, causing +.Xr sendmail 8 +to attempt redelivery later. +That means that some users will keep getting the same message every time +.Xr sendmail 8 +runs its queue. +This problem does not exist for +.Xr smtpd 8 +users. +.Pp +If you are running +.Xr sendmail 8 +and have disk quotas on +.Pa /var/mail +it is imperative that you unset the +.Dq m +mailer flag for the +.Sq local +mailer. +To do this, locate the line beginning with +.Dq Mlocal +in +.Pa /etc/mail/sendmail.cf +and remove the +.Dq m +from the flags section, denoted by +.Dq F= . +Alternately, you can override the default mailer flags by adding the line: +.Pp +.Dl define(`LOCAL_MAILER_FLAGS', `rn9S')dnl +.Pp +to your +.Dq \.mc +file (this is the source file that is used to generate +.Pa /etc/mail/sendmail.cf ) . diff --git a/contrib/libexec/mail.local/mail.local.c b/contrib/libexec/mail.local/mail.local.c new file mode 100644 index 00000000..a574b3fe --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.c @@ -0,0 +1,392 @@ +/* $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> + * Copyright (c) 1996-1998 David Mazieres <dm@lcs.mit.edu> + * Copyright (c) 1990 The Regents of the University of California. + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "includes.h" + +#include <sys/types.h> + +#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> +#include <pwd.h> +#include <time.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include "pathnames.h" +#include "mail.local.h" + +int +main(int argc, char *argv[]) +{ + struct passwd *pw; + 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:")) != -1) + switch (ch) { + case 'd': /* backward compatible */ + break; + case 'f': + case 'r': /* backward compatible */ + if (from) + merr(EX_USAGE, "multiple -f options"); + from = optarg; + break; + case 'l': + lockfile=1; + break; + case 'L': + lockfile=0; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!*argv) + usage(); + + /* + * If from not specified, use the name from getlogin() if the + * uid matches, otherwise, use the name from the password file + * corresponding to the uid. + */ + uid = getuid(); + if (!from && (!(from = getlogin()) || + !(pw = getpwnam(from)) || pw->pw_uid != uid)) + from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; + + fd = storemail(from); + for (eval = 0; *argv; ++argv) { + if ((ch = deliver(fd, *argv, lockfile)) != 0) + eval = ch; + } + exit(eval); +} + +int +storemail(char *from) +{ + FILE *fp = NULL; + time_t tval; + int fd, eline; + size_t len; + char *line, *tbuf; + + if ((tbuf = strdup(_PATH_LOCTMP)) == NULL) + merr(EX_OSERR, "unable to allocate memory"); + if ((fd = mkstemp(tbuf)) == -1 || !(fp = fdopen(fd, "w+"))) + merr(EX_OSERR, "unable to open temporary file"); + (void)unlink(tbuf); + free(tbuf); + + (void)time(&tval); + (void)fprintf(fp, "From %s %s", from, ctime(&tval)); + + for (eline = 1, tbuf = NULL; (line = fgetln(stdin, &len));) { + /* We have to NUL-terminate the line since fgetln does not */ + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + else { + /* No trailing newline, so alloc space and copy */ + if ((tbuf = malloc(len + 1)) == NULL) + merr(EX_OSERR, "unable to allocate memory"); + memcpy(tbuf, line, len); + tbuf[len] = '\0'; + line = tbuf; + } + if (line[0] == '\0') + eline = 1; + else { + if (eline && line[0] == 'F' && len > 5 && + !memcmp(line, "From ", 5)) + (void)putc('>', fp); + eline = 0; + } + (void)fprintf(fp, "%s\n", line); + if (ferror(fp)) + break; + } + free(tbuf); + + /* Output a newline; note, empty messages are allowed. */ + (void)putc('\n', fp); + (void)fflush(fp); + if (ferror(fp)) + merr(EX_OSERR, "temporary file write error"); + return(fd); +} + +int +deliver(int fd, char *name, int lockfile) +{ + struct stat sb, fsb; + struct passwd *pw; + int mbfd=-1, lfd=-1, rval=EX_OSERR; + char biffmsg[100], buf[8*1024], path[PATH_MAX]; + off_t curoff; + size_t off; + ssize_t nr, nw; + + /* + * Disallow delivery to unknown names -- special mailboxes can be + * handled in the sendmail aliases file. + */ + if (!(pw = getpwnam(name))) { + mwarn("unknown name: %s", name); + return(EX_NOUSER); + } + + (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name); + + if (lockfile) { + lfd = lockspool(name, pw); + if (lfd == -1) + return(EX_OSERR); + } + + /* after this point, always exit via bad to remove lockfile */ +retry: + if (lstat(path, &sb)) { + if (errno != ENOENT) { + mwarn("%s: %s", path, strerror(errno)); + goto bad; + } + if ((mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|O_EXLOCK, + S_IRUSR|S_IWUSR)) == -1) { +#ifndef HAVE_O_EXLOCK + /* XXX : do something! */ +#endif + if (errno == EEXIST) { + /* file appeared since lstat */ + goto retry; + } else { + mwarn("%s: %s", path, strerror(errno)); + rval = EX_CANTCREAT; + goto bad; + } + } + /* + * Set the owner and group. Historically, binmail repeated + * this at each mail delivery. We no longer do this, assuming + * that if the ownership or permissions were changed there + * was a reason for doing so. + */ + if (fchown(mbfd, pw->pw_uid, pw->pw_gid) == -1) { + 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)) { + mwarn("%s: linked or special file", path); + goto bad; + } + if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK, + S_IRUSR|S_IWUSR)) == -1) { + mwarn("%s: %s", path, strerror(errno)); + goto bad; + } + if (fstat(mbfd, &fsb) == -1) { + /* relating error to path may be bad style */ + mwarn("%s: %s", path, strerror(errno)); + goto bad; + } + if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) { + mwarn("%s: changed after open", path); + goto bad; + } + /* paranoia? */ + if (fsb.st_nlink != 1 || !S_ISREG(fsb.st_mode)) { + mwarn("%s: linked or special file", path); + rval = EX_CANTCREAT; + goto bad; + } + } + + 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) { + mwarn("temporary file: %s", strerror(errno)); + goto bad; + } + + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (off = 0; off < nr; off += nw) + if ((nw = write(mbfd, buf + off, nr - off)) == -1) { + mwarn("%s: %s", path, strerror(errno)); + (void)ftruncate(mbfd, curoff); + goto bad; + } + + if (nr == 0) { + rval = 0; + } else { + (void)ftruncate(mbfd, curoff); + mwarn("temporary file: %s", strerror(errno)); + } + +bad: + if (lfd != -1) + unlockspool(); + + if (mbfd != -1) { + (void)fsync(mbfd); /* Don't wait for update. */ + (void)close(mbfd); /* Implicit unlock. */ + } + + if (!rval) + notifybiff(biffmsg); + return(rval); +} + +void +notifybiff(char *msg) +{ + static struct addrinfo *res0; + struct addrinfo hints, *res; + static int f = -1; + size_t len; + int error; + + if (res0 == NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + error = getaddrinfo("localhost", "biff", &hints, &res0); + if (error) { + /* Be silent if biff service not available. */ + if (error != EAI_SERVICE) { + mwarn("localhost: %s", gai_strerror(error)); + } + return; + } + } + + if (f == -1) { + for (res = res0; res != NULL; res = res->ai_next) { + f = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (f != -1) + break; + } + } + if (f == -1) { + mwarn("socket: %s", strerror(errno)); + return; + } + + len = strlen(msg) + 1; /* XXX */ + 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(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 new file mode 100644 index 00000000..bc3137cb --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.h @@ -0,0 +1,42 @@ +/* $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. + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +void baditem(char *); +int deliver(int, char *, int); +void merr(int, const char *, ...); +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); diff --git a/contrib/libexec/mail.local/pathnames.h b/contrib/libexec/mail.local/pathnames.h new file mode 100644 index 00000000..0a2c2731 --- /dev/null +++ b/contrib/libexec/mail.local/pathnames.h @@ -0,0 +1,38 @@ +/* $OpenBSD: pathnames.h,v 1.5 2003/06/02 19:38:24 millert Exp $*/ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * from: @(#)pathnames.h 5.3 (Berkeley) 1/17/91 + */ +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#define _PATH_LOCTMP "/tmp/local.XXXXXXXXXX" +#define _PATH_LOCKSPOOL PATH_LIBEXEC"/lockspool" |