diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/mail.local/mail.local.8 | 11 | ||||
-rw-r--r-- | libexec/mail.local/mail.local.c | 224 |
2 files changed, 159 insertions, 76 deletions
diff --git a/libexec/mail.local/mail.local.8 b/libexec/mail.local/mail.local.8 index ddbf6db30fe..6b0903164cc 100644 --- a/libexec/mail.local/mail.local.8 +++ b/libexec/mail.local/mail.local.8 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)mail.local.8 6.8 (Berkeley) 4/27/91 -.\" $Id: mail.local.8,v 1.4 1996/08/29 04:24:33 deraadt Exp $ +.\" $Id: mail.local.8,v 1.5 1996/08/29 07:21:57 deraadt Exp $ .\" .Dd April 27, 1991 .Dt MAIL.LOCAL 8 @@ -43,6 +43,7 @@ .Op Fl L .Op Fl l .Op Fl f Ar from +.Op Fl H .Ar user ... .Sh DESCRIPTION .Nm Mail.local @@ -67,6 +68,14 @@ Request that .Fn flock be used for locking the mail spool rather than .Nm username.lock . +.It Fl H +This mode is useful for a client mail program to attain proper locking. +In this mode +.Nm mail.local +(ignoring all other arguments) attains a +.Nm username.lock +for the calling user and retains it until stdin is closed or a +SIGINT signal is received. .El .Pp Individual mail messages in the mailbox are delimited by an empty diff --git a/libexec/mail.local/mail.local.c b/libexec/mail.local/mail.local.c index 6b3e9bd85f4..cc7e39db292 100644 --- a/libexec/mail.local/mail.local.c +++ b/libexec/mail.local/mail.local.c @@ -39,13 +39,14 @@ char copyright[] = #ifndef lint /*static char sccsid[] = "from: @(#)mail.local.c 5.6 (Berkeley) 6/19/91";*/ -static char rcsid[] = "$Id: mail.local.c,v 1.5 1996/08/29 04:19:34 deraadt Exp $"; +static char rcsid[] = "$Id: mail.local.c,v 1.6 1996/08/29 07:21:58 deraadt Exp $"; #endif /* not lint */ #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> +#include <sys/signal.h> #include <syslog.h> #include <fcntl.h> #include <netdb.h> @@ -66,6 +67,9 @@ void err __P((int, const char *, ...)); void notifybiff __P((char *)); int store __P((char *)); void usage __P((void)); +int dohold __P((void)); +int getlock __P((char *, struct passwd *)); +void rellock __P((void)); int main(argc, argv) @@ -75,7 +79,7 @@ main(argc, argv) extern int optind; extern char *optarg; struct passwd *pw; - int ch, fd, eval, lockfile=1; + int ch, fd, eval, lockfile=1, holdme=0; uid_t uid; char *from; @@ -98,6 +102,9 @@ main(argc, argv) case 'L': lockfile=0; break; + case 'H': + holdme=1; + break; case '?': default: usage(); @@ -108,6 +115,9 @@ main(argc, argv) if (!*argv) usage(); + if (holdme) + exit(dohold()); + /* * If from not specified, use the name from getlogin() if the * uid matches, otherwise, use the name from the password file @@ -124,6 +134,47 @@ main(argc, argv) exit(eval); } +void +unhold() +{ + rellock(); + exit(0); +} + +int +dohold() +{ + struct passwd *pw; + char *from, c; + int holdfd; + + signal(SIGTERM, unhold); + signal(SIGINT, unhold); + signal(SIGHUP, unhold); + + from = getlogin(); + if (from) { + pw = getpwnam(from); + if (pw == NULL) + return (1); + } else { + pw = getpwuid(getuid()); + if (pw) + from = pw->pw_name; + else + return (1); + } + + holdfd = getlock(from, pw); + if (holdfd == -1) + return (1); + + while (read(0, &c, 1) == -1 && errno == EINTR) + ; + rellock(); + return (0); +} + int store(from) char *from; @@ -184,6 +235,97 @@ baditem(path) path, npath); } +char lpath[MAXPATHLEN]; + +void +rellock() +{ + if (lpath[0]) + unlink(lpath); +} + +int +getlock(name, pw) + 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 & 7) == 7) { + /* + * 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) { + if (lstat(lpath, &sb) != -1 && + S_ISLNK(fsb.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) { + err(NOTFATAL, "%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); + } + } + } + sleep(1 << tries); + tries++; + continue; + } + seteuid(0); + } else { + /* + * Only root can write the spool directory. + */ + if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL, + S_IRUSR|S_IWUSR)) < 0) { + err(NOTFATAL, "%s: %s", lpath, strerror(errno)); + return(-1); + } + } + return (lfd); +} + + + int deliver(fd, name, lockfile) int fd; @@ -193,7 +335,7 @@ deliver(fd, name, lockfile) struct stat sb, fsb; struct passwd *pw; int mbfd=-1, nr, nw, off, rval=1, lfd=-1; - char biffmsg[100], buf[8*1024], path[MAXPATHLEN], lpath[MAXPATHLEN]; + char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; off_t curoff; /* @@ -208,77 +350,9 @@ deliver(fd, name, lockfile) (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name); if (lockfile) { - int tries = 0; - - (void)snprintf(lpath, sizeof lpath, "%s/%s.lock", - _PATH_MAILDIR, name); - - if (stat(_PATH_MAILDIR, &sb) != -1 && - (sb.st_mode & 7) == 7) { - /* - * 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) { - if (lstat(lpath, &sb) != -1 && - S_ISLNK(fsb.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) { - err(NOTFATAL, "%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); - } - } - } - sleep(1 << tries); - tries++; - continue; - } - seteuid(0); - } else { - /* - * Only root can write the spool directory. - */ - if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL, - S_IRUSR|S_IWUSR)) < 0) { - err(NOTFATAL, "%s: %s", lpath, strerror(errno)); - return(1); - } - } + lfd = getlock(name, pw); + if (lfd == -1) + return (1); } /* after this point, always exit via bad to remove lockfile */ @@ -359,7 +433,7 @@ retry: bad: if (lfd != -1) { - unlink(lpath); + rellock(); close(lfd); } |