BSD 4_4 release
[unix-history] / usr / src / usr.sbin / sendmail / src / main.c
index 722d060..5027aeb 100644 (file)
@@ -1,33 +1,57 @@
 /*
  * Copyright (c) 1983 Eric P. Allman
 /*
  * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * 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
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1988 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     6.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     8.1 (Berkeley) 6/7/93";
 #endif /* not lint */
 
 #define        _DEFINE
 
 #endif /* not lint */
 
 #define        _DEFINE
 
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include "sendmail.h"
 #include <signal.h>
 #include <sgtty.h>
 #include <signal.h>
 #include <sgtty.h>
-#include "sendmail.h"
 #ifdef NAMED_BIND
 #include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 #ifdef NAMED_BIND
 #include <arpa/nameser.h>
 #include <resolv.h>
 #endif
+#include <pwd.h>
 
 # ifdef lint
 char   edata, end;
 
 # ifdef lint
 char   edata, end;
@@ -74,6 +98,7 @@ ADDRESS               NullAddress =   /* a null address */
                { "", "", NULL, "" };
 char           *UserEnviron[MAXUSERENVIRON + 1];
                                /* saved user environment */
                { "", "", NULL, "" };
 char           *UserEnviron[MAXUSERENVIRON + 1];
                                /* saved user environment */
+char           RealUserName[256];      /* the actual user id on this host */
 
 /*
 **  Pointers for setproctitle.
 
 /*
 **  Pointers for setproctitle.
@@ -87,19 +112,6 @@ char                **Argv = NULL;          /* pointer to argument vector */
 char           *LastArgv = NULL;       /* end of argv */
 # endif /* SETPROCTITLE */
 
 char           *LastArgv = NULL;       /* end of argv */
 # endif /* SETPROCTITLE */
 
-/*
-**  The file in which to log raw recipient information.
-**     This is logged before aliasing, forwarding, and so forth so we
-**     can see how our addresses are being used.  For example, this
-**     would give us the names of aliases (instead of what they alias
-**     to), the pre-MX hostnames, and so forth.
-**
-**     This is specified on the command line, not in the config file,
-**     and is therefore really only useful for logging SMTP RCPTs.
-*/
-
-char           *RcptLogFile = NULL;    /* file name */
-
 static void    obsolete();
 
 #ifdef DAEMON
 static void    obsolete();
 
 #ifdef DAEMON
@@ -108,7 +120,7 @@ ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
 #endif /* SMTP */
 #endif /* DAEMON */
 
 #endif /* SMTP */
 #endif /* DAEMON */
 
-#define MAXCONFIGLEVEL 3       /* highest config version level known */
+#define MAXCONFIGLEVEL 4       /* highest config version level known */
 
 main(argc, argv, envp)
        int argc;
 
 main(argc, argv, envp)
        int argc;
@@ -118,7 +130,6 @@ main(argc, argv, envp)
        register char *p;
        register char *q;
        char **av;
        register char *p;
        register char *q;
        char **av;
-       char *locname;
        extern int finis();
        extern char Version[];
        char *ep, *from;
        extern int finis();
        extern char Version[];
        char *ep, *from;
@@ -132,16 +143,17 @@ main(argc, argv, envp)
        bool safecf = TRUE;
        static bool reenter = FALSE;
        char *argv0 = argv[0];
        bool safecf = TRUE;
        static bool reenter = FALSE;
        char *argv0 = argv[0];
+       struct passwd *pw;
+       struct stat stb;
        char jbuf[MAXHOSTNAMELEN];      /* holds MyHostName */
        extern int DtableSize;
        extern int optind;
        char jbuf[MAXHOSTNAMELEN];      /* holds MyHostName */
        extern int DtableSize;
        extern int optind;
-       extern bool safefile();
        extern time_t convtime();
        extern putheader(), putbody();
        extern time_t convtime();
        extern putheader(), putbody();
-       extern ENVELOPE *newenvelope();
        extern void intsig();
        extern char **myhostname();
        extern char *arpadate();
        extern void intsig();
        extern char **myhostname();
        extern char *arpadate();
+       extern char *getauthinfo();
        extern char *optarg;
        extern char **environ;
 
        extern char *optarg;
        extern char **environ;
 
@@ -157,8 +169,6 @@ main(argc, argv, envp)
                abort();
        }
        reenter = TRUE;
                abort();
        }
        reenter = TRUE;
-       extern ADDRESS *recipient();
-       bool canrename;
 
 #ifndef SYS5TZ
        /* enforce use of kernel-supplied time zone information */
 
 #ifndef SYS5TZ
        /* enforce use of kernel-supplied time zone information */
@@ -176,8 +186,13 @@ main(argc, argv, envp)
        */
 
        i = open("/dev/null", O_RDWR);
        */
 
        i = open("/dev/null", O_RDWR);
-       while (i >= 0 && i < 2)
-               i = dup(i);
+       if (fstat(STDIN_FILENO, &stb) < 0)
+               (void) dup2(i, STDIN_FILENO);
+       if (fstat(STDOUT_FILENO, &stb) < 0)
+               (void) dup2(i, STDOUT_FILENO);
+       if (fstat(STDERR_FILENO, &stb) < 0)
+               (void) dup2(i, STDERR_FILENO);
+       (void) close(i);
 
        i = DtableSize;
        while (--i > 0)
 
        i = DtableSize;
        while (--i > 0)
@@ -193,20 +208,29 @@ main(argc, argv, envp)
        openlog("sendmail", LOG_PID);
 #endif 
 
        openlog("sendmail", LOG_PID);
 #endif 
 
+       /* set up the blank envelope */
+       BlankEnvelope.e_puthdr = putheader;
+       BlankEnvelope.e_putbody = putbody;
+       BlankEnvelope.e_xfp = NULL;
+       STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
+       CurEnv = &BlankEnvelope;
+       STRUCTCOPY(NullAddress, MainEnvelope.e_from);
+
        /*
        **  Set default values for variables.
        **      These cannot be in initialized data space.
        */
 
        /*
        **  Set default values for variables.
        **      These cannot be in initialized data space.
        */
 
-       setdefaults();
+       setdefaults(&BlankEnvelope);
 
 
-       /* set up the blank envelope */
-       BlankEnvelope.e_puthdr = putheader;
-       BlankEnvelope.e_putbody = putbody;
-       BlankEnvelope.e_xfp = NULL;
-       STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
-       STRUCTCOPY(BlankEnvelope, MainEnvelope);
-       CurEnv = &MainEnvelope;
+       RealUid = getuid();
+       RealGid = getgid();
+
+       pw = getpwuid(RealUid);
+       if (pw != NULL)
+               (void) strcpy(RealUserName, pw->pw_name);
+       else
+               (void) sprintf(RealUserName, "Unknown UID %d", RealUid);
 
        /* Handle any non-getoptable constructions. */
        obsolete(argv);
 
        /* Handle any non-getoptable constructions. */
        obsolete(argv);
@@ -219,7 +243,11 @@ main(argc, argv, envp)
        **      to the run that froze the configuration.
        */
        nothaw = FALSE;
        **      to the run that froze the configuration.
        */
        nothaw = FALSE;
-#define OPTIONS                "b:C:cd:e:F:f:h:Iimno:p:q:R:r:sTtv"
+#ifdef __osf__
+#define OPTIONS                "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvx"
+#else
+#define OPTIONS                "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtv"
+#endif
        while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
                switch (j)
        while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
                switch (j)
@@ -249,8 +277,12 @@ main(argc, argv, envp)
        InChannel = stdin;
        OutChannel = stdout;
 
        InChannel = stdin;
        OutChannel = stdout;
 
+# ifdef FROZENCONFIG
        if (!nothaw)
                readconfig = !thaw(FreezeFile, argv0);
        if (!nothaw)
                readconfig = !thaw(FreezeFile, argv0);
+# else
+       readconfig = TRUE;
+# endif
 
 # ifdef SETPROCTITLE
        /*
 
 # ifdef SETPROCTITLE
        /*
@@ -284,11 +316,15 @@ main(argc, argv, envp)
                (void) signal(SIGHUP, intsig);
        (void) signal(SIGTERM, intsig);
        (void) signal(SIGPIPE, SIG_IGN);
                (void) signal(SIGHUP, intsig);
        (void) signal(SIGTERM, intsig);
        (void) signal(SIGPIPE, SIG_IGN);
-       OldUmask = umask(0);
+       OldUmask = umask(022);
        OpMode = MD_DELIVER;
        OpMode = MD_DELIVER;
-       MotherPid = getpid();
        FullName = getenv("NAME");
 
        FullName = getenv("NAME");
 
+#ifdef NAMED_BIND
+       if (tTd(8, 8))
+               _res.options |= RES_DEBUG;
+#endif
+
        errno = 0;
        from = NULL;
 
        errno = 0;
        from = NULL;
 
@@ -297,54 +333,61 @@ main(argc, argv, envp)
                /* initialize some macros, etc. */
                initmacros();
 
                /* initialize some macros, etc. */
                initmacros();
 
-               /* hostname */
-               av = myhostname(jbuf, sizeof jbuf);
-               if (jbuf[0] != '\0')
-               {
-                       struct  utsname utsname;
-                       extern char *strchr();
+               /* version */
+               define('v', Version, CurEnv);
+       }
 
 
-                       if (tTd(0, 4))
-                               printf("canonical name: %s\n", jbuf);
-                       p = newstr(jbuf);
-                       define('w', p, CurEnv);
+       /* hostname */
+       av = myhostname(jbuf, sizeof jbuf);
+       if (jbuf[0] != '\0')
+       {
+               struct  utsname utsname;
 
 
-                       q = strchr(jbuf, '.');
-                       if (q != NULL)
-                       {
-                               *q++ = '\0';
-                               p = newstr(jbuf);
-                               define('m', q, CurEnv);
-                       }
-                       setclass('w', p);
+               if (tTd(0, 4))
+                       printf("canonical name: %s\n", jbuf);
+               p = newstr(jbuf);
+               define('w', p, CurEnv);
+               setclass('w', p);
 
 
-                       if (uname(&utsname) >= 0)
-                               p = utsname.nodename;
-                       else
-                       {
-                               makelower(jbuf);
-                               p = jbuf;
-                       }
-                       if (tTd(0, 4))
-                               printf("UUCP nodename: %s\n", p);
-                       p = newstr(p);
-                       define('k', p, CurEnv);
+               q = strchr(jbuf, '.');
+               if (q != NULL)
+               {
+                       *q++ = '\0';
+                       define('m', q, CurEnv);
+                       p = newstr(jbuf);
                        setclass('w', p);
                }
                        setclass('w', p);
                }
-               while (av != NULL && *av != NULL)
+
+               if (uname(&utsname) >= 0)
+                       p = utsname.nodename;
+               else
                {
                {
-                       if (tTd(0, 4))
-                               printf("\ta.k.a.: %s\n", *av);
-                       setclass('w', *av++);
+                       makelower(jbuf);
+                       p = jbuf;
                }
                }
-
-               /* version */
-               define('v', Version, CurEnv);
+               if (tTd(0, 4))
+                       printf("UUCP nodename: %s\n", p);
+               p = newstr(p);
+               define('k', p, CurEnv);
+               setclass('w', p);
+       }
+       while (av != NULL && *av != NULL)
+       {
+               if (tTd(0, 4))
+                       printf("\ta.k.a.: %s\n", *av);
+               setclass('w', *av++);
        }
 
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
 
        }
 
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
 
+       /*
+       **  Find our real host name for future logging.
+       */
+
+       p = getauthinfo(STDIN_FILENO);
+       define('_', p, CurEnv);
+
        /*
        ** Crack argv.
        */
        /*
        ** Crack argv.
        */
@@ -391,10 +434,19 @@ main(argc, argv, envp)
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
+#ifdef FROZENCONFIG
                          case MD_FREEZE:
                          case MD_FREEZE:
+#endif
                                OpMode = j;
                                break;
 
                                OpMode = j;
                                break;
 
+#ifndef FROZENCONFIG
+                         case MD_FREEZE:
+                               usrerr("Frozen configurations unsupported");
+                               ExitStat = EX_USAGE;
+                               break;
+#endif
+
                          default:
                                usrerr("Invalid operation mode %c", j);
                                ExitStat = EX_USAGE;
                          default:
                                usrerr("Invalid operation mode %c", j);
                                ExitStat = EX_USAGE;
@@ -402,7 +454,15 @@ main(argc, argv, envp)
                        }
                        break;
 
                        }
                        break;
 
+                 case 'B':     /* body type */
+                       CurEnv->e_bodytype = newstr(optarg);
+                       break;
+
                  case 'C':     /* select configuration file (already done) */
                  case 'C':     /* select configuration file (already done) */
+                       if (getuid() != 0)
+                               auth_warning(CurEnv,
+                                       "Processed by %s with -C %s",
+                                       RealUserName, optarg);
                        break;
 
                  case 'd':     /* debugging -- redo in case frozen */
                        break;
 
                  case 'd':     /* debugging -- redo in case frozen */
@@ -420,6 +480,10 @@ main(argc, argv, envp)
                                break;
                        }
                        from = newstr(optarg);
                                break;
                        }
                        from = newstr(optarg);
+                       if (strcmp(RealUserName, from) != 0)
+                               auth_warning(CurEnv,
+                                       "%s set sender to %s using -%c",
+                                       RealUserName, from, j);
                        break;
 
                  case 'F':     /* set full name */
                        break;
 
                  case 'F':     /* set full name */
@@ -441,7 +505,7 @@ main(argc, argv, envp)
                        break;
 
                  case 'o':     /* set option */
                        break;
 
                  case 'o':     /* set option */
-                       setoption(*optarg, optarg + 1, FALSE, TRUE);
+                       setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
                        break;
 
                  case 'p':     /* set protocol */
                        break;
 
                  case 'p':     /* set protocol */
@@ -450,7 +514,7 @@ main(argc, argv, envp)
                                *q++ = '\0';
                        if (*optarg != '\0')
                                define('r', newstr(optarg), CurEnv);
                                *q++ = '\0';
                        if (*optarg != '\0')
                                define('r', newstr(optarg), CurEnv);
-                       if (*q != '\0')
+                       if (q != NULL && *q != '\0')
                                define('s', newstr(q), CurEnv);
                        break;
 
                                define('s', newstr(q), CurEnv);
                        break;
 
@@ -459,7 +523,24 @@ main(argc, argv, envp)
                        (void) unsetenv("HOSTALIASES");
                        FullName = NULL;
                        queuemode = TRUE;
                        (void) unsetenv("HOSTALIASES");
                        FullName = NULL;
                        queuemode = TRUE;
-                       QueueIntvl = convtime(optarg);
+                       switch (optarg[0])
+                       {
+                         case 'I':
+                               QueueLimitId = newstr(&optarg[1]);
+                               break;
+
+                         case 'R':
+                               QueueLimitRecipient = newstr(&optarg[1]);
+                               break;
+
+                         case 'S':
+                               QueueLimitSender = newstr(&optarg[1]);
+                               break;
+
+                         default:
+                               QueueIntvl = convtime(optarg, 'm');
+                               break;
+                       }
 # else /* QUEUE */
                        usrerr("I don't know about queues");
                        ExitStat = EX_USAGE;
 # else /* QUEUE */
                        usrerr("I don't know about queues");
                        ExitStat = EX_USAGE;
@@ -476,15 +557,15 @@ main(argc, argv, envp)
                  case 'm':     /* send to me too */
                  case 'T':     /* set timeout interval */
                  case 'v':     /* give blow-by-blow description */
                  case 'm':     /* send to me too */
                  case 'T':     /* set timeout interval */
                  case 'v':     /* give blow-by-blow description */
-                       setoption(j, "T", FALSE, TRUE);
+                       setoption(j, "T", FALSE, TRUE, CurEnv);
                        break;
 
                  case 'e':     /* error message disposition */
                        break;
 
                  case 'e':     /* error message disposition */
-                       setoption(j, optarg, FALSE, TRUE);
+                       setoption(j, optarg, FALSE, TRUE, CurEnv);
                        break;
 
                  case 's':     /* save From lines in headers */
                        break;
 
                  case 's':     /* save From lines in headers */
-                       setoption('f', "T", FALSE, TRUE);
+                       setoption('f', "T", FALSE, TRUE, CurEnv);
                        break;
 
 # ifdef DBM
                        break;
 
 # ifdef DBM
@@ -493,9 +574,10 @@ main(argc, argv, envp)
                        break;
 # endif /* DBM */
 
                        break;
 # endif /* DBM */
 
-                 case 'R':     /* log raw recipient info */
-                       RcptLogFile = newstr(optarg);
+# ifdef __osf__
+                 case 'x':     /* random flag that DEC OSF/1 mailx passes */
                        break;
                        break;
+# endif
 
                  default:
                        ExitStat = EX_USAGE;
 
                  default:
                        ExitStat = EX_USAGE;
@@ -505,11 +587,6 @@ main(argc, argv, envp)
        }
        av += optind;
 
        }
        av += optind;
 
-#ifdef NAMED_BIND
-       if (tTd(8, 8))
-               _res.options |= RES_DEBUG;
-#endif
-
        /*
        **  Do basic initialization.
        **      Read system control file.
        /*
        **  Do basic initialization.
        **      Read system control file.
@@ -553,8 +630,10 @@ main(argc, argv, envp)
                }
        }
 # endif /* QUEUE */
                }
        }
 # endif /* QUEUE */
+
        switch (OpMode)
        {
        switch (OpMode)
        {
+# ifdef FROZENCONFIG
          case MD_FREEZE:
                /* this is critical to avoid forgeries of the frozen config */
                (void) setgid(getgid());
          case MD_FREEZE:
                /* this is critical to avoid forgeries of the frozen config */
                (void) setgid(getgid());
@@ -563,6 +642,7 @@ main(argc, argv, envp)
                /* freeze the configuration */
                freeze(FreezeFile);
                exit(EX_OK);
                /* freeze the configuration */
                freeze(FreezeFile);
                exit(EX_OK);
+# endif
 
          case MD_INITALIAS:
                Verbose = TRUE;
 
          case MD_INITALIAS:
                Verbose = TRUE;
@@ -572,20 +652,27 @@ main(argc, argv, envp)
                /* remove things that don't make sense in daemon mode */
                FullName = NULL;
                break;
                /* remove things that don't make sense in daemon mode */
                FullName = NULL;
                break;
+
+         case MD_SMTP:
+               if (RealUid != 0)
+                       auth_warning(CurEnv,
+                               "%s owned process doing -bs",
+                               RealUserName);
+               break;
        }
 
        /* do heuristic mode adjustment */
        if (Verbose)
        {
                /* turn off noconnect option */
        }
 
        /* do heuristic mode adjustment */
        if (Verbose)
        {
                /* turn off noconnect option */
-               setoption('c', "F", TRUE, FALSE);
+               setoption('c', "F", TRUE, FALSE, CurEnv);
 
                /* turn on interactive delivery */
 
                /* turn on interactive delivery */
-               setoption('d', "", TRUE, FALSE);
+               setoption('d', "", TRUE, FALSE, CurEnv);
        }
 
        /* our name for SMTP codes */
        }
 
        /* our name for SMTP codes */
-       expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+       expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
        MyHostName = jbuf;
 
        /* the indices of built-in mailers */
        MyHostName = jbuf;
 
        /* the indices of built-in mailers */
@@ -621,6 +708,10 @@ main(argc, argv, envp)
                exit(EX_SOFTWARE);
        }
 
                exit(EX_SOFTWARE);
        }
 
+       /* if we've had errors so far, exit now */
+       if (ExitStat != EX_OK)
+               exit(ExitStat);
+
        /*
        **  Do operation-mode-dependent initialization.
        */
        /*
        **  Do operation-mode-dependent initialization.
        */
@@ -640,7 +731,7 @@ main(argc, argv, envp)
 
          case MD_INITALIAS:
                /* initialize alias database */
 
          case MD_INITALIAS:
                /* initialize alias database */
-               initaliases(AliasFile, TRUE, CurEnv);
+               initmaps(TRUE, CurEnv);
                exit(EX_OK);
 
          case MD_DAEMON:
                exit(EX_OK);
 
          case MD_DAEMON:
@@ -649,7 +740,7 @@ main(argc, argv, envp)
 
          default:
                /* open the alias database */
 
          default:
                /* open the alias database */
-               initaliases(AliasFile, FALSE, CurEnv);
+               initmaps(FALSE, CurEnv);
                break;
        }
 
                break;
        }
 
@@ -664,9 +755,9 @@ main(argc, argv, envp)
 
                        if (m == NULL)
                                continue;
 
                        if (m == NULL)
                                continue;
-                       printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
-                               m->m_mailer, m->m_s_rwset, m->m_r_rwset,
-                               m->m_maxsize);
+                       printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name,
+                               m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
+                               m->m_re_rwset, m->m_rh_rwset, m->m_maxsize);
                        for (j = '\0'; j <= '\177'; j++)
                                if (bitnset(j, m->m_flags))
                                        (void) putchar(j);
                        for (j = '\0'; j <= '\177'; j++)
                                if (bitnset(j, m->m_flags))
                                        (void) putchar(j);
@@ -692,7 +783,7 @@ main(argc, argv, envp)
        **  Switch to the main envelope.
        */
 
        **  Switch to the main envelope.
        */
 
-       CurEnv = newenvelope(&MainEnvelope);
+       CurEnv = newenvelope(&MainEnvelope, CurEnv);
        MainEnvelope.e_flags = BlankEnvelope.e_flags;
 
        /*
        MainEnvelope.e_flags = BlankEnvelope.e_flags;
 
        /*
@@ -701,10 +792,12 @@ main(argc, argv, envp)
 
        if (OpMode == MD_TEST)
        {
 
        if (OpMode == MD_TEST)
        {
-               bool terminal = isatty(fileno(stdin));
                char buf[MAXLINE];
 
                char buf[MAXLINE];
 
-               if (terminal)
+               if (isatty(fileno(stdin)))
+                       Verbose = TRUE;
+
+               if (Verbose)
                {
                        printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
                        printf("Enter <ruleset> <address>\n");
                {
                        printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
                        printf("Enter <ruleset> <address>\n");
@@ -713,22 +806,22 @@ main(argc, argv, envp)
                {
                        register char **pvp;
                        char *q;
                {
                        register char **pvp;
                        char *q;
-                       extern char *DelimChar;
+                       auto char *delimptr;
                        extern bool invalidaddr();
 
                        extern bool invalidaddr();
 
-                       if (terminal)
+                       if (Verbose)
                                printf("> ");
                        (void) fflush(stdout);
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
                                printf("> ");
                        (void) fflush(stdout);
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
-                       if (!terminal)
+                       if (!Verbose)
                                printf("> %s", buf);
                        if (buf[0] == '#')
                                continue;
                                printf("> %s", buf);
                        if (buf[0] == '#')
                                continue;
-                       for (p = buf; isspace(*p); p++)
+                       for (p = buf; isascii(*p) && isspace(*p); p++)
                                continue;
                        q = p;
                                continue;
                        q = p;
-                       while (*p != '\0' && !isspace(*p))
+                       while (*p != '\0' && !(isascii(*p) && isspace(*p)))
                                p++;
                        if (*p == '\0')
                        {
                                p++;
                        if (*p == '\0')
                        {
@@ -740,20 +833,24 @@ main(argc, argv, envp)
                                continue;
                        do
                        {
                                continue;
                        do
                        {
-                               extern char **prescan();
                                char pvpbuf[PSBUFSIZE];
 
                                char pvpbuf[PSBUFSIZE];
 
-                               pvp = prescan(++p, ',', pvpbuf);
+                               pvp = prescan(++p, ',', pvpbuf, &delimptr);
                                if (pvp == NULL)
                                        continue;
                                p = q;
                                while (*p != '\0')
                                {
                                if (pvp == NULL)
                                        continue;
                                p = q;
                                while (*p != '\0')
                                {
-                                       rewrite(pvp, atoi(p));
+                                       int stat;
+
+                                       stat = rewrite(pvp, atoi(p), CurEnv);
+                                       if (stat != EX_OK)
+                                               printf("== Ruleset %s status %d\n",
+                                                       p, stat);
                                        while (*p != '\0' && *p++ != ',')
                                                continue;
                                }
                                        while (*p != '\0' && *p++ != ',')
                                                continue;
                                }
-                       } while (*(p = DelimChar) != '\0');
+                       } while (*(p = delimptr) != '\0');
                }
        }
 
                }
        }
 
@@ -780,6 +877,8 @@ main(argc, argv, envp)
 
        if (OpMode == MD_DAEMON || QueueIntvl != 0)
        {
 
        if (OpMode == MD_DAEMON || QueueIntvl != 0)
        {
+               char dtype[200];
+
                if (!tTd(0, 1))
                {
                        /* put us in background */
                if (!tTd(0, 1))
                {
                        /* put us in background */
@@ -789,13 +888,26 @@ main(argc, argv, envp)
                        if (i != 0)
                                exit(0);
 
                        if (i != 0)
                                exit(0);
 
-                       /* get our pid right */
-                       MotherPid = getpid();
-
                        /* disconnect from our controlling tty */
                        /* disconnect from our controlling tty */
-                       disconnect(TRUE);
+                       disconnect(TRUE, CurEnv);
                }
 
                }
 
+               dtype[0] = '\0';
+               if (OpMode == MD_DAEMON)
+                       strcat(dtype, "+SMTP");
+               if (QueueIntvl != 0)
+               {
+                       strcat(dtype, "+queueing@");
+                       strcat(dtype, pintvl(QueueIntvl, TRUE));
+               }
+               if (tTd(0, 1))
+                       strcat(dtype, "+debugging");
+
+               syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1);
+#ifdef XLA
+               xla_create_file();
+#endif
+
 # ifdef QUEUE
                if (queuemode)
                {
 # ifdef QUEUE
                if (queuemode)
                {
@@ -811,9 +923,15 @@ main(argc, argv, envp)
                getrequests();
 
                /* at this point we are in a child: reset state */
                getrequests();
 
                /* at this point we are in a child: reset state */
-               OpMode = MD_SMTP;
-               (void) newenvelope(CurEnv);
-               openxscript(CurEnv);
+               (void) newenvelope(CurEnv, CurEnv);
+
+               /*
+               **  Get authentication data
+               */
+
+               p = getauthinfo(fileno(InChannel));
+               define('_', p, CurEnv);
+
 #endif /* DAEMON */
        }
        
 #endif /* DAEMON */
        }
        
@@ -831,8 +949,19 @@ main(argc, argv, envp)
        **  Do basic system initialization and set the sender
        */
 
        **  Do basic system initialization and set the sender
        */
 
+       /* make sendmail immune from process group signals */
+# ifdef _POSIX_JOB_CONTROL
+       (void) setpgid(0, getpid());
+# else
+# ifndef SYSTEM5
+       (void) setpgrp(0, getpid());
+# endif
+# endif
+
        initsys(CurEnv);
        initsys(CurEnv);
-       setsender(from, CurEnv);
+       setsender(from, CurEnv, NULL, FALSE);
+       if (macvalue('s', CurEnv) == NULL)
+               define('s', RealHostName, CurEnv);
 
        if (*av == NULL && !GrabTo)
        {
 
        if (*av == NULL && !GrabTo)
        {
@@ -840,11 +969,14 @@ main(argc, argv, envp)
 
                /* collect body for UUCP return */
                if (OpMode != MD_VERIFY)
 
                /* collect body for UUCP return */
                if (OpMode != MD_VERIFY)
-                       collect(FALSE, CurEnv);
+                       collect(FALSE, FALSE, CurEnv);
                finis();
        }
        if (OpMode == MD_VERIFY)
                finis();
        }
        if (OpMode == MD_VERIFY)
-               SendMode = SM_VERIFY;
+       {
+               CurEnv->e_sendmode = SM_VERIFY;
+               CurEnv->e_errormode = EM_QUIET;
+       }
 
        /*
        **  Scan argv and deliver the message to everyone.
 
        /*
        **  Scan argv and deliver the message to everyone.
@@ -862,7 +994,7 @@ main(argc, argv, envp)
 
        CurEnv->e_to = NULL;
        if (OpMode != MD_VERIFY || GrabTo)
 
        CurEnv->e_to = NULL;
        if (OpMode != MD_VERIFY || GrabTo)
-               collect(FALSE, CurEnv);
+               collect(FALSE, FALSE, CurEnv);
        errno = 0;
 
        /* collect statistics */
        errno = 0;
 
        /* collect statistics */
@@ -887,7 +1019,8 @@ main(argc, argv, envp)
        sendall(CurEnv, SM_DEFAULT);
 
        /*
        sendall(CurEnv, SM_DEFAULT);
 
        /*
-       ** All done.
+       **  All done.
+       **      Don't send return error message if in VERIFY mode.
        */
 
        finis();
        */
 
        finis();
@@ -915,14 +1048,19 @@ finis()
        dropenvelope(CurEnv);
 
        /* flush any cached connections */
        dropenvelope(CurEnv);
 
        /* flush any cached connections */
-       mci_flush();
+       mci_flush(TRUE, NULL);
 
        /* post statistics */
        poststats(StatFile);
 
 
        /* post statistics */
        poststats(StatFile);
 
+# ifdef XLA
+       /* clean up extended load average stuff */
+       xla_all_end();
+# endif
+
        /* and exit */
 # ifdef LOG
        /* and exit */
 # ifdef LOG
-       if (LogLevel > 11)
+       if (LogLevel > 78)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 # endif /* LOG */
        if (ExitStat == EX_TEMPFAIL)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 # endif /* LOG */
        if (ExitStat == EX_TEMPFAIL)
@@ -950,6 +1088,9 @@ intsig()
 {
        FileName = NULL;
        unlockqueue(CurEnv);
 {
        FileName = NULL;
        unlockqueue(CurEnv);
+#ifdef XLA
+       xla_all_end();
+#endif
        exit(EX_OK);
 }
 \f/*
        exit(EX_OK);
 }
 \f/*
@@ -977,15 +1118,17 @@ struct metamac   MetaMacros[] =
        /* these are RHS metasymbols */
        '#', CANONNET,          '@', CANONHOST,         ':', CANONUSER,
        '>', CALLSUBR,
        /* these are RHS metasymbols */
        '#', CANONNET,          '@', CANONHOST,         ':', CANONUSER,
        '>', CALLSUBR,
-       '{', MATCHLOOKUP,               '}', MATCHELOOKUP,
 
        /* the conditional operations */
        '?', CONDIF,            '|', CONDELSE,          '.', CONDFI,
 
 
        /* the conditional operations */
        '?', CONDIF,            '|', CONDELSE,          '.', CONDFI,
 
-       /* and finally the hostname lookup characters */
+       /* the hostname lookup characters */
        '[', HOSTBEGIN,         ']', HOSTEND,
        '(', LOOKUPBEGIN,       ')', LOOKUPEND,
 
        '[', HOSTBEGIN,         ']', HOSTEND,
        '(', LOOKUPBEGIN,       ')', LOOKUPEND,
 
+       /* miscellaneous control characters */
+       '&', MACRODEXPAND,
+
        '\0'
 };
 
        '\0'
 };
 
@@ -1024,6 +1167,8 @@ initmacros()
 **             Writes BSS and malloc'ed memory to freezefile
 */
 
 **             Writes BSS and malloc'ed memory to freezefile
 */
 
+# ifdef FROZENCONFIG
+
 union frz
 {
        char            frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
 union frz
 {
        char            frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
@@ -1037,13 +1182,21 @@ union frz
        } frzinfo;
 };
 
        } frzinfo;
 };
 
+#if defined(__hpux) || defined(__alpha)
+#define BRK_TYPE        int
+#define SBRK_TYPE       void *
+#else
+#define BRK_TYPE        char *
+#define SBRK_TYPE       char *
+#endif
+
 freeze(freezefile)
        char *freezefile;
 {
        int f;
        union frz fhdr;
 freeze(freezefile)
        char *freezefile;
 {
        int f;
        union frz fhdr;
+       extern SBRK_TYPE sbrk();
        extern char edata, end;
        extern char edata, end;
-       extern char *sbrk();
        extern char Version[];
 
        if (freezefile == NULL)
        extern char Version[];
 
        if (freezefile == NULL)
@@ -1102,9 +1255,8 @@ thaw(freezefile, binfile)
        struct stat fst, sst;
        extern char edata, end;
        extern char Version[];
        struct stat fst, sst;
        extern char edata, end;
        extern char Version[];
-       extern caddr_t brk();
        extern char **myhostname();
        extern char **myhostname();
-       extern char *macvalue();
+       extern BRK_TYPE brk();
 
        if (freezefile == NULL)
                return (FALSE);
 
        if (freezefile == NULL)
                return (FALSE);
@@ -1144,13 +1296,14 @@ thaw(freezefile, binfile)
            fhdr.frzinfo.frzend != &end ||
            strcmp(fhdr.frzinfo.frzver, Version) != 0)
        {
            fhdr.frzinfo.frzend != &end ||
            strcmp(fhdr.frzinfo.frzver, Version) != 0)
        {
+               fprintf(stderr, "Wrong version of frozen config file\n");
                syslog(LOG_WARNING, "Wrong version of frozen config file");
                (void) close(f);
                return (FALSE);
        }
 
        /* arrange to have enough space */
                syslog(LOG_WARNING, "Wrong version of frozen config file");
                (void) close(f);
                return (FALSE);
        }
 
        /* arrange to have enough space */
-       if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
+       if (brk(fhdr.frzinfo.frzbrk) == (BRK_TYPE) -1)
        {
                syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
                (void) close(f);
        {
                syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
                (void) close(f);
@@ -1180,6 +1333,8 @@ thaw(freezefile, binfile)
                p, hbuf);
        return (FALSE);
 }
                p, hbuf);
        return (FALSE);
 }
+
+# endif /* FROZENCONFIG */
 \f/*
 **  DISCONNECT -- remove our connection with any foreground process
 **
 \f/*
 **  DISCONNECT -- remove our connection with any foreground process
 **
@@ -1198,14 +1353,15 @@ thaw(freezefile, binfile)
 **             the controlling tty.
 */
 
 **             the controlling tty.
 */
 
-disconnect(fulldrop)
+disconnect(fulldrop, e)
        bool fulldrop;
        bool fulldrop;
+       register ENVELOPE *e;
 {
        int fd;
 
        if (tTd(52, 1))
 {
        int fd;
 
        if (tTd(52, 1))
-               printf("disconnect: In %d Out %d\n", fileno(InChannel),
-                                               fileno(OutChannel));
+               printf("disconnect: In %d Out %d, e=%x\n",
+                       fileno(InChannel), fileno(OutChannel), e);
        if (tTd(52, 5))
        {
                printf("don't\n");
        if (tTd(52, 5))
        {
                printf("don't\n");
@@ -1219,7 +1375,7 @@ disconnect(fulldrop)
 
        /* we can't communicate with our caller, so.... */
        HoldErrs = TRUE;
 
        /* we can't communicate with our caller, so.... */
        HoldErrs = TRUE;
-       ErrorMode = EM_MAIL;
+       CurEnv->e_errormode = EM_MAIL;
        Verbose = FALSE;
 
        /* all input from /dev/null */
        Verbose = FALSE;
 
        /* all input from /dev/null */
@@ -1236,22 +1392,20 @@ disconnect(fulldrop)
                (void) fclose(OutChannel);
                OutChannel = stdout;
        }
                (void) fclose(OutChannel);
                OutChannel = stdout;
        }
-       if (CurEnv->e_xfp == NULL)
-               CurEnv->e_xfp = fopen("/dev/null", "w");
+       if (e->e_xfp == NULL)
+               fd = open("/dev/null", O_WRONLY, 0666);
+       else
+               fd = fileno(e->e_xfp);
        (void) fflush(stdout);
        (void) fflush(stdout);
-       (void) close(1);
-       (void) close(2);
-       while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
-               continue;
+       dup2(fd, STDOUT_FILENO);
+       dup2(fd, STDERR_FILENO);
+       if (e->e_xfp == NULL)
+               close(fd);
 
        /* drop our controlling TTY completely if possible */
        if (fulldrop)
        {
 
        /* drop our controlling TTY completely if possible */
        if (fulldrop)
        {
-#ifdef SYSTEM5
-               (void) setpgrp();
-#else
                (void) setsid();
                (void) setsid();
-#endif
 #ifdef TIOCNOTTY
                fd = open("/dev/tty", 2);
                if (fd >= 0)
 #ifdef TIOCNOTTY
                fd = open("/dev/tty", 2);
                if (fd >= 0)
@@ -1265,7 +1419,7 @@ disconnect(fulldrop)
        }
 
 # ifdef LOG
        }
 
 # ifdef LOG
-       if (LogLevel > 11)
+       if (LogLevel > 71)
                syslog(LOG_DEBUG, "in background, pid=%d", getpid());
 # endif /* LOG */
 
                syslog(LOG_DEBUG, "in background, pid=%d", getpid());
 # endif /* LOG */
 
@@ -1278,7 +1432,7 @@ obsolete(argv)
 {
        char *ap;
 
 {
        char *ap;
 
-       while (ap = *++argv)
+       while ((ap = *++argv) != NULL)
        {
                /* Return if "--" or not an option of any form. */
                if (ap[0] != '-' || ap[1] == '-')
        {
                /* Return if "--" or not an option of any form. */
                if (ap[0] != '-' || ap[1] == '-')
@@ -1302,7 +1456,49 @@ obsolete(argv)
 
                /* if -d doesn't have an argument, use 0-99.1 */
                if (ap[1] == 'd' && ap[2] == '\0' &&
 
                /* if -d doesn't have an argument, use 0-99.1 */
                if (ap[1] == 'd' && ap[2] == '\0' &&
-                   (argv[1] == NULL || argv[1][0] == '-'))
+                   (argv[1] == NULL || !isdigit(argv[1][0])))
                        *argv = "-d0-99.1";
        }
 }
                        *argv = "-d0-99.1";
        }
 }
+\f/*
+**  AUTH_WARNING -- specify authorization warning
+**
+**     Parameters:
+**             e -- the current envelope.
+**             msg -- the text of the message.
+**             args -- arguments to the message.
+**
+**     Returns:
+**             none.
+*/
+
+void
+#ifdef __STDC__
+auth_warning(register ENVELOPE *e, const char *msg, ...)
+#else
+auth_warning(e, msg, va_alist)
+       register ENVELOPE *e;
+       const char *msg;
+       va_dcl
+#endif
+{
+       char buf[MAXLINE];
+       VA_LOCAL_DECL
+
+       if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
+       {
+               register char *p;
+               static char hostbuf[48];
+               extern char **myhostname();
+
+               if (hostbuf[0] == '\0')
+                       (void) myhostname(hostbuf, sizeof hostbuf);
+
+               (void) sprintf(buf, "%s: ", hostbuf);
+               p = &buf[strlen(buf)];
+               VA_START(msg);
+               vsprintf(p, msg, ap);
+               VA_END;
+               addheader("X-Authentication-Warning", buf, e);
+       }
+}