diff options
author | peter <peter@FreeBSD.org> | 1997-06-27 15:17:19 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1997-06-27 15:17:19 +0000 |
commit | ffc2d3d70315c587069f7268c77ccacce772a7e4 (patch) | |
tree | 8cbd2d8ef7f7d2877b971c8365f2641d3c6564ad /usr.sbin/sendmail | |
parent | 30e296b7618348906cd1a4d7dddfe581ded43a2a (diff) | |
download | FreeBSD-src-ffc2d3d70315c587069f7268c77ccacce772a7e4.zip FreeBSD-src-ffc2d3d70315c587069f7268c77ccacce772a7e4.tar.gz |
Merge in sendmail-8.8.5 -> 8.8.6 changes to those files that have left the
vendor branch.
Diffstat (limited to 'usr.sbin/sendmail')
25 files changed, 2151 insertions, 1416 deletions
diff --git a/usr.sbin/sendmail/mail.local/mail.local.c b/usr.sbin/sendmail/mail.local/mail.local.c index a61cde5..d854e78 100644 --- a/usr.sbin/sendmail/mail.local/mail.local.c +++ b/usr.sbin/sendmail/mail.local/mail.local.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mail.local.c,v 1.7 1997/02/22 16:13:23 peter Exp $ + * $Id: mail.local.c,v 1.8 1997/03/31 05:11:16 imp Exp $ */ #ifndef lint @@ -40,7 +40,7 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mail.local.c 8.34 (Berkeley) 11/24/96"; +static char sccsid[] = "@(#)mail.local.c 8.39 (Berkeley) 5/28/97"; #endif /* not lint */ /* @@ -88,6 +88,7 @@ static char sccsid[] = "@(#)mail.local.c 8.34 (Berkeley) 11/24/96"; #if defined(_AIX) # define USE_LOCKF 1 +# define USET_SETEUID 1 # define USE_VSYSLOG 0 #endif @@ -148,9 +149,17 @@ static char sccsid[] = "@(#)mail.local.c 8.34 (Berkeley) 11/24/96"; # define _BSD_VA_LIST_ va_list #endif +#if defined(BSD4_4) || defined(linux) +# define HASSNPRINTF 1 +#endif + +#if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) +# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ +#endif + #if !defined(BSD4_4) && !defined(linux) extern char *strerror __P((int)); -extern int snprintf __P((char *, int, const char *, ...)); +extern int snprintf __P((char *, size_t, const char *, ...)); extern FILE *fdopen __P((int, const char *)); #endif @@ -384,9 +393,13 @@ deliver(fd, name, nobiff, nofsync) */ tryagain: lockmbox(path); - if (lstat(path, &sb)) { + if (lstat(path, &sb) < 0) { mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); + if (lstat(path, &sb) < 0) + goto filechanged; + else + sb.st_uid = pw->pw_uid; if (mbfd == -1) { if (errno == EEXIST) goto tryagain; @@ -405,20 +418,20 @@ tryagain: goto err0; } 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)) { - eval = EX_CANTCREAT; - warn("%s: file changed after open", path); - goto err1; - } } if (mbfd == -1) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); goto err0; + } else if (fstat(mbfd, &fsb) < 0 || + fsb.st_nlink != 1 || sb.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) { +filechanged: + eval = EX_CANTCREAT; + warn("%s: file changed after open", path); + goto err1; } /* Wait until we can get a lock on the file. */ @@ -486,9 +499,9 @@ err0: unlockmbox(); if (close(mbfd)) { e_to_sys(errno); warn("%s: %s", path, strerror(errno)); - unlockmbox(); - return; - } + truncate(path, curoff); + } else if (!nobiff) + notifybiff(biffmsg); if (setreuid(0, 0) < 0) { e_to_sys(errno); @@ -498,8 +511,6 @@ err0: unlockmbox(); printf("reset euid = %d\n", geteuid()); #endif unlockmbox(); - if (!nobiff) - notifybiff(biffmsg); } /* @@ -520,6 +531,8 @@ lockmbox(path) if (locked) return; + if (strlen(path) + 6 > sizeof lockname) + return; sprintf(lockname, "%s.lock", path); for (;; sleep(5)) { int fd; @@ -774,16 +787,16 @@ strerror(eno) return ebuf; } -# endif +#endif /* !defined(BSD4_4) && !defined(__osf__) */ -#if !defined(BSD4_4) && !defined(linux) +#if !HASSNPRINTF # if __STDC__ -snprintf(char *buf, int bufsiz, const char *fmt, ...) +snprintf(char *buf, size_t bufsiz, const char *fmt, ...) # else snprintf(buf, bufsiz, fmt, va_alist) char *buf; - int bufsiz; + size_t bufsiz; const char *fmt; va_dcl # endif @@ -799,7 +812,7 @@ snprintf(buf, bufsiz, fmt, va_alist) va_end(ap); } -#endif +#endif /* !HASSNPRINTF */ #ifdef ultrix @@ -892,7 +905,7 @@ _gettemp(path, doopen) break; if (*trv == '/') { *trv = '\0'; - if (stat(path, &sbuf)) + if (stat(path, &sbuf) < 0) return(0); if (!S_ISDIR(sbuf.st_mode)) { errno = ENOTDIR; @@ -911,7 +924,7 @@ _gettemp(path, doopen) if (errno != EEXIST) return(0); } - else if (stat(path, &sbuf)) + else if (stat(path, &sbuf) < 0) return(errno == ENOENT ? 1 : 0); /* tricky little algorithm for backward compatibility */ @@ -932,4 +945,4 @@ _gettemp(path, doopen) /*NOTREACHED*/ } -#endif +#endif /* ultrix */ diff --git a/usr.sbin/sendmail/mailstats/mailstats.c b/usr.sbin/sendmail/mailstats/mailstats.c index 3833da3..625b44c 100644 --- a/usr.sbin/sendmail/mailstats/mailstats.c +++ b/usr.sbin/sendmail/mailstats/mailstats.c @@ -40,7 +40,7 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mailstats.c 8.8 (Berkeley) 9/25/96"; +static char sccsid[] = "@(#)mailstats.c 8.10 (Berkeley) 5/30/97"; #endif /* not lint */ #define NOT_SENDMAIL @@ -66,7 +66,7 @@ main(argc, argv) bool mnames; long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0; char mtable[MAXMAILERS][MNAMELEN+1]; - char sfilebuf[100]; + char sfilebuf[MAXLINE]; char buf[MAXLINE]; extern char *ctime(); @@ -145,6 +145,13 @@ main(argc, argv) } /* this is the S or StatusFile option -- save it */ + if (strlen(b) >= sizeof sfilebuf) + { + fprintf(stderr, + "StatusFile filename too long: %.30s...\n", + s); + exit(EX_CONFIG); + } strcpy(sfilebuf, b); b = strchr(sfilebuf, '#'); if (b == NULL) diff --git a/usr.sbin/sendmail/makemap/Makefile b/usr.sbin/sendmail/makemap/Makefile index 1cc9b59..db59c4f 100644 --- a/usr.sbin/sendmail/makemap/Makefile +++ b/usr.sbin/sendmail/makemap/Makefile @@ -1,8 +1,13 @@ -# @(#)Makefile 8.1 (Berkeley) 6/7/93 +# @(#)Makefile 8.4 (Berkeley) 6/10/97 PROG= makemap MAN8= makemap.8 -CFLAGS+=-I${.CURDIR}/../src -DNEWDB +CFLAGS+=-I${.CURDIR}/../src -DNEWDB -DNOT_SENDMAIL + +SRCS= makemap.c safefile.c + +safefile.c: ${.CURDIR}/../src/safefile.c + ln -s ${.CURDIR}/../src/safefile.c .include "../../Makefile.inc" .include <bsd.prog.mk> diff --git a/usr.sbin/sendmail/makemap/makemap.c b/usr.sbin/sendmail/makemap/makemap.c index a1e73c4..7ef4612 100644 --- a/usr.sbin/sendmail/makemap/makemap.c +++ b/usr.sbin/sendmail/makemap/makemap.c @@ -33,21 +33,15 @@ */ #ifndef lint -static char sccsid[] = "@(#)makemap.c 8.19 (Berkeley) 11/18/96"; +static char sccsid[] = "@(#)makemap.c 8.35 (Berkeley) 6/10/97"; #endif /* not lint */ -#include <stdio.h> -#include <sysexits.h> #include <sys/types.h> -#include <ctype.h> -#include <string.h> #include <sys/errno.h> #ifndef ISC_UNIX # include <sys/file.h> #endif -#define NOT_SENDMAIL -#include "useful.h" -#include "conf.h" +#include "sendmail.h" #ifdef NDBM #include <ndbm.h> @@ -74,6 +68,17 @@ union dbent } xx; }; +uid_t RealUid; +gid_t RealGid; +char *RealUserName; +uid_t RunAsUid; +uid_t RunAsGid; +char *RunAsUserName; +int Verbose = 2; +bool DontInitGroups = TRUE; +bool UnsafeGroupWrites = FALSE; +u_char tTdvect[100]; + #define BUFSIZE 1024 main(argc, argv) @@ -87,12 +92,12 @@ main(argc, argv) bool allowdups = FALSE; bool verbose = FALSE; bool foldcase = TRUE; + bool ignoresafeties = FALSE; int exitstat; int opt; char *typename; char *mapname; char *ext; - char *lext; int lineno; int st; int mode; @@ -117,15 +122,33 @@ main(argc, argv) #endif char ibuf[BUFSIZE]; char fbuf[MAXNAME]; - char lbuf[MAXNAME]; + char dbuf[MAXNAME]; + char pbuf[MAXNAME]; + static char rnamebuf[MAXNAME]; /* holds RealUserName */ + struct passwd *pw; + int sff = SFF_ROOTOK|SFF_REGONLY|SFF_NOLINK|SFF_NOWLINK; + struct stat std, stp; extern char *optarg; extern int optind; extern bool lockfile(); progname = argv[0]; -#ifdef FFR_CFLAG -#define OPTIONS "Nc:dforv" + RunAsUid = RealUid = getuid(); + RunAsGid = RealGid = getgid(); + pw = getpwuid(RealUid); + if (pw != NULL) + { + if (strlen(pw->pw_name) > MAXNAME - 1) + pw->pw_name[MAXNAME] = 0; + sprintf(rnamebuf, "%s", pw->pw_name); + } + else + sprintf(rnamebuf, "Unknown UID %d", RealUid); + RunAsUserName = RealUserName = rnamebuf; + +#if _FFR_NEW_MAKEMAP_FLAGS +#define OPTIONS "Nc:dforsv" #else #define OPTIONS "Ndforv" #endif @@ -137,7 +160,7 @@ main(argc, argv) inclnull = TRUE; break; -#ifdef FFR_CFLAG +#if _FFR_NEW_MAKEMAP_FLAGS case 'c': dbcachesize = atol(optarg); break; @@ -159,6 +182,12 @@ main(argc, argv) allowreplace = TRUE; break; +#if _FFR_NEW_MAKEMAP_FLAGS + case 's': + ignoresafeties = TRUE; + break; +#endif + case 'v': verbose = TRUE; break; @@ -178,12 +207,10 @@ main(argc, argv) typename = argv[0]; mapname = argv[1]; ext = NULL; - lext = NULL; if (strcmp(typename, "dbm") == 0) { type = T_DBM; - lext = ".dir"; } else if (strcmp(typename, "btree") == 0) { @@ -202,8 +229,10 @@ main(argc, argv) switch (type) { case T_ERR: -#ifdef FFR_CFLAG - fprintf(stderr, "Usage: %s [-N] [-c cachesize] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); +#if _FFR_NEW_MAKEMAP_FLAGS + fprintf(stderr, + "Usage: %s [-N] [-c cachesize] [-d] [-f] [-o] [-r] [-s] [-v] type mapname\n", + progname); #else fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); #endif @@ -270,6 +299,11 @@ main(argc, argv) el = strlen(ext); fl = strlen(mapname); + if (el + fl + 1 >= sizeof fbuf) + { + fprintf(stderr, "%s: file name too long", mapname); + exit(EX_USAGE); + } if (fl < el || strcmp(&mapname[fl - el], ext) != 0) { strcpy(fbuf, mapname); @@ -278,9 +312,68 @@ main(argc, argv) } } - strcpy(lbuf, mapname); - if (lext != NULL) - strcat(lbuf, lext); + if (!notrunc) + sff |= SFF_CREAT; + switch (type) + { +#ifdef NEWDB + case T_BTREE: + case T_HASH: + if (strlen(mapname) >= sizeof dbuf) + { + fprintf(stderr, + "%s: map name too long\n", mapname); + exit(EX_USAGE); + } + strcpy(dbuf, mapname); + if (!ignoresafeties && + (st = safefile(dbuf, RealUid, RealGid, RealUserName, + sff, S_IWUSR, &std)) != 0) + { + fprintf(stderr, + "%s: could not create: %s\n", + dbuf, errstring(st)); + exit(EX_CANTCREAT); + } + break; +#endif +#ifdef NDBM + case T_DBM: + if (strlen(mapname) + 5 > sizeof dbuf) + { + fprintf(stderr, + "%s: map name too long\n", mapname); + exit(EX_USAGE); + } + sprintf(dbuf, "%s.dir", mapname); + if (!ignoresafeties && + (st = safefile(dbuf, RealUid, RealGid, RealUserName, + sff, S_IWUSR, &std)) != 0) + { + fprintf(stderr, + "%s: could not create: %s\n", + dbuf, errstring(st)); + exit(EX_CANTCREAT); + } + sprintf(pbuf, "%s.pag", mapname); + if (!ignoresafeties && + (st = safefile(pbuf, RealUid, RealGid, RealUserName, + sff, S_IWUSR, &stp)) != 0) + { + fprintf(stderr, + "%s: could not create: %s\n", + pbuf, errstring(st)); + exit(EX_CANTCREAT); + } + break; +#endif + default: + fprintf(stderr, + "%s: internal error: type %d\n", + progname, + type); + exit(EX_SOFTWARE); + } /* ** Create the database. @@ -289,24 +382,36 @@ main(argc, argv) mode = O_RDWR; if (!notrunc) mode |= O_CREAT|O_TRUNC; -#ifdef O_EXLOCK +#if O_EXLOCK mode |= O_EXLOCK; #else /* pre-lock the database */ - fd = open(lbuf, mode & ~O_TRUNC, 0644); + if (ignoresafeties) + fd = dfopen(dbuf, mode & ~O_TRUNC, 0644, sff); + else + fd = safeopen(dbuf, mode & ~O_TRUNC, 0644, sff); if (fd < 0) { fprintf(stderr, "%s: cannot create type %s map %s\n", progname, typename, mapname); exit(EX_CANTCREAT); } - (void) lockfile(fd); #endif switch (type) { #ifdef NDBM case T_DBM: dbp.dbm = dbm_open(mapname, mode, 0644); + if (!ignoresafeties && dbp.dbm != NULL && + (filechanged(dbuf, dbm_dirfno(dbp.dbm), &std, sff) || + filechanged(pbuf, dbm_pagfno(dbp.dbm), &stp, sff))) + { + fprintf(stderr, + "dbm map %s: file changed after open\n", + mapname); + dbm_close(dbp.dbm); + exit(EX_CANTCREAT); + } break; #endif @@ -315,10 +420,19 @@ main(argc, argv) /* tweak some parameters for performance */ hinfo.nelem = 4096; hinfo.cachesize = dbcachesize; - + dbp.db = dbopen(mapname, mode, 0644, DB_HASH, &hinfo); if (dbp.db != NULL) { + if (!ignoresafeties && + filechanged(dbuf, dbp.db->fd(dbp.db), &std, sff)) + { + fprintf(stderr, + "db map %s: file changed after open\n", + mapname); + dbp.db->close(dbp.db); + exit(EX_CANTCREAT); + } # if OLD_NEWDB (void) (*dbp.db->sync)(dbp.db); # else @@ -334,6 +448,15 @@ main(argc, argv) dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); if (dbp.db != NULL) { + if (!ignoresafeties && + filechanged(dbuf, dbp.db->fd(dbp.db), &std, sff)) + { + fprintf(stderr, + "db map %s: file changed after open\n", + mapname); + dbp.db->close(dbp.db); + exit(EX_CANTCREAT); + } # if OLD_NEWDB (void) (*dbp.db->sync)(dbp.db); # else @@ -344,7 +467,8 @@ main(argc, argv) #endif default: - fprintf(stderr, "%s: internal error: type %d\n", progname, type); + fprintf(stderr, "%s: internal error: type %d\n", + progname, type); exit(EX_SOFTWARE); } @@ -447,7 +571,8 @@ main(argc, argv) } else if (st > 0) { - fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", + fprintf(stderr, + "%s: %s: line %d: key %s: duplicate key\n", progname, mapname, lineno, key.xx.data); } } @@ -477,7 +602,7 @@ main(argc, argv) #endif } -#ifndef O_EXLOCK +#if !O_EXLOCK /* release locks */ close(fd); #endif @@ -489,6 +614,11 @@ main(argc, argv) ** ** Parameters: ** fd -- the file descriptor of the file. +** filename -- the file name (for error messages). +** ext -- the filename extension. +** type -- type of the lock. Bits can be: +** LOCK_EX -- exclusive lock. +** LOCK_NB -- non-blocking. ** ** Returns: ** TRUE if the lock was acquired. @@ -496,8 +626,11 @@ main(argc, argv) */ bool -lockfile(fd) +lockfile(fd, filename, ext, type) int fd; + char *filename; + char *ext; + int type; { # if !HASFLOCK int action; @@ -505,8 +638,16 @@ lockfile(fd) extern int errno; bzero(&lfd, sizeof lfd); - lfd.l_type = F_WRLCK; - action = F_SETLKW; + if (bitset(LOCK_UN, type)) + lfd.l_type = F_UNLCK; + else if (bitset(LOCK_EX, type)) + lfd.l_type = F_WRLCK; + else + lfd.l_type = F_RDLCK; + if (bitset(LOCK_NB, type)) + action = F_SETLK; + else + action = F_SETLKW; if (fcntl(fd, action, &lfd) >= 0) return TRUE; @@ -525,10 +666,110 @@ lockfile(fd) # else /* HASFLOCK */ - if (flock(fd, LOCK_EX) >= 0) + if (flock(fd, type) >= 0) return TRUE; # endif return FALSE; } + +/*VARARGS2*/ +void +#ifdef __STDC__ +message(const char *msg, ...) +#else +message(msg, va_alist) + const char *msg; + va_dcl +#endif +{ + const char *m; + VA_LOCAL_DECL + + m = msg; + if (isdigit(m[0]) && isdigit(m[1]) && isdigit(m[2]) && m[3] == ' ') + m += 4; + VA_START(msg); + vfprintf(stderr, m, ap); + VA_END; + fprintf(stderr, "\n"); +} + +/*VARARGS2*/ +void +#ifdef __STDC__ +syserr(const char *msg, ...) +#else +syserr(msg, va_alist) + const char *msg; + va_dcl +#endif +{ + const char *m; + VA_LOCAL_DECL + + m = msg; + if (isdigit(m[0]) && isdigit(m[1]) && isdigit(m[2]) && m[3] == ' ') + m += 4; + VA_START(msg); + vfprintf(stderr, m, ap); + VA_END; + fprintf(stderr, "\n"); +} + +const char * +errstring(err) + int err; +{ + static char errstr[64]; +#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) + extern char *sys_errlist[]; + extern int sys_nerr; +#endif + + /* handle pseudo-errors internal to sendmail */ + switch (err) + { + case E_SM_OPENTIMEOUT: + return "Timeout on file open"; + + case E_SM_NOSLINK: + return "Symbolic links not allowed"; + + case E_SM_NOHLINK: + return "Hard links not allowed"; + + case E_SM_REGONLY: + return "Regular files only"; + + case E_SM_ISEXEC: + return "Executable files not allowed"; + + case E_SM_WWDIR: + return "World writable directory"; + + case E_SM_GWDIR: + return "Group writable directory"; + + case E_SM_FILECHANGE: + return "File changed after open"; + + case E_SM_WWFILE: + return "World writable file"; + + case E_SM_GWFILE: + return "Group writable file"; + } + +#if HASSTRERROR + return strerror(err); +#else + if (err < 0 || err > sys_nerr) + { + sprintf(errstr, "Error %d", err); + return errstr; + } + return sys_errlist[err]; +#endif +} diff --git a/usr.sbin/sendmail/praliases/praliases.c b/usr.sbin/sendmail/praliases/praliases.c index 1177164..e0cae65 100644 --- a/usr.sbin/sendmail/praliases/praliases.c +++ b/usr.sbin/sendmail/praliases/praliases.c @@ -39,7 +39,7 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)praliases.c 8.4 (Berkeley) 9/25/96"; +static char sccsid[] = "@(#)praliases.c 8.5 (Berkeley) 5/28/97"; #endif /* not lint */ #include <ndbm.h> @@ -83,6 +83,11 @@ main(argc, argv) argv += optind; #ifdef NEWDB + if (strlen(filename) + 4 >= sizeof buf) + { + fprintf(stderr, "Alias filename too long: %.30s...\n", filename); + exit(EX_USAGE); + } (void) strcpy(buf, filename); (void) strcat(buf, ".db"); if (db = dbopen(buf, O_RDONLY, 0444 , DB_HASH, NULL)) { diff --git a/usr.sbin/sendmail/src/Makefile b/usr.sbin/sendmail/src/Makefile index f8d8370..a634725 100644 --- a/usr.sbin/sendmail/src/Makefile +++ b/usr.sbin/sendmail/src/Makefile @@ -1,4 +1,4 @@ -# @(#)Makefile 8.7 (Berkeley) 10/31/95 +# @(#)Makefile 8.8 (Berkeley) 3/28/97 ######################################################################### # This Makefile is for 4.4BSD only!!! For all other systems, use # @@ -25,14 +25,14 @@ CFLAGS+=-I${.CURDIR} ${DBMDEF} ${NIS} #-DNETISO SRCS= alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \ deliver.c domain.c envelope.c err.c headers.c macro.c main.c map.c \ - mci.c mime.c parseaddr.c queue.c readcf.c recipient.c savemail.c \ - srvrsmtp.c stab.c stats.c sysexits.c trace.c udb.c usersmtp.c \ - util.c version.c + mci.c mime.c parseaddr.c queue.c readcf.c recipient.c safefile.c \ + savemail.c srvrsmtp.c stab.c stats.c sysexits.c trace.c udb.c \ + usersmtp.c util.c version.c DPADD= ${LIBUTIL} LDADD= -lutil MAN1= mailq.1 newaliases.1 MAN5= aliases.5 -MAN8= sendmail.8 +MAN8= sendmail.8 LINKS= /usr/sbin/sendmail /usr/bin/newaliases \ /usr/sbin/sendmail /usr/bin/mailq \ /usr/sbin/sendmail /usr/bin/hoststat \ diff --git a/usr.sbin/sendmail/src/collect.c b/usr.sbin/sendmail/src/collect.c index d5d8982..219a47f 100644 --- a/usr.sbin/sendmail/src/collect.c +++ b/usr.sbin/sendmail/src/collect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)collect.c 8.62 (Berkeley) 12/11/96"; +static char sccsid[] = "@(#)collect.c 8.69 (Berkeley) 5/29/97"; #endif /* not lint */ # include <errno.h> @@ -52,8 +52,6 @@ static char sccsid[] = "@(#)collect.c 8.62 (Berkeley) 12/11/96"; ** style message to say we are ready to collect ** input, and never ignore a single dot to mean ** end of message. -** requeueflag -- this message will be requeued later, so -** don't do final processing on it. ** hdrp -- the location to stash the header. ** e -- the current envelope. ** @@ -83,10 +81,9 @@ static EVENT *CollectTimeout; #define MS_BODY 2 /* reading message body */ void -collect(fp, smtpmode, requeueflag, hdrp, e) +collect(fp, smtpmode, hdrp, e) FILE *fp; bool smtpmode; - bool requeueflag; HDR **hdrp; register ENVELOPE *e; { @@ -103,7 +100,7 @@ collect(fp, smtpmode, requeueflag, hdrp, e) volatile int mstate; u_char *volatile pbp; u_char peekbuf[8]; - char dfname[20]; + char dfname[MAXQFNAME]; char bufbuf[MAXLINE]; extern bool isheader(); extern void eatheader(); @@ -117,10 +114,12 @@ collect(fp, smtpmode, requeueflag, hdrp, e) if (!headeronly) { + int tfd; struct stat stbuf; strcpy(dfname, queuename(e, 'd')); - if ((tf = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL) + tfd = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode, SFF_ANYFILE); + if (tfd < 0 || (tf = fdopen(tfd, "w")) == NULL) { syserr("Cannot create %s", dfname); e->e_flags |= EF_NO_BODY_RETN; @@ -169,12 +168,10 @@ collect(fp, smtpmode, requeueflag, hdrp, e) /* handle possible input timeout */ if (setjmp(CtxCollectTimeout) != 0) { -#ifdef LOG if (LogLevel > 2) - syslog(LOG_NOTICE, + sm_syslog(LOG_NOTICE, e->e_id, "timeout waiting for input from %s during message collect", CurHostName ? CurHostName : "<local machine>"); -#endif errno = 0; usrerr("451 timeout waiting for input during message collect"); goto readerr; @@ -417,10 +414,9 @@ readerr: if (tTd(30, 1)) printf("collect: premature EOM: %s\n", errmsg); -#ifdef LOG if (LogLevel >= 2) - syslog(LOG_WARNING, "collect: premature EOM: %s", errmsg); -#endif + sm_syslog(LOG_WARNING, e->e_id, + "collect: premature EOM: %s", errmsg); inputerr = TRUE; } @@ -455,14 +451,12 @@ readerr: problem = "I/O error"; else problem = "read timeout"; -# ifdef LOG if (LogLevel > 0 && feof(fp)) - syslog(LOG_NOTICE, + sm_syslog(LOG_NOTICE, e->e_id, "collect: %s on connection from %.100s, sender=%s: %s", problem, host, shortenstring(e->e_from.q_paddr, 203), errstring(errno)); -# endif if (feof(fp)) usrerr("451 collect: %s on connection from %s, from=%s", problem, host, @@ -501,7 +495,7 @@ readerr: markstats(e, (ADDRESS *) NULL); } -#ifdef _FFR_DSN_RRT +#if _FFR_DSN_RRT_OPTION /* ** If we have a Return-Receipt-To:, turn it into a DSN. */ @@ -576,11 +570,10 @@ readerr: e->e_status = "5.2.3"; usrerr("552 Message exceeds maximum fixed size (%ld)", MaxMessageSize); -# ifdef LOG if (LogLevel > 6) - syslog(LOG_NOTICE, "%s: message size (%ld) exceeds maximum (%ld)", - e->e_id, e->e_msgsize, MaxMessageSize); -# endif + sm_syslog(LOG_NOTICE, e->e_id, + "message size (%ld) exceeds maximum (%ld)", + e->e_msgsize, MaxMessageSize); } /* check for illegal 8-bit data */ diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c index a768d18..0d50508 100644 --- a/usr.sbin/sendmail/src/conf.c +++ b/usr.sbin/sendmail/src/conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)conf.c 8.333 (Berkeley) 1/21/97"; +static char sccsid[] = "@(#)conf.c 8.362 (Berkeley) 6/14/97"; #endif /* not lint */ # include "sendmail.h" @@ -140,6 +140,9 @@ struct prival PrivacyValues[] = { "novrfy", PRIV_NOVRFY }, { "restrictmailq", PRIV_RESTRICTMAILQ }, { "restrictqrun", PRIV_RESTRICTQRUN }, +#if _FFR_PRIVACY_NOETRN + { "noetrn", PRIV_NOETRN }, +#endif { "authwarnings", PRIV_AUTHWARNINGS }, { "noreceipts", PRIV_NORECEIPTS }, { "goaway", PRIV_GOAWAY }, @@ -187,6 +190,7 @@ setdefaults(e) extern void setdefuser(); extern void setupmaps(); extern void setupmailers(); + extern void setupheaders(); SpaceSub = ' '; /* option B */ QueueLA = 8; /* option x */ @@ -233,6 +237,7 @@ setdefaults(e) setdefuser(); setupmaps(); setupmailers(); + setupheaders(); } @@ -252,46 +257,6 @@ setdefuser() defpwent == NULL ? "nobody" : defpwent->pw_name); } /* -** HOST_MAP_INIT -- initialize host class structures -*/ - -bool host_map_init __P((MAP *map, char *args)); - -bool -host_map_init(MAP *map, char *args) -{ - register char *p = args; - - for (;;) - { - while (isascii(*p) && isspace(*p)) - p++; - if (*p != '-') - break; - switch (*++p) - { - case 'a': - map->map_app = ++p; - break; - - case 'm': - map->map_mflags |= MF_MATCHONLY; - break; - - case 't': - map->map_mflags |= MF_NODEFER; - break; - } - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - if (*p != '\0') - *p++ = '\0'; - } - if (map->map_app != NULL) - map->map_app = newstr(map->map_app); - return TRUE; -} -/* ** SETUPMAILERS -- initialize default mailers */ @@ -366,8 +331,8 @@ setupmaps() #endif #ifdef LDAPMAP MAPDEF("ldapx", NULL, 0, - ldap_map_parseargs, ldap_map_open, ldap_map_close, - ldap_map_lookup, null_map_store); + ldap_map_parseargs, ldap_map_open, ldap_map_close, + ldap_map_lookup, null_map_store); #endif #ifdef HESIOD @@ -1060,7 +1025,11 @@ setsignal(sig, handler) sigfunc_t handler; { #if defined(SYS5SIGNALS) || defined(BSD4_3) +# ifdef BSD4_3 return signal(sig, handler); +# else + return sigset(sig, handler); +# endif #else struct sigaction n, o; @@ -1523,8 +1492,8 @@ getla() dg_sys_info((long *)&load_info, DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); - if (tTd(3, 1)) - printf("getla: %d\n", (int) (load_info.one_minute + 0.5)); + if (tTd(3, 1)) + printf("getla: %d\n", (int) (load_info.one_minute + 0.5)); return((int) (load_info.one_minute + 0.5)); } @@ -1555,8 +1524,8 @@ getla() (size_t) 1, 0) == -1) return 0; - if (tTd(3, 1)) - printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5)); + if (tTd(3, 1)) + printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5)); return (int) (pstd.psd_avg_1_min + 0.5); } @@ -1697,8 +1666,7 @@ int getla(void) static int kmem = -1; static enum { getla_none, getla_32, getla_64 } kernel_type = getla_none; - uint32_t avenrun32[3]; - uint64_t avenrun64[3]; + uint32_t avenrun[3]; if (kernel_type == getla_none) { @@ -1781,57 +1749,47 @@ int getla(void) switch (kernel_type) { + case getla_none: + return -1; + case getla_32: if (lseek(kmem, (off_t) Nl32[X_AVENRUN].n_value, SEEK_SET) == -1 || - read(kmem, (char *) avenrun32, sizeof(avenrun32)) < sizeof(avenrun32)) + read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) { if (tTd(3, 1)) printf("getla: lseek or read: %s\n", errstring(errno)); return -1; } - if (tTd(3, 5)) - { - printf("getla: avenrun{32} = %ld", - (long int) avenrun32[0]); - if (tTd(3, 15)) - printf(", %ld, %ld", - (long int)avenrun32[1], - (long int)avenrun32[2]); - printf("\n"); - } - if (tTd(3, 1)) - printf("getla: %d\n", - (int) (avenrun32[0] + FSCALE/2) >> FSHIFT); - return ((int) (avenrun32[0] + FSCALE/2) >> FSHIFT); + break; case getla_64: /* Using of lseek64 is perhaps overkill ... */ if (lseek64(kmem, (off64_t) Nl64[X_AVENRUN].n_value, SEEK_SET) == -1 || - read(kmem, (char *) avenrun64, sizeof(avenrun64)) < - sizeof(avenrun64)) + read(kmem, (char *) avenrun, sizeof(avenrun)) < + sizeof(avenrun)) { if (tTd(3, 1)) printf("getla: lseek64 or read: %s\n", errstring(errno)); return -1; } - if (tTd(3, 5)) - { - printf("getla: avenrun{64} = %lld", - (long long int) avenrun64[0]); - if (tTd(3, 15)) - printf(", %lld, %lld", - (long long int) avenrun64[1], - (long long int) avenrun64[2]); - printf("\n"); - } - if (tTd(3, 1)) - printf("getla: %d\n", - (int) (avenrun64[0] + FSCALE/2) >> FSHIFT); - return ((int) (avenrun64[0] + FSCALE/2) >> FSHIFT); + break; } - return -1; + if (tTd(3, 5)) + { + printf("getla: avenrun = %ld", + (long int) avenrun[0]); + if (tTd(3, 15)) + printf(", %ld, %ld", + (long int)avenrun[1], + (long int)avenrun[2]); + printf("\n"); + } + if (tTd(3, 1)) + printf("getla: %d\n", + (int) (avenrun[0] + FSCALE/2) >> FSHIFT); + return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); } #endif @@ -1911,7 +1869,9 @@ getla() afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC); if (afd < 0) { - syslog(LOG_ERR, "can't open %s: %m", _PATH_AVENRUN); + sm_syslog(LOG_ERR, NOQID, + "can't open %s: %m", + _PATH_AVENRUN); return -1; } } @@ -2031,16 +1991,19 @@ int getloadavg( call_data ) ** none. */ +extern int get_num_procs_online __P((void)); + bool shouldqueue(pri, ctime) long pri; time_t ctime; { bool rval; + int queuela = QueueLA * get_num_procs_online(); if (tTd(3, 30)) printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri); - if (CurrentLA < QueueLA) + if (CurrentLA < queuela) { if (tTd(3, 30)) printf("FALSE (CurrentLA < QueueLA)\n"); @@ -2054,7 +2017,7 @@ shouldqueue(pri, ctime) return (TRUE); } #endif - rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1)); + rval = pri > (QueueFactor / (CurrentLA - queuela + 1)); if (tTd(3, 30)) printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE"); return rval; @@ -2078,6 +2041,7 @@ bool refuseconnections(port) int port; { + int refusela = RefuseLA * get_num_procs_online(); time_t now; static time_t lastconn = (time_t) 0; static int conncnt = 0; @@ -2100,24 +2064,22 @@ refuseconnections(port) /* sleep to flatten out connection load */ setproctitle("deferring connections on port %d: %d per second", port, ConnRateThrottle); -#ifdef LOG if (LogLevel >= 14) - syslog(LOG_INFO, "deferring connections on port %d: %d per second", + sm_syslog(LOG_INFO, NOQID, + "deferring connections on port %d: %d per second", port, ConnRateThrottle); -#endif sleep(1); } CurrentLA = getla(); - if (CurrentLA >= RefuseLA) + if (CurrentLA >= refusela) { setproctitle("rejecting connections on port %d: load average: %d", port, CurrentLA); -#ifdef LOG if (LogLevel >= 14) - syslog(LOG_INFO, "rejecting connections on port %d: load average: %d", + sm_syslog(LOG_INFO, NOQID, + "rejecting connections on port %d: load average: %d", port, CurrentLA); -#endif return TRUE; } @@ -2125,11 +2087,10 @@ refuseconnections(port) { setproctitle("rejecting connections on port %d: min free: %d", port, MinBlocksFree); -#ifdef LOG if (LogLevel >= 14) - syslog(LOG_INFO, "rejecting connections on port %d: min free: %d", + sm_syslog(LOG_INFO, NOQID, + "rejecting connections on port %d: min free: %d", port, MinBlocksFree); -#endif return TRUE; } @@ -2142,11 +2103,10 @@ refuseconnections(port) { setproctitle("rejecting connections on port %d: %d children, max %d", port, CurChildren, MaxChildren); -#ifdef LOG if (LogLevel >= 14) - syslog(LOG_INFO, "rejecting connections on port %d: %d children, max %d", + sm_syslog(LOG_INFO, NOQID, + "rejecting connections on port %d: %d children, max %d", port, CurChildren, MaxChildren); -#endif return TRUE; } } @@ -2175,6 +2135,7 @@ refuseconnections(port) #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */ #define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */ #define SPT_SCO 6 /* write kernel u. area */ +#define SPT_CHANGEARGV 7 /* write our own strings into argv[] */ #ifndef SPT_TYPE # define SPT_TYPE SPT_REUSEARGV @@ -2199,7 +2160,7 @@ typedef unsigned int *pt_entry_t; # endif # endif -# if SPT_TYPE == SPT_PSSTRINGS +# if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV # define SETPROC_STATIC static # else # define SETPROC_STATIC @@ -2248,7 +2209,7 @@ initsetproctitle(argc, argv, envp) extern char **environ; /* - ** Move the environment so setproctitle can use the space at + ** Move the environment so setproctitle can use the space at ** the top of memory. */ @@ -2350,11 +2311,65 @@ setproctitle(fmt, va_alist) *p++ = SPT_PADCHAR; Argv[1] = NULL; # endif +# if SPT_TYPE == SPT_CHANGEARGV + Argv[0] = buf; + Argv[1] = 0; +# endif # endif /* SPT_TYPE != SPT_NONE */ } #endif /* SPT_TYPE != SPT_BUILTIN */ /* +** WAITFOR -- wait for a particular process id. +** +** Parameters: +** pid -- process id to wait for. +** +** Returns: +** status of pid. +** -1 if pid never shows up. +** +** Side Effects: +** none. +*/ + +int +waitfor(pid) + pid_t pid; +{ +#ifdef WAITUNION + union wait st; +#else + auto int st; +#endif + pid_t i; +#if defined(ISC_UNIX) || defined(_SCO_unix_) + int savesig; +#endif + + do + { + errno = 0; +#if defined(ISC_UNIX) || defined(_SCO_unix_) + savesig = releasesignal(SIGCHLD); +#endif + i = wait(&st); +#if defined(ISC_UNIX) || defined(_SCO_unix_) + if (savesig > 0) + blocksignal(SIGCHLD); +#endif + if (i > 0) + proc_list_drop(i); + } while ((i >= 0 || errno == EINTR) && i != pid); + if (i < 0) + return -1; +#ifdef WAITUNION + return st.w_status; +#else + return st; +#endif +} +/* ** REAPCHILD -- pick up the body of my child, lest it become a zombie ** ** Parameters: @@ -2382,12 +2397,10 @@ reapchild(sig) { if (count++ > 1000) { -#ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, + sm_syslog(LOG_ALERT, NOQID, "reapchild: waitpid loop: pid=%d, status=%x", pid, status); -#endif break; } proc_list_drop(pid); @@ -2401,7 +2414,14 @@ reapchild(sig) # else /* WNOHANG */ auto int status; - while ((pid = wait(&status)) > 0) + /* + ** Catch one zombie -- we will be re-invoked (we hope) if there + ** are more. Unreliable signals probably break this, but this + ** is the "old system" situation -- waitpid or wait3 are to be + ** strongly preferred. + */ + + if ((pid = wait(&status)) > 0) proc_list_drop(pid); # endif /* WNOHANG */ # endif @@ -2875,12 +2895,10 @@ vsprintf(s, fmt, ap) ** %lx has been added. */ -#if !HASSNPRINTF - /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. + * A bombproof version of doprnt (sm_dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * @@ -2891,10 +2909,12 @@ vsprintf(s, fmt, ap) * causing nast effects. **************************************************************/ -static void dopr(); -static char *end; +static void sm_dopr(); +static char *DoprEnd; static int SnprfOverflow; +#if !HASSNPRINTF + /* VARARGS3 */ int # ifdef __STDC__ @@ -2926,19 +2946,22 @@ vsnprintf(str, count, fmt, args) va_list args; { str[0] = 0; - end = str + count - 1; + DoprEnd = str + count - 1; SnprfOverflow = 0; - dopr( str, fmt, args ); + sm_dopr( str, fmt, args ); if (count > 0) - end[0] = 0; + DoprEnd[0] = 0; if (SnprfOverflow && tTd(57, 2)) printf("\nvsnprintf overflow, len = %d, str = %s", count, shortenstring(str, 203)); return strlen(str); } +# endif /* !luna2 */ +#endif /* !HASSNPRINTF */ + /* - * dopr(): poor man's version of doprintf + * sm_dopr(): poor man's version of doprintf */ static void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth)); @@ -2946,9 +2969,10 @@ static void fmtnum __P((long value, int base, int dosign, int ljust, int len, in static void dostr __P(( char * , int )); static char *output; static void dopr_outch __P(( int c )); +static int SyslogErrno; static void -dopr( buffer, format, args ) +sm_dopr( buffer, format, args ) char *buffer; const char *format; va_list args; @@ -2962,30 +2986,35 @@ dopr( buffer, format, args ) int ljust; int len; int zpad; +# if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) + extern char *sys_errlist[]; + extern int sys_nerr; +# endif + output = buffer; while( (ch = *format++) ){ - switch( ch ){ - case '%': - ljust = len = zpad = maxwidth = 0; - longflag = pointflag = 0; - nextch: - ch = *format++; - switch( ch ){ - case 0: - dostr( "**end of format**" , 0); - return; - case '-': ljust = 1; goto nextch; - case '0': /* set zero padding if len not set */ - if(len==0 && !pointflag) zpad = '0'; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': + switch( ch ){ + case '%': + ljust = len = zpad = maxwidth = 0; + longflag = pointflag = 0; + nextch: + ch = *format++; + switch( ch ){ + case 0: + dostr( "**end of format**" , 0); + return; + case '-': ljust = 1; goto nextch; + case '0': /* set zero padding if len not set */ + if(len==0 && !pointflag) zpad = '0'; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': if (pointflag) maxwidth = maxwidth*10 + ch - '0'; else len = len*10 + ch - '0'; - goto nextch; + goto nextch; case '*': if (pointflag) maxwidth = va_arg( args, int ); @@ -2993,64 +3022,78 @@ dopr( buffer, format, args ) len = va_arg( args, int ); goto nextch; case '.': pointflag = 1; goto nextch; - case 'l': longflag = 1; goto nextch; - case 'u': case 'U': - /*fmtnum(value,base,dosign,ljust,len,zpad) */ - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 10,0, ljust, len, zpad ); break; - case 'o': case 'O': - /*fmtnum(value,base,dosign,ljust,len,zpad) */ - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 8,0, ljust, len, zpad ); break; - case 'd': case 'D': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 10,1, ljust, len, zpad ); break; - case 'x': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 16,0, ljust, len, zpad ); break; - case 'X': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value,-16,0, ljust, len, zpad ); break; - case 's': - strvalue = va_arg( args, char *); + case 'l': longflag = 1; goto nextch; + case 'u': case 'U': + /*fmtnum(value,base,dosign,ljust,len,zpad) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,0, ljust, len, zpad ); break; + case 'o': case 'O': + /*fmtnum(value,base,dosign,ljust,len,zpad) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 8,0, ljust, len, zpad ); break; + case 'd': case 'D': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,1, ljust, len, zpad ); break; + case 'x': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 16,0, ljust, len, zpad ); break; + case 'X': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value,-16,0, ljust, len, zpad ); break; + case 's': + strvalue = va_arg( args, char *); if (maxwidth > 0 || !pointflag) { if (pointflag && len > maxwidth) len = maxwidth; /* Adjust padding */ fmtstr( strvalue,ljust,len,zpad, maxwidth); } break; - case 'c': - ch = va_arg( args, int ); - dopr_outch( ch ); break; - case '%': dopr_outch( ch ); continue; - default: - dostr( "???????" , 0); - } - break; - default: - dopr_outch( ch ); - break; - } + case 'c': + ch = va_arg( args, int ); + dopr_outch( ch ); break; + case 'm': +#if HASSTRERROR + dostr(strerror(SyslogErrno), 0); +#else + if (SyslogErrno < 0 || SyslogErrno > sys_nerr) + { + dostr("Error ", 0); + fmtnum(SyslogErrno, 10, 0, 0, 0, 0); + } + else + dostr(sys_errlist[SyslogErrno], 0); +#endif + break; + + case '%': dopr_outch( ch ); continue; + default: + dostr( "???????" , 0); + } + break; + default: + dopr_outch( ch ); + break; + } } *output = 0; } @@ -3063,7 +3106,7 @@ fmtstr( value, ljust, len, zpad, maxwidth ) int padlen, strlen; /* amount to pad */ if( value == 0 ){ - value = "<NULL>"; + value = "<NULL>"; } for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */ if (strlen > maxwidth && maxwidth) @@ -3072,13 +3115,13 @@ fmtstr( value, ljust, len, zpad, maxwidth ) if( padlen < 0 ) padlen = 0; if( ljust ) padlen = -padlen; while( padlen > 0 ) { - dopr_outch( ' ' ); - --padlen; + dopr_outch( ' ' ); + --padlen; } dostr( value, maxwidth ); while( padlen < 0 ) { - dopr_outch( ' ' ); - ++padlen; + dopr_outch( ' ' ); + ++padlen; } } @@ -3095,50 +3138,50 @@ fmtnum( value, base, dosign, ljust, len, zpad ) int caps = 0; /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", - value, base, dosign, ljust, len, zpad )); */ + value, base, dosign, ljust, len, zpad )); */ uvalue = value; if( dosign ){ - if( value < 0 ) { - signvalue = '-'; - uvalue = -value; - } + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } } if( base < 0 ){ - caps = 1; - base = -base; + caps = 1; + base = -base; } do{ - convert[place++] = - (caps? "0123456789ABCDEF":"0123456789abcdef") - [uvalue % (unsigned)base ]; - uvalue = (uvalue / (unsigned)base ); + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); }while(uvalue); convert[place] = 0; padlen = len - place; if( padlen < 0 ) padlen = 0; if( ljust ) padlen = -padlen; /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", - convert,place,signvalue,padlen)); */ + convert,place,signvalue,padlen)); */ if( zpad && padlen > 0 ){ - if( signvalue ){ - dopr_outch( signvalue ); - --padlen; - signvalue = 0; - } - while( padlen > 0 ){ - dopr_outch( zpad ); - --padlen; - } + if( signvalue ){ + dopr_outch( signvalue ); + --padlen; + signvalue = 0; + } + while( padlen > 0 ){ + dopr_outch( zpad ); + --padlen; + } } while( padlen > 0 ) { - dopr_outch( ' ' ); - --padlen; + dopr_outch( ' ' ); + --padlen; } if( signvalue ) dopr_outch( signvalue ); while( place > 0 ) dopr_outch( convert[--place] ); while( padlen < 0 ){ - dopr_outch( ' ' ); - ++padlen; + dopr_outch( ' ' ); + ++padlen; } } @@ -3160,20 +3203,16 @@ dopr_outch( c ) { #if 0 if( iscntrl(c) && c != '\n' && c != '\t' ){ - c = '@' + (c & 0x1F); - if( end == 0 || output < end ) - *output++ = '^'; + c = '@' + (c & 0x1F); + if( DoprEnd == 0 || output < DoprEnd ) + *output++ = '^'; } #endif - if( end == 0 || output < end ) - *output++ = c; + if( DoprEnd == 0 || output < DoprEnd ) + *output++ = c; else SnprfOverflow++; } - -# endif /* !luna2 */ - -#endif /* !HASSNPRINTF */ /* ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use ** @@ -3428,7 +3467,7 @@ freediskspace(dir, bsize) { if (bsize != NULL) *bsize = FSBLOCKSIZE; - if (fs.SFS_BAVAIL < 0) + if (fs.SFS_BAVAIL <= 0) return 0; else return fs.SFS_BAVAIL; @@ -3477,15 +3516,12 @@ enoughdiskspace(msize) if (bfree < msize) { -#ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, - "%s: low on space (have %ld, %s needs %ld in %s)", - CurEnv->e_id == NULL ? "[NOQUEUE]" : CurEnv->e_id, + sm_syslog(LOG_ALERT, CurEnv->e_id, + "low on space (have %ld, %s needs %ld in %s)", bfree, CurHostName == NULL ? "SMTP-DAEMON" : CurHostName, msize, QueueDir); -#endif return FALSE; } } @@ -3591,7 +3627,7 @@ transienterror(err) #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) case ENOSR: /* Out of streams resources */ #endif - case EOPENTIMEOUT: /* PSEUDO: open timed out */ + case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */ return TRUE; } @@ -3621,6 +3657,7 @@ lockfile(fd, filename, ext, type) char *ext; int type; { + int i; # if !HASFLOCK int action; struct flock lfd; @@ -3645,7 +3682,9 @@ lockfile(fd, filename, ext, type) printf("lockfile(%s%s, action=%d, type=%d): ", filename, ext, action, lfd.l_type); - if (fcntl(fd, action, &lfd) >= 0) + while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR) + continue; + if (i >= 0) { if (tTd(55, 60)) printf("SUCCESS\n"); @@ -3691,7 +3730,9 @@ lockfile(fd, filename, ext, type) if (tTd(55, 60)) printf("lockfile(%s%s, type=%o): ", filename, ext, type); - if (flock(fd, type) >= 0) + while ((i = flock(fd, type)) < 0 && errno == EINTR) + continue; + if (i >= 0) { if (tTd(55, 60)) printf("SUCCESS\n"); @@ -3722,53 +3763,73 @@ lockfile(fd, filename, ext, type) /* ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) ** +** Unfortunately, given that we can't predict other systems on which +** a remote mounted (NFS) filesystem will be mounted, the answer is +** almost always that this is unsafe. +** +** Note also that many operating systems have non-compliant +** implementations of the _POSIX_CHOWN_RESTRICTED variable and the +** fpathconf() routine. According to IEEE 1003.1-1990, if +** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then +** no non-root process can give away the file. However, vendors +** don't take NFS into account, so a comfortable value of +** _POSIX_CHOWN_RESTRICTED tells us nothing. +** +** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf() +** even on files where chown is not restricted. Many systems get +** this wrong on NFS-based filesystems (that is, they say that chown +** is restricted [safe] on NFS filesystems where it may not be, since +** other systems can access the same filesystem and do file giveaway; +** only the NFS server knows for sure!) Hence, it is important to +** get the value of SAFENFSPATHCONF correct -- it should be defined +** _only_ after testing (see test/t_pathconf.c) a system on an unsafe +** NFS-based filesystem to ensure that you can get meaningful results. +** If in doubt, assume unsafe! +** +** You may also need to tweak IS_SAFE_CHOWN -- it should be a +** condition indicating whether the return from pathconf indicates +** that chown is safe (typically either > 0 or >= 0 -- there isn't +** even any agreement about whether a zero return means that a file +** is or is not safe). It defaults to "> 0". +** +** If the parent directory is safe (writable only by owner back +** to the root) then we can relax slightly and trust fpathconf +** in more circumstances. This is really a crock -- if this is an +** NFS mounted filesystem then we really know nothing about the +** underlying implementation. However, most systems pessimize and +** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which +** we interpret as unsafe, as we should. Thus, this heuristic gets +** us into a possible problem only on systems that have a broken +** pathconf implementation and which are also poorly configured +** (have :include: files in group- or world-writable directories). +** ** Parameters: ** fd -- the file descriptor to check. +** safedir -- set if the parent directory is safe. ** ** Returns: -** TRUE -- if only root can chown the file to an arbitrary -** user. +** TRUE -- if the chown(2) operation is "safe" -- that is, +** only root can chown the file to an arbitrary user. ** FALSE -- if an arbitrary user can give away a file. */ +#ifndef IS_SAFE_CHOWN +# define IS_SAFE_CHOWN > 0 +#endif + bool -chownsafe(fd) +chownsafe(fd, safedir) int fd; + bool safedir; { -#ifdef __hpux - char *s; - int tfd; - uid_t o_uid, o_euid; - gid_t o_gid, o_egid; - bool rval; - struct stat stbuf; - - o_uid = getuid(); - o_euid = geteuid(); - o_gid = getgid(); - o_egid = getegid(); - fstat(fd, &stbuf); - setresuid(stbuf.st_uid, stbuf.st_uid, -1); - setresgid(stbuf.st_gid, stbuf.st_gid, -1); - s = tmpnam(NULL); - tfd = open(s, O_RDONLY|O_CREAT, 0600); - rval = fchown(tfd, DefUid, DefGid) != 0; - close(tfd); - setresuid(o_uid, o_euid, -1); - setresgid(o_gid, o_egid, -1); - unlink(s); - return rval; -#else -# ifdef _POSIX_CHOWN_RESTRICTED -# if _POSIX_CHOWN_RESTRICTED == -1 - return FALSE; -# else - return TRUE; -# endif -# else -# ifdef _PC_CHOWN_RESTRICTED +#if !defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1 +# if defined(_PC_CHOWN_RESTRICTED) int rval; + /* give the system administrator a chance to override */ + if (ChownAlwaysSafe) + return TRUE; + /* ** Some systems (e.g., SunOS) seem to have the call and the ** #define _PC_CHOWN_RESTRICTED, but don't actually implement @@ -3777,15 +3838,14 @@ chownsafe(fd) errno = 0; rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); - if (errno == 0) - return rval > 0; -# endif -# ifdef BSD - return TRUE; +# if SAFENFSPATHCONF + return errno == 0 && rval IS_SAFE_CHOWN; # else - return FALSE; + return safedir && errno == 0 && rval IS_SAFE_CHOWN; # endif # endif +#else + return ChownAlwaysSafe; #endif } /* @@ -4022,11 +4082,10 @@ validate_connection(sap, hostname, e) #if TCPWRAPPERS if (!hosts_ctl("sendmail", hostname, anynet_ntoa(sap), STRING_UNKNOWN)) { -# ifdef LOG if (LogLevel >= 4) - syslog(LOG_NOTICE, "tcpwrappers (%s, %s) rejection", + sm_syslog(LOG_NOTICE, NOQID, + "tcpwrappers (%s, %s) rejection", hostname, anynet_ntoa(sap)); -# endif return FALSE; } #endif @@ -4379,7 +4438,7 @@ secureware_setup_secure(uid) ** Loads $=w with the names of all the interfaces. */ -#ifdef SIOCGIFCONF +#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN struct rtentry; struct mbuf; # include <arpa/inet.h> @@ -4392,19 +4451,38 @@ struct mbuf; void load_if_names() { -#ifdef SIOCGIFCONF +#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN int s; int i; - struct ifconf ifc; - char interfacebuf[10240]; + struct ifconf ifc; + int numifs; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) return; /* get the list of known IP address from the kernel */ - ifc.ifc_buf = interfacebuf; - ifc.ifc_len = sizeof interfacebuf; +# ifdef SIOCGIFNUM + if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) + { + /* can't get number of interfaces -- fall back */ + if (tTd(0, 4)) + printf("SIOCGIFNUM failed: %s\n", errstring(errno)); + numifs = -1; + } + else if (tTd(0, 42)) + printf("system has %d interfaces\n", numifs); + if (numifs < 0) +# endif + numifs = 512; + + if (numifs <= 0) + { + close(s); + return; + } + ifc.ifc_len = numifs * sizeof (struct ifreq); + ifc.ifc_buf = xalloc(ifc.ifc_len); if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { if (tTd(0, 4)) @@ -4429,7 +4507,6 @@ load_if_names() #endif char ip_addr[256]; extern char *inet_ntoa(); - extern struct hostent *gethostbyaddr(); #ifdef BSD4_4_SOCKADDR if (sa->sa_len > sizeof ifr->ifr_addr) @@ -4450,12 +4527,12 @@ load_if_names() ioctl(s, SIOCGIFFLAGS, (char *) &ifrf); if (tTd(0, 41)) printf("\tflags: %x\n", ifrf.ifr_flags); - if (!bitset(IFF_UP, ifrf.ifr_flags)) - continue; +# define IFRFREF ifrf #else - if (!bitset(IFF_UP, ifr->ifr_flags)) - continue; +# define IFRFREF (*ifr) #endif + if (!bitset(IFF_UP, IFRFREF.ifr_flags)) + continue; /* extract IP address from the list*/ ia = (((struct sockaddr_in *) sa)->sin_addr); @@ -4478,18 +4555,21 @@ load_if_names() } /* skip "loopback" interface "lo" */ - if (strcmp("lo0", ifr->ifr_name) == 0) + if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags)) continue; /* lookup name with IP address */ hp = sm_gethostbyaddr((char *) &ia, sizeof(ia), AF_INET); if (hp == NULL) { -#ifdef LOG if (LogLevel > 3) - syslog(LOG_WARNING, - "gethostbyaddr() failed for %.100s\n", - inet_ntoa(ia)); + sm_syslog(LOG_WARNING, NOQID, + "gethostbyaddr(%.100s) failed: %d\n", + inet_ntoa(ia), +#if NAMED_BIND + h_errno); +#else + -1); #endif continue; } @@ -4514,7 +4594,166 @@ load_if_names() hp->h_aliases++; } } + free(ifc.ifc_buf); close(s); +# undef IFRFREF +#endif +} +/* +** GET_NUM_PROCS_ONLINE -- return the number of processors currently online +** +** Parameters: +** none. +** +** Returns: +** The number of processors online. +*/ + +int +get_num_procs_online() +{ + int nproc = 0; + +#if _FFR_SCALE_LA_BY_NUM_PROCS +#ifdef _SC_NPROCESSORS_ONLN + nproc = (int) sysconf(_SC_NPROCESSORS_ONLN); +#endif +#endif + if (nproc <= 0) + nproc = 1; + return nproc; +} +/* +** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE +** +** Parameters: +** level -- syslog level +** id -- envelope ID or NULL (NOQUEUE) +** fmt -- format string +** arg... -- arguments as implied by fmt. +** +** Returns: +** none +*/ + +/* VARARGS3 */ +void +# ifdef __STDC__ +sm_syslog(int level, const char *id, const char *fmt, ...) +# else +sm_syslog(level, id, fmt, va_alist) + int level; + const char *id; + const char *fmt; + va_dcl +#endif +{ + static char *buf = NULL; + static size_t bufsize = MAXLINE; + char *begin, *end; + int seq = 1; + int idlen; + extern int SnprfOverflow; + VA_LOCAL_DECL + + SyslogErrno = errno; + if (id == NULL) + { + id = "NOQUEUE"; + idlen = 9; + } + else if (strcmp(id, NOQID) == 0) + { + id = ""; + idlen = 0; + } + else + idlen = strlen(id + 2); +bufalloc: + if (buf == NULL) + buf = (char *) xalloc(sizeof(char) * bufsize); + + /* do a virtual vsnprintf into buf */ + VA_START(fmt); + buf[0] = 0; + DoprEnd = buf + bufsize - 1; + SnprfOverflow = 0; + sm_dopr(buf, fmt, ap); + *DoprEnd = '\0'; + VA_END; + /* end of virtual vsnprintf */ + + if (SnprfOverflow) + { + /* String too small, redo with correct size */ + bufsize += SnprfOverflow + 1; + free(buf); + buf = NULL; + goto bufalloc; + } + if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE) + { +#if LOG + if (*id == '\0') + syslog(level, "%s", buf); + else + syslog(level, "%s: %s", id, buf); +#else + /*XXX should do something more sensible */ + if (*id == '\0') + fprintf(stderr, "%s\n", buf); + else + fprintf(stderr, "%s: %s\n", id, buf); +#endif + return; + } + + begin = buf; + while (*begin != '\0' && + (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE) + { + char save; + + if (seq == 999) + { + /* Too many messages */ + break; + } + end = begin + SYSLOG_BUFSIZE - idlen - 12; + while (end > begin) + { + /* Break on comma or space */ + if (*end == ',' || *end == ' ') + { + end++; /* Include separator */ + break; + } + end--; + } + /* No separator, break midstring... */ + if (end == begin) + end = begin + SYSLOG_BUFSIZE - idlen - 12; + save = *end; + *end = 0; +#if LOG + syslog(level, "%s[%d]: %s ...", id, seq++, begin); +#else + fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin); +#endif + *end = save; + begin = end; + } + if (seq == 999) +#if LOG + syslog(level, "%s[%d]: log terminated, too many parts", id, seq); +#else + fprintf(stderr, "%s[%d]: log terminated, too many parts\n", id, seq); +#endif + else if (*begin != '\0') +#if LOG + syslog(level, "%s[%d]: %s", id, seq, begin); +#else + fprintf(stderr, "%s[%d]: %s\n", id, seq, begin); #endif } /* @@ -4547,7 +4786,7 @@ hard_syslog(pri, msg, va_alist) # endif { int i; - char buf[SYSLOG_BUFSIZE * 2]; + char buf[SYSLOG_BUFSIZE]; VA_LOCAL_DECL; VA_START(msg); @@ -4607,7 +4846,7 @@ char *CompileOptions[] = #if LDAPMAP "LDAPMAP", #endif -#ifdef LOG +#if LOG "LOG", #endif #if MATCHGECOS @@ -4689,6 +4928,9 @@ char *CompileOptions[] = char *OsCompileOptions[] = { +#if BOGUS_O_EXCL + "BOGUS_O_EXCL", +#endif #if HASFCHMOD "HASFCHMOD", #endif @@ -4725,6 +4967,9 @@ char *OsCompileOptions[] = #if HASSNPRINTF "HASSNPRINTF", #endif +#if HASSTRERROR + "HASSTRERROR", +#endif #if HASULIMIT "HASULIMIT", #endif @@ -4752,12 +4997,18 @@ char *OsCompileOptions[] = #if RLIMIT_NEEDS_SYS_TIME_H "RLIMIT_NEEDS_SYS_TIME_H", #endif +#if SAFENFSPATHCONF + "SAFENFSPATHCONF", +#endif #if SECUREWARE "SECUREWARE", #endif #if SHARE_V1 "SHARE_V1", #endif +#if SIOCGIFCONF_IS_BROKEN + "SIOCGIFCONF_IS_BROKEN", +#endif #if SYS5SETPGRP "SYS5SETPGRP", #endif diff --git a/usr.sbin/sendmail/src/conf.h b/usr.sbin/sendmail/src/conf.h index 1e0b765..745b7a0 100644 --- a/usr.sbin/sendmail/src/conf.h +++ b/usr.sbin/sendmail/src/conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)conf.h 8.288 (Berkeley) 1/17/97 + * @(#)conf.h 8.313 (Berkeley) 6/11/97 */ /* @@ -79,6 +79,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define MAXMIMEARGS 20 /* max args in Content-Type: */ # define MAXMIMENESTING 20 /* max MIME multipart nesting */ # define QUEUESEGSIZE 1000 /* increment for queue size */ +# define MAXQFNAME 20 /* max qf file name length */ /********************************************************************** ** Compilation options. @@ -130,7 +131,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ ** be turned off unless absolutely necessary. **********************************************************************/ -# define LOG /* enable logging -- don't turn off */ +# define LOG 1 /* enable logging -- don't turn off */ /********************************************************************** ** End of site-specific configuration. @@ -175,6 +176,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define HASINITGROUPS 1 /* has initgroups(3) call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define USESETEUID 1 /* has useable seteuid(2) call */ +# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */ # define seteuid(e) setresuid(-1, e, -1) # define IP_SRCROUTE 1 /* can check IP source routing */ # define LA_TYPE LA_HPUX @@ -185,6 +187,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ # endif # define syslog hard_syslog +# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */ # ifdef V4FS /* HP-UX 10.x */ @@ -217,6 +220,7 @@ extern void hard_syslog(int, char *, ...); */ #ifdef _AIX4 +# include <sys/select.h> # define _AIX3 1 /* pull in AIX3 stuff */ # define USESETEUID 1 /* seteuid(2) works */ # define TZ_TYPE TZ_NAME /* use tzname[] vector */ @@ -336,6 +340,7 @@ typedef int pid_t; # define SFS_BAVAIL f_bfree /* alternate field name */ # ifdef IRIX6 # define LA_TYPE LA_IRIX6 /* figure out at run time */ +# define SAFENFSPATHCONF 0 /* pathconf(2) lies on NFS filesystems */ # else # define LA_TYPE LA_INT @@ -373,6 +378,7 @@ typedef int pid_t; # define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define IP_SRCROUTE 1 /* can check IP source routing */ +# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */ # ifdef SOLARIS_2_3 # define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */ @@ -402,6 +408,9 @@ typedef int pid_t; # ifndef SYSLOG_BUFSIZE # define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */ # endif +# ifndef TZ_TYPE +# define TZ_TYPE TZ_TZNAME +# endif # if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) # define USESETEUID 1 /* seteuid works as of 2.3 */ # endif @@ -529,6 +538,7 @@ extern long dgux_inet_addr(); # ifndef IDENTPROTO # define IDENTPROTO 0 /* pre-4.4 TCP/IP implementation is broken */ # endif +# define SYSLOG_BUFSIZE 256 #endif @@ -558,6 +568,8 @@ extern long dgux_inet_addr(); # ifndef TZ_TYPE # define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ # endif +# define GIDSET_T gid_t +# define MAXNAMLEN NAME_MAX #endif @@ -600,8 +612,10 @@ extern long dgux_inet_addr(); # define UID_T int /* compiler gripes on uid_t */ # define GID_T int /* ditto for gid_t */ # define MODE_T int /* and mode_t */ -# define sleep sleepX # define setpgid setpgrp +# ifndef NOT_SENDMAIL +# define sleep sleepX +# endif # ifndef LA_TYPE # define LA_TYPE LA_MACH # endif @@ -624,12 +638,13 @@ typedef int pid_t; ** See also BSD defines. */ -#if defined(BSD4_4) && !defined(__bsdi__) +#if defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__) # include <paths.h> # define HASUNSETENV 1 /* has unsetenv(3) call */ # define USESETEUID 1 /* has useable seteuid(2) call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ +# define HASSTRERROR 1 /* has strerror(3) */ # include <sys/cdefs.h> # define ERRLIST_PREDEFINED /* don't declare sys_errlist */ # define BSD4_4_SOCKADDR /* has sa_len */ @@ -655,6 +670,7 @@ typedef int pid_t; # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ # define HASUNAME 1 /* has uname(2) syscall */ +# define HASSTRERROR 1 /* has strerror(3) */ # include <sys/cdefs.h> # define ERRLIST_PREDEFINED /* don't declare sys_errlist */ # define BSD4_4_SOCKADDR /* has sa_len */ @@ -696,9 +712,12 @@ typedef int pid_t; # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ # define HASUNAME 1 /* has uname(2) syscall */ +# define HASSTRERROR 1 /* has strerror(3) */ +# include <sys/cdefs.h> # define ERRLIST_PREDEFINED /* don't declare sys_errlist */ # define BSD4_4_SOCKADDR /* has sa_len */ # define NETLINK 1 /* supports AF_LINK */ +# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */ # define GIDSET_T gid_t # ifndef LA_TYPE # define LA_TYPE LA_SUBR @@ -740,7 +759,7 @@ typedef int pid_t; ** For mt Xinu's Mach386 system. */ -#if defined(MACH) && defined(i386) +#if defined(MACH) && defined(i386) && !defined(__GNU__) # define MACH386 1 # define HASUNSETENV 1 /* has unsetenv(3) call */ # define HASINITGROUPS 1 /* has initgroups(3) call */ @@ -764,6 +783,50 @@ typedef int pid_t; #endif + +/* +** GNU OS (hurd) +** Largely BSD & posix compatible. +** Port contributed by Miles Bader <miles@gnu.ai.mit.edu>. +*/ + +#ifdef __GNU_HURD__ +# define SIOCGIFCONF_IS_BROKEN 1 +# define IP_SRCROUTE 0 +# define HASFCHMOD 1 +# define HASFLOCK 1 +# define HASUNAME 1 +# define HASUNSETENV 1 +# define HASSETSID 1 +# define HASINITGROUPS 1 +# define HASSETVBUF 1 +# define HASSETREUID 1 +# define USESETEUID 1 +# define HASLSTAT 1 +# define HASSETRLIMIT 1 +# define HASWAITPID 1 +# define HASGETDTABLESIZE 1 +# define HASSTRERROR 1 +/* # define NEEDGETOPT 1 */ +# define HASGETUSERSHELL 1 +# define ERRLIST_PREDEFINED 1 +# define BSD4_4_SOCKADDR 1 +# define GIDSET_T gid_t +# define LA_TYPE LA_MACH + +/* GNU uses mach[34], which renames some rpcs from mach2.x. */ +# define host_self mach_host_self +# define SFS_TYPE SFS_STATFS +# define SPT_TYPE SPT_CHANGEARGV + +/* GNU has no MAXPATHLEN; ideally the code should be changed to not use it. */ +# define MAXPATHLEN 2048 + +/* Define device num frobbing macros. */ +# define major(x) ((x)>>8) +# define minor(x) ((x)&0xFF) +#endif /* GNU */ + /* ** 4.3 BSD -- this is for very old systems ** @@ -1069,6 +1132,7 @@ extern void *malloc(); # define GIDSET_T gid_t /* from <linux/types.h> */ # define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */ # define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */ +# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */ # ifndef HASFLOCK # include <linux/version.h> # if LINUX_VERSION_CODE < 66399 @@ -1120,10 +1184,12 @@ extern void *malloc(); # define HASUNAME 1 /* use System V uname(2) system call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASINITGROUPS 1 /* has initgroups(3) call */ -# define HASSETVBUF 1 /* we have setvbuf(3) in libc */ +# define HASSETVBUF 1 /* has setvbuf(3) in libc */ +# define HASSTRERROR 1 /* has strerror(3) */ # define SIGFUNC_DEFINED /* sigfunc_t already defined */ -# define SIGFUNC_RETURN (0) /* XXX this is a guess */ -# define SIGFUNC_DECL int /* XXX this is a guess */ +# define SIGFUNC_RETURN /* POSIX-mode */ +# define SIGFUNC_DECL void /* POSIX-mode */ +# define ERRLIST_PREDEFINED 1 # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif @@ -1832,7 +1898,7 @@ typedef struct msgb mblk_t; ** are closed. Some firewalls return this error if you try to connect ** to the IDENT port (113), so you can't receive email from these hosts ** on these systems. The firewall really should use a more specific -** message such as ICMP_UNREACH_PROTOCOL or _PORT or _NET_PROHIB. If +** message such as ICMP_UNREACH_PROTOCOL or _PORT or _FILTER_PROHIB. If ** not explicitly set to zero above, default it on. */ @@ -1933,12 +1999,21 @@ typedef struct msgb mblk_t; #if !defined(S_ISLNK) && defined(S_IFLNK) # define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK) #endif +#ifndef S_IRUSR +# define S_IRUSR 0400 +#endif #ifndef S_IWUSR # define S_IWUSR 0200 #endif +#ifndef S_IRGRP +# define S_IRGRP 0040 +#endif #ifndef S_IWGRP # define S_IWGRP 0020 #endif +#ifndef S_IROTH +# define S_IROTH 0004 +#endif #ifndef S_IWOTH # define S_IWOTH 0002 #endif @@ -1960,6 +2035,13 @@ typedef struct msgb mblk_t; /* +** An "impossible" file mode to indicate that the file does not exist. +*/ + +#define ST_MODE_NOFILE 0171147 /* unlikely to occur */ + + +/* ** These are used in a few cases where we need some special ** error codes, but where the system doesn't provide something ** reasonable. They are printed in errstring. @@ -1969,7 +2051,16 @@ typedef struct msgb mblk_t; # define E_PSEUDOBASE 256 #endif -#define EOPENTIMEOUT (E_PSEUDOBASE + 0) /* timeout on open */ +#define E_SM_OPENTIMEOUT (E_PSEUDOBASE + 0) /* Timeout on file open */ +#define E_SM_NOSLINK (E_PSEUDOBASE + 1) /* Symbolic links not allowed */ +#define E_SM_NOHLINK (E_PSEUDOBASE + 2) /* Hard links not allowed */ +#define E_SM_REGONLY (E_PSEUDOBASE + 3) /* Regular files only */ +#define E_SM_ISEXEC (E_PSEUDOBASE + 4) /* Executable files not allowed */ +#define E_SM_WWDIR (E_PSEUDOBASE + 5) /* World writable directory */ +#define E_SM_GWDIR (E_PSEUDOBASE + 6) /* Group writable directory */ +#define E_SM_FILECHANGE (E_PSEUDOBASE + 7) /* File changed after open */ +#define E_SM_WWFILE (E_PSEUDOBASE + 8) /* World writable file */ +#define E_SM_GWFILE (E_PSEUDOBASE + 9) /* Group writable file */ #define E_DNSBASE (E_PSEUDOBASE + 20) /* base for DNS h_errno */ /* type of arbitrary pointer */ @@ -1981,16 +2072,8 @@ typedef struct msgb mblk_t; # include "cdefs.h" #endif -#if NAMED_BIND -# include <arpa/nameser.h> -# ifdef __svr4__ -# ifdef NOERROR -# undef NOERROR /* avoid compiler conflict with stream.h */ -# endif -# endif -# ifndef __ksr__ -extern int h_errno; -# endif +#if NAMED_BIND && !defined(__ksr__) +extern int h_errno; #endif /* @@ -2136,7 +2219,7 @@ typedef void (*sigfunc_t) __P((int)); # if (SYSLOG_BUFSIZE) > 768 # define TOBUFSIZE (SYSLOG_BUFSIZE - 512) # else -# define TOBUFSIZE 256 +# define TOBUFSIZE (SYSLOG_BUFSIZE / 2) # endif #endif @@ -2185,3 +2268,18 @@ typedef void (*sigfunc_t) __P((int)); #if !defined(NGROUPS_MAX) && defined(NGROUPS) # define NGROUPS_MAX NGROUPS /* POSIX naming convention */ #endif + +/* +** If we don't have a system syslog, simulate it. +*/ + +#if !LOG +# define LOG_EMERG 0 /* system is unusable */ +# define LOG_ALERT 1 /* action must be taken immediately */ +# define LOG_CRIT 2 /* critical conditions */ +# define LOG_ERR 3 /* error conditions */ +# define LOG_WARNING 4 /* warning conditions */ +# define LOG_NOTICE 5 /* normal but significant condition */ +# define LOG_INFO 6 /* informational */ +# define LOG_DEBUG 7 /* debug-level messages */ +#endif diff --git a/usr.sbin/sendmail/src/daemon.c b/usr.sbin/sendmail/src/daemon.c index bd8a914..41f1a72 100644 --- a/usr.sbin/sendmail/src/daemon.c +++ b/usr.sbin/sendmail/src/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -37,13 +37,17 @@ #ifndef lint #ifdef DAEMON -static char sccsid[] = "@(#)daemon.c 8.159 (Berkeley) 1/14/97 (with daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.175 (Berkeley) 6/1/97 (with daemon mode)"; #else -static char sccsid[] = "@(#)daemon.c 8.159 (Berkeley) 1/14/97 (without daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.175 (Berkeley) 6/1/97 (without daemon mode)"; #endif #endif /* not lint */ -#if DAEMON || defined(SOCK_STREAM) +#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) +# define USE_SOCK_STREAM 1 +#endif + +#if DAEMON || defined(USE_SOCK_STREAM) # include <arpa/inet.h> # if NAMED_BIND # include <resolv.h> @@ -55,6 +59,8 @@ static char sccsid[] = "@(#)daemon.c 8.159 (Berkeley) 1/14/97 (without daemon mo #if DAEMON +# include <sys/time.h> + # if IP_SRCROUTE # include <netinet/in_systm.h> # include <netinet/ip.h> @@ -166,8 +172,12 @@ getrequests(e) /* write the pid to the log file for posterity */ pidf = safefopen(PidFile, O_WRONLY|O_CREAT|O_TRUNC, 0644, - SFF_NOSLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT); - if (pidf != NULL) + SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT); + if (pidf == NULL) + { + sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile); + } + else { extern char *CommandLineArgs; @@ -200,7 +210,6 @@ getrequests(e) int savederrno; int pipefd[2]; extern bool refuseconnections(); - extern int getla(); /* see if we are rejecting connections */ (void) blocksignal(SIGALRM); @@ -234,13 +243,15 @@ getrequests(e) if (!wordinclass(jbuf, 'w')) { dumpstate("daemon lost $j"); - syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); + sm_syslog(LOG_ALERT, NOQID, + "daemon process doesn't have $j in $=w; see syslog"); abort(); } else if (j_has_dot && strchr(jbuf, '.') == NULL) { dumpstate("daemon $j lost dot"); - syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); + sm_syslog(LOG_ALERT, NOQID, + "daemon process $j lost dot; see syslog"); abort(); } } @@ -260,13 +271,29 @@ getrequests(e) log an error here; #endif (void) releasesignal(SIGALRM); - do + for (;;) { + fd_set readfds; + struct timeval timeout; + + FD_ZERO(&readfds); + FD_SET(DaemonSocket, &readfds); + timeout.tv_sec = 60; + timeout.tv_usec = 0; + + t = select(DaemonSocket + 1, &readfds, NULL, NULL, &timeout); + if (DoQueueRun) + (void) runqueue(TRUE, FALSE); + if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds)) + continue; + errno = 0; lotherend = socksize; t = accept(DaemonSocket, (struct sockaddr *)&RealHostAddr, &lotherend); - } while (t < 0 && errno == EINTR); + if (t >= 0 || errno != EINTR) + break; + } savederrno = errno; (void) blocksignal(SIGALRM); if (t < 0) @@ -381,6 +408,9 @@ getrequests(e) OutChannel = outchannel; DisConnected = FALSE; + /* open maps for check_relay ruleset */ + initmaps(FALSE, e); + /* validate the connection */ HoldErrs = TRUE; nullconn = !validate_connection(&RealHostAddr, RealHostName, e); @@ -463,10 +493,9 @@ opendaemonsocket(firsttime) saveerrno = errno; syserr("opendaemonsocket: can't create server SMTP socket"); severe: -# ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, "problem creating SMTP socket"); -# endif /* LOG */ + sm_syslog(LOG_ALERT, NOQID, + "problem creating SMTP socket"); DaemonSocket = -1; continue; } @@ -747,7 +776,7 @@ makeconnection(host, port, mci, e) register MCI *mci; ENVELOPE *e; { - register volatile int i = 0; + register volatile int addrno = 0; register volatile int s; register struct hostent *volatile hp = (struct hostent *)NULL; SOCKADDR addr; @@ -870,7 +899,7 @@ gothostent: hp->h_length); break; } - i = 1; + addrno = 1; } /* @@ -883,10 +912,9 @@ gothostent: if (sp == NULL) { -#ifdef LOG if (LogLevel > 2) - syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); -#endif + sm_syslog(LOG_ERR, NOQID, + "makeconnection: service \"smtp\" unknown"); port = htons(25); } else @@ -988,22 +1016,23 @@ gothostent: if (setjmp(CtxConnectTimeout) == 0) { + int i; + if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); else if (TimeOuts.to_connect != 0) ev = setevent(TimeOuts.to_connect, connecttimeout, 0); else ev = NULL; - if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) - { - if (ev != NULL) - clrevent(ev); + i = connect(s, (struct sockaddr *) &addr, addrlen); + sav_errno = errno; + if (ev != NULL) + clrevent(ev); + if (i >= 0) break; - } } - sav_errno = errno; - if (ev != NULL) - clrevent(ev); + else + sav_errno = errno; /* if running demand-dialed connection, try again */ if (DialDelay > 0 && firstconnect) @@ -1018,7 +1047,7 @@ gothostent: /* couldn't connect.... figure out why */ (void) close(s); - if (hp != NULL && hp->h_addr_list[i]) + if (hp != NULL && hp->h_addr_list[addrno]) { if (tTd(16, 1)) printf("Connect failed (%s); trying new address....\n", @@ -1027,14 +1056,14 @@ gothostent: { #if NETINET case AF_INET: - bcopy(hp->h_addr_list[i++], + bcopy(hp->h_addr_list[addrno++], &addr.sin.sin_addr, INADDRSZ); break; #endif default: - bcopy(hp->h_addr_list[i++], + bcopy(hp->h_addr_list[addrno++], addr.sa.sa_data, hp->h_length); break; @@ -1129,19 +1158,17 @@ myhostname(hostbuf, size) if (strchr(hostbuf, '.') == NULL && !getcanonname(hostbuf, size, TRUE)) { -#ifdef LOG - syslog(LOG_CRIT, "My unqualified host name (%s) unknown; sleeping for retry", + sm_syslog(LOG_CRIT, NOQID, + "My unqualified host name (%s) unknown; sleeping for retry", hostbuf); -#endif message("My unqualified host name (%s) unknown; sleeping for retry", hostbuf); sleep(60); if (!getcanonname(hostbuf, size, TRUE)) { -#ifdef LOG - syslog(LOG_ALERT, "unable to qualify my own domain name (%s) -- using short name", + sm_syslog(LOG_ALERT, NOQID, + "unable to qualify my own domain name (%s) -- using short name", hostbuf); -#endif message("WARNING: unable to qualify my own domain name (%s) -- using short name", hostbuf); } @@ -1181,6 +1208,9 @@ getauthinfo(fd) int i; EVENT *ev; int nleft; + struct hostent *hp; + char **ha; + bool may_be_forged; char ibuf[MAXNAME + 1]; static char hbuf[MAXNAME * 2 + 2]; @@ -1203,6 +1233,30 @@ getauthinfo(fd) RealHostName[MAXNAME - 1] = '\0'; } + /* cross check RealHostName with forward DNS lookup */ + if (anynet_ntoa(&RealHostAddr)[0] == '[') + { + /* address is not a socket */ + may_be_forged = FALSE; + } + else + { + /* try to match the reverse against the forward lookup */ + hp = gethostbyname(RealHostName); + + if (hp == NULL) + may_be_forged = TRUE; + else + { + for (ha = hp->h_addr_list; *ha != NULL; ha++) + if (bcmp(*ha, + (char *) &RealHostAddr.sin.sin_addr, + hp->h_length) == 0) + break; + may_be_forged = *ha == NULL; + } + } + if (TimeOuts.to_ident == 0) goto noident; @@ -1340,6 +1394,9 @@ noident: postident: #if IP_SRCROUTE +# ifndef GET_IPOPT_DST +# define GET_IPOPT_DST(dst) (dst) +# endif /* ** Extract IP source routing information. ** @@ -1383,21 +1440,31 @@ postident: case IPOPT_SSRR: case IPOPT_LSRR: + /* + ** Source routing. + ** o[0] is the option type (loose/strict). + ** o[1] is the length of this option, + ** including option type and + ** length. + ** o[2] is the pointer into the route + ** data. + ** o[3] begins the route data. + */ + p = &hbuf[strlen(hbuf)]; l = sizeof hbuf - (hbuf - p) - 6; snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s", *o == IPOPT_SSRR ? "!" : "", l > 240 ? 120 : l / 2, - inet_ntoa(ipopt.ipopt_dst)); + inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst))); i = strlen(p); p += i; l -= strlen(p); - /* o[1] is option length */ - j = *++o / sizeof(struct in_addr) - 1; + j = o[1] / sizeof(struct in_addr) - 1; /* q skips length and router pointer to data */ - q = o + 2; + q = &o[3]; for ( ; j >= 0; j--) { memcpy(&addr, q, sizeof(addr)); @@ -1412,7 +1479,7 @@ postident: l -= i + 1; q += sizeof(struct in_addr); } - o += *o; + o += o[1]; break; default: @@ -1433,6 +1500,11 @@ noipsr: (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", anynet_ntoa(&RealHostAddr)); } + if (may_be_forged) + { + p = &hbuf[strlen(hbuf)]; + (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)"); + } postipsr: if (tTd(9, 1)) @@ -1443,7 +1515,7 @@ postipsr: ** HOST_MAP_LOOKUP -- turn a hostname into canonical form ** ** Parameters: -** map -- a pointer to this map (unused). +** map -- a pointer to this map. ** name -- the (presumably unqualified) hostname. ** av -- unused -- for compatibility with other mapping ** functions. @@ -1457,7 +1529,8 @@ postipsr: ** Side Effects: ** Looks up the host specified in hbuf. If it is not ** the canonical name for that host, return the canonical -** name. +** name (unless MF_MATCHONLY is set, which will cause the +** status only to be returned). */ char * @@ -1498,7 +1571,16 @@ host_map_lookup(map, name, av, statp) message("851 %s: Name server timeout", shortenstring(name, 33)); } - return s->s_namecanon.nc_cname; + if (*statp != EX_OK) + return NULL; + if (bitset(MF_MATCHONLY, map->map_mflags)) + cp = map_rewrite(map, name, strlen(name), NULL); + else + cp = map_rewrite(map, + s->s_namecanon.nc_cname, + strlen(s->s_namecanon.nc_cname), + av); + return cp; } /* @@ -1532,16 +1614,12 @@ host_map_lookup(map, name, av, statp) { if (tTd(9, 1)) printf("%s\n", hbuf); + s->s_namecanon.nc_stat = EX_OK; + s->s_namecanon.nc_cname = newstr(hbuf); if (bitset(MF_MATCHONLY, map->map_mflags)) - { - cp = map_rewrite(map, name, strlen(name), av); - s->s_namecanon.nc_cname = newstr(hbuf); - } + cp = map_rewrite(map, name, strlen(name), NULL); else - { cp = map_rewrite(map, hbuf, strlen(hbuf), av); - s->s_namecanon.nc_cname = newstr(cp); - } return cp; } else @@ -1589,6 +1667,7 @@ host_map_lookup(map, name, av, statp) return (NULL); *cp = '\0'; in_addr.s_addr = inet_addr(&name[1]); + *cp = ']'; /* nope -- ask the name server */ hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); @@ -1604,9 +1683,12 @@ host_map_lookup(map, name, av, statp) } /* found a match -- copy out */ - cp = map_rewrite(map, (char *) hp->h_name, strlen(hp->h_name), av); s->s_namecanon.nc_stat = *statp = EX_OK; - s->s_namecanon.nc_cname = newstr(cp); + s->s_namecanon.nc_cname = newstr(hp->h_name); + if (bitset(MF_MATCHONLY, map->map_mflags)) + cp = map_rewrite(map, name, strlen(name), NULL); + else + cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); return cp; } @@ -1688,16 +1770,63 @@ host_map_lookup(map, name, avp, statp) char *statp; { register struct hostent *hp; + char *cp; hp = sm_gethostbyname(name); - if (hp != NULL) - return hp->h_name; - *statp = EX_NOHOST; - return NULL; + if (hp == NULL) + { + *statp = EX_NOHOST; + return NULL; + } + if (bitset(MF_MATCHONLY, map->map_mflags)) + cp = map_rewrite(map, name, strlen(name), NULL); + else + cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); + return cp; } #endif /* DAEMON */ /* +** HOST_MAP_INIT -- initialize host class structures +*/ + +bool +host_map_init(map, args) + MAP *map; + char *args; +{ + register char *p = args; + + for (;;) + { + while (isascii(*p) && isspace(*p)) + p++; + if (*p != '-') + break; + switch (*++p) + { + case 'a': + map->map_app = ++p; + break; + + case 'm': + map->map_mflags |= MF_MATCHONLY; + break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; + } + while (*p != '\0' && !(isascii(*p) && isspace(*p))) + p++; + if (*p != '\0') + *p++ = '\0'; + } + if (map->map_app != NULL) + map->map_app = newstr(map->map_app); + return TRUE; +} +/* ** ANYNET_NTOA -- convert a network address to printable form. ** ** Parameters: @@ -1707,7 +1836,7 @@ host_map_lookup(map, name, avp, statp) ** A printable version of that sockaddr. */ -#ifdef SOCK_STREAM +#ifdef USE_SOCK_STREAM #if NETLINK # include <net/if_dl.h> diff --git a/usr.sbin/sendmail/src/deliver.c b/usr.sbin/sendmail/src/deliver.c index fb6db2d..b5d5413 100644 --- a/usr.sbin/sendmail/src/deliver.c +++ b/usr.sbin/sendmail/src/deliver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 8.266 (Berkeley) 1/17/97"; +static char sccsid[] = "@(#)deliver.c 8.282 (Berkeley) 6/11/97"; #endif /* not lint */ #include "sendmail.h" @@ -76,7 +76,7 @@ sendall(e, mode) int otherowners; register ENVELOPE *ee; ENVELOPE *splitenv = NULL; - bool oldverbose = Verbose; + int oldverbose = Verbose; bool somedeliveries = FALSE; pid_t pid; extern void sendenvelope(); @@ -96,7 +96,6 @@ sendall(e, mode) } /* determine actual delivery mode */ - CurrentLA = getla(); if (mode == SM_DEFAULT) { mode = e->e_sendmode; @@ -295,6 +294,7 @@ sendall(e, mode) { extern HDR *copyheader(); extern ADDRESS *copyqueue(); + extern void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); /* ** Split this envelope into two. @@ -360,42 +360,12 @@ sendall(e, mode) } if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) - { - char df1buf[20], df2buf[20]; - - ee->e_dfp = NULL; - snprintf(df1buf, sizeof df1buf, "%s", - queuename(e, 'd')); - snprintf(df2buf, sizeof df2buf, "%s", - queuename(ee, 'd')); - if (link(df1buf, df2buf) < 0) - { - int saverrno = errno; - - syserr("sendall: link(%s, %s)", - df1buf, df2buf); - if (saverrno == EEXIST) - { - if (unlink(df2buf) < 0) - { - syserr("!sendall: unlink(%s): permanent", - df2buf); - /*NOTREACHED*/ - } - if (link(df1buf, df2buf) < 0) - { - syserr("!sendall: link(%s, %s): permanent", - df1buf, df2buf); - /*NOTREACHED*/ - } - } - } - } -#ifdef LOG + dup_queue_file(e, ee, 'd'); + openxscript(ee); if (LogLevel > 4) - syslog(LOG_INFO, "%s: clone %s, owner=%s", - ee->e_id, e->e_id, owner); -#endif + sm_syslog(LOG_INFO, ee->e_id, + "clone %s, owner=%s", + e->e_id, owner); } } @@ -420,6 +390,15 @@ sendall(e, mode) if (tTd(13, 29)) printf("No deliveries: auto-queuing\n"); mode = SM_QUEUE; + + /* treat this as a delivery in terms of counting tries */ + e->e_dtime = curtime(); + e->e_ntries++; + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + ee->e_dtime = curtime(); + ee->e_ntries++; + } } # if QUEUE @@ -462,7 +441,7 @@ sendall(e, mode) switch (mode) { case SM_VERIFY: - Verbose = TRUE; + Verbose = 2; break; case SM_QUEUE: @@ -563,6 +542,9 @@ sendall(e, mode) finis(); } + /* be sure to give error messages in child */ + QuickAbort = OnlyOneError = FALSE; + /* ** Close any cached connections. ** @@ -619,12 +601,10 @@ sendenvelope(e, mode) printf("sendenvelope(%s) e_flags=0x%lx\n", e->e_id == NULL ? "[NOQUEUE]" : e->e_id, e->e_flags); -#ifdef LOG if (LogLevel > 80) - syslog(LOG_DEBUG, "%s: sendenvelope, flags=0x%x", - e->e_id == NULL ? "[NOQUEUE]" : e->e_id, + sm_syslog(LOG_DEBUG, e->e_id, + "sendenvelope, flags=0x%x", e->e_flags); -#endif /* ** If we have had global, fatal errors, don't bother sending @@ -709,6 +689,51 @@ sendenvelope(e, mode) #endif } /* +** DUP_QUEUE_FILE -- duplicate a queue file into a split queue +** +** Parameters: +** e -- the existing envelope +** ee -- the new envelope +** type -- the queue file type (e.g., 'd') +** +** Returns: +** none +*/ + +void +dup_queue_file(e, ee, type) + struct envelope *e, *ee; + int type; +{ + char f1buf[MAXQFNAME], f2buf[MAXQFNAME]; + + ee->e_dfp = NULL; + ee->e_xfp = NULL; + snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type)); + snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type)); + if (link(f1buf, f2buf) < 0) + { + int saverrno = errno; + + syserr("sendall: link(%s, %s)", f1buf, f2buf); + if (saverrno == EEXIST) + { + if (unlink(f2buf) < 0) + { + syserr("!sendall: unlink(%s): permanent", + f2buf); + /*NOTREACHED*/ + } + if (link(f1buf, f2buf) < 0) + { + syserr("!sendall: link(%s, %s): permanent", + f1buf, f2buf); + /*NOTREACHED*/ + } + } + } +} +/* ** DOFORK -- do a fork, retrying a couple of times on failure. ** ** This MUST be a macro, since after a vfork we are running @@ -826,6 +851,7 @@ deliver(e, firstto) time_t xstart; bool suidwarn; bool anyok; /* at least one address was OK */ + bool goodmxfound = FALSE; /* at least one MX was OK */ int mpvect[2]; int rpvect[2]; char *pv[MAXPV+1]; @@ -1018,6 +1044,7 @@ deliver(e, firstto) e->e_flags |= EF_NO_BODY_RETN; to->q_status = "5.2.3"; usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); + markfailure(e, to, NULL, EX_UNAVAILABLE); giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); continue; } @@ -1294,8 +1321,11 @@ tryhost: curhost++; continue; } - strncpy(hostbuf, curhost, p - curhost); - hostbuf[p - curhost] = '\0'; + i = p - curhost; + if (i >= sizeof hostbuf) + i = sizeof hostbuf - 1; + strncpy(hostbuf, curhost, i); + hostbuf[i] = '\0'; if (*p != '\0') p++; curhost = p; @@ -1318,11 +1348,16 @@ tryhost: } mci->mci_mailer = m; if (mci->mci_exitstat != EX_OK) + { + if (mci->mci_exitstat == EX_TEMPFAIL) + goodmxfound = TRUE; continue; + } if (mci_lock_host(mci) != EX_OK) { mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); + goodmxfound = TRUE; continue; } @@ -1343,6 +1378,7 @@ tryhost: #endif if (i == EX_OK) { + goodmxfound = TRUE; mci->mci_state = MCIS_OPENING; mci_cache(mci); if (TrafficLogFile != NULL) @@ -1355,6 +1391,8 @@ tryhost: if (tTd(11, 1)) printf("openmailer: makeconnection => stat=%d, errno=%d\n", i, errno); + if (i == EX_TEMPFAIL) + goodmxfound = TRUE; mci_unlock_host(mci); } @@ -1863,7 +1901,12 @@ tryhost: for (to = tochain; to != NULL; to = to->q_tchain) { e->e_to = to->q_paddr; - if ((i = smtprcpt(to, m, mci, e)) != EX_OK) + if (strlen(to->q_paddr) + (t - tobuf) + 2 >= sizeof tobuf) + { + /* not enough room */ + continue; + } + else if ((i = smtprcpt(to, m, mci, e)) != EX_OK) { markfailure(e, to, mci, i); giveresponse(i, m, mci, ctladdr, xstart, e); @@ -1948,8 +1991,15 @@ tryhost: rcode = smtpgetstat(m, mci, e); if (rcode == EX_OK) { - strcat(tobuf, ","); - strcat(tobuf, to->q_paddr); + if (strlen(to->q_paddr) + strlen(tobuf) + 2 >= sizeof tobuf) + { + syserr("LMTP tobuf overflow"); + } + else + { + strcat(tobuf, ","); + strcat(tobuf, to->q_paddr); + } anyok = TRUE; } else @@ -1968,6 +2018,8 @@ tryhost: /* mark bad addresses */ if (rcode != EX_OK) { + if (goodmxfound && rcode == EX_NOHOST) + rcode = EX_TEMPFAIL; markfailure(e, to, mci, rcode); continue; } @@ -2084,6 +2136,7 @@ markfailure(e, q, mci, rcode) case EX_IOERR: case EX_OSERR: q->q_flags |= QQUEUEUP; + q->q_flags &= ~QDONTSEND; break; default: @@ -2203,7 +2256,7 @@ endmailer(mci, e, pv) if (mci->mci_pid == 0) return (EX_OK); -#ifdef _FFR_TIMEOUT_WAIT +#if _FFR_TIMEOUT_WAIT put a timeout around the wait #endif @@ -2428,7 +2481,6 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) time_t xstart; register ENVELOPE *e; { -# ifdef LOG register char *bp; register char *p; int l; @@ -2533,11 +2585,12 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) if (q == NULL) break; - syslog(LOG_INFO, "%s: to=%.*s [more]%s", - e->e_id, ++q - p, p, buf); + sm_syslog(LOG_INFO, e->e_id, + "to=%.*s [more]%s", + ++q - p, p, buf); p = q; } - syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); + sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf); # else /* we have a very short log buffer size */ @@ -2549,11 +2602,12 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) if (q == NULL) break; - syslog(LOG_INFO, "%s: to=%.*s [more]", - e->e_id, ++q - p, p); + sm_syslog(LOG_INFO, e->e_id, + "to=%.*s [more]", + ++q - p, p); p = q; } - syslog(LOG_INFO, "%s: to=%s", e->e_id, p); + sm_syslog(LOG_INFO, e->e_id, "to=%s", p); if (ctladdr != NULL) { @@ -2567,7 +2621,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) ctladdr->q_uid, ctladdr->q_gid); bp += strlen(bp); } - syslog(LOG_INFO, "%s: %s", e->e_id, buf); + sm_syslog(LOG_INFO, e->e_id, "%s", buf); } bp = buf; snprintf(bp, SPACELEFT(buf, bp), "delay=%s", @@ -2585,7 +2639,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name); bp += strlen(bp); } - syslog(LOG_INFO, "%s: %.1000s", e->e_id, buf); + sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); buf[0] = '\0'; bp = buf; @@ -2612,11 +2666,10 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) snprintf(buf, sizeof buf, "relay=%.100s", p); } if (buf[0] != '\0') - syslog(LOG_INFO, "%s: %.1000s", e->e_id, buf); + sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); - syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); + sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(stat, 63)); # endif /* short log buffer */ -# endif /* LOG */ } /* ** PUTFROMLINE -- output a UNIX-style from line (or whatever) @@ -2688,7 +2741,7 @@ putfromline(mci, e) } } expand(template, buf, sizeof buf, e); - putxline(buf, mci, PXLF_NOTHINGSPECIAL); + putxline(buf, strlen(buf), mci, PXLF_NOTHINGSPECIAL); } /* ** PUTBODY -- put the body of a message. @@ -2828,7 +2881,7 @@ putbody(mci, e, separator) switch (ostate) { case OS_HEAD: -#ifdef _FFR_NONULLS +#if _FFR_NONULLS if (c == '\0' && bitnset(M_NONULLS, mci->mci_mailer->m_flags)) break; @@ -2933,7 +2986,7 @@ putbody(mci, e, separator) ostate = OS_CR; continue; } -#ifdef _FFR_NONULLS +#if _FFR_NONULLS if (c == '\0' && bitnset(M_NONULLS, mci->mci_mailer->m_flags)) break; @@ -3214,7 +3267,7 @@ mailfile(filename, ctladdr, sfflags, e) if (setuid(RealUid) < 0 && suidwarn) syserr("mailfile: setuid(%ld) failed", (long) RealUid); - sfflags |= SFF_NOPATHCHECK; + sfflags |= SFF_NOPATHCHECK|SFF_NOLINK; sfflags &= ~SFF_OPENASROOT; f = safefopen(filename, oflags, FileMode, sfflags); if (f == NULL) @@ -3252,6 +3305,7 @@ mailfile(filename, ctladdr, sfflags, e) #endif (void) xfclose(f, "mailfile", filename); (void) fflush(stdout); + setuid(RealUid); exit(ExitStat); /*NOTREACHED*/ } diff --git a/usr.sbin/sendmail/src/domain.c b/usr.sbin/sendmail/src/domain.c index ca2d8f8..741a7cd 100644 --- a/usr.sbin/sendmail/src/domain.c +++ b/usr.sbin/sendmail/src/domain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1986, 1995, 1996 Eric P. Allman + * Copyright (c) 1986, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if NAMED_BIND -static char sccsid[] = "@(#)domain.c 8.64 (Berkeley) 10/30/96 (with name server)"; +static char sccsid[] = "@(#)domain.c 8.67 (Berkeley) 4/9/97 (with name server)"; #else -static char sccsid[] = "@(#)domain.c 8.64 (Berkeley) 10/30/96 (without name server)"; +static char sccsid[] = "@(#)domain.c 8.67 (Berkeley) 4/9/97 (without name server)"; #endif #endif /* not lint */ @@ -197,6 +197,7 @@ getmxrr(host, mxhosts, droplocalhost, rcode) goto punt; case TRY_AGAIN: + case -1: /* couldn't connect to the name server */ if (fallbackMX != NULL) { @@ -880,6 +881,7 @@ gethostalias(host) fclose(fp); return NULL; } + fclose(fp); /* got a match; extract the equivalent name */ while (*p != '\0' && isascii(*p) && isspace(*p)) diff --git a/usr.sbin/sendmail/src/headers.c b/usr.sbin/sendmail/src/headers.c index 310f45f..940faf7 100644 --- a/usr.sbin/sendmail/src/headers.c +++ b/usr.sbin/sendmail/src/headers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,13 +33,36 @@ */ #ifndef lint -static char sccsid[] = "@(#)headers.c 8.103 (Berkeley) 12/11/96"; +static char sccsid[] = "@(#)headers.c 8.110 (Berkeley) 6/14/97"; #endif /* not lint */ # include <errno.h> # include "sendmail.h" /* +** SETUPHEADERS -- initialize headers in symbol table +** +** Parameters: +** none +** +** Returns: +** none +*/ + +void +setupheaders() +{ + struct hdrinfo *hi; + STAB *s; + + for (hi = HdrInfo; hi->hi_field != NULL; hi++) + { + s = stab(hi->hi_field, ST_HEADER, ST_ENTER); + s->s_header.hi_flags = hi->hi_flags; + s->s_header.hi_ruleset = NULL; + } +} +/* ** CHOMPHEADER -- process and save a header line. ** ** Called by collect and by readcf to deal with header lines. @@ -58,6 +81,8 @@ static char sccsid[] = "@(#)headers.c 8.103 (Berkeley) 12/11/96"; ** Contents of 'line' are destroyed. */ +struct hdrinfo NormalHeader = { NULL, 0, NULL }; + int chompheader(line, def, hdrp, e) char *line; @@ -70,9 +95,10 @@ chompheader(line, def, hdrp, e) HDR **hp; char *fname; char *fvalue; - struct hdrinfo *hi; bool cond = FALSE; bool headeronly; + STAB *s; + struct hdrinfo *hi; BITMAP mopts; if (tTd(31, 6)) @@ -116,7 +142,7 @@ chompheader(line, def, hdrp, e) if (*p++ != ':' || fname == fvalue) { syserr("553 header syntax error, line \"%s\"", line); - return (0); + return 0; } *fvalue = '\0'; fvalue = p; @@ -129,19 +155,44 @@ chompheader(line, def, hdrp, e) if (strlen(fname) > 100) return H_EOH; - /* see if it is a known type */ - for (hi = HdrInfo; hi->hi_field != NULL; hi++) +#if _FFR_HEADER_RSCHECK + /* check to see if it represents a ruleset call */ + if (def) { - if (strcasecmp(hi->hi_field, fname) == 0) - break; + char hbuf[50]; + + (void) expand(fvalue, hbuf, sizeof hbuf, e); + for (p = hbuf; isascii(*p) && isspace(*p); ) + p++; + if ((*p++ & 0377) == CALLSUBR) + { + auto char *endp; + + if (strtorwset(p, &endp, ST_ENTER) > 0) + { + *endp = '\0'; + s = stab(fname, ST_HEADER, ST_ENTER); + s->s_header.hi_ruleset = newstr(p); + } + return 0; + } } +#endif + + /* see if it is a known type */ + s = stab(fname, ST_HEADER, ST_FIND); + if (s != NULL) + hi = &s->s_header; + else + hi = &NormalHeader; if (tTd(31, 9)) { - if (hi->hi_field == NULL) - printf("no header match\n"); + if (s == NULL) + printf("no header flags match\n"); else - printf("header match, hi_flags=%x\n", hi->hi_flags); + printf("header match, flags=%x, ruleset=%s\n", + hi->hi_flags, hi->hi_ruleset); } /* see if this is a resent message */ @@ -155,7 +206,7 @@ chompheader(line, def, hdrp, e) /* if this means "end of header" quit now */ if (bitset(H_EOH, hi->hi_flags)) - return (hi->hi_flags); + return hi->hi_flags; /* ** Horrible hack to work around problem with Lotus Notes SMTP @@ -172,6 +223,13 @@ chompheader(line, def, hdrp, e) } /* + ** If there is a check ruleset, verify it against the header. + */ + + if (!def && hi->hi_ruleset != NULL) + (void) rscheck(hi->hi_ruleset, fvalue, NULL, e); + + /* ** Drop explicit From: if same as what we would generate. ** This is to make MH (which doesn't always give a full name) ** insert the full name information in all circumstances. @@ -191,7 +249,7 @@ chompheader(line, def, hdrp, e) if (e->e_from.q_paddr != NULL && (strcmp(fvalue, e->e_from.q_paddr) == 0 || strcmp(fvalue, e->e_from.q_user) == 0)) - return (hi->hi_flags); + return hi->hi_flags; } /* delete default value for this header */ @@ -232,7 +290,7 @@ chompheader(line, def, hdrp, e) e->e_flags &= ~EF_OLDSTYLE; } - return (h->h_flags); + return h->h_flags; } /* ** ADDHEADER -- add a header entry to the end of the queue. @@ -258,15 +316,11 @@ addheader(field, value, hdrlist) HDR **hdrlist; { register HDR *h; - register struct hdrinfo *hi; + STAB *s; HDR **hp; /* find info struct */ - for (hi = HdrInfo; hi->hi_field != NULL; hi++) - { - if (strcasecmp(field, hi->hi_field) == 0) - break; - } + s = stab(field, ST_HEADER, ST_FIND); /* find current place in list -- keep back pointer? */ for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) @@ -280,7 +334,9 @@ addheader(field, value, hdrlist) h->h_field = field; h->h_value = newstr(value); h->h_link = *hp; - h->h_flags = hi->hi_flags | H_DEFAULT; + h->h_flags = H_DEFAULT; + if (s != NULL) + h->h_flags |= s->s_header.hi_flags; clrbitmap(h->h_mflags); *hp = h; } @@ -577,10 +633,8 @@ eatheader(e, full) ** Log collection information. */ -# ifdef LOG if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) logsender(e, msgid); -# endif /* LOG */ e->e_flags &= ~EF_LOGSENDER; } /* @@ -599,7 +653,6 @@ logsender(e, msgid) register ENVELOPE *e; char *msgid; { -# ifdef LOG char *name; register char *sbp; register char *p; @@ -663,37 +716,39 @@ logsender(e, msgid) p = macvalue('r', e); if (p != NULL) (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p); - syslog(LOG_INFO, "%s: %.850s, relay=%.100s", - e->e_id, sbuf, name); + sm_syslog(LOG_INFO, e->e_id, + "%.850s, relay=%.100s", + sbuf, name); # else /* short syslog buffer */ - syslog(LOG_INFO, "%s: from=%s", - e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : - shortenstring(e->e_from.q_paddr, 83)); - syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", - e->e_id, e->e_msgsize, e->e_class, - e->e_msgpriority, e->e_nrcpts); + sm_syslog(LOG_INFO, e->e_id, + "from=%s", + e->e_from.q_paddr == NULL ? "<NONE>" + : shortenstring(e->e_from.q_paddr, 83)); + sm_syslog(LOG_INFO, e->e_id, + "size=%ld, class=%ld, pri=%ld, nrcpts=%d", + e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); if (msgid != NULL) - syslog(LOG_INFO, "%s: msgid=%s", - e->e_id, shortenstring(mbuf, 83)); + sm_syslog(LOG_INFO, e->e_id, + "msgid=%s", + shortenstring(mbuf, 83)); sbp = sbuf; - snprintf(sbp, SPACELEFT(sbuf, sbp), "%s:", e->e_id); - sbp += strlen(sbp); + *sbp = '\0'; if (e->e_bodytype != NULL) { - snprintf(sbp, SPACELEFT(sbuf, sbp), " bodytype=%.20s,", e->e_bodytype); + snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype); sbp += strlen(sbp); } p = macvalue('r', e); if (p != NULL) { - snprintf(sbp, SPACELEFT(sbuf, sbp), " proto=%.20s,", p); + snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p); sbp += strlen(sbp); } - syslog(LOG_INFO, "%.400s relay=%.100s", sbuf, name); + sm_syslog(LOG_INFO, e->e_id, + "%.400srelay=%.100s", sbuf, name); # endif -# endif } /* ** PRIENCODE -- encode external priority names into internal values. @@ -788,7 +843,7 @@ crackaddr(addr) */ bp = bufhead = buf; - buflim = &buf[sizeof buf - 6]; + buflim = &buf[sizeof buf - 7]; p = addrhead = addr; copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; bracklev = 0; @@ -1165,7 +1220,7 @@ putheader(mci, hdr, e) /* suppress return receipts if requested */ if (bitset(H_RECEIPTTO, h->h_flags) && -#if _FFR_DSN_RRT +#if _FFR_DSN_RRT_OPTION (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) #else bitset(EF_NORECEIPT, e->e_flags)) @@ -1181,7 +1236,7 @@ putheader(mci, hdr, e) { expand(p, buf, sizeof buf, e); p = buf; - if (p == NULL || *p == '\0') + if (*p == '\0') { if (tTd(34, 11)) printf(" (skipped -- null value)\n"); @@ -1275,7 +1330,7 @@ put_vanilla_header(h, v, mci) char obuf[MAXLINE]; putflags = 0; -#ifdef _FFR_7BITHDRS +#if _FFR_7BITHDRS if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) putflags |= PXLF_STRIP8BIT; #endif @@ -1290,7 +1345,7 @@ put_vanilla_header(h, v, mci) l = sizeof obuf - (obp - obuf); snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); - putxline(obuf, mci, putflags); + putxline(obuf, strlen(obuf), mci, putflags); v += l + 1; obp = obuf; if (*v != ' ' && *v != '\t') @@ -1298,7 +1353,7 @@ put_vanilla_header(h, v, mci) } snprintf(obp, SPACELEFT(obuf, obp), "%.*s", sizeof obuf - (obp - obuf) - 1, v); - putxline(obuf, mci, putflags); + putxline(obuf, strlen(obuf), mci, putflags); } /* ** COMMAIZE -- output a header field, making a comma-translated list. @@ -1340,7 +1395,7 @@ commaize(h, p, oldstyle, mci, e) if (tTd(14, 2)) printf("commaize(%s: %s)\n", h->h_field, p); -#ifdef _FFR_7BITHDRS +#if _FFR_7BITHDRS if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) putflags |= PXLF_STRIP8BIT; #endif @@ -1348,6 +1403,8 @@ commaize(h, p, oldstyle, mci, e) obp = obuf; (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field); opos = strlen(h->h_field) + 2; + if (opos > 202) + opos = 202; obp += opos; omax = mci->mci_mailer->m_linelimit - 2; if (omax < 0 || omax > 78) @@ -1441,7 +1498,7 @@ commaize(h, p, oldstyle, mci, e) if (opos > omax && !firstone) { snprintf(obp, SPACELEFT(obuf, obp), ",\n"); - putxline(obuf, mci, putflags); + putxline(obuf, strlen(obuf), mci, putflags); obp = obuf; (void) strcpy(obp, " "); opos = strlen(obp); @@ -1460,7 +1517,7 @@ commaize(h, p, oldstyle, mci, e) *p = savechar; } *obp = '\0'; - putxline(obuf, mci, putflags); + putxline(obuf, strlen(obuf), mci, putflags); } /* ** COPYHEADER -- copy header list diff --git a/usr.sbin/sendmail/src/main.c b/usr.sbin/sendmail/src/main.c index 193ba54..b9be725 100644 --- a/usr.sbin/sendmail/src/main.c +++ b/usr.sbin/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -39,7 +39,7 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.230 (Berkeley) 1/17/97"; +static char sccsid[] = "@(#)main.c 8.246 (Berkeley) 6/11/97"; #endif /* not lint */ #define _DEFINE @@ -62,13 +62,8 @@ char edata, end; ** turn calls a bunch of mail servers that do the real work of ** delivering the mail. ** -** Sendmail is driven by tables read in from /usr/lib/sendmail.cf -** (read by readcf.c). Some more static configuration info, -** including some code that you may want to tailor for your -** installation, is in conf.c. You may also want to touch -** daemon.c (if you have some other IPC mechanism), acct.c -** (to change your accounting), names.c (to adjust the name -** server mechanism). +** Sendmail is driven by settings read in from /etc/sendmail.cf +** (read by readcf.c). ** ** Usage: ** /usr/lib/sendmail [flags] addr ... @@ -82,7 +77,7 @@ char edata, end; ** International Computer Science Institute ** (11/88 - 9/89). ** UCB/Mammoth Project (10/89 - 7/95). -** InReference, Inc. (8/95 - present). +** InReference, Inc. (8/95 - 1/97). ** The support of the my employers is gratefully acknowledged. ** Few of them (Britton-Lee in particular) have had ** anything to gain from my involvement in this project. @@ -99,6 +94,10 @@ char *CommandLineArgs; /* command line args for pid file */ bool Warn_Q_option = FALSE; /* warn about Q option use */ char **SaveArgv; /* argument vector for re-execing */ +#ifdef NGROUPS_MAX +GIDSET_T InitialGidSet[NGROUPS_MAX]; +#endif + static void obsolete(); extern void printmailer __P((MAILER *)); extern void tTflag __P((char *)); @@ -219,7 +218,7 @@ main(argc, argv, envp) } errno = 0; -#ifdef LOG +#if LOG # ifdef LOG_MAIL openlog("sendmail", LOG_PID, LOG_MAIL); # else @@ -229,6 +228,15 @@ main(argc, argv, envp) tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); +#ifdef NGROUPS_MAX + /* save initial group set for future checks */ + i = getgroups(NGROUPS_MAX, InitialGidSet); + if (i == 0) + InitialGidSet[0] = (GID_T) -1; + while (i < NGROUPS_MAX) + InitialGidSet[i++] = InitialGidSet[0]; +#endif + /* drop group id privileges (RunAsUser not yet set) */ drop_privileges(); @@ -489,9 +497,6 @@ main(argc, argv, envp) #endif } - /* probe interfaces and locate any additional names */ - load_if_names(); - /* current time */ define('b', arpadate((char *) NULL), CurEnv); @@ -828,6 +833,10 @@ main(argc, argv, envp) expand("\201m", jbuf, sizeof jbuf, CurEnv); setclass('m', jbuf); + /* probe interfaces and locate any additional names */ + if (!DontProbeInterfaces) + load_if_names(); + if (tTd(0, 1)) { printf("\n============ SYSTEM IDENTITY (after readcf) ============"); @@ -880,6 +889,10 @@ main(argc, argv, envp) setuserenv("TZ", NULL); tzset(); + /* be sure we don't pick up bogus HOSTALIASES environment variable */ + if (queuemode && RealUid != 0) + (void) unsetenv("HOSTALIASES"); + /* check for sane configuration level */ if (ConfigLevel > MAXCONFIGLEVEL) { @@ -904,13 +917,12 @@ main(argc, argv, envp) /* check for permissions */ if ((OpMode == MD_DAEMON || OpMode == MD_PURGESTAT) && RealUid != 0) { -#ifdef LOG if (LogLevel > 1) - syslog(LOG_ALERT, "user %d attempted to %s", + sm_syslog(LOG_ALERT, NOQID, + "user %d attempted to %s", RealUid, OpMode == MD_DAEMON ? "run daemon" : "purge host status"); -#endif usrerr("Permission denied"); exit(EX_USAGE); } @@ -923,6 +935,8 @@ main(argc, argv, envp) case MD_TEST: /* don't have persistent host status in test mode */ HostStatDir = NULL; + Verbose = 2; + CurEnv->e_errormode = EM_PRINT; break; case MD_FGDAEMON: @@ -938,10 +952,9 @@ main(argc, argv, envp) GrabTo = FALSE; /* arrange to restart on hangup signal */ -#ifdef LOG if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') - syslog(LOG_WARNING, "daemon invoked without full pathname; kill -1 won't work"); -#endif + sm_syslog(LOG_WARNING, NOQID, + "daemon invoked without full pathname; kill -1 won't work"); setsignal(SIGHUP, sighup); /* workaround: can't seem to release the signal in the parent */ @@ -949,7 +962,8 @@ main(argc, argv, envp) break; case MD_INITALIAS: - Verbose = TRUE; + Verbose = 2; + CurEnv->e_errormode = EM_PRINT; /* fall through... */ case MD_PRINT: @@ -1088,17 +1102,23 @@ main(argc, argv, envp) #endif /* operate in queue directory */ - if (OpMode == MD_TEST) - /* nothing -- just avoid further if clauses */ ; - else if (QueueDir == NULL) + if (QueueDir == NULL) { - syserr("QueueDirectory (Q) option must be set"); - ExitStat = EX_CONFIG; + if (OpMode != MD_TEST) + { + syserr("QueueDirectory (Q) option must be set"); + ExitStat = EX_CONFIG; + } } - else if (chdir(QueueDir) < 0) + else { - syserr("cannot chdir(%s)", QueueDir); - ExitStat = EX_CONFIG; + /* test path to get warning messages */ + (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE); + if (OpMode != MD_TEST && chdir(QueueDir) < 0) + { + syserr("cannot chdir(%s)", QueueDir); + ExitStat = EX_CONFIG; + } } /* check host status directory for validity */ @@ -1226,7 +1246,7 @@ main(argc, argv, envp) SIGFUNC_DECL intindebug __P((int)); if (isatty(fileno(stdin))) - Verbose = TRUE; + Verbose = 2; if (Verbose) { @@ -1261,7 +1281,6 @@ main(argc, argv, envp) if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) { - (void) unsetenv("HOSTALIASES"); (void) runqueue(FALSE, Verbose); finis(); } @@ -1305,9 +1324,8 @@ main(argc, argv, envp) if (tTd(0, 1)) strcat(dtype, "+debugging"); -#ifdef LOG - syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1); -#endif + sm_syslog(LOG_INFO, NOQID, + "starting daemon (%s): %s", Version, dtype + 1); #ifdef XLA xla_create_file(); #endif @@ -1317,8 +1335,14 @@ main(argc, argv, envp) { (void) runqueue(TRUE, FALSE); if (OpMode != MD_DAEMON) + { for (;;) + { pause(); + if (DoQueueRun) + (void) runqueue(TRUE, FALSE); + } + } } # endif /* QUEUE */ dropenvelope(CurEnv, TRUE); @@ -1402,7 +1426,7 @@ main(argc, argv, envp) /* collect body for UUCP return */ if (OpMode != MD_VERIFY) - collect(InChannel, FALSE, FALSE, NULL, CurEnv); + collect(InChannel, FALSE, NULL, CurEnv); finis(); } @@ -1423,8 +1447,21 @@ main(argc, argv, envp) CurEnv->e_to = NULL; if (OpMode != MD_VERIFY || GrabTo) { + long savedflags = CurEnv->e_flags & EF_FATALERRS; + CurEnv->e_flags |= EF_GLOBALERRS; - collect(InChannel, FALSE, FALSE, NULL, CurEnv); + CurEnv->e_flags &= ~EF_FATALERRS; + collect(InChannel, FALSE, NULL, CurEnv); + + /* bail out if there were fatal errors in collect */ + if (OpMode != MD_VERIFY && bitset(EF_FATALERRS, CurEnv->e_flags)) + { + CurEnv->e_flags |= EF_CLRQUEUE; + finis(); + /*NOTREACHED*/ + return -1; + } + CurEnv->e_flags |= savedflags; } errno = 0; @@ -1443,6 +1480,7 @@ main(argc, argv, envp) printaddr(&CurEnv->e_from, FALSE); } CurEnv->e_to = NULL; + CurrentLA = getla(); sendall(CurEnv, SM_DEFAULT); /* @@ -1493,6 +1531,13 @@ finis() if (tTd(2, 9)) printopenfds(FALSE); + /* if we fail in finis(), just exit */ + if (setjmp(TopFrame) != 0) + { + /* failed -- just give it up */ + goto forceexit; + } + /* clean up temp files */ CurEnv->e_to = NULL; if (CurEnv->e_id != NULL) @@ -1507,10 +1552,11 @@ finis() # endif /* and exit */ -# ifdef LOG + forceexit: if (LogLevel > 78) - syslog(LOG_DEBUG, "finis, pid=%d", getpid()); -# endif /* LOG */ + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "finis, pid=%d", + getpid()); if (ExitStat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) ExitStat = EX_OK; @@ -1540,11 +1586,8 @@ SIGFUNC_DECL intsig(sig) int sig; { -#ifdef LOG if (LogLevel > 79) - syslog(LOG_DEBUG, "%s: interrupt", - CurEnv->e_id == NULL ? "[NOQUEUE]" : CurEnv->e_id); -#endif + sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); FileName = NULL; unlockqueue(CurEnv); #ifdef XLA @@ -1665,11 +1708,10 @@ disconnect(droplev, e) printf("don't\n"); return; } -#ifdef LOG if (LogLevel > 93) - syslog(LOG_DEBUG, "%s: disconnect level %d", - e->e_id == NULL ? "[NOQUEUE]" : e->e_id, droplev); -#endif + sm_syslog(LOG_DEBUG, e->e_id, + "disconnect level %d", + droplev); /* be sure we don't get nasty signals */ (void) setsignal(SIGINT, SIG_IGN); @@ -1678,7 +1720,7 @@ disconnect(droplev, e) /* we can't communicate with our caller, so.... */ HoldErrs = TRUE; CurEnv->e_errormode = EM_MAIL; - Verbose = FALSE; + Verbose = 0; DisConnected = TRUE; /* all input from /dev/null */ @@ -1719,10 +1761,10 @@ disconnect(droplev, e) checkfd012("disconnect"); #endif -# ifdef LOG if (LogLevel > 71) - syslog(LOG_DEBUG, "in background, pid=%d", getpid()); -# endif /* LOG */ + sm_syslog(LOG_DEBUG, e->e_id, + "in background, pid=%d", + getpid()); errno = 0; } @@ -1822,11 +1864,10 @@ auth_warning(e, msg, va_alist) vsnprintf(p, SPACELEFT(buf, p), msg, ap); VA_END; addheader("X-Authentication-Warning", buf, &e->e_header); -#ifdef LOG if (LogLevel > 3) - syslog(LOG_INFO, "%s: Authentication-Warning: %.400s", - e->e_id == NULL ? "[NOQUEUE]" : e->e_id, buf); -#endif + sm_syslog(LOG_INFO, e->e_id, + "Authentication-Warning: %.400s", + buf); } } /* @@ -1916,22 +1957,23 @@ void dumpstate(when) char *when; { -#ifdef LOG register char *j = macvalue('j', CurEnv); int rs; - syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---", + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "--- dumping state on %s: $j = %s ---", when, j == NULL ? "<NULL>" : j); if (j != NULL) { if (!wordinclass(j, 'w')) - syslog(LOG_DEBUG, "*** $j not in $=w ***"); + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "*** $j not in $=w ***"); } - syslog(LOG_DEBUG, "CurChildren = %d", CurChildren); - syslog(LOG_DEBUG, "--- open file descriptors: ---"); + sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); + sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); printopenfds(TRUE); - syslog(LOG_DEBUG, "--- connection cache: ---"); + sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); mci_dump_all(TRUE); rs = strtorwset("debug_dumpstate", NULL, ST_FIND); if (rs > 0) @@ -1942,14 +1984,13 @@ dumpstate(when) pv[0] = NULL; stat = rewrite(pv, rs, 0, CurEnv); - syslog(LOG_DEBUG, + sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- ruleset debug_dumpstate returns stat %d, pv: ---", stat); for (pvp = pv; *pvp != NULL; pvp++) - syslog(LOG_DEBUG, "%s", *pvp); + sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); } - syslog(LOG_DEBUG, "--- end of state dump ---"); -#endif + sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); } @@ -1968,31 +2009,24 @@ sighup(sig) { if (SaveArgv[0][0] != '/') { -#ifdef LOG if (LogLevel > 3) - syslog(LOG_INFO, "could not restart: need full path"); -#endif + sm_syslog(LOG_INFO, NOQID, "could not restart: need full path"); exit(EX_OSFILE); } -#ifdef LOG if (LogLevel > 3) - syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]); -#endif + sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]); + alarm(0); releasesignal(SIGHUP); if (setgid(RealGid) < 0 || setuid(RealUid) < 0) { -#ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, "could not set[ug]id(%d, %d): %m", + sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m", RealUid, RealGid); -#endif exit(EX_OSERR); } execv(SaveArgv[0], (ARGV_T) SaveArgv); -#ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]); -#endif + sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]); exit(EX_OSFILE); } /* @@ -2285,6 +2319,11 @@ testmodeline(line, e) printf("Map named \"%s\" not found\n", p); return; } + if (!bitset(MF_OPEN, map->s_map.map_mflags)) + { + printf("Map named \"%s\" not open\n", p); + return; + } printf("map_lookup: %s (%s) ", p, q); p = (*map->s_map.map_class->map_lookup) (&map->s_map, q, NULL, &rcode); diff --git a/usr.sbin/sendmail/src/mime.c b/usr.sbin/sendmail/src/mime.c index 999c5ab..3e5a610 100644 --- a/usr.sbin/sendmail/src/mime.c +++ b/usr.sbin/sendmail/src/mime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1996 Eric P. Allman + * Copyright (c) 1994, 1996-1997 Eric P. Allman * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * @@ -36,7 +36,7 @@ # include <string.h> #ifndef lint -static char sccsid[] = "@(#)mime.c 8.54 (Berkeley) 1/14/97"; +static char sccsid[] = "@(#)mime.c 8.59 (Berkeley) 5/6/97"; #endif /* not lint */ /* @@ -259,10 +259,10 @@ mime8to7(mci, header, e, boundaries, flags) if (strcasecmp(argv[i].field, "boundary") == 0) break; } - if (i >= argc) + if (i >= argc || argv[i].value == NULL) { - syserr("mime8to7: Content-Type: \"%s\": missing boundary", - p); + syserr("mime8to7: Content-Type: \"%s\": %s boundary", + i >= argc ? "missing" : "bogus", p); p = "---"; /* avoid bounce loops */ @@ -311,7 +311,7 @@ mime8to7(mci, header, e, boundaries, flags) bt = mimeboundary(buf, boundaries); if (bt != MBT_NOTSEP) break; - putxline(buf, mci, PXLF_MAPFROM|PXLF_STRIP8BIT); + putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT); if (tTd(43, 99)) printf(" ...%s", buf); } @@ -325,7 +325,7 @@ mime8to7(mci, header, e, boundaries, flags) putline(buf, mci); if (tTd(43, 35)) printf(" ...%s\n", buf); - collect(e->e_dfp, FALSE, FALSE, &hdr, e); + collect(e->e_dfp, FALSE, &hdr, e); if (tTd(43, 101)) putline("+++after collect", mci); putheader(mci, hdr, e); @@ -346,7 +346,7 @@ mime8to7(mci, header, e, boundaries, flags) bt = mimeboundary(buf, boundaries); if (bt != MBT_NOTSEP) break; - putxline(buf, mci, PXLF_MAPFROM|PXLF_STRIP8BIT); + putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT); if (tTd(43, 99)) printf(" ...%s", buf); } @@ -377,7 +377,7 @@ mime8to7(mci, header, e, boundaries, flags) putline("", mci); mci->mci_flags |= MCIF_INMIME; - collect(e->e_dfp, FALSE, FALSE, &hdr, e); + collect(e->e_dfp, FALSE, &hdr, e); if (tTd(43, 101)) putline("+++after collect", mci); putheader(mci, hdr, e); @@ -1048,8 +1048,8 @@ mime7to8(mci, header, e) if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) fbufp++; - *fbufp = '\0'; - putline((char *) fbuf, mci); + putxline((char *) fbuf, fbufp - fbuf, + mci, PXLF_MAPFROM); fbufp = fbuf; } if (c3 == '=') @@ -1061,8 +1061,8 @@ mime7to8(mci, header, e) if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) fbufp++; - *fbufp = '\0'; - putline((char *) fbuf, mci); + putxline((char *) fbuf, fbufp - fbuf, + mci, PXLF_MAPFROM); fbufp = fbuf; } if (c4 == '=') @@ -1074,8 +1074,8 @@ mime7to8(mci, header, e) if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) fbufp++; - *fbufp = '\0'; - putline((char *) fbuf, mci); + putxline((char *) fbuf, fbufp - fbuf, + mci, PXLF_MAPFROM); fbufp = fbuf; } } @@ -1090,7 +1090,9 @@ mime7to8(mci, header, e) &fbuf[MAXLINE] - fbufp) == 0) continue; - putline((char *) fbuf, mci); + if (fbufp - fbuf > 0) + putxline((char *) fbuf, fbufp - fbuf - 1, mci, + PXLF_MAPFROM); fbufp = fbuf; } } @@ -1099,7 +1101,7 @@ mime7to8(mci, header, e) if (fbufp > fbuf) { *fbufp = '\0'; - putline((char *) fbuf, mci); + putxline((char *) fbuf, fbufp - fbuf, mci, PXLF_MAPFROM); } if (tTd(43, 3)) printf("\t\t\tmime7to8 => %s to 8bit done\n", cte); diff --git a/usr.sbin/sendmail/src/parseaddr.c b/usr.sbin/sendmail/src/parseaddr.c index a10c329..258e0a9 100644 --- a/usr.sbin/sendmail/src/parseaddr.c +++ b/usr.sbin/sendmail/src/parseaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)parseaddr.c 8.115 (Berkeley) 11/24/96"; +static char sccsid[] = "@(#)parseaddr.c 8.128 (Berkeley) 6/14/97"; #endif /* not lint */ # include "sendmail.h" @@ -220,6 +220,11 @@ invalidaddr(addr, delimptr) if (savedelim != '\0') *delimptr = '\0'; } + if (strlen(addr) > TOBUFSIZE - 2) + { + usrerr("553 Address too long (%d bytes max)", TOBUFSIZE - 2); + goto failure; + } for (; *addr != '\0'; addr++) { if ((*addr & 0340) == 0200) @@ -233,6 +238,7 @@ invalidaddr(addr, delimptr) } setstat(EX_USAGE); usrerr("553 Address contained invalid control characters"); +failure: if (delimptr != NULL && savedelim != '\0') *delimptr = savedelim; return TRUE; @@ -756,6 +762,7 @@ rewrite(pvp, ruleset, reclevel, e) struct match mlist[MAXMATCH]; /* stores match on LHS */ char *npvp[MAXATOM+1]; /* temporary space for rebuild */ extern int callsubr __P((char**, int, ENVELOPE *)); + extern int sm_strcasecmp __P((char *, char *)); if (OpMode == MD_TEST || tTd(21, 1)) { @@ -930,7 +937,7 @@ rewrite(pvp, ruleset, reclevel, e) default: /* must have exact match */ - if (strcasecmp(rp, ap)) + if (sm_strcasecmp(rp, ap)) goto backup; avp++; break; @@ -1436,7 +1443,7 @@ map_lookup(map, key, argvect, pstat, e) map->s_name, key, errno); if (e->e_message == NULL) { - char mbuf[300]; + char mbuf[320]; snprintf(mbuf, sizeof mbuf, "%.80s map: lookup (%s): deferred", @@ -2106,6 +2113,10 @@ remotename(name, m, flags, pstat, e) ** none. */ +#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ + Q_PINGFLAGS|QHASNOTIFY|\ + QRELAYED|QEXPANDED|QDELIVERED|QDELAYED) + void maplocaluser(a, sendq, aliaslevel, e) register ADDRESS *a; @@ -2127,6 +2138,10 @@ maplocaluser(a, sendq, aliaslevel, e) if (pvp == NULL) return; + define('h', a->q_host, e); + define('u', a->q_user, e); + define('z', a->q_home, e); + if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) { a->q_flags |= QQUEUEUP; @@ -2139,7 +2154,16 @@ maplocaluser(a, sendq, aliaslevel, e) /* if non-null, mailer destination specified -- has it changed? */ a1 = buildaddr(pvp, NULL, 0, e); if (a1 == NULL || sameaddr(a, a1)) + { + if (a1 != NULL) + free(a1); return; + } + + /* make new address take on flags and print attributes of old */ + a1->q_flags &= ~Q_COPYFLAGS; + a1->q_flags |= a->q_flags & Q_COPYFLAGS; + a1->q_paddr = a->q_paddr; /* mark old address as dead; insert new address */ a->q_flags |= QDONTSEND; @@ -2324,6 +2348,8 @@ rscheck(rwset, p1, p2, e) int rsno; auto ADDRESS a1; bool saveQuickAbort = QuickAbort; + bool saveSuprErrs = SuprErrs; + bool saveOnlyOneError = OnlyOneError; char buf0[MAXLINE]; char pvpbuf[PSBUFSIZE]; extern char MsgBuf[]; @@ -2360,44 +2386,52 @@ rscheck(rwset, p1, p2, e) } (void) snprintf(buf, bufsize, "%s", p1); } + SuprErrs = TRUE; + OnlyOneError = QuickAbort = FALSE; pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); + SuprErrs = saveSuprErrs; if (pvp == NULL) { + syserr("rscheck: cannot prescan input: \"%s\"", + shortenstring(buf, 203)); rstat = EX_DATAERR; goto finis; } (void) rewrite(pvp, rsno, 0, e); if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || pvp[1] == NULL || strcmp(pvp[1], "error") != 0) - return EX_OK; + { + rstat = EX_OK; + goto finis; + } /* got an error -- process it */ saveexitstat = ExitStat; - QuickAbort = FALSE; (void) buildaddr(pvp, &a1, 0, e); - QuickAbort = saveQuickAbort; rstat = ExitStat; ExitStat = saveexitstat; -#ifdef LOG if (LogLevel >= 4) { if (p2 == NULL) - syslog(LOG_NOTICE, "Ruleset %s (%s) rejection: %s", + sm_syslog(LOG_NOTICE, e->e_id, + "Ruleset %s (%s) rejection: %s", rwset, p1, MsgBuf); else - syslog(LOG_NOTICE, "Ruleset %s (%s, %s) rejection: %s", + sm_syslog(LOG_NOTICE, e->e_id, + "Ruleset %s (%s, %s) rejection: %s", rwset, p1, p2, MsgBuf); } -#endif - - if (QuickAbort) - longjmp(TopFrame, 2); - /* clean up */ finis: + /* clean up */ + QuickAbort = saveQuickAbort; + OnlyOneError = saveOnlyOneError; setstat(rstat); if (buf != buf0) free(buf); + + if (rstat != EX_OK && (QuickAbort || (OnlyOneError && !HoldErrs))) + longjmp(TopFrame, 2); return rstat; } diff --git a/usr.sbin/sendmail/src/readcf.c b/usr.sbin/sendmail/src/readcf.c index c868136..f050fde 100644 --- a/usr.sbin/sendmail/src/readcf.c +++ b/usr.sbin/sendmail/src/readcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)readcf.c 8.184 (Berkeley) 1/14/97"; +static char sccsid[] = "@(#)readcf.c 8.196 (Berkeley) 5/29/97"; #endif /* not lint */ # include "sendmail.h" @@ -121,7 +121,7 @@ readcf(cfname, safe, e) FileName = cfname; LineNumber = 0; - cf = fopen(cfname, "r"); + cf = safefopen(cfname, O_RDONLY, 0444, SFF_OPENASROOT|SFF_NOLOCK); if (cf == NULL) { syserr("cannot open"); @@ -145,11 +145,10 @@ readcf(cfname, safe, e) if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) fprintf(stderr, "%s: WARNING: dangerous write permissions\n", FileName); -#ifdef LOG if (LogLevel > 0) - syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", + sm_syslog(LOG_CRIT, NOQID, + "%s: WARNING: dangerous write permissions", FileName); -#endif } #ifdef XLA @@ -745,7 +744,7 @@ fileclass(class, filename, fmt, safe, optional) else { pid = -1; - sff = SFF_REGONLY; + sff = SFF_REGONLY|SFF_NOWLINK; if (safe) sff |= SFF_OPENASROOT; f = safefopen(filename, O_RDONLY, 0, sff); @@ -761,7 +760,7 @@ fileclass(class, filename, fmt, safe, optional) { register char *p; # if SCANF - char wordbuf[MAXNAME+1]; + char wordbuf[MAXLINE + 1]; # endif if (buf[0] == '#') @@ -1482,14 +1481,30 @@ struct optioninfo { "SingleThreadDelivery", O_SINGTHREAD, FALSE }, #define O_RUNASUSER 0x9d { "RunAsUser", O_RUNASUSER, FALSE }, -#ifdef _FFR_DSN_RRT +#if _FFR_DSN_RRT_OPTION #define O_DSN_RRT 0x9e { "RrtImpliesDsn", O_DSN_RRT, FALSE }, #endif -#ifdef _FFR_PIDFILE_OPT +#if _FFR_PIDFILE_OPTION #define O_PIDFILE 0x9f { "PidFile", O_PIDFILE, FALSE }, #endif +#if _FFR_WRITABLE_DIRECTORIES_ARE_FATAL_OPTION +#define O_WDAF 0xa0 + { "WritableDirectoriesAreFatal", O_WDAF, FALSE }, +#endif +#if _FFR_CHOWN_IS_ALWAYS_SAFE_OPTION +#define O_CIAS 0xa1 + { "ChownIsAlwaysSafe", O_CIAS, FALSE }, +#endif +#if _FFR_DONT_PROBE_INTERFACES_OPTION +#define O_DPI 0xa2 + { "DontProbeInterfaces", O_DPI, FALSE }, +#endif +#if _FFR_MAXRCPT_OPTION +#define O_MAXRCPT 0xa3 + { "MaxRecipientPerMessage", O_MAXRCPT, FALSE }, +#endif { NULL, '\0', FALSE } }; @@ -1575,9 +1590,9 @@ setoption(opt, val, safe, sticky, e) } if (strlen(val) != strlen(o->o_name)) { - bool oldVerbose = Verbose; + int oldVerbose = Verbose; - Verbose = TRUE; + Verbose = 1; message("Option %s used as abbreviation for %s", val, o->o_name); Verbose = oldVerbose; @@ -2061,7 +2076,7 @@ setoption(opt, val, safe, sticky, e) break; case 'v': /* run in verbose mode */ - Verbose = atobool(val); + Verbose = atobool(val) ? 1 : 0; break; case 'w': /* if we are best MX, try host directly */ @@ -2251,6 +2266,8 @@ setoption(opt, val, safe, sticky, e) syserr("readcf: option RunAsUser: unknown user %s", val); else { + if (*p == '\0') + RunAsUserName = newstr(val); RunAsUid = pw->pw_uid; RunAsGid = pw->pw_gid; } @@ -2258,7 +2275,7 @@ setoption(opt, val, safe, sticky, e) if (*p == '\0') break; if (isascii(*p) && isdigit(*p)) - DefGid = atoi(p); + RunAsGid = atoi(p); else { register struct group *gr; @@ -2272,16 +2289,40 @@ setoption(opt, val, safe, sticky, e) } break; -#ifdef _FFR_DSN_RRT +#if _FFR_DSN_RRT_OPTION case O_DSN_RRT: - RrtImpliesDsn = atobool(p); + RrtImpliesDsn = atobool(val); break; #endif -#ifdef _FFR_PIDFILE_OPT +#if _FFR_PIDFILE_OPTION case O_PIDFILE: free(PidFile); - PidFile = newstr(p); + PidFile = newstr(val); + break; +#endif + +#if _FFR_WRITABLE_DIRECTORIES_ARE_FATAL_OPTION + case O_WDAF: + FatalWritableDirs = atobool(val); + break; +#endif + +#if _FFR_CHOWN_IS_ALWAYS_SAFE_OPTION + case O_CIAS: + ChownIsAlwaysSafe = atobool(val); + break; +#endif + +#if _FFR_DONT_PROBE_INTERFACES_OPTION + case O_DPI: + DontProbeInterfaces = atobool(val); + break; +#endif + +#if _FFR_MAXRCPT_OPTION + case O_MAXRCPT: + MaxRcptPerMsg = atoi(val); break; #endif diff --git a/usr.sbin/sendmail/src/recipient.c b/usr.sbin/sendmail/src/recipient.c index 92e6bc3..2076884 100644 --- a/usr.sbin/sendmail/src/recipient.c +++ b/usr.sbin/sendmail/src/recipient.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)recipient.c 8.118 (Berkeley) 12/1/96"; +static char sccsid[] = "@(#)recipient.c 8.130 (Berkeley) 5/29/97"; #endif /* not lint */ # include "sendmail.h" @@ -76,7 +76,6 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) { register char *p; register ADDRESS *al; /* list of addresses to send to */ - bool firstone; /* set on first address sent */ char delimiter; /* the address delimiter */ int naddrs; int i; @@ -105,7 +104,6 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) delimiter = ','; - firstone = TRUE; al = NULL; naddrs = 0; @@ -185,7 +183,6 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) } al = a; - firstone = FALSE; } /* arrange to send to everyone on the local send list */ @@ -303,8 +300,12 @@ recipient(a, sendq, aliaslevel, e) { a->q_flags |= QBADADDR; a->q_status = "5.7.1"; - usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", - a->q_alias->q_ruser, MyHostName); + if (a->q_alias->q_ruser == NULL) + usrerr("550 UID %d is an unknown user: cannot mail to programs", + a->q_alias->q_uid); + else + usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", + a->q_alias->q_ruser, MyHostName); } else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) { @@ -378,13 +379,11 @@ recipient(a, sendq, aliaslevel, e) ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); if (transienterror(ret)) { -#ifdef LOG if (LogLevel > 2) - syslog(LOG_ERR, "%s: include %s: transient error: %s", - e->e_id == NULL ? "NOQUEUE" : e->e_id, + sm_syslog(LOG_ERR, e->e_id, + "include %s: transient error: %s", shortenstring(a->q_user, 203), errstring(ret)); -#endif a->q_flags |= QQUEUEUP; a->q_flags &= ~QDONTSEND; usrerr("451 Cannot open %s: %s", @@ -416,8 +415,12 @@ recipient(a, sendq, aliaslevel, e) { a->q_flags |= QBADADDR; a->q_status = "5.7.1"; - usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", - a->q_alias->q_ruser, MyHostName); + if (a->q_alias->q_ruser == NULL) + usrerr("550 UID %d is an unknown user: cannot mail to files", + a->q_alias->q_uid); + else + usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", + a->q_alias->q_ruser, MyHostName); } else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) { @@ -426,6 +429,10 @@ recipient(a, sendq, aliaslevel, e) usrerr("550 Address %s is unsafe for mailing to files", a->q_alias->q_paddr); } + else if (strcmp(buf, "/dev/null") == 0) + { + /* /dev/null is always accepted */ + } else if (!writable(buf, a->q_alias, SFF_CREAT)) { a->q_flags |= QBADADDR; @@ -451,12 +458,10 @@ recipient(a, sendq, aliaslevel, e) a->q_flags |= QQUEUEUP; if (e->e_message == NULL) e->e_message = newstr("Deferred: user database error"); -# ifdef LOG if (LogLevel > 8) - syslog(LOG_INFO, "%s: deferred: udbexpand: %s", - e->e_id == NULL ? "NOQUEUE" : e->e_id, + sm_syslog(LOG_INFO, e->e_id, + "deferred: udbexpand: %s", errstring(errno)); -# endif message("queued (user database error): %s", errstring(errno)); e->e_nrcpts++; @@ -808,7 +813,13 @@ writable(filename, ctladdr, flags) ** File does exist -- check that it is writable. */ - if (ctladdr != NULL && geteuid() == 0) + if (geteuid() != 0) + { + euid = geteuid(); + egid = getegid(); + uname = NULL; + } + else if (ctladdr != NULL) { euid = ctladdr->q_uid; egid = ctladdr->q_gid; @@ -844,6 +855,7 @@ writable(filename, ctladdr, flags) if (geteuid() == 0 && (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) flags |= SFF_SETUIDOK; + flags |= SFF_NOLINK; errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); return errno == 0; @@ -908,25 +920,11 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) char *volatile uname; int rval = 0; volatile int sfflags = SFF_REGONLY; + register char *p; + bool safechown = FALSE; + bool safedir = FALSE; struct stat st; char buf[MAXLINE]; -#ifdef _POSIX_CHOWN_RESTRICTED -# if _POSIX_CHOWN_RESTRICTED == -1 -# define safechown FALSE -# else -# define safechown TRUE -# endif -#else -# ifdef _PC_CHOWN_RESTRICTED - bool safechown; -# else -# ifdef BSD -# define safechown TRUE -# else -# define safechown FALSE -# endif -# endif -#endif extern bool chownsafe(); if (tTd(27, 2)) @@ -1000,7 +998,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) errno = 0; /* return pseudo-error code */ - rval = EOPENTIMEOUT; + rval = E_SM_OPENTIMEOUT; goto resetuid; } if (TimeOuts.to_fileopen > 0) @@ -1008,8 +1006,25 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) else ev = NULL; - /* the input file must be marked safe */ - rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); + /* check for writable parent directory */ + p = strrchr(fname, '/'); + if (p != NULL) + { + *p = '\0'; + if (safedirpath(fname, uid, gid, uname, sfflags|SFF_SAFEDIRPATH) == 0) + { + /* in safe directory: relax chown & link rules */ + safedir = TRUE; + sfflags |= SFF_NOPATHCHECK; + } + *p = '/'; + } + + /* allow links only in unwritable directories */ + if (!safedir) + sfflags |= SFF_NOLINK; + + rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, &st); if (rval != 0) { /* don't use this :include: file */ @@ -1017,15 +1032,17 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) printf("include: not safe (uid=%d): %s\n", (int) uid, errstring(rval)); } - else + else if ((fp = fopen(fname, "r")) == NULL) { - fp = fopen(fname, "r"); - if (fp == NULL) - { - rval = errno; - if (tTd(27, 4)) - printf("include: open: %s\n", errstring(rval)); - } + rval = errno; + if (tTd(27, 4)) + printf("include: open: %s\n", errstring(rval)); + } + else if (filechanged(fname, fileno(fp), &st, sfflags)) + { + rval = E_SM_FILECHANGE; + if (tTd(27, 4)) + printf("include: file changed after open\n"); } if (ev != NULL) clrevent(ev); @@ -1058,7 +1075,7 @@ resetuid: printf("include: reset uid = %d/%d\n", (int) getuid(), (int) geteuid()); - if (rval == EOPENTIMEOUT) + if (rval == E_SM_OPENTIMEOUT) usrerr("451 open timeout on %s", fname); if (fp == NULL) @@ -1071,9 +1088,14 @@ resetuid: return rval; } -#ifndef safechown - safechown = chownsafe(fileno(fp)); -#endif + /* if path was writable, check to avoid file giveaway tricks */ + safechown = chownsafe(fileno(fp), safedir); + if (tTd(27, 6)) + printf("include: parent of %s is %s, chown is %ssafe\n", + fname, + safedir ? "safe" : "dangerous", + safechown ? "" : "un"); + if (ca == NULL && safechown) { ctladdr->q_uid = st.st_uid; @@ -1104,13 +1126,12 @@ resetuid: sh = "/SENDMAIL/ANY/SHELL/"; if (!usershellok(pw->pw_name, sh)) { -#ifdef LOG if (LogLevel >= 12) - syslog(LOG_INFO, "%s: user %s has bad shell %s, marked %s", + sm_syslog(LOG_INFO, e->e_id, + "%s: user %s has bad shell %s, marked %s", shortenstring(fname, 203), pw->pw_name, sh, safechown ? "bogus" : "unsafe"); -#endif if (safechown) ctladdr->q_flags |= QBOGUSSHELL; else @@ -1141,13 +1162,12 @@ resetuid: if (bitset(S_IWOTH | (UnsafeGroupWrites ? S_IWGRP : 0), st.st_mode)) { -#ifdef LOG if (LogLevel >= 12) - syslog(LOG_INFO, "%s: %s writable %s file, marked unsafe", + sm_syslog(LOG_INFO, e->e_id, + "%s: %s writable %s file, marked unsafe", shortenstring(fname, 203), bitset(S_IWOTH, st.st_mode) ? "world" : "group", forwarding ? "forward" : ":include:"); -#endif ctladdr->q_flags |= QUNSAFEADDR; } @@ -1184,12 +1204,10 @@ resetuid: e->e_to = NULL; message("%s to %s", forwarding ? "forwarding" : "sending", buf); -#ifdef LOG if (forwarding && LogLevel > 9) - syslog(LOG_INFO, "%s: forward %.200s => %s", - e->e_id == NULL ? "NOQUEUE" : e->e_id, + sm_syslog(LOG_INFO, e->e_id, + "forward %.200s => %s", oldto, shortenstring(buf, 203)); -#endif nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); } diff --git a/usr.sbin/sendmail/src/savemail.c b/usr.sbin/sendmail/src/savemail.c index e3cbfa3..894352c 100644 --- a/usr.sbin/sendmail/src/savemail.c +++ b/usr.sbin/sendmail/src/savemail.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)savemail.c 8.103 (Berkeley) 1/18/97"; +static char sccsid[] = "@(#)savemail.c 8.110 (Berkeley) 4/7/97"; #endif /* not lint */ # include "sendmail.h" @@ -349,13 +349,13 @@ savemail(e, sendbody) /* we have a home directory; write dead.letter */ define('z', p, e); expand("\201z/dead.letter", buf, sizeof buf, e); - flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; + flags = SFF_NOLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; e->e_to = buf; if (mailfile(buf, NULL, flags, e) == EX_OK) { - bool oldverb = Verbose; + int oldverb = Verbose; - Verbose = TRUE; + Verbose = 1; message("Saved message in %s", buf); Verbose = oldverb; state = ESM_DONE; @@ -383,7 +383,7 @@ savemail(e, sendbody) snprintf(buf, sizeof buf, "%sdead.letter", _PATH_VARTMP); - flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT; + flags = SFF_NOLINK|SFF_CREAT|SFF_REGONLY|SFF_OPENASROOT|SFF_MUSTOWN; if (!writable(buf, NULL, flags) || (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode, flags)) == NULL) @@ -407,15 +407,15 @@ savemail(e, sendbody) state = ESM_PANIC; else { - bool oldverb = Verbose; + int oldverb = Verbose; - Verbose = TRUE; + Verbose = 1; message("Saved message in %s", buf); Verbose = oldverb; -#ifdef LOG if (LogLevel > 3) - syslog(LOG_NOTICE, "Saved message in %s", buf); -#endif + sm_syslog(LOG_NOTICE, e->e_id, + "Saved message in %s", + buf); state = ESM_DONE; } (void) xfclose(fp, "savemail", buf); @@ -550,7 +550,6 @@ returntosender(msg, returnq, flags, e) addheader("To", q->q_paddr, &ee->e_header); } -# ifdef LOG if (LogLevel > 5) { if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags)) @@ -559,10 +558,10 @@ returntosender(msg, returnq, flags, e) p = "postmaster notify"; else p = "DSN"; - syslog(LOG_INFO, "%s: %s: %s: %s", - e->e_id, ee->e_id, p, shortenstring(msg, 203)); + sm_syslog(LOG_INFO, e->e_id, + "%s: %s: %s", + ee->e_id, p, shortenstring(msg, 203)); } -# endif if (SendMIMEErrors) { @@ -759,11 +758,15 @@ errbody(mci, e, separator) { if (*ErrMsgFile == '/') { - xfile = fopen(ErrMsgFile, "r"); + xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, + SFF_ROOTOK|SFF_REGONLY); if (xfile != NULL) { while (fgets(buf, sizeof buf, xfile) != NULL) { +#if _FFR_BUG_FIX + translate_dollars(buf); +#endif expand(buf, buf, sizeof buf, e); putline(buf, mci); } @@ -1223,7 +1226,7 @@ smtptodsn(smtpstat) return "5.2.2"; case 553: /* Req action not taken: mailbox name not allowed */ - return "5.1.3"; + return "5.1.0"; case 554: /* Transaction failed */ return "5.0.0"; diff --git a/usr.sbin/sendmail/src/sendmail.8 b/usr.sbin/sendmail/src/sendmail.8 index 601ccd5..67cef7f 100644 --- a/usr.sbin/sendmail/src/sendmail.8 +++ b/usr.sbin/sendmail/src/sendmail.8 @@ -1,3 +1,4 @@ +.\" Copyright (c) 1983, 1997 Eric P. Allman .\" Copyright (c) 1988, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -29,9 +30,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)sendmail.8 8.11 (Berkeley) 1/16/97 +.\" @(#)sendmail.8 8.12 (Berkeley) 2/1/97 .\" -.Dd January 16, 1997 +.Dd February 1, 1997 .Dt SENDMAIL 8 .Os BSD 4 .Sh NAME diff --git a/usr.sbin/sendmail/src/sendmail.h b/usr.sbin/sendmail/src/sendmail.h index 9c0e3e2..2eb40c8 100644 --- a/usr.sbin/sendmail/src/sendmail.h +++ b/usr.sbin/sendmail/src/sendmail.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sendmail.h 8.219 (Berkeley) 1/14/97 + * @(#)sendmail.h 8.236 (Berkeley) 6/5/97 */ /* @@ -41,7 +41,7 @@ # ifdef _DEFINE # define EXTERN # ifndef lint -static char SmailSccsId[] = "@(#)sendmail.h 8.219 1/14/97"; +static char SmailSccsId[] = "@(#)sendmail.h 8.236 6/5/97"; # endif # else /* _DEFINE */ # define EXTERN extern @@ -87,6 +87,13 @@ static char SmailSccsId[] = "@(#)sendmail.h 8.219 1/14/97"; # include <netccitt/x25.h> # endif +#if NAMED_BIND +# include <arpa/nameser.h> +# ifdef NOERROR +# undef NOERROR /* avoid <sys/streams.h> conflict */ +# endif +#endif + /* forward references for prototypes */ @@ -391,6 +398,7 @@ struct hdrinfo { char *hi_field; /* the name of the field */ u_short hi_flags; /* status bits, see below */ + char *hi_ruleset; /* validity check ruleset */ }; extern struct hdrinfo HdrInfo[]; @@ -726,7 +734,7 @@ MAPCLASS #define MCF_OPTFILE 0x0008 /* file name is optional */ /* functions */ -extern char *map_rewrite __P((MAP *, char *, int, char **)); +extern char *map_rewrite __P((MAP *, const char *, int, char **)); extern MAP *makemapentry __P((char *)); extern void initmaps __P((bool, ENVELOPE *)); /* @@ -752,6 +760,7 @@ struct symtab NAMECANON sv_namecanon; /* canonical name cache */ int sv_macro; /* macro name => id mapping */ int sv_ruleset; /* ruleset index */ + struct hdrinfo sv_header; /* header metainfo */ char *sv_service[MAXMAPSTACK]; /* service switch */ } s_value; }; @@ -771,6 +780,7 @@ typedef struct symtab STAB; # define ST_MACRO 9 /* macro name to id mapping */ # define ST_RULESET 10 /* ruleset index */ # define ST_SERVICE 11 /* service switch entry */ +# define ST_HEADER 12 /* special header flags */ # define ST_MCI 16 /* mailer connection info (offset) */ # define s_class s_value.sv_class @@ -785,6 +795,7 @@ typedef struct symtab STAB; # define s_macro s_value.sv_macro # define s_ruleset s_value.sv_ruleset # define s_service s_value.sv_service +# define s_header s_value.sv_header extern STAB *stab __P((char *, int, int)); extern void stabapply __P((void (*)(STAB *, int), int)); @@ -916,6 +927,7 @@ EXTERN int NoRecipientAction; #define PRIV_NOVRFY 0x0010 /* disallow VRFY command entirely */ #define PRIV_AUTHWARNINGS 0x0020 /* flag possible authorization probs */ #define PRIV_NORECEIPTS 0x0040 /* disallow return receipts */ +#define PRIV_NOETRN 0x0080 /* disallow ETRN command entirely */ #define PRIV_RESTRICTMAILQ 0x1000 /* restrict mailq command */ #define PRIV_RESTRICTQRUN 0x2000 /* restrict queue run */ #define PRIV_GOAWAY 0x0fff /* don't give no info, anyway, anyhow */ @@ -943,7 +955,7 @@ struct prival /* -** Flags passed to safefile. +** Flags passed to safefile/safedirpath. */ #define SFF_ANYFILE 0 /* no special restrictions */ @@ -955,12 +967,25 @@ struct prival #define SFF_SETUIDOK 0x0020 /* setuid files are ok */ #define SFF_CREAT 0x0040 /* ok to create file if necessary */ #define SFF_REGONLY 0x0080 /* regular files only */ +#define SFF_SAFEDIRPATH 0x0100 /* no writable directories allowed */ +#define SFF_NOHLINK 0x0200 /* file cannot have hard links */ +#define SFF_NOWLINK 0x0400 /* links only in non-writable dirs */ +#define SFF_NOWFILES 0x0800 /* disallow world writable files */ -/* flags that are actually specific to safefopen */ +/* flags that are actually specific to safeopen/safefopen/dfopen */ #define SFF_OPENASROOT 0x1000 /* open as root instead of real user */ +#define SFF_NOLOCK 0x2000 /* don't lock the file */ + +/* pseudo-flags */ +#define SFF_NOLINK (SFF_NOHLINK|SFF_NOSLINK) /* functions */ extern int safefile __P((char *, UID_T, GID_T, char *, int, int, struct stat *)); +extern int safedirpath __P((char *, UID_T, GID_T, char *, int)); +extern int safeopen __P((char *, int, int, int)); +extern FILE *safefopen __P((char *, int, int, int)); +extern int dfopen __P((char *, int, int, int)); +extern bool filechanged __P((char *, int, struct stat *, int)); /* @@ -1077,7 +1102,6 @@ EXTERN bool FromFlag; /* if set, "From" person is explicit */ EXTERN bool MeToo; /* send to the sender also */ EXTERN bool IgnrDot; /* don't let dot end messages */ EXTERN bool SaveFrom; /* save leading "From" lines */ -EXTERN bool Verbose; /* set if blow-by-blow desired */ EXTERN bool GrabTo; /* if set, get recipients from msg */ EXTERN bool SuprErrs; /* set if we are suppressing errors */ EXTERN bool HoldErrs; /* only output errors to transcript */ @@ -1102,6 +1126,7 @@ EXTERN uid_t DefUid; /* default uid to run as */ EXTERN gid_t DefGid; /* default gid to run as */ EXTERN char *DefUser; /* default user to run as (from DefUid) */ EXTERN MODE_T OldUmask; /* umask when sendmail starts up */ +EXTERN int Verbose; /* set if blow-by-blow desired */ EXTERN int Errors; /* set if errors (local to single pass) */ EXTERN int ExitStat; /* exit status code */ EXTERN int LineNumber; /* line number in current input */ @@ -1123,6 +1148,7 @@ EXTERN char *RealHostName; /* name of host we are talking to */ EXTERN char *CurHostName; /* current host we are dealing with */ EXTERN jmp_buf TopFrame; /* branch-to-top-of-loop-on-error frame */ EXTERN bool QuickAbort; /* .... but only if we want a quick abort */ +EXTERN bool OnlyOneError; /* .... or only want to give one SMTP reply */ EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */ EXTERN bool SendMIMEErrors; /* send error messages in MIME format */ EXTERN bool MatchGecos; /* look for user names in gecos field */ @@ -1163,11 +1189,16 @@ EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */ EXTERN int DefaultNotify; /* default DSN notification flags */ EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */ EXTERN bool UserSubmission; /* initial (user) mail submission */ +EXTERN char *RunAsUserName; /* user to become for bulk of run */ EXTERN uid_t RunAsUid; /* UID to become for bulk of run */ EXTERN gid_t RunAsGid; /* GID to become for bulk of run */ -#ifdef _FFR_DSN_RRT +EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */ +EXTERN bool DoQueueRun; /* non-interrupt time queue run needed */ +#if _FFR_DSN_RRT_OPTION EXTERN bool RrtImpliesDsn; /* turn Return-Receipt-To: into DSN */ #endif +EXTERN bool DontProbeInterfaces; /* don't probe interfaces for names */ +EXTERN bool ChownAlwaysSafe; /* treat chown(2) as safe */ EXTERN bool IgnoreHostStatus; /* ignore long term host status files */ EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */ EXTERN bool UnsafeGroupWrites; /* group-writable files are unsafe */ @@ -1194,6 +1225,7 @@ EXTERN char *QueueLimitSender; /* limit queue runs to this sender */ EXTERN char *QueueLimitId; /* limit queue runs to this id */ EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */ EXTERN char *DoubleBounceAddr; /* where to send double bounces */ +EXTERN bool FatalWritableDirs; /* no writable dirs in map paths */ EXTERN char **ExternalEnviron; /* input environment */ EXTERN char *UserEnviron[MAXUSERENVIRON + 1]; /* saved user environment */ @@ -1249,6 +1281,12 @@ EXTERN u_char tTdvect[100]; */ +/* +** The "no queue id" queue id for sm_syslog +*/ + +#define NOQID "*~*" + /* ** Some in-line functions @@ -1272,7 +1310,6 @@ EXTERN u_char tTdvect[100]; */ extern char *xalloc __P((int)); -extern FILE *dfopen __P((char *, int, int)); extern char *sfgets __P((char *, int, FILE *, time_t, char *)); extern char *queuename __P((ENVELOPE *, int)); extern time_t curtime __P(()); @@ -1295,7 +1332,6 @@ extern void rebuildaliases __P((MAP *, bool)); extern void readaliases __P((MAP *, FILE *, bool, bool)); extern void finis __P(()); extern void setsender __P((char *, ENVELOPE *, char **, int, bool)); -extern FILE *safefopen __P((char *, int, int, int)); extern void xputs __P((const char *)); extern void logsender __P((ENVELOPE *, char *)); extern void smtprset __P((MAILER *, MCI *, ENVELOPE *)); @@ -1303,7 +1339,7 @@ extern void smtpquit __P((MAILER *, MCI *, ENVELOPE *)); extern void setuserenv __P((const char *, const char *)); extern char *getextenv __P((const char *)); extern void disconnect __P((int, ENVELOPE *)); -extern void putxline __P((char *, MCI *, int)); +extern void putxline __P((char *, size_t, MCI *, int)); extern void dumpfd __P((int, bool, bool)); extern void makemailer __P((char *)); extern void putfromline __P((MCI *, ENVELOPE *)); @@ -1328,7 +1364,6 @@ extern void proc_list_clear __P((void)); extern void buffer_errors __P((void)); extern void flush_errors __P((bool)); extern void putline __P((char *, MCI *)); -extern void putxline __P((char *, MCI *, int)); extern bool xtextok __P((char *)); extern char *xtextify __P((char *, char *)); extern char *xuntextify __P((char *)); @@ -1341,7 +1376,7 @@ extern int endmailer __P((MCI *, ENVELOPE *, char **)); extern void fixcrlf __P((char *, bool)); extern int dofork __P((void)); extern void initsys __P((ENVELOPE *)); -extern void collect __P((FILE *, bool, bool, HDR **, ENVELOPE *)); +extern void collect __P((FILE *, bool, HDR **, ENVELOPE *)); extern void stripquotes __P((char *)); extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *)); extern void unlockqueue __P((ENVELOPE *)); @@ -1385,6 +1420,7 @@ extern void usrerr(const char *, ...); extern void message(const char *, ...); extern void nmessage(const char *, ...); extern void setproctitle(const char *fmt, ...); +extern void sm_syslog(int, const char *, const char *, ...); #else extern void auth_warning(); extern void syserr(); @@ -1392,6 +1428,7 @@ extern void usrerr(); extern void message(); extern void nmessage(); extern void setproctitle(); +extern void sm_syslog(); #endif #if !HASSNPRINTF diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c index 1195d8a..fa39e68 100644 --- a/usr.sbin/sendmail/src/srvrsmtp.c +++ b/usr.sbin/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if SMTP -static char sccsid[] = "@(#)srvrsmtp.c 8.136 (Berkeley) 1/17/97 (with SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.146 (Berkeley) 6/11/97 (with SMTP)"; #else -static char sccsid[] = "@(#)srvrsmtp.c 8.136 (Berkeley) 1/17/97 (without SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.146 (Berkeley) 6/11/97 (without SMTP)"; #endif #endif /* not lint */ @@ -153,6 +153,7 @@ smtp(nullserver, e) volatile int n_noop = 0; /* count of NOOP/VERB/ONEX etc cmds */ volatile int n_helo = 0; /* count of HELO/EHLO commands */ bool ok; + int lognullconnection = TRUE; char inp[MAXLINE]; char cmdbuf[MAXLINE]; extern ENVELOPE BlankEnvelope; @@ -160,7 +161,7 @@ smtp(nullserver, e) extern void settime __P((ENVELOPE *)); extern bool enoughdiskspace __P((long)); extern int runinchild __P((char *, ENVELOPE *)); - extern void checksmtpattack __P((volatile int *, int, char *)); + extern void checksmtpattack __P((volatile int *, int, char *, ENVELOPE *)); if (fileno(OutChannel) != fileno(stdout)) { @@ -177,11 +178,12 @@ smtp(nullserver, e) CurSmtpClient = CurHostName; setproctitle("server %s startup", CurSmtpClient); -#if defined(LOG) && DAEMON +#if DAEMON if (LogLevel > 11) { /* log connection information */ - syslog(LOG_INFO, "SMTP connect from %.100s (%.100s)", + sm_syslog(LOG_INFO, NOQID, + "SMTP connect from %.100s (%.100s)", CurSmtpClient, anynet_ntoa(&RealHostAddr)); } #endif @@ -231,7 +233,9 @@ smtp(nullserver, e) } QuickAbort = FALSE; HoldErrs = FALSE; + SuprErrs = FALSE; LogUsrErrs = FALSE; + OnlyOneError = TRUE; e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); /* setup for the read */ @@ -252,11 +256,10 @@ smtp(nullserver, e) disconnect(1, e); message("421 %s Lost input channel from %s", MyHostName, CurSmtpClient); -#ifdef LOG if (LogLevel > (gotmail ? 1 : 19)) - syslog(LOG_NOTICE, "lost input channel from %.100s", + sm_syslog(LOG_NOTICE, e->e_id, + "lost input channel from %.100s", CurSmtpClient); -#endif if (InChild) ExitStat = EX_QUIT; finis(); @@ -269,10 +272,10 @@ smtp(nullserver, e) if (e->e_xfp != NULL) fprintf(e->e_xfp, "<<< %s\n", inp); -#ifdef LOG if (LogLevel >= 15) - syslog(LOG_INFO, "<-- %s", inp); -#endif + sm_syslog(LOG_INFO, e->e_id, + "<-- %s", + inp); if (e->e_id == NULL) setproctitle("%s: %.80s", CurSmtpClient, inp); @@ -324,7 +327,7 @@ smtp(nullserver, e) default: if (++badcommands > MAXBADCOMMANDS) sleep(1); - message("550 Access denied"); + usrerr("550 Access denied"); continue; } } @@ -332,6 +335,15 @@ smtp(nullserver, e) /* non-null server */ switch (c->cmdcode) { + case CMDMAIL: + case CMDEXPN: + case CMDVRFY: + case CMDETRN: + lognullconnection = FALSE; + } + + switch (c->cmdcode) + { case CMDHELO: /* hello -- introduce yourself */ case CMDEHLO: /* extended hello */ if (c->cmdcode == CMDEHLO) @@ -346,12 +358,12 @@ smtp(nullserver, e) } /* avoid denial-of-service */ - checksmtpattack(&n_helo, MAXHELOCOMMANDS, "HELO/EHLO"); + checksmtpattack(&n_helo, MAXHELOCOMMANDS, "HELO/EHLO", e); /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ if (gothello) { - message("503 %s Duplicate HELO/EHLO", + usrerr("503 %s Duplicate HELO/EHLO", MyHostName); break; } @@ -359,7 +371,7 @@ smtp(nullserver, e) /* check for valid domain name (re 1123 5.2.5) */ if (*p == '\0' && !AllowBogusHELO) { - message("501 %s requires domain address", + usrerr("501 %s requires domain address", cmdbuf); break; } @@ -384,7 +396,7 @@ smtp(nullserver, e) if (*q != '\0') { if (!AllowBogusHELO) - message("501 Invalid domain name"); + usrerr("501 Invalid domain name"); else { message("250 %s Invalid domain name, accepting anyway", @@ -442,13 +454,13 @@ smtp(nullserver, e) if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) { - message("503 Polite people say HELO first"); + usrerr("503 Polite people say HELO first"); break; } } if (gotmail) { - message("503 Sender already specified"); + usrerr("503 Sender already specified"); if (InChild) finis(); break; @@ -578,7 +590,7 @@ smtp(nullserver, e) if (!enoughdiskspace(e->e_msgsize)) { - message("452 Insufficient disk space; try again later"); + usrerr("452 Insufficient disk space; try again later"); break; } message("250 Sender ok"); @@ -600,6 +612,13 @@ smtp(nullserver, e) QuickAbort = TRUE; LogUsrErrs = TRUE; + /* limit flooding of our machine */ + if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg) + { + usrerr("450 Too many recipients"); + break; + } + if (e->e_sendmode != SM_DELIVER) e->e_flags |= EF_VRFYONLY; @@ -674,21 +693,20 @@ smtp(nullserver, e) else { /* punt -- should keep message in ADDRESS.... */ - message("550 Addressee unknown"); + usrerr("550 Addressee unknown"); } - e->e_to = NULL; break; case CMDDATA: /* data -- text of mail */ SmtpPhase = "server DATA"; if (!gotmail) { - message("503 Need MAIL command"); + usrerr("503 Need MAIL command"); break; } else if (nrcpts <= 0) { - message("503 Need RCPT (recipient)"); + usrerr("503 Need RCPT (recipient)"); break; } @@ -713,7 +731,7 @@ smtp(nullserver, e) /* collect the text of the message */ SmtpPhase = "collect"; buffer_errors(); - collect(InChannel, TRUE, doublequeue, NULL, e); + collect(InChannel, TRUE, NULL, e); flush_errors(TRUE); if (Errors != 0) goto abortmessage; @@ -785,7 +803,10 @@ smtp(nullserver, e) break; case CMDRSET: /* rset -- reset state */ - message("250 Reset state"); + if (tTd(94, 100)) + message("451 Test failure"); + else + message("250 Reset state"); /* arrange to ignore any current send list */ e->e_sendqueue = NULL; @@ -795,6 +816,7 @@ smtp(nullserver, e) /* clean up a bit */ gotmail = FALSE; + SuprErrs = TRUE; dropenvelope(e, TRUE); CurEnv = e = newenvelope(e, CurEnv); break; @@ -802,7 +824,7 @@ smtp(nullserver, e) case CMDVRFY: /* vrfy -- verify address */ case CMDEXPN: /* expn -- expand address */ checksmtpattack(&nverifies, MAXVRFYCOMMANDS, - c->cmdcode == CMDVRFY ? "VRFY" : "EXPN"); + c->cmdcode == CMDVRFY ? "VRFY" : "EXPN", e); vrfy = c->cmdcode == CMDVRFY; if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, PrivacyFlags)) @@ -811,39 +833,35 @@ smtp(nullserver, e) message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); else message("502 Sorry, we do not allow this operation"); -#ifdef LOG if (LogLevel > 5) - syslog(LOG_INFO, "%.100s: %s [rejected]", + sm_syslog(LOG_INFO, e->e_id, + "%.100s: %s [rejected]", CurSmtpClient, shortenstring(inp, 203)); -#endif break; } else if (!gothello && bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, PrivacyFlags)) { - message("503 I demand that you introduce yourself first"); + usrerr("503 I demand that you introduce yourself first"); break; } if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) break; -#ifdef LOG if (LogLevel > 5) - syslog(LOG_INFO, "%.100s: %s", + sm_syslog(LOG_INFO, e->e_id, + "%.100s: %s", CurSmtpClient, shortenstring(inp, 203)); -#endif vrfyqueue = NULL; - QuickAbort = TRUE; if (vrfy) e->e_flags |= EF_VRFYONLY; while (*p != '\0' && isascii(*p) && isspace(*p)) p++; if (*p == '\0') { - message("501 Argument required"); - Errors++; + usrerr("501 Argument required"); } else { @@ -857,7 +875,7 @@ smtp(nullserver, e) } if (vrfyqueue == NULL) { - message("554 Nothing to %s", vrfy ? "VRFY" : "EXPN"); + usrerr("554 Nothing to %s", vrfy ? "VRFY" : "EXPN"); } while (vrfyqueue != NULL) { @@ -878,24 +896,23 @@ smtp(nullserver, e) case CMDETRN: /* etrn -- force queue flush */ if (strlen(p) <= 0) { - message("500 Parameter required"); + usrerr("500 Parameter required"); break; } /* crude way to avoid denial-of-service attacks */ - checksmtpattack(&n_etrn, MAXETRNCOMMANDS, "ETRN"); + checksmtpattack(&n_etrn, MAXETRNCOMMANDS, "ETRN", e); id = p; if (*id == '@') id++; else *--id = '@'; -#ifdef LOG if (LogLevel > 5) - syslog(LOG_INFO, "%.100s: ETRN %s", + sm_syslog(LOG_INFO, e->e_id, + "%.100s: ETRN %s", CurSmtpClient, shortenstring(id, 203)); -#endif QueueLimitRecipient = id; ok = runqueue(TRUE, TRUE); QueueLimitRecipient = NULL; @@ -908,7 +925,7 @@ smtp(nullserver, e) break; case CMDNOOP: /* noop -- do nothing */ - checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "NOOP"); + checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "NOOP", e); message("250 OK"); break; @@ -924,6 +941,10 @@ doquit: if (InChild) ExitStat = EX_QUIT; + if (lognullconnection && LogLevel > 5) + sm_syslog(LOG_INFO, NULL, + "Null connection from %.100s", + CurSmtpClient); finis(); case CMDVERB: /* set verbose mode */ @@ -933,20 +954,20 @@ doquit: message("502 Verbose unavailable"); break; } - checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "VERB"); - Verbose = TRUE; + checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "VERB", e); + Verbose = 1; e->e_sendmode = SM_DELIVER; message("250 Verbose mode"); break; case CMDONEX: /* doing one transaction only */ - checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "ONEX"); + checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "ONEX", e); OneXact = TRUE; message("250 Only one transaction"); break; case CMDXUSR: /* initial (user) submission */ - checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "XUSR"); + checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "XUSR", e); UserSubmission = TRUE; message("250 Initial submission"); break; @@ -968,13 +989,11 @@ doquit: case CMDDBGDEBUG: /* set debug mode */ # endif /* SMTPDEBUG */ case CMDLOGBOGUS: /* bogus command */ -# ifdef LOG if (LogLevel > 0) - syslog(LOG_CRIT, + sm_syslog(LOG_CRIT, e->e_id, "\"%s\" command from %.100s (%.100s)", c->cmdname, CurSmtpClient, anynet_ntoa(&RealHostAddr)); -# endif /* FALL THROUGH */ case CMDERROR: /* unknown command */ @@ -985,7 +1004,8 @@ doquit: goto doquit; } - message("500 Command unrecognized"); + usrerr("500 Command unrecognized: \"%s\"", + shortenstring(inp, 203)); break; default: @@ -1003,6 +1023,7 @@ doquit: ** maxcount -- maximum value for this counter before we ** slow down. ** cname -- command name for logging. +** e -- the current envelope. ** ** Returns: ** none. @@ -1012,20 +1033,20 @@ doquit: */ void -checksmtpattack(pcounter, maxcount, cname) +checksmtpattack(pcounter, maxcount, cname, e) volatile int *pcounter; int maxcount; char *cname; + ENVELOPE *e; { if (++(*pcounter) >= maxcount) { -#ifdef LOG if (*pcounter == maxcount && LogLevel > 5) { - syslog(LOG_INFO, "%.100s: %.40s attack?", + sm_syslog(LOG_INFO, e->e_id, + "%.100s: %.40s attack?", CurSmtpClient, cname); } -#endif sleep(*pcounter / maxcount); } } @@ -1065,9 +1086,8 @@ skipword(p, w) if (*p != ':') { syntax: - message("501 Syntax error in parameters scanning \"%s\"", + usrerr("501 Syntax error in parameters scanning \"%s\"", shortenstring(firstp, 203)); - Errors++; return (NULL); } *p++ = '\0'; @@ -1411,7 +1431,8 @@ help(topic) extern char Version[]; - if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) + if (HelpFile == NULL || + (hf = safefopen(HelpFile, O_RDONLY, 0444, SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK)) == NULL) { /* no help */ errno = 0; diff --git a/usr.sbin/sendmail/src/udb.c b/usr.sbin/sendmail/src/udb.c index af4c298..51c6873 100644 --- a/usr.sbin/sendmail/src/udb.c +++ b/usr.sbin/sendmail/src/udb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if USERDB -static char sccsid [] = "@(#)udb.c 8.47 (Berkeley) 12/6/96 (with USERDB)"; +static char sccsid [] = "@(#)udb.c 8.51 (Berkeley) 5/29/97 (with USERDB)"; #else -static char sccsid [] = "@(#)udb.c 8.47 (Berkeley) 12/6/96 (without USERDB)"; +static char sccsid [] = "@(#)udb.c 8.51 (Berkeley) 5/29/97 (without USERDB)"; #endif #endif @@ -120,7 +120,7 @@ struct option char *val; }; -extern int _udbx_init __P((void)); +extern int _udbx_init __P((ENVELOPE *)); /* ** UDBEXPAND -- look up user in database and expand ** @@ -173,7 +173,7 @@ udbexpand(a, sendq, aliaslevel, e) /* on first call, locate the database */ if (!UdbInitialized) { - if (_udbx_init() == EX_TEMPFAIL) + if (_udbx_init(e) == EX_TEMPFAIL) return EX_TEMPFAIL; } @@ -259,14 +259,19 @@ udbexpand(a, sendq, aliaslevel, e) breakout = TRUE; if (info.size >= userleft - 1) { - char *nuser = xalloc(usersize + MEMCHUNKSIZE); + char *nuser; + int size = MEMCHUNKSIZE; + + if (info.size > MEMCHUNKSIZE) + size = info.size; + nuser = xalloc(usersize + size); bcopy(user, nuser, usersize); if (user != userbuf) free(user); user = nuser; - usersize += MEMCHUNKSIZE; - userleft += MEMCHUNKSIZE; + usersize += size; + userleft += size; } p = &user[strlen(user)]; if (p != user) @@ -287,12 +292,11 @@ udbexpand(a, sendq, aliaslevel, e) break; message("expanded to %s", user); -#ifdef LOG if (LogLevel >= 10) - syslog(LOG_INFO, "%s: expand %.100s => %s", - e->e_id, e->e_to, + sm_syslog(LOG_INFO, e->e_id, + "expand %.100s => %s", + e->e_to, shortenstring(user, 203)); -#endif naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { @@ -417,12 +421,11 @@ udbexpand(a, sendq, aliaslevel, e) user[info.size] = '\0'; message("hesioded to %s", user); -#ifdef LOG if (LogLevel >= 10) - syslog(LOG_INFO, "%s: hesiod %.100s => %s", - e->e_id, e->e_to, + sm_syslog(LOG_INFO, e->e_id, + "hesiod %.100s => %s", + e->e_to, shortenstring(user, 203)); -#endif naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) @@ -539,7 +542,7 @@ udbmatch(user, field) if (!UdbInitialized) { - if (_udbx_init() == EX_TEMPFAIL) + if (_udbx_init(CurEnv) == EX_TEMPFAIL) return NULL; } @@ -552,7 +555,10 @@ udbmatch(user, field) return NULL; /* long names can never match and are a pain to deal with */ - if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) + i = strlen(field); + if (i < sizeof "maildrop") + i = sizeof "maildrop"; + if ((strlen(user) + i) > sizeof keybuf - 4) return NULL; /* names beginning with colons indicate metadata */ @@ -785,7 +791,7 @@ udb_map_lookup(map, name, av, statp) ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. ** ** Parameters: -** none. +** e -- the current envelope. ** ** Returns: ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a @@ -800,7 +806,8 @@ udb_map_lookup(map, name, av, statp) #define MAXUDBOPTS 27 int -_udbx_init() +_udbx_init(e) + ENVELOPE *e; { register char *p; register struct udbent *up; @@ -957,19 +964,18 @@ _udbx_init() { int saveerrno = errno; - printf("dbopen(%s): %s", + printf("dbopen(%s): %s\n", up->udb_dbname, errstring(errno)); errno = saveerrno; } if (errno != ENOENT && errno != EACCES) { -#ifdef LOG if (LogLevel > 2) - syslog(LOG_ERR, "dbopen(%s): %s", + sm_syslog(LOG_ERR, e->e_id, + "dbopen(%s): %s", up->udb_dbname, errstring(errno)); -#endif up->udb_type = UDB_EOLIST; if (up->udb_dbname != spec) free(up->udb_dbname); diff --git a/usr.sbin/sendmail/src/usersmtp.c b/usr.sbin/sendmail/src/usersmtp.c index 23d1348..8529497 100644 --- a/usr.sbin/sendmail/src/usersmtp.c +++ b/usr.sbin/sendmail/src/usersmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if SMTP -static char sccsid[] = "@(#)usersmtp.c 8.80 (Berkeley) 1/18/97 (with SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 8.87 (Berkeley) 6/3/97 (with SMTP)"; #else -static char sccsid[] = "@(#)usersmtp.c 8.80 (Berkeley) 1/18/97 (without SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 8.87 (Berkeley) 6/3/97 (without SMTP)"; #endif #endif /* not lint */ @@ -389,7 +389,7 @@ smtpmailfrom(m, mci, e) !bitset(EF_DONT_MIME, e->e_flags) && !bitnset(M_8BITS, m->m_flags)) bodytype = "8BITMIME"; - if (bodytype != NULL) + if (bodytype != NULL && strlen(bodytype) + 7 < l) { strcat(optbuf, " BODY="); strcat(optbuf, bodytype); @@ -524,6 +524,8 @@ smtpmailfrom(m, mci, e) { /* exceeded storage allocation */ mci_setstat(mci, EX_NOTSTICKY, "5.2.2", SmtpReplyBuffer); + if (bitset(MCIF_SIZE, mci->mci_flags)) + e->e_flags |= EF_NO_BODY_RETN; return EX_UNAVAILABLE; } else if (REPLYTYPE(r) == 5) @@ -533,14 +535,13 @@ smtpmailfrom(m, mci, e) return EX_UNAVAILABLE; } -#ifdef LOG if (LogLevel > 1) { - syslog(LOG_CRIT, "%s: %.100s: SMTP MAIL protocol error: %s", - e->e_id, mci->mci_host, + sm_syslog(LOG_CRIT, e->e_id, + "%.100s: SMTP MAIL protocol error: %s", + mci->mci_host, shortenstring(SmtpReplyBuffer, 403)); } -#endif /* protocol error -- close up */ mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); @@ -651,14 +652,13 @@ smtprcpt(to, m, mci, e) return EX_UNAVAILABLE; } -#ifdef LOG if (LogLevel > 1) { - syslog(LOG_CRIT, "%s: %.100s: SMTP RCPT protocol error: %s", - e->e_id, mci->mci_host, + sm_syslog(LOG_CRIT, e->e_id, + "%.100s: SMTP RCPT protocol error: %s", + mci->mci_host, shortenstring(SmtpReplyBuffer, 403)); } -#endif mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); return EX_PROTOCOL; @@ -718,14 +718,13 @@ smtpdata(m, mci, e) } else if (r != 354) { -#ifdef LOG if (LogLevel > 1) { - syslog(LOG_CRIT, "%s: %.100s: SMTP DATA-1 protocol error: %s", - e->e_id, mci->mci_host, + sm_syslog(LOG_CRIT, e->e_id, + "%.100s: SMTP DATA-1 protocol error: %s", + mci->mci_host, shortenstring(SmtpReplyBuffer, 403)); } -#endif smtprset(m, mci, e); mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); return (EX_PROTOCOL); @@ -800,8 +799,6 @@ smtpdata(m, mci, e) xstat = EX_NOTSTICKY; if (r == 452) rstat = EX_TEMPFAIL; - else if (r == 552) - rstat = EX_UNAVAILABLE; else if (REPLYTYPE(r) == 4) rstat = xstat = EX_TEMPFAIL; else if (REPLYCLASS(r) != 5) @@ -809,7 +806,7 @@ smtpdata(m, mci, e) else if (REPLYTYPE(r) == 2) rstat = xstat = EX_OK; else if (REPLYTYPE(r) == 5) - rstat = xstat = EX_UNAVAILABLE; + rstat = EX_UNAVAILABLE; else rstat = EX_PROTOCOL; mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer); @@ -818,14 +815,13 @@ smtpdata(m, mci, e) e->e_statmsg = newstr(&SmtpReplyBuffer[4]); if (rstat != EX_PROTOCOL) return rstat; -#ifdef LOG if (LogLevel > 1) { - syslog(LOG_CRIT, "%s: %.100s: SMTP DATA-2 protocol error: %s", - e->e_id, mci->mci_host, + sm_syslog(LOG_CRIT, e->e_id, + "%.100s: SMTP DATA-2 protocol error: %s", + mci->mci_host, shortenstring(SmtpReplyBuffer, 403)); } -#endif return rstat; } @@ -877,14 +873,13 @@ smtpgetstat(m, mci, e) else if (REPLYTYPE(r) == 5) stat = EX_UNAVAILABLE; mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer); -#ifdef LOG if (LogLevel > 1 && stat == EX_PROTOCOL) { - syslog(LOG_CRIT, "%s: %.100s: SMTP DATA-3 protocol error: %s", - e->e_id, mci->mci_host, + sm_syslog(LOG_CRIT, e->e_id, + "%.100s: SMTP DATA-3 protocol error: %s", + mci->mci_host, shortenstring(SmtpReplyBuffer, 403)); } -#endif return stat; } @@ -929,10 +924,7 @@ smtpquit(m, mci, e) (void) reply(m, mci, e, TimeOuts.to_quit, NULL); SuprErrs = oldSuprErrs; if (mci->mci_state == MCIS_CLOSED) - { - SuprErrs = oldSuprErrs; return; - } } /* now actually close the connection and pick up the zombie */ @@ -1025,7 +1017,8 @@ reply(m, mci, e, timeout, pfunc) ** Read the input line, being careful not to hang. */ - for (bufp = SmtpReplyBuffer;; bufp = junkbuf) + bufp = SmtpReplyBuffer; + for (;;) { register char *p; extern time_t curtime(); @@ -1120,26 +1113,32 @@ reply(m, mci, e, timeout, pfunc) if (Verbose) nmessage("050 %s", bufp); + /* ignore improperly formated input */ + if (!(isascii(bufp[0]) && isdigit(bufp[0])) || + !(isascii(bufp[1]) && isdigit(bufp[1])) || + !(isascii(bufp[2]) && isdigit(bufp[2])) || + !(bufp[3] == ' ' || bufp[3] == '-')) + continue; + /* process the line */ if (pfunc != NULL) (*pfunc)(bufp, firstline, m, mci, e); firstline = FALSE; - /* if continuation is required, we can go on */ - if (bufp[3] == '-') - continue; - - /* ignore improperly formated input */ - if (!(isascii(bufp[0]) && isdigit(bufp[0]))) - continue; - /* decode the reply code */ r = atoi(bufp); /* extra semantics: 0xx codes are "informational" */ - if (r >= 100) + if (r < 100) + continue; + + /* if no continuation lines, return this line */ + if (bufp[3] != '-') break; + + /* first line of real reply -- ignore rest */ + bufp = junkbuf; } /* diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c index 242b615..5e5e7af 100644 --- a/usr.sbin/sendmail/src/util.c +++ b/usr.sbin/sendmail/src/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)util.c 8.115 (Berkeley) 1/5/97"; +static char sccsid[] = "@(#)util.c 8.129 (Berkeley) 6/11/97"; #endif /* not lint */ # include "sendmail.h" @@ -449,352 +449,6 @@ buildfname(gecos, login, buf, buflen) *bp = '\0'; } /* -** SAFEFILE -- return true if a file exists and is safe for a user. -** -** Parameters: -** fn -- filename to check. -** uid -- user id to compare against. -** gid -- group id to compare against. -** uname -- user name to compare against (used for group -** sets). -** flags -- modifiers: -** SFF_MUSTOWN -- "uid" must own this file. -** SFF_NOSLINK -- file cannot be a symbolic link. -** mode -- mode bits that must match. -** st -- if set, points to a stat structure that will -** get the stat info for the file. -** -** Returns: -** 0 if fn exists, is owned by uid, and matches mode. -** An errno otherwise. The actual errno is cleared. -** -** Side Effects: -** none. -*/ - -#include <grp.h> - -#ifndef S_IXOTH -# define S_IXOTH (S_IEXEC >> 6) -#endif - -#ifndef S_IXGRP -# define S_IXGRP (S_IEXEC >> 3) -#endif - -#ifndef S_IXUSR -# define S_IXUSR (S_IEXEC) -#endif - -#define ST_MODE_NOFILE 0171147 /* unlikely to occur */ - -int -safefile(fn, uid, gid, uname, flags, mode, st) - char *fn; - UID_T uid; - GID_T gid; - char *uname; - int flags; - int mode; - struct stat *st; -{ - register char *p; - register struct group *gr = NULL; - int file_errno = 0; - struct stat stbuf; - struct stat fstbuf; - - if (tTd(44, 4)) - printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", - fn, (int) uid, (int) gid, flags, mode); - errno = 0; - if (st == NULL) - st = &fstbuf; - - /* first check to see if the file exists at all */ -#ifdef HASLSTAT - if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) - : stat(fn, st)) < 0) -#else - if (stat(fn, st) < 0) -#endif - { - file_errno = errno; - } - else if (bitset(SFF_SETUIDOK, flags) && - !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) && - S_ISREG(st->st_mode)) - { - /* - ** If final file is setuid, run as the owner of that - ** file. Gotta be careful not to reveal anything too - ** soon here! - */ - -#ifdef SUID_ROOT_FILES_OK - if (bitset(S_ISUID, st->st_mode)) -#else - if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0) -#endif - { - uid = st->st_uid; - uname = NULL; - } -#ifdef SUID_ROOT_FILES_OK - if (bitset(S_ISGID, st->st_mode)) -#else - if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0) -#endif - gid = st->st_gid; - } - - if (!bitset(SFF_NOPATHCHECK, flags) || - (uid == 0 && !bitset(SFF_ROOTOK, flags))) - { - /* check the path to the file for acceptability */ - for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') - { - *p = '\0'; - if (stat(fn, &stbuf) < 0) - break; - if (uid == 0 && bitset(S_IWGRP|S_IWOTH, stbuf.st_mode)) - message("051 WARNING: writable directory %s", - fn); - if (uid == 0 && !bitset(SFF_ROOTOK, flags)) - { - if (bitset(S_IXOTH, stbuf.st_mode)) - continue; - break; - } - if (stbuf.st_uid == uid && - bitset(S_IXUSR, stbuf.st_mode)) - continue; - if (stbuf.st_gid == gid && - bitset(S_IXGRP, stbuf.st_mode)) - continue; -#ifndef NO_GROUP_SET - if (uname != NULL && !DontInitGroups && - ((gr != NULL && gr->gr_gid == stbuf.st_gid) || - (gr = getgrgid(stbuf.st_gid)) != NULL)) - { - register char **gp; - - for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) - if (strcmp(*gp, uname) == 0) - break; - if (gp != NULL && *gp != NULL && - bitset(S_IXGRP, stbuf.st_mode)) - continue; - } -#endif - if (!bitset(S_IXOTH, stbuf.st_mode)) - break; - } - if (p != NULL) - { - int ret = errno; - - if (ret == 0) - ret = EACCES; - if (tTd(44, 4)) - printf("\t[dir %s] %s\n", fn, errstring(ret)); - *p = '/'; - return ret; - } - } - - /* - ** If the target file doesn't exist, check the directory to - ** ensure that it is writable by this user. - */ - - if (file_errno != 0) - { - int ret = file_errno; - - if (tTd(44, 4)) - printf("\t%s\n", errstring(ret)); - - errno = 0; - if (!bitset(SFF_CREAT, flags)) - return ret; - - /* check to see if legal to create the file */ - p = strrchr(fn, '/'); - if (p == NULL) - return ENOTDIR; - *p = '\0'; - if (stat(fn, &stbuf) >= 0) - { - int md = S_IWRITE|S_IEXEC; - if (stbuf.st_uid != uid) - md >>= 6; - if ((stbuf.st_mode & md) != md) - errno = EACCES; - } - ret = errno; - if (tTd(44, 4)) - printf("\t[final dir %s uid %d mode %lo] %s\n", - fn, (int) stbuf.st_uid, (u_long) stbuf.st_mode, - errstring(ret)); - *p = '/'; - st->st_mode = ST_MODE_NOFILE; - return ret; - } - -#ifdef S_ISLNK - if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) - { - if (tTd(44, 4)) - printf("\t[slink mode %o]\tEPERM\n", st->st_mode); - return EPERM; - } -#endif - if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) - { - if (tTd(44, 4)) - printf("\t[non-reg mode %o]\tEPERM\n", st->st_mode); - return EPERM; - } - if (bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && - bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) - { - if (tTd(44, 4)) - printf("\t[exec bits %o]\tEPERM]\n", st->st_mode); - return EPERM; - } - if (st->st_nlink > 1) - { - if (tTd(44, 4)) - printf("\t[link count %d]\tEPERM\n", st->st_nlink); - return EPERM; - } - - if (uid == 0 && bitset(SFF_OPENASROOT, flags)) - ; - else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) - mode >>= 6; - else if (st->st_uid != uid) - { - mode >>= 3; - if (st->st_gid == gid) - ; -#ifndef NO_GROUP_SET - else if (uname != NULL && !DontInitGroups && - ((gr != NULL && gr->gr_gid == st->st_gid) || - (gr = getgrgid(st->st_gid)) != NULL)) - { - register char **gp; - - for (gp = gr->gr_mem; *gp != NULL; gp++) - if (strcmp(*gp, uname) == 0) - break; - if (*gp == NULL) - mode >>= 3; - } -#endif - else - mode >>= 3; - } - if (tTd(44, 4)) - printf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", - (int) st->st_uid, (int) st->st_nlink, - (u_long) st->st_mode, (u_long) mode); - if ((st->st_uid == uid || st->st_uid == 0 || - !bitset(SFF_MUSTOWN, flags)) && - (st->st_mode & mode) == mode) - { - if (tTd(44, 4)) - printf("\tOK\n"); - return 0; - } - if (tTd(44, 4)) - printf("\tEACCES\n"); - return EACCES; -} -/* -** SAFEFOPEN -- do a file open with extra checking -** -** Parameters: -** fn -- the file name to open. -** omode -- the open-style mode flags. -** cmode -- the create-style mode flags. -** sff -- safefile flags. -** -** Returns: -** Same as fopen. -*/ - -#ifndef O_ACCMODE -# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) -#endif - -FILE * -safefopen(fn, omode, cmode, sff) - char *fn; - int omode; - int cmode; - int sff; -{ - int rval; - FILE *fp; - int smode; - struct stat stb, sta; - - if (bitset(O_CREAT, omode)) - sff |= SFF_CREAT; - smode = 0; - switch (omode & O_ACCMODE) - { - case O_RDONLY: - smode = S_IREAD; - break; - - case O_WRONLY: - smode = S_IWRITE; - break; - - case O_RDWR: - smode = S_IREAD|S_IWRITE; - break; - - default: - smode = 0; - break; - } - if (bitset(SFF_OPENASROOT, sff)) - rval = safefile(fn, 0, 0, NULL, sff, smode, &stb); - else - rval = safefile(fn, RealUid, RealGid, RealUserName, - sff, smode, &stb); - if (rval != 0) - { - errno = rval; - return NULL; - } - if (stb.st_mode == ST_MODE_NOFILE) - omode |= O_EXCL; - - fp = dfopen(fn, omode, cmode); - if (fp == NULL) - return NULL; - if (bitset(O_EXCL, omode)) - return fp; - if (fstat(fileno(fp), &sta) < 0 || - sta.st_nlink != stb.st_nlink || - sta.st_dev != stb.st_dev || - sta.st_ino != stb.st_ino || - sta.st_uid != stb.st_uid || - sta.st_gid != stb.st_gid) - { - syserr("554 cannot open: file %s changed after open", fn); - fclose(fp); - errno = EPERM; - return NULL; - } - return fp; -} -/* ** FIXCRLF -- fix <CR><LF> in line. ** ** Looks for the <CR><LF> combination and turns it into the @@ -830,80 +484,6 @@ fixcrlf(line, stripnl) *p = '\0'; } /* -** DFOPEN -- determined file open -** -** This routine has the semantics of fopen, except that it will -** keep trying a few times to make this happen. The idea is that -** on very loaded systems, we may run out of resources (inodes, -** whatever), so this tries to get around it. -*/ - -struct omodes -{ - int mask; - int mode; - char *farg; -} OpenModes[] = -{ - { O_ACCMODE, O_RDONLY, "r" }, - { O_ACCMODE|O_APPEND, O_WRONLY, "w" }, - { O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a" }, - { O_TRUNC, 0, "w+" }, - { O_APPEND, O_APPEND, "a+" }, - { 0, 0, "r+" }, -}; - -FILE * -dfopen(filename, omode, cmode) - char *filename; - int omode; - int cmode; -{ - register int tries; - int fd; - register struct omodes *om; - struct stat st; - - for (om = OpenModes; om->mask != 0; om++) - if ((omode & om->mask) == om->mode) - break; - - for (tries = 0; tries < 10; tries++) - { - sleep((unsigned) (10 * tries)); - errno = 0; - fd = open(filename, omode, cmode); - if (fd >= 0) - break; - switch (errno) - { - case ENFILE: /* system file table full */ - case EINTR: /* interrupted syscall */ -#ifdef ETXTBSY - case ETXTBSY: /* Apollo: net file locked */ -#endif - continue; - } - break; - } - if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) - { - int locktype; - - /* lock the file to avoid accidental conflicts */ - if ((omode & O_ACCMODE) != O_RDONLY) - locktype = LOCK_EX; - else - locktype = LOCK_SH; - (void) lockfile(fd, filename, NULL, locktype); - errno = 0; - } - if (fd < 0) - return NULL; - else - return fdopen(fd, om->farg); -} -/* ** PUTLINE -- put a line like fputs obeying SMTP conventions ** ** This routine always guarantees outputing a newline (or CRLF, @@ -925,7 +505,7 @@ putline(l, mci) register char *l; register MCI *mci; { - putxline(l, mci, PXLF_MAPFROM); + putxline(l, strlen(l), mci, PXLF_MAPFROM); } /* ** PUTXLINE -- putline with flags bits. @@ -935,6 +515,7 @@ putline(l, mci) ** ** Parameters: ** l -- line to put. +** len -- the length of the line. ** mci -- the mailer connection information. ** pxflags -- flag bits: ** PXLF_MAPFROM -- map From_ to >From_. @@ -948,12 +529,13 @@ putline(l, mci) */ void -putxline(l, mci, pxflags) +putxline(l, len, mci, pxflags) register char *l; + size_t len; register MCI *mci; int pxflags; { - register char *p; + register char *p, *end; register char svchar; int slop = 0; @@ -966,12 +548,13 @@ putxline(l, mci, pxflags) *p = svchar &~ 0200; } + end = l + len; do { /* find the end of the line */ - p = strchr(l, '\n'); + p = memchr(l, '\n', end - l); if (p == NULL) - p = &l[strlen(l)]; + p = end; if (TrafficLogFile != NULL) fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); @@ -1005,8 +588,12 @@ putxline(l, mci, pxflags) fputs(mci->mci_mailer->m_eol, mci->mci_out); (void) putc(' ', mci->mci_out); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%s!\n%05d >>> ", - l, (int) getpid()); + { + for ( ; l < q; ++l) + (void) putc(*l, TrafficLogFile); + fprintf(TrafficLogFile, "!\n%05d >>> ", + (int) getpid()); + } *q = svchar; l = q; slop = 1; @@ -1029,10 +616,14 @@ putxline(l, mci, pxflags) if (TrafficLogFile != NULL) (void) putc('>', TrafficLogFile); } - if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%.*s\n", p - l, l); for ( ; l < p; ++l) + { + if (TrafficLogFile != NULL) + (void) putc(*l, TrafficLogFile); (void) putc(*l, mci->mci_out); + } + if (TrafficLogFile != NULL) + (void) putc('\n', TrafficLogFile); fputs(mci->mci_mailer->m_eol, mci->mci_out); if (*l == '\n') { @@ -1043,7 +634,7 @@ putxline(l, mci, pxflags) (void) putc(' ', TrafficLogFile); } } - } while (l[0] != '\0'); + } while (l < end); } /* ** XUNLINK -- unlink a file, doing logging as appropriate. @@ -1064,16 +655,16 @@ xunlink(f) { register int i; -# ifdef LOG if (LogLevel > 98) - syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); -# endif /* LOG */ + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "unlink %s", + f); i = unlink(f); -# ifdef LOG if (i < 0 && LogLevel > 97) - syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); -# endif /* LOG */ + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "%s: unlink-fail %d", + f, errno); } /* ** XFCLOSE -- close a file, doing logging as appropriate. @@ -1147,20 +738,19 @@ sfgets(buf, siz, fp, timeout, during) { if (setjmp(CtxReadTimeout) != 0) { -# ifdef LOG if (LogLevel > 1) - syslog(LOG_NOTICE, + sm_syslog(LOG_NOTICE, CurEnv->e_id, "timeout waiting for input from %.100s during %s", CurHostName ? CurHostName : "local", during); -# endif errno = 0; - usrerr("451 timeout waiting for input during %s", - during); buf[0] = '\0'; #if XDEBUG checkfd012(during); #endif + if (TrafficLogFile != NULL) + fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", + (int) getpid()); return (NULL); } ev = setevent(timeout, readtimeout, 0); @@ -1365,46 +955,6 @@ atooct(s) return (i); } /* -** WAITFOR -- wait for a particular process id. -** -** Parameters: -** pid -- process id to wait for. -** -** Returns: -** status of pid. -** -1 if pid never shows up. -** -** Side Effects: -** none. -*/ - -int -waitfor(pid) - pid_t pid; -{ -#ifdef WAITUNION - union wait st; -#else - auto int st; -#endif - pid_t i; - - do - { - errno = 0; - i = wait(&st); - if (i > 0) - proc_list_drop(i); - } while ((i >= 0 || errno == EINTR) && i != pid); - if (i < 0) - return -1; -#ifdef WAITUNION - return st.w_status; -#else - return st; -#endif -} -/* ** BITINTERSECT -- tell if two bitmaps intersect ** ** Parameters: @@ -1606,7 +1156,9 @@ checkfds(where) continue; if (printhdr) { - syslog(LOG_DEBUG, "%s: changed fds:", where); + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "%s: changed fds:", + where); printhdr = FALSE; } dumpfd(fd, TRUE, TRUE); @@ -1772,11 +1324,10 @@ defprint: } printit: -#ifdef LOG if (logit) - syslog(LOG_DEBUG, "%.800s", buf); + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "%.800s", buf); else -#endif printf("%s\n", buf); } /* @@ -2084,10 +1635,8 @@ cleanstrcpy(t, f, l) register char *f; int l; { -#ifdef LOG /* check for newlines and log if necessary */ (void) denlstring(f, TRUE, TRUE); -#endif l--; while (l > 0 && *f != '\0') @@ -2146,20 +1695,23 @@ denlstring(s, strict, logattacks) for (p = bp; (p = strchr(p, '\n')) != NULL; ) *p++ = ' '; -#ifdef LOG if (logattacks) { - syslog(LOG_NOTICE, "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", + sm_syslog(LOG_NOTICE, CurEnv->e_id, + "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", RealHostName == NULL ? "[UNKNOWN]" : RealHostName, shortenstring(bp, 203)); } -#endif return bp; } /* ** PATH_IS_DIR -- check to see if file exists and is a directory. ** +** There are some additional checks for security violations in +** here. This routine is intended to be used for the host status +** support. +** ** Parameters: ** pathname -- pathname to check for directory-ness. ** createflag -- if set, create directory if needed. @@ -2176,7 +1728,11 @@ path_is_dir(pathname, createflag) { struct stat statbuf; +#if HASLSTAT + if (lstat(pathname, &statbuf) < 0) +#else if (stat(pathname, &statbuf) < 0) +#endif { if (errno != ENOENT || !createflag) return FALSE; @@ -2189,6 +1745,14 @@ path_is_dir(pathname, createflag) errno = ENOTDIR; return FALSE; } + + /* security: don't allow writable directories */ + if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) + { + errno = EACCES; + return FALSE; + } + return TRUE; } /* @@ -2320,11 +1884,10 @@ proc_list_probe() continue; if (kill(ProcListVec[i], 0) < 0) { -#ifdef LOG if (LogLevel > 3) - syslog(LOG_DEBUG, "proc_list_probe: lost pid %d", + sm_syslog(LOG_DEBUG, CurEnv->e_id, + "proc_list_probe: lost pid %d", ProcListVec[i]); -#endif ProcListVec[i] = NO_PID; CurChildren--; } @@ -2332,3 +1895,119 @@ proc_list_probe() if (CurChildren < 0) CurChildren = 0; } +/* +** SM_STRCASECMP -- 8-bit clean version of strcasecmp +** +** Thank you, vendors, for making this all necessary. +*/ + +/* + * 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[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { + 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, + 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, + 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, + 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, + 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, + 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, + 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, + 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, + 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, +}; + +int +sm_strcasecmp(s1, s2) + const char *s1, *s2; +{ + register const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return (0); + return (cm[*us1] - cm[*--us2]); +} + +int +sm_strncasecmp(s1, s2, n) + const char *s1, *s2; + register size_t n; +{ + if (n != 0) { + register const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + do { + if (cm[*us1] != cm[*us2++]) + return (cm[*us1] - cm[*--us2]); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +} |