BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / deliver.c
index 25eb945..c8e05f1 100644 (file)
@@ -1,9 +1,52 @@
-# include <signal.h>
-# include <errno.h>
-# include "sendmail.h"
-# include <sys/stat.h>
-
-SCCSID(@(#)deliver.c   4.3             %G%);
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1988 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)deliver.c  5.41 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+#include "sendmail.h"
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef NAMED_BIND
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
 
 /*
 **  DELIVER -- Deliver a message to a list of addresses.
 
 /*
 **  DELIVER -- Deliver a message to a list of addresses.
@@ -41,7 +84,7 @@ deliver(e, firstto)
        register ADDRESS *to = firstto;
        bool clever = FALSE;            /* running user smtp to this mailer */
        ADDRESS *tochain = NULL;        /* chain of users in this mailer call */
        register ADDRESS *to = firstto;
        bool clever = FALSE;            /* running user smtp to this mailer */
        ADDRESS *tochain = NULL;        /* chain of users in this mailer call */
-       register int rcode;             /* response code */
+       int rcode;              /* response code */
        char *pv[MAXPV+1];
        char tobuf[MAXLINE-50];         /* text line of to people */
        char buf[MAXNAME];
        char *pv[MAXPV+1];
        char tobuf[MAXLINE-50];         /* text line of to people */
        char buf[MAXNAME];
@@ -51,17 +94,23 @@ deliver(e, firstto)
        extern char *remotename();
 
        errno = 0;
        extern char *remotename();
 
        errno = 0;
-       if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags))
+       if (bitset(QDONTSEND, to->q_flags))
                return (0);
 
                return (0);
 
+#ifdef NAMED_BIND
+       /* unless interactive, try twice, over a minute */
+       if (OpMode == MD_DAEMON || OpMode == MD_SMTP) {
+               _res.retrans = 30;
+               _res.retry = 2;
+       }
+#endif 
+
        m = to->q_mailer;
        host = to->q_host;
 
        m = to->q_mailer;
        host = to->q_host;
 
-# ifdef DEBUG
        if (tTd(10, 1))
                printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
                        m->m_mno, host, to->q_user);
        if (tTd(10, 1))
                printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
                        m->m_mno, host, to->q_user);
-# endif DEBUG
 
        /*
        **  If this mailer is expensive, and if we don't want to make
 
        /*
        **  If this mailer is expensive, and if we don't want to make
@@ -102,7 +151,7 @@ deliver(e, firstto)
        */
 
        /* rewrite from address, using rewriting rules */
        */
 
        /* rewrite from address, using rewriting rules */
-       expand("$f", buf, &buf[sizeof buf - 1], e);
+       expand("\001f", buf, &buf[sizeof buf - 1], e);
        (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE));
 
        define('g', tfrombuf, e);               /* translated sender address */
        (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE));
 
        define('g', tfrombuf, e);               /* translated sender address */
@@ -118,7 +167,7 @@ deliver(e, firstto)
                        *pvp++ = "-f";
                else
                        *pvp++ = "-r";
                        *pvp++ = "-f";
                else
                        *pvp++ = "-r";
-               expand("$g", buf, &buf[sizeof buf - 1], e);
+               expand("\001g", buf, &buf[sizeof buf - 1], e);
                *pvp++ = newstr(buf);
        }
 
                *pvp++ = newstr(buf);
        }
 
@@ -131,7 +180,7 @@ deliver(e, firstto)
 
        for (mvp = m->m_argv; (p = *++mvp) != NULL; )
        {
 
        for (mvp = m->m_argv; (p = *++mvp) != NULL; )
        {
-               while ((p = index(p, '$')) != NULL)
+               while ((p = index(p, '\001')) != NULL)
                        if (*++p == 'u')
                                break;
                if (p != NULL)
                        if (*++p == 'u')
                                break;
                if (p != NULL)
@@ -189,16 +238,14 @@ deliver(e, firstto)
                        continue;
 
                /* avoid overflowing tobuf */
                        continue;
 
                /* avoid overflowing tobuf */
-               if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0)
+               if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
                        break;
 
                        break;
 
-# ifdef DEBUG
                if (tTd(10, 1))
                {
                        printf("\nsend to ");
                        printaddr(to, FALSE);
                }
                if (tTd(10, 1))
                {
                        printf("\nsend to ");
                        printaddr(to, FALSE);
                }
-# endif DEBUG
 
                /* compute effective uid/gid when sending */
                if (to->q_mailer == ProgMailer)
 
                /* compute effective uid/gid when sending */
                if (to->q_mailer == ProgMailer)
@@ -215,8 +262,8 @@ deliver(e, firstto)
 
                if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
                {
 
                if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
                {
-                       usrerr("Message is too large; %ld bytes max", m->m_maxsize);
                        NoReturn = TRUE;
                        NoReturn = TRUE;
+                       usrerr("Message is too large; %ld bytes max", m->m_maxsize);
                        giveresponse(EX_UNAVAILABLE, m, e);
                        continue;
                }
                        giveresponse(EX_UNAVAILABLE, m, e);
                        continue;
                }
@@ -275,6 +322,8 @@ deliver(e, firstto)
                        {
                                rcode = mailfile(user, getctladdr(to));
                                giveresponse(rcode, m, e);
                        {
                                rcode = mailfile(user, getctladdr(to));
                                giveresponse(rcode, m, e);
+                               if (rcode == EX_OK)
+                                       to->q_flags |= QSENT;
                                continue;
                        }
                }
                                continue;
                        }
                }
@@ -341,54 +390,73 @@ deliver(e, firstto)
        **      If we are running SMTP, we just need to clean up.
        */
 
        **      If we are running SMTP, we just need to clean up.
        */
 
-       message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name);
-
        if (ctladdr == NULL)
                ctladdr = &e->e_from;
        if (ctladdr == NULL)
                ctladdr = &e->e_from;
-# ifdef SMTP
+#ifdef NAMED_BIND
+       _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);           /* XXX */
+#endif
+#ifdef SMTP
        if (clever)
        {
        if (clever)
        {
-               /* send the initial SMTP protocol */
-               rcode = smtpinit(m, pv);
-
-               if (rcode == EX_OK)
+               rcode = EX_OK;
+#ifdef NAMED_BIND
+               if (host[0] && host[0] != '[')
                {
                {
-                       /* send the recipient list */
-                       tobuf[0] = '\0';
-                       for (to = tochain; to != NULL; to = to->q_tchain)
-                       {
-                               int i;
-
-                               e->e_to = to->q_paddr;
-                               i = smtprcpt(to, m);
-                               if (i != EX_OK)
-                               {
-                                       markfailure(e, to, i);
-                                       giveresponse(i, m, e);
+                       expand("\001w", buf, &buf[sizeof(buf) - 1], e);
+                       Nmx = getmxrr(host, MxHosts, buf, &rcode);
+               }
+               else
+#endif
+               {
+                       Nmx = 1;
+                       MxHosts[0] = host;
+               }
+               if (Nmx >= 0)
+               {
+                       message(Arpa_Info, "Connecting to %s (%s)...",
+                           MxHosts[0], m->m_name);
+                       if ((rcode = smtpinit(m, pv)) == EX_OK) {
+                               register char *t = tobuf;
+                               register int i;
+
+                               /* send the recipient list */
+                               tobuf[0] = '\0';
+                               for (to = tochain; to; to = to->q_tchain) {
+                                       e->e_to = to->q_paddr;
+                                       if ((i = smtprcpt(to, m)) != EX_OK) {
+                                               markfailure(e, to, i);
+                                               giveresponse(i, m, e);
+                                       }
+                                       else {
+                                               *t++ = ',';
+                                               for (p = to->q_paddr; *p; *t++ = *p++);
+                                       }
                                }
                                }
-                               else
-                               {
-                                       strcat(tobuf, ",");
-                                       strcat(tobuf, to->q_paddr);
+
+                               /* now send the data */
+                               if (tobuf[0] == '\0')
+                                       e->e_to = NULL;
+                               else {
+                                       e->e_to = tobuf + 1;
+                                       rcode = smtpdata(m, e);
                                }
                                }
-                       }
 
 
-                       /* now send the data */
-                       if (tobuf[0] == '\0')
-                               e->e_to = NULL;
-                       else
-                       {
-                               e->e_to = tobuf + 1;
-                               rcode = smtpdata(m, e);
+                               /* now close the connection */
+                               smtpquit(m);
                        }
                        }
-
-                       /* now close the connection */
-                       smtpquit(pv[0], m);
                }
        }
        else
                }
        }
        else
-# endif SMTP
+#endif /* SMTP */
+       {
+               static int sendoff();
+
+               message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name);
                rcode = sendoff(e, m, pv, ctladdr);
                rcode = sendoff(e, m, pv, ctladdr);
+       }
+#ifdef NAMED_BIND
+       _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
+#endif
 
        /*
        **  Do final status disposal.
 
        /*
        **  Do final status disposal.
@@ -399,11 +467,11 @@ deliver(e, firstto)
 
        if (tobuf[0] != '\0')
                giveresponse(rcode, m, e);
 
        if (tobuf[0] != '\0')
                giveresponse(rcode, m, e);
-       if (rcode != EX_OK)
-       {
-               for (to = tochain; to != NULL; to = to->q_tchain)
+       for (to = tochain; to != NULL; to = to->q_tchain)
+               if (rcode != EX_OK)
                        markfailure(e, to, rcode);
                        markfailure(e, to, rcode);
-       }
+               else
+                       to->q_flags |= QSENT;
 
        errno = 0;
        define('g', (char *) NULL, e);
 
        errno = 0;
        define('g', (char *) NULL, e);
@@ -433,7 +501,7 @@ markfailure(e, q, rcode)
 {
        if (rcode == EX_OK)
                return;
 {
        if (rcode == EX_OK)
                return;
-       else if (rcode != EX_TEMPFAIL)
+       else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR)
                q->q_flags |= QBADADDR;
        else if (curtime() > e->e_ctime + TimeOut)
        {
                q->q_flags |= QBADADDR;
        else if (curtime() > e->e_ctime + TimeOut)
        {
@@ -488,12 +556,13 @@ markfailure(e, q, rcode)
 {\
        register int i;\
 \
 {\
        register int i;\
 \
-       for (i = NFORKTRIES; i-- > 0; )\
+       for (i = NFORKTRIES; --i >= 0; )\
        {\
                pid = fORKfN();\
                if (pid >= 0)\
                        break;\
        {\
                pid = fORKfN();\
                if (pid >= 0)\
                        break;\
-               sleep(NFORKTRIES - i);\
+               if (i > 0)\
+                       sleep((unsigned) NFORKTRIES - i);\
        }\
 }
 \f/*
        }\
 }
 \f/*
@@ -534,7 +603,7 @@ dofork()
 **     Side Effects:
 **             none.
 */
 **     Side Effects:
 **             none.
 */
-
+static
 sendoff(e, m, pvp, ctladdr)
        register ENVELOPE *e;
        MAILER *m;
 sendoff(e, m, pvp, ctladdr)
        register ENVELOPE *e;
        MAILER *m;
@@ -563,6 +632,8 @@ sendoff(e, m, pvp, ctladdr)
        putline("\n", mfile, m);
        (*e->e_putbody)(mfile, m, e);
        (void) fclose(mfile);
        putline("\n", mfile, m);
        (*e->e_putbody)(mfile, m, e);
        (void) fclose(mfile);
+       if (rfile != NULL)
+               (void) fclose(rfile);
 
        i = endmailer(pid, pvp[0]);
 
 
        i = endmailer(pid, pvp[0]);
 
@@ -615,9 +686,9 @@ endmailer(pid, name)
        /* see if it died a horrid death */
        if ((st & 0377) != 0)
        {
        /* see if it died a horrid death */
        if ((st & 0377) != 0)
        {
-               syserr("endmailer %s: stat %o", name, st);
-               ExitStat = EX_UNAVAILABLE;
-               return (EX_UNAVAILABLE);
+               syserr("mailer %s died with signal %o", name, st);
+               ExitStat = EX_TEMPFAIL;
+               return (EX_TEMPFAIL);
        }
 
        /* normal death -- return status */
        }
 
        /* normal death -- return status */
@@ -655,19 +726,19 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        int pid;
        int mpvect[2];
        int rpvect[2];
        int pid;
        int mpvect[2];
        int rpvect[2];
-       FILE *mfile;
-       FILE *rfile;
+       FILE *mfile = NULL;
+       FILE *rfile = NULL;
        extern FILE *fdopen();
 
        extern FILE *fdopen();
 
-# ifdef DEBUG
        if (tTd(11, 1))
        {
                printf("openmailer:");
                printav(pvp);
        }
        if (tTd(11, 1))
        {
                printf("openmailer:");
                printav(pvp);
        }
-# endif DEBUG
        errno = 0;
 
        errno = 0;
 
+       CurHostName = m->m_mailer;
+
        /*
        **  Deal with the special case of mail handled through an IPC
        **  connection.
        /*
        **  Deal with the special case of mail handled through an IPC
        **  connection.
@@ -677,7 +748,6 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        **  We also handle a debug version that just talks to stdin/out.
        */
 
        **  We also handle a debug version that just talks to stdin/out.
        */
 
-#ifdef DEBUG
        /* check for Local Person Communication -- not for mortals!!! */
        if (strcmp(m->m_mailer, "[LPC]") == 0)
        {
        /* check for Local Person Communication -- not for mortals!!! */
        if (strcmp(m->m_mailer, "[LPC]") == 0)
        {
@@ -685,28 +755,61 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
                *prfile = stdin;
                return (0);
        }
                *prfile = stdin;
                return (0);
        }
-#endif DEBUG
 
        if (strcmp(m->m_mailer, "[IPC]") == 0)
        {
 
        if (strcmp(m->m_mailer, "[IPC]") == 0)
        {
+#ifdef HOSTINFO
+               register STAB *st;
+               extern STAB *stab();
+#endif HOSTINFO
 #ifdef DAEMON
 #ifdef DAEMON
-               register int i;
+               register int i, j;
                register u_short port;
 
                register u_short port;
 
+               CurHostName = pvp[1];
                if (!clever)
                        syserr("non-clever IPC");
                if (pvp[2] != NULL)
                        port = atoi(pvp[2]);
                else
                        port = 0;
                if (!clever)
                        syserr("non-clever IPC");
                if (pvp[2] != NULL)
                        port = atoi(pvp[2]);
                else
                        port = 0;
-               i = makeconnection(pvp[1], port, pmfile, prfile);
-               if (i != EX_OK)
+               for (j = 0; j < Nmx; j++)
                {
                {
-                       ExitStat = i;
-                       return (-1);
+                       CurHostName = MxHosts[j];
+#ifdef HOSTINFO
+               /* see if we have already determined that this host is fried */
+                       st = stab(MxHosts[j], ST_HOST, ST_FIND);
+                       if (st == NULL || st->s_host.ho_exitstat == EX_OK) {
+                               if (j > 1)
+                                       message(Arpa_Info,
+                                           "Connecting to %s (%s)...",
+                                           MxHosts[j], m->m_name);
+                               i = makeconnection(MxHosts[j], port, pmfile, prfile);
+                       }
+                       else
+                       {
+                               i = st->s_host.ho_exitstat;
+                               errno = st->s_host.ho_errno;
+                       }
+#else HOSTINFO
+                       i = makeconnection(MxHosts[j], port, pmfile, prfile);
+#endif HOSTINFO
+                       if (i != EX_OK)
+                       {
+#ifdef HOSTINFO
+                               /* enter status of this host */
+                               if (st == NULL)
+                                       st = stab(MxHosts[j], ST_HOST, ST_ENTER);
+                               st->s_host.ho_exitstat = i;
+                               st->s_host.ho_errno = errno;
+#endif HOSTINFO
+                               ExitStat = i;
+                               continue;
+                       }
+                       else
+                               return (0);
                }
                }
-               else
-                       return (0);
+               return (-1);
 #else DAEMON
                syserr("openmailer: no IPC");
                return (-1);
 #else DAEMON
                syserr("openmailer: no IPC");
                return (-1);
@@ -734,11 +837,17 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        /*
        **  Actually fork the mailer process.
        **      DOFORK is clever about retrying.
        /*
        **  Actually fork the mailer process.
        **      DOFORK is clever about retrying.
+       **
+       **      Dispose of SIGCHLD signal catchers that may be laying
+       **      around so that endmail will get it.
        */
 
        if (CurEnv->e_xfp != NULL)
                (void) fflush(CurEnv->e_xfp);           /* for debugging */
        (void) fflush(stdout);
        */
 
        if (CurEnv->e_xfp != NULL)
                (void) fflush(CurEnv->e_xfp);           /* for debugging */
        (void) fflush(stdout);
+# ifdef SIGCHLD
+       (void) signal(SIGCHLD, SIG_DFL);
+# endif SIGCHLD
        DOFORK(XFORK);
        /* pid is set by DOFORK */
        if (pid < 0)
        DOFORK(XFORK);
        /* pid is set by DOFORK */
        if (pid < 0)
@@ -758,6 +867,9 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        }
        else if (pid == 0)
        {
        }
        else if (pid == 0)
        {
+               int i;
+               extern int DtableSize;
+
                /* child -- set up input & exec mailer */
                /* make diagnostic output be standard output */
                (void) signal(SIGINT, SIG_IGN);
                /* child -- set up input & exec mailer */
                /* make diagnostic output be standard output */
                (void) signal(SIGINT, SIG_IGN);
@@ -792,45 +904,37 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
                (void) close(mpvect[0]);
                if (!bitnset(M_RESTR, m->m_flags))
                {
                (void) close(mpvect[0]);
                if (!bitnset(M_RESTR, m->m_flags))
                {
-                       if (ctladdr->q_uid == 0)
+                       if (ctladdr == NULL || ctladdr->q_uid == 0)
                        {
                                (void) setgid(DefGid);
                        {
                                (void) setgid(DefGid);
+                               (void) initgroups(DefUser, DefGid);
                                (void) setuid(DefUid);
                        }
                        else
                        {
                                (void) setgid(ctladdr->q_gid);
                                (void) setuid(DefUid);
                        }
                        else
                        {
                                (void) setgid(ctladdr->q_gid);
+                               (void) initgroups(ctladdr->q_ruser?
+                                       ctladdr->q_ruser: ctladdr->q_user,
+                                       ctladdr->q_gid);
                                (void) setuid(ctladdr->q_uid);
                        }
                }
 
                                (void) setuid(ctladdr->q_uid);
                        }
                }
 
-               /*
-               **  We have to be careful with vfork - we can't mung up the
-               **  memory but we don't want the mailer to inherit any extra
-               **  open files.  Chances are the mailer won't
-               **  care about an extra file, but then again you never know.
-               **  Actually, we would like to close(fileno(pwf)), but it's
-               **  declared static so we can't.  But if we fclose(pwf), which
-               **  is what endpwent does, it closes it in the parent too and
-               **  the next getpwnam will be slower.  If you have a weird
-               **  mailer that chokes on the extra file you should do the
-               **  endpwent().                 -MRH
-               **
-               **  Similar comments apply to log.  However, openlog is
-               **  clever enough to set the FIOCLEX mode on the file,
-               **  so it will be closed automatically on the exec.
-               */
-
-               closeall();
+               /* arrange for all the files to be closed */
+               for (i = 3; i < DtableSize; i++) {
+                       register int j;
+                       if ((j = fcntl(i, F_GETFD, 0)) != -1)
+                               (void)fcntl(i, F_SETFD, j|1);
+               }
 
                /* try to execute the mailer */
 
                /* try to execute the mailer */
-               execv(m->m_mailer, pvp);
-
-               /* syserr fails because log is closed */
-               /* syserr("Cannot exec %s", m->m_mailer); */
-               printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno);
-               (void) fflush(stdout);
-               _exit(EX_UNAVAILABLE);
+               execve(m->m_mailer, pvp, UserEnviron);
+               syserr("Cannot exec %s", m->m_mailer);
+               if (m == LocalMailer || errno == EIO || errno == EAGAIN ||
+                   errno == ENOMEM || errno == EPROCLIM)
+                       _exit(EX_TEMPFAIL);
+               else
+                       _exit(EX_UNAVAILABLE);
        }
 
        /*
        }
 
        /*
@@ -843,7 +947,8 @@ openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        {
                (void) close(rpvect[1]);
                rfile = fdopen(rpvect[0], "r");
        {
                (void) close(rpvect[1]);
                rfile = fdopen(rpvect[0], "r");
-       }
+       } else
+               rfile = NULL;
 
        *pmfile = mfile;
        *prfile = rfile;
 
        *pmfile = mfile;
        *prfile = rfile;
@@ -876,6 +981,9 @@ giveresponse(stat, m, e)
        extern char *SysExMsg[];
        register int i;
        extern int N_SysEx;
        extern char *SysExMsg[];
        register int i;
        extern int N_SysEx;
+#ifdef NAMED_BIND
+       extern int h_errno;
+#endif
        char buf[MAXLINE];
 
 #ifdef lint
        char buf[MAXLINE];
 
 #ifdef lint
@@ -899,17 +1007,44 @@ giveresponse(stat, m, e)
        else if (stat == EX_TEMPFAIL)
        {
                (void) strcpy(buf, SysExMsg[i]);
        else if (stat == EX_TEMPFAIL)
        {
                (void) strcpy(buf, SysExMsg[i]);
-               if (errno != 0)
+#ifdef NAMED_BIND
+               if (h_errno == TRY_AGAIN)
                {
                        extern char *errstring();
 
                {
                        extern char *errstring();
 
+                       statmsg = errstring(h_errno+MAX_ERRNO);
+               }
+               else
+#endif
+               {
+                       if (errno != 0)
+                       {
+                               extern char *errstring();
+
+                               statmsg = errstring(errno);
+                       }
+                       else
+                       {
+#ifdef SMTP
+                               extern char SmtpError[];
+
+                               statmsg = SmtpError;
+#else SMTP
+                               statmsg = NULL;
+#endif SMTP
+                       }
+               }
+               if (statmsg != NULL && statmsg[0] != '\0')
+               {
                        (void) strcat(buf, ": ");
                        (void) strcat(buf, ": ");
-                       (void) strcat(buf, errstring(errno));
+                       (void) strcat(buf, statmsg);
                }
                statmsg = buf;
        }
        else
                }
                statmsg = buf;
        }
        else
+       {
                statmsg = SysExMsg[i];
                statmsg = SysExMsg[i];
+       }
 
        /*
        **  Print the message as appropriate
 
        /*
        **  Print the message as appropriate
@@ -942,6 +1077,9 @@ giveresponse(stat, m, e)
                e->e_message = newstr(&statmsg[4]);
        }
        errno = 0;
                e->e_message = newstr(&statmsg[4]);
        }
        errno = 0;
+#ifdef NAMED_BIND
+       h_errno = 0;
+#endif
 }
 \f/*
 **  LOGDELIVERY -- log the delivery in the system log
 }
 \f/*
 **  LOGDELIVERY -- log the delivery in the system log
@@ -969,15 +1107,12 @@ logdelivery(stat)
 \f/*
 **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
 **
 \f/*
 **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
 **
-**     then passes the rest of the message through.  If we have
-**     managed to extract a date already, use that; otherwise,
-**     use the current date/time.
+**     This can be made an arbitrary message separator by changing $l
 **
 **
-**     One of the ugliest hacks seen by human eyes is
-**     contained herein: UUCP wants those stupid
-**     "emote from <host>" lines.  Why oh why does a
-**     well-meaning programmer such as myself have to
-**     deal with this kind of antique garbage????
+**     One of the ugliest hacks seen by human eyes is contained herein:
+**     UUCP wants those stupid "remote from <host>" lines.  Why oh why
+**     does a well-meaning programmer such as myself have to deal with
+**     this kind of antique garbage????
 **
 **     Parameters:
 **             fp -- the file to output to.
 **
 **     Parameters:
 **             fp -- the file to output to.
@@ -994,9 +1129,8 @@ putfromline(fp, m)
        register FILE *fp;
        register MAILER *m;
 {
        register FILE *fp;
        register MAILER *m;
 {
-       char *template = "$l\n";
+       char *template = "\001l\n";
        char buf[MAXLINE];
        char buf[MAXLINE];
-       extern char SentDate[];
 
        if (bitnset(M_NHDR, m->m_flags))
                return;
 
        if (bitnset(M_NHDR, m->m_flags))
                return;
@@ -1007,14 +1141,14 @@ putfromline(fp, m)
                char *bang;
                char xbuf[MAXLINE];
 
                char *bang;
                char xbuf[MAXLINE];
 
-               expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
+               expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
                bang = index(buf, '!');
                if (bang == NULL)
                        syserr("No ! in UUCP! (%s)", buf);
                else
                {
                        *bang++ = '\0';
                bang = index(buf, '!');
                if (bang == NULL)
                        syserr("No ! in UUCP! (%s)", buf);
                else
                {
                        *bang++ = '\0';
-                       (void) sprintf(xbuf, "From %s  $d remote from %s\n", bang, buf);
+                       (void) sprintf(xbuf, "From %s  \001d remote from %s\n", bang, buf);
                        template = xbuf;
                }
        }
                        template = xbuf;
                }
        }
@@ -1054,7 +1188,8 @@ putbody(fp, m, e)
                {
                        e->e_dfp = fopen(e->e_df, "r");
                        if (e->e_dfp == NULL)
                {
                        e->e_dfp = fopen(e->e_df, "r");
                        if (e->e_dfp == NULL)
-                               syserr("Cannot open %s", e->e_df);
+                               syserr("putbody: Cannot open %s for %s from %s",
+                               e->e_df, e->e_to, e->e_from);
                }
                else
                        putline("<<< No Message Collected >>>", fp, m);
                }
                else
                        putline("<<< No Message Collected >>>", fp, m);
@@ -1063,7 +1198,12 @@ putbody(fp, m, e)
        {
                rewind(e->e_dfp);
                while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
        {
                rewind(e->e_dfp);
                while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
+               {
+                       if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) &&
+                           strncmp(buf, "From ", 5) == 0)
+                               (void) putc('>', fp);
                        putline(buf, fp, m);
                        putline(buf, fp, m);
+               }
 
                if (ferror(e->e_dfp))
                {
 
                if (ferror(e->e_dfp))
                {
@@ -1112,6 +1252,7 @@ mailfile(filename, ctladdr)
 {
        register FILE *f;
        register int pid;
 {
        register FILE *f;
        register int pid;
+       ENVELOPE *e = CurEnv;
 
        /*
        **  Fork so we can change permissions here.
 
        /*
        **  Fork so we can change permissions here.
@@ -1131,7 +1272,7 @@ mailfile(filename, ctladdr)
                (void) signal(SIGINT, SIG_DFL);
                (void) signal(SIGHUP, SIG_DFL);
                (void) signal(SIGTERM, SIG_DFL);
                (void) signal(SIGINT, SIG_DFL);
                (void) signal(SIGHUP, SIG_DFL);
                (void) signal(SIGTERM, SIG_DFL);
-               umask(OldUmask);
+               (void) umask(OldUmask);
                if (stat(filename, &stb) < 0)
                {
                        errno = 0;
                if (stat(filename, &stb) < 0)
                {
                        errno = 0;
@@ -1140,13 +1281,28 @@ mailfile(filename, ctladdr)
                if (bitset(0111, stb.st_mode))
                        exit(EX_CANTCREAT);
                if (ctladdr == NULL)
                if (bitset(0111, stb.st_mode))
                        exit(EX_CANTCREAT);
                if (ctladdr == NULL)
-                       ctladdr = &CurEnv->e_from;
+                       ctladdr = &e->e_from;
+               /* we have to open the dfile BEFORE setuid */
+               if (e->e_dfp == NULL &&  e->e_df != NULL)
+               {
+                       e->e_dfp = fopen(e->e_df, "r");
+                       if (e->e_dfp == NULL) {
+                               syserr("mailfile: Cannot open %s for %s from %s",
+                               e->e_df, e->e_to, e->e_from);
+                       }
+               }
+
                if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0)
                {
                if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0)
                {
-                       if (ctladdr->q_uid == 0)
+                       if (ctladdr->q_uid == 0) {
                                (void) setgid(DefGid);
                                (void) setgid(DefGid);
-                       else
+                               (void) initgroups(DefUser, DefGid);
+                       } else {
                                (void) setgid(ctladdr->q_gid);
                                (void) setgid(ctladdr->q_gid);
+                               (void) initgroups(ctladdr->q_ruser?
+                                       ctladdr->q_ruser: ctladdr->q_user,
+                                       ctladdr->q_gid);
+                       }
                }
                if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0)
                {
                }
                if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0)
                {
@@ -1182,6 +1338,7 @@ mailfile(filename, ctladdr)
                        return (EX_UNAVAILABLE);
                else
                        return ((st >> 8) & 0377);
                        return (EX_UNAVAILABLE);
                else
                        return ((st >> 8) & 0377);
+               /*NOTREACHED*/
        }
 }
 \f/*
        }
 }
 \f/*
@@ -1209,25 +1366,25 @@ sendall(e, mode)
        register ADDRESS *q;
        bool oldverbose;
        int pid;
        register ADDRESS *q;
        bool oldverbose;
        int pid;
+       int nsent;
+       FILE *lockfp = NULL, *queueup();
 
        /* determine actual delivery mode */
        if (mode == SM_DEFAULT)
        {
 
        /* determine actual delivery mode */
        if (mode == SM_DEFAULT)
        {
-               extern int QueueLA;
+               extern bool shouldqueue();
 
 
-               if (getla() > QueueLA)
+               if (shouldqueue(e->e_msgpriority))
                        mode = SM_QUEUE;
                else
                        mode = SendMode;
        }
 
                        mode = SM_QUEUE;
                else
                        mode = SendMode;
        }
 
-#ifdef DEBUG
        if (tTd(13, 1))
        {
                printf("\nSENDALL: mode %c, sendqueue:\n", mode);
                printaddr(e->e_sendqueue, TRUE);
        }
        if (tTd(13, 1))
        {
                printf("\nSENDALL: mode %c, sendqueue:\n", mode);
                printaddr(e->e_sendqueue, TRUE);
        }
-#endif DEBUG
 
        /*
        **  Do any preprocessing necessary for the mode we are running.
 
        /*
        **  Do any preprocessing necessary for the mode we are running.
@@ -1239,7 +1396,9 @@ sendall(e, mode)
 
        if (e->e_hopcount > MAXHOP)
        {
 
        if (e->e_hopcount > MAXHOP)
        {
-               syserr("sendall: too many hops (%d max)", MAXHOP);
+               errno = 0;
+               syserr("sendall: too many hops %d (%d max): from %s, to %s",
+                       e->e_hopcount, MAXHOP, e->e_from, e->e_to);
                return;
        }
 
                return;
        }
 
@@ -1255,7 +1414,7 @@ sendall(e, mode)
        if ((mode == SM_QUEUE || mode == SM_FORK ||
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
        if ((mode == SM_QUEUE || mode == SM_FORK ||
             (mode != SM_VERIFY && SuperSafe)) &&
            !bitset(EF_INQUEUE, e->e_flags))
-               queueup(e, TRUE, mode == SM_QUEUE);
+               lockfp = queueup(e, TRUE, mode == SM_QUEUE);
 #endif QUEUE
 
        oldverbose = Verbose;
 #endif QUEUE
 
        oldverbose = Verbose;
@@ -1282,6 +1441,8 @@ sendall(e, mode)
                {
                        /* be sure we leave the temp files to our child */
                        e->e_id = e->e_df = NULL;
                {
                        /* be sure we leave the temp files to our child */
                        e->e_id = e->e_df = NULL;
+                       if (lockfp != NULL)
+                               (void) fclose(lockfp);
                        return;
                }
 
                        return;
                }
 
@@ -1299,6 +1460,7 @@ sendall(e, mode)
        **  Run through the list and send everything.
        */
 
        **  Run through the list and send everything.
        */
 
+       nsent = 0;
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (mode == SM_VERIFY)
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                if (mode == SM_VERIFY)
@@ -1307,8 +1469,20 @@ sendall(e, mode)
                        if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
                                message(Arpa_Info, "deliverable");
                }
                        if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
                                message(Arpa_Info, "deliverable");
                }
-               else
-                       (void) deliver(e, q);
+               else if (!bitset(QDONTSEND, q->q_flags))
+               {
+                       /*
+                       **  Checkpoint the send list every few addresses
+                       */
+
+                       if (nsent >= CheckpointInterval)
+                       {
+                               queueup(e, TRUE, FALSE);
+                               nsent = 0;
+                       }
+                       if (deliver(e, q) == EX_OK)
+                               nsent++;
+               }
        }
        Verbose = oldverbose;
 
        }
        Verbose = oldverbose;
 
@@ -1316,20 +1490,21 @@ sendall(e, mode)
        **  Now run through and check for errors.
        */
 
        **  Now run through and check for errors.
        */
 
-       if (mode == SM_VERIFY)
+       if (mode == SM_VERIFY) {
+               if (lockfp != NULL)
+                       (void) fclose(lockfp);
                return;
                return;
+       }
 
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                register ADDRESS *qq;
 
 
        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        {
                register ADDRESS *qq;
 
-# ifdef DEBUG
                if (tTd(13, 3))
                {
                        printf("Checking ");
                        printaddr(q, FALSE);
                }
                if (tTd(13, 3))
                {
                        printf("Checking ");
                        printaddr(q, FALSE);
                }
-# endif DEBUG
 
                /* only send errors if the message failed */
                if (!bitset(QBADADDR, q->q_flags))
 
                /* only send errors if the message failed */
                if (!bitset(QBADADDR, q->q_flags))
@@ -1351,17 +1526,16 @@ sendall(e, mode)
                                (void) strcat(obuf, "owner");
                        else
                                (void) strcat(obuf, qq->q_user);
                                (void) strcat(obuf, "owner");
                        else
                                (void) strcat(obuf, qq->q_user);
+                       makelower(obuf);
                        if (aliaslookup(obuf) == NULL)
                                continue;
 
                        if (aliaslookup(obuf) == NULL)
                                continue;
 
-# ifdef DEBUG
                        if (tTd(13, 4))
                                printf("Errors to %s\n", obuf);
                        if (tTd(13, 4))
                                printf("Errors to %s\n", obuf);
-# endif DEBUG
 
                        /* owner list exists -- add it to the error queue */
                        sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue);
 
                        /* owner list exists -- add it to the error queue */
                        sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue);
-                       ErrorMode == EM_MAIL;
+                       ErrorMode = EM_MAIL;
                        break;
                }
 
                        break;
                }
 
@@ -1370,6 +1544,10 @@ sendall(e, mode)
                        sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue);
        }
 
                        sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue);
        }
 
+       /* this removes the lock on the file */
+       if (lockfp != NULL)
+               (void) fclose(lockfp);
+
        if (mode == SM_FORK)
                finis();
 }
        if (mode == SM_FORK)
                finis();
 }