diff options
Diffstat (limited to 'usr.sbin/sendmail/src/conf.c')
| -rw-r--r-- | usr.sbin/sendmail/src/conf.c | 1239 |
1 files changed, 1101 insertions, 138 deletions
diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c index f87534803fd2..1a9646365b88 100644 --- a/usr.sbin/sendmail/src/conf.c +++ b/usr.sbin/sendmail/src/conf.c @@ -33,15 +33,15 @@ */ #ifndef lint -static char sccsid[] = "@(#)conf.c 8.3 (Berkeley) 7/13/93"; +static char sccsid[] = "@(#)conf.c 8.82 (Berkeley) 3/6/94"; #endif /* not lint */ +# include "sendmail.h" +# include "pathnames.h" # include <sys/ioctl.h> # include <sys/param.h> -# include <signal.h> +# include <netdb.h> # include <pwd.h> -# include "sendmail.h" -# include "pathnames.h" /* ** CONF.C -- Sendmail Configuration Tables. @@ -87,7 +87,7 @@ struct hdrinfo HdrInfo[] = "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 */ @@ -128,8 +128,6 @@ struct hdrinfo HdrInfo[] = ** Location of system files/databases/etc. */ -char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ -char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ @@ -146,7 +144,8 @@ struct prival PrivacyValues[] = "needvrfyhelo", PRIV_NEEDVRFYHELO, "noexpn", PRIV_NOEXPN, "novrfy", PRIV_NOVRFY, - "restrictmailq", PRIV_RESTRMAILQ, + "restrictmailq", PRIV_RESTRICTMAILQ, + "restrictqrun", PRIV_RESTRICTQRUN, "authwarnings", PRIV_AUTHWARNINGS, "goaway", PRIV_GOAWAY, NULL, 0, @@ -159,6 +158,25 @@ struct prival PrivacyValues[] = */ 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 ** @@ -491,7 +509,12 @@ checkcompat(to, e) # ifdef lint if (to == NULL) to++; -# endif lint +# 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; @@ -508,6 +531,29 @@ checkcompat(to, e) 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: @@ -542,6 +588,25 @@ 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. @@ -558,71 +623,37 @@ rlsesigs() /* 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 int */ +#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 -# if defined(sun) && !defined(BSD) -# define LA_TYPE LA_INT -# endif -# if defined(mips) || defined(__alpha) - /* Ultrix or OSF/1 or RISC/os */ -# define LA_TYPE LA_INT -# define LA_AVENRUN "avenrun" -# endif -# if defined(__hpux) -# define LA_TYPE LA_FLOAT -# define LA_AVENRUN "avenrun" -# endif -# if defined(__NeXT__) -# define LA_TYPE LA_ZERO -# endif - -/* now do the guesses based on general OS type */ -# ifndef LA_TYPE -# if defined(SYSTEM5) -# define LA_TYPE LA_INT -# define LA_AVENRUN "avenrun" -# else -# if defined(BSD) -# define LA_TYPE LA_SUBR -# else -# define LA_TYPE LA_ZERO -# endif -# endif -# endif +# define LA_TYPE LA_ZERO #endif -#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) +#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) #include <nlist.h> #ifndef LA_AVENRUN -#define LA_AVENRUN "_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(__hpux) -# define _PATH_UNIX "/hp-ux" -# endif -# if defined(mips) && !defined(ultrix) - /* powerful RISC/os */ -# define _PATH_UNIX "/unix" -# endif -# if defined(Solaris2) - /* Solaris 2 */ -# define _PATH_UNIX "/kernel/unix" -# endif -# if defined(SYSTEM5) -# ifndef _PATH_UNIX -# define _PATH_UNIX "/unix" -# endif -# endif -# ifndef _PATH_UNIX -# define _PATH_UNIX "/vmunix" -# endif +# if defined(SYSTEM5) +# define _PATH_UNIX "/unix" +# else +# define _PATH_UNIX "/vmunix" +# endif #endif struct nlist Nl[] = @@ -641,12 +672,12 @@ struct nlist Nl[] = # define FSHIFT 10 # endif -# if (LA_TYPE == LA_INT) +# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) # define FSHIFT 8 # endif #endif -#if (LA_TYPE == LA_INT) && !defined(FSCALE) +#if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE) # define FSCALE (1 << FSHIFT) #endif @@ -656,7 +687,11 @@ getla() #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; @@ -697,7 +732,7 @@ getla() printf("getla: lseek or read: %s\n", errstring(errno)); return (-1); } -#if LA_TYPE == LA_INT +#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) if (tTd(3, 5)) { printf("getla: avenrun = %d", avenrun[0]); @@ -725,6 +760,22 @@ getla() #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]; @@ -740,6 +791,88 @@ getla() 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() @@ -751,6 +884,55 @@ getla() #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: conf.c,v 1.5.2.1 1994/04/18 03:53:45 rgrimes 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? ** @@ -822,12 +1004,19 @@ refuseconnections() */ #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 @@ -837,6 +1026,12 @@ refuseconnections() # endif #endif +#ifndef PROCTITLEPAD +# define PROCTITLEPAD ' ' +#endif + +#ifndef HASSETPROCTITLE + /*VARARGS1*/ #ifdef __STDC__ setproctitle(char *fmt, ...) @@ -886,11 +1081,13 @@ setproctitle(fmt, va_alist) (void) strcpy(Argv[0], buf); p = &Argv[0][i]; while (p < LastArgv) - *p++ = ' '; + *p++ = PROCTITLEPAD; # endif # endif # endif /* SETPROCTITLE */ } + +#endif /* ** REAPCHILD -- pick up the body of my child, lest it become a zombie ** @@ -904,12 +1101,11 @@ setproctitle(fmt, va_alist) ** Picks up extant zombies. */ -# include <sys/wait.h> - void reapchild() { -# if defined(WIFEXITED) && !defined(__NeXT__) + int olderrno = errno; +# ifdef HASWAITPID auto int status; int count; int pid; @@ -937,9 +1133,10 @@ reapchild() continue; # endif /* WNOHANG */ # endif -# ifdef SYSTEM5 - (void) signal(SIGCHLD, reapchild); +# ifdef SYS5SIGNALS + (void) setsignal(SIGCHLD, reapchild); # endif + errno = olderrno; } /* ** UNSETENV -- remove a variable from the environment @@ -960,7 +1157,7 @@ reapchild() ** Modifies environ. */ -#ifdef UNSETENV +#ifndef HASUNSETENV void unsetenv(name) @@ -981,7 +1178,7 @@ unsetenv(name) *pp = pp[1]; } -#endif /* UNSETENV */ +#endif /* ** GETDTABLESIZE -- return number of file descriptors ** @@ -1011,11 +1208,11 @@ getdtsize() return rl.rlim_cur; #endif -# if defined(_SC_OPEN_MAX) && !defined(NO_SYSCONF) - return sysconf(_SC_OPEN_MAX); -# else -# ifdef HASGETDTABLESIZE +# ifdef HASGETDTABLESIZE return getdtablesize(); +# else +# ifdef _SC_OPEN_MAX + return sysconf(_SC_OPEN_MAX); # else return NOFILE; # endif @@ -1090,12 +1287,6 @@ uname(name) */ #ifndef HASINITGROUPS -# if !defined(SYSTEM5) || defined(__hpux) -# define HASINITGROUPS -# endif -#endif - -#ifndef HASINITGROUPS initgroups(name, basegid) char *name; @@ -1114,61 +1305,317 @@ initgroups(name, basegid) pid_t setsid __P ((void)) { -# ifdef SYSTEM5 +#ifdef TIOCNOTTY + int fd; + + fd = open("/dev/tty", 2); + if (fd >= 0) + { + (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); + (void) close(fd); + } +#endif /* TIOCNOTTY */ +# ifdef SYS5SETPGRP return setpgrp(); # else - return 0; + return setpgid(0, getpid()); # endif } #endif /* -** ENOUGHSPACE -- check to see if there is enough free space on the queue fs +** DGUX_INET_ADDR -- inet_addr for DG/UX ** -** Only implemented if you have statfs. +** 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: -** 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. +** shell -- the user's shell from /etc/passwd ** ** Returns: -** TRUE if there is enough space. -** FALSE otherwise. +** TRUE -- if it is ok to use this for unrestricted access. +** FALSE -- if the shell is restricted. */ -#ifndef HASSTATFS -# if defined(BSD4_4) || defined(__osf__) -# define HASSTATFS +#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 +}; -#ifdef HASSTATFS -# undef HASUSTAT #endif -#if defined(HASUSTAT) -# include <ustat.h> +#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. +*/ -#ifdef HASSTATFS -# if defined(sgi) || defined(apollo) -# include <sys/statfs.h> -# else -# if (defined(sun) && !defined(BSD)) || defined(__hpux) -# include <sys/vfs.h> -# else -# include <sys/mount.h> -# endif -# endif +/* 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 */ + +#ifndef SFS_TYPE +# define SFS_TYPE SFS_NONE #endif -bool -enoughspace(msize) - long msize; +#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 + +long +freespace(dir, 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 @@ -1181,46 +1628,81 @@ enoughspace(msize) # 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 extern int errno; - if (MinBlocksFree <= 0 && msize <= 0) - { - if (tTd(4, 80)) - printf("enoughspace: no threshold\n"); - return TRUE; - } - -# if defined(HASUSTAT) - if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) +# if SFS_TYPE == SFS_USTAT + if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) # else -# if defined(sgi) || defined(apollo) - if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) +# if SFS_TYPE == SFS_4ARGS + if (statfs(dir, &fs, sizeof fs, 0) == 0) # else # if defined(ultrix) - if (statfs(QueueDir, &fs) > 0) + if (statfs(dir, &fs) > 0) # else - if (statfs(QueueDir, &fs) == 0) + 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", - fs.f_bavail, msize); + bfree, msize); /* convert msize to block count */ - msize = msize / FSBLOCKSIZE + 1; + msize = msize / bsize + 1; if (MinBlocksFree >= 0) msize += MinBlocksFree; - if (fs.f_bavail < msize) + if (bfree < msize) { #ifdef LOG if (LogLevel > 0) - syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", - QueueDir, fs.f_bavail, msize); + syslog(LOG_ALERT, + "%s: low on space (have %ld, %s needs %ld in %s)", + CurEnv->e_id, bfree, + CurHostName, msize, QueueDir); #endif return FALSE; } @@ -1228,7 +1710,6 @@ enoughspace(msize) else if (tTd(4, 80)) printf("enoughspace failure: min=%ld, need=%ld: %s\n", MinBlocksFree, msize, errstring(errno)); -#endif return TRUE; } /* @@ -1322,7 +1803,10 @@ transienterror(err) #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: /* Can't assign requested address */ #endif -#ifdef ENOSR +#ifdef ETXTBSY + case ETXTBSY: /* (Apollo) file locked */ +#endif +#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) case ENOSR: /* Out of streams resources */ #endif return TRUE; @@ -1332,11 +1816,12 @@ transienterror(err) return FALSE; } /* -** LOCKFILE -- lock a file using flock or (shudder) lockf +** 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. @@ -1347,15 +1832,20 @@ transienterror(err) */ bool -lockfile(fd, filename, type) +lockfile(fd, filename, ext, type) int fd; char *filename; + char *ext; int type; { -# ifdef LOCKF +# 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)) @@ -1368,19 +1858,492 @@ lockfile(fd, filename, type) else action = F_SETLKW; - lfd.l_whence = lfd.l_start = lfd.l_len = 0; + 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)) - syserr("cannot lockf(%s, %o)", filename, 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 = ""; + + 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) - syserr("cannot flock(%s, %o)", filename, 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; +} +/* +** 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. +*/ + +#if defined(__FreeBSD__) && defined(_POSIX_CHOWN_RESTRICTED) +# undef _POSIX_CHOWN_RESTRICTED +# define _POSIX_CHOWN_RESTRICTED 1 +#endif + +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 |
