more cleanup for DSN drafts
[unix-history] / usr / src / usr.sbin / sendmail / src / deliver.c
index 3951851..6c2deeb 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  8.84.1.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)deliver.c  8.137 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -47,8 +47,8 @@ sendall(e, mode)
        register ADDRESS *q;
        char *owner;
        int otherowners;
        register ADDRESS *q;
        char *owner;
        int otherowners;
-       bool announcequeueup;
        bool oldverbose = Verbose;
        bool oldverbose = Verbose;
+       bool somedeliveries = FALSE;
        int pid;
        extern void sendenvelope();
        int pid;
        int pid;
        extern void sendenvelope();
        int pid;
@@ -78,16 +78,17 @@ sendall(e, mode)
                if (mode != SM_VERIFY &&
                    shouldqueue(e->e_msgpriority, e->e_ctime))
                        mode = SM_QUEUE;
                if (mode != SM_VERIFY &&
                    shouldqueue(e->e_msgpriority, e->e_ctime))
                        mode = SM_QUEUE;
-               announcequeueup = mode == SM_QUEUE;
        }
        }
-       else
-               announcequeueup = FALSE;
 
        if (tTd(13, 1))
        {
 
        if (tTd(13, 1))
        {
+               extern void printenvflags();
+
                printf("\n===== SENDALL: mode %c, id %s, e_from ",
                        mode, e->e_id);
                printaddr(&e->e_from, FALSE);
                printf("\n===== SENDALL: mode %c, id %s, e_from ",
                        mode, e->e_id);
                printaddr(&e->e_from, FALSE);
+               printf("\te_flags = ");
+               printenvflags(e);
                printf("sendqueue:\n");
                printaddr(e->e_sendqueue, TRUE);
        }
                printf("sendqueue:\n");
                printaddr(e->e_sendqueue, TRUE);
        }
@@ -103,7 +104,7 @@ sendall(e, mode)
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
        if (e->e_hopcount > MaxHopCount)
        {
                errno = 0;
-               queueup(e, TRUE, announcequeueup);
+               queueup(e, TRUE, mode == SM_QUEUE);
                e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
                syserr("554 too many hops %d (%d max): from %s via %s, to %s",
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
                e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
                syserr("554 too many hops %d (%d max): from %s via %s, to %s",
                        e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
@@ -323,6 +324,34 @@ sendall(e, mode)
                        {
                                otherowners++;
                        }
                        {
                                otherowners++;
                        }
+
+                       /*
+                       **  If this mailer is expensive, and if we don't
+                       **  want to make connections now, just mark these
+                       **  addresses and return.  This is useful if we
+                       **  want to batch connections to reduce load.  This
+                       **  will cause the messages to be queued up, and a
+                       **  daemon will come along to send the messages later.
+                       */
+
+                       if (bitset(QBADADDR|QQUEUEUP, q->q_flags))
+                               continue;
+                       if (NoConnect && !Verbose &&
+                           bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
+                       {
+                               q->q_flags |= QQUEUEUP;
+                               e->e_to = q->q_paddr;
+                               message("queued");
+                               if (LogLevel > 8)
+                                       logdelivery(q->q_mailer, NULL,
+                                                   "queued", NULL,
+                                                   (time_t) 0, e);
+                               e->e_to = NULL;
+                       }
+                       else
+                       {
+                               somedeliveries = TRUE;
+                       }
                }
 
                if (owner != NULL && otherowners > 0)
                }
 
                if (owner != NULL && otherowners > 0)
@@ -358,7 +387,6 @@ sendall(e, mode)
                        ee->e_from.q_flags |= QDONTSEND;
                        ee->e_dfp = NULL;
                        ee->e_xfp = NULL;
                        ee->e_from.q_flags |= QDONTSEND;
                        ee->e_dfp = NULL;
                        ee->e_xfp = NULL;
-                       ee->e_df = NULL;
                        ee->e_errormode = EM_MAIL;
                        
                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
                        ee->e_errormode = EM_MAIL;
                        
                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
@@ -374,15 +402,17 @@ sendall(e, mode)
                                        q->q_flags &= ~QQUEUEUP;
                                }
 
                                        q->q_flags &= ~QQUEUEUP;
                                }
 
-                       if (e->e_df != NULL && mode != SM_VERIFY)
+                       if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
                        {
                        {
+                               char df1buf[20], df2buf[20];
+
                                ee->e_dfp = NULL;
                                ee->e_dfp = NULL;
-                               ee->e_df = queuename(ee, 'd');
-                               ee->e_df = newstr(ee->e_df);
-                               if (link(e->e_df, ee->e_df) < 0)
+                               strcpy(df1buf, queuename(e, 'd'));
+                               strcpy(df2buf, queuename(ee, 'd'));
+                               if (link(df1buf, df2buf) < 0)
                                {
                                        syserr("sendall: link(%s, %s)",
                                {
                                        syserr("sendall: link(%s, %s)",
-                                               e->e_df, ee->e_df);
+                                               df1buf, df2buf);
                                }
                        }
 #ifdef LOG
                                }
                        }
 #ifdef LOG
@@ -413,6 +443,10 @@ sendall(e, mode)
                e->e_flags |= EF_NORECEIPT;
        }
 
                e->e_flags |= EF_NORECEIPT;
        }
 
+       /* if nothing to be delivered, just queue up everything */
+       if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY)
+               mode = SM_QUEUE;
+
        bool oldverbose = Verbose;
 
        if (splitenv != NULL)
        bool oldverbose = Verbose;
 
        if (splitenv != NULL)
@@ -636,8 +670,8 @@ deliver(e, firstto)
        int rpvect[2];
        char *pv[MAXPV+1];
        char tobuf[TOBUFSIZE];          /* text line of to people */
        int rpvect[2];
        char *pv[MAXPV+1];
        char tobuf[TOBUFSIZE];          /* text line of to people */
-       char buf[MAXNAME];
-       char rpathbuf[MAXNAME];         /* translated return path */
+       char buf[MAXNAME + 1];
+       char rpathbuf[MAXNAME + 1];     /* translated return path */
        extern int checkcompat();
 
        errno = 0;
        extern int checkcompat();
 
        errno = 0;
@@ -666,33 +700,6 @@ deliver(e, firstto)
        if (tTd(10, 100))
                printopenfds(FALSE);
 
        if (tTd(10, 100))
                printopenfds(FALSE);
 
-       /*
-       **  If this mailer is expensive, and if we don't want to make
-       **  connections now, just mark these addresses and return.
-       **      This is useful if we want to batch connections to
-       **      reduce load.  This will cause the messages to be
-       **      queued up, and a daemon will come along to send the
-       **      messages later.
-       **              This should be on a per-mailer basis.
-       */
-
-       if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)
-       {
-               for (; to != NULL; to = to->q_next)
-               {
-                       if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||
-                           to->q_mailer != m)
-                               continue;
-                       to->q_flags |= QQUEUEUP;
-                       e->e_to = to->q_paddr;
-                       message("queued");
-                       if (LogLevel > 8)
-                               logdelivery(m, NULL, "queued", NULL, xstart, e);
-               }
-               e->e_to = NULL;
-               return (0);
-       }
-
        /*
        **  Do initial argv setup.
        **      Insert the mailer name.  Notice that $x expansion is
        /*
        **  Do initial argv setup.
        **      Insert the mailer name.  Notice that $x expansion is
@@ -752,7 +759,7 @@ deliver(e, firstto)
                        break;
 
                /* this entry is safe -- go ahead and process it */
                        break;
 
                /* this entry is safe -- go ahead and process it */
-               expand(*mvp, buf, &buf[sizeof buf - 1], e);
+               expand(*mvp, buf, sizeof buf, e);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV - 3])
                {
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV - 3])
                {
@@ -839,7 +846,7 @@ 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)
                {
-                       e->e_flags |= EF_NORETURN;
+                       e->e_flags |= EF_NO_BODY_RETN;
                        usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
                        giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e);
                        continue;
                        usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
                        giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e);
                        continue;
@@ -938,7 +945,7 @@ deliver(e, firstto)
 
                if (!clever)
                {
 
                if (!clever)
                {
-                       expand(*mvp, buf, &buf[sizeof buf - 1], e);
+                       expand(*mvp, buf, sizeof buf, e);
                        *pvp++ = newstr(buf);
                        if (pvp >= &pv[MAXPV - 2])
                        {
                        *pvp++ = newstr(buf);
                        if (pvp >= &pv[MAXPV - 2])
                        {
@@ -964,7 +971,7 @@ deliver(e, firstto)
 
        while (!clever && *++mvp != NULL)
        {
 
        while (!clever && *++mvp != NULL)
        {
-               expand(*mvp, buf, &buf[sizeof buf - 1], e);
+               expand(*mvp, buf, sizeof buf, e);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV])
                        syserr("554 deliver: pv overflow after $u for %s", pv[0]);
                *pvp++ = newstr(buf);
                if (pvp >= &pv[MAXPV])
                        syserr("554 deliver: pv overflow after $u for %s", pv[0]);
@@ -1080,7 +1087,7 @@ tryhost:
                while (*curhost != '\0')
                {
                        register char *p;
                while (*curhost != '\0')
                {
                        register char *p;
-                       static char hostbuf[MAXNAME];
+                       static char hostbuf[MAXNAME + 1];
 
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
 
                        /* pull the next host from the signature */
                        p = strchr(curhost, ':');
@@ -1248,10 +1255,7 @@ tryhost:
                        extern int DtableSize;
 
                        if (e->e_lockfp != NULL)
                        extern int DtableSize;
 
                        if (e->e_lockfp != NULL)
-                       {
-                               fclose(e->e_lockfp);
-                               e->e_lockfp = NULL;
-                       }
+                               (void) close(fileno(e->e_lockfp));
 
                        /* child -- set up input & exec mailer */
                        (void) setsignal(SIGINT, SIG_IGN);
 
                        /* child -- set up input & exec mailer */
                        (void) setsignal(SIGINT, SIG_IGN);
@@ -1293,14 +1297,14 @@ tryhost:
                        if (m->m_execdir != NULL)
                        {
                                char *p, *q;
                        if (m->m_execdir != NULL)
                        {
                                char *p, *q;
-                               char buf[MAXLINE];
+                               char buf[MAXLINE + 1];
 
                                for (p = m->m_execdir; p != NULL; p = q)
                                {
                                        q = strchr(p, ':');
                                        if (q != NULL)
                                                *q = '\0';
 
                                for (p = m->m_execdir; p != NULL; p = q)
                                {
                                        q = strchr(p, ':');
                                        if (q != NULL)
                                                *q = '\0';
-                                       expand(p, buf, &buf[sizeof buf] - 1, e);
+                                       expand(p, buf, sizeof buf, e);
                                        if (q != NULL)
                                                *q++ = ':';
                                        if (tTd(11, 20))
                                        if (q != NULL)
                                                *q++ = ':';
                                        if (tTd(11, 20))
@@ -1475,7 +1479,7 @@ tryhost:
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
                                rcode, mci->mci_state, firstsig);
                        rcode = EX_SOFTWARE;
                }
-               else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0')
+               else if (curhost != NULL && *curhost != '\0')
                {
                        /* try next MX site */
                        goto tryhost;
                {
                        /* try next MX site */
                        goto tryhost;
@@ -1598,6 +1602,7 @@ tryhost:
                                        to->q_paddr);
                        }
                        else if (bitset(QPINGONSUCCESS, to->q_flags) &&
                                        to->q_paddr);
                        }
                        else if (bitset(QPINGONSUCCESS, to->q_flags) &&
+                                bitset(QPRIMARY, to->q_flags) &&
                                 !bitset(MCIF_DSN, mci->mci_flags))
                        {
                                to->q_flags |= QRELAYED;
                                 !bitset(MCIF_DSN, mci->mci_flags))
                        {
                                to->q_flags |= QRELAYED;
@@ -2195,7 +2200,7 @@ putfromline(mci, e)
                char *bang;
                char xbuf[MAXLINE];
 
                char *bang;
                char xbuf[MAXLINE];
 
-               expand("\201g", buf, &buf[sizeof buf - 1], e);
+               expand("\201g", buf, sizeof buf, e);
                bang = strchr(buf, '!');
                if (bang == NULL)
                {
                bang = strchr(buf, '!');
                if (bang == NULL)
                {
@@ -2210,8 +2215,8 @@ putfromline(mci, e)
                }
        }
 # endif /* UGLYUUCP */
                }
        }
 # endif /* UGLYUUCP */
-       expand(template, buf, &buf[sizeof buf - 1], e);
-       putline(buf, mci);
+       expand(template, buf, sizeof buf, e);
+       putxline(buf, mci, FALSE);
 }
 \f/*
 **  PUTBODY -- put the body of a message.
 }
 \f/*
 **  PUTBODY -- put the body of a message.
@@ -2245,12 +2250,14 @@ putbody(mci, e, separator)
        **  Output the body of the message
        */
 
        **  Output the body of the message
        */
 
-       if (e->e_dfp == NULL && e->e_df != NULL)
+       if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
        {
        {
-               e->e_dfp = fopen(e->e_df, "r");
+               char *df = queuename(e, 'd');
+
+               e->e_dfp = fopen(df, "r");
                if (e->e_dfp == NULL)
                        syserr("putbody: Cannot open %s for %s from %s",
                if (e->e_dfp == NULL)
                        syserr("putbody: Cannot open %s for %s from %s",
-                       e->e_df, e->e_to, e->e_from.q_paddr);
+                               df, e->e_to, e->e_from.q_paddr);
        }
        if (e->e_dfp == NULL)
        {
        }
        if (e->e_dfp == NULL)
        {
@@ -2278,6 +2285,8 @@ putbody(mci, e, separator)
 
        if (bitset(MCIF_CVT8TO7, mci->mci_flags))
        {
 
        if (bitset(MCIF_CVT8TO7, mci->mci_flags))
        {
+               char *boundaries[MAXMIMENESTING + 1];
+
                /*
                **  Do 8 to 7 bit MIME conversion.
                */
                /*
                **  Do 8 to 7 bit MIME conversion.
                */
@@ -2294,7 +2303,8 @@ putbody(mci, e, separator)
                }
 
                /* now do the hard work */
                }
 
                /* now do the hard work */
-               mime8to7(mci, e->e_header, e, NULL);
+               boundaries[0] = NULL;
+               mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER);
        }
        else
        {
        }
        else
        {
@@ -2463,7 +2473,7 @@ putch:
 
        if (ferror(e->e_dfp))
        {
 
        if (ferror(e->e_dfp))
        {
-               syserr("putbody: %s: read error", e->e_df);
+               syserr("putbody: df%s: read error", e->e_id);
                ExitStat = EX_IOERR;
        }
 
                ExitStat = EX_IOERR;
        }
 
@@ -2541,6 +2551,8 @@ mailfile(filename, ctladdr, e)
                struct stat stb;
                struct stat fsb;
                MCI mcibuf;
                struct stat stb;
                struct stat fsb;
                MCI mcibuf;
+               int oflags = O_WRONLY|O_APPEND;
+               int oflags = O_WRONLY|O_APPEND;
 
                if (e->e_lockfp != NULL)
                {
 
                if (e->e_lockfp != NULL)
                {
@@ -2553,9 +2565,19 @@ mailfile(filename, ctladdr, e)
                (void) setsignal(SIGTERM, SIG_DFL);
                (void) umask(OldUmask);
 
                (void) setsignal(SIGTERM, SIG_DFL);
                (void) umask(OldUmask);
 
+#ifdef HASLSTAT
+               if ((SafeFileEnv != NULL ? lstat(filename, &stb)
+                                        : stat(filename, &stb)) < 0)
+#else
                if (stat(filename, &stb) < 0)
                if (stat(filename, &stb) < 0)
+               {
+#endif
+               {
                        stb.st_mode = FileMode;
                        stb.st_mode = FileMode;
-               else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1)
+                       oflags |= O_CREAT|O_EXCL;
+               }
+               else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 ||
+                        (SafeFileEnv != NULL && !S_ISREG(stb.st_mode)))
                        exit(EX_CANTCREAT);
                mode = stb.st_mode;
 
                        exit(EX_CANTCREAT);
                mode = stb.st_mode;
 
@@ -2570,15 +2592,34 @@ mailfile(filename, ctladdr, e)
                }
 
                /* we have to open the dfile BEFORE setuid */
                }
 
                /* we have to open the dfile BEFORE setuid */
-               if (e->e_dfp == NULL && e->e_df != NULL)
+               if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
                {
                {
-                       e->e_dfp = fopen(e->e_df, "r");
+                       char *df = queuename(e, 'd');
+
+                       e->e_dfp = fopen(df, "r");
                        if (e->e_dfp == NULL)
                        {
                                syserr("mailfile: Cannot open %s for %s from %s",
                        if (e->e_dfp == NULL)
                        {
                                syserr("mailfile: Cannot open %s for %s from %s",
-                                       e->e_df, e->e_to, e->e_from.q_paddr);
+                                       df, e->e_to, e->e_from.q_paddr);
+                       }
+               }
+
+               if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
+               {
+                       int i;
+
+                       if (chroot(SafeFileEnv) < 0)
+                       {
+                               syserr("mailfile: Cannot chroot(%s)",
+                                       SafeFileEnv);
+                               exit(EX_CANTCREAT);
                        }
                        }
+                       i = strlen(SafeFileEnv);
+                       if (strncmp(SafeFileEnv, filename, i) == 0)
+                               filename += i;
                }
                }
+               if (chdir("/") < 0)
+                       syserr("mailfile: cannot chdir(/)");
 
                if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
                {
 
                if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
                {
@@ -2602,17 +2643,18 @@ mailfile(filename, ctladdr, e)
                }
                FileName = filename;
                LineNumber = 0;
                }
                FileName = filename;
                LineNumber = 0;
-               f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode);
+               f = dfopen(filename, oflags, FileMode);
                if (f == NULL)
                {
                        message("554 cannot open: %s", errstring(errno));
                        exit(EX_CANTCREAT);
                }
                if (fstat(fileno(f), &fsb) < 0 ||
                if (f == NULL)
                {
                        message("554 cannot open: %s", errstring(errno));
                        exit(EX_CANTCREAT);
                }
                if (fstat(fileno(f), &fsb) < 0 ||
-                   stb.st_nlink != fsb.st_nlink ||
-                   stb.st_dev != fsb.st_dev ||
-                   stb.st_ino != fsb.st_ino ||
-                   stb.st_uid != fsb.st_uid)
+                   (!bitset(O_CREAT, oflags) &&
+                    (stb.st_nlink != fsb.st_nlink ||
+                     stb.st_dev != fsb.st_dev ||
+                     stb.st_ino != fsb.st_ino ||
+                     stb.st_uid != fsb.st_uid)))
                {
                        message("554 cannot write: file changed after open");
                        exit(EX_CANTCREAT);
                {
                        message("554 cannot write: file changed after open");
                        exit(EX_CANTCREAT);