BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.sbin / sendmail / src / conf.c
index 86ce0cc..4ac109a 100644 (file)
@@ -3,17 +3,44 @@
  * Copyright (c) 1988, 1993
  *     The 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
-static char sccsid[] = "@(#)conf.c     8.30 (Berkeley) %G%";
+static char sccsid[] = "@(#)conf.c     8.89 (Berkeley) 4/18/94";
 #endif /* not lint */
 
 # include "sendmail.h"
 # include "pathnames.h"
 # include <sys/ioctl.h>
 # include <sys/param.h>
 #endif /* not lint */
 
 # include "sendmail.h"
 # include "pathnames.h"
 # include <sys/ioctl.h>
 # include <sys/param.h>
+# include <netdb.h>
 # include <pwd.h>
 
 /*
 # include <pwd.h>
 
 /*
@@ -40,7 +67,7 @@ static char sccsid[] = "@(#)conf.c    8.30 (Berkeley) %G%";
 
 
 
 
 
 
-\f/*
+/*
 **  Header info table
 **     Final (null) entry contains the flags used for any other field.
 **
 **  Header info table
 **     Final (null) entry contains the flags used for any other field.
 **
@@ -60,7 +87,7 @@ struct hdrinfo        HdrInfo[] =
        "from",                 H_FROM,
        "reply-to",             H_FROM,
        "full-name",            H_ACHECK,
        "from",                 H_FROM,
        "reply-to",             H_FROM,
        "full-name",            H_ACHECK,
-       "return-receipt-to",    H_FROM /* |H_RECEIPTTO */,
+       "return-receipt-to",    H_FROM|H_RECEIPTTO,
        "errors-to",            H_FROM|H_ERRORSTO,
 
                /* destination fields */
        "errors-to",            H_FROM|H_ERRORSTO,
 
                /* destination fields */
@@ -101,7 +128,6 @@ struct hdrinfo      HdrInfo[] =
 **  Location of system files/databases/etc.
 */
 
 **  Location of system files/databases/etc.
 */
 
-char   *ConfFile =     _PATH_SENDMAILCF;       /* runtime configuration */
 char   *PidFile =      _PATH_SENDMAILPID;      /* stores daemon proc id */
 
 
 char   *PidFile =      _PATH_SENDMAILPID;      /* stores daemon proc id */
 
 
@@ -121,6 +147,7 @@ struct prival PrivacyValues[] =
        "restrictmailq",        PRIV_RESTRICTMAILQ,
        "restrictqrun",         PRIV_RESTRICTQRUN,
        "authwarnings",         PRIV_AUTHWARNINGS,
        "restrictmailq",        PRIV_RESTRICTMAILQ,
        "restrictqrun",         PRIV_RESTRICTQRUN,
        "authwarnings",         PRIV_AUTHWARNINGS,
+       "noreceipts",           PRIV_NORECEIPTS,
        "goaway",               PRIV_GOAWAY,
        NULL,                   0,
 };
        "goaway",               PRIV_GOAWAY,
        NULL,                   0,
 };
@@ -132,6 +159,25 @@ struct prival PrivacyValues[] =
 */
 
 int    DtableSize =    50;             /* max open files; reset in 4.2bsd */
 */
 
 int    DtableSize =    50;             /* max open files; reset in 4.2bsd */
+
+
+/*
+**  Following should be config parameters (and probably will be in
+**  future releases).  In the meantime, setting these is considered
+**  unsupported, and is intentionally undocumented.
+*/
+
+#ifdef BROKENSMTPPEERS
+bool   BrokenSmtpPeers = TRUE;         /* set if you have broken SMTP peers */
+#else
+bool   BrokenSmtpPeers = FALSE;        /* set if you have broken SMTP peers */
+#endif
+#ifdef NOLOOPBACKCHECK
+bool   CheckLoopBack = FALSE;          /* set to check HELO loopback */
+#else
+bool   CheckLoopBack = TRUE;           /* set to check HELO loopback */
+#endif
+
 \f/*
 **  SETDEFAULTS -- set default values
 **
 \f/*
 **  SETDEFAULTS -- set default values
 **
@@ -465,6 +511,11 @@ checkcompat(to, e)
        if (to == NULL)
                to++;
 # endif /* lint */
        if (to == NULL)
                to++;
 # endif /* lint */
+
+       if (tTd(49, 1))
+               printf("checkcompat(to=%s, from=%s)\n",
+                       to->q_paddr, e->e_from.q_paddr);
+
 # ifdef EXAMPLE_CODE
        /* this code is intended as an example only */
        register STAB *s;
 # ifdef EXAMPLE_CODE
        /* this code is intended as an example only */
        register STAB *s;
@@ -486,12 +537,12 @@ checkcompat(to, e)
 **     This is essentially old BSD "signal(3)".
 */
 
 **     This is essentially old BSD "signal(3)".
 */
 
-setsig_t
+sigfunc_t
 setsignal(sig, handler)
        int sig;
 setsignal(sig, handler)
        int sig;
-       setsig_t handler;
+       sigfunc_t handler;
 {
 {
-#if defined(SYS5SIGNALS) || defined(BSD4_3)
+#if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
        return signal(sig, handler);
 #else
        struct sigaction n, o;
        return signal(sig, handler);
 #else
        struct sigaction n, o;
@@ -538,6 +589,25 @@ rlsesigs()
 {
 }
 \f/*
 {
 }
 \f/*
+**  INIT_MD -- do machine dependent initializations
+**
+**     Systems that have global modes that should be set should do
+**     them here rather than in main.
+*/
+
+#ifdef _AUX_SOURCE
+# include      <compat.h>
+#endif
+
+init_md(argc, argv)
+       int argc;
+       char **argv;
+{
+#ifdef _AUX_SOURCE
+       setcompat(getcompat() | COMPAT_BSDPROT);
+#endif
+}
+\f/*
 **  GETLA -- get the current load average
 **
 **     This code stolen from la.c.
 **  GETLA -- get the current load average
 **
 **     This code stolen from la.c.
@@ -559,6 +629,7 @@ rlsesigs()
 #define LA_SUBR                4       /* call getloadavg */
 #define LA_MACH                5       /* MACH load averages (as on NeXT boxes) */
 #define LA_SHORT       6       /* read kmem for avenrun; interpret as short */
 #define LA_SUBR                4       /* call getloadavg */
 #define LA_MACH                5       /* MACH load averages (as on NeXT boxes) */
 #define LA_SHORT       6       /* read kmem for avenrun; interpret as short */
+#define LA_PROCSTR     7       /* read string ("1.17") from /proc/loadavg */
 
 /* do guesses based on general OS type */
 #ifndef LA_TYPE
 
 /* do guesses based on general OS type */
 #ifndef LA_TYPE
@@ -598,17 +669,17 @@ struct    nlist Nl[] =
 #  define FSHIFT       5
 # endif
 
 #  define FSHIFT       5
 # endif
 
-# if defined(__alpha)
+# if defined(__alpha) || defined(IRIX)
 #  define FSHIFT       10
 # endif
 #  define FSHIFT       10
 # endif
+#endif
 
 
-# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
-#  define FSHIFT       8
-# endif
+#ifndef FSHIFT
+# define FSHIFT                8
 #endif
 
 #endif
 
-#if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE)
-#  define FSCALE       (1 << FSHIFT)
+#ifndef FSCALE
+# define FSCALE                (1 << FSHIFT)
 #endif
 
 getla()
 #endif
 
 getla()
@@ -651,6 +722,9 @@ getla()
                                        _PATH_UNIX, LA_AVENRUN);
                        return (-1);
                }
                                        _PATH_UNIX, LA_AVENRUN);
                        return (-1);
                }
+#ifdef IRIX
+               Nl[X_AVENRUN].n_value &= 0x7fffffff;
+#endif
        }
        if (tTd(3, 20))
                printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
        }
        if (tTd(3, 20))
                printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
@@ -690,6 +764,22 @@ getla()
 #else
 #if LA_TYPE == LA_SUBR
 
 #else
 #if LA_TYPE == LA_SUBR
 
+#ifdef DGUX
+
+#include <sys/dg_sys_info.h>
+
+int getla()
+{
+       struct dg_sys_info_load_info load_info;
+
+       dg_sys_info((long *)&load_info,
+               DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
+
+       return((int) (load_info.one_minute + 0.5));
+}
+
+#else
+
 getla()
 {
        double avenrun[3];
 getla()
 {
        double avenrun[3];
@@ -705,14 +795,19 @@ getla()
        return ((int) (avenrun[0] + 0.5));
 }
 
        return ((int) (avenrun[0] + 0.5));
 }
 
+#endif /* DGUX */
 #else
 #if LA_TYPE == LA_MACH
 
 /*
 #else
 #if LA_TYPE == LA_MACH
 
 /*
-**  This has been tested on NeXT release 2.1.
+**  This has been tested on NEXTSTEP release 2.1/3.X.
 */
 
 */
 
-#include <mach.h>
+#if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
+# include <mach/mach.h>
+#else
+# include <mach.h>
+#endif
 
 getla()
 {
 
 getla()
 {
@@ -736,6 +831,52 @@ getla()
 }
 
 
 }
 
 
+#else
+#if LA_TYPE == LA_PROCSTR
+
+/*
+**  Read /proc/loadavg for the load average.  This is assumed to be
+**  in a format like "0.15 0.12 0.06".
+**
+**     Initially intended for Linux.  This has been in the kernel
+**     since at least 0.99.15.
+*/
+
+# ifndef _PATH_LOADAVG
+#  define _PATH_LOADAVG        "/proc/loadavg"
+# endif
+
+int
+getla()
+{
+       double avenrun;
+       register int result;
+       FILE *fp;
+
+       fp = fopen(_PATH_LOADAVG, "r");
+       if (fp == NULL) 
+       {
+               if (tTd(3, 1))
+                       printf("getla: fopen(%s): %s\n",
+                               _PATH_LOADAVG, errstring(errno));
+               return -1;
+       }
+       result = fscanf(fp, "%lf", &avenrun);
+       fclose(fp);
+       if (result != 1)
+       {
+               if (tTd(3, 1))
+                       printf("getla: fscanf() = %d: %s\n",
+                               result, errstring(errno));
+               return -1;
+       }
+
+       if (tTd(3, 1))
+               printf("getla(): %.2f\n", avenrun);
+
+       return ((int) (avenrun + 0.5));
+}
+
 #else
 
 getla()
 #else
 
 getla()
@@ -748,6 +889,54 @@ getla()
 #endif
 #endif
 #endif
 #endif
 #endif
 #endif
+#endif
+
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:  Many and varied...
+ */
+
+/* Non Apollo stuff removed by Don Lewis 11/15/93 */
+#ifndef lint
+static char  rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
+#endif /* !lint */
+
+#ifdef apollo
+# undef volatile
+#    include <apollo/base.h>
+
+/* ARGSUSED */
+int getloadavg( call_data )
+     caddr_t   call_data;      /* pointer to (double) return value */
+{
+     double *avenrun = (double *) call_data;
+     int i;
+     status_$t      st;
+     long loadav[3];
+     proc1_$get_loadav(loadav, &st);
+     *avenrun = loadav[0] / (double) (1 << 16);
+     return(0);
+}
+#   endif /* apollo */
 \f/*
 **  SHOULDQUEUE -- should this message be queued or sent?
 **
 \f/*
 **  SHOULDQUEUE -- should this message be queued or sent?
 **
@@ -807,10 +996,8 @@ refuseconnections()
 **  SETPROCTITLE -- set process title for ps
 **
 **     Parameters:
 **  SETPROCTITLE -- set process title for ps
 **
 **     Parameters:
-**             fmt -- a printf style format string.  If NULL, the first
-**                     parameter is a literal proctitle previously
-**                     returned by getproctitle.
-**             va_alist -- possible parameters to fmt.
+**             fmt -- a printf style format string.
+**             a, b, c -- possible parameters to fmt.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -821,6 +1008,9 @@ refuseconnections()
 */
 
 #ifdef SETPROCTITLE
 */
 
 #ifdef SETPROCTITLE
+# ifdef HASSETPROCTITLE
+   *** ERROR ***  Cannot have both SETPROCTITLE and HASSETPROCTITLE defined
+# endif
 # ifdef __hpux
 #  include <sys/pstat.h>
 # endif
 # ifdef __hpux
 #  include <sys/pstat.h>
 # endif
@@ -829,6 +1019,7 @@ refuseconnections()
 #  include <sys/exec.h>
 #  ifdef __bsdi__
 #   undef PS_STRINGS   /* BSDI 1.0 doesn't do PS_STRINGS as we expect */
 #  include <sys/exec.h>
 #  ifdef __bsdi__
 #   undef PS_STRINGS   /* BSDI 1.0 doesn't do PS_STRINGS as we expect */
+#   define PROCTITLEPAD        '\0'
 #  endif
 #  ifdef PS_STRINGS
 #   define SETPROC_STATIC static
 #  endif
 #  ifdef PS_STRINGS
 #   define SETPROC_STATIC static
@@ -839,7 +1030,11 @@ refuseconnections()
 # endif
 #endif
 
 # endif
 #endif
 
-char   ProcTitleBuf[MAXLINE];
+#ifndef PROCTITLEPAD
+# define PROCTITLEPAD  ' '
+#endif
+
+#ifndef HASSETPROCTITLE
 
 /*VARARGS1*/
 #ifdef __STDC__
 
 /*VARARGS1*/
 #ifdef __STDC__
@@ -853,6 +1048,7 @@ setproctitle(fmt, va_alist)
 # ifdef SETPROCTITLE
        register char *p;
        register int i;
 # ifdef SETPROCTITLE
        register char *p;
        register int i;
+       SETPROC_STATIC char buf[MAXLINE];
        VA_LOCAL_DECL
 #  ifdef __hpux
        union pstun pst;
        VA_LOCAL_DECL
 #  ifdef __hpux
        union pstun pst;
@@ -860,39 +1056,42 @@ setproctitle(fmt, va_alist)
        extern char **Argv;
        extern char *LastArgv;
 
        extern char **Argv;
        extern char *LastArgv;
 
-       VA_START(fmt);
-       if (fmt == NULL)
-       {
-               /* restore old proctitle */
-               (void) strcpy(ProcTitleBuf, va_arg(ap, char *));
-       }
-       else
-       {
-               p = ProcTitleBuf;
+       p = buf;
 
 
-               /* print sendmail: heading for grep */
-               (void) strcpy(p, "sendmail: ");
-               p += strlen(p);
+       /* print sendmail: heading for grep */
+       (void) strcpy(p, "sendmail: ");
+       p += strlen(p);
 
 
-               /* print the argument string */
-               (void) vsprintf(p, fmt, ap);
-       }
+       /* print the argument string */
+       VA_START(fmt);
+       (void) vsprintf(p, fmt, ap);
        VA_END;
 
        VA_END;
 
-       i = strlen(ProcTitleBuf);
+       i = strlen(buf);
+
+#  ifdef __hpux
+       pst.pst_command = buf;
+       pstat(PSTAT_SETCMD, pst, i, 0, 0);
+#  else
+#   ifdef PS_STRINGS
+       PS_STRINGS->ps_nargvstr = 1;
+       PS_STRINGS->ps_argvstr = buf;
+#   else
        if (i > LastArgv - Argv[0] - 2)
        {
                i = LastArgv - Argv[0] - 2;
        if (i > LastArgv - Argv[0] - 2)
        {
                i = LastArgv - Argv[0] - 2;
-               ProcTitleBuf[i] = '\0';
+               buf[i] = '\0';
        }
        }
-       (void) strcpy(Argv[0], ProcTitleBuf);
+       (void) strcpy(Argv[0], buf);
        p = &Argv[0][i];
        while (p < LastArgv)
        p = &Argv[0][i];
        while (p < LastArgv)
-               *p++ = ' ';
+               *p++ = PROCTITLEPAD;
 #   endif
 #  endif
 # endif /* SETPROCTITLE */
 }
 #   endif
 #  endif
 # endif /* SETPROCTITLE */
 }
+
+#endif
 \f/*
 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
 **
 \f/*
 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
 **
@@ -906,11 +1105,10 @@ setproctitle(fmt, va_alist)
 **             Picks up extant zombies.
 */
 
 **             Picks up extant zombies.
 */
 
-# include <sys/wait.h>
-
 void
 reapchild()
 {
 void
 reapchild()
 {
+       int olderrno = errno;
 # ifdef HASWAITPID
        auto int status;
        int count;
 # ifdef HASWAITPID
        auto int status;
        int count;
@@ -921,8 +1119,10 @@ reapchild()
        {
                if (count++ > 1000)
                {
        {
                if (count++ > 1000)
                {
+#ifdef LOG
                        syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
                                pid, status);
                        syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
                                pid, status);
+#endif
                        break;
                }
        }
                        break;
                }
        }
@@ -942,6 +1142,7 @@ reapchild()
 # ifdef SYS5SIGNALS
        (void) setsignal(SIGCHLD, reapchild);
 # endif
 # ifdef SYS5SIGNALS
        (void) setsignal(SIGCHLD, reapchild);
 # endif
+       errno = olderrno;
 }
 \f/*
 **  UNSETENV -- remove a variable from the environment
 }
 \f/*
 **  UNSETENV -- remove a variable from the environment
@@ -1113,20 +1314,60 @@ setsid __P ((void))
 #ifdef TIOCNOTTY
        int fd;
 
 #ifdef TIOCNOTTY
        int fd;
 
-       fd = open("/dev/tty", 2);
+       fd = open("/dev/tty", O_RDWR, 0);
        if (fd >= 0)
        {
                (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
                (void) close(fd);
        }
 #endif /* TIOCNOTTY */
        if (fd >= 0)
        {
                (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
                (void) close(fd);
        }
 #endif /* TIOCNOTTY */
-# ifdef SYSTEM5
+# ifdef SYS5SETPGRP
        return setpgrp();
 # else
        return setpgid(0, getpid());
 # endif
 }
 
        return setpgrp();
 # else
        return setpgid(0, getpid());
 # endif
 }
 
+#endif
+\f/*
+**  FSYNC -- dummy fsync
+*/
+
+#ifdef NEEDFSYNC
+
+fsync(fd)
+       int fd;
+{
+# ifdef O_SYNC
+       return fcntl(fd, F_SETFL, O_SYNC);
+# else
+       /* nothing we can do */
+       return 0;
+# endif
+}
+
+#endif
+\f/*
+**  DGUX_INET_ADDR -- inet_addr for DG/UX
+**
+**     Data General DG/UX version of inet_addr returns a struct in_addr
+**     instead of a long.  This patches things.
+*/
+
+#ifdef DGUX
+
+#undef inet_addr
+
+long
+dgux_inet_addr(host)
+       char *host;
+{
+       struct in_addr haddr;
+
+       haddr = inet_addr(host);
+       return haddr.s_addr;
+}
+
 #endif
 \f/*
 **  GETOPT -- for old systems or systems with bogus implementations
 #endif
 \f/*
 **  GETOPT -- for old systems or systems with bogus implementations
@@ -1155,9 +1396,13 @@ static char sccsid[] = "@(#)getopt.c     4.3 (Berkeley) 3/9/86";
 /*
  * get option letter from argument vector
  */
 /*
  * get option letter from argument vector
  */
-int    opterr = 1,             /* if error message should be printed */
-       optind = 1,             /* index into parent argv vector */
-       optopt;                 /* character checked for validity */
+#ifdef _CONVEX_SOURCE
+extern int     optind, opterr;
+#else
+int    opterr = 1;             /* if error message should be printed */
+int    optind = 1;             /* index into parent argv vector */
+#endif
+int    optopt;                 /* character checked for validity */
 char   *optarg;                /* argument associated with option */
 
 #define BADCH  (int)'?'
 char   *optarg;                /* argument associated with option */
 
 #define BADCH  (int)'?'
@@ -1166,9 +1411,9 @@ char      *optarg;                /* argument associated with option */
                fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
 
 getopt(nargc,nargv,ostr)
                fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
 
 getopt(nargc,nargv,ostr)
-int    nargc;
-char   **nargv,
-       *ostr;
+       int             nargc;
+       char *const     *nargv;
+       const char      *ostr;
 {
        static char     *place = EMSG;  /* option letter processing */
        static char     atend = 0;
 {
        static char     *place = EMSG;  /* option letter processing */
        static char     atend = 0;
@@ -1253,6 +1498,99 @@ vsprintf(s, fmt, ap)
 
 #endif
 \f/*
 
 #endif
 \f/*
+**  USERSHELLOK -- tell if a user's shell is ok for unrestricted use
+**
+**     Parameters:
+**             shell -- the user's shell from /etc/passwd
+**
+**     Returns:
+**             TRUE -- if it is ok to use this for unrestricted access.
+**             FALSE -- if the shell is restricted.
+*/
+
+#if !HASGETUSERSHELL
+
+# ifndef _PATH_SHELLS
+#  define _PATH_SHELLS "/etc/shells"
+# endif
+
+char   *DefaultUserShells[] =
+{
+       "/bin/sh",
+       "/usr/bin/sh",
+       "/bin/csh",
+       "/usr/bin/csh",
+#ifdef __hpux
+       "/bin/rsh",
+       "/bin/ksh",
+       "/bin/rksh",
+       "/bin/pam",
+       "/usr/bin/keysh",
+       "/bin/posix/sh",
+#endif
+       NULL
+};
+
+#endif
+
+#define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/"
+
+bool
+usershellok(shell)
+       char *shell;
+{
+#if HASGETUSERSHELL
+       register char *p;
+       extern char *getusershell();
+
+       setusershell();
+       while ((p = getusershell()) != NULL)
+               if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
+                       break;
+       endusershell();
+       return p != NULL;
+#else
+       register FILE *shellf;
+       char buf[MAXLINE];
+
+       shellf = fopen(_PATH_SHELLS, "r");
+       if (shellf == NULL)
+       {
+               /* no /etc/shells; see if it is one of the std shells */
+               char **d;
+
+               for (d = DefaultUserShells; *d != NULL; d++)
+               {
+                       if (strcmp(shell, *d) == 0)
+                               return TRUE;
+               }
+               return FALSE;
+       }
+
+       while (fgets(buf, sizeof buf, shellf) != NULL)
+       {
+               register char *p, *q;
+
+               p = buf;
+               while (*p != '\0' && *p != '#' && *p != '/')
+                       p++;
+               if (*p == '#' || *p == '\0')
+                       continue;
+               q = p;
+               while (*p != '\0' && *p != '#' && !isspace(*p))
+                       p++;
+               *p = '\0';
+               if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
+               {
+                       fclose(shellf);
+                       return TRUE;
+               }
+       }
+       fclose(shellf);
+       return FALSE;
+#endif
+}
+\f/*
 **  FREESPACE -- see how much free space is on the queue filesystem
 **
 **     Only implemented if you have statfs.
 **  FREESPACE -- see how much free space is on the queue filesystem
 **
 **     Only implemented if you have statfs.
@@ -1270,24 +1608,33 @@ vsprintf(s, fmt, ap)
 **             Puts the filesystem block size into bsize.
 */
 
 **             Puts the filesystem block size into bsize.
 */
 
-#ifdef HASSTATFS
-# undef HASUSTAT
+/* statfs types */
+#define SFS_NONE       0       /* no statfs implementation */
+#define SFS_USTAT      1       /* use ustat */
+#define SFS_4ARGS      2       /* use four-argument statfs call */
+#define SFS_VFS                3       /* use <sys/vfs.h> implementation */
+#define SFS_MOUNT      4       /* use <sys/mount.h> implementation */
+#define SFS_STATFS     5       /* use <sys/statfs.h> implementation */
+#define SFS_STATVFS    6       /* use <sys/statvfs.h> implementation */
+
+#ifndef SFS_TYPE
+# define SFS_TYPE      SFS_NONE
 #endif
 
 #endif
 
-#if defined(HASUSTAT)
+#if SFS_TYPE == SFS_USTAT
 # include <ustat.h>
 #endif
 # include <ustat.h>
 #endif
-
-#ifdef HASSTATFS
-# if defined(IRIX) || defined(apollo) || defined(_SCO_unix_)
-#  include <sys/statfs.h>
-# else
-#  if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) || defined(NeXT)
-#   include <sys/vfs.h>
-#  else
-#   include <sys/mount.h>
-#  endif
-# endif
+#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
+# include <sys/statfs.h>
+#endif
+#if SFS_TYPE == SFS_VFS
+# include <sys/vfs.h>
+#endif
+#if SFS_TYPE == SFS_MOUNT
+# include <sys/mount.h>
+#endif
+#if SFS_TYPE == SFS_STATVFS
+# include <sys/statvfs.h>
 #endif
 
 long
 #endif
 
 long
@@ -1295,8 +1642,8 @@ freespace(dir, bsize)
        char *dir;
        long *bsize;
 {
        char *dir;
        long *bsize;
 {
-#if defined(HASSTATFS) || defined(HASUSTAT)
-# if defined(HASUSTAT)
+#if SFS_TYPE != SFS_NONE
+# if SFS_TYPE == SFS_USTAT
        struct ustat fs;
        struct stat statbuf;
 #  define FSBLOCKSIZE  DEV_BSIZE
        struct ustat fs;
        struct stat statbuf;
 #  define FSBLOCKSIZE  DEV_BSIZE
@@ -1307,19 +1654,24 @@ freespace(dir, bsize)
 #   define f_bavail    fd_bfreen
 #   define FSBLOCKSIZE fs.fd_bsize
 #  else
 #   define f_bavail    fd_bfreen
 #   define FSBLOCKSIZE fs.fd_bsize
 #  else
+#   if SFS_TYPE == SFS_STATVFS
+       struct statvfs fs;
+#    define FSBLOCKSIZE        fs.f_bsize
+#   else
        struct statfs fs;
        struct statfs fs;
-#   define FSBLOCKSIZE fs.f_bsize
-#   if defined(_SCO_unix_) || defined(IRIX)
-#    define f_bavail f_bfree
+#    define FSBLOCKSIZE        fs.f_bsize
+#    if defined(_SCO_unix_) || defined(IRIX) || defined(apollo)
+#     define f_bavail f_bfree
+#    endif
 #   endif
 #  endif
 # endif
        extern int errno;
 
 #   endif
 #  endif
 # endif
        extern int errno;
 
-# if defined(HASUSTAT)
+# if SFS_TYPE == SFS_USTAT
        if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
 # else
        if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
 # else
-#  if defined(IRIX) || defined(apollo)
+#  if SFS_TYPE == SFS_4ARGS
        if (statfs(dir, &fs, sizeof fs, 0) == 0)
 #  else
 #   if defined(ultrix)
        if (statfs(dir, &fs, sizeof fs, 0) == 0)
 #  else
 #   if defined(ultrix)
@@ -1484,6 +1836,9 @@ transienterror(err)
 #ifdef EADDRNOTAVAIL
          case EADDRNOTAVAIL:           /* Can't assign requested address */
 #endif
 #ifdef EADDRNOTAVAIL
          case EADDRNOTAVAIL:           /* Can't assign requested address */
 #endif
+#ifdef ETXTBSY
+         case ETXTBSY:                 /* (Apollo) file locked */
+#endif
 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
          case ENOSR:                   /* Out of streams resources */
 #endif
 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
          case ENOSR:                   /* Out of streams resources */
 #endif
@@ -1516,7 +1871,7 @@ lockfile(fd, filename, ext, type)
        char *ext;
        int type;
 {
        char *ext;
        int type;
 {
-# ifndef HASFLOCK
+# if !HASFLOCK
        int action;
        struct flock lfd;
 
        int action;
        struct flock lfd;
 
@@ -1567,8 +1922,17 @@ lockfile(fd, filename, ext, type)
        }
 
        if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
        }
 
        if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
-               syserr("cannot lockf(%s%s, fd=%d, type=%o)",
-                       filename, ext, fd, type);
+       {
+               int omode = -1;
+#  ifdef F_GETFL
+               int oerrno = errno;
+
+               (void) fcntl(fd, F_GETFL, &omode);
+               errno = oerrno;
+#  endif
+               syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
+                       filename, ext, fd, type, omode, geteuid());
+       }
 # else
        if (ext == NULL)
                ext = "";
 # else
        if (ext == NULL)
                ext = "";
@@ -1587,10 +1951,427 @@ lockfile(fd, filename, ext, type)
                printf("(%s) ", errstring(errno));
 
        if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
                printf("(%s) ", errstring(errno));
 
        if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
-               syserr("cannot flock(%s%s, fd=%d, type=%o)",
-                       filename, ext, fd, type);
+       {
+               int omode = -1;
+#  ifdef F_GETFL
+               int oerrno = errno;
+
+               (void) fcntl(fd, F_GETFL, &omode);
+               errno = oerrno;
+#  endif
+               syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
+                       filename, ext, fd, type, omode, geteuid());
+       }
 # endif
        if (tTd(55, 60))
                printf("FAIL\n");
        return FALSE;
 }
 # endif
        if (tTd(55, 60))
                printf("FAIL\n");
        return FALSE;
 }
+\f/*
+**  CHOWNSAFE -- tell if chown is "safe" (executable only by root)
+**
+**     Parameters:
+**             fd -- the file descriptor to check.
+**
+**     Returns:
+**             TRUE -- if only root can chown the file to an arbitrary
+**                     user.
+**             FALSE -- if an arbitrary user can give away a file.
+*/
+
+bool
+chownsafe(fd)
+       int fd;
+{
+#ifdef __hpux
+       char *s;
+       int tfd;
+       uid_t o_uid, o_euid;
+       gid_t o_gid, o_egid;
+       bool rval;
+       struct stat stbuf;
+
+       o_uid = getuid();
+       o_euid = geteuid();
+       o_gid = getgid();
+       o_egid = getegid();
+       fstat(fd, &stbuf);
+       setresuid(stbuf.st_uid, stbuf.st_uid, -1);
+       setresgid(stbuf.st_gid, stbuf.st_gid, -1);
+       s = tmpnam(NULL);
+       tfd = open(s, O_RDONLY|O_CREAT, 0600);
+       rval = fchown(tfd, DefUid, DefGid) != 0;
+       close(tfd);
+       unlink(s);
+       setreuid(o_uid, o_euid);
+       setresgid(o_gid, o_egid, -1);
+       return rval;
+#else
+# ifdef _POSIX_CHOWN_RESTRICTED
+#  if _POSIX_CHOWN_RESTRICTED == -1
+       return FALSE;
+#  else
+       return TRUE;
+#  endif
+# else
+#  ifdef _PC_CHOWN_RESTRICTED
+       return fpathconf(fd, _PC_CHOWN_RESTRICTED) > 0;
+#  else
+#   ifdef BSD
+       return TRUE;
+#   else
+       return FALSE;
+#   endif
+#  endif
+# endif
+#endif
+}
+\f/*
+**  GETCFNAME -- return the name of the .cf file.
+**
+**     Some systems (e.g., NeXT) determine this dynamically.
+*/
+
+char *
+getcfname()
+{
+       if (ConfFile != NULL)
+               return ConfFile;
+#ifdef NETINFO
+       {
+               extern char *ni_propval();
+               char *cflocation;
+
+               cflocation = ni_propval("/locations/sendmail", "sendmail.cf");
+               if (cflocation != NULL)
+                       return cflocation;
+       }
+#endif
+       return _PATH_SENDMAILCF;
+}
+\f/*
+**  SETVENDOR -- process vendor code from V configuration line
+**
+**     Parameters:
+**             vendor -- string representation of vendor.
+**
+**     Returns:
+**             TRUE -- if ok.
+**             FALSE -- if vendor code could not be processed.
+**
+**     Side Effects:
+**             It is reasonable to set mode flags here to tweak
+**             processing in other parts of the code if necessary.
+**             For example, if you are a vendor that uses $%y to
+**             indicate YP lookups, you could enable that here.
+*/
+
+bool
+setvendor(vendor)
+       char *vendor;
+{
+       if (strcasecmp(vendor, "Berkeley") == 0)
+               return TRUE;
+
+       /* add vendor extensions here */
+
+       return FALSE;
+}
+\f/*
+**  STRTOL -- convert string to long integer
+**
+**     For systems that don't have it in the C library.
+**
+**     This is taken verbatim from the 4.4-Lite C library.
+*/
+
+#ifdef NEEDSTRTOL
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c   8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+
+long
+strtol(nptr, endptr, base)
+       const char *nptr;
+       char **endptr;
+       register int base;
+{
+       register const char *s = nptr;
+       register unsigned long acc;
+       register int c;
+       register unsigned long cutoff;
+       register int neg = 0, any, cutlim;
+
+       /*
+        * Skip white space and pick up leading +/- sign if any.
+        * If base is 0, allow 0x for hex and 0 for octal, else
+        * assume decimal; if base is already 16, allow 0x.
+        */
+       do {
+               c = *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else if (c == '+')
+               c = *s++;
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       /*
+        * Compute the cutoff value between legal numbers and illegal
+        * numbers.  That is the largest legal value, divided by the
+        * base.  An input number that is greater than this value, if
+        * followed by a legal input character, is too big.  One that
+        * is equal to this value may be valid or not; the limit
+        * between valid and invalid numbers is then based on the last
+        * digit.  For instance, if the range for longs is
+        * [-2147483648..2147483647] and the input base is 10,
+        * cutoff will be set to 214748364 and cutlim to either
+        * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+        * a value > 214748364, or equal but the next digit is > 7 (or 8),
+        * the number is too big, and we will return a range error.
+        *
+        * Set any if any `digits' consumed; make it negative to indicate
+        * overflow.
+        */
+       cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+       cutlim = cutoff % (unsigned long)base;
+       cutoff /= (unsigned long)base;
+       for (acc = 0, any = 0;; c = *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+                       any = -1;
+               else {
+                       any = 1;
+                       acc *= base;
+                       acc += c;
+               }
+       }
+       if (any < 0) {
+               acc = neg ? LONG_MIN : LONG_MAX;
+               errno = ERANGE;
+       } else if (neg)
+               acc = -acc;
+       if (endptr != 0)
+               *endptr = (char *)(any ? s - 1 : nptr);
+       return (acc);
+}
+
+#endif
+\f/*
+**  SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
+**
+**     Solaris versions prior through 2.3 don't properly deliver a
+**     canonical h_name field.  This tries to work around it.
+*/
+
+#ifdef SOLARIS
+
+struct hostent *
+solaris_gethostbyname(name)
+       const char *name;
+{
+# ifdef SOLARIS_2_3
+       static struct hostent hp;
+       static char buf[1000];
+       extern struct hostent *_switch_gethostbyname_r();
+
+       return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
+# else
+       extern struct hostent *__switch_gethostbyname();
+
+       return __switch_gethostbyname(name);
+# endif
+}
+
+struct hostent *
+solaris_gethostbyaddr(addr, len, type)
+       const char *addr;
+       int len;
+       int type;
+{
+# ifdef SOLARIS_2_3
+       static struct hostent hp;
+       static char buf[1000];
+       extern struct hostent *_switch_gethostbyaddr_r();
+
+       return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
+# else
+       extern struct hostent *__switch_gethostbyaddr();
+
+       return __switch_gethostbyaddr(addr, len, type);
+# endif
+}
+
+#endif
+\f/*
+**  NI_PROPVAL -- netinfo property value lookup routine
+**
+**     Parameters:
+**             directory -- the Netinfo directory name.
+**             propname -- the Netinfo property name.
+**
+**     Returns:
+**             NULL -- if:
+**                     1. the directory is not found
+**                     2. the property name is not found
+**                     3. the property contains multiple values
+**                     4. some error occured
+**             else -- the location of the config file.
+**
+**     Notes:
+**             Caller should free the return value of ni_proval
+*/
+
+#ifdef NETINFO
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN    "."
+# define PARENT_NETINFO_DOMAIN   ".."
+# define MAX_NI_LEVELS           256
+
+char *
+ni_propval(directory, propname)
+       char *directory;
+       char *propname;
+{
+       char *propval = NULL;
+       int i;
+       void *ni = NULL;
+       void *lastni = NULL;
+       ni_status nis;
+       ni_id nid;
+       ni_namelist ninl;
+
+       /*
+       **  If the passed directory and property name are found
+       **  in one of netinfo domains we need to search (starting
+       **  from the local domain moving all the way back to the
+       **  root domain) set propval to the property's value
+       **  and return it.
+       */
+
+       for (i = 0; i < MAX_NI_LEVELS; ++i)
+       {
+               if (i == 0)
+               {
+                       nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+               }
+               else
+               {
+                       if (lastni != NULL)
+                               ni_free(lastni);
+                       lastni = ni;
+                       nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+               }
+
+               /*
+               **  Don't bother if we didn't get a handle on a
+               **  proper domain.  This is not necessarily an error.
+               **  We would get a positive ni_status if, for instance
+               **  we never found the directory or property and tried
+               **  to open the parent of the root domain!
+               */
+
+               if (nis != 0)
+                       break;
+
+               /*
+               **  Find the path to the server information.
+               */
+
+               if (ni_pathsearch(ni, &nid, directory) != 0)
+                       continue;
+
+               /*
+               **  Find "host" information.
+               */
+
+               if (ni_lookupprop(ni, &nid, propname, &ninl) != 0)
+                       continue;
+
+               /*
+               **  If there's only one name in
+               **  the list, assume we've got
+               **  what we want.
+               */
+
+               if (ninl.ni_namelist_len == 1)
+               {
+                       propval = ni_name_dup(ninl.ni_namelist_val[0]);
+                       break;
+               }
+       }
+
+       /*
+       **  Clean up.
+       */
+
+       if (ni != NULL)
+               ni_free(ni);
+       if (lastni != NULL && ni != lastni)
+               ni_free(lastni);
+
+       return propval;
+}
+
+#endif /* NETINFO */
+\f/*
+**  HARD_SYSLOG -- call syslog repeatedly until it works
+**
+**     Needed on HP-UX, which apparently doesn't guarantee that
+**     syslog succeeds during interrupt handlers.
+*/
+
+#ifdef __hpux
+
+# define MAXSYSLOGTRIES        100
+# undef syslog
+
+# ifdef __STDC__
+hard_syslog(int pri, char *msg, ...)
+# else
+hard_syslog(pri, msg, va_alist)
+       int pri;
+       char *msg;
+       va_dcl
+# endif
+{
+       int i;
+       char buf[SYSLOG_BUFSIZE * 2];
+       VA_LOCAL_DECL;
+
+       VA_START(msg);
+       vsprintf(buf, msg, ap);
+       VA_END;
+
+       for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; )
+               continue;
+}
+
+#endif