From 118e66930a750fc19073e1520aaad0ec05999404 Mon Sep 17 00:00:00 2001 From: Eric Allman Date: Fri, 26 Feb 1993 16:19:40 -0800 Subject: [PATCH] better handling of transient errors SCCS-vsn: usr.sbin/sendmail/src/alias.c 6.19 SCCS-vsn: usr.sbin/sendmail/src/deliver.c 6.27 SCCS-vsn: usr.sbin/sendmail/src/util.c 6.8 SCCS-vsn: usr.sbin/sendmail/src/envelope.c 6.15 SCCS-vsn: usr.sbin/sendmail/src/recipient.c 6.18 --- usr/src/usr.sbin/sendmail/src/alias.c | 20 +++-- usr/src/usr.sbin/sendmail/src/deliver.c | 7 +- usr/src/usr.sbin/sendmail/src/envelope.c | 3 +- usr/src/usr.sbin/sendmail/src/recipient.c | 28 +++--- usr/src/usr.sbin/sendmail/src/util.c | 105 ++++++++++++++++++++-- 5 files changed, 133 insertions(+), 30 deletions(-) diff --git a/usr/src/usr.sbin/sendmail/src/alias.c b/usr/src/usr.sbin/sendmail/src/alias.c index b18616ca8d..8838e489b7 100644 --- a/usr/src/usr.sbin/sendmail/src/alias.c +++ b/usr/src/usr.sbin/sendmail/src/alias.c @@ -29,15 +29,15 @@ ERROR: DBM is no longer supported -- use NDBM instead. #ifndef lint #ifdef NEWDB #ifdef NDBM -static char sccsid[] = "@(#)alias.c 6.18 (Berkeley) %G% (with NEWDB and NDBM)"; +static char sccsid[] = "@(#)alias.c 6.19 (Berkeley) %G% (with NEWDB and NDBM)"; #else -static char sccsid[] = "@(#)alias.c 6.18 (Berkeley) %G% (with NEWDB)"; +static char sccsid[] = "@(#)alias.c 6.19 (Berkeley) %G% (with NEWDB)"; #endif #else #ifdef NDBM -static char sccsid[] = "@(#)alias.c 6.18 (Berkeley) %G% (with NDBM)"; +static char sccsid[] = "@(#)alias.c 6.19 (Berkeley) %G% (with NDBM)"; #else -static char sccsid[] = "@(#)alias.c 6.18 (Berkeley) %G% (without NEWDB or NDBM)"; +static char sccsid[] = "@(#)alias.c 6.19 (Berkeley) %G% (without NEWDB or NDBM)"; #endif #endif #endif /* not lint */ @@ -925,7 +925,6 @@ forward(user, sendq, e) { char *pp; char *ep; - extern bool safefile(); if (tTd(27, 1)) printf("forward(%s)\n", user->q_paddr); @@ -947,7 +946,9 @@ forward(user, sendq, e) for (pp = ForwardPath; pp != NULL; pp = ep) { + int err; char buf[MAXPATHLEN+1]; + extern bool transienterror(); ep = strchr(pp, ':'); if (ep != NULL) @@ -957,8 +958,15 @@ forward(user, sendq, e) *ep++ = ':'; if (tTd(27, 3)) printf("forward: trying %s\n", buf); - if (include(buf, TRUE, user, sendq, e) == 0) + err = include(buf, TRUE, user, sendq, e); + if (err == 0) break; + if (transienterror(err)) + { + /* we have to suspend this message */ + user->q_flags |= QQUEUEUP|QDONTSEND; + return; + } } } /* diff --git a/usr/src/usr.sbin/sendmail/src/deliver.c b/usr/src/usr.sbin/sendmail/src/deliver.c index 6257aba27a..93d71a2b74 100644 --- a/usr/src/usr.sbin/sendmail/src/deliver.c +++ b/usr/src/usr.sbin/sendmail/src/deliver.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 6.26 (Berkeley) %G%"; +static char sccsid[] = "@(#)deliver.c 6.27 (Berkeley) %G%"; #endif /* not lint */ #include "sendmail.h" @@ -106,7 +106,8 @@ deliver(e, firstto) { for (; to != NULL; to = to->q_next) { - if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) + if (bitset(QDONTSEND|QQUEUEUP, to->q_flags) || + to->q_mailer != m) continue; to->q_flags |= QQUEUEUP|QDONTSEND; e->e_to = to->q_paddr; @@ -230,7 +231,7 @@ deliver(e, firstto) break; /* if already sent or not for this host, don't send */ - if (bitset(QDONTSEND, to->q_flags) || + if (bitset(QDONTSEND|QQUEUEUP, to->q_flags) || to->q_mailer != firstto->q_mailer || strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) continue; diff --git a/usr/src/usr.sbin/sendmail/src/envelope.c b/usr/src/usr.sbin/sendmail/src/envelope.c index b36383bcea..168084a7e3 100644 --- a/usr/src/usr.sbin/sendmail/src/envelope.c +++ b/usr/src/usr.sbin/sendmail/src/envelope.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)envelope.c 6.14 (Berkeley) %G%"; +static char sccsid[] = "@(#)envelope.c 6.15 (Berkeley) %G%"; #endif /* not lint */ #include @@ -428,7 +428,6 @@ setsender(from, e) extern struct passwd *getpwnam(); extern char *macvalue(); extern char **prescan(); - extern bool safefile(); extern char *FullName; if (tTd(45, 1)) diff --git a/usr/src/usr.sbin/sendmail/src/recipient.c b/usr/src/usr.sbin/sendmail/src/recipient.c index c362a8d5d3..061ee52613 100644 --- a/usr/src/usr.sbin/sendmail/src/recipient.c +++ b/usr/src/usr.sbin/sendmail/src/recipient.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)recipient.c 6.17 (Berkeley) %G%"; +static char sccsid[] = "@(#)recipient.c 6.18 (Berkeley) %G%"; #endif /* not lint */ # include @@ -36,6 +36,7 @@ static char sccsid[] = "@(#)recipient.c 6.17 (Berkeley) %G%"; ** expansion. ** sendq -- a pointer to the head of a queue to put ** these people into. +** e -- the envelope in which to add these recipients. ** qflags -- special flags to set in the q_flags field. ** ** Returns: @@ -215,7 +216,7 @@ recipient(a, sendq, e) bool quoted = FALSE; /* set if the addr has a quote bit */ int findusercount = 0; char buf[MAXNAME]; /* unquoted image of the user name */ - extern bool safefile(); + extern int safefile(); e->e_to = a->q_paddr; m = a->q_mailer; @@ -315,8 +316,12 @@ recipient(a, sendq, e) } else { + int err; + message("including file %s", a->q_user); - (void) include(a->q_user, FALSE, a, sendq, e); + err = include(a->q_user, FALSE, a, sendq, e); + if (transienterror(err)) + a->q_flags |= QQUEUEUP|QDONTSEND; } } else if (m == FileMailer) @@ -332,7 +337,7 @@ recipient(a, sendq, e) usrerr("550 Cannot mail directly to files"); } else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : - (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) + (*p = '\0', safefile(buf, getruid(), S_IWRITE|S_IEXEC) != 0)) { a->q_flags |= QBADADDR; giveresponse(EX_CANTCREAT, m, e); @@ -357,7 +362,7 @@ recipient(a, sendq, e) if (udbexpand(a, sendq, e) == EX_TEMPFAIL) { - a->q_flags |= QQUEUEUP; + a->q_flags |= QQUEUEUP|QDONTSEND; if (e->e_message == NULL) e->e_message = newstr("Deferred: user database error"); # ifdef LOG @@ -373,7 +378,7 @@ recipient(a, sendq, e) # endif /* if it was an alias or a UDB expansion, just return now */ - if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) + if (bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags)) return (a); /* @@ -400,7 +405,7 @@ recipient(a, sendq, e) ** and deliver it. */ - if (!bitset(QDONTSEND, a->q_flags)) + if (!bitset(QDONTSEND|QQUEUEUP, a->q_flags)) { auto bool fuzzy; register struct passwd *pw; @@ -626,6 +631,7 @@ include(fname, forwarding, ctladdr, sendq, e) int oldlinenumber = LineNumber; register EVENT *ev = NULL; int nincludes; + int ret; char buf[MAXLINE]; static int includetimeout(); @@ -647,13 +653,14 @@ include(fname, forwarding, ctladdr, sendq, e) ev = setevent((time_t) 60, includetimeout, 0); /* if forwarding, the input file must be marked safe */ - if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD)) + if (forwarding && (ret = safefile(fname, ctladdr->q_uid, S_IREAD)) != 0) { /* don't use this .forward file */ clrevent(ev); if (tTd(27, 4)) - printf("include: not safe (uid=%d)\n", ctladdr->q_uid); - return EPERM; + printf("include: not safe (uid=%d): %s\n", + ctladdr->q_uid, errstring(ret)); + return ret; } fp = fopen(fname, "r"); @@ -745,6 +752,7 @@ includetimeout() ** ** Parameters: ** argv -- argument vector to send to. +** e -- the current envelope. ** ** Returns: ** none. diff --git a/usr/src/usr.sbin/sendmail/src/util.c b/usr/src/usr.sbin/sendmail/src/util.c index 6711b3a9f8..3f2d63358d 100644 --- a/usr/src/usr.sbin/sendmail/src/util.c +++ b/usr/src/usr.sbin/sendmail/src/util.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)util.c 6.7 (Berkeley) %G%"; +static char sccsid[] = "@(#)util.c 6.8 (Berkeley) %G%"; #endif /* not lint */ # include @@ -420,14 +420,14 @@ fullname(pw, buf) ** mode -- mode bits that must match. ** ** Returns: -** TRUE if fn exists, is owned by uid, and matches mode. -** FALSE otherwise. +** 0 if fn exists, is owned by uid, and matches mode. +** An errno otherwise. The actual errno is cleared. ** ** Side Effects: ** none. */ -bool +int safefile(fn, uid, mode) char *fn; uid_t uid; @@ -435,11 +435,16 @@ safefile(fn, uid, mode) { struct stat stbuf; - if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && - (stbuf.st_mode & mode) == mode) - return (TRUE); - errno = 0; - return (FALSE); + if (stat(fn, &stbuf) < 0) + { + int ret = errno; + + errno = 0; + return ret; + } + if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) + return 0; + return EPERM; } /* ** FIXCRLF -- fix in line. @@ -919,3 +924,85 @@ bitzerop(map) return (FALSE); return (TRUE); } + /* +** TRANSIENTERROR -- tell if an error code indicates a transient failure +** +** This looks at an errno value and tells if this is likely to +** go away if retried later. +** +** Parameters: +** err -- the errno code to classify. +** +** Returns: +** TRUE if this is probably transient. +** FALSE otherwise. +*/ + +bool +transienterror(err) + int err; +{ + switch (err) + { + case EIO: /* I/O error */ + case ENXIO: /* Device not configured */ + case EAGAIN: /* Resource temporarily unavailable */ + case ENOMEM: /* Cannot allocate memory */ + case ENODEV: /* Operation not supported by device */ + case ENFILE: /* Too many open files in system */ + case EMFILE: /* Too many open files */ + case ENOSPC: /* No space left on device */ +#ifdef ETIMEDOUT + case ETIMEDOUT: /* Connection timed out */ +#endif +#ifdef ESTALE + case ESTALE: /* Stale NFS file handle */ +#endif +#ifdef ENETDOWN + case ENETDOWN: /* Network is down */ +#endif +#ifdef ENETUNREACH + case ENETUNREACH: /* Network is unreachable */ +#endif +#ifdef ENETRESET + case ENETRESET: /* Network dropped connection on reset */ +#endif +#ifdef ECONNABORTED + case ECONNABORTED: /* Software caused connection abort */ +#endif +#ifdef ECONNRESET + case ECONNRESET: /* Connection reset by peer */ +#endif +#ifdef ENOBUFS + case ENOBUFS: /* No buffer space available */ +#endif +#ifdef ESHUTDOWN + case ESHUTDOWN: /* Can't send after socket shutdown */ +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: /* Connection refused */ +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: /* Host is down */ +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: /* No route to host */ +#endif +#ifdef EDQUOT + case EDQUOT: /* Disc quota exceeded */ +#endif +#ifdef EPROCLIM + case EPROCLIM: /* Too many processes */ +#endif +#ifdef EUSERS + case EUSERS: /* Too many users */ +#endif +#ifdef EDEADLK + case EDEADLK: /* Resource deadlock avoided */ +#endif + return TRUE; + } + + /* nope, must be permanent */ + return FALSE; +} -- 2.20.1