diff options
Diffstat (limited to 'libexec/mail.local/mail.local.c')
-rw-r--r-- | libexec/mail.local/mail.local.c | 443 |
1 files changed, 49 insertions, 394 deletions
diff --git a/libexec/mail.local/mail.local.c b/libexec/mail.local/mail.local.c index 1ee4466..cb47bfb 100644 --- a/libexec/mail.local/mail.local.c +++ b/libexec/mail.local/mail.local.c @@ -29,6 +29,8 @@ * 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. + * + * $Id: mail.local.c,v 1.12 1997/02/22 14:21:48 peter Exp $ */ #ifndef lint @@ -38,18 +40,9 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95"; +static char sccsid[] = "@(#)mail.local.c 8.6 (Berkeley) 4/8/94"; #endif /* not lint */ -/* - * This is not intended to compile on System V derived systems - * such as Solaris or HP-UX, since they use a totally different - * approach to mailboxes (essentially, they have a setgid program - * rather than setuid, and they rely on the ability to "give away" - * files to do their work). IT IS NOT A BUG that this doesn't - * compile on such architectures. - */ - #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> @@ -67,7 +60,6 @@ static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95"; #include <syslog.h> #include <time.h> #include <unistd.h> -#include <ctype.h> #if __STDC__ #include <stdarg.h> @@ -75,61 +67,13 @@ static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95"; #include <varargs.h> #endif -#ifndef LOCK_EX -# include <sys/file.h> -#endif - -#ifdef BSD4_4 -# include "pathnames.h" -#endif - -#ifndef __P -# ifdef __STDC__ -# define __P(protos) protos -# else -# define __P(protos) () -# define const -# endif -#endif -#ifndef __dead -# if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__) -# define __dead __volatile -# else -# define __dead -# endif -#endif - -#ifndef BSD4_4 -# define _BSD_VA_LIST_ va_list -extern char *strerror __P((int)); -extern int snprintf __P((char *, int, const char *, ...)); -#endif - -/* - * If you don't have setreuid, and you have saved uids, and you have - * a seteuid() call that doesn't try to emulate using setuid(), then - * you can try defining USE_SETEUID. - */ -#ifdef USE_SETEUID -# define setreuid(r, e) seteuid(e) -#endif - -#ifndef _PATH_LOCTMP -# define _PATH_LOCTMP "/tmp/local.XXXXXX" -#endif -#ifndef _PATH_MAILDIR -# define _PATH_MAILDIR "/var/spool/mail" -#endif - -#ifndef S_ISREG -# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) -#endif +#include "pathnames.h" int eval = EX_OK; /* sysexits.h error value. */ -void deliver __P((int, char *)); +void deliver __P((int, char *, int)); void e_to_sys __P((int)); -__dead void err __P((const char *, ...)); +void err __P((const char *, ...)) __dead2; void notifybiff __P((char *)); int store __P((char *)); void usage __P((void)); @@ -142,28 +86,19 @@ main(argc, argv) char *argv[]; { struct passwd *pw; - int ch, fd; + int ch, fd, nobiff; uid_t uid; char *from; - extern char *optarg; - extern int optind; - - /* make sure we have some open file descriptors */ - for (fd = 10; fd < 30; fd++) - (void) close(fd); - - /* use a reasonable umask */ - (void) umask(0077); -#ifdef LOG_MAIL openlog("mail.local", 0, LOG_MAIL); -#else - openlog("mail.local", 0); -#endif from = NULL; - while ((ch = getopt(argc, argv, "df:r:")) != EOF) + nobiff = 0; + while ((ch = getopt(argc, argv, "bdf:r:")) != -1) switch(ch) { + case 'b': + nobiff++; + break; case 'd': /* Backward compatible. */ break; case 'f': @@ -204,7 +139,7 @@ main(argc, argv) * at the expense of repeated failures and multiple deliveries. */ for (fd = store(from); *argv; ++argv) - deliver(fd, *argv); + deliver(fd, *argv, nobiff); exit(eval); } @@ -215,15 +150,15 @@ store(from) FILE *fp; time_t tval; int fd, eline; - char line[2048]; - char tmpbuf[sizeof _PATH_LOCTMP + 1]; + char *tn, line[2048]; - strcpy(tmpbuf, _PATH_LOCTMP); - if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) { + tn = strdup(_PATH_LOCTMP); + if ((fd = mkstemp(tn)) == -1 || (fp = fdopen(fd, "w+")) == NULL) { e_to_sys(errno); err("unable to open temporary file"); } - (void)unlink(tmpbuf); + (void)unlink(tn); + free(tn); (void)time(&tval); (void)fprintf(fp, "From %s %s", from, ctime(&tval)); @@ -259,14 +194,13 @@ store(from) } void -deliver(fd, name) - int fd; +deliver(fd, name, nobiff) + int fd, nobiff; char *name; { struct stat fsb, sb; struct passwd *pw; int mbfd, nr, nw, off; - char *p; char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; off_t curoff; @@ -280,25 +214,6 @@ deliver(fd, name) warn("unknown name: %s", name); return; } - endpwent(); - - /* - * Keep name reasonably short to avoid buffer overruns. - * This isn't necessary on BSD because of the proper - * definition of snprintf(), but it can cause problems - * on other systems. - * Also, clear out any bogus characters. - */ - - if (strlen(name) > 40) - name[40] = '\0'; - for (p = name; *p != '\0'; p++) - { - if (!isascii(*p)) - *p &= 0x7f; - else if (!isprint(*p)) - *p = '.'; - } (void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name); @@ -324,7 +239,6 @@ deliver(fd, name) * open(2) should support flock'ing the file. */ tryagain: - lockmbox(path); if (lstat(path, &sb)) { mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); @@ -334,31 +248,28 @@ tryagain: } else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) { e_to_sys(errno); warn("chown %u.%u: %s", pw->pw_uid, pw->pw_gid, name); - goto err1; + return; } - } else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) { + } else if (sb.st_nlink != 1 || S_ISLNK(sb.st_mode)) { e_to_sys(errno); - warn("%s: irregular file", path); - goto err0; - } else if (sb.st_uid != pw->pw_uid) { - warn("%s: wrong ownership (%d)", path, sb.st_uid); - unlockmbox(); + warn("%s: linked file", path); return; } else { mbfd = open(path, O_APPEND|O_WRONLY, 0); if (mbfd != -1 && (fstat(mbfd, &fsb) || fsb.st_nlink != 1 || - !S_ISREG(fsb.st_mode) || sb.st_dev != fsb.st_dev || - sb.st_ino != fsb.st_ino || sb.st_uid != fsb.st_uid)) { + S_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev || + sb.st_ino != fsb.st_ino)) { warn("%s: file changed after open", path); - goto err1; + (void)close(mbfd); + return; } } if (mbfd == -1) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); - goto err0; + return; } /* Wait until we can get a lock on the file. */ @@ -368,11 +279,12 @@ tryagain: goto err1; } - /* Get the starting offset of the new message for biff. */ - curoff = lseek(mbfd, (off_t)0, SEEK_END); - (void)snprintf(biffmsg, sizeof(biffmsg), - sizeof curoff > sizeof(long) ? "%s@%qd\n" : "%s@%ld\n", - name, curoff); + if (!nobiff) { + /* Get the starting offset of the new message for biff. */ + curoff = lseek(mbfd, (off_t)0, SEEK_END); + (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%qd\n", + name, curoff); + } /* Copy the message into the file. */ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { @@ -380,113 +292,39 @@ tryagain: warn("temporary file: %s", strerror(errno)); goto err1; } - if (setreuid(0, pw->pw_uid) < 0) { - e_to_sys(errno); - warn("setreuid(0, %d): %s (r=%d, e=%d)", - pw->pw_uid, strerror(errno), getuid(), geteuid()); - goto err1; - } -#ifdef DEBUG - printf("new euid = %d\n", geteuid()); -#endif while ((nr = read(fd, buf, sizeof(buf))) > 0) - for (off = 0; off < nr; off += nw) - if ((nw = write(mbfd, buf + off, nr - off)) < 0) { + for (off = 0; off < nr; nr -= nw, off += nw) + if ((nw = write(mbfd, buf + off, nr)) < 0) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); - goto err3; + goto err2; } if (nr < 0) { e_to_sys(errno); warn("temporary file: %s", strerror(errno)); - goto err3; +err2: (void)ftruncate(mbfd, curoff); +err1: (void)close(mbfd); + return; } +#ifndef DONT_FSYNC /* Flush to disk, don't wait for update. */ if (fsync(mbfd)) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); -err3: - if (setreuid(0, 0) < 0) { - e_to_sys(errno); - warn("setreuid(0, 0): %s", strerror(errno)); - } -#ifdef DEBUG - printf("reset euid = %d\n", geteuid()); -#endif -err2: (void)ftruncate(mbfd, curoff); -err1: (void)close(mbfd); -err0: unlockmbox(); - return; + goto err2; } - +#endif + /* Close and check -- NFS doesn't write until the close. */ if (close(mbfd)) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); - unlockmbox(); return; } - if (setreuid(0, 0) < 0) { - e_to_sys(errno); - warn("setreuid(0, 0): %s", strerror(errno)); - } -#ifdef DEBUG - printf("reset euid = %d\n", geteuid()); -#endif - unlockmbox(); - notifybiff(biffmsg); -} - -/* - * user.lock files are necessary for compatibility with other - * systems, e.g., when the mail spool file is NFS exported. - * Alas, mailbox locking is more than just a local matter. - * EPA 11/94. - */ - -char lockname[MAXPATHLEN]; -int locked = 0; - -lockmbox(path) - char *path; -{ - int statfailed = 0; - - if (locked) - return; - sprintf(lockname, "%s.lock", path); - for (;; sleep(5)) { - int fd; - struct stat st; - time_t now; - - fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0); - if (fd >= 0) { - locked = 1; - close(fd); - return; - } - if (stat(lockname, &st) < 0) { - if (statfailed++ > 5) - return; - continue; - } - statfailed = 0; - time(&now); - if (now < st.st_ctime + 300) - continue; - unlink(lockname); - } -} - -unlockmbox() -{ - if (!locked) - return; - unlink(lockname); - locked = 0; + if (!nobiff) + notifybiff(biffmsg); } void @@ -508,7 +346,7 @@ notifybiff(msg) return; } addr.sin_family = hp->h_addrtype; - memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); + memmove(&addr.sin_addr, hp->h_addr, hp->h_length); addr.sin_port = sp->s_port; } if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { @@ -525,7 +363,7 @@ void usage() { eval = EX_USAGE; - err("usage: mail.local [-f from] user ..."); + err("usage: mail.local [-b] [-f from] user ..."); } #if __STDC__ @@ -587,17 +425,8 @@ vwarn(fmt, ap) (void)vfprintf(stderr, fmt, ap); (void)fprintf(stderr, "\n"); -#if !defined(ultrix) && !defined(__osf__) /* Log the message to syslog. */ vsyslog(LOG_ERR, fmt, ap); -#else - { - char fmtbuf[10240]; - - (void) sprintf(fmtbuf, fmt, ap); - syslog(LOG_ERR, "%s", fmtbuf); - } -#endif } /* @@ -682,7 +511,7 @@ e_to_sys(num) #ifdef ETIMEDOUT case ETIMEDOUT: /* Connection timed out */ #endif -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: /* Operation would block. */ #endif eval = EX_TEMPFAIL; @@ -692,177 +521,3 @@ e_to_sys(num) break; } } - -#ifndef BSD4_4 - -# ifndef __osf__ -char * -strerror(eno) - int eno; -{ - extern int sys_nerr; - extern char *sys_errlist[]; - static char ebuf[60]; - - if (eno >= 0 && eno <= sys_nerr) - return sys_errlist[eno]; - (void) sprintf(ebuf, "Error %d", eno); - return ebuf; -} -# endif - -# if __STDC__ -snprintf(char *buf, int bufsiz, const char *fmt, ...) -# else -snprintf(buf, bufsiz, fmt, va_alist) - char *buf; - int bufsiz; - const char *fmt; - va_dcl -# endif -{ - va_list ap; - -# if __STDC__ - va_start(ap, fmt); -# else - va_start(ap); -# endif - vsprintf(buf, fmt, ap); - va_end(ap); -} - -#endif - -#ifdef ultrix - -/* - * Copyright (c) 1987, 1993 - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. 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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <ctype.h> - -static int _gettemp(); - -mkstemp(path) - char *path; -{ - int fd; - - return (_gettemp(path, &fd) ? fd : -1); -} - -/* -char * -mktemp(path) - char *path; -{ - return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); -} -*/ - -static -_gettemp(path, doopen) - char *path; - register int *doopen; -{ - extern int errno; - register char *start, *trv; - struct stat sbuf; - u_int pid; - - pid = getpid(); - for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ - while (*--trv == 'X') { - *trv = (pid % 10) + '0'; - pid /= 10; - } - - /* - * check the target directory; if you have six X's and it - * doesn't exist this runs for a *very* long time. - */ - for (start = trv + 1;; --trv) { - if (trv <= path) - break; - if (*trv == '/') { - *trv = '\0'; - if (stat(path, &sbuf)) - return(0); - if (!S_ISDIR(sbuf.st_mode)) { - errno = ENOTDIR; - return(0); - } - *trv = '/'; - break; - } - } - - for (;;) { - if (doopen) { - if ((*doopen = - open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) - return(1); - if (errno != EEXIST) - return(0); - } - else if (stat(path, &sbuf)) - return(errno == ENOENT ? 1 : 0); - - /* tricky little algorithm for backward compatibility */ - for (trv = start;;) { - if (!*trv) - return(0); - if (*trv == 'z') - *trv++ = 'a'; - else { - if (isdigit(*trv)) - *trv = 'a'; - else - ++*trv; - break; - } - } - } - /*NOTREACHED*/ -} - -#endif |