better handling of transient errors
authorEric Allman <eric@ucbvax.Berkeley.EDU>
Sat, 27 Feb 1993 00:19:40 +0000 (16:19 -0800)
committerEric Allman <eric@ucbvax.Berkeley.EDU>
Sat, 27 Feb 1993 00:19:40 +0000 (16:19 -0800)
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
usr/src/usr.sbin/sendmail/src/deliver.c
usr/src/usr.sbin/sendmail/src/envelope.c
usr/src/usr.sbin/sendmail/src/recipient.c
usr/src/usr.sbin/sendmail/src/util.c

index b18616c..8838e48 100644 (file)
@@ -29,15 +29,15 @@ ERROR: DBM is no longer supported -- use NDBM instead.
 #ifndef lint
 #ifdef NEWDB
 #ifdef NDBM
 #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
 #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
 #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
 #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 */
 #endif
 #endif
 #endif /* not lint */
@@ -925,7 +925,6 @@ forward(user, sendq, e)
 {
        char *pp;
        char *ep;
 {
        char *pp;
        char *ep;
-       extern bool safefile();
 
        if (tTd(27, 1))
                printf("forward(%s)\n", user->q_paddr);
 
        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)
        {
 
        for (pp = ForwardPath; pp != NULL; pp = ep)
        {
+               int err;
                char buf[MAXPATHLEN+1];
                char buf[MAXPATHLEN+1];
+               extern bool transienterror();
 
                ep = strchr(pp, ':');
                if (ep != NULL)
 
                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);
                        *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;
                        break;
+               if (transienterror(err))
+               {
+                       /* we have to suspend this message */
+                       user->q_flags |= QQUEUEUP|QDONTSEND;
+                       return;
+               }
        }
 }
 \f/*
        }
 }
 \f/*
index 6257aba..93d71a2 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #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"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -106,7 +106,8 @@ deliver(e, firstto)
        {
                for (; to != NULL; to = to->q_next)
                {
        {
                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;
                                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 */
                        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;
                    to->q_mailer != firstto->q_mailer ||
                    strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0)
                        continue;
index b36383b..168084a 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)envelope.c 6.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)envelope.c 6.15 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -428,7 +428,6 @@ setsender(from, e)
        extern struct passwd *getpwnam();
        extern char *macvalue();
        extern char **prescan();
        extern struct passwd *getpwnam();
        extern char *macvalue();
        extern char **prescan();
-       extern bool safefile();
        extern char *FullName;
 
        if (tTd(45, 1))
        extern char *FullName;
 
        if (tTd(45, 1))
index c362a8d..061ee52 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)recipient.c        6.17 (Berkeley) %G%";
+static char sccsid[] = "@(#)recipient.c        6.18 (Berkeley) %G%";
 #endif /* not lint */
 
 # include <sys/types.h>
 #endif /* not lint */
 
 # include <sys/types.h>
@@ -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.
 **                     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:
 **             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 */
        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;
 
        e->e_to = a->q_paddr;
        m = a->q_mailer;
@@ -315,8 +316,12 @@ recipient(a, sendq, e)
                }
                else
                {
                }
                else
                {
+                       int err;
+
                        message("including file %s", a->q_user);
                        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)
                }
        }
        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)) :
                        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);
                {
                        a->q_flags |= QBADADDR;
                        giveresponse(EX_CANTCREAT, m, e);
@@ -357,7 +362,7 @@ recipient(a, sendq, e)
 
                if (udbexpand(a, sendq, e) == EX_TEMPFAIL)
                {
 
                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
                        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 */
 # 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);
 
        /*
                return (a);
 
        /*
@@ -400,7 +405,7 @@ recipient(a, sendq, e)
        **  and deliver it.
        */
 
        **  and deliver it.
        */
 
-       if (!bitset(QDONTSEND, a->q_flags))
+       if (!bitset(QDONTSEND|QQUEUEUP, a->q_flags))
        {
                auto bool fuzzy;
                register struct passwd *pw;
        {
                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 oldlinenumber = LineNumber;
        register EVENT *ev = NULL;
        int nincludes;
+       int ret;
        char buf[MAXLINE];
        static int includetimeout();
 
        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 */
        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))
        {
                /* 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");
        }
 
        fp = fopen(fname, "r");
@@ -745,6 +752,7 @@ includetimeout()
 **
 **     Parameters:
 **             argv -- argument vector to send to.
 **
 **     Parameters:
 **             argv -- argument vector to send to.
+**             e -- the current envelope.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
index 6711b3a..3f2d633 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)util.c     6.7 (Berkeley) %G%";
+static char sccsid[] = "@(#)util.c     6.8 (Berkeley) %G%";
 #endif /* not lint */
 
 # include <stdio.h>
 #endif /* not lint */
 
 # include <stdio.h>
@@ -420,14 +420,14 @@ fullname(pw, buf)
 **             mode -- mode bits that must match.
 **
 **     Returns:
 **             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.
 */
 
 **
 **     Side Effects:
 **             none.
 */
 
-bool
+int
 safefile(fn, uid, mode)
        char *fn;
        uid_t uid;
 safefile(fn, uid, mode)
        char *fn;
        uid_t uid;
@@ -435,11 +435,16 @@ safefile(fn, uid, mode)
 {
        struct stat stbuf;
 
 {
        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;
 }
 \f/*
 **  FIXCRLF -- fix <CR><LF> in line.
 }
 \f/*
 **  FIXCRLF -- fix <CR><LF> in line.
@@ -919,3 +924,85 @@ bitzerop(map)
                        return (FALSE);
        return (TRUE);
 }
                        return (FALSE);
        return (TRUE);
 }
+\f/*
+**  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;
+}