summaryrefslogtreecommitdiffstats
path: root/usr.sbin/sendmail/src/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sendmail/src/conf.c')
-rw-r--r--usr.sbin/sendmail/src/conf.c2377
1 files changed, 2377 insertions, 0 deletions
diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c
new file mode 100644
index 0000000..4ac109a
--- /dev/null
+++ b/usr.sbin/sendmail/src/conf.c
@@ -0,0 +1,2377 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)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>
+# include <netdb.h>
+# include <pwd.h>
+
+/*
+** CONF.C -- Sendmail Configuration Tables.
+**
+** Defines the configuration of this installation.
+**
+** Configuration Variables:
+** HdrInfo -- a table describing well-known header fields.
+** Each entry has the field name and some flags,
+** which are described in sendmail.h.
+**
+** Notes:
+** I have tried to put almost all the reasonable
+** configuration information into the configuration
+** file read at runtime. My intent is that anything
+** here is a function of the version of UNIX you
+** are running, or is really static -- for example
+** the headers are a superset of widely used
+** protocols. If you find yourself playing with
+** this file too much, you may be making a mistake!
+*/
+
+
+
+
+/*
+** Header info table
+** Final (null) entry contains the flags used for any other field.
+**
+** Not all of these are actually handled specially by sendmail
+** at this time. They are included as placeholders, to let
+** you know that "someday" I intend to have sendmail do
+** something with them.
+*/
+
+struct hdrinfo HdrInfo[] =
+{
+ /* originator fields, most to least significant */
+ "resent-sender", H_FROM|H_RESENT,
+ "resent-from", H_FROM|H_RESENT,
+ "resent-reply-to", H_FROM|H_RESENT,
+ "sender", H_FROM,
+ "from", H_FROM,
+ "reply-to", H_FROM,
+ "full-name", H_ACHECK,
+ "return-receipt-to", H_FROM|H_RECEIPTTO,
+ "errors-to", H_FROM|H_ERRORSTO,
+
+ /* destination fields */
+ "to", H_RCPT,
+ "resent-to", H_RCPT|H_RESENT,
+ "cc", H_RCPT,
+ "resent-cc", H_RCPT|H_RESENT,
+ "bcc", H_RCPT|H_ACHECK,
+ "resent-bcc", H_RCPT|H_ACHECK|H_RESENT,
+ "apparently-to", H_RCPT,
+
+ /* message identification and control */
+ "message-id", 0,
+ "resent-message-id", H_RESENT,
+ "message", H_EOH,
+ "text", H_EOH,
+
+ /* date fields */
+ "date", 0,
+ "resent-date", H_RESENT,
+
+ /* trace fields */
+ "received", H_TRACE|H_FORCE,
+ "x400-received", H_TRACE|H_FORCE,
+ "via", H_TRACE|H_FORCE,
+ "mail-from", H_TRACE|H_FORCE,
+
+ /* miscellaneous fields */
+ "comments", H_FORCE,
+ "return-path", H_FORCE|H_ACHECK,
+
+ NULL, 0,
+};
+
+
+
+/*
+** Location of system files/databases/etc.
+*/
+
+char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */
+
+
+
+/*
+** Privacy values
+*/
+
+struct prival PrivacyValues[] =
+{
+ "public", PRIV_PUBLIC,
+ "needmailhelo", PRIV_NEEDMAILHELO,
+ "needexpnhelo", PRIV_NEEDEXPNHELO,
+ "needvrfyhelo", PRIV_NEEDVRFYHELO,
+ "noexpn", PRIV_NOEXPN,
+ "novrfy", PRIV_NOVRFY,
+ "restrictmailq", PRIV_RESTRICTMAILQ,
+ "restrictqrun", PRIV_RESTRICTQRUN,
+ "authwarnings", PRIV_AUTHWARNINGS,
+ "noreceipts", PRIV_NORECEIPTS,
+ "goaway", PRIV_GOAWAY,
+ NULL, 0,
+};
+
+
+
+/*
+** Miscellaneous stuff.
+*/
+
+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
+
+ /*
+** SETDEFAULTS -- set default values
+**
+** Because of the way freezing is done, these must be initialized
+** using direct code.
+**
+** Parameters:
+** e -- the default envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Initializes a bunch of global variables to their
+** default values.
+*/
+
+#define DAYS * 24 * 60 * 60
+
+setdefaults(e)
+ register ENVELOPE *e;
+{
+ SpaceSub = ' '; /* option B */
+ QueueLA = 8; /* option x */
+ RefuseLA = 12; /* option X */
+ WkRecipFact = 30000L; /* option y */
+ WkClassFact = 1800L; /* option z */
+ WkTimeFact = 90000L; /* option Z */
+ QueueFactor = WkRecipFact * 20; /* option q */
+ FileMode = (RealUid != geteuid()) ? 0644 : 0600;
+ /* option F */
+ DefUid = 1; /* option u */
+ DefGid = 1; /* option g */
+ CheckpointInterval = 10; /* option C */
+ MaxHopCount = 25; /* option h */
+ e->e_sendmode = SM_FORK; /* option d */
+ e->e_errormode = EM_PRINT; /* option e */
+ SevenBit = FALSE; /* option 7 */
+ MaxMciCache = 1; /* option k */
+ MciCacheTimeout = 300; /* option K */
+ LogLevel = 9; /* option L */
+ settimeouts(NULL); /* option r */
+ TimeOuts.to_q_return = 5 DAYS; /* option T */
+ TimeOuts.to_q_warning = 0; /* option T */
+ PrivacyFlags = 0; /* option p */
+ setdefuser();
+ setupmaps();
+ setupmailers();
+}
+
+
+/*
+** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
+*/
+
+setdefuser()
+{
+ struct passwd *defpwent;
+ static char defuserbuf[40];
+
+ DefUser = defuserbuf;
+ if ((defpwent = getpwuid(DefUid)) != NULL)
+ strcpy(defuserbuf, defpwent->pw_name);
+ else
+ strcpy(defuserbuf, "nobody");
+}
+ /*
+** HOST_MAP_INIT -- initialize host class structures
+*/
+
+bool
+host_map_init(map, args)
+ MAP *map;
+ char *args;
+{
+ register char *p = args;
+
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'a':
+ map->map_app = ++p;
+ break;
+ }
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ if (map->map_app != NULL)
+ map->map_app = newstr(map->map_app);
+ return TRUE;
+}
+ /*
+** SETUPMAILERS -- initialize default mailers
+*/
+
+setupmailers()
+{
+ char buf[100];
+
+ strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
+ makemailer(buf);
+
+ strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE");
+ makemailer(buf);
+
+ strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
+ makemailer(buf);
+}
+ /*
+** SETUPMAPS -- set up map classes
+*/
+
+#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
+ { \
+ extern bool parse __P((MAP *, char *)); \
+ extern bool open __P((MAP *, int)); \
+ extern void close __P((MAP *)); \
+ extern char *lookup __P((MAP *, char *, char **, int *)); \
+ extern void store __P((MAP *, char *, char *)); \
+ s = stab(name, ST_MAPCLASS, ST_ENTER); \
+ s->s_mapclass.map_cname = name; \
+ s->s_mapclass.map_ext = ext; \
+ s->s_mapclass.map_cflags = flags; \
+ s->s_mapclass.map_parse = parse; \
+ s->s_mapclass.map_open = open; \
+ s->s_mapclass.map_close = close; \
+ s->s_mapclass.map_lookup = lookup; \
+ s->s_mapclass.map_store = store; \
+ }
+
+setupmaps()
+{
+ register STAB *s;
+
+#ifdef NEWDB
+ MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, hash_map_open, db_map_close,
+ db_map_lookup, db_map_store);
+ MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, bt_map_open, db_map_close,
+ db_map_lookup, db_map_store);
+#endif
+
+#ifdef NDBM
+ MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, ndbm_map_open, ndbm_map_close,
+ ndbm_map_lookup, ndbm_map_store);
+#endif
+
+#ifdef NIS
+ MAPDEF("nis", NULL, MCF_ALIASOK,
+ map_parseargs, nis_map_open, nis_map_close,
+ nis_map_lookup, nis_map_store);
+#endif
+
+ MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
+ map_parseargs, stab_map_open, stab_map_close,
+ stab_map_lookup, stab_map_store);
+
+ MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
+ map_parseargs, impl_map_open, impl_map_close,
+ impl_map_lookup, impl_map_store);
+
+ /* host DNS lookup */
+ MAPDEF("host", NULL, 0,
+ host_map_init, null_map_open, null_map_close,
+ host_map_lookup, null_map_store);
+
+ /* dequote map */
+ MAPDEF("dequote", NULL, 0,
+ dequote_init, null_map_open, null_map_close,
+ dequote_map, null_map_store);
+
+#if 0
+# ifdef USERDB
+ /* user database */
+ MAPDEF("udb", ".db", 0,
+ udb_map_parse, null_map_open, null_map_close,
+ udb_map_lookup, null_map_store);
+# endif
+#endif
+}
+
+#undef MAPDEF
+ /*
+** USERNAME -- return the user id of the logged in user.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** The login name of the logged in user.
+**
+** Side Effects:
+** none.
+**
+** Notes:
+** The return value is statically allocated.
+*/
+
+char *
+username()
+{
+ static char *myname = NULL;
+ extern char *getlogin();
+ register struct passwd *pw;
+
+ /* cache the result */
+ if (myname == NULL)
+ {
+ myname = getlogin();
+ if (myname == NULL || myname[0] == '\0')
+ {
+ pw = getpwuid(RealUid);
+ if (pw != NULL)
+ myname = newstr(pw->pw_name);
+ }
+ else
+ {
+ uid_t uid = RealUid;
+
+ myname = newstr(myname);
+ if ((pw = getpwnam(myname)) == NULL ||
+ (uid != 0 && uid != pw->pw_uid))
+ {
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ myname = newstr(pw->pw_name);
+ }
+ }
+ if (myname == NULL || myname[0] == '\0')
+ {
+ syserr("554 Who are you?");
+ myname = "postmaster";
+ }
+ }
+
+ return (myname);
+}
+ /*
+** TTYPATH -- Get the path of the user's tty
+**
+** Returns the pathname of the user's tty. Returns NULL if
+** the user is not logged in or if s/he has write permission
+** denied.
+**
+** Parameters:
+** none
+**
+** Returns:
+** pathname of the user's tty.
+** NULL if not logged in or write permission denied.
+**
+** Side Effects:
+** none.
+**
+** WARNING:
+** Return value is in a local buffer.
+**
+** Called By:
+** savemail
+*/
+
+char *
+ttypath()
+{
+ struct stat stbuf;
+ register char *pathn;
+ extern char *ttyname();
+ extern char *getlogin();
+
+ /* compute the pathname of the controlling tty */
+ if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
+ (pathn = ttyname(0)) == NULL)
+ {
+ errno = 0;
+ return (NULL);
+ }
+
+ /* see if we have write permission */
+ if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
+ {
+ errno = 0;
+ return (NULL);
+ }
+
+ /* see if the user is logged in */
+ if (getlogin() == NULL)
+ return (NULL);
+
+ /* looks good */
+ return (pathn);
+}
+ /*
+** CHECKCOMPAT -- check for From and To person compatible.
+**
+** This routine can be supplied on a per-installation basis
+** to determine whether a person is allowed to send a message.
+** This allows restriction of certain types of internet
+** forwarding or registration of users.
+**
+** If the hosts are found to be incompatible, an error
+** message should be given using "usrerr" and 0 should
+** be returned.
+**
+** 'NoReturn' can be set to suppress the return-to-sender
+** function; this should be done on huge messages.
+**
+** Parameters:
+** to -- the person being sent to.
+**
+** Returns:
+** an exit status
+**
+** Side Effects:
+** none (unless you include the usrerr stuff)
+*/
+
+checkcompat(to, e)
+ register ADDRESS *to;
+ register ENVELOPE *e;
+{
+# ifdef 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;
+
+ s = stab("arpa", ST_MAILER, ST_FIND);
+ if (s != NULL && e->e_from.q_mailer != LocalMailer &&
+ to->q_mailer == s->s_mailer)
+ {
+ usrerr("553 No ARPA mail through this machine: see your system administration");
+ /* NoReturn = TRUE; to supress return copy */
+ return (EX_UNAVAILABLE);
+ }
+# endif /* EXAMPLE_CODE */
+ return (EX_OK);
+}
+ /*
+** SETSIGNAL -- set a signal handler
+**
+** This is essentially old BSD "signal(3)".
+*/
+
+sigfunc_t
+setsignal(sig, handler)
+ int sig;
+ sigfunc_t handler;
+{
+#if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
+ return signal(sig, handler);
+#else
+ struct sigaction n, o;
+
+ bzero(&n, sizeof n);
+ n.sa_handler = handler;
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+#endif
+}
+ /*
+** HOLDSIGS -- arrange to hold all signals
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Arranges that signals are held.
+*/
+
+holdsigs()
+{
+}
+ /*
+** RLSESIGS -- arrange to release all signals
+**
+** This undoes the effect of holdsigs.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Arranges that signals are released.
+*/
+
+rlsesigs()
+{
+}
+ /*
+** 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
+}
+ /*
+** GETLA -- get the current load average
+**
+** This code stolen from la.c.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** The current load average as an integer.
+**
+** Side Effects:
+** none.
+*/
+
+/* try to guess what style of load average we have */
+#define LA_ZERO 1 /* always return load average as zero */
+#define LA_INT 2 /* read kmem for avenrun; interpret as long */
+#define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
+#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
+# define LA_TYPE LA_ZERO
+#endif
+
+#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
+
+#include <nlist.h>
+
+#ifndef LA_AVENRUN
+# ifdef SYSTEM5
+# define LA_AVENRUN "avenrun"
+# else
+# define LA_AVENRUN "_avenrun"
+# endif
+#endif
+
+/* _PATH_UNIX should be defined in <paths.h> */
+#ifndef _PATH_UNIX
+# if defined(SYSTEM5)
+# define _PATH_UNIX "/unix"
+# else
+# define _PATH_UNIX "/vmunix"
+# endif
+#endif
+
+struct nlist Nl[] =
+{
+ { LA_AVENRUN },
+#define X_AVENRUN 0
+ { 0 },
+};
+
+#ifndef FSHIFT
+# if defined(unixpc)
+# define FSHIFT 5
+# endif
+
+# if defined(__alpha) || defined(IRIX)
+# define FSHIFT 10
+# endif
+#endif
+
+#ifndef FSHIFT
+# define FSHIFT 8
+#endif
+
+#ifndef FSCALE
+# define FSCALE (1 << FSHIFT)
+#endif
+
+getla()
+{
+ static int kmem = -1;
+#if LA_TYPE == LA_INT
+ long avenrun[3];
+#else
+# if LA_TYPE == LA_SHORT
+ short avenrun[3];
+# else
+ double avenrun[3];
+# endif
+#endif
+ extern off_t lseek();
+ extern int errno;
+
+ if (kmem < 0)
+ {
+ kmem = open("/dev/kmem", 0, 0);
+ if (kmem < 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: open(/dev/kmem): %s\n",
+ errstring(errno));
+ return (-1);
+ }
+ (void) fcntl(kmem, F_SETFD, 1);
+ if (nlist(_PATH_UNIX, Nl) < 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: nlist(%s): %s\n", _PATH_UNIX,
+ errstring(errno));
+ return (-1);
+ }
+ if (Nl[X_AVENRUN].n_value == 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: nlist(%s, %s) ==> 0\n",
+ _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 (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
+ read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
+ {
+ /* thank you Ian */
+ if (tTd(3, 1))
+ printf("getla: lseek or read: %s\n", errstring(errno));
+ return (-1);
+ }
+#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
+ if (tTd(3, 5))
+ {
+ printf("getla: avenrun = %d", avenrun[0]);
+ if (tTd(3, 15))
+ printf(", %d, %d", avenrun[1], avenrun[2]);
+ printf("\n");
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
+ return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
+#else
+ if (tTd(3, 5))
+ {
+ printf("getla: avenrun = %g", avenrun[0]);
+ if (tTd(3, 15))
+ printf(", %g, %g", avenrun[1], avenrun[2]);
+ printf("\n");
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] +0.5));
+ return ((int) (avenrun[0] + 0.5));
+#endif
+}
+
+#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];
+
+ if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
+ {
+ if (tTd(3, 1))
+ perror("getla: getloadavg failed:");
+ return (-1);
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] +0.5));
+ return ((int) (avenrun[0] + 0.5));
+}
+
+#endif /* DGUX */
+#else
+#if LA_TYPE == LA_MACH
+
+/*
+** This has been tested on NEXTSTEP release 2.1/3.X.
+*/
+
+#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()
+{
+ processor_set_t default_set;
+ kern_return_t error;
+ unsigned int info_count;
+ struct processor_set_basic_info info;
+ host_t host;
+
+ error = processor_set_default(host_self(), &default_set);
+ if (error != KERN_SUCCESS)
+ return -1;
+ info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
+ if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
+ &host, (processor_set_info_t)&info,
+ &info_count) != KERN_SUCCESS)
+ {
+ return -1;
+ }
+ return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
+}
+
+
+#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()
+{
+ if (tTd(3, 1))
+ printf("getla: ZERO\n");
+ return (0);
+}
+
+#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 */
+ /*
+** SHOULDQUEUE -- should this message be queued or sent?
+**
+** Compares the message cost to the load average to decide.
+**
+** Parameters:
+** pri -- the priority of the message in question.
+** ctime -- the message creation time.
+**
+** Returns:
+** TRUE -- if this message should be queued up for the
+** time being.
+** FALSE -- if the load is low enough to send this message.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+shouldqueue(pri, ctime)
+ long pri;
+ time_t ctime;
+{
+ if (CurrentLA < QueueLA)
+ return (FALSE);
+ if (CurrentLA >= RefuseLA)
+ return (TRUE);
+ return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
+}
+ /*
+** REFUSECONNECTIONS -- decide if connections should be refused
+**
+** Parameters:
+** none.
+**
+** Returns:
+** TRUE if incoming SMTP connections should be refused
+** (for now).
+** FALSE if we should accept new work.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+refuseconnections()
+{
+#ifdef XLA
+ if (!xla_smtp_ok())
+ return TRUE;
+#endif
+
+ /* this is probably too simplistic */
+ return (CurrentLA >= RefuseLA);
+}
+ /*
+** SETPROCTITLE -- set process title for ps
+**
+** Parameters:
+** fmt -- a printf style format string.
+** a, b, c -- possible parameters to fmt.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Clobbers argv of our main procedure so ps(1) will
+** display the title.
+*/
+
+#ifdef SETPROCTITLE
+# ifdef HASSETPROCTITLE
+ *** ERROR *** Cannot have both SETPROCTITLE and HASSETPROCTITLE defined
+# endif
+# ifdef __hpux
+# include <sys/pstat.h>
+# endif
+# ifdef BSD4_4
+# include <machine/vmparam.h>
+# 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
+# endif
+# ifndef SETPROC_STATIC
+# define SETPROC_STATIC
+# endif
+#endif
+
+#ifndef PROCTITLEPAD
+# define PROCTITLEPAD ' '
+#endif
+
+#ifndef HASSETPROCTITLE
+
+/*VARARGS1*/
+#ifdef __STDC__
+setproctitle(char *fmt, ...)
+#else
+setproctitle(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+# ifdef SETPROCTITLE
+ register char *p;
+ register int i;
+ SETPROC_STATIC char buf[MAXLINE];
+ VA_LOCAL_DECL
+# ifdef __hpux
+ union pstun pst;
+# endif
+ extern char **Argv;
+ extern char *LastArgv;
+
+ p = buf;
+
+ /* print sendmail: heading for grep */
+ (void) strcpy(p, "sendmail: ");
+ p += strlen(p);
+
+ /* print the argument string */
+ VA_START(fmt);
+ (void) vsprintf(p, fmt, ap);
+ VA_END;
+
+ 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;
+ buf[i] = '\0';
+ }
+ (void) strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while (p < LastArgv)
+ *p++ = PROCTITLEPAD;
+# endif
+# endif
+# endif /* SETPROCTITLE */
+}
+
+#endif
+ /*
+** REAPCHILD -- pick up the body of my child, lest it become a zombie
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Picks up extant zombies.
+*/
+
+void
+reapchild()
+{
+ int olderrno = errno;
+# ifdef HASWAITPID
+ auto int status;
+ int count;
+ int pid;
+
+ count = 0;
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ if (count++ > 1000)
+ {
+#ifdef LOG
+ syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
+ pid, status);
+#endif
+ break;
+ }
+ }
+# else
+# ifdef WNOHANG
+ union wait status;
+
+ while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
+ continue;
+# else /* WNOHANG */
+ auto int status;
+
+ while (wait(&status) > 0)
+ continue;
+# endif /* WNOHANG */
+# endif
+# ifdef SYS5SIGNALS
+ (void) setsignal(SIGCHLD, reapchild);
+# endif
+ errno = olderrno;
+}
+ /*
+** UNSETENV -- remove a variable from the environment
+**
+** Not needed on newer systems.
+**
+** Parameters:
+** name -- the string name of the environment variable to be
+** deleted from the current environment.
+**
+** Returns:
+** none.
+**
+** Globals:
+** environ -- a pointer to the current environment.
+**
+** Side Effects:
+** Modifies environ.
+*/
+
+#ifndef HASUNSETENV
+
+void
+unsetenv(name)
+ char *name;
+{
+ extern char **environ;
+ register char **pp;
+ int len = strlen(name);
+
+ for (pp = environ; *pp != NULL; pp++)
+ {
+ if (strncmp(name, *pp, len) == 0 &&
+ ((*pp)[len] == '=' || (*pp)[len] == '\0'))
+ break;
+ }
+
+ for (; *pp != NULL; pp++)
+ *pp = pp[1];
+}
+
+#endif
+ /*
+** GETDTABLESIZE -- return number of file descriptors
+**
+** Only on non-BSD systems
+**
+** Parameters:
+** none
+**
+** Returns:
+** size of file descriptor table
+**
+** Side Effects:
+** none
+*/
+
+#ifdef SOLARIS
+# include <sys/resource.h>
+#endif
+
+int
+getdtsize()
+{
+#ifdef RLIMIT_NOFILE
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
+ return rl.rlim_cur;
+#endif
+
+# ifdef HASGETDTABLESIZE
+ return getdtablesize();
+# else
+# ifdef _SC_OPEN_MAX
+ return sysconf(_SC_OPEN_MAX);
+# else
+ return NOFILE;
+# endif
+# endif
+}
+ /*
+** UNAME -- get the UUCP name of this system.
+*/
+
+#ifndef HASUNAME
+
+int
+uname(name)
+ struct utsname *name;
+{
+ FILE *file;
+ char *n;
+
+ name->nodename[0] = '\0';
+
+ /* try /etc/whoami -- one line with the node name */
+ if ((file = fopen("/etc/whoami", "r")) != NULL)
+ {
+ (void) fgets(name->nodename, NODE_LENGTH + 1, file);
+ (void) fclose(file);
+ n = strchr(name->nodename, '\n');
+ if (n != NULL)
+ *n = '\0';
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+
+ /* try /usr/include/whoami.h -- has a #define somewhere */
+ if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
+ {
+ char buf[MAXLINE];
+
+ while (fgets(buf, MAXLINE, file) != NULL)
+ if (sscanf(buf, "#define sysname \"%*[^\"]\"",
+ NODE_LENGTH, name->nodename) > 0)
+ break;
+ (void) fclose(file);
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+
+#ifdef TRUST_POPEN
+ /*
+ ** Popen is known to have security holes.
+ */
+
+ /* try uuname -l to return local name */
+ if ((file = popen("uuname -l", "r")) != NULL)
+ {
+ (void) fgets(name, NODE_LENGTH + 1, file);
+ (void) pclose(file);
+ n = strchr(name, '\n');
+ if (n != NULL)
+ *n = '\0';
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+#endif
+
+ return (-1);
+}
+#endif /* HASUNAME */
+ /*
+** INITGROUPS -- initialize groups
+**
+** Stub implementation for System V style systems
+*/
+
+#ifndef HASINITGROUPS
+
+initgroups(name, basegid)
+ char *name;
+ int basegid;
+{
+ return 0;
+}
+
+#endif
+ /*
+** SETSID -- set session id (for non-POSIX systems)
+*/
+
+#ifndef HASSETSID
+
+pid_t
+setsid __P ((void))
+{
+#ifdef TIOCNOTTY
+ int fd;
+
+ fd = open("/dev/tty", O_RDWR, 0);
+ if (fd >= 0)
+ {
+ (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
+ (void) close(fd);
+ }
+#endif /* TIOCNOTTY */
+# ifdef SYS5SETPGRP
+ return setpgrp();
+# else
+ return setpgid(0, getpid());
+# endif
+}
+
+#endif
+ /*
+** 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
+ /*
+** 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
+ /*
+** GETOPT -- for old systems or systems with bogus implementations
+*/
+
+#ifdef NEEDGETOPT
+
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+
+/*
+** this version hacked to add `atend' flag to allow state machine
+** to reset if invoked by the program to scan args for a 2nd time
+*/
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+/*
+ * get option letter from argument vector
+ */
+#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)'?'
+#define EMSG ""
+#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
+ fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
+
+getopt(nargc,nargv,ostr)
+ int nargc;
+ char *const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ static char atend = 0;
+ register char *oli; /* option letter list index */
+
+ if (atend) {
+ atend = 0;
+ place = EMSG;
+ }
+ if(!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
+ atend++;
+ return(EOF);
+ }
+ if (*place == '-') { /* found "--" */
+ ++optind;
+ atend++;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
+ if (!*place) ++optind;
+ tell(": illegal option -- ");
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place) ++optind;
+ }
+ else { /* need an argument */
+ if (*place) optarg = place; /* no white space */
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ tell(": option requires an argument -- ");
+ }
+ else optarg = nargv[optind]; /* white space */
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
+
+#endif
+ /*
+** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
+*/
+
+#ifdef NEEDVPRINTF
+
+#define MAXARG 16
+
+vfprintf(fp, fmt, ap)
+ FILE * fp;
+ char * fmt;
+ char ** ap;
+{
+ char * bp[MAXARG];
+ int i = 0;
+
+ while (*ap && i < MAXARG)
+ bp[i++] = *ap++;
+ fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
+ bp[4], bp[5], bp[6], bp[7],
+ bp[8], bp[9], bp[10], bp[11],
+ bp[12], bp[13], bp[14], bp[15]);
+}
+
+vsprintf(s, fmt, ap)
+ char * s;
+ char * fmt;
+ char ** ap;
+{
+ char * bp[MAXARG];
+ int i = 0;
+
+ while (*ap && i < MAXARG)
+ bp[i++] = *ap++;
+ sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
+ bp[4], bp[5], bp[6], bp[7],
+ bp[8], bp[9], bp[10], bp[11],
+ bp[12], bp[13], bp[14], bp[15]);
+}
+
+#endif
+ /*
+** 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
+}
+ /*
+** FREESPACE -- see how much free space is on the queue filesystem
+**
+** Only implemented if you have statfs.
+**
+** Parameters:
+** dir -- the directory in question.
+** bsize -- a variable into which the filesystem
+** block size is stored.
+**
+** Returns:
+** The number of bytes free on the queue filesystem.
+** -1 if the statfs call fails.
+**
+** Side effects:
+** Puts the filesystem block size into bsize.
+*/
+
+/* 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
+
+#if SFS_TYPE == SFS_USTAT
+# include <ustat.h>
+#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
+freespace(dir, bsize)
+ char *dir;
+ long *bsize;
+{
+#if SFS_TYPE != SFS_NONE
+# if SFS_TYPE == SFS_USTAT
+ struct ustat fs;
+ struct stat statbuf;
+# define FSBLOCKSIZE DEV_BSIZE
+# define f_bavail f_tfree
+# else
+# if defined(ultrix)
+ struct fs_data fs;
+# 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;
+# 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;
+
+# if SFS_TYPE == SFS_USTAT
+ if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
+# else
+# if SFS_TYPE == SFS_4ARGS
+ if (statfs(dir, &fs, sizeof fs, 0) == 0)
+# else
+# if defined(ultrix)
+ if (statfs(dir, &fs) > 0)
+# else
+ if (statfs(dir, &fs) == 0)
+# endif
+# endif
+# endif
+ {
+ if (bsize != NULL)
+ *bsize = FSBLOCKSIZE;
+ return (fs.f_bavail);
+ }
+#endif
+ return (-1);
+}
+ /*
+** ENOUGHSPACE -- check to see if there is enough free space on the queue fs
+**
+** Only implemented if you have statfs.
+**
+** Parameters:
+** msize -- the size to check against. If zero, we don't yet
+** know how big the message will be, so just check for
+** a "reasonable" amount.
+**
+** Returns:
+** TRUE if there is enough space.
+** FALSE otherwise.
+*/
+
+bool
+enoughspace(msize)
+ long msize;
+{
+ long bfree, bsize;
+
+ if (MinBlocksFree <= 0 && msize <= 0)
+ {
+ if (tTd(4, 80))
+ printf("enoughspace: no threshold\n");
+ return TRUE;
+ }
+
+ if ((bfree = freespace(QueueDir, &bsize)) >= 0)
+ {
+ if (tTd(4, 80))
+ printf("enoughspace: bavail=%ld, need=%ld\n",
+ bfree, msize);
+
+ /* convert msize to block count */
+ msize = msize / bsize + 1;
+ if (MinBlocksFree >= 0)
+ msize += MinBlocksFree;
+
+ if (bfree < msize)
+ {
+#ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_ALERT,
+ "%s: low on space (have %ld, %s needs %ld in %s)",
+ CurEnv->e_id, bfree,
+ CurHostName, msize, QueueDir);
+#endif
+ return FALSE;
+ }
+ }
+ else if (tTd(4, 80))
+ printf("enoughspace failure: min=%ld, need=%ld: %s\n",
+ MinBlocksFree, msize, errstring(errno));
+ return TRUE;
+}
+ /*
+** TRANSIENTERROR -- tell if an error code indicates a transient failure
+**
+** This looks at an errno value and tells if this is likely to
+** go away if retried later.
+**
+** Parameters:
+** err -- the errno code to classify.
+**
+** Returns:
+** TRUE if this is probably transient.
+** FALSE otherwise.
+*/
+
+bool
+transienterror(err)
+ int err;
+{
+ switch (err)
+ {
+ case EIO: /* I/O error */
+ case ENXIO: /* Device not configured */
+ case EAGAIN: /* Resource temporarily unavailable */
+ case ENOMEM: /* Cannot allocate memory */
+ case ENODEV: /* Operation not supported by device */
+ case ENFILE: /* Too many open files in system */
+ case EMFILE: /* Too many open files */
+ case ENOSPC: /* No space left on device */
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: /* Connection timed out */
+#endif
+#ifdef ESTALE
+ case ESTALE: /* Stale NFS file handle */
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: /* Network is down */
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: /* Network is unreachable */
+#endif
+#ifdef ENETRESET
+ case ENETRESET: /* Network dropped connection on reset */
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: /* Software caused connection abort */
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: /* Connection reset by peer */
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS: /* No buffer space available */
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: /* Can't send after socket shutdown */
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: /* Connection refused */
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: /* Host is down */
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: /* No route to host */
+#endif
+#ifdef EDQUOT
+ case EDQUOT: /* Disc quota exceeded */
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: /* Too many processes */
+#endif
+#ifdef EUSERS
+ case EUSERS: /* Too many users */
+#endif
+#ifdef EDEADLK
+ case EDEADLK: /* Resource deadlock avoided */
+#endif
+#ifdef EISCONN
+ case EISCONN: /* Socket already connected */
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: /* Operation now in progress */
+#endif
+#ifdef EALREADY
+ case EALREADY: /* Operation already in progress */
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: /* Address already in use */
+#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
+ return TRUE;
+ }
+
+ /* nope, must be permanent */
+ return FALSE;
+}
+ /*
+** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
+**
+** Parameters:
+** fd -- the file descriptor of the file.
+** filename -- the file name (for error messages).
+** ext -- the filename extension.
+** type -- type of the lock. Bits can be:
+** LOCK_EX -- exclusive lock.
+** LOCK_NB -- non-blocking.
+**
+** Returns:
+** TRUE if the lock was acquired.
+** FALSE otherwise.
+*/
+
+bool
+lockfile(fd, filename, ext, type)
+ int fd;
+ char *filename;
+ char *ext;
+ int type;
+{
+# if !HASFLOCK
+ int action;
+ struct flock lfd;
+
+ if (ext == NULL)
+ ext = "";
+
+ bzero(&lfd, sizeof lfd);
+ if (bitset(LOCK_UN, type))
+ lfd.l_type = F_UNLCK;
+ else if (bitset(LOCK_EX, type))
+ lfd.l_type = F_WRLCK;
+ else
+ lfd.l_type = F_RDLCK;
+
+ if (bitset(LOCK_NB, type))
+ action = F_SETLK;
+ else
+ action = F_SETLKW;
+
+ if (tTd(55, 60))
+ printf("lockfile(%s%s, action=%d, type=%d): ",
+ filename, ext, action, lfd.l_type);
+
+ if (fcntl(fd, action, &lfd) >= 0)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (tTd(55, 60))
+ printf("(%s) ", errstring(errno));
+
+ /*
+ ** On SunOS, if you are testing using -oQ/tmp/mqueue or
+ ** -oA/tmp/aliases or anything like that, and /tmp is mounted
+ ** as type "tmp" (that is, served from swap space), the
+ ** previous fcntl will fail with "Invalid argument" errors.
+ ** Since this is fairly common during testing, we will assume
+ ** that this indicates that the lock is successfully grabbed.
+ */
+
+ if (errno == EINVAL)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
+ {
+ 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 = "";
+
+ if (tTd(55, 60))
+ printf("lockfile(%s%s, type=%o): ", filename, ext, type);
+
+ if (flock(fd, type) >= 0)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (tTd(55, 60))
+ printf("(%s) ", errstring(errno));
+
+ if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
+ {
+ 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;
+}
+ /*
+** 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
+}
+ /*
+** 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;
+}
+ /*
+** 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;
+}
+ /*
+** 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
+ /*
+** 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
+ /*
+** 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 */
+ /*
+** 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
OpenPOWER on IntegriCloud