Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: head/contrib/sendmail/cf/m4/cfhead.m4
===================================================================
--- head/contrib/sendmail/cf/m4/cfhead.m4 (revision 66496)
+++ head/contrib/sendmail/cf/m4/cfhead.m4 (revision 66497)
@@ -1,255 +1,257 @@
#
# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
# The Regents of the University of California. All rights reserved.
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
# $FreeBSD$
#
######################################################################
######################################################################
#####
##### SENDMAIL CONFIGURATION FILE
#####
ifdef(`unix', `dnl
ifdef(`TEMPFILE', `dnl', `define(`TEMPFILE', maketemp(/tmp/cfXXXXXX))dnl
syscmd(sh _CF_DIR_`'sh/makeinfo.sh _CF_DIR_ > TEMPFILE)dnl
include(TEMPFILE)dnl
syscmd(rm -f TEMPFILE)dnl')', `dnl')
#####
######################################################################
######################################################################
divert(-1)
changecom()
undefine(`format')
undefine(`hpux')
ifdef(`pushdef', `',
`errprint(`You need a newer version of M4, at least as new as
System V or GNU')
include(NoSuchFile)')
define(`PUSHDIVERT', `pushdef(`__D__', divnum)divert($1)')
define(`POPDIVERT', `divert(__D__)popdef(`__D__')')
define(`OSTYPE',
`PUSHDIVERT(-1)
ifdef(`__OSTYPE__', `errprint(`duplicate OSTYPE'($1)
)')
define(`__OSTYPE__', $1)
define(`_ARG_', $2)
include(_CF_DIR_`'ostype/$1.m4)POPDIVERT`'')
## helpful functions
define(`lower', `translit(`$1', `ABCDEFGHIJKLMNOPQRSTUVWXYZ', `abcdefghijklmnopqrstuvwx')')
define(`strcasecmp', `ifelse(lower($1), lower($2), `1', `0')')
## new FEATUREs
define(`_DNSBL_R_',`')
## access to further arguments in FEATURE/HACK
define(`_ACC_ARG_1_',`$1')
define(`_ACC_ARG_2_',`$2')
define(`_ACC_ARG_3_',`$3')
define(`_ACC_ARG_4_',`$4')
define(`_ACC_ARG_5_',`$5')
define(`_ACC_ARG_6_',`$6')
define(`_ACC_ARG_7_',`$7')
define(`_ACC_ARG_8_',`$8')
define(`_ACC_ARG_9_',`$9')
define(`_ARG1_',`_ACC_ARG_1_(_ARGS_)')
define(`_ARG2_',`_ACC_ARG_2_(_ARGS_)')
define(`_ARG3_',`_ACC_ARG_3_(_ARGS_)')
define(`_ARG4_',`_ACC_ARG_4_(_ARGS_)')
define(`_ARG5_',`_ACC_ARG_5_(_ARGS_)')
define(`_ARG6_',`_ACC_ARG_6_(_ARGS_)')
define(`_ARG7_',`_ACC_ARG_7_(_ARGS_)')
define(`_ARG8_',`_ACC_ARG_8_(_ARGS_)')
define(`_ARG9_',`_ACC_ARG_9_(_ARGS_)')
dnl define if not yet defined: if `$1' is not defined it will be `$2'
define(`_DEFIFNOT',`ifdef(`$1',`',`define(`$1',`$2')')')
dnl ----------------------------------------
dnl add a char $2 to a string $1 if it is not there
define(`_ADDCHAR_',`define(`_I_',`eval(index(`$1',`$2') >= 0)')`'ifelse(_I_,`1',`$1',`$1$2')')
dnl ----
dnl delete a char $2 from a string $1 if it is there
define(`_DELCHAR_',`define(`_IDX_',`index(`$1',`$2')')`'define(`_I_',`eval(_IDX_ >= 0)')`'ifelse(_I_,`1',`substr(`$1',0,_IDX_)`'substr(`$1',eval(_IDX_+1))',`$1')')
dnl ----
dnl apply a macro to a whole string by recursion (one char at a time)
dnl $1: macro
dnl $2: first argument to macro
dnl $3: list that is split up into characters
define(`_AP_',`ifelse(`$3',`',`$2',`_AP_(`$1',$1(`$2',substr(`$3',0,1)),substr(`$3',1))')')
dnl ----
dnl MODIFY_MAILER_FLAGS: append tail of $2 to $1_MF_A/D_
dnl A if head($2) = +
dnl D if head($2) = -
dnl $1_MF_ is set otherwise; set _A/D_ to `'
define(`MODIFY_MAILER_FLAGS',`define(`_hd_',`substr(`$2',0,1)')define(`_tl_',`substr(`$2',1)')`'ifelse(_hd_,`+',`ifdef($1`'_MF_A_, `define($1`'_MF_A_,$1_MF_A_`'_tl_)', `define($1`'_MF_A_, _tl_)')',_hd_,`-',`ifdef($1`'_MF_D_, `define($1`'_MF_D_,$1_MF_D_`'_tl_)', `define($1`'_MF_D_,_tl_)')',`define($1`'_MF_,`$2')define($1`'_MF_A_,`')define($1`'_MF_D_,`')')')
dnl ----
dnl actually modify flags:
dnl $1: flags (strings) to modify
dnl $2: name of flags (just first part) to modify
dnl WARNING: the order might be important: if someone adds and delete the
dnl same characters, he does not deserve any better, does he?
dnl this could be coded more efficiently... (do not apply the macro if _MF_A/D_ is undefined)
define(`_MODMF_',`ifdef($2`'_MF_,`$2_MF_',`_AP_(`_ADDCHAR_',_AP_(`_DELCHAR_',$1,ifdef($2`'_MF_D_,`$2_MF_D_',`')),ifdef($2`'_MF_A_,`$2_MF_A_',`'))')')
dnl usage:
dnl MODIFY_MAILER_FLAGS(`LOCAL',`+FlaGs')dnl
dnl in MAILER.m4: _MODMF_(LMF,`LOCAL')
dnl ----------------------------------------
define(`MAILER',
`define(`_M_N_', `ifelse(`$2', `', `$1', `$2')')dnl
ifdef(_MAILER_`'_M_N_`'_, `dnl`'',
`define(_MAILER_`'_M_N_`'_, `')define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')PUSHDIVERT(7)include(_CF_DIR_`'mailer/$1.m4)POPDIVERT`'')')
define(`DOMAIN', `PUSHDIVERT(-1)define(`_ARG_', `$2')include(_CF_DIR_`'domain/$1.m4)POPDIVERT`'')
define(`FEATURE', `PUSHDIVERT(-1)define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')include(_CF_DIR_`'feature/$1.m4)POPDIVERT`'')
define(`HACK', `PUSHDIVERT(-1)define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')include(_CF_DIR_`'hack/$1.m4)POPDIVERT`'')
define(`_DPO_',`')
define(`DAEMON_OPTIONS', `define(`_DPO_', defn(`_DPO_')
O DaemonPortOptions=`$1')')
define(`_MAIL_FILTERS_', `')
define(`MAIL_FILTER', `define(`_MAIL_FILTERS_', defn(`_MAIL_FILTERS_')
X`'$1`, '`$2')')
define(`INPUT_MAIL_FILTER', `MAIL_FILTER(`$1', `$2')
ifelse(defn(`confINPUT_MAIL_FILTERS')X, `X',
`define(`confINPUT_MAIL_FILTERS', $1)',
`define(`confINPUT_MAIL_FILTERS', defn(`confINPUT_MAIL_FILTERS')`, '`$1')')')
define(`CF_LEVEL', `9')dnl
define(`VERSIONID', ``##### $1 #####'')
define(`LOCAL_RULE_0', `divert(3)')
define(`LOCAL_RULE_1',
`divert(9)dnl
#######################################
### Ruleset 1 -- Sender Rewriting ###
#######################################
Ssender=1
')
define(`LOCAL_RULE_2',
`divert(9)dnl
##########################################
### Ruleset 2 -- Recipient Rewriting ###
##########################################
Srecipient=2
')
define(`LOCAL_RULESETS',
`divert(9)
')
define(`LOCAL_RULE_3', `divert(2)')
define(`LOCAL_CONFIG', `divert(6)')
define(`MAILER_DEFINITIONS', `divert(7)')
define(`LOCAL_NET_CONFIG', `define(`_LOCAL_RULES_', 1)divert(1)')
define(`UUCPSMTP', `R DOL(*) < @ $1 .UUCP > DOL(*) DOL(1) < @ $2 > DOL(2)')
define(`CONCAT', `$1$2$3$4$5$6$7')
define(`DOL', ``$'$1')
define(`SITECONFIG',
`CONCAT(D, $3, $2)
define(`_CLASS_$3_', `')dnl
ifelse($3, U, Cw$2 $2.UUCP, `dnl')
define(`SITE', `ifelse(CONCAT($'2`, $3), SU,
CONCAT(CY, $'1`),
CONCAT(C, $3, $'1`))')
sinclude(_CF_DIR_`'siteconfig/$1.m4)')
define(`EXPOSED_USER', `PUSHDIVERT(5)CE$1
POPDIVERT`'dnl`'')
+ifdef(`_FFR_EXPOSED_USER_FILE', `define(`EXPOSED_USER_FILE', `PUSHDIVERT(5)FE$1
+POPDIVERT`'dnl`'')', `dnl')
define(`LOCAL_USER', `PUSHDIVERT(5)CL$1
POPDIVERT`'dnl`'')
define(`MASQUERADE_AS', `define(`MASQUERADE_NAME', $1)')
define(`MASQUERADE_DOMAIN', `PUSHDIVERT(5)CM$1
POPDIVERT`'dnl`'')
define(`MASQUERADE_EXCEPTION', `PUSHDIVERT(5)CN$1
POPDIVERT`'dnl`'')
define(`MASQUERADE_DOMAIN_FILE', `PUSHDIVERT(5)FM$1
POPDIVERT`'dnl`'')
define(`LOCAL_DOMAIN', `PUSHDIVERT(5)Cw$1
POPDIVERT`'dnl`'')
define(`CANONIFY_DOMAIN', `PUSHDIVERT(5)C{Canonify}$1
POPDIVERT`'dnl`'')
define(`CANONIFY_DOMAIN_FILE', `PUSHDIVERT(5)F{Canonify}$1
POPDIVERT`'dnl`'')
define(`GENERICS_DOMAIN', `PUSHDIVERT(5)CG$1
POPDIVERT`'dnl`'')
define(`GENERICS_DOMAIN_FILE', `PUSHDIVERT(5)FG$1
POPDIVERT`'dnl`'')
define(`LDAPROUTE_DOMAIN', `PUSHDIVERT(5)C{LDAPRoute}$1
POPDIVERT`'dnl`'')
define(`LDAPROUTE_DOMAIN_FILE', `PUSHDIVERT(5)F{LDAPRoute}$1
POPDIVERT`'dnl`'')
define(`VIRTUSER_DOMAIN', `PUSHDIVERT(5)C{VirtHost}$1
define(`_VIRTHOSTS_')
POPDIVERT`'dnl`'')
define(`VIRTUSER_DOMAIN_FILE', `PUSHDIVERT(5)F{VirtHost}$1
define(`_VIRTHOSTS_')
POPDIVERT`'dnl`'')
define(`RELAY_DOMAIN', `PUSHDIVERT(5)CR$1
POPDIVERT`'dnl`'')
define(`RELAY_DOMAIN_FILE', `PUSHDIVERT(5)FR$1
POPDIVERT`'dnl`'')
define(`TRUST_AUTH_MECH', `PUSHDIVERT(5)C{TrustAuthMech}$1
POPDIVERT`'dnl`'')
define(`_OPTINS', `ifdef(`$1', `$2$1$3')')
m4wrap(`include(_CF_DIR_`m4/proto.m4')')
# default location for files
ifdef(`MAIL_SETTINGS_DIR', , `define(`MAIL_SETTINGS_DIR', `/etc/mail/')')
# set our default hashed database type
define(`DATABASE_MAP_TYPE', `hash')
# set up default values for options
define(`ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
define(`confMAILER_NAME', ``MAILER-DAEMON'')
define(`confFROM_LINE', `From $g $d')
define(`confOPERATORS', `.:%@!^/[]+')
define(`confSMTP_LOGIN_MSG', `$j Sendmail $v/$Z; $b')
define(`_REC_AUTH_', `$.$?{auth_type}(authenticated')
define(`_REC_FULL_AUTH_', `$.$?{auth_type}(authenticated as ${auth_authen} $?{auth_author}for ${auth_author} $.with ${auth_type}')
define(`_REC_HDR_', `$?sfrom $s $.$?_($?s$|from $.$_)')
define(`_REC_END_', `for $u; $|;
$.$b$?g
(envelope-from $g)$.')
define(`_REC_TLS_', `(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})$.$?u')
define(`_REC_BY_', `$.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}')
define(`confRECEIVED_HEADER', `_REC_HDR_
_REC_AUTH_$?{auth_ssf} (${auth_ssf} bits)$.)
_REC_BY_
_REC_TLS_
_REC_END_')
define(`confSEVEN_BIT_INPUT', `False')
define(`confEIGHT_BIT_HANDLING', `pass8')
define(`confALIAS_WAIT', `10')
define(`confMIN_FREE_BLOCKS', `100')
define(`confBLANK_SUB', `.')
define(`confCON_EXPENSIVE', `False')
define(`confDELIVERY_MODE', `background')
define(`confTEMP_FILE_MODE', `0600')
define(`confMCI_CACHE_SIZE', `2')
define(`confMCI_CACHE_TIMEOUT', `5m')
define(`confUSE_ERRORS_TO', `False')
define(`confLOG_LEVEL', `9')
define(`confCHECK_ALIASES', `False')
define(`confOLD_STYLE_HEADERS', `True')
define(`confPRIVACY_FLAGS', `authwarnings')
define(`confSAFE_QUEUE', `True')
define(`confTO_QUEUERETURN', `5d')
define(`confTO_QUEUEWARN', `4h')
define(`confTIME_ZONE', `USE_SYSTEM')
define(`confCW_FILE', `MAIL_SETTINGS_DIR`'local-host-names')
define(`confMIME_FORMAT_ERRORS', `True')
define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward')
define(`confCR_FILE', `-o MAIL_SETTINGS_DIR`'relay-domains')
define(`confMILTER_MACROS_CONNECT', ``j, _, {daemon_name}, {if_name}, {if_addr}'')
define(`confMILTER_MACROS_HELO', ``{tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer}'')
define(`confMILTER_MACROS_ENVFROM', ``i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author}, {mail_mailer}, {mail_host}, {mail_addr}'')
define(`confMILTER_MACROS_ENVRCPT', ``{rcpt_mailer}, {rcpt_host}, {rcpt_addr}'')
divert(0)dnl
-VERSIONID(`$Id: cfhead.m4,v 8.76.4.9 2000/07/11 23:50:30 geir Exp $')
+VERSIONID(`$Id: cfhead.m4,v 8.76.4.13 2000/08/24 17:09:50 gshapiro Exp $')
Index: head/contrib/sendmail/mail.local/mail.local.8
===================================================================
--- head/contrib/sendmail/mail.local/mail.local.8 (revision 66496)
+++ head/contrib/sendmail/mail.local/mail.local.8 (revision 66497)
@@ -1,119 +1,125 @@
-.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" By using this file, you agree to the terms and conditions set
.\" forth in the LICENSE file which can be found at the top level of
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: mail.local.8,v 8.14 1999/08/26 15:49:20 ca Exp $
+.\" $Id: mail.local.8,v 8.14.14.3 2000/09/17 17:04:25 gshapiro Exp $
.\"
.\" $FreeBSD$
.\"
-.TH MAIL.LOCAL 8 "$Date: 1999/08/26 15:49:20 $"
+.TH MAIL.LOCAL 8 "$Date: 2000/09/17 17:04:25 $"
.SH NAME
.B mail.local
\- store mail in a mailbox
.SH SYNOPSIS
.B mail.local
-.RB [ \-7 "] [" \-B "] [" \-d "] [" \-l "] [" \-s "] [" \-f
+.RB [ \-7 "] [" \-B "] [" \-b "] [" \-d "] [" \-l "] [" \-s "] [" \-f
.IR from "] " "user ..."
.SH DESCRIPTION
.B Mail.local
reads the standard input up to an end-of-file and appends it to each
.I user's
.B mail
file. The
.I user
must be a valid user name.
.PP
The options are as follows:
.TP 1i
.B \-7
Do not advertise 8BITMIME support in LMTP mode.
.TP
.B \-B
Turn off the attempts to notify the
.Dq biff
service.
.TP
.B \-b
Return a permanent error instead of a temporary error
if a mailbox exceeds quota.
.TP
.B \-d
Specify this is a delivery (for backward compatibility).
.TP
.BI \-f " from"
Specify the sender's name.
.TP
.B \-l
Turn on LMTP mode.
.TP
.B \-s
Turn off the
.Xr fsync 2
call that forces the mailbox to be committed to disk before returning a
.Dq success
status.
.TP
.BI \-r " from"
Specify the sender's name (for backward compatibility).
.PP
Individual mail messages in the mailbox are delimited by an empty
line followed by a line beginning with the string ``From ''.
A line containing the string ``From '', the sender's name and a time stamp
is prepended to each delivered mail message.
A blank line is appended to each message.
A greater-than character (``>'') is prepended to any line in the message
which could be mistaken for a ``From '' delimiter line
(that is,
a line beginning with the five characters
``From '' following a blank line).
.PP
The mail files are exclusively locked with
flock(2)
while mail is appended,
and a
.B user.lock
file also is created while the mailbox is locked
for compatibility with older MUAs.
.PP
If the ``biff'' service is returned by
getservbyname(3),
the biff server is notified of delivered mail.
.PP
The
.B mail.local
utility exits 0 on success, and >0 if an error occurs.
.SH ENVIRONMENT
.IP TZ
Used to set the appropriate time zone on the timestamp.
.SH FILES
.PD 0.2v
.TP 2.2i
/tmp/local.XXXXXX
temporary files
.TP
/var/mail/user
user's mailbox directory
.TP
/var/mail/user.lock
lock file for a user's mailbox
.PD
.SH SEE ALSO
mail(1),
flock(2),
getservbyname(3),
comsat(8),
sendmail(8)
+.SH WARNING
+.B mail.local
+escapes only "^From " lines that follow an empty line.
+If all lines starting with "From " should be escaped,
+use the 'E' flag for the local mailer in the
+sendmail.cf file.
.SH HISTORY
A superset of
.B mail.local
(handling mailbox reading as well as mail delivery)
appeared in
Version 7 AT&T UNIX
as the program
.BR mail .
Index: head/contrib/sendmail/mail.local/mail.local.c
===================================================================
--- head/contrib/sendmail/mail.local/mail.local.c (revision 66496)
+++ head/contrib/sendmail/mail.local/mail.local.c (revision 66497)
@@ -1,1705 +1,1732 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
-static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.13 2000/07/18 05:41:38 gshapiro Exp $";
+static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.37 2000/09/22 00:49:10 doug Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
/*
** This is not intended to work on System V derived systems
** such as Solaris or HP-UX, since they use a totally different
** approach to mailboxes (essentially, they have a setgid program
** rather than setuid, and they rely on the ability to "give away"
** files to do their work). IT IS NOT A BUG that this doesn't
** work on such architectures.
*/
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/file.h>
+/* additional mode for open() */
+# define EXTRA_MODE 0
-#include <netinet/in.h>
-#include <arpa/nameser.h>
+# include <sys/types.h>
+# include <sys/param.h>
+# include <sys/stat.h>
+# include <sys/socket.h>
+# include <sys/file.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-#ifdef EX_OK
-# undef EX_OK /* unistd.h may have another use for this */
-#endif /* EX_OK */
-#include <sysexits.h>
-#include <ctype.h>
+# include <netinet/in.h>
+# include <arpa/nameser.h>
-#ifndef __P
-# include "sendmail/cdefs.h"
-#endif /* ! __P */
-#include "sendmail/useful.h"
+# include <fcntl.h>
+# include <netdb.h>
+# include <pwd.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <syslog.h>
+# include <time.h>
+# include <unistd.h>
+# ifdef EX_OK
+# undef EX_OK /* unistd.h may have another use for this */
+# endif /* EX_OK */
+# include <sysexits.h>
+# include <ctype.h>
+# ifndef __P
+# include "sendmail/cdefs.h"
+# endif /* ! __P */
+# include "sendmail/useful.h"
+
extern size_t strlcpy __P((char *, const char *, size_t));
extern size_t strlcat __P((char *, const char *, size_t));
-#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# ifndef HASSTRERROR
-# define HASSTRERROR 1
-# endif /* ! HASSTRERROR */
-#endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
- defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+# if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
+# ifndef HASSTRERROR
+# define HASSTRERROR 1
+# endif /* ! HASSTRERROR */
+# endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
-#include "sendmail/errstring.h"
+# include "sendmail/errstring.h"
+# ifndef LOCKTO_RM
+# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
+# endif /* ! LOCKTO_RM */
+# ifndef LOCKTO_GLOB
+# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
+# endif /* ! LOCKTO_GLOB */
-#ifndef LOCKTO_RM
-# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
-#endif /* LOCKTO_RM */
-#ifndef LOCKTO_GLOB
-# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
-#endif /* LOCKTO_GLOB */
-
-#ifdef __STDC__
-# include <stdarg.h>
-# define REALLOC(ptr, size) realloc(ptr, size)
-#else /* __STDC__ */
-# include <varargs.h>
+# ifdef __STDC__
+# include <stdarg.h>
+# define REALLOC(ptr, size) realloc(ptr, size)
+# else /* __STDC__ */
+# include <varargs.h>
/* define a realloc() which works for NULL pointers */
-# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
-#endif /* __STDC__ */
+# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
+# endif /* __STDC__ */
-#if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
-# define USE_LOCKF 1
-# define USE_SETEUID 1
-# define _PATH_MAILDIR "/var/mail"
-#endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
+# if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
+# define USE_LOCKF 1
+# define USE_SETEUID 1
+# define _PATH_MAILDIR "/var/mail"
+# endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
-#ifdef NCR_MP_RAS3
-# define USE_LOCKF 1
-# define HASSNPRINTF 1
-# define _PATH_MAILDIR "/var/mail"
-#endif /* NCR_MP_RAS3 */
+# ifdef NCR_MP_RAS3
+# define USE_LOCKF 1
+# define HASSNPRINTF 1
+# define _PATH_MAILDIR "/var/mail"
+# endif /* NCR_MP_RAS3 */
-#if defined(_AIX)
-# define USE_LOCKF 1
-# define USE_SETEUID 1
-# define USE_VSYSLOG 0
-#endif /* defined(_AIX) */
+# if defined(_AIX)
+# define USE_LOCKF 1
+# define USE_SETEUID 1
+# define USE_VSYSLOG 0
+# endif /* defined(_AIX) */
-#if defined(__hpux)
-# define USE_LOCKF 1
-# define USE_SETRESUID 1
-# define USE_VSYSLOG 0
-#endif /* defined(__hpux) */
+# if defined(__hpux)
+# define USE_LOCKF 1
+# define USE_SETRESUID 1
+# define USE_VSYSLOG 0
+# endif /* defined(__hpux) */
-#ifdef DGUX
-# define HASSNPRINTF 1
-# define USE_LOCKF 1
-# define USE_VSYSLOG 0
-#endif /* DGUX */
+# ifdef DGUX
+# define HASSNPRINTF 1
+# define USE_LOCKF 1
+# define USE_VSYSLOG 0
+# endif /* DGUX */
-#if defined(_CRAY)
-# if !defined(MAXPATHLEN)
-# define MAXPATHLEN PATHSIZE
-# endif /* !defined(MAXPATHLEN) */
-# define USE_VSYSLOG 0
-# define _PATH_MAILDIR "/usr/spool/mail"
-#endif /* defined(_CRAY) */
+# if defined(_CRAY)
+# if !defined(MAXPATHLEN)
+# define MAXPATHLEN PATHSIZE
+# endif /* !defined(MAXPATHLEN) */
+# define USE_VSYSLOG 0
+# define _PATH_MAILDIR "/usr/spool/mail"
+# endif /* defined(_CRAY) */
-#if defined(ultrix)
-# define USE_VSYSLOG 0
-#endif /* defined(ultrix) */
+# if defined(ultrix)
+# define USE_VSYSLOG 0
+# endif /* defined(ultrix) */
-#if defined(__osf__)
-# define USE_VSYSLOG 0
-#endif /* defined(__osf__) */
+# if defined(__osf__)
+# define USE_VSYSLOG 0
+# endif /* defined(__osf__) */
-#if defined(NeXT) && !defined(__APPLE__)
-# include <libc.h>
-# define _PATH_MAILDIR "/usr/spool/mail"
-# define S_IRUSR S_IREAD
-# define S_IWUSR S_IWRITE
-#endif /* defined(NeXT) && !defined(__APPLE__) */
+# if defined(NeXT) && !defined(__APPLE__)
+# include <libc.h>
+# define _PATH_MAILDIR "/usr/spool/mail"
+# define S_IRUSR S_IREAD
+# define S_IWUSR S_IWRITE
+# endif /* defined(NeXT) && !defined(__APPLE__) */
-#if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# include <paths.h>
-#endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
+# include <paths.h>
+# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
/*
* If you don't have flock, you could try using lockf instead.
*/
-#ifdef USE_LOCKF
-# define flock(a, b) lockf(a, b, 0)
-# ifdef LOCK_EX
-# undef LOCK_EX
-# endif /* LOCK_EX */
-# define LOCK_EX F_LOCK
-#endif /* USE_LOCKF */
+# ifdef USE_LOCKF
+# define flock(a, b) lockf(a, b, 0)
+# ifdef LOCK_EX
+# undef LOCK_EX
+# endif /* LOCK_EX */
+# define LOCK_EX F_LOCK
+# endif /* USE_LOCKF */
-#ifndef USE_VSYSLOG
-# define USE_VSYSLOG 1
-#endif /* ! USE_VSYSLOG */
+# ifndef USE_VSYSLOG
+# define USE_VSYSLOG 1
+# endif /* ! USE_VSYSLOG */
-#ifndef LOCK_EX
-# include <sys/file.h>
-#endif /* ! LOCK_EX */
+# ifndef LOCK_EX
+# include <sys/file.h>
+# endif /* ! LOCK_EX */
-#if defined(BSD4_4) || defined(__GLIBC__)
-# include <paths.h>
-# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
-#endif /* defined(BSD4_4) || defined(__GLIBC__) */
+# if defined(BSD4_4) || defined(__GLIBC__)
+# include <paths.h>
+# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
+# endif /* defined(BSD4_4) || defined(__GLIBC__) */
-#ifdef BSD4_4
-# define HAS_ST_GEN 1
-#else /* BSD4_4 */
-# ifndef _BSD_VA_LIST_
-# define _BSD_VA_LIST_ va_list
-# endif /* ! _BSD_VA_LIST_ */
-#endif /* BSD4_4 */
+# ifdef BSD4_4
+# define HAS_ST_GEN 1
+# else /* BSD4_4 */
+# ifndef _BSD_VA_LIST_
+# define _BSD_VA_LIST_ va_list
+# endif /* ! _BSD_VA_LIST_ */
+# endif /* BSD4_4 */
-#if defined(BSD4_4) || defined(linux)
-# define HASSNPRINTF 1
-#else /* defined(BSD4_4) || defined(linux) */
-# ifndef ultrix
+# if defined(BSD4_4) || defined(linux)
+# define HASSNPRINTF 1
+# else /* defined(BSD4_4) || defined(linux) */
+# ifndef ultrix
extern FILE *fdopen __P((int, const char *));
-# endif /* ! ultrix */
-#endif /* defined(BSD4_4) || defined(linux) */
+# endif /* ! ultrix */
+# endif /* defined(BSD4_4) || defined(linux) */
-#if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
-# define CONTENTLENGTH 1 /* Needs the Content-Length header */
-#endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
+# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
+# define CONTENTLENGTH 1 /* Needs the Content-Length header */
+# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
-#if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
-# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-#endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
+# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
+# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
+# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
-#ifdef HPUX11
-# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-#endif /* HPUX11 */
+# ifdef HPUX11
+# define HASSNPRINTF 1 /* has snprintf starting in 11.X */
+# endif /* HPUX11 */
-#if _AIX4 >= 40300
-# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
-#endif /* _AIX4 >= 40300 */
+# if _AIX4 >= 40300
+# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
+# endif /* _AIX4 >= 40300 */
-#if !HASSNPRINTF
+# if !HASSNPRINTF
extern int snprintf __P((char *, size_t, const char *, ...));
-# ifndef _CRAY
+# ifndef _CRAY
extern int vsnprintf __P((char *, size_t, const char *, ...));
-# endif /* ! _CRAY */
-#endif /* !HASSNPRINTF */
+# endif /* ! _CRAY */
+# endif /* !HASSNPRINTF */
/*
** If you don't have setreuid, and you have saved uids, and you have
** a seteuid() call that doesn't try to emulate using setuid(), then
** you can try defining USE_SETEUID.
*/
-#ifdef USE_SETEUID
-# define setreuid(r, e) seteuid(e)
-#endif /* USE_SETEUID */
+# ifdef USE_SETEUID
+# define setreuid(r, e) seteuid(e)
+# endif /* USE_SETEUID */
/*
** And of course on hpux you have setresuid()
*/
-#ifdef USE_SETRESUID
-# define setreuid(r, e) setresuid(-1, e, -1)
-#endif /* USE_SETRESUID */
+# ifdef USE_SETRESUID
+# define setreuid(r, e) setresuid(-1, e, -1)
+# endif /* USE_SETRESUID */
-#ifndef _PATH_LOCTMP
-# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
-#endif /* ! _PATH_LOCTMP */
-# ifndef _PATH_MAILDIR
-# define _PATH_MAILDIR "/var/spool/mail"
-# endif /* ! _PATH_MAILDIR */
+# ifndef _PATH_LOCTMP
+# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
+# endif /* ! _PATH_LOCTMP */
+# ifndef _PATH_MAILDIR
+# define _PATH_MAILDIR "/var/spool/mail"
+# endif /* ! _PATH_MAILDIR */
-#ifndef S_ISREG
-# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
-#endif /* ! S_ISREG */
+# ifndef S_ISREG
+# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
+# endif /* ! S_ISREG */
-#ifdef MAILLOCK
-# include <maillock.h>
-#endif /* MAILLOCK */
+# ifdef MAILLOCK
+# include <maillock.h>
+# endif /* MAILLOCK */
+# define U_UID pw->pw_uid
+# define U_GID pw->pw_gid
+
#ifndef INADDRSZ
# define INADDRSZ 4 /* size of an IPv4 address in bytes */
#endif /* ! INADDRSZ */
#ifndef MAILER_DAEMON
# define MAILER_DAEMON "MAILER-DAEMON"
#endif /* ! MAILER_DAEMON */
#ifdef CONTENTLENGTH
char ContentHdr[40] = "Content-Length: ";
off_t HeaderLength;
off_t BodyLength;
#endif /* CONTENTLENGTH */
bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */
int ExitVal = EX_OK; /* sysexits.h error value. */
bool LMTPMode = FALSE;
bool bouncequota = FALSE; /* permanent error when over quota */
bool nobiff = FALSE;
bool nofsync = FALSE;
void deliver __P((int, char *, bool));
int e_to_sys __P((int));
void notifybiff __P((char *));
int store __P((char *, int));
void usage __P((void));
void vwarn __P((const char *, _BSD_VA_LIST_));
int lockmbox __P((char *));
void unlockmbox __P((void));
void mailerr __P((const char *, const char *, ...));
int
main(argc, argv)
int argc;
char *argv[];
{
struct passwd *pw;
int ch, fd;
uid_t uid;
char *from;
extern char *optarg;
extern int optind;
extern void dolmtp __P((bool));
/* make sure we have some open file descriptors */
for (fd = 10; fd < 30; fd++)
(void) close(fd);
/* use a reasonable umask */
(void) umask(0077);
# ifdef LOG_MAIL
openlog("mail.local", 0, LOG_MAIL);
# else /* LOG_MAIL */
openlog("mail.local", 0);
# endif /* LOG_MAIL */
from = NULL;
while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1)
{
switch(ch)
{
case '7': /* Do not advertise 8BITMIME */
EightBitMime = FALSE;
break;
case 'B':
nobiff = TRUE;
break;
case 'b': /* bounce mail when over quota. */
bouncequota = TRUE;
break;
case 'd': /* Backward compatible. */
break;
case 'f':
case 'r': /* Backward compatible. */
if (from != NULL)
{
mailerr(NULL, "multiple -f options");
usage();
}
from = optarg;
break;
case 'l':
LMTPMode = TRUE;
break;
case 's':
nofsync++;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
/* initialize biff structures */
if (!nobiff)
notifybiff(NULL);
if (LMTPMode)
dolmtp(bouncequota);
if (*argv == '\0')
usage();
/*
** If from not specified, use the name from getlogin() if the
** uid matches, otherwise, use the name from the password file
** corresponding to the uid.
*/
uid = getuid();
if (from == NULL && ((from = getlogin()) == NULL ||
(pw = getpwnam(from)) == NULL ||
pw->pw_uid != uid))
from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
/*
** There is no way to distinguish the error status of one delivery
** from the rest of the deliveries. So, if we failed hard on one
** or more deliveries, but had no failures on any of the others, we
** return a hard failure. If we failed temporarily on one or more
** deliveries, we return a temporary failure regardless of the other
** failures. This results in the delivery being reattempted later
** at the expense of repeated failures and multiple deliveries.
*/
for (fd = store(from, 0); *argv; ++argv)
deliver(fd, *argv, bouncequota);
exit(ExitVal);
/* NOTREACHED */
return ExitVal;
}
char *
parseaddr(s, rcpt)
char *s;
bool rcpt;
{
char *p;
int l;
if (*s++ != '<')
return NULL;
p = s;
/* at-domain-list */
while (*p == '@')
{
p++;
while (*p != ',' && *p != ':' && *p != '\0')
p++;
if (*p == '\0')
return NULL;
/* Skip over , or : */
p++;
}
s = p;
/* local-part */
while (*p != '\0' && *p != '@' && *p != '>')
{
if (*p == '\\')
{
if (*++p == '\0')
return NULL;
}
else if (*p == '\"')
{
p++;
while (*p != '\0' && *p != '\"')
{
if (*p == '\\')
{
if (*++p == '\0')
return NULL;
}
p++;
}
if (*p == '\0' || *(p + 1) == '\0')
return NULL;
}
/* +detail ? */
if (*p == '+' && rcpt)
*p = '\0';
p++;
}
/* @domain */
if (*p == '@')
{
if (rcpt)
*p++ = '\0';
while (*p != '\0' && *p != '>')
p++;
}
if (*p != '>')
return NULL;
else
*p = '\0';
p++;
if (*p != '\0' && *p != ' ')
return NULL;
if (*s == '\0')
s = MAILER_DAEMON;
l = strlen(s) + 1;
p = malloc(l);
if (p == NULL)
{
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
(void) strlcpy(p, s, l);
return p;
}
char *
process_recipient(addr)
char *addr;
{
if (getpwnam(addr) == NULL)
return "550 5.1.1 user unknown";
return NULL;
}
#define RCPT_GROW 30
void
dolmtp(bouncequota)
bool bouncequota;
{
char *return_path = NULL;
char **rcpt_addr = NULL;
int rcpt_num = 0;
int rcpt_alloc = 0;
bool gotlhlo = FALSE;
char *err;
int msgfd;
char *p;
int i;
char myhostname[1024];
char buf[4096];
(void) gethostname(myhostname, sizeof myhostname - 1);
printf("220 %s LMTP ready\r\n", myhostname);
for (;;)
{
(void) fflush(stdout);
if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
exit(EX_OK);
p = buf + strlen(buf) - 1;
if (p >= buf && *p == '\n')
*p-- = '\0';
if (p >= buf && *p == '\r')
*p-- = '\0';
switch (buf[0])
{
case 'd':
case 'D':
if (strcasecmp(buf, "data") == 0)
{
if (rcpt_num == 0)
{
printf("503 5.5.1 No recipients\r\n");
continue;
}
msgfd = store(return_path, rcpt_num);
if (msgfd == -1)
continue;
for (i = 0; i < rcpt_num; i++)
{
p = strchr(rcpt_addr[i], '+');
if (p != NULL)
*p++ = '\0';
- deliver(msgfd, rcpt_addr[i], bouncequota);
+ deliver(msgfd, rcpt_addr[i],
+ bouncequota);
}
(void) close(msgfd);
goto rset;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'l':
case 'L':
if (strncasecmp(buf, "lhlo ", 5) == 0)
{
/* check for duplicate per RFC 1651 4.2 */
if (gotlhlo)
{
printf("503 %s Duplicate LHLO\r\n",
myhostname);
continue;
}
gotlhlo = TRUE;
printf("250-%s\r\n", myhostname);
if (EightBitMime)
printf("250-8BITMIME\r\n");
printf("250-ENHANCEDSTATUSCODES\r\n");
printf("250 PIPELINING\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'm':
case 'M':
if (strncasecmp(buf, "mail ", 5) == 0)
{
if (return_path != NULL)
{
printf("503 5.5.1 Nested MAIL command\r\n");
continue;
}
if (strncasecmp(buf+5, "from:", 5) != 0 ||
((return_path = parseaddr(buf + 10,
FALSE)) == NULL))
{
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
printf("250 2.5.0 ok\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'n':
case 'N':
if (strcasecmp(buf, "noop") == 0)
{
printf("250 2.0.0 ok\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'q':
case 'Q':
if (strcasecmp(buf, "quit") == 0)
{
printf("221 2.0.0 bye\r\n");
exit(EX_OK);
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'r':
case 'R':
if (strncasecmp(buf, "rcpt ", 5) == 0)
{
if (return_path == NULL)
{
printf("503 5.5.1 Need MAIL command\r\n");
continue;
}
if (rcpt_num >= rcpt_alloc)
{
rcpt_alloc += RCPT_GROW;
rcpt_addr = (char **)
- REALLOC((char *)rcpt_addr,
+ REALLOC((char *) rcpt_addr,
rcpt_alloc *
sizeof(char **));
if (rcpt_addr == NULL)
{
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
}
if (strncasecmp(buf + 5, "to:", 3) != 0 ||
((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
TRUE)) == NULL))
{
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL)
{
printf("%s\r\n", err);
continue;
}
rcpt_num++;
printf("250 2.1.5 ok\r\n");
continue;
}
else if (strcasecmp(buf, "rset") == 0)
{
printf("250 2.0.0 ok\r\n");
rset:
while (rcpt_num)
free(rcpt_addr[--rcpt_num]);
if (return_path != NULL)
free(return_path);
return_path = NULL;
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'v':
case 'V':
if (strncasecmp(buf, "vrfy ", 5) == 0)
{
printf("252 2.3.3 try RCPT to attempt delivery\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
default:
syntaxerr:
printf("500 5.5.2 Syntax error\r\n");
continue;
/* NOTREACHED */
break;
}
}
}
int
store(from, lmtprcpts)
char *from;
int lmtprcpts;
{
FILE *fp = NULL;
time_t tval;
bool eline;
bool fullline = TRUE; /* current line is terminated */
bool prevfl; /* previous line was terminated */
char line[2048];
int fd;
char tmpbuf[sizeof _PATH_LOCTMP + 1];
(void) umask(0077);
(void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL)
{
if (lmtprcpts)
{
printf("451 4.3.0 unable to open temporary file\r\n");
return -1;
}
else
{
mailerr("451 4.3.0", "unable to open temporary file");
exit(ExitVal);
}
}
(void) unlink(tmpbuf);
if (LMTPMode)
{
printf("354 go ahead\r\n");
(void) fflush(stdout);
}
(void) time(&tval);
(void) fprintf(fp, "From %s %s", from, ctime(&tval));
#ifdef CONTENTLENGTH
HeaderLength = 0;
BodyLength = -1;
#endif /* CONTENTLENGTH */
line[0] = '\0';
eline = TRUE;
while (fgets(line, sizeof(line), stdin) != (char *)NULL)
{
size_t line_len = 0;
int peek;
prevfl = fullline; /* preserve state of previous line */
while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
line_len++;
line_len++;
/* Check for dot-stuffing */
if (prevfl && lmtprcpts && line[0] == '.')
{
if (line[1] == '\n' ||
(line[1] == '\r' && line[2] == '\n'))
goto lmtpdot;
memcpy(line, line + 1, line_len);
line_len--;
}
/* Check to see if we have the full line from fgets() */
fullline = FALSE;
if (line_len > 0)
{
if (line[line_len - 1] == '\n')
{
if (line_len >= 2 &&
line[line_len - 2] == '\r')
{
line[line_len - 2] = '\n';
line[line_len - 1] = '\0';
line_len--;
}
fullline = TRUE;
}
else if (line[line_len - 1] == '\r')
{
/* Did we just miss the CRLF? */
peek = fgetc(stdin);
if (peek == '\n')
{
line[line_len - 1] = '\n';
fullline = TRUE;
}
else
(void) ungetc(peek, stdin);
}
}
else
fullline = TRUE;
#ifdef CONTENTLENGTH
if (prevfl && line[0] == '\n' && HeaderLength == 0)
{
eline = FALSE;
HeaderLength = ftell(fp);
if (HeaderLength <= 0)
{
/*
** shouldn't happen, unless ftell() is
** badly broken
*/
HeaderLength = -1;
}
}
#else /* CONTENTLENGTH */
if (prevfl && line[0] == '\n')
eline = TRUE;
#endif /* CONTENTLENGTH */
else
{
if (eline && line[0] == 'F' &&
!memcmp(line, "From ", 5))
- (void)putc('>', fp);
+ (void) putc('>', fp);
eline = FALSE;
#ifdef CONTENTLENGTH
/* discard existing "Content-Length:" headers */
if (prevfl && HeaderLength == 0 &&
(line[0] == 'C' || line[0] == 'c') &&
strncasecmp(line, ContentHdr, 15) == 0)
{
/*
** be paranoid: clear the line
** so no "wrong matches" may occur later
*/
line[0] = '\0';
continue;
}
#endif /* CONTENTLENGTH */
}
(void) fwrite(line, sizeof(char), line_len, fp);
if (ferror(fp))
{
if (lmtprcpts)
{
while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
(void) fclose(fp);
return -1;
}
else
{
mailerr("451 4.3.0",
"temporary file write error");
(void) fclose(fp);
exit(ExitVal);
}
}
}
if (lmtprcpts)
{
/* Got a premature EOF -- toss message and exit */
exit(EX_OK);
}
/* If message not newline terminated, need an extra. */
if (strchr(line, '\n') == NULL)
(void) putc('\n', fp);
lmtpdot:
#ifdef CONTENTLENGTH
BodyLength = ftell(fp);
if (HeaderLength == 0 && BodyLength > 0) /* empty body */
{
HeaderLength = BodyLength;
BodyLength = 0;
}
else
BodyLength = BodyLength - HeaderLength - 1 ;
if (HeaderLength > 0 && BodyLength >= 0)
{
extern char *quad_to_string();
if (sizeof BodyLength > sizeof(long))
snprintf(line, sizeof line, "%s\n",
quad_to_string(BodyLength));
else
- snprintf(line, sizeof line, "%ld\n", (long) BodyLength);
+ snprintf(line, sizeof line, "%ld\n",
+ (long) BodyLength);
strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16);
}
else
BodyLength = -1; /* Something is wrong here */
#endif /* CONTENTLENGTH */
/* Output a newline; note, empty messages are allowed. */
(void) putc('\n', fp);
if (fflush(fp) == EOF || ferror(fp) != 0)
{
if (lmtprcpts)
{
while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
(void) fclose(fp);
return -1;
}
else
{
mailerr("451 4.3.0", "temporary file write error");
(void) fclose(fp);
exit(ExitVal);
}
}
return fd;
}
void
deliver(fd, name, bouncequota)
int fd;
char *name;
bool bouncequota;
{
struct stat fsb;
struct stat sb;
struct passwd *pw;
char path[MAXPATHLEN];
int mbfd, nr = 0, nw, off;
char *p;
off_t curoff;
#ifdef CONTENTLENGTH
off_t headerbytes;
int readamount;
#endif /* CONTENTLENGTH */
char biffmsg[100], buf[8*1024];
extern char *quad_to_string();
/*
** Disallow delivery to unknown names -- special mailboxes can be
** handled in the sendmail aliases file.
*/
if ((pw = getpwnam(name)) == NULL)
{
if (ExitVal != EX_TEMPFAIL)
ExitVal = EX_UNAVAILABLE;
if (LMTPMode)
{
if (ExitVal == EX_TEMPFAIL)
- printf("451 4.3.0 cannot lookup name: %s\r\n", name);
+ printf("451 4.3.0 cannot lookup name: %s\r\n",
+ name);
else
printf("550 5.1.1 unknown name: %s\r\n", name);
}
else
{
char *errcode = NULL;
if (ExitVal == EX_TEMPFAIL)
errcode = "451 4.3.0";
else
errcode = "550 5.1.1";
mailerr(errcode, "unknown name: %s", name);
}
return;
}
endpwent();
/*
** Keep name reasonably short to avoid buffer overruns.
** This isn't necessary on BSD because of the proper
** definition of snprintf(), but it can cause problems
** on other systems.
** Also, clear out any bogus characters.
*/
if (strlen(name) > 40)
name[40] = '\0';
for (p = name; *p != '\0'; p++)
{
if (!isascii(*p))
*p &= 0x7f;
else if (!isprint(*p))
*p = '.';
}
(void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
/*
** If the mailbox is linked or a symlink, fail. There's an obvious
** race here, that the file was replaced with a symbolic link after
** the lstat returned, but before the open. We attempt to detect
** this by comparing the original stat information and information
** returned by an fstat of the file descriptor returned by the open.
**
** NB: this is a symptom of a larger problem, that the mail spooling
** directory is writeable by the wrong users. If that directory is
** writeable, system security is compromised for other reasons, and
** it cannot be fixed here.
**
** If we created the mailbox, set the owner/group. If that fails,
** just return. Another process may have already opened it, so we
** can't unlink it. Historically, binmail set the owner/group at
** each mail delivery. We no longer do this, assuming that if the
** ownership or permissions were changed there was a reason.
**
** XXX
** open(2) should support flock'ing the file.
*/
tryagain:
#ifdef MAILLOCK
p = name;
#else /* MAILLOCK */
p = path;
#endif /* MAILLOCK */
if ((off = lockmbox(p)) != 0)
{
if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
{
ExitVal = EX_TEMPFAIL;
mailerr("451 4.3.0",
"lockmailbox %s failed; error code %d %s",
p, off, errno > 0 ? errstring(errno) : "");
}
else
{
mailerr("551 5.3.0",
"lockmailbox %s failed; error code %d %s",
p, off, errno > 0 ? errstring(errno) : "");
}
return;
}
if (lstat(path, &sb) < 0)
{
int save_errno;
int mode = S_IRUSR|S_IWUSR;
- gid_t gid = pw->pw_gid;
+ gid_t gid = U_GID;
#ifdef MAILGID
(void) umask(0007);
gid = MAILGID;
mode |= S_IRGRP|S_IWGRP;
#endif /* MAILGID */
- mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, mode);
-
+ mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE,
+ mode);
save_errno = errno;
if (lstat(path, &sb) < 0)
{
ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0",
"%s: lstat: file changed after open", path);
goto err1;
}
- else
- sb.st_uid = pw->pw_uid;
if (mbfd == -1)
{
if (save_errno == EEXIST)
goto tryagain;
+
+ /* open failed, don't try again */
+ mailerr("450 4.2.0", "%s: %s", path,
+ errstring(save_errno));
+ goto err0;
}
- else if (fchown(mbfd, pw->pw_uid, gid) < 0)
+ else if (fchown(mbfd, U_UID, gid) < 0)
{
mailerr("451 4.3.0", "chown %u.%u: %s",
- pw->pw_uid, gid, name);
+ U_UID, gid, name);
goto err1;
}
+ else
+ {
+ /*
+ ** open() was successful, now close it so can
+ ** be opened as the right owner again.
+ ** Paranoia: reset mbdf since the file descriptor
+ ** is no longer valid; better safe than sorry.
+ */
+
+ sb.st_uid = U_UID;
+ (void) close(mbfd);
+ mbfd = -1;
+ }
}
else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode))
{
mailerr("550 5.2.0", "%s: irregular file", path);
goto err0;
}
- else if (sb.st_uid != pw->pw_uid)
+ else if (sb.st_uid != U_UID)
{
ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0", "%s: wrong ownership (%d)",
path, sb.st_uid);
goto err0;
}
- else
- mbfd = open(path, O_APPEND|O_WRONLY, 0);
- if (mbfd == -1)
+ /* change UID for quota checks */
+ if (setreuid(0, U_UID) < 0)
{
+ mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
+ U_UID, errstring(errno), getuid(), geteuid());
+ goto err1;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "new euid = %d\n", geteuid());
+#endif /* DEBUG */
+ mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0);
+ if (mbfd < 0)
+ {
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err0;
}
else if (fstat(mbfd, &fsb) < 0 ||
fsb.st_nlink != 1 ||
sb.st_nlink != 1 ||
!S_ISREG(fsb.st_mode) ||
sb.st_dev != fsb.st_dev ||
sb.st_ino != fsb.st_ino ||
-#if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */
+# if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */
sb.st_gen != fsb.st_gen ||
-#endif /* HAS_ST_GEN && 0 */
+# endif /* HAS_ST_GEN && 0 */
sb.st_uid != fsb.st_uid)
{
ExitVal = EX_TEMPFAIL;
mailerr("550 5.2.0", "%s: fstat: file changed after open",
path);
goto err1;
}
/* Wait until we can get a lock on the file. */
if (flock(mbfd, LOCK_EX) < 0)
{
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err1;
}
if (!nobiff)
{
/* Get the starting offset of the new message for biff. */
curoff = lseek(mbfd, (off_t)0, SEEK_END);
if (sizeof curoff > sizeof(long))
- (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
- name, quad_to_string(curoff));
+ (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
+ name, quad_to_string(curoff));
else
- (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
- name, curoff);
+ (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
+ name, (long) curoff);
}
/* Copy the message into the file. */
if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
{
mailerr("450 4.2.0", "temporary file: %s",
errstring(errno));
goto err1;
}
- if (setreuid(0, pw->pw_uid) < 0)
- {
- mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
- pw->pw_uid, errstring(errno), getuid(), geteuid());
- goto err1;
- }
#ifdef DEBUG
- fprintf(stderr, "new euid = %d\n", geteuid());
+ fprintf(stderr, "before writing: euid = %d\n", geteuid());
#endif /* DEBUG */
#ifdef CONTENTLENGTH
headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
for (;;)
{
if (headerbytes == 0)
{
snprintf(buf, sizeof buf, "%s", ContentHdr);
nr = strlen(buf);
headerbytes = -1;
readamount = 0;
}
else if (headerbytes > sizeof(buf) || headerbytes < 0)
readamount = sizeof(buf);
else
readamount = headerbytes;
if (readamount != 0)
nr = read(fd, buf, readamount);
if (nr <= 0)
break;
if (headerbytes > 0)
headerbytes -= nr ;
#else /* CONTENTLENGTH */
while ((nr = read(fd, buf, sizeof(buf))) > 0)
{
#endif /* CONTENTLENGTH */
for (off = 0; off < nr; off += nw)
{
if ((nw = write(mbfd, buf + off, nr - off)) < 0)
{
#ifdef EDQUOT
if (errno == EDQUOT && bouncequota)
mailerr("552 5.2.2", "%s: %s",
path, errstring(errno));
else
#endif /* EDQUOT */
mailerr("450 4.2.0", "%s: %s",
path, errstring(errno));
goto err3;
}
}
}
if (nr < 0)
{
mailerr("450 4.2.0", "temporary file: %s",
errstring(errno));
goto err3;
}
/* Flush to disk, don't wait for update. */
if (!nofsync && fsync(mbfd) < 0)
{
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
err3:
if (setreuid(0, 0) < 0)
{
#if 0
/* already printed an error above for this recipient */
(void) e_to_sys(errno);
mailerr("450 4.2.0", "setreuid(0, 0): %s",
errstring(errno));
#endif /* 0 */
}
#ifdef DEBUG
fprintf(stderr, "reset euid = %d\n", geteuid());
#endif /* DEBUG */
(void) ftruncate(mbfd, curoff);
-err1: (void) close(mbfd);
+err1: if (mbfd >= 0)
+ (void) close(mbfd);
err0: unlockmbox();
return;
}
/* Close and check -- NFS doesn't write until the close. */
if (close(mbfd))
{
#ifdef EDQUOT
if (errno == EDQUOT && bouncequota)
mailerr("552 5.2.2", "%s: %s", path, errstring(errno));
else
#endif /* EDQUOT */
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
(void) truncate(path, curoff);
}
else if (!nobiff)
notifybiff(biffmsg);
if (setreuid(0, 0) < 0)
{
mailerr("450 4.2.0", "setreuid(0, 0): %s",
errstring(errno));
goto err0;
}
#ifdef DEBUG
fprintf(stderr, "reset euid = %d\n", geteuid());
#endif /* DEBUG */
unlockmbox();
if (LMTPMode)
printf("250 2.1.5 %s OK\r\n", name);
}
/*
** user.lock files are necessary for compatibility with other
** systems, e.g., when the mail spool file is NFS exported.
** Alas, mailbox locking is more than just a local matter.
** EPA 11/94.
*/
bool Locked = FALSE;
#ifdef MAILLOCK
int
lockmbox(name)
char *name;
{
- int r;
+ int r = 0;
if (Locked)
return 0;
if ((r = maillock(name, 15)) == L_SUCCESS)
{
Locked = TRUE;
return 0;
}
switch (r)
{
case L_TMPLOCK: /* Can't create tmp file */
case L_TMPWRITE: /* Can't write pid into lockfile */
case L_MAXTRYS: /* Failed after retrycnt attempts */
errno = 0;
r = EX_TEMPFAIL;
break;
case L_ERROR: /* Check errno for reason */
r = errno;
break;
default: /* other permanent errors */
errno = 0;
r = EX_UNAVAILABLE;
break;
}
return r;
}
void
unlockmbox()
{
if (Locked)
mailunlock();
Locked = FALSE;
}
#else /* MAILLOCK */
char LockName[MAXPATHLEN];
int
lockmbox(path)
char *path;
{
int statfailed = 0;
time_t start;
if (Locked)
return 0;
if (strlen(path) + 6 > sizeof LockName)
return EX_SOFTWARE;
(void) snprintf(LockName, sizeof LockName, "%s.lock", path);
(void) time(&start);
for (; ; sleep(5))
{
int fd;
struct stat st;
time_t now;
/* global timeout */
(void) time(&now);
if (now > start + LOCKTO_GLOB)
{
errno = 0;
return EX_TEMPFAIL;
}
fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, 0);
if (fd >= 0)
{
/* defeat lock checking programs which test pid */
(void) write(fd, "0", 2);
Locked = TRUE;
(void) close(fd);
return 0;
}
if (stat(LockName, &st) < 0)
{
if (statfailed++ > 5)
{
errno = 0;
return EX_TEMPFAIL;
}
continue;
}
statfailed = 0;
(void) time(&now);
if (now < st.st_ctime + LOCKTO_RM)
continue;
/* try to remove stale lockfile */
if (unlink(LockName) < 0)
return errno;
}
}
void
unlockmbox()
{
if (!Locked)
return;
(void) unlink(LockName);
Locked = FALSE;
}
#endif /* MAILLOCK */
void
notifybiff(msg)
char *msg;
{
static bool initialized = FALSE;
static int f = -1;
struct hostent *hp;
struct servent *sp;
int len;
static struct sockaddr_in addr;
if (!initialized)
{
initialized = TRUE;
/* Be silent if biff service not available. */
if ((sp = getservbyname("biff", "udp")) == NULL ||
(hp = gethostbyname("localhost")) == NULL ||
hp->h_length != INADDRSZ)
return;
addr.sin_family = hp->h_addrtype;
memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ);
addr.sin_port = sp->s_port;
}
/* No message, just return */
if (msg == NULL)
return;
/* Couldn't initialize addr struct */
if (addr.sin_family == AF_UNSPEC)
return;
if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return;
len = strlen(msg) + 1;
(void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr));
}
void
usage()
{
ExitVal = EX_USAGE;
- mailerr(NULL, "usage: mail.local [-B] [-l] [-f from] [-s] user ...");
+ mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-l] [-f from] user ...");
exit(ExitVal);
}
void
#ifdef __STDC__
mailerr(const char *hdr, const char *fmt, ...)
#else /* __STDC__ */
mailerr(hdr, fmt, va_alist)
const char *hdr;
const char *fmt;
va_dcl
#endif /* __STDC__ */
{
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else /* __STDC__ */
va_start(ap);
#endif /* __STDC__ */
if (LMTPMode)
{
if (hdr != NULL)
printf("%s ", hdr);
(void) vprintf(fmt, ap);
(void) printf("\r\n");
}
else
{
(void) e_to_sys(errno);
vwarn(fmt, ap);
}
}
void
vwarn(fmt, ap)
const char *fmt;
_BSD_VA_LIST_ ap;
{
/*
** Log the message to stderr.
**
** Don't use LOG_PERROR as an openlog() flag to do this,
** it's not portable enough.
*/
if (ExitVal != EX_USAGE)
(void) fprintf(stderr, "mail.local: ");
(void) vfprintf(stderr, fmt, ap);
(void) fprintf(stderr, "\n");
#if USE_VSYSLOG
/* Log the message to syslog. */
vsyslog(LOG_ERR, fmt, ap);
#else /* USE_VSYSLOG */
{
char fmtbuf[10240];
(void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap);
syslog(LOG_ERR, "%s", fmtbuf);
}
#endif /* USE_VSYSLOG */
}
/*
* e_to_sys --
* Guess which errno's are temporary. Gag me.
*/
int
e_to_sys(num)
int num;
{
/* Temporary failures override hard errors. */
if (ExitVal == EX_TEMPFAIL)
return ExitVal;
switch (num) /* Hopefully temporary errors. */
{
#ifdef EDQUOT
case EDQUOT: /* Disc quota exceeded */
if (bouncequota)
{
ExitVal = EX_UNAVAILABLE;
break;
}
/* FALLTHROUGH */
#endif /* EDQUOT */
#ifdef EAGAIN
case EAGAIN: /* Resource temporarily unavailable */
#endif /* EAGAIN */
#ifdef EBUSY
case EBUSY: /* Device busy */
#endif /* EBUSY */
#ifdef EPROCLIM
case EPROCLIM: /* Too many processes */
#endif /* EPROCLIM */
#ifdef EUSERS
case EUSERS: /* Too many users */
#endif /* EUSERS */
#ifdef ECONNABORTED
case ECONNABORTED: /* Software caused connection abort */
#endif /* ECONNABORTED */
#ifdef ECONNREFUSED
case ECONNREFUSED: /* Connection refused */
#endif /* ECONNREFUSED */
#ifdef ECONNRESET
case ECONNRESET: /* Connection reset by peer */
#endif /* ECONNRESET */
#ifdef EDEADLK
case EDEADLK: /* Resource deadlock avoided */
#endif /* EDEADLK */
#ifdef EFBIG
case EFBIG: /* File too large */
#endif /* EFBIG */
#ifdef EHOSTDOWN
case EHOSTDOWN: /* Host is down */
#endif /* EHOSTDOWN */
#ifdef EHOSTUNREACH
case EHOSTUNREACH: /* No route to host */
#endif /* EHOSTUNREACH */
#ifdef EMFILE
case EMFILE: /* Too many open files */
#endif /* EMFILE */
#ifdef ENETDOWN
case ENETDOWN: /* Network is down */
#endif /* ENETDOWN */
#ifdef ENETRESET
case ENETRESET: /* Network dropped connection on reset */
#endif /* ENETRESET */
#ifdef ENETUNREACH
case ENETUNREACH: /* Network is unreachable */
#endif /* ENETUNREACH */
#ifdef ENFILE
case ENFILE: /* Too many open files in system */
#endif /* ENFILE */
#ifdef ENOBUFS
case ENOBUFS: /* No buffer space available */
#endif /* ENOBUFS */
#ifdef ENOMEM
case ENOMEM: /* Cannot allocate memory */
#endif /* ENOMEM */
#ifdef ENOSPC
case ENOSPC: /* No space left on device */
#endif /* ENOSPC */
#ifdef EROFS
case EROFS: /* Read-only file system */
#endif /* EROFS */
#ifdef ESTALE
case ESTALE: /* Stale NFS file handle */
#endif /* ESTALE */
#ifdef ETIMEDOUT
case ETIMEDOUT: /* Connection timed out */
#endif /* ETIMEDOUT */
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
case EWOULDBLOCK: /* Operation would block. */
#endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */
ExitVal = EX_TEMPFAIL;
break;
default:
ExitVal = EX_UNAVAILABLE;
break;
}
return ExitVal;
}
#if defined(ultrix) || defined(_CRAY)
/*
* Copyright (c) 1987, 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.
*/
# if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
# endif /* defined(LIBC_SCCS) && !defined(lint) */
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <errno.h>
# include <stdio.h>
# include <ctype.h>
static int _gettemp();
mkstemp(path)
char *path;
{
int fd;
return (_gettemp(path, &fd) ? fd : -1);
}
# if 0
char *
mktemp(path)
char *path;
{
return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
}
# endif /* 0 */
static
_gettemp(path, doopen)
char *path;
register int *doopen;
{
extern int errno;
register char *start, *trv;
struct stat sbuf;
u_int pid;
pid = getpid();
for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
while (*--trv == 'X')
{
*trv = (pid % 10) + '0';
pid /= 10;
}
/*
* check the target directory; if you have six X's and it
* doesn't exist this runs for a *very* long time.
*/
for (start = trv + 1;; --trv)
{
if (trv <= path)
break;
if (*trv == '/')
{
*trv = '\0';
if (stat(path, &sbuf) < 0)
return(0);
if (!S_ISDIR(sbuf.st_mode))
{
errno = ENOTDIR;
return(0);
}
*trv = '/';
break;
}
}
for (;;)
{
if (doopen)
{
- if ((*doopen =
- open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+ if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR,
+ 0600)) >= 0)
return(1);
if (errno != EEXIST)
return(0);
}
else if (stat(path, &sbuf) < 0)
return(errno == ENOENT ? 1 : 0);
/* tricky little algorithm for backward compatibility */
for (trv = start;;)
{
if (!*trv)
return(0);
if (*trv == 'z')
*trv++ = 'a';
else
{
if (isascii(*trv) && isdigit(*trv))
*trv = 'a';
else
++*trv;
break;
}
}
}
/* NOTREACHED */
}
#endif /* defined(ultrix) || defined(_CRAY) */
Index: head/contrib/sendmail/mailstats/mailstats.c
===================================================================
--- head/contrib/sendmail/mailstats/mailstats.c (revision 66496)
+++ head/contrib/sendmail/mailstats/mailstats.c (revision 66497)
@@ -1,318 +1,318 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*
*/
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.\n\
+"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
-static char id[] = "@(#)$Id: mailstats.c,v 8.53.16.10 2000/07/18 05:51:15 gshapiro Exp $";
+static char id[] = "@(#)$Id: mailstats.c,v 8.53.16.11 2000/09/17 17:04:26 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
#include <unistd.h>
#include <stddef.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
#endif /* EX_OK */
#include <sysexits.h>
#include <sendmail/sendmail.h>
#include <sendmail/mailstats.h>
#include <sendmail/pathnames.h>
#define MNAMELEN 20 /* max length of mailer name */
int
main(argc, argv)
int argc;
char **argv;
{
register int i;
int mno;
int save_errno;
int ch, fd;
char *sfile;
char *cfile;
FILE *cfp;
bool mnames;
bool progmode;
long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0;
long dismsgs = 0;
time_t now;
char mtable[MAXMAILERS][MNAMELEN + 1];
char sfilebuf[MAXLINE];
char buf[MAXLINE];
struct statistics stats;
extern char *ctime();
extern char *optarg;
extern int optind;
cfile = _PATH_SENDMAILCF;
sfile = NULL;
mnames = TRUE;
progmode = FALSE;
while ((ch = getopt(argc, argv, "C:f:op")) != -1)
{
switch (ch)
{
case 'C':
cfile = optarg;
break;
case 'f':
sfile = optarg;
break;
case 'o':
mnames = FALSE;
break;
case 'p':
progmode = TRUE;
break;
case '?':
default:
usage:
(void) fputs("usage: mailstats [-C cffile] [-f stfile] [-o] [-p]\n",
stderr);
exit(EX_USAGE);
}
}
argc -= optind;
argv += optind;
if (argc != 0)
goto usage;
if ((cfp = fopen(cfile, "r")) == NULL)
{
save_errno = errno;
fprintf(stderr, "mailstats: ");
errno = save_errno;
perror(cfile);
exit(EX_NOINPUT);
}
mno = 0;
(void) strlcpy(mtable[mno++], "prog", MNAMELEN + 1);
(void) strlcpy(mtable[mno++], "*file*", MNAMELEN + 1);
(void) strlcpy(mtable[mno++], "*include*", MNAMELEN + 1);
while (fgets(buf, sizeof(buf), cfp) != NULL)
{
register char *b;
char *s;
register char *m;
b = buf;
switch (*b++)
{
case 'M': /* mailer definition */
break;
case 'O': /* option -- see if .st file */
if (strncasecmp(b, " StatusFile", 11) == 0 &&
!(isascii(b[11]) && isalnum(b[11])))
{
/* new form -- find value */
b = strchr(b, '=');
if (b == NULL)
continue;
while (isascii(*++b) && isspace(*b))
continue;
}
else if (*b++ != 'S')
{
/* something else boring */
continue;
}
/* this is the S or StatusFile option -- save it */
if (strlcpy(sfilebuf, b, sizeof sfilebuf) >=
sizeof sfilebuf)
{
fprintf(stderr,
"StatusFile filename too long: %.30s...\n",
b);
exit(EX_CONFIG);
}
b = strchr(sfilebuf, '#');
if (b == NULL)
b = strchr(sfilebuf, '\n');
if (b == NULL)
b = &sfilebuf[strlen(sfilebuf)];
while (isascii(*--b) && isspace(*b))
continue;
*++b = '\0';
if (sfile == NULL)
sfile = sfilebuf;
default:
continue;
}
if (mno >= MAXMAILERS)
{
fprintf(stderr,
"Too many mailers defined, %d max.\n",
MAXMAILERS);
exit(EX_SOFTWARE);
}
m = mtable[mno];
s = m + MNAMELEN; /* is [MNAMELEN + 1] */
while (*b != ',' && !(isascii(*b) && isspace(*b)) &&
*b != '\0' && m < s)
*m++ = *b++;
*m = '\0';
for (i = 0; i < mno; i++)
{
if (strcmp(mtable[i], mtable[mno]) == 0)
break;
}
if (i == mno)
mno++;
}
(void) fclose(cfp);
for (; mno < MAXMAILERS; mno++)
mtable[mno][0]='\0';
if (sfile == NULL)
{
fprintf(stderr, "mailstats: no statistics file located\n");
exit (EX_OSFILE);
}
fd = open(sfile, O_RDONLY);
if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0)
{
save_errno = errno;
(void) fputs("mailstats: ", stderr);
errno = save_errno;
perror(sfile);
exit(EX_NOINPUT);
}
if (i == 0)
{
(void) sleep(1);
if ((i = read(fd, &stats, sizeof stats)) < 0)
{
save_errno = errno;
(void) fputs("mailstats: ", stderr);
errno = save_errno;
perror(sfile);
exit(EX_NOINPUT);
}
else if (i == 0)
{
memset((ARBPTR_T) &stats, '\0', sizeof stats);
(void) time(&stats.stat_itime);
}
}
if (i != 0)
{
if (stats.stat_magic != STAT_MAGIC)
{
fprintf(stderr,
"mailstats: incorrect magic number in %s\n",
sfile);
exit(EX_OSERR);
}
else if (stats.stat_version != STAT_VERSION)
{
fprintf(stderr,
"mailstats version (%d) incompatible with %s version (%d)\n",
STAT_VERSION, sfile, stats.stat_version);
exit(EX_OSERR);
}
else if (i != sizeof stats || stats.stat_size != sizeof(stats))
{
(void) fputs("mailstats: file size changed.\n", stderr);
exit(EX_OSERR);
}
}
if (progmode)
{
(void) time(&now);
printf("%ld %ld\n", (long) stats.stat_itime, (long) now);
}
else
{
printf("Statistics from %s", ctime(&stats.stat_itime));
printf(" M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis%s\n",
mnames ? " Mailer" : "");
}
for (i = 0; i < MAXMAILERS; i++)
{
if (stats.stat_nf[i] || stats.stat_nt[i] ||
stats.stat_nr[i] || stats.stat_nd[i])
{
char *format;
if (progmode)
format = "%2d %8ld %10ld %8ld %10ld %6ld %6ld";
else
format = "%2d %8ld %10ldK %8ld %10ldK %6ld %6ld";
printf(format, i,
stats.stat_nf[i], stats.stat_bf[i],
stats.stat_nt[i], stats.stat_bt[i],
stats.stat_nr[i], stats.stat_nd[i]);
if (mnames)
printf(" %s", mtable[i]);
printf("\n");
frmsgs += stats.stat_nf[i];
frbytes += stats.stat_bf[i];
tomsgs += stats.stat_nt[i];
tobytes += stats.stat_bt[i];
rejmsgs += stats.stat_nr[i];
dismsgs += stats.stat_nd[i];
}
}
if (progmode)
{
printf(" T %8ld %10ld %8ld %10ld %6ld %6ld\n",
frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
printf(" C %8ld %8ld %6ld\n",
stats.stat_cf, stats.stat_ct, stats.stat_cr);
(void) close(fd);
fd = open(sfile, O_RDWR | O_TRUNC);
if (fd >= 0)
(void) close(fd);
}
else
{
printf("=============================================================\n");
printf(" T %8ld %10ldK %8ld %10ldK %6ld %6ld\n",
frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
printf(" C %8ld %10s %8ld %10s %6ld\n",
stats.stat_cf, "", stats.stat_ct, "", stats.stat_cr);
}
exit(EX_OK);
/* NOTREACHED */
return EX_OK;
}
Index: head/contrib/sendmail/makemap/makemap.c
===================================================================
--- head/contrib/sendmail/makemap/makemap.c (revision 66496)
+++ head/contrib/sendmail/makemap/makemap.c (revision 66497)
@@ -1,576 +1,576 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1992 Eric P. Allman. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
-static char id[] = "@(#)$Id: makemap.c,v 8.135.4.10 2000/07/18 05:41:39 gshapiro Exp $";
+static char id[] = "@(#)$Id: makemap.c,v 8.135.4.11 2000/09/13 01:11:10 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
#include <sys/types.h>
#ifndef ISC_UNIX
# include <sys/file.h>
#endif /* ! ISC_UNIX */
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
#endif /* EX_OK */
#include <sysexits.h>
#include <sendmail/sendmail.h>
#include <sendmail/pathnames.h>
#include <libsmdb/smdb.h>
uid_t RealUid;
gid_t RealGid;
char *RealUserName;
uid_t RunAsUid;
uid_t RunAsGid;
char *RunAsUserName;
int Verbose = 2;
bool DontInitGroups = FALSE;
uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
#define BUFSIZE 1024
#if _FFR_DELIM
# define ISSEP(c) ((sep == '\0' && isascii(c) && isspace(c)) || (c) == sep)
#else /* _FFR_DELIM */
# define ISSEP(c) (isascii(c) && isspace(c))
#endif /* _FFR_DELIM */
static void
usage(progname)
char *progname;
{
fprintf(stderr,
"Usage: %s [-C cffile] [-N] [-c cachesize] [-d] [-e] [-f] [-l] [-o] [-r] [-s] %s[-u] [-v] type mapname\n",
progname,
#if _FFR_DELIM
"[-t delimiter] "
#else /* _FFR_DELIM */
""
#endif /* _FFR_DELIM */
);
exit(EX_USAGE);
}
int
main(argc, argv)
int argc;
char **argv;
{
char *progname;
char *cfile;
bool inclnull = FALSE;
bool notrunc = FALSE;
bool allowreplace = FALSE;
bool allowempty = FALSE;
bool verbose = FALSE;
bool foldcase = TRUE;
bool unmake = FALSE;
#if _FFR_DELIM
char sep = '\0';
#endif /* _FFR_DELIM */
int exitstat;
int opt;
char *typename = NULL;
char *mapname = NULL;
int lineno;
int st;
int mode;
int smode;
int putflags = 0;
long sff = SFF_ROOTOK|SFF_REGONLY;
struct passwd *pw;
SMDB_DATABASE *database;
SMDB_CURSOR *cursor;
SMDB_DBENT db_key, db_val;
SMDB_DBPARAMS params;
SMDB_USER_INFO user_info;
char ibuf[BUFSIZE];
#if HASFCHOWN
FILE *cfp;
char buf[MAXLINE];
#endif /* HASFCHOWN */
static char rnamebuf[MAXNAME]; /* holds RealUserName */
extern char *optarg;
extern int optind;
memset(&params, '\0', sizeof params);
params.smdbp_cache_size = 1024 * 1024;
progname = strrchr(argv[0], '/');
if (progname != NULL)
progname++;
else
progname = argv[0];
cfile = _PATH_SENDMAILCF;
clrbitmap(DontBlameSendmail);
RunAsUid = RealUid = getuid();
RunAsGid = RealGid = getgid();
pw = getpwuid(RealUid);
if (pw != NULL)
(void) strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
else
(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
(int) RealUid);
RunAsUserName = RealUserName = rnamebuf;
user_info.smdbu_id = RunAsUid;
user_info.smdbu_group_id = RunAsGid;
(void) strlcpy(user_info.smdbu_name, RunAsUserName,
SMDB_MAX_USER_NAME_LEN);
#define OPTIONS "C:Nc:t:deflorsuv"
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'C':
cfile = optarg;
break;
case 'N':
inclnull = TRUE;
break;
case 'c':
params.smdbp_cache_size = atol(optarg);
break;
case 'd':
params.smdbp_allow_dup = TRUE;
break;
case 'e':
allowempty = TRUE;
break;
case 'f':
foldcase = FALSE;
break;
case 'l':
smdb_print_available_types();
exit(EX_OK);
break;
case 'o':
notrunc = TRUE;
break;
case 'r':
allowreplace = TRUE;
break;
case 's':
setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
break;
#if _FFR_DELIM
case 't':
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid separator\n");
break;
}
sep = *optarg;
break;
#endif /* _FFR_DELIM */
case 'u':
unmake = TRUE;
break;
case 'v':
verbose = TRUE;
break;
default:
usage(progname);
/* NOTREACHED */
}
}
if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
sff |= SFF_NOSLINK;
if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
sff |= SFF_NOHLINK;
if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
sff |= SFF_NOWLINK;
argc -= optind;
argv += optind;
if (argc != 2)
{
usage(progname);
/* NOTREACHED */
}
else
{
typename = argv[0];
mapname = argv[1];
}
#if HASFCHOWN
/* Find TrustedUser value in sendmail.cf */
if ((cfp = fopen(cfile, "r")) == NULL)
{
fprintf(stderr, "makemap: %s: %s", cfile, errstring(errno));
exit(EX_NOINPUT);
}
while (fgets(buf, sizeof(buf), cfp) != NULL)
{
register char *b;
if ((b = strchr(buf, '\n')) != NULL)
*b = '\0';
b = buf;
switch (*b++)
{
case 'O': /* option */
if (strncasecmp(b, " TrustedUser", 12) == 0 &&
!(isascii(b[12]) && isalnum(b[12])))
{
b = strchr(b, '=');
if (b == NULL)
continue;
while (isascii(*++b) && isspace(*b))
continue;
if (isascii(*b) && isdigit(*b))
TrustedUid = atoi(b);
else
{
TrustedUid = 0;
pw = getpwnam(b);
if (pw == NULL)
fprintf(stderr,
"TrustedUser: unknown user %s\n", b);
else
TrustedUid = pw->pw_uid;
}
# ifdef UID_MAX
if (TrustedUid > UID_MAX)
{
fprintf(stderr,
"TrustedUser: uid value (%ld) > UID_MAX (%ld)",
(long) TrustedUid,
(long) UID_MAX);
TrustedUid = 0;
}
# endif /* UID_MAX */
break;
}
default:
continue;
}
}
(void) fclose(cfp);
#endif /* HASFCHOWN */
if (!params.smdbp_allow_dup && !allowreplace)
putflags = SMDBF_NO_OVERWRITE;
if (unmake)
{
mode = O_RDONLY;
smode = S_IRUSR;
}
else
{
mode = O_RDWR;
if (!notrunc)
{
mode |= O_CREAT|O_TRUNC;
sff |= SFF_CREAT;
}
smode = S_IWUSR;
}
params.smdbp_num_elements = 4096;
errno = smdb_open_database(&database, mapname, mode, smode, sff,
typename, &user_info, &params);
if (errno != SMDBE_OK)
{
char *hint;
if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
(hint = smdb_db_definition(typename)) != NULL)
fprintf(stderr,
"%s: Need to recompile with -D%s for %s support\n",
progname, hint, typename);
else
fprintf(stderr,
"%s: error opening type %s map %s: %s\n",
progname, typename, mapname, errstring(errno));
exit(EX_CANTCREAT);
}
(void) database->smdb_sync(database, 0);
- if (geteuid() == 0 && TrustedUid != 0)
+ if (!unmake && geteuid() == 0 && TrustedUid != 0)
{
errno = database->smdb_set_owner(database, TrustedUid, -1);
if (errno != SMDBE_OK)
{
fprintf(stderr,
"WARNING: ownership change on %s failed %s",
mapname, errstring(errno));
}
}
/*
** Copy the data
*/
exitstat = EX_OK;
if (unmake)
{
bool stop;
errno = database->smdb_cursor(database, &cursor, 0);
if (errno != SMDBE_OK)
{
fprintf(stderr,
"%s: cannot make cursor for type %s map %s\n",
progname, typename, mapname);
exit(EX_SOFTWARE);
}
memset(&db_key, '\0', sizeof db_key);
memset(&db_val, '\0', sizeof db_val);
for (stop = FALSE, lineno = 0; !stop; lineno++)
{
errno = cursor->smdbc_get(cursor, &db_key, &db_val,
SMDB_CURSOR_GET_NEXT);
if (errno != SMDBE_OK)
{
stop = TRUE;
}
if (!stop)
printf("%.*s\t%.*s\n",
(int) db_key.data.size,
(char *) db_key.data.data,
(int) db_val.data.size,
(char *)db_val.data.data);
}
(void) cursor->smdbc_close(cursor);
}
else
{
lineno = 0;
while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
{
register char *p;
lineno++;
/*
** Parse the line.
*/
p = strchr(ibuf, '\n');
if (p != NULL)
*p = '\0';
else if (!feof(stdin))
{
fprintf(stderr,
"%s: %s: line %d: line too long (%ld bytes max)\n",
progname, mapname, lineno, (long) sizeof ibuf);
exitstat = EX_DATAERR;
continue;
}
if (ibuf[0] == '\0' || ibuf[0] == '#')
continue;
if (
#if _FFR_DELIM
sep == '\0' &&
#endif /* _FFR_DELIM */
isascii(ibuf[0]) && isspace(ibuf[0]))
{
fprintf(stderr,
"%s: %s: line %d: syntax error (leading space)\n",
progname, mapname, lineno);
exitstat = EX_DATAERR;
continue;
}
memset(&db_key, '\0', sizeof db_key);
memset(&db_val, '\0', sizeof db_val);
db_key.data.data = ibuf;
for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
{
if (foldcase && isascii(*p) && isupper(*p))
*p = tolower(*p);
}
db_key.data.size = p - ibuf;
if (inclnull)
db_key.data.size++;
if (*p != '\0')
*p++ = '\0';
while (ISSEP(*p))
p++;
if (!allowempty && *p == '\0')
{
fprintf(stderr,
"%s: %s: line %d: no RHS for LHS %s\n",
progname, mapname, lineno,
(char *) db_key.data.data);
exitstat = EX_DATAERR;
continue;
}
db_val.data.data = p;
db_val.data.size = strlen(p);
if (inclnull)
db_val.data.size++;
/*
** Do the database insert.
*/
if (verbose)
{
printf("key=`%s', val=`%s'\n",
(char *) db_key.data.data,
(char *) db_val.data.data);
}
errno = database->smdb_put(database, &db_key, &db_val,
putflags);
switch (errno)
{
case SMDBE_KEY_EXIST:
st = 1;
break;
case 0:
st = 0;
break;
default:
st = -1;
break;
}
if (st < 0)
{
fprintf(stderr,
"%s: %s: line %d: key %s: put error: %s\n",
progname, mapname, lineno,
(char *) db_key.data.data,
errstring(errno));
exitstat = EX_IOERR;
}
else if (st > 0)
{
fprintf(stderr,
"%s: %s: line %d: key %s: duplicate key\n",
progname, mapname,
lineno, (char *) db_key.data.data);
exitstat = EX_DATAERR;
}
}
}
/*
** Now close the database.
*/
errno = database->smdb_close(database);
if (errno != SMDBE_OK)
{
fprintf(stderr, "%s: close(%s): %s\n",
progname, mapname, errstring(errno));
exitstat = EX_IOERR;
}
smdb_free_database(database);
exit(exitstat);
/* NOTREACHED */
return exitstat;
}
/*VARARGS1*/
void
#ifdef __STDC__
message(const char *msg, ...)
#else /* __STDC__ */
message(msg, va_alist)
const char *msg;
va_dcl
#endif /* __STDC__ */
{
const char *m;
VA_LOCAL_DECL
m = msg;
if (isascii(m[0]) && isdigit(m[0]) &&
isascii(m[1]) && isdigit(m[1]) &&
isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
m += 4;
VA_START(msg);
(void) vfprintf(stderr, m, ap);
VA_END;
(void) fprintf(stderr, "\n");
}
/*VARARGS1*/
void
#ifdef __STDC__
syserr(const char *msg, ...)
#else /* __STDC__ */
syserr(msg, va_alist)
const char *msg;
va_dcl
#endif /* __STDC__ */
{
const char *m;
VA_LOCAL_DECL
m = msg;
if (isascii(m[0]) && isdigit(m[0]) &&
isascii(m[1]) && isdigit(m[1]) &&
isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
m += 4;
VA_START(msg);
(void) vfprintf(stderr, m, ap);
VA_END;
(void) fprintf(stderr, "\n");
}
Index: head/contrib/sendmail/rmail/rmail.c
===================================================================
--- head/contrib/sendmail/rmail/rmail.c (revision 66496)
+++ head/contrib/sendmail/rmail/rmail.c (revision 66497)
@@ -1,472 +1,482 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
-static char id[] = "@(#)$Id: rmail.c,v 8.39.4.5 2000/07/18 05:55:29 gshapiro Exp $";
+static char id[] = "@(#)$Id: rmail.c,v 8.39.4.8 2000/09/16 22:20:25 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
/*
* RMAIL -- UUCP mail server.
*
* This program reads the >From ... remote from ... lines that UUCP is so
* fond of and turns them into something reasonable. It then execs sendmail
* with various options built from these lines.
*
* The expected syntax is:
*
* <user> := [-a-z0-9]+
* <date> := ctime format
* <site> := [-a-z0-9!]+
* <blank line> := "^\n$"
* <from> := "From" <space> <user> <space> <date>
* [<space> "remote from" <space> <site>]
* <forward> := ">" <from>
* msg := <from> <forward>* <blank-line> <body>
*
* The output of rmail(8) compresses the <forward> lines into a single
* from path.
*
* The err(3) routine is included here deliberately to make this code
* a bit more portable.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef BSD4_4
# define FORK vfork
# include <paths.h>
#else /* BSD4_4 */
# define FORK fork
# ifndef _PATH_SENDMAIL
# define _PATH_SENDMAIL "/usr/lib/sendmail"
# endif /* ! _PATH_SENDMAIL */
#endif /* BSD4_4 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
#endif /* EX_OK */
#include <sysexits.h>
#ifndef MAX
# define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif /* ! MAX */
#ifndef __P
# ifdef __STDC__
# define __P(protos) protos
# else /* __STDC__ */
# define __P(protos) ()
# define const
# endif /* __STDC__ */
#endif /* ! __P */
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif /* ! STDIN_FILENO */
-#if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300
+#if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11)
# define HASSNPRINTF 1
-#endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 */
+#endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11) */
#if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
# define memmove(d, s, l) (bcopy((s), (d), (l)))
#endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */
#if !HASSNPRINTF
extern int snprintf __P((char *, size_t, const char *, ...));
#endif /* !HASSNPRINTF */
#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
# ifndef HASSTRERROR
# define HASSTRERROR 1
# endif /* ! HASSTRERROR */
#endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
#if defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__)
# undef WIFEXITED
# undef WEXITSTATUS
# define WIFEXITED(st) (((st) & 0377) == 0)
# define WEXITSTATUS(st) (((st) >> 8) & 0377)
#endif /* defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__) */
#include "sendmail/errstring.h"
static void err __P((int, const char *, ...));
static void usage __P((void));
static char *xalloc __P((int));
#define newstr(s) strcpy(xalloc(strlen(s) + 1), s)
static char *
xalloc(sz)
register int sz;
{
register char *p;
/* some systems can't handle size zero mallocs */
if (sz <= 0)
sz = 1;
p = malloc((unsigned) sz);
if (p == NULL)
err(EX_TEMPFAIL, "out of memory");
return (p);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int ch, debug, i, pdes[2], pid, status;
size_t fplen = 0, fptlen = 0, len;
off_t offset;
FILE *fp;
char *addrp = NULL, *domain, *p, *t;
char *from_path, *from_sys, *from_user;
- char *args[100], buf[2048], lbuf[2048];
+ char **args, buf[2048], lbuf[2048];
struct stat sb;
extern char *optarg;
extern int optind;
debug = 0;
domain = "UUCP"; /* Default "domain". */
while ((ch = getopt(argc, argv, "D:T")) != -1)
{
switch (ch)
{
case 'T':
debug = 1;
break;
case 'D':
domain = optarg;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
from_path = from_sys = from_user = NULL;
for (offset = 0; ; )
{
/* Get and nul-terminate the line. */
if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
exit(EX_DATAERR);
if ((p = strchr(lbuf, '\n')) == NULL)
err(EX_DATAERR, "line too long");
*p = '\0';
/* Parse lines until reach a non-"From" line. */
if (!strncmp(lbuf, "From ", 5))
addrp = lbuf + 5;
else if (!strncmp(lbuf, ">From ", 6))
addrp = lbuf + 6;
else if (offset == 0)
err(EX_DATAERR,
"missing or empty From line: %s", lbuf);
else
{
*p = '\n';
break;
}
if (addrp == NULL || *addrp == '\0')
err(EX_DATAERR, "corrupted From line: %s", lbuf);
/* Use the "remote from" if it exists. */
for (p = addrp; (p = strchr(p + 1, 'r')) != NULL; )
{
if (!strncmp(p, "remote from ", 12))
{
for (t = p += 12; *t != '\0'; ++t)
{
if (isascii(*t) && isspace(*t))
break;
}
*t = '\0';
if (debug)
fprintf(stderr, "remote from: %s\n", p);
break;
}
}
/* Else use the string up to the last bang. */
if (p == NULL)
{
if (*addrp == '!')
err(EX_DATAERR, "bang starts address: %s",
addrp);
else if ((t = strrchr(addrp, '!')) != NULL)
{
*t = '\0';
p = addrp;
addrp = t + 1;
if (*addrp == '\0')
err(EX_DATAERR,
"corrupted From line: %s", lbuf);
if (debug)
fprintf(stderr, "bang: %s\n", p);
}
}
/* 'p' now points to any system string from this line. */
if (p != NULL)
{
/* Nul terminate it as necessary. */
for (t = p; *t != '\0'; ++t)
{
if (isascii(*t) && isspace(*t))
break;
}
*t = '\0';
/* If the first system, copy to the from_sys string. */
if (from_sys == NULL)
{
from_sys = newstr(p);
if (debug)
fprintf(stderr, "from_sys: %s\n",
from_sys);
}
/* Concatenate to the path string. */
len = t - p;
if (from_path == NULL)
{
fplen = 0;
if ((from_path = malloc(fptlen = 256)) == NULL)
err(EX_TEMPFAIL, NULL);
}
if (fplen + len + 2 > fptlen)
{
fptlen += MAX(fplen + len + 2, 256);
if ((from_path = realloc(from_path,
fptlen)) == NULL)
err(EX_TEMPFAIL, NULL);
}
memmove(from_path + fplen, p, len);
fplen += len;
from_path[fplen++] = '!';
from_path[fplen] = '\0';
}
/* Save off from user's address; the last one wins. */
for (p = addrp; *p != '\0'; ++p)
{
if (isascii(*p) && isspace(*p))
break;
}
*p = '\0';
if (*addrp == '\0')
addrp = "<>";
if (from_user != NULL)
free(from_user);
from_user = newstr(addrp);
if (debug)
{
if (from_path != NULL)
fprintf(stderr, "from_path: %s\n", from_path);
fprintf(stderr, "from_user: %s\n", from_user);
}
if (offset != -1)
offset = (off_t)ftell(stdin);
}
+
+ /* Allocate args (with room for sendmail args as well as recipients */
+ args = (char **)xalloc(sizeof(*args) * (10 + argc));
+
i = 0;
args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */
+ args[i++] = "-G"; /* relay submission */
args[i++] = "-oee"; /* No errors, just status. */
#ifdef QUEUE_ONLY
args[i++] = "-odq"; /* Queue it, don't try to deliver. */
#else
args[i++] = "-odi"; /* Deliver in foreground. */
#endif
args[i++] = "-oi"; /* Ignore '.' on a line by itself. */
/* set from system and protocol used */
if (from_sys == NULL)
snprintf(buf, sizeof(buf), "-p%s", domain);
else if (strchr(from_sys, '.') == NULL)
snprintf(buf, sizeof(buf), "-p%s:%s.%s",
domain, from_sys, domain);
else
snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
args[i++] = newstr(buf);
/* Set name of ``from'' person. */
snprintf(buf, sizeof(buf), "-f%s%s",
from_path ? from_path : "", from_user);
args[i++] = newstr(buf);
/*
** Don't copy arguments beginning with - as they will be
** passed to sendmail and could be interpreted as flags.
** To prevent confusion of sendmail wrap < and > around
** the address (helps to pass addrs like @gw1,@gw2:aa@bb)
*/
- while (*argv)
+ while (*argv != NULL)
{
if (**argv == '-')
err(EX_USAGE, "dash precedes argument: %s", *argv);
if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
args[i++] = *argv;
else
{
len = strlen(*argv) + 3;
if ((args[i] = malloc(len)) == NULL)
err(EX_TEMPFAIL, "Cannot malloc");
snprintf(args[i++], len, "<%s>", *argv);
}
argv++;
+ argc--;
+
+ /* Paranoia check, argc used for args[] bound */
+ if (argc < 0)
+ err(EX_SOFTWARE, "Argument count mismatch");
}
- args[i] = 0;
+ args[i] = NULL;
if (debug)
{
fprintf(stderr, "Sendmail arguments:\n");
- for (i = 0; args[i]; i++)
+ for (i = 0; args[i] != NULL; i++)
fprintf(stderr, "\t%s\n", args[i]);
}
/*
** If called with a regular file as standard input, seek to the right
** position in the file and just exec sendmail. Could probably skip
** skip the stat, but it's not unreasonable to believe that a failed
** seek will cause future reads to fail.
*/
if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode))
{
if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
err(EX_TEMPFAIL, "stdin seek");
(void) execv(_PATH_SENDMAIL, args);
err(EX_OSERR, "%s", _PATH_SENDMAIL);
}
if (pipe(pdes) < 0)
err(EX_OSERR, NULL);
switch (pid = FORK())
{
case -1: /* Err. */
err(EX_OSERR, NULL);
/* NOTREACHED */
case 0: /* Child. */
if (pdes[0] != STDIN_FILENO)
{
(void) dup2(pdes[0], STDIN_FILENO);
(void) close(pdes[0]);
}
(void) close(pdes[1]);
(void) execv(_PATH_SENDMAIL, args);
_exit(127);
/* NOTREACHED */
}
if ((fp = fdopen(pdes[1], "w")) == NULL)
err(EX_OSERR, NULL);
(void) close(pdes[0]);
/* Copy the file down the pipe. */
do
{
(void) fprintf(fp, "%s", lbuf);
} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
if (ferror(stdin))
err(EX_TEMPFAIL, "stdin: %s", errstring(errno));
if (fclose(fp))
err(EX_OSERR, NULL);
if ((waitpid(pid, &status, 0)) == -1)
err(EX_OSERR, "%s", _PATH_SENDMAIL);
if (!WIFEXITED(status))
err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL);
if (WEXITSTATUS(status))
err(status, "%s: terminated with %d (non-zero) status",
_PATH_SENDMAIL, WEXITSTATUS(status));
exit(EX_OK);
/* NOTREACHED */
return EX_OK;
}
static void
usage()
{
(void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
exit(EX_USAGE);
}
#ifdef __STDC__
# include <stdarg.h>
#else /* __STDC__ */
# include <varargs.h>
#endif /* __STDC__ */
static void
#ifdef __STDC__
err(int eval, const char *fmt, ...)
#else /* __STDC__ */
err(eval, fmt, va_alist)
int eval;
const char *fmt;
va_dcl
#endif /* __STDC__ */
{
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else /* __STDC__ */
va_start(ap);
#endif /* __STDC__ */
(void) fprintf(stderr, "rmail: ");
(void) vfprintf(stderr, fmt, ap);
va_end(ap);
(void) fprintf(stderr, "\n");
exit(eval);
}
Index: head/contrib/sendmail/smrsh/smrsh.c
===================================================================
--- head/contrib/sendmail/smrsh/smrsh.c (revision 66496)
+++ head/contrib/sendmail/smrsh/smrsh.c (revision 66497)
@@ -1,381 +1,381 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1993 Eric P. Allman. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.\n\
+"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
-static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.4 2000/05/25 21:44:29 gshapiro Exp $";
+static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.5 2000/09/17 17:04:27 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
/*
** SMRSH -- sendmail restricted shell
**
** This is a patch to get around the prog mailer bugs in most
** versions of sendmail.
**
** Use this in place of /bin/sh in the "prog" mailer definition
** in your sendmail.cf file. You then create CMDDIR (owned by
** root, mode 755) and put links to any programs you want
** available to prog mailers in that directory. This should
** include things like "vacation" and "procmail", but not "sed"
** or "sh".
**
** Leading pathnames are stripped from program names so that
** existing .forward files that reference things like
** "/usr/bin/vacation" will continue to work.
**
** The following characters are completely illegal:
** < > ^ & ` ( ) \n \r
** The following characters are sometimes illegal:
** | &
** This is more restrictive than strictly necessary.
**
** To use this, add FEATURE(`smrsh') to your .mc file.
**
** This can be used on any version of sendmail.
**
** In loving memory of RTM. 11/02/93.
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/file.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifdef EX_OK
# undef EX_OK
#endif /* EX_OK */
#include <sysexits.h>
#include <syslog.h>
#include <stdlib.h>
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif /* ! TRUE */
/* directory in which all commands must reside */
#ifndef CMDDIR
# define CMDDIR "/usr/libexec/sm.bin"
#endif /* ! CMDDIR */
/* characters disallowed in the shell "-c" argument */
#define SPECIALS "<|>^();&`$\r\n"
/* default search path */
#ifndef PATH
# define PATH "/bin:/usr/bin"
#endif /* ! PATH */
#ifndef __P
# include "sendmail/cdefs.h"
#endif /* ! __P */
extern size_t strlcpy __P((char *, const char *, size_t));
extern size_t strlcat __P((char *, const char *, size_t));
char newcmdbuf[1000];
char *prg, *par;
/*
** ADDCMD -- add a string to newcmdbuf, check for overflow
**
** Parameters:
** s -- string to add
** cmd -- it's a command: prepend CMDDIR/
** len -- length of string to add
**
** Side Effects:
** changes newcmdbuf or exits with a failure.
**
*/
void
addcmd(s, cmd, len)
char *s;
int cmd;
int len;
{
if (s == NULL || *s == '\0')
return;
if (sizeof newcmdbuf - strlen(newcmdbuf) <=
len + (cmd ? (strlen(CMDDIR) + 1) : 0))
{
fprintf(stderr, "%s: command too long: %s\n", prg, par);
#ifndef DEBUG
syslog(LOG_WARNING, "command too long: %.40s", par);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
if (cmd)
{
(void) strlcat(newcmdbuf, CMDDIR, sizeof newcmdbuf);
(void) strlcat(newcmdbuf, "/", sizeof newcmdbuf);
}
(void) strlcat(newcmdbuf, s, sizeof newcmdbuf);
}
int
main(argc, argv)
int argc;
char **argv;
{
register char *p;
register char *q;
register char *r;
register char *cmd;
int i;
int isexec;
int save_errno;
char *newenv[2];
char cmdbuf[1000];
char pathbuf[1000];
char specialbuf[32];
#ifndef DEBUG
# ifndef LOG_MAIL
openlog("smrsh", 0);
# else /* ! LOG_MAIL */
openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
# endif /* ! LOG_MAIL */
#endif /* ! DEBUG */
(void) strlcpy(pathbuf, "PATH=", sizeof pathbuf);
(void) strlcat(pathbuf, PATH, sizeof pathbuf);
newenv[0] = pathbuf;
newenv[1] = NULL;
/*
** Do basic argv usage checking
*/
prg = argv[0];
par = argv[2];
if (argc != 3 || strcmp(argv[1], "-c") != 0)
{
fprintf(stderr, "Usage: %s -c command\n", prg);
#ifndef DEBUG
syslog(LOG_ERR, "usage");
#endif /* ! DEBUG */
exit(EX_USAGE);
}
/*
** Disallow special shell syntax. This is overly restrictive,
** but it should shut down all attacks.
** Be sure to include 8-bit versions, since many shells strip
** the address to 7 bits before checking.
*/
if (strlen(SPECIALS) * 2 >= sizeof specialbuf)
{
#ifndef DEBUG
syslog(LOG_ERR, "too many specials: %.40s", SPECIALS);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
(void) strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
for (p = specialbuf; *p != '\0'; p++)
*p |= '\200';
(void) strlcat(specialbuf, SPECIALS, sizeof specialbuf);
/*
** Do a quick sanity check on command line length.
*/
i = strlen(par);
if (i > (sizeof newcmdbuf - sizeof CMDDIR - 2))
{
fprintf(stderr, "%s: command too long: %s\n", prg, par);
#ifndef DEBUG
syslog(LOG_WARNING, "command too long: %.40s", par);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
q = par;
newcmdbuf[0] = '\0';
isexec = FALSE;
while (*q)
{
/*
** Strip off a leading pathname on the command name. For
** example, change /usr/ucb/vacation to vacation.
*/
/* strip leading spaces */
while (*q != '\0' && isascii(*q) && isspace(*q))
q++;
if (*q == '\0')
{
if (isexec)
{
fprintf(stderr, "%s: missing command to exec\n",
prg);
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
break;
}
/* find the end of the command name */
p = strpbrk(q, " \t");
if (p == NULL)
cmd = &q[strlen(q)];
else
{
*p = '\0';
cmd = p;
}
/* search backwards for last / (allow for 0200 bit) */
while (cmd > q)
{
if ((*--cmd & 0177) == '/')
{
cmd++;
break;
}
}
/* cmd now points at final component of path name */
/* allow a few shell builtins */
if (strcmp(q, "exec") == 0 && p != NULL)
{
addcmd("exec ", FALSE, strlen("exec "));
/* test _next_ arg */
q = ++p;
isexec = TRUE;
continue;
}
else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
{
addcmd(cmd, FALSE, strlen(cmd));
/* test following chars */
}
else
{
/*
** Check to see if the command name is legal.
*/
(void) strlcpy(cmdbuf, CMDDIR, sizeof cmdbuf);
(void) strlcat(cmdbuf, "/", sizeof cmdbuf);
(void) strlcat(cmdbuf, cmd, sizeof cmdbuf);
#ifdef DEBUG
printf("Trying %s\n", cmdbuf);
#endif /* DEBUG */
if (access(cmdbuf, X_OK) < 0)
{
/* oops.... crack attack possiblity */
fprintf(stderr,
"%s: %s not available for sendmail programs\n",
prg, cmd);
if (p != NULL)
*p = ' ';
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: attempt to use %s",
getuid(), cmd);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
/*
** Create the actual shell input.
*/
addcmd(cmd, TRUE, strlen(cmd));
}
isexec = FALSE;
if (p != NULL)
*p = ' ';
else
break;
r = strpbrk(p, specialbuf);
if (r == NULL) {
addcmd(p, FALSE, strlen(p));
break;
}
#if ALLOWSEMI
if (*r == ';') {
addcmd(p, FALSE, r - p + 1);
q = r + 1;
continue;
}
#endif /* ALLOWSEMI */
if ((*r == '&' && *(r + 1) == '&') ||
(*r == '|' && *(r + 1) == '|'))
{
addcmd(p, FALSE, r - p + 2);
q = r + 2;
continue;
}
fprintf(stderr, "%s: cannot use %c in command\n", prg, *r);
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
getuid(), *r, par);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
} /* end of while *q */
if (isexec)
{
fprintf(stderr, "%s: missing command to exec\n", prg);
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
/* make sure we created something */
if (newcmdbuf[0] == '\0')
{
fprintf(stderr, "Usage: %s -c command\n", prg);
#ifndef DEBUG
syslog(LOG_ERR, "usage");
#endif /* ! DEBUG */
exit(EX_USAGE);
}
/*
** Now invoke the shell
*/
#ifdef DEBUG
printf("%s\n", newcmdbuf);
#endif /* DEBUG */
(void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, NULL, newenv);
save_errno = errno;
#ifndef DEBUG
syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
#endif /* ! DEBUG */
errno = save_errno;
perror("/bin/sh");
exit(EX_OSFILE);
/* NOTREACHED */
return EX_OSFILE;
}
Index: head/contrib/sendmail/src/conf.c
===================================================================
--- head/contrib/sendmail/src/conf.c (revision 66496)
+++ head/contrib/sendmail/src/conf.c (revision 66497)
@@ -1,5700 +1,5707 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
-static char id[] = "@(#)$Id: conf.c,v 8.646.2.2.2.23 2000/07/15 17:35:18 gshapiro Exp $";
+static char id[] = "@(#)$Id: conf.c,v 8.646.2.2.2.32 2000/09/23 00:31:33 ca Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
#include <sendmail.h>
#include <sendmail/pathnames.h>
# include <sys/ioctl.h>
# include <sys/param.h>
#include <limits.h>
#if NETINET || NETINET6
# include <arpa/inet.h>
#endif /* NETINET || NETINET6 */
#if HASULIMIT && defined(HPUX11)
# include <ulimit.h>
#endif /* HASULIMIT && defined(HPUX11) */
static void setupmaps __P((void));
static void setupmailers __P((void));
static int get_num_procs_online __P((void));
/*
** 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, NULL },
{ "resent-from", H_FROM|H_RESENT, NULL },
{ "resent-reply-to", H_FROM|H_RESENT, NULL },
{ "sender", H_FROM, NULL },
{ "from", H_FROM, NULL },
{ "reply-to", H_FROM, NULL },
{ "errors-to", H_FROM|H_ERRORSTO, NULL },
{ "full-name", H_ACHECK, NULL },
{ "return-receipt-to", H_RECEIPTTO, NULL },
/* destination fields */
{ "to", H_RCPT, NULL },
{ "resent-to", H_RCPT|H_RESENT, NULL },
{ "cc", H_RCPT, NULL },
{ "resent-cc", H_RCPT|H_RESENT, NULL },
{ "bcc", H_RCPT|H_BCC, NULL },
{ "resent-bcc", H_RCPT|H_BCC|H_RESENT, NULL },
{ "apparently-to", H_RCPT, NULL },
/* message identification and control */
{ "message-id", 0, NULL },
{ "resent-message-id", H_RESENT, NULL },
{ "message", H_EOH, NULL },
{ "text", H_EOH, NULL },
/* date fields */
{ "date", 0, NULL },
{ "resent-date", H_RESENT, NULL },
/* trace fields */
{ "received", H_TRACE|H_FORCE, NULL },
{ "x400-received", H_TRACE|H_FORCE, NULL },
{ "via", H_TRACE|H_FORCE, NULL },
{ "mail-from", H_TRACE|H_FORCE, NULL },
/* miscellaneous fields */
{ "comments", H_FORCE|H_ENCODABLE, NULL },
{ "return-path", H_FORCE|H_ACHECK|H_BINDLATE, NULL },
{ "content-transfer-encoding", H_CTE, NULL },
{ "content-type", H_CTYPE, NULL },
{ "content-length", H_ACHECK, NULL },
{ "subject", H_ENCODABLE, NULL },
{ "x-authentication-warning", H_FORCE, NULL },
{ NULL, 0, NULL }
};
/*
** 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 },
{ "noetrn", PRIV_NOETRN },
{ "noverb", PRIV_NOVERB },
{ "authwarnings", PRIV_AUTHWARNINGS },
{ "noreceipts", PRIV_NORECEIPTS },
{ "nobodyreturn", PRIV_NOBODYRETN },
{ "goaway", PRIV_GOAWAY },
{ NULL, 0 }
};
/*
** DontBlameSendmail values
*/
struct dbsval DontBlameSendmailValues[] =
{
{ "safe", DBS_SAFE },
{ "assumesafechown", DBS_ASSUMESAFECHOWN },
{ "groupwritabledirpathsafe", DBS_GROUPWRITABLEDIRPATHSAFE },
{ "groupwritableforwardfilesafe",
DBS_GROUPWRITABLEFORWARDFILESAFE },
{ "groupwritableincludefilesafe",
DBS_GROUPWRITABLEINCLUDEFILESAFE },
{ "groupwritablealiasfile", DBS_GROUPWRITABLEALIASFILE },
{ "worldwritablealiasfile", DBS_WORLDWRITABLEALIASFILE },
{ "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH },
{ "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH },
{ "mapinunsafedirpath", DBS_MAPINUNSAFEDIRPATH },
{ "linkedaliasfileinwritabledir",
DBS_LINKEDALIASFILEINWRITABLEDIR },
{ "linkedclassfileinwritabledir",
DBS_LINKEDCLASSFILEINWRITABLEDIR },
{ "linkedforwardfileinwritabledir",
DBS_LINKEDFORWARDFILEINWRITABLEDIR },
{ "linkedincludefileinwritabledir",
DBS_LINKEDINCLUDEFILEINWRITABLEDIR },
{ "linkedmapinwritabledir", DBS_LINKEDMAPINWRITABLEDIR },
{ "linkedserviceswitchfileinwritabledir",
DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR },
{ "filedeliverytohardlink", DBS_FILEDELIVERYTOHARDLINK },
{ "filedeliverytosymlink", DBS_FILEDELIVERYTOSYMLINK },
{ "writemaptohardlink", DBS_WRITEMAPTOHARDLINK },
{ "writemaptosymlink", DBS_WRITEMAPTOSYMLINK },
{ "writestatstohardlink", DBS_WRITESTATSTOHARDLINK },
{ "writestatstosymlink", DBS_WRITESTATSTOSYMLINK },
{ "forwardfileingroupwritabledirpath",
DBS_FORWARDFILEINGROUPWRITABLEDIRPATH },
{ "includefileingroupwritabledirpath",
DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH },
{ "classfileinunsafedirpath", DBS_CLASSFILEINUNSAFEDIRPATH },
{ "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH },
{ "helpfileinunsafedirpath", DBS_HELPFILEINUNSAFEDIRPATH },
{ "forwardfileinunsafedirpathsafe",
DBS_FORWARDFILEINUNSAFEDIRPATHSAFE },
{ "includefileinunsafedirpathsafe",
DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
{ "runprograminunsafedirpath", DBS_RUNPROGRAMINUNSAFEDIRPATH },
{ "runwritableprogram", DBS_RUNWRITABLEPROGRAM },
{ "nonrootsafeaddr", DBS_NONROOTSAFEADDR },
{ "truststickybit", DBS_TRUSTSTICKYBIT },
{ "dontwarnforwardfileinunsafedirpath",
DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH },
{ "insufficiententropy", DBS_INSUFFICIENTENTROPY },
#if _FFR_UNSAFE_SASL
{ "groupreadablesaslfile", DBS_GROUPREADABLESASLFILE },
#endif /* _FFR_UNSAFE_SASL */
+#if _FFR_UNSAFE_WRITABLE_INCLUDE
+ { "groupwritableforwardfile", DBS_GROUPWRITABLEFORWARDFILE },
+ { "groupwritableincludefile", DBS_GROUPWRITABLEINCLUDEFILE },
+ { "worldwritableforwardfile", DBS_WORLDWRITABLEFORWARDFILE },
+ { "worldwritableincludefile", DBS_WORLDWRITABLEINCLUDEFILE },
+#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */
{ NULL, 0 }
};
/*
** Miscellaneous stuff.
*/
int DtableSize = 50; /* max open files; reset in 4.2bsd */
/*
** 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 MINUTES * 60
#define HOURS * 60 MINUTES
#define DAYS * 24 HOURS
#ifndef MAXRULERECURSION
# define MAXRULERECURSION 50 /* max ruleset recursion depth */
#endif /* ! MAXRULERECURSION */
void
setdefaults(e)
register ENVELOPE *e;
{
int i;
int numprocs;
struct passwd *pw;
numprocs = get_num_procs_online();
SpaceSub = ' '; /* option B */
QueueLA = 8 * numprocs; /* option x */
RefuseLA = 12 * numprocs; /* 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 */
#if _FFR_QUEUE_FILE_MODE
QueueFileMode = (RealUid != geteuid()) ? 0644 : 0600;
/* option QueueFileMode */
#endif /* _FFR_QUEUE_FILE_MODE */
if (((pw = sm_getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
((pw = sm_getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
((pw = sm_getpwnam("daemon")) != NULL && pw->pw_uid != 0))
{
DefUid = pw->pw_uid; /* option u */
DefGid = pw->pw_gid; /* option g */
DefUser = newstr(pw->pw_name);
}
else
{
DefUid = 1; /* option u */
DefGid = 1; /* option g */
setdefuser();
}
TrustedUid = 0;
if (tTd(37, 4))
dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
DefUser != NULL ? DefUser : "<1:1>",
(int) DefUid, (int) DefGid);
CheckpointInterval = 10; /* option C */
MaxHopCount = 25; /* option h */
set_delivery_mode(SM_FORK, e); /* option d */
e->e_errormode = EM_PRINT; /* option e */
e->e_queuedir = NOQDIR;
e->e_ctime = curtime();
SevenBitInput = FALSE; /* option 7 */
MaxMciCache = 1; /* option k */
MciCacheTimeout = 5 MINUTES; /* option K */
LogLevel = 9; /* option L */
inittimeouts(NULL, FALSE); /* option r */
PrivacyFlags = PRIV_PUBLIC; /* option p */
MeToo = TRUE; /* option m */
SendMIMEErrors = TRUE; /* option f */
SuperSafe = TRUE; /* option s */
clrbitmap(DontBlameSendmail); /* DontBlameSendmail option */
#if MIME8TO7
MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */
#else /* MIME8TO7 */
MimeMode = MM_PASS8BIT;
#endif /* MIME8TO7 */
for (i = 0; i < MAXTOCLASS; i++)
{
TimeOuts.to_q_return[i] = 5 DAYS; /* option T */
TimeOuts.to_q_warning[i] = 0; /* option T */
}
ServiceSwitchFile = "/etc/mail/service.switch";
ServiceCacheMaxAge = (time_t) 10;
HostsFile = _PATH_HOSTS;
PidFile = newstr(_PATH_SENDMAILPID);
MustQuoteChars = "@,;:\\()[].'";
MciInfoTimeout = 30 MINUTES;
MaxRuleRecursion = MAXRULERECURSION;
MaxAliasRecursion = 10;
MaxMacroRecursion = 10;
ColonOkInAddr = TRUE;
DontLockReadFiles = TRUE;
DoubleBounceAddr = "postmaster";
MaxHeadersLength = MAXHDRSLEN;
MaxForwardEntries = 0;
#if SASL
AuthMechanisms = newstr(AUTH_MECHANISMS);
#endif /* SASL */
#ifdef HESIOD_INIT
HesiodContext = NULL;
#endif /* HESIOD_INIT */
#if NETINET6
/* Detect if IPv6 is available at run time */
i = socket(AF_INET6, SOCK_STREAM, 0);
if (i >= 0)
{
InetMode = AF_INET6;
(void) close(i);
}
else
InetMode = AF_INET;
#else /* NETINET6 */
InetMode = AF_INET;
#endif /* NETINET6 */
ControlSocketName = NULL;
memset(&ConnectOnlyTo, '\0', sizeof ConnectOnlyTo);
DataFileBufferSize = 4096;
XscriptFileBufferSize = 4096;
for (i = 0; i < MAXRWSETS; i++)
RuleSetNames[i] = NULL;
#if _FFR_MILTER
InputFilters[0] = NULL;
#endif /* _FFR_MILTER */
setupmaps();
setupmailers();
setupheaders();
}
/*
** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
*/
void
setdefuser()
{
struct passwd *defpwent;
static char defuserbuf[40];
DefUser = defuserbuf;
defpwent = sm_getpwuid(DefUid);
snprintf(defuserbuf, sizeof defuserbuf, "%s",
defpwent == NULL ? "nobody" : defpwent->pw_name);
if (tTd(37, 4))
dprintf("setdefuser: DefUid=%d, DefUser=%s\n",
(int) DefUid, DefUser);
}
/*
** SETUPMAILERS -- initialize default mailers
*/
static void
setupmailers()
{
char buf[100];
(void) strlcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u",
sizeof buf);
makemailer(buf);
(void) strlcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=X-Unix/X-Unix/X-Unix, A=FILE \201u",
sizeof buf);
makemailer(buf);
(void) strlcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u",
sizeof buf);
makemailer(buf);
initerrmailers();
}
/*
** 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; \
}
static void
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 /* NEWDB */
#ifdef NDBM
MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
map_parseargs, ndbm_map_open, ndbm_map_close,
ndbm_map_lookup, ndbm_map_store);
#endif /* NDBM */
#ifdef NIS
MAPDEF("nis", NULL, MCF_ALIASOK,
map_parseargs, nis_map_open, null_map_close,
nis_map_lookup, null_map_store);
#endif /* NIS */
#ifdef NISPLUS
MAPDEF("nisplus", NULL, MCF_ALIASOK,
map_parseargs, nisplus_map_open, null_map_close,
nisplus_map_lookup, null_map_store);
#endif /* NISPLUS */
#ifdef LDAPMAP
MAPDEF("ldap", NULL, MCF_ALIASOK,
ldapmap_parseargs, ldapmap_open, ldapmap_close,
ldapmap_lookup, null_map_store);
/* Deprecated */
MAPDEF("ldapx", NULL, MCF_ALIASOK,
ldapx_map_parseargs, ldapmap_open, ldapmap_close,
ldapmap_lookup, null_map_store);
#endif /* LDAPMAP */
#ifdef PH_MAP
MAPDEF("ph", NULL, 0,
ph_map_parseargs, ph_map_open, ph_map_close,
ph_map_lookup, null_map_store);
#endif /* PH_MAP */
#if MAP_NSD
/* IRIX 6.5 nsd support */
MAPDEF("nsd", NULL, MCF_ALIASOK,
map_parseargs, null_map_open, null_map_close,
nsd_map_lookup, null_map_store);
#endif /* MAP_NSD */
#ifdef HESIOD
MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
map_parseargs, hes_map_open, null_map_close,
hes_map_lookup, null_map_store);
#endif /* HESIOD */
#if NETINFO
MAPDEF("netinfo", NULL, MCF_ALIASOK,
map_parseargs, ni_map_open, null_map_close,
ni_map_lookup, null_map_store);
#endif /* NETINFO */
#if 0
MAPDEF("dns", NULL, 0,
dns_map_init, null_map_open, null_map_close,
dns_map_lookup, null_map_store);
#endif /* 0 */
#if NAMED_BIND
/* best MX DNS lookup */
MAPDEF("bestmx", NULL, MCF_OPTFILE,
map_parseargs, null_map_open, null_map_close,
bestmx_map_lookup, null_map_store);
#endif /* NAMED_BIND */
MAPDEF("host", NULL, 0,
host_map_init, null_map_open, null_map_close,
host_map_lookup, null_map_store);
MAPDEF("text", NULL, MCF_ALIASOK,
map_parseargs, text_map_open, null_map_close,
text_map_lookup, null_map_store);
MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
map_parseargs, stab_map_open, null_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);
/* access to system passwd file */
MAPDEF("user", NULL, MCF_OPTFILE,
map_parseargs, user_map_open, null_map_close,
user_map_lookup, null_map_store);
/* dequote map */
MAPDEF("dequote", NULL, 0,
dequote_init, null_map_open, null_map_close,
dequote_map, null_map_store);
#ifdef MAP_REGEX
MAPDEF("regex", NULL, 0,
regex_map_init, null_map_open, null_map_close,
regex_map_lookup, null_map_store);
#endif /* MAP_REGEX */
#if USERDB
/* user database */
MAPDEF("userdb", ".db", 0,
map_parseargs, null_map_open, null_map_close,
udb_map_lookup, null_map_store);
#endif /* USERDB */
/* arbitrary programs */
MAPDEF("program", NULL, MCF_ALIASOK,
map_parseargs, null_map_open, null_map_close,
prog_map_lookup, null_map_store);
/* sequenced maps */
MAPDEF("sequence", NULL, MCF_ALIASOK,
seq_map_parse, null_map_open, null_map_close,
seq_map_lookup, seq_map_store);
/* switched interface to sequenced maps */
MAPDEF("switch", NULL, MCF_ALIASOK,
map_parseargs, switch_map_open, null_map_close,
seq_map_lookup, seq_map_store);
/* null map lookup -- really for internal use only */
MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE,
map_parseargs, null_map_open, null_map_close,
null_map_lookup, null_map_store);
/* syslog map -- logs information to syslog */
MAPDEF("syslog", NULL, 0,
syslog_map_parseargs, null_map_open, null_map_close,
syslog_map_lookup, null_map_store);
/* macro storage map -- rulesets can set macros */
MAPDEF("macro", NULL, 0,
dequote_init, null_map_open, null_map_close,
macro_map_lookup, null_map_store);
/* arithmetic map -- add/subtract/compare */
MAPDEF("arith", NULL, 0,
dequote_init, null_map_open, null_map_close,
arith_map_lookup, null_map_store);
if (tTd(38, 2))
{
/* bogus map -- always return tempfail */
MAPDEF("bogus", NULL, MCF_ALIASOK|MCF_OPTFILE,
map_parseargs, null_map_open, null_map_close,
bogus_map_lookup, null_map_store);
}
}
#undef MAPDEF
/*
** INITHOSTMAPS -- initial host-dependent maps
**
** This should act as an interface to any local service switch
** provided by the host operating system.
**
** Parameters:
** none
**
** Returns:
** none
**
** Side Effects:
** Should define maps "host" and "users" as necessary
** for this OS. If they are not defined, they will get
** a default value later. It should check to make sure
** they are not defined first, since it's possible that
** the config file has provided an override.
*/
void
inithostmaps()
{
register int i;
int nmaps;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
char buf[MAXLINE];
/*
** Set up default hosts maps.
*/
#if 0
nmaps = switch_map_find("hosts", maptype, mapreturn);
for (i = 0; i < nmaps; i++)
{
if (strcmp(maptype[i], "files") == 0 &&
stab("hosts.files", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts",
sizeof buf);
(void) makemapentry(buf);
}
# if NAMED_BIND
else if (strcmp(maptype[i], "dns") == 0 &&
stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "hosts.dns dns A", sizeof buf);
(void) makemapentry(buf);
}
# endif /* NAMED_BIND */
# ifdef NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "hosts.nisplus nisplus -k name -v address hosts.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NISPLUS */
# ifdef NIS
else if (strcmp(maptype[i], "nis") == 0 &&
stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "hosts.nis nis -k 0 -v 1 hosts.byname",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NIS */
# if NETINFO
else if (strcmp(maptype[i], "netinfo") == 0) &&
stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "hosts.netinfo netinfo -v name /machines",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NETINFO */
}
#endif /* 0 */
/*
** Make sure we have a host map.
*/
if (stab("host", ST_MAP, ST_FIND) == NULL)
{
/* user didn't initialize: set up host map */
(void) strlcpy(buf, "host host", sizeof buf);
#if NAMED_BIND
if (ConfigLevel >= 2)
(void) strlcat(buf, " -a. -D", sizeof buf);
#endif /* NAMED_BIND */
(void) makemapentry(buf);
}
/*
** Set up default aliases maps
*/
nmaps = switch_map_find("aliases", maptype, mapreturn);
for (i = 0; i < nmaps; i++)
{
if (strcmp(maptype[i], "files") == 0 &&
stab("aliases.files", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases.files null", sizeof buf);
(void) makemapentry(buf);
}
#ifdef NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion mail_aliases.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NISPLUS */
#ifdef NIS
else if (strcmp(maptype[i], "nis") == 0 &&
stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases.nis nis mail.aliases",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NIS */
#if NETINFO
else if (strcmp(maptype[i], "netinfo") == 0 &&
stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases.netinfo netinfo -z, /aliases",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NETINFO */
#ifdef HESIOD
else if (strcmp(maptype[i], "hesiod") == 0 &&
stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases.hesiod hesiod aliases",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* HESIOD */
}
if (stab("aliases", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "aliases switch aliases", sizeof buf);
(void) makemapentry(buf);
}
#if 0 /* "user" map class is a better choice */
/*
** Set up default users maps.
*/
nmaps = switch_map_find("passwd", maptype, mapreturn);
for (i = 0; i < nmaps; i++)
{
if (strcmp(maptype[i], "files") == 0 &&
stab("users.files", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd",
sizeof buf);
(void) makemapentry(buf);
}
# ifdef NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "users.nisplus nisplus -m -kname -vhome passwd.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NISPLUS */
# ifdef NIS
else if (strcmp(maptype[i], "nis") == 0 &&
stab("users.nis", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "users.nis nis -m passwd.byname",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NIS */
# ifdef HESIOD
else if (strcmp(maptype[i], "hesiod") == 0) &&
stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "users.hesiod hesiod", sizeof buf);
(void) makemapentry(buf);
}
# endif /* HESIOD */
}
if (stab("users", ST_MAP, ST_FIND) == NULL)
{
(void) strlcpy(buf, "users switch -m passwd", sizeof buf);
(void) makemapentry(buf);
}
#endif /* 0 */
}
/*
** SWITCH_MAP_FIND -- find the list of types associated with a map
**
** This is the system-dependent interface to the service switch.
**
** Parameters:
** service -- the name of the service of interest.
** maptype -- an out-array of strings containing the types
** of access to use for this service. There can
** be at most MAXMAPSTACK types for a single service.
** mapreturn -- an out-array of return information bitmaps
** for the map.
**
** Returns:
** The number of map types filled in, or -1 for failure.
**
** Side effects:
** Preserves errno so nothing in the routine clobbers it.
*/
#if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
# define _USE_SUN_NSSWITCH_
#endif /* defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) */
#ifdef _USE_SUN_NSSWITCH_
# include <nsswitch.h>
#endif /* _USE_SUN_NSSWITCH_ */
#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
# define _USE_DEC_SVC_CONF_
#endif /* defined(ultrix) || (defined(__osf__) && defined(__alpha)) */
#ifdef _USE_DEC_SVC_CONF_
# include <sys/svcinfo.h>
#endif /* _USE_DEC_SVC_CONF_ */
int
switch_map_find(service, maptype, mapreturn)
char *service;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
{
int svcno;
int save_errno = errno;
#ifdef _USE_SUN_NSSWITCH_
struct __nsw_switchconfig *nsw_conf;
enum __nsw_parse_err pserr;
struct __nsw_lookup *lk;
static struct __nsw_lookup lkp0 =
{ "files", {1, 0, 0, 0}, NULL, NULL };
static struct __nsw_switchconfig lkp_default =
{ 0, "sendmail", 3, &lkp0 };
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
lk = lkp_default.lookups;
else
lk = nsw_conf->lookups;
svcno = 0;
while (lk != NULL)
{
maptype[svcno] = lk->service_name;
if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
mapreturn[MA_NOTFOUND] |= 1 << svcno;
if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
mapreturn[MA_TRYAGAIN] |= 1 << svcno;
if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
mapreturn[MA_TRYAGAIN] |= 1 << svcno;
svcno++;
lk = lk->next;
}
errno = save_errno;
return svcno;
#endif /* _USE_SUN_NSSWITCH_ */
#ifdef _USE_DEC_SVC_CONF_
struct svcinfo *svcinfo;
int svc;
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
svcinfo = getsvc();
if (svcinfo == NULL)
goto punt;
if (strcmp(service, "hosts") == 0)
svc = SVC_HOSTS;
else if (strcmp(service, "aliases") == 0)
svc = SVC_ALIASES;
else if (strcmp(service, "passwd") == 0)
svc = SVC_PASSWD;
else
{
errno = save_errno;
return -1;
}
for (svcno = 0; svcno < SVC_PATHSIZE; svcno++)
{
switch (svcinfo->svcpath[svc][svcno])
{
case SVC_LOCAL:
maptype[svcno] = "files";
break;
case SVC_YP:
maptype[svcno] = "nis";
break;
case SVC_BIND:
maptype[svcno] = "dns";
break;
# ifdef SVC_HESIOD
case SVC_HESIOD:
maptype[svcno] = "hesiod";
break;
# endif /* SVC_HESIOD */
case SVC_LAST:
errno = save_errno;
return svcno;
}
}
errno = save_errno;
return svcno;
#endif /* _USE_DEC_SVC_CONF_ */
#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
/*
** Fall-back mechanism.
*/
STAB *st;
time_t now = curtime();
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge)
{
/* (re)read service switch */
register FILE *fp;
long sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
if (!bitnset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR,
DontBlameSendmail))
sff |= SFF_NOWLINK;
if (ConfigFileRead)
ServiceCacheTime = now;
fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
if (fp != NULL)
{
char buf[MAXLINE];
while (fgets(buf, sizeof buf, fp) != NULL)
{
register char *p;
p = strpbrk(buf, "#\n");
if (p != NULL)
*p = '\0';
p = strpbrk(buf, " \t");
if (p != NULL)
*p++ = '\0';
if (buf[0] == '\0')
continue;
if (p == NULL)
{
sm_syslog(LOG_ERR, NOQID,
"Bad line on %.100s: %.100s",
ServiceSwitchFile,
buf);
continue;
}
while (isspace(*p))
p++;
if (*p == '\0')
continue;
/*
** Find/allocate space for this service entry.
** Space for all of the service strings
** are allocated at once. This means
** that we only have to free the first
** one to free all of them.
*/
st = stab(buf, ST_SERVICE, ST_ENTER);
if (st->s_service[0] != NULL)
free((void *) st->s_service[0]);
p = newstr(p);
for (svcno = 0; svcno < MAXMAPSTACK; )
{
if (*p == '\0')
break;
st->s_service[svcno++] = p;
p = strpbrk(p, " \t");
if (p == NULL)
break;
*p++ = '\0';
while (isspace(*p))
p++;
}
if (svcno < MAXMAPSTACK)
st->s_service[svcno] = NULL;
}
(void) fclose(fp);
}
}
/* look up entry in cache */
st = stab(service, ST_SERVICE, ST_FIND);
if (st != NULL && st->s_service[0] != NULL)
{
/* extract data */
svcno = 0;
while (svcno < MAXMAPSTACK)
{
maptype[svcno] = st->s_service[svcno];
if (maptype[svcno++] == NULL)
break;
}
errno = save_errno;
return --svcno;
}
#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
#if !defined(_USE_SUN_NSSWITCH_)
/* if the service file doesn't work, use an absolute fallback */
# ifdef _USE_DEC_SVC_CONF_
punt:
# endif /* _USE_DEC_SVC_CONF_ */
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
svcno = 0;
if (strcmp(service, "aliases") == 0)
{
maptype[svcno++] = "files";
# if defined(AUTO_NETINFO_ALIASES) && defined (NETINFO)
maptype[svcno++] = "netinfo";
# endif /* defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) */
# ifdef AUTO_NIS_ALIASES
# ifdef NISPLUS
maptype[svcno++] = "nisplus";
# endif /* NISPLUS */
# ifdef NIS
maptype[svcno++] = "nis";
# endif /* NIS */
# endif /* AUTO_NIS_ALIASES */
errno = save_errno;
return svcno;
}
if (strcmp(service, "hosts") == 0)
{
# if NAMED_BIND
maptype[svcno++] = "dns";
# else /* NAMED_BIND */
# if defined(sun) && !defined(BSD)
/* SunOS */
maptype[svcno++] = "nis";
# endif /* defined(sun) && !defined(BSD) */
# endif /* NAMED_BIND */
# if defined(AUTO_NETINFO_HOSTS) && defined (NETINFO)
maptype[svcno++] = "netinfo";
# endif /* defined(AUTO_NETINFO_HOSTS) && defined (NETINFO) */
maptype[svcno++] = "files";
errno = save_errno;
return svcno;
}
errno = save_errno;
return -1;
#endif /* !defined(_USE_SUN_NSSWITCH_) */
}
/*
** 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 = sm_getpwuid(RealUid);
if (pw != NULL)
myname = newstr(pw->pw_name);
}
else
{
uid_t uid = RealUid;
myname = newstr(myname);
if ((pw = sm_getpwnam(myname)) == NULL ||
(uid != 0 && uid != pw->pw_uid))
{
pw = sm_getpwuid(uid);
if (pw != NULL)
myname = newstr(pw->pw_name);
}
}
if (myname == NULL || myname[0] == '\0')
{
syserr("554 5.3.0 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(S_IWOTH, 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 an EX_ code
** should be returned. You can also set to->q_status to
** a DSN-style status code.
**
** EF_NO_BODY_RETN can be set in e->e_flags to suppress the
** body during the return-to-sender function; this should be done
** on huge messages. This bit may already be set by the ESMTP
** protocol.
**
** Parameters:
** to -- the person being sent to.
**
** Returns:
** an exit status
**
** Side Effects:
** none (unless you include the usrerr stuff)
*/
int
checkcompat(to, e)
register ADDRESS *to;
register ENVELOPE *e;
{
if (tTd(49, 1))
dprintf("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 && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
to->q_mailer == s->s_mailer)
{
usrerr("553 No ARPA mail through this machine: see your system administration");
/* e->e_flags |= EF_NO_BODY_RETN; to suppress body on return */
to->q_status = "5.7.1";
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;
{
/*
** First, try for modern signal calls
** and restartable syscalls
*/
# ifdef SA_RESTART
struct sigaction n, o;
memset(&n, '\0', sizeof n);
# if USE_SA_SIGACTION
n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
n.sa_flags = SA_RESTART|SA_SIGINFO;
# else /* USE_SA_SIGACTION */
n.sa_handler = handler;
n.sa_flags = SA_RESTART;
# endif /* USE_SA_SIGACTION */
if (sigaction(sig, &n, &o) < 0)
return SIG_ERR;
return o.sa_handler;
# else /* SA_RESTART */
/*
** Else check for SYS5SIGNALS or
** BSD4_3 signals
*/
# if defined(SYS5SIGNALS) || defined(BSD4_3)
# ifdef BSD4_3
return signal(sig, handler);
# else /* BSD4_3 */
return sigset(sig, handler);
# endif /* BSD4_3 */
# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
/*
** Finally, if nothing else is available,
** go for a default
*/
struct sigaction n, o;
memset(&n, '\0', sizeof n);
n.sa_handler = handler;
if (sigaction(sig, &n, &o) < 0)
return SIG_ERR;
return o.sa_handler;
# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
# endif /* SA_RESTART */
}
/*
** BLOCKSIGNAL -- hold a signal to prevent delivery
**
** Parameters:
** sig -- the signal to block.
**
** Returns:
** 1 signal was previously blocked
** 0 signal was not previously blocked
** -1 on failure.
*/
int
blocksignal(sig)
int sig;
{
# ifdef BSD4_3
# ifndef sigmask
# define sigmask(s) (1 << ((s) - 1))
# endif /* ! sigmask */
return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
# else /* BSD4_3 */
# ifdef ALTOS_SYSTEM_V
sigfunc_t handler;
handler = sigset(sig, SIG_HOLD);
if (handler == SIG_ERR)
return -1;
else
return handler == SIG_HOLD;
# else /* ALTOS_SYSTEM_V */
sigset_t sset, oset;
(void) sigemptyset(&sset);
(void) sigaddset(&sset, sig);
if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
return -1;
else
return sigismember(&oset, sig);
# endif /* ALTOS_SYSTEM_V */
# endif /* BSD4_3 */
}
/*
** RELEASESIGNAL -- release a held signal
**
** Parameters:
** sig -- the signal to release.
**
** Returns:
** 1 signal was previously blocked
** 0 signal was not previously blocked
** -1 on failure.
*/
int
releasesignal(sig)
int sig;
{
# ifdef BSD4_3
return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
# else /* BSD4_3 */
# ifdef ALTOS_SYSTEM_V
sigfunc_t handler;
handler = sigset(sig, SIG_HOLD);
if (sigrelse(sig) < 0)
return -1;
else
return handler == SIG_HOLD;
# else /* ALTOS_SYSTEM_V */
sigset_t sset, oset;
(void) sigemptyset(&sset);
(void) sigaddset(&sset, sig);
if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
return -1;
else
return sigismember(&oset, sig);
# endif /* ALTOS_SYSTEM_V */
# endif /* BSD4_3 */
}
/*
** HOLDSIGS -- arrange to hold all signals
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** Arranges that signals are held.
*/
void
holdsigs()
{
}
/*
** RLSESIGS -- arrange to release all signals
**
** This undoes the effect of holdsigs.
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** Arranges that signals are released.
*/
void
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 /* _AUX_SOURCE */
#if SHARE_V1
# include <shares.h>
#endif /* SHARE_V1 */
void
init_md(argc, argv)
int argc;
char **argv;
{
#ifdef _AUX_SOURCE
setcompat(getcompat() | COMPAT_BSDPROT);
#endif /* _AUX_SOURCE */
#ifdef SUN_EXTENSIONS
init_md_sun();
#endif /* SUN_EXTENSIONS */
#if _CONVEX_SOURCE
/* keep gethostby*() from stripping the local domain name */
set_domain_trim_off();
#endif /* _CONVEX_SOURCE */
#ifdef __QNX__
/*
** Due to QNX's network distributed nature, you can target a tcpip
** stack on a different node in the qnx network; this patch lets
** this feature work. The __sock_locate() must be done before the
** environment is clear.
*/
__sock_locate();
#endif /* __QNX__ */
#if SECUREWARE || defined(_SCO_unix_)
set_auth_parameters(argc, argv);
# ifdef _SCO_unix_
/*
** This is required for highest security levels (the kernel
** won't let it call set*uid() or run setuid binaries without
** it). It may be necessary on other SECUREWARE systems.
*/
if (getluid() == -1)
setluid(0);
# endif /* _SCO_unix_ */
#endif /* SECUREWARE || defined(_SCO_unix_) */
#ifdef VENDOR_DEFAULT
VendorCode = VENDOR_DEFAULT;
#else /* VENDOR_DEFAULT */
VendorCode = VENDOR_BERKELEY;
#endif /* VENDOR_DEFAULT */
}
/*
** INIT_VENDOR_MACROS -- vendor-dependent macro initializations
**
** Called once, on startup.
**
** Parameters:
** e -- the global envelope.
**
** Returns:
** none.
**
** Side Effects:
** vendor-dependent.
*/
void
init_vendor_macros(e)
register ENVELOPE *e;
{
}
/*
** 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 */
#define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */
#define LA_DGUX 9 /* special DGUX implementation */
#define LA_HPUX 10 /* special HPUX implementation */
#define LA_IRIX6 11 /* special IRIX 6.2 implementation */
#define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */
#define LA_DEVSHORT 13 /* read short from a device */
#define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */
/* do guesses based on general OS type */
#ifndef LA_TYPE
# define LA_TYPE LA_ZERO
#endif /* ! LA_TYPE */
#ifndef FSHIFT
# if defined(unixpc)
# define FSHIFT 5
# endif /* defined(unixpc) */
# if defined(__alpha) || defined(IRIX)
# define FSHIFT 10
# endif /* defined(__alpha) || defined(IRIX) */
#endif /* ! FSHIFT */
#ifndef FSHIFT
# define FSHIFT 8
#endif /* ! FSHIFT */
#ifndef FSCALE
# define FSCALE (1 << FSHIFT)
#endif /* ! FSCALE */
#ifndef LA_AVENRUN
# ifdef SYSTEM5
# define LA_AVENRUN "avenrun"
# else /* SYSTEM5 */
# define LA_AVENRUN "_avenrun"
# endif /* SYSTEM5 */
#endif /* ! LA_AVENRUN */
/* _PATH_KMEM should be defined in <paths.h> */
#ifndef _PATH_KMEM
# define _PATH_KMEM "/dev/kmem"
#endif /* ! _PATH_KMEM */
#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
# include <nlist.h>
/* _PATH_UNIX should be defined in <paths.h> */
# ifndef _PATH_UNIX
# if defined(SYSTEM5)
# define _PATH_UNIX "/unix"
# else /* defined(SYSTEM5) */
# define _PATH_UNIX "/vmunix"
# endif /* defined(SYSTEM5) */
# endif /* ! _PATH_UNIX */
# ifdef _AUX_SOURCE
struct nlist Nl[2];
# else /* _AUX_SOURCE */
struct nlist Nl[] =
{
{ LA_AVENRUN },
{ 0 },
};
# endif /* _AUX_SOURCE */
# define X_AVENRUN 0
static int
getla()
{
static int kmem = -1;
# if LA_TYPE == LA_INT
long avenrun[3];
# else /* LA_TYPE == LA_INT */
# if LA_TYPE == LA_SHORT
short avenrun[3];
# else /* LA_TYPE == LA_SHORT */
double avenrun[3];
# endif /* LA_TYPE == LA_SHORT */
# endif /* LA_TYPE == LA_INT */
extern int errno;
extern off_t lseek();
if (kmem < 0)
{
# ifdef _AUX_SOURCE
(void) strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN,
sizeof Nl[X_AVENRUN].n_name);
Nl[1].n_name[0] = '\0';
# endif /* _AUX_SOURCE */
# if defined(_AIX3) || defined(_AIX4)
if (knlist(Nl, 1, sizeof Nl[0]) < 0)
# else /* defined(_AIX3) || defined(_AIX4) */
if (nlist(_PATH_UNIX, Nl) < 0)
# endif /* defined(_AIX3) || defined(_AIX4) */
{
if (tTd(3, 1))
dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
errstring(errno));
return -1;
}
if (Nl[X_AVENRUN].n_value == 0)
{
if (tTd(3, 1))
dprintf("getla: nlist(%s, %s) ==> 0\n",
_PATH_UNIX, LA_AVENRUN);
return -1;
}
# ifdef NAMELISTMASK
Nl[X_AVENRUN].n_value &= NAMELISTMASK;
# endif /* NAMELISTMASK */
kmem = open(_PATH_KMEM, 0, 0);
if (kmem < 0)
{
if (tTd(3, 1))
dprintf("getla: open(/dev/kmem): %s\n",
errstring(errno));
return -1;
}
(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
if (tTd(3, 20))
dprintf("getla: symbol address = %#lx\n",
(u_long) Nl[X_AVENRUN].n_value);
if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
{
/* thank you Ian */
if (tTd(3, 1))
dprintf("getla: lseek or read: %s\n",
errstring(errno));
return -1;
}
# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
if (tTd(3, 5))
{
# if LA_TYPE == LA_SHORT
dprintf("getla: avenrun = %d", avenrun[0]);
if (tTd(3, 15))
dprintf(", %d, %d", avenrun[1], avenrun[2]);
# else /* LA_TYPE == LA_SHORT */
dprintf("getla: avenrun = %ld", avenrun[0]);
if (tTd(3, 15))
dprintf(", %ld, %ld", avenrun[1], avenrun[2]);
# endif /* LA_TYPE == LA_SHORT */
dprintf("\n");
}
if (tTd(3, 1))
dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
# else /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
if (tTd(3, 5))
{
dprintf("getla: avenrun = %g", avenrun[0]);
if (tTd(3, 15))
dprintf(", %g, %g", avenrun[1], avenrun[2]);
dprintf("\n");
}
if (tTd(3, 1))
dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
return ((int) (avenrun[0] + 0.5));
# endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
}
#endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) */
#if LA_TYPE == LA_READKSYM
# include <sys/ksym.h>
static int
getla()
{
static int kmem = -1;
long avenrun[3];
extern int errno;
struct mioc_rksym mirk;
if (kmem < 0)
{
kmem = open("/dev/kmem", 0, 0);
if (kmem < 0)
{
if (tTd(3, 1))
dprintf("getla: open(/dev/kmem): %s\n",
errstring(errno));
return -1;
}
(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
mirk.mirk_symname = LA_AVENRUN;
mirk.mirk_buf = avenrun;
mirk.mirk_buflen = sizeof(avenrun);
if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
{
if (tTd(3, 1))
dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
errstring(errno));
return -1;
}
if (tTd(3, 5))
{
dprintf("getla: avenrun = %d", avenrun[0]);
if (tTd(3, 15))
dprintf(", %d, %d", avenrun[1], avenrun[2]);
dprintf("\n");
}
if (tTd(3, 1))
dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
}
#endif /* LA_TYPE == LA_READKSYM */
#if LA_TYPE == LA_DGUX
# include <sys/dg_sys_info.h>
static 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);
if (tTd(3, 1))
dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5));
return ((int) (load_info.one_minute + 0.5));
}
#endif /* LA_TYPE == LA_DGUX */
#if LA_TYPE == LA_HPUX
/* forward declarations to keep gcc from complaining */
struct pst_dynamic;
struct pst_status;
struct pst_static;
struct pst_vminfo;
struct pst_diskinfo;
struct pst_processor;
struct pst_lv;
struct pst_swapinfo;
# include <sys/param.h>
# include <sys/pstat.h>
static int
getla()
{
struct pst_dynamic pstd;
if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
(size_t) 1, 0) == -1)
return 0;
if (tTd(3, 1))
dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
return (int) (pstd.psd_avg_1_min + 0.5);
}
#endif /* LA_TYPE == LA_HPUX */
#if LA_TYPE == LA_SUBR
static int
getla()
{
double avenrun[3];
if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
{
if (tTd(3, 1))
dprintf("getla: getloadavg failed: %s",
errstring(errno));
return -1;
}
if (tTd(3, 1))
dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
return ((int) (avenrun[0] + 0.5));
}
#endif /* LA_TYPE == LA_SUBR */
#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 /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
# include <mach.h>
# endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
static int
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)
{
if (tTd(3, 1))
dprintf("getla: processor_set_default failed: %s",
errstring(errno));
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)
{
if (tTd(3, 1))
dprintf("getla: processor_set_info failed: %s",
errstring(errno));
return -1;
}
if (tTd(3, 1))
dprintf("getla: %d\n",
(int) ((info.load_average + (LOAD_SCALE / 2)) /
LOAD_SCALE));
return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
}
#endif /* LA_TYPE == LA_MACH */
#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 /* ! _PATH_LOADAVG */
static int
getla()
{
double avenrun;
register int result;
FILE *fp;
fp = fopen(_PATH_LOADAVG, "r");
if (fp == NULL)
{
if (tTd(3, 1))
dprintf("getla: fopen(%s): %s\n",
_PATH_LOADAVG, errstring(errno));
return -1;
}
result = fscanf(fp, "%lf", &avenrun);
(void) fclose(fp);
if (result != 1)
{
if (tTd(3, 1))
dprintf("getla: fscanf() = %d: %s\n",
result, errstring(errno));
return -1;
}
if (tTd(3, 1))
dprintf("getla(): %.2f\n", avenrun);
return ((int) (avenrun + 0.5));
}
#endif /* LA_TYPE == LA_PROCSTR */
#if LA_TYPE == LA_IRIX6
# include <sys/sysmp.h>
int getla(void)
{
static int kmem = -1;
int avenrun[3];
if (kmem < 0)
{
kmem = open(_PATH_KMEM, 0, 0);
if (kmem < 0)
{
if (tTd(3, 1))
dprintf("getla: open(%s): %s\n", _PATH_KMEM,
errstring(errno));
return -1;
}
(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
{
if (tTd(3, 1))
dprintf("getla: lseek or read: %s\n",
errstring(errno));
return -1;
}
if (tTd(3, 5))
{
dprintf("getla: avenrun = %ld", (long int) avenrun[0]);
if (tTd(3, 15))
dprintf(", %ld, %ld",
(long int) avenrun[1], (long int) avenrun[2]);
dprintf("\n");
}
if (tTd(3, 1))
dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
}
#endif /* LA_TYPE == LA_IRIX6 */
#if LA_TYPE == LA_KSTAT
# include <kstat.h>
static int
getla()
{
static kstat_ctl_t *kc = NULL;
static kstat_t *ksp = NULL;
kstat_named_t *ksn;
int la;
if (kc == NULL) /* if not initialized before */
kc = kstat_open();
if (kc == NULL)
{
if (tTd(3, 1))
dprintf("getla: kstat_open(): %s\n",
errstring(errno));
return -1;
}
if (ksp == NULL)
ksp = kstat_lookup(kc, "unix", 0, "system_misc");
if (ksp == NULL)
{
if (tTd(3, 1))
dprintf("getla: kstat_lookup(): %s\n",
errstring(errno));
return -1;
}
if (kstat_read(kc, ksp, NULL) < 0)
{
if (tTd(3, 1))
dprintf("getla: kstat_read(): %s\n",
errstring(errno));
return -1;
}
ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
/* kstat_close(kc); /o do not close for fast access */
return la;
}
#endif /* LA_TYPE == LA_KSTAT */
#if LA_TYPE == LA_DEVSHORT
/*
** Read /dev/table/avenrun for the load average. This should contain
** three shorts for the 1, 5, and 15 minute loads. We only read the
** first, since that's all we care about.
**
** Intended for SCO OpenServer 5.
*/
# ifndef _PATH_AVENRUN
# define _PATH_AVENRUN "/dev/table/avenrun"
# endif /* ! _PATH_AVENRUN */
static int
getla()
{
static int afd = -1;
short avenrun;
int loadav;
int r;
errno = EBADF;
if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
{
if (errno != EBADF)
return -1;
afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
if (afd < 0)
{
sm_syslog(LOG_ERR, NOQID,
"can't open %s: %m",
_PATH_AVENRUN);
return -1;
}
}
r = read(afd, &avenrun, sizeof avenrun);
if (tTd(3, 5))
dprintf("getla: avenrun = %d\n", avenrun);
loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
if (tTd(3, 1))
dprintf("getla: %d\n", loadav);
return loadav;
}
#endif /* LA_TYPE == LA_DEVSHORT */
#if LA_TYPE == LA_ALPHAOSF
struct rtentry;
struct mbuf;
# include <sys/table.h>
int getla()
{
int ave = 0;
struct tbl_loadavg tab;
if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
{
if (tTd(3, 1))
dprintf("getla: table %s\n", errstring(errno));
return -1;
}
if (tTd(3, 1))
dprintf("getla: scale = %d\n", tab.tl_lscale);
if (tab.tl_lscale)
ave = ((tab.tl_avenrun.l[2] + (tab.tl_lscale/2)) /
tab.tl_lscale);
else
ave = (int) (tab.tl_avenrun.d[2] + 0.5);
if (tTd(3, 1))
dprintf("getla: %d\n", ave);
return ave;
}
#endif /* LA_TYPE == LA_ALPHAOSF */
#if LA_TYPE == LA_ZERO
static int
getla()
{
if (tTd(3, 1))
dprintf("getla: ZERO\n");
return 0;
}
#endif /* LA_TYPE == LA_ZERO */
/*
* 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[] = "@(#)$OrigId: 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 */
/*
** SM_GETLA -- get the current load average and set macro
**
** Parameters:
** e -- the envelope for the load average macro.
**
** Returns:
** The current load average as an integer.
**
** Side Effects:
** Sets the load average macro ({load_avg}) if
** envelope e is not NULL.
*/
int
sm_getla(e)
ENVELOPE *e;
{
register int la;
la = getla();
if (e != NULL)
{
char labuf[8];
- snprintf(labuf, sizeof labuf, "%d", CurrentLA);
+ snprintf(labuf, sizeof labuf, "%d", la);
define(macid("{load_avg}", NULL), newstr(labuf), e);
}
return la;
}
/*
** 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.
** ct -- 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.
*/
/* ARGSUSED1 */
bool
shouldqueue(pri, ct)
long pri;
time_t ct;
{
bool rval;
if (tTd(3, 30))
dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
CurrentLA, pri);
if (CurrentLA < QueueLA)
{
if (tTd(3, 30))
dprintf("FALSE (CurrentLA < QueueLA)\n");
return FALSE;
}
#if 0 /* this code is reported to cause oscillation around RefuseLA */
if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
{
if (tTd(3, 30))
dprintf("TRUE (CurrentLA >= RefuseLA)\n");
return TRUE;
}
#endif /* 0 */
rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1));
if (tTd(3, 30))
dprintf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
return rval;
}
/*
** REFUSECONNECTIONS -- decide if connections should be refused
**
** Parameters:
** name -- daemon name (for error messages only)
** e -- the current envelope.
** d -- number of daemon
**
** Returns:
** TRUE if incoming SMTP connections should be refused
** (for now).
** FALSE if we should accept new work.
**
** Side Effects:
** Sets process title when it is rejecting connections.
*/
bool
refuseconnections(name, e, d)
char *name;
ENVELOPE *e;
int d;
{
time_t now;
static time_t lastconn[MAXDAEMONS];
static int conncnt[MAXDAEMONS];
#ifdef XLA
if (!xla_smtp_ok())
return TRUE;
#endif /* XLA */
now = curtime();
if (now != lastconn[d])
{
lastconn[d] = now;
conncnt[d] = 0;
}
else if (conncnt[d]++ > ConnRateThrottle && ConnRateThrottle > 0)
{
/* sleep to flatten out connection load */
sm_setproctitle(TRUE, e, "deferring connections on daemon %s: %d per second",
name, ConnRateThrottle);
if (LogLevel >= 9)
sm_syslog(LOG_INFO, NOQID,
"deferring connections on daemon %s: %d per second",
name, ConnRateThrottle);
(void) sleep(1);
}
CurrentLA = getla();
if (RefuseLA > 0 && CurrentLA >= RefuseLA)
{
sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: load average: %d",
name, CurrentLA);
if (LogLevel >= 9)
sm_syslog(LOG_INFO, NOQID,
"rejecting connections on daemon %s: load average: %d",
name, CurrentLA);
return TRUE;
}
if (MaxChildren > 0 && CurChildren >= MaxChildren)
{
proc_list_probe();
if (CurChildren >= MaxChildren)
{
sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: %d children, max %d",
name, CurChildren, MaxChildren);
if (LogLevel >= 9)
sm_syslog(LOG_INFO, NOQID,
"rejecting connections on daemon %s: %d children, max %d",
name, CurChildren, MaxChildren);
return TRUE;
}
}
return FALSE;
}
/*
** 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.
*/
#define SPT_NONE 0 /* don't use it at all */
#define SPT_REUSEARGV 1 /* cover argv with title information */
#define SPT_BUILTIN 2 /* use libc builtin */
#define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */
#define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */
#define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */
#define SPT_SCO 6 /* write kernel u. area */
#define SPT_CHANGEARGV 7 /* write our own strings into argv[] */
#ifndef SPT_TYPE
# define SPT_TYPE SPT_REUSEARGV
#endif /* ! SPT_TYPE */
#if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
# if SPT_TYPE == SPT_PSTAT
# include <sys/pstat.h>
# endif /* SPT_TYPE == SPT_PSTAT */
# if SPT_TYPE == SPT_PSSTRINGS
# include <machine/vmparam.h>
# include <sys/exec.h>
# ifndef PS_STRINGS /* hmmmm.... apparently not available after all */
# undef SPT_TYPE
# define SPT_TYPE SPT_REUSEARGV
# else /* ! PS_STRINGS */
# ifndef NKPDE /* FreeBSD 2.0 */
# define NKPDE 63
typedef unsigned int *pt_entry_t;
# endif /* ! NKPDE */
# endif /* ! PS_STRINGS */
# endif /* SPT_TYPE == SPT_PSSTRINGS */
# if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
# define SETPROC_STATIC static
# else /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
# define SETPROC_STATIC
# endif /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
# if SPT_TYPE == SPT_SYSMIPS
# include <sys/sysmips.h>
# include <sys/sysnews.h>
# endif /* SPT_TYPE == SPT_SYSMIPS */
# if SPT_TYPE == SPT_SCO
# include <sys/immu.h>
# include <sys/dir.h>
# include <sys/user.h>
# include <sys/fs/s5param.h>
# if PSARGSZ > MAXLINE
# define SPT_BUFSIZE PSARGSZ
# endif /* PSARGSZ > MAXLINE */
# endif /* SPT_TYPE == SPT_SCO */
# ifndef SPT_PADCHAR
# define SPT_PADCHAR ' '
# endif /* ! SPT_PADCHAR */
#endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
#ifndef SPT_BUFSIZE
# define SPT_BUFSIZE MAXLINE
#endif /* ! SPT_BUFSIZE */
/*
** Pointers for setproctitle.
** This allows "ps" listings to give more useful information.
*/
static char **Argv = NULL; /* pointer to argument vector */
static char *LastArgv = NULL; /* end of argv */
#if SPT_TYPE != SPT_BUILTIN
static void setproctitle __P((const char *, ...));
#endif /* SPT_TYPE != SPT_BUILTIN */
void
initsetproctitle(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
register int i, envpsize = 0;
extern char **environ;
/*
** Move the environment so setproctitle can use the space at
** the top of memory.
*/
for (i = 0; envp[i] != NULL; i++)
envpsize += strlen(envp[i]) + 1;
environ = (char **) xalloc(sizeof (char *) * (i + 1));
for (i = 0; envp[i] != NULL; i++)
environ[i] = newstr(envp[i]);
environ[i] = NULL;
/*
** Save start and extent of argv for setproctitle.
*/
Argv = argv;
/*
** Determine how much space we can use for setproctitle.
** Use all contiguous argv and envp pointers starting at argv[0]
*/
for (i = 0; i < argc; i++)
{
if (i == 0 || LastArgv + 1 == argv[i])
LastArgv = argv[i] + strlen(argv[i]);
}
for (i = 0; LastArgv != NULL && envp[i] != NULL; i++)
{
if (LastArgv + 1 == envp[i])
LastArgv = envp[i] + strlen(envp[i]);
}
}
#if SPT_TYPE != SPT_BUILTIN
/*VARARGS1*/
static void
# ifdef __STDC__
setproctitle(const char *fmt, ...)
# else /* __STDC__ */
setproctitle(fmt, va_alist)
const char *fmt;
va_dcl
# endif /* __STDC__ */
{
# if SPT_TYPE != SPT_NONE
register int i;
register char *p;
SETPROC_STATIC char buf[SPT_BUFSIZE];
VA_LOCAL_DECL
# if SPT_TYPE == SPT_PSTAT
union pstun pst;
# endif /* SPT_TYPE == SPT_PSTAT */
# if SPT_TYPE == SPT_SCO
off_t seek_off;
static int kmem = -1;
static int kmempid = -1;
struct user u;
# endif /* SPT_TYPE == SPT_SCO */
p = buf;
/* print sendmail: heading for grep */
(void) strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
p += strlen(p);
/* print the argument string */
VA_START(fmt);
(void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
VA_END;
i = strlen(buf);
# if SPT_TYPE == SPT_PSTAT
pst.pst_command = buf;
pstat(PSTAT_SETCMD, pst, i, 0, 0);
# endif /* SPT_TYPE == SPT_PSTAT */
# if SPT_TYPE == SPT_PSSTRINGS
PS_STRINGS->ps_nargvstr = 1;
PS_STRINGS->ps_argvstr = buf;
# endif /* SPT_TYPE == SPT_PSSTRINGS */
# if SPT_TYPE == SPT_SYSMIPS
sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
# endif /* SPT_TYPE == SPT_SYSMIPS */
# if SPT_TYPE == SPT_SCO
if (kmem < 0 || kmempid != getpid())
{
if (kmem >= 0)
close(kmem);
kmem = open(_PATH_KMEM, O_RDWR, 0);
if (kmem < 0)
return;
(void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
kmempid = getpid();
}
buf[PSARGSZ - 1] = '\0';
seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
(void) write(kmem, buf, PSARGSZ);
# endif /* SPT_TYPE == SPT_SCO */
# if SPT_TYPE == SPT_REUSEARGV
if (LastArgv == NULL)
return;
if (i > LastArgv - Argv[0] - 2)
{
i = LastArgv - Argv[0] - 2;
buf[i] = '\0';
}
(void) strlcpy(Argv[0], buf, i + 1);
p = &Argv[0][i];
while (p < LastArgv)
*p++ = SPT_PADCHAR;
Argv[1] = NULL;
# endif /* SPT_TYPE == SPT_REUSEARGV */
# if SPT_TYPE == SPT_CHANGEARGV
Argv[0] = buf;
Argv[1] = 0;
# endif /* SPT_TYPE == SPT_CHANGEARGV */
# endif /* SPT_TYPE != SPT_NONE */
}
#endif /* SPT_TYPE != SPT_BUILTIN */
/*
** SM_SETPROCTITLE -- set process task and set process title for ps
**
** Possibly set process status and call setproctitle() to
** change the ps display.
**
** Parameters:
** status -- whether or not to store as process status
** e -- the current envelope.
** fmt -- a printf style format string.
** a, b, c -- possible parameters to fmt.
**
** Returns:
** none.
*/
/*VARARGS2*/
void
#ifdef __STDC__
sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...)
#else /* __STDC__ */
sm_setproctitle(status, e, fmt, va_alist)
bool status;
ENVELOPE *e;
const char *fmt;
va_dcl
#endif /* __STDC__ */
{
char buf[SPT_BUFSIZE];
VA_LOCAL_DECL
/* print the argument string */
VA_START(fmt);
(void) vsnprintf(buf, sizeof buf, fmt, ap);
VA_END;
if (status)
proc_list_set(getpid(), buf);
if (ProcTitlePrefix != NULL)
{
char prefix[SPT_BUFSIZE];
expand(ProcTitlePrefix, prefix, sizeof prefix, e);
setproctitle("%s: %s", prefix, buf);
}
else
setproctitle("%s", buf);
}
/*
** WAITFOR -- wait for a particular process id.
**
** Parameters:
** pid -- process id to wait for.
**
** Returns:
** status of pid.
** -1 if pid never shows up.
**
** Side Effects:
** none.
*/
int
waitfor(pid)
pid_t pid;
{
# ifdef WAITUNION
union wait st;
# else /* WAITUNION */
auto int st;
# endif /* WAITUNION */
pid_t i;
# if defined(ISC_UNIX) || defined(_SCO_unix_)
int savesig;
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
do
{
errno = 0;
# if defined(ISC_UNIX) || defined(_SCO_unix_)
savesig = releasesignal(SIGCHLD);
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
i = wait(&st);
# if defined(ISC_UNIX) || defined(_SCO_unix_)
if (savesig > 0)
blocksignal(SIGCHLD);
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
if (i > 0)
(void) proc_list_drop(i);
} while ((i >= 0 || errno == EINTR) && i != pid);
if (i < 0)
return -1;
# ifdef WAITUNION
return st.w_status;
# else /* WAITUNION */
return st;
# endif /* WAITUNION */
}
/*
** REAPCHILD -- pick up the body of my child, lest it become a zombie
**
** Parameters:
** sig -- the signal that got us here (unused).
**
** Returns:
** none.
**
** Side Effects:
** Picks up extant zombies.
** Control socket exits may restart/shutdown daemon.
*/
/* ARGSUSED0 */
SIGFUNC_DECL
reapchild(sig)
int sig;
{
int save_errno = errno;
int st;
pid_t pid;
#if HASWAITPID
auto int status;
int count;
count = 0;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
{
st = status;
if (count++ > 1000)
{
if (LogLevel > 0)
sm_syslog(LOG_ALERT, NOQID,
"reapchild: waitpid loop: pid=%d, status=%x",
pid, status);
break;
}
#else /* HASWAITPID */
# ifdef WNOHANG
union wait status;
while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
{
st = status.w_status;
# else /* WNOHANG */
auto int status;
/*
** Catch one zombie -- we will be re-invoked (we hope) if there
** are more. Unreliable signals probably break this, but this
** is the "old system" situation -- waitpid or wait3 are to be
** strongly preferred.
*/
if ((pid = wait(&status)) > 0)
{
st = status;
# endif /* WNOHANG */
#endif /* HASWAITPID */
/* Drop PID and check if it was a control socket child */
if (proc_list_drop(pid) == PROC_CONTROL &&
WIFEXITED(st))
{
/* if so, see if we need to restart or shutdown */
if (WEXITSTATUS(st) == EX_RESTART)
{
/* emulate a SIGHUP restart */
sighup(0);
/* NOTREACHED */
}
else if (WEXITSTATUS(st) == EX_SHUTDOWN)
{
/* emulate a SIGTERM shutdown */
intsig(0);
/* NOTREACHED */
}
}
}
#ifdef SYS5SIGNALS
(void) setsignal(SIGCHLD, reapchild);
#endif /* SYS5SIGNALS */
errno = save_errno;
return SIGFUNC_RETURN;
}
/*
** PUTENV -- emulation of putenv() in terms of setenv()
**
** Not needed on Posix-compliant systems.
** This doesn't have full Posix semantics, but it's good enough
** for sendmail.
**
** Parameter:
** env -- the environment to put.
**
** Returns:
** none.
*/
#if NEEDPUTENV
# if NEEDPUTENV == 2 /* no setenv(3) call available */
int
putenv(str)
char *str;
{
char **current;
int matchlen, envlen = 0;
char *tmp;
char **newenv;
static bool first = TRUE;
extern char **environ;
/*
* find out how much of str to match when searching
* for a string to replace.
*/
if ((tmp = strchr(str, '=')) == NULL || tmp == str)
matchlen = strlen(str);
else
matchlen = (int) (tmp - str);
++matchlen;
/*
* Search for an existing string in the environment and find the
* length of environ. If found, replace and exit.
*/
for (current = environ; *current; current++)
{
++envlen;
if (strncmp(str, *current, matchlen) == 0)
{
/* found it, now insert the new version */
*current = (char *)str;
return 0;
}
}
/*
* There wasn't already a slot so add space for a new slot.
* If this is our first time through, use malloc(), else realloc().
*/
if (first)
{
newenv = (char **) malloc(sizeof(char *) * (envlen + 2));
if (newenv == NULL)
return -1;
first = FALSE;
(void) memcpy(newenv, environ, sizeof(char *) * envlen);
}
else
{
newenv = (char **) realloc((char *)environ, sizeof(char *) * (envlen + 2));
if (newenv == NULL)
return -1;
}
/* actually add in the new entry */
environ = newenv;
environ[envlen] = (char *)str;
environ[envlen + 1] = NULL;
return 0;
}
# else /* NEEDPUTENV == 2 */
int
putenv(env)
char *env;
{
char *p;
int l;
char nbuf[100];
p = strchr(env, '=');
if (p == NULL)
return 0;
l = p - env;
if (l > sizeof nbuf - 1)
l = sizeof nbuf - 1;
memmove(nbuf, env, l);
nbuf[l] = '\0';
return setenv(nbuf, ++p, 1);
}
# endif /* NEEDPUTENV == 2 */
#endif /* NEEDPUTENV */
/*
** 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.
*/
#if !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 /* !HASUNSETENV */
/*
** 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 /* SOLARIS */
int
getdtsize()
{
# ifdef RLIMIT_NOFILE
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
return rl.rlim_cur;
# endif /* RLIMIT_NOFILE */
# if HASGETDTABLESIZE
return getdtablesize();
# else /* HASGETDTABLESIZE */
# ifdef _SC_OPEN_MAX
return sysconf(_SC_OPEN_MAX);
# else /* _SC_OPEN_MAX */
return NOFILE;
# endif /* _SC_OPEN_MAX */
# endif /* HASGETDTABLESIZE */
}
/*
** UNAME -- get the UUCP name of this system.
*/
#if !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;
}
# if 0
/*
** 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 /* 0 */
return -1;
}
#endif /* !HASUNAME */
/*
** INITGROUPS -- initialize groups
**
** Stub implementation for System V style systems
*/
#if !HASINITGROUPS
initgroups(name, basegid)
char *name;
int basegid;
{
return 0;
}
#endif /* !HASINITGROUPS */
/*
** SETGROUPS -- set group list
**
** Stub implementation for systems that don't have group lists
*/
#ifndef NGROUPS_MAX
int
setgroups(ngroups, grouplist)
int ngroups;
GIDSET_T grouplist[];
{
return 0;
}
#endif /* ! NGROUPS_MAX */
/*
** SETSID -- set session id (for non-POSIX systems)
*/
#if !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) ioctl(fd, TIOCNOTTY, (char *) 0);
(void) close(fd);
}
# endif /* TIOCNOTTY */
# ifdef SYS5SETPGRP
return setpgrp();
# else /* SYS5SETPGRP */
return setpgid(0, getpid());
# endif /* SYS5SETPGRP */
}
#endif /* !HASSETSID */
/*
** FSYNC -- dummy fsync
*/
#if NEEDFSYNC
fsync(fd)
int fd;
{
# ifdef O_SYNC
return fcntl(fd, F_SETFL, O_SYNC);
# else /* O_SYNC */
/* nothing we can do */
return 0;
# endif /* O_SYNC */
}
#endif /* NEEDFSYNC */
/*
** 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. Only needed on versions
** prior to 5.4.3.
*/
#ifdef DGUX_5_4_2
# undef inet_addr
long
dgux_inet_addr(host)
char *host;
{
struct in_addr haddr;
haddr = inet_addr(host);
return haddr.s_addr;
}
#endif /* DGUX_5_4_2 */
/*
** GETOPT -- for old systems or systems with bogus implementations
*/
#if 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 /* defined(LIBC_SCCS) && !defined(lint) */
/*
* get option letter from argument vector
*/
# ifdef _CONVEX_SOURCE
extern int optind, opterr, optopt;
extern char *optarg;
# else /* _CONVEX_SOURCE */
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = 0; /* character checked for validity */
char *optarg = NULL; /* argument associated with option */
# endif /* _CONVEX_SOURCE */
# define BADCH (int)'?'
# define EMSG ""
# define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
int
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 = NULL; /* option letter list index */
if (atend) {
atend = 0;
place = EMSG;
}
if(!*place) { /* update scanning pointer */
if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
atend++;
return -1;
}
if (*place == '-') { /* found "--" */
++optind;
atend++;
return -1;
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
if (!*place) ++optind;
tell(": illegal option -- ");
}
if (oli && *++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 /* NEEDGETOPT */
/*
** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
*/
#if 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 /* NEEDVPRINTF */
/*
** USERSHELLOK -- tell if a user's shell is ok for unrestricted use
**
** Parameters:
** user -- the name of the user we are checking.
** 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 /* ! _PATH_SHELLS */
# if defined(_AIX3) || defined(_AIX4)
# include <userconf.h>
# if _AIX4 >= 40200
# include <userpw.h>
# endif /* _AIX4 >= 40200 */
# include <usersec.h>
# endif /* defined(_AIX3) || defined(_AIX4) */
static char *DefaultUserShells[] =
{
"/bin/sh", /* standard shell */
"/usr/bin/sh",
"/bin/csh", /* C shell */
"/usr/bin/csh",
# ifdef __hpux
# ifdef V4FS
"/usr/bin/rsh", /* restricted Bourne shell */
"/usr/bin/ksh", /* Korn shell */
"/usr/bin/rksh", /* restricted Korn shell */
"/usr/bin/pam",
"/usr/bin/keysh", /* key shell (extended Korn shell) */
"/usr/bin/posix/sh",
# else /* V4FS */
"/bin/rsh", /* restricted Bourne shell */
"/bin/ksh", /* Korn shell */
"/bin/rksh", /* restricted Korn shell */
"/bin/pam",
"/usr/bin/keysh", /* key shell (extended Korn shell) */
"/bin/posix/sh",
# endif /* V4FS */
# endif /* __hpux */
# if defined(_AIX3) || defined(_AIX4)
"/bin/ksh", /* Korn shell */
"/usr/bin/ksh",
"/bin/tsh", /* trusted shell */
"/usr/bin/tsh",
"/bin/bsh", /* Bourne shell */
"/usr/bin/bsh",
# endif /* defined(_AIX3) || defined(_AIX4) */
# if defined(__svr4__) || defined(__svr5__)
"/bin/ksh", /* Korn shell */
"/usr/bin/ksh",
# endif /* defined(__svr4__) || defined(__svr5__) */
# ifdef sgi
"/sbin/sh", /* SGI's shells really live in /sbin */
"/sbin/csh",
"/bin/ksh", /* Korn shell */
"/sbin/ksh",
"/usr/bin/ksh",
"/bin/tcsh", /* Extended csh */
"/usr/bin/tcsh",
# endif /* sgi */
NULL
};
#endif /* !HASGETUSERSHELL */
#define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/"
bool
usershellok(user, shell)
char *user;
char *shell;
{
# if HASGETUSERSHELL
register char *p;
extern char *getusershell();
if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
ConfigLevel <= 1)
return TRUE;
setusershell();
while ((p = getusershell()) != NULL)
if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
break;
endusershell();
return p != NULL;
# else /* HASGETUSERSHELL */
# if USEGETCONFATTR
auto char *v;
# endif /* USEGETCONFATTR */
register FILE *shellf;
char buf[MAXLINE];
if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
ConfigLevel <= 1)
return TRUE;
# if USEGETCONFATTR
/*
** Naturally IBM has a "better" idea.....
**
** What a crock. This interface isn't documented, it is
** considered part of the security library (-ls), and it
** only works if you are running as root (since the list
** of valid shells is obviously a source of great concern).
** I recommend that you do NOT define USEGETCONFATTR,
** especially since you are going to have to set up an
** /etc/shells anyhow to handle the cases where getconfattr
** fails.
*/
if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
{
while (*v != '\0')
{
if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
return TRUE;
v += strlen(v) + 1;
}
return FALSE;
}
# endif /* USEGETCONFATTR */
shellf = fopen(_PATH_SHELLS, "r");
if (shellf == NULL)
{
/* no /etc/shells; see if it is one of the std shells */
char **d;
if (errno != ENOENT && LogLevel > 3)
sm_syslog(LOG_ERR, NOQID,
"usershellok: cannot open %s: %s",
_PATH_SHELLS, errstring(errno));
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 != '#' && !(isascii(*p) && isspace(*p)))
p++;
*p = '\0';
if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
{
(void) fclose(shellf);
return TRUE;
}
}
(void) fclose(shellf);
return FALSE;
# endif /* HASGETUSERSHELL */
}
/*
** FREEDISKSPACE -- 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 blocks 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 /* ! SFS_TYPE */
#if SFS_TYPE == SFS_USTAT
# include <ustat.h>
#endif /* SFS_TYPE == SFS_USTAT */
#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
# include <sys/statfs.h>
#endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
#if SFS_TYPE == SFS_VFS
# include <sys/vfs.h>
#endif /* SFS_TYPE == SFS_VFS */
#if SFS_TYPE == SFS_MOUNT
# include <sys/mount.h>
#endif /* SFS_TYPE == SFS_MOUNT */
#if SFS_TYPE == SFS_STATVFS
# include <sys/statvfs.h>
#endif /* SFS_TYPE == SFS_STATVFS */
long
freediskspace(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 SFS_BAVAIL f_tfree
# else /* SFS_TYPE == SFS_USTAT */
# if defined(ultrix)
struct fs_data fs;
# define SFS_BAVAIL fd_bfreen
# define FSBLOCKSIZE 1024L
# else /* defined(ultrix) */
# if SFS_TYPE == SFS_STATVFS
struct statvfs fs;
# define FSBLOCKSIZE fs.f_frsize
# else /* SFS_TYPE == SFS_STATVFS */
struct statfs fs;
# define FSBLOCKSIZE fs.f_bsize
# endif /* SFS_TYPE == SFS_STATVFS */
# endif /* defined(ultrix) */
# endif /* SFS_TYPE == SFS_USTAT */
# ifndef SFS_BAVAIL
# define SFS_BAVAIL f_bavail
# endif /* ! SFS_BAVAIL */
# if SFS_TYPE == SFS_USTAT
if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
# else /* SFS_TYPE == SFS_USTAT */
# if SFS_TYPE == SFS_4ARGS
if (statfs(dir, &fs, sizeof fs, 0) == 0)
# else /* SFS_TYPE == SFS_4ARGS */
# if SFS_TYPE == SFS_STATVFS
if (statvfs(dir, &fs) == 0)
# else /* SFS_TYPE == SFS_STATVFS */
# if defined(ultrix)
if (statfs(dir, &fs) > 0)
# else /* defined(ultrix) */
if (statfs(dir, &fs) == 0)
# endif /* defined(ultrix) */
# endif /* SFS_TYPE == SFS_STATVFS */
# endif /* SFS_TYPE == SFS_4ARGS */
# endif /* SFS_TYPE == SFS_USTAT */
{
if (bsize != NULL)
*bsize = FSBLOCKSIZE;
if (fs.SFS_BAVAIL <= 0)
return 0;
else if (fs.SFS_BAVAIL > LONG_MAX)
return (long) LONG_MAX;
else
return (long) fs.SFS_BAVAIL;
}
# endif /* SFS_TYPE != SFS_NONE */
return -1;
}
/*
** ENOUGHDISKSPACE -- is there 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.
** log -- log message?
**
** Returns:
** TRUE if there is enough space.
** FALSE otherwise.
*/
bool
enoughdiskspace(msize, log)
long msize;
bool log;
{
long bfree;
long bsize;
if (MinBlocksFree <= 0 && msize <= 0)
{
if (tTd(4, 80))
dprintf("enoughdiskspace: no threshold\n");
return TRUE;
}
bfree = freediskspace(QueueDir, &bsize);
if (bfree >= 0)
{
if (tTd(4, 80))
dprintf("enoughdiskspace: bavail=%ld, need=%ld\n",
bfree, msize);
/* convert msize to block count */
msize = msize / bsize + 1;
if (MinBlocksFree >= 0)
msize += MinBlocksFree;
if (bfree < msize)
{
if (log && LogLevel > 0)
sm_syslog(LOG_ALERT, CurEnv->e_id,
"low on space (have %ld, %s needs %ld in %s)",
bfree,
CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
msize, QueueDir);
return FALSE;
}
}
else if (tTd(4, 80))
dprintf("enoughdiskspace 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 /* ETIMEDOUT */
#ifdef ESTALE
case ESTALE: /* Stale NFS file handle */
#endif /* ESTALE */
#ifdef ENETDOWN
case ENETDOWN: /* Network is down */
#endif /* ENETDOWN */
#ifdef ENETUNREACH
case ENETUNREACH: /* Network is unreachable */
#endif /* ENETUNREACH */
#ifdef ENETRESET
case ENETRESET: /* Network dropped connection on reset */
#endif /* ENETRESET */
#ifdef ECONNABORTED
case ECONNABORTED: /* Software caused connection abort */
#endif /* ECONNABORTED */
#ifdef ECONNRESET
case ECONNRESET: /* Connection reset by peer */
#endif /* ECONNRESET */
#ifdef ENOBUFS
case ENOBUFS: /* No buffer space available */
#endif /* ENOBUFS */
#ifdef ESHUTDOWN
case ESHUTDOWN: /* Can't send after socket shutdown */
#endif /* ESHUTDOWN */
#ifdef ECONNREFUSED
case ECONNREFUSED: /* Connection refused */
#endif /* ECONNREFUSED */
#ifdef EHOSTDOWN
case EHOSTDOWN: /* Host is down */
#endif /* EHOSTDOWN */
#ifdef EHOSTUNREACH
case EHOSTUNREACH: /* No route to host */
#endif /* EHOSTUNREACH */
#ifdef EDQUOT
case EDQUOT: /* Disc quota exceeded */
#endif /* EDQUOT */
#ifdef EPROCLIM
case EPROCLIM: /* Too many processes */
#endif /* EPROCLIM */
#ifdef EUSERS
case EUSERS: /* Too many users */
#endif /* EUSERS */
#ifdef EDEADLK
case EDEADLK: /* Resource deadlock avoided */
#endif /* EDEADLK */
#ifdef EISCONN
case EISCONN: /* Socket already connected */
#endif /* EISCONN */
#ifdef EINPROGRESS
case EINPROGRESS: /* Operation now in progress */
#endif /* EINPROGRESS */
#ifdef EALREADY
case EALREADY: /* Operation already in progress */
#endif /* EALREADY */
#ifdef EADDRINUSE
case EADDRINUSE: /* Address already in use */
#endif /* EADDRINUSE */
#ifdef EADDRNOTAVAIL
case EADDRNOTAVAIL: /* Can't assign requested address */
#endif /* EADDRNOTAVAIL */
#ifdef ETXTBSY
case ETXTBSY: /* (Apollo) file locked */
#endif /* ETXTBSY */
#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
case ENOSR: /* Out of streams resources */
#endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */
#ifdef ENOLCK
case ENOLCK: /* No locks available */
#endif /* ENOLCK */
case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */
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;
{
int i;
int save_errno;
# if !HASFLOCK
int action;
struct flock lfd;
if (ext == NULL)
ext = "";
memset(&lfd, '\0', 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))
dprintf("lockfile(%s%s, action=%d, type=%d): ",
filename, ext, action, lfd.l_type);
while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
continue;
if (i >= 0)
{
if (tTd(55, 60))
dprintf("SUCCESS\n");
return TRUE;
}
save_errno = errno;
if (tTd(55, 60))
dprintf("(%s) ", errstring(save_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 (save_errno == EINVAL)
{
if (tTd(55, 60))
dprintf("SUCCESS\n");
return TRUE;
}
if (!bitset(LOCK_NB, type) ||
(save_errno != EACCES && save_errno != EAGAIN))
{
int omode = -1;
# ifdef F_GETFL
(void) fcntl(fd, F_GETFL, &omode);
errno = save_errno;
# endif /* F_GETFL */
syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename, ext, fd, type, omode, geteuid());
dumpfd(fd, TRUE, TRUE);
}
# else /* !HASFLOCK */
if (ext == NULL)
ext = "";
if (tTd(55, 60))
dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
while ((i = flock(fd, type)) < 0 && errno == EINTR)
continue;
if (i >= 0)
{
if (tTd(55, 60))
dprintf("SUCCESS\n");
return TRUE;
}
save_errno = errno;
if (tTd(55, 60))
dprintf("(%s) ", errstring(save_errno));
if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
{
int omode = -1;
# ifdef F_GETFL
(void) fcntl(fd, F_GETFL, &omode);
errno = save_errno;
# endif /* F_GETFL */
syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename, ext, fd, type, omode, geteuid());
dumpfd(fd, TRUE, TRUE);
}
# endif /* !HASFLOCK */
if (tTd(55, 60))
dprintf("FAIL\n");
errno = save_errno;
return FALSE;
}
/*
** CHOWNSAFE -- tell if chown is "safe" (executable only by root)
**
** Unfortunately, given that we can't predict other systems on which
** a remote mounted (NFS) filesystem will be mounted, the answer is
** almost always that this is unsafe.
**
** Note also that many operating systems have non-compliant
** implementations of the _POSIX_CHOWN_RESTRICTED variable and the
** fpathconf() routine. According to IEEE 1003.1-1990, if
** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
** no non-root process can give away the file. However, vendors
** don't take NFS into account, so a comfortable value of
** _POSIX_CHOWN_RESTRICTED tells us nothing.
**
** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
** even on files where chown is not restricted. Many systems get
** this wrong on NFS-based filesystems (that is, they say that chown
** is restricted [safe] on NFS filesystems where it may not be, since
** other systems can access the same filesystem and do file giveaway;
** only the NFS server knows for sure!) Hence, it is important to
** get the value of SAFENFSPATHCONF correct -- it should be defined
** _only_ after testing (see test/t_pathconf.c) a system on an unsafe
** NFS-based filesystem to ensure that you can get meaningful results.
** If in doubt, assume unsafe!
**
** You may also need to tweak IS_SAFE_CHOWN -- it should be a
** condition indicating whether the return from pathconf indicates
** that chown is safe (typically either > 0 or >= 0 -- there isn't
** even any agreement about whether a zero return means that a file
** is or is not safe). It defaults to "> 0".
**
** If the parent directory is safe (writable only by owner back
** to the root) then we can relax slightly and trust fpathconf
** in more circumstances. This is really a crock -- if this is an
** NFS mounted filesystem then we really know nothing about the
** underlying implementation. However, most systems pessimize and
** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
** we interpret as unsafe, as we should. Thus, this heuristic gets
** us into a possible problem only on systems that have a broken
** pathconf implementation and which are also poorly configured
** (have :include: files in group- or world-writable directories).
**
** Parameters:
** fd -- the file descriptor to check.
** safedir -- set if the parent directory is safe.
**
** Returns:
** TRUE -- if the chown(2) operation is "safe" -- that is,
** only root can chown the file to an arbitrary user.
** FALSE -- if an arbitrary user can give away a file.
*/
#ifndef IS_SAFE_CHOWN
# define IS_SAFE_CHOWN > 0
#endif /* ! IS_SAFE_CHOWN */
bool
chownsafe(fd, safedir)
int fd;
bool safedir;
{
# if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
(defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
int rval;
/* give the system administrator a chance to override */
if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
return TRUE;
/*
** Some systems (e.g., SunOS) seem to have the call and the
** #define _PC_CHOWN_RESTRICTED, but don't actually implement
** the call. This heuristic checks for that.
*/
errno = 0;
rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
# if SAFENFSPATHCONF
return errno == 0 && rval IS_SAFE_CHOWN;
# else /* SAFENFSPATHCONF */
return safedir && errno == 0 && rval IS_SAFE_CHOWN;
# endif /* SAFENFSPATHCONF */
# else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
# endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
}
/*
** RESETLIMITS -- reset system controlled resource limits
**
** This is to avoid denial-of-service attacks
**
** Parameters:
** none
**
** Returns:
** none
*/
#if HASSETRLIMIT
# ifdef RLIMIT_NEEDS_SYS_TIME_H
# include <sys/time.h>
# endif /* RLIMIT_NEEDS_SYS_TIME_H */
# include <sys/resource.h>
#endif /* HASSETRLIMIT */
#ifndef FD_SETSIZE
# define FD_SETSIZE 256
#endif /* ! FD_SETSIZE */
void
resetlimits()
{
#if HASSETRLIMIT
struct rlimit lim;
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
(void) setrlimit(RLIMIT_CPU, &lim);
(void) setrlimit(RLIMIT_FSIZE, &lim);
# ifdef RLIMIT_NOFILE
lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
(void) setrlimit(RLIMIT_NOFILE, &lim);
# endif /* RLIMIT_NOFILE */
#else /* HASSETRLIMIT */
# if HASULIMIT
(void) ulimit(2, 0x3fffff);
(void) ulimit(4, FD_SETSIZE);
# endif /* HASULIMIT */
#endif /* HASSETRLIMIT */
errno = 0;
}
/*
** GETCFNAME -- return the name of the .cf file.
**
** Some systems (e.g., NeXT) determine this dynamically.
*/
char *
getcfname()
{
if (ConfFile != NULL)
return ConfFile;
#if NETINFO
{
char *cflocation;
cflocation = ni_propval("/locations", NULL, "sendmail",
"sendmail.cf", '\0');
if (cflocation != NULL)
return cflocation;
}
#endif /* NETINFO */
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)
{
VendorCode = VENDOR_BERKELEY;
return TRUE;
}
/* add vendor extensions here */
#ifdef SUN_EXTENSIONS
if (strcasecmp(vendor, "Sun") == 0)
{
VendorCode = VENDOR_SUN;
return TRUE;
}
#endif /* SUN_EXTENSIONS */
#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
if (strcasecmp(vendor, VENDOR_NAME) == 0)
{
VendorCode = VENDOR_CODE;
return TRUE;
}
#endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
return FALSE;
}
/*
** GETVENDOR -- return vendor name based on vendor code
**
** Parameters:
** vendorcode -- numeric representation of vendor.
**
** Returns:
** string containing vendor name.
*/
char *
getvendor(vendorcode)
int vendorcode;
{
#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
/*
** Can't have the same switch case twice so need to
** handle VENDOR_CODE outside of switch. It might
** match one of the existing VENDOR_* codes.
*/
if (vendorcode == VENDOR_CODE)
return VENDOR_NAME;
#endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
switch (vendorcode)
{
case VENDOR_BERKELEY:
return "Berkeley";
case VENDOR_SUN:
return "Sun";
case VENDOR_HP:
return "HP";
case VENDOR_IBM:
return "IBM";
case VENDOR_SENDMAIL:
return "Sendmail";
default:
return "Unknown";
}
}
/*
** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
**
** Vendor_pre_defaults is called before reading the configuration
** file; vendor_post_defaults is called immediately after.
**
** Parameters:
** e -- the global environment to initialize.
**
** Returns:
** none.
*/
#if SHARE_V1
int DefShareUid; /* default share uid to run as -- unused??? */
#endif /* SHARE_V1 */
void
vendor_pre_defaults(e)
ENVELOPE *e;
{
#if SHARE_V1
/* OTHERUID is defined in shares.h, do not be alarmed */
DefShareUid = OTHERUID;
#endif /* SHARE_V1 */
#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
sun_pre_defaults(e);
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
#ifdef apollo
/*
** stupid domain/os can't even open
** /etc/mail/sendmail.cf without this
*/
setuserenv("ISP", NULL);
setuserenv("SYSTYPE", NULL);
#endif /* apollo */
}
void
vendor_post_defaults(e)
ENVELOPE *e;
{
#ifdef __QNX__
char *p;
/* Makes sure the SOCK environment variable remains */
if (p = getextenv("SOCK"))
setuserenv("SOCK", p);
#endif /* __QNX__ */
#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
sun_post_defaults(e);
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
}
/*
** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
*/
void
vendor_daemon_setup(e)
ENVELOPE *e;
{
#if HASSETLOGIN
(void) setlogin(RunAsUserName);
#endif /* HASSETLOGIN */
#if SECUREWARE
if (getluid() != -1)
{
usrerr("Daemon cannot have LUID");
finis(FALSE, EX_USAGE);
}
#endif /* SECUREWARE */
}
/*
** VENDOR_SET_UID -- do setup for setting a user id
**
** This is called when we are still root.
**
** Parameters:
** uid -- the uid we are about to become.
**
** Returns:
** none.
*/
void
vendor_set_uid(uid)
UID_T uid;
{
/*
** We need to setup the share groups (lnodes)
** and add auditing information (luid's)
** before we loose our ``root''ness.
*/
#if SHARE_V1
if (setupshares(uid, syserr) != 0)
syserr("Unable to set up shares");
#endif /* SHARE_V1 */
#if SECUREWARE
(void) setup_secure(uid);
#endif /* SECUREWARE */
}
/*
** VALIDATE_CONNECTION -- check connection for rationality
**
** If the connection is rejected, this routine should log an
** appropriate message -- but should never issue any SMTP protocol.
**
** Parameters:
** sap -- a pointer to a SOCKADDR naming the peer.
** hostname -- the name corresponding to sap.
** e -- the current envelope.
**
** Returns:
** error message from rejection.
** NULL if not rejected.
*/
#if TCPWRAPPERS
# include <tcpd.h>
/* tcpwrappers does no logging, but you still have to declare these -- ugh */
int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
#endif /* TCPWRAPPERS */
#if DAEMON
char *
validate_connection(sap, hostname, e)
SOCKADDR *sap;
char *hostname;
ENVELOPE *e;
{
# if TCPWRAPPERS
char *host;
# endif /* TCPWRAPPERS */
if (tTd(48, 3))
dprintf("validate_connection(%s, %s)\n",
hostname, anynet_ntoa(sap));
if (rscheck("check_relay", hostname, anynet_ntoa(sap),
e, TRUE, TRUE, 4) != EX_OK)
{
static char reject[BUFSIZ*2];
extern char MsgBuf[];
if (tTd(48, 4))
dprintf(" ... validate_connection: BAD (rscheck)\n");
if (strlen(MsgBuf) >= 3)
(void) strlcpy(reject, MsgBuf, sizeof reject);
else
(void) strlcpy(reject, "Access denied", sizeof reject);
return reject;
}
# if TCPWRAPPERS
if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
host = "unknown";
else
host = hostname;
if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
{
if (tTd(48, 4))
dprintf(" ... validate_connection: BAD (tcpwrappers)\n");
if (LogLevel >= 4)
sm_syslog(LOG_NOTICE, e->e_id,
"tcpwrappers (%s, %s) rejection",
host, anynet_ntoa(sap));
return "Access denied";
}
# endif /* TCPWRAPPERS */
if (tTd(48, 4))
dprintf(" ... validate_connection: OK\n");
return NULL;
}
#endif /* DAEMON */
/*
** 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.
*/
#if NEEDSTRTOL
# if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
# endif /* defined(LIBC_SCCS) && !defined(lint) */
/*
* 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 /* NEEDSTRTOL */
/*
** STRSTR -- find first substring in string
**
** Parameters:
** big -- the big (full) string.
** little -- the little (sub) string.
**
** Returns:
** A pointer to the first instance of little in big.
** big if little is the null string.
** NULL if little is not contained in big.
*/
#if NEEDSTRSTR
char *
strstr(big, little)
char *big;
char *little;
{
register char *p = big;
int l;
if (*little == '\0')
return big;
l = strlen(little);
while ((p = strchr(p, *little)) != NULL)
{
if (strncmp(p, little, l) == 0)
return p;
p++;
}
return NULL;
}
#endif /* NEEDSTRSTR */
/*
** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
**
** Some operating systems have wierd problems with the gethostbyXXX
** routines. For example, Solaris versions at least through 2.3
** don't properly deliver a canonical h_name field. This tries to
** work around these problems.
**
** Support IPv6 as well as IPv4.
*/
#if NETINET6 && NEEDSGETIPNODE && __RES < 19990909
# ifndef AI_DEFAULT
# define AI_DEFAULT 0 /* dummy */
# endif /* ! AI_DEFAULT */
# ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0 /* dummy */
# endif /* ! AI_ADDRCONFIG */
# ifndef AI_V4MAPPED
# define AI_V4MAPPED 0 /* dummy */
# endif /* ! AI_V4MAPPED */
# ifndef AI_ALL
# define AI_ALL 0 /* dummy */
# endif /* ! AI_ALL */
static struct hostent *
getipnodebyname(name, family, flags, err)
char *name;
int family;
int flags;
int *err;
{
bool resv6 = TRUE;
struct hostent *h;
if (family == AF_INET6)
{
/* From RFC2133, section 6.1 */
resv6 = bitset(RES_USE_INET6, _res.options);
_res.options |= RES_USE_INET6;
}
h_errno = 0;
h = gethostbyname(name);
*err = h_errno;
if (family == AF_INET6 && !resv6)
_res.options &= ~RES_USE_INET6;
return h;
}
static struct hostent *
getipnodebyaddr(addr, len, family, err)
char *addr;
int len;
int family;
int *err;
{
struct hostent *h;
h_errno = 0;
h = gethostbyaddr(addr, len, family);
*err = h_errno;
return h;
}
#endif /* NEEDSGETIPNODE && NETINET6 && __RES < 19990909 */
struct hostent *
sm_gethostbyname(name, family)
char *name;
int family;
{
struct hostent *h = NULL;
#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
# if SOLARIS == 20300 || SOLARIS == 203
static struct hostent hp;
static char buf[1000];
extern struct hostent *_switch_gethostbyname_r();
if (tTd(61, 10))
dprintf("_switch_gethostbyname_r(%s)... ", name);
h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
# else /* SOLARIS == 20300 || SOLARIS == 203 */
extern struct hostent *__switch_gethostbyname();
if (tTd(61, 10))
dprintf("__switch_gethostbyname(%s)... ", name);
h = __switch_gethostbyname(name);
# endif /* SOLARIS == 20300 || SOLARIS == 203 */
#else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
int nmaps;
# if NETINET6
int flags = AI_DEFAULT|AI_ALL;
int err;
# endif /* NETINET6 */
int save_errno;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
char hbuf[MAXNAME];
if (tTd(61, 10))
dprintf("sm_gethostbyname(%s, %d)... ", name, family);
# if NETINET6
# if ADDRCONFIG_IS_BROKEN
flags &= ~AI_ADDRCONFIG;
# endif /* ADDRCONFIG_IS_BROKEN */
h = getipnodebyname(name, family, flags, &err);
h_errno = err;
# else /* NETINET6 */
h = gethostbyname(name);
# endif /* NETINET6 */
save_errno = errno;
if (h == NULL)
{
if (tTd(61, 10))
dprintf("failure\n");
nmaps = switch_map_find("hosts", maptype, mapreturn);
while (--nmaps >= 0)
if (strcmp(maptype[nmaps], "nis") == 0 ||
strcmp(maptype[nmaps], "files") == 0)
break;
if (nmaps >= 0)
{
/* try short name */
if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
{
errno = save_errno;
return NULL;
}
(void) strlcpy(hbuf, name, sizeof hbuf);
shorten_hostname(hbuf);
/* if it hasn't been shortened, there's no point */
if (strcmp(hbuf, name) != 0)
{
if (tTd(61, 10))
dprintf("sm_gethostbyname(%s, %d)... ",
hbuf, family);
# if NETINET6
h = getipnodebyname(hbuf, family,
AI_V4MAPPED|AI_ALL,
&err);
h_errno = err;
save_errno = errno;
# else /* NETINET6 */
h = gethostbyname(hbuf);
save_errno = errno;
# endif /* NETINET6 */
}
}
}
#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
if (tTd(61, 10))
{
if (h == NULL)
dprintf("failure\n");
else
{
dprintf("%s\n", h->h_name);
if (tTd(61, 11))
{
#if NETINET6
struct in6_addr ia6;
char buf6[INET6_ADDRSTRLEN];
#else /* NETINET6 */
struct in_addr ia;
#endif /* NETINET6 */
int i;
if (h->h_aliases != NULL)
for (i = 0; h->h_aliases[i] != NULL;
i++)
dprintf("\talias: %s\n",
h->h_aliases[i]);
for (i = 0; h->h_addr_list[i] != NULL; i++)
{
char *addr;
#if NETINET6
memmove(&ia6, h->h_addr_list[i],
IN6ADDRSZ);
addr = anynet_ntop(&ia6,
buf6, sizeof buf6);
#else /* NETINET6 */
memmove(&ia, h->h_addr_list[i],
INADDRSZ);
addr = (char *) inet_ntoa(ia);
#endif /* NETINET6 */
if (addr != NULL)
dprintf("\taddr: %s\n", addr);
}
}
}
}
errno = save_errno;
return h;
}
struct hostent *
sm_gethostbyaddr(addr, len, type)
char *addr;
int len;
int type;
{
struct hostent *hp;
#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
# if SOLARIS == 20300 || SOLARIS == 203
static struct hostent he;
static char buf[1000];
extern struct hostent *_switch_gethostbyaddr_r();
hp = _switch_gethostbyaddr_r(addr, len, type, &he, buf, sizeof(buf), &h_errno);
# else /* SOLARIS == 20300 || SOLARIS == 203 */
extern struct hostent *__switch_gethostbyaddr();
hp = __switch_gethostbyaddr(addr, len, type);
# endif /* SOLARIS == 20300 || SOLARIS == 203 */
#else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
# if NETINET6
int err;
# endif /* NETINET6 */
# if NETINET6
hp = getipnodebyaddr(addr, len, type, &err);
h_errno = err;
# else /* NETINET6 */
hp = gethostbyaddr(addr, len, type);
# endif /* NETINET6 */
return hp;
#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
}
/*
** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
*/
struct passwd *
sm_getpwnam(user)
char *user;
{
# ifdef _AIX4
extern struct passwd *_getpwnam_shadow(const char *, const int);
return _getpwnam_shadow(user, 0);
# else /* _AIX4 */
return getpwnam(user);
# endif /* _AIX4 */
}
struct passwd *
sm_getpwuid(uid)
UID_T uid;
{
# if defined(_AIX4) && 0
extern struct passwd *_getpwuid_shadow(const int, const int);
return _getpwuid_shadow(uid,0);
# else /* defined(_AIX4) && 0 */
return getpwuid(uid);
# endif /* defined(_AIX4) && 0 */
}
/*
** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
**
** Set up the trusted computing environment for C2 level security
** under SecureWare.
**
** Parameters:
** uid -- uid of the user to initialize in the TCB
**
** Returns:
** none
**
** Side Effects:
** Initialized the user in the trusted computing base
*/
#if SECUREWARE
# include <sys/security.h>
# include <prot.h>
void
secureware_setup_secure(uid)
UID_T uid;
{
int rc;
if (getluid() != -1)
return;
if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
{
switch (rc)
{
case SSI_NO_PRPW_ENTRY:
syserr("No protected passwd entry, uid = %d", uid);
break;
case SSI_LOCKED:
syserr("Account has been disabled, uid = %d", uid);
break;
case SSI_RETIRED:
syserr("Account has been retired, uid = %d", uid);
break;
case SSI_BAD_SET_LUID:
syserr("Could not set LUID, uid = %d", uid);
break;
case SSI_BAD_SET_PRIVS:
syserr("Could not set kernel privs, uid = %d", uid);
default:
syserr("Unknown return code (%d) from set_secure_info(%d)",
rc, uid);
break;
}
finis(FALSE, EX_NOPERM);
}
}
#endif /* SECUREWARE */
/*
** ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
**
** Add hostnames to class 'w' based on the IP address read from
** the network interface.
**
** Parameters:
** sa -- a pointer to a SOCKADDR containing the address
**
** Returns:
** 0 if successful, -1 if host lookup fails.
*/
static int
add_hostnames(sa)
SOCKADDR *sa;
{
struct hostent *hp;
char **ha;
char hnb[MAXHOSTNAMELEN];
/* lookup name with IP address */
switch (sa->sa.sa_family)
{
#if NETINET
case AF_INET:
hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
sizeof(sa->sin.sin_addr), sa->sa.sa_family);
break;
#endif /* NETINET */
#if NETINET6
case AF_INET6:
hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
sizeof(sa->sin6.sin6_addr), sa->sa.sa_family);
break;
#endif /* NETINET6 */
default:
/* Give warning about unsupported family */
if (LogLevel > 3)
sm_syslog(LOG_WARNING, NOQID,
"Unsupported address family %d: %.100s",
sa->sa.sa_family, anynet_ntoa(sa));
return -1;
}
if (hp == NULL)
{
int save_errno = errno;
if (LogLevel > 3 &&
#if NETINET6
!(sa->sa.sa_family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
#endif /* NETINET6 */
TRUE)
sm_syslog(LOG_WARNING, NOQID,
"gethostbyaddr(%.100s) failed: %d\n",
anynet_ntoa(sa),
#if NAMED_BIND
h_errno
#else /* NAMED_BIND */
-1
#endif /* NAMED_BIND */
);
errno = save_errno;
return -1;
}
/* save its cname */
if (!wordinclass((char *) hp->h_name, 'w'))
{
setclass('w', (char *) hp->h_name);
if (tTd(0, 4))
dprintf("\ta.k.a.: %s\n", hp->h_name);
if (snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb
&& !wordinclass((char *) hnb, 'w'))
setclass('w', hnb);
}
else
{
if (tTd(0, 43))
dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
}
/* save all it aliases name */
for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
{
if (!wordinclass(*ha, 'w'))
{
setclass('w', *ha);
if (tTd(0, 4))
dprintf("\ta.k.a.: %s\n", *ha);
if (snprintf(hnb, sizeof hnb,
"[%s]", *ha) < sizeof hnb &&
!wordinclass((char *) hnb, 'w'))
setclass('w', hnb);
}
else
{
if (tTd(0, 43))
dprintf("\ta.k.a.: %s (already in $=w)\n",
*ha);
}
}
return 0;
}
/*
** LOAD_IF_NAMES -- load interface-specific names into $=w
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** Loads $=w with the names of all the interfaces.
*/
#if !NETINET
# define SIOCGIFCONF_IS_BROKEN 1 /* XXX */
#endif /* !NETINET */
#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
struct rtentry;
struct mbuf;
# ifndef SUNOS403
# include <sys/time.h>
# endif /* ! SUNOS403 */
# if (_AIX4 >= 40300) && !defined(_NET_IF_H)
# undef __P
# endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
# include <net/if.h>
#endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
void
load_if_names()
{
#if NETINET6 && defined(SIOCGLIFCONF)
int s;
int i;
struct lifconf lifc;
struct lifnum lifn;
int numifs;
s = socket(InetMode, SOCK_DGRAM, 0);
if (s == -1)
return;
/* get the list of known IP address from the kernel */
# ifdef SIOCGLIFNUM
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = 0;
if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
{
/* can't get number of interfaces -- fall back */
if (tTd(0, 4))
dprintf("SIOCGLIFNUM failed: %s\n", errstring(errno));
numifs = -1;
}
else
{
numifs = lifn.lifn_count;
if (tTd(0, 42))
dprintf("system has %d interfaces\n", numifs);
}
if (numifs < 0)
# endif /* SIOCGLIFNUM */
numifs = MAXINTERFACES;
if (numifs <= 0)
{
close(s);
return;
}
lifc.lifc_len = numifs * sizeof (struct lifreq);
lifc.lifc_buf = xalloc(lifc.lifc_len);
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = 0;
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
{
if (tTd(0, 4))
dprintf("SIOCGLIFCONF failed: %s\n", errstring(errno));
close(s);
return;
}
/* scan the list of IP address */
if (tTd(0, 40))
dprintf("scanning for interface specific names, lifc_len=%d\n",
lifc.lifc_len);
for (i = 0; i < lifc.lifc_len; )
{
struct lifreq *ifr = (struct lifreq *)&lifc.lifc_buf[i];
SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
char *addr;
struct in6_addr ia6;
struct in_addr ia;
# ifdef SIOCGLIFFLAGS
struct lifreq ifrf;
# endif /* SIOCGLIFFLAGS */
char ip_addr[256];
char buf6[INET6_ADDRSTRLEN];
int af = ifr->lifr_addr.ss_family;
/*
** We must close and recreate the socket each time
** since we don't know what type of socket it is now
** (each status function may change it).
*/
(void) close(s);
s = socket(af, SOCK_DGRAM, 0);
if (s == -1)
return;
/*
** If we don't have a complete ifr structure,
** don't try to use it.
*/
if ((lifc.lifc_len - i) < sizeof *ifr)
break;
# ifdef BSD4_4_SOCKADDR
if (sa->sa.sa_len > sizeof ifr->lifr_addr)
i += sizeof ifr->lifr_name + sa->sa.sa_len;
else
# endif /* BSD4_4_SOCKADDR */
i += sizeof *ifr;
if (tTd(0, 20))
dprintf("%s\n", anynet_ntoa(sa));
if (af != AF_INET && af != AF_INET6)
continue;
# ifdef SIOCGLIFFLAGS
memset(&ifrf, '\0', sizeof(struct lifreq));
(void) strlcpy(ifrf.lifr_name, ifr->lifr_name,
sizeof(ifrf.lifr_name));
if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
{
if (tTd(0, 4))
dprintf("SIOCGLIFFLAGS failed: %s\n",
errstring(errno));
continue;
}
else if (tTd(0, 41))
dprintf("\tflags: %lx\n",
(unsigned long)ifrf.lifr_flags);
if (!bitset(IFF_UP, ifrf.lifr_flags))
continue;
# endif /* SIOCGLIFFLAGS */
ip_addr[0] = '\0';
/* extract IP address from the list*/
switch (af)
{
case AF_INET6:
ia6 = sa->sin6.sin6_addr;
if (ia6.s6_addr == in6addr_any.s6_addr)
{
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
message("WARNING: interface %s is UP with %s address",
ifr->lifr_name,
addr == NULL ? "(NULL)" : addr);
continue;
}
/* save IP address in text from */
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
if (addr != NULL)
(void) snprintf(ip_addr, sizeof ip_addr,
"[%.*s]",
- sizeof ip_addr - 3, addr);
+ (int) sizeof ip_addr - 3, addr);
break;
case AF_INET:
ia = sa->sin.sin_addr;
if (ia.s_addr == INADDR_ANY ||
ia.s_addr == INADDR_NONE)
{
message("WARNING: interface %s is UP with %s address",
ifr->lifr_name, inet_ntoa(ia));
continue;
}
/* save IP address in text from */
(void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
- sizeof ip_addr - 3, inet_ntoa(ia));
+ (int) sizeof ip_addr - 3, inet_ntoa(ia));
break;
}
if (*ip_addr == '\0')
continue;
if (!wordinclass(ip_addr, 'w'))
{
setclass('w', ip_addr);
if (tTd(0, 4))
dprintf("\ta.k.a.: %s\n", ip_addr);
}
# ifdef SIOCGLIFFLAGS
/* skip "loopback" interface "lo" */
if (bitset(IFF_LOOPBACK, ifrf.lifr_flags))
continue;
# endif /* SIOCGLIFFLAGS */
(void) add_hostnames(sa);
}
free(lifc.lifc_buf);
close(s);
#else /* NETINET6 && defined(SIOCGLIFCONF) */
# if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
int s;
int i;
struct ifconf ifc;
int numifs;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
return;
/* get the list of known IP address from the kernel */
# if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
{
/* can't get number of interfaces -- fall back */
if (tTd(0, 4))
dprintf("SIOCGIFNUM failed: %s\n", errstring(errno));
numifs = -1;
}
else if (tTd(0, 42))
dprintf("system has %d interfaces\n", numifs);
if (numifs < 0)
# endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
numifs = MAXINTERFACES;
if (numifs <= 0)
{
(void) close(s);
return;
}
ifc.ifc_len = numifs * sizeof (struct ifreq);
ifc.ifc_buf = xalloc(ifc.ifc_len);
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
{
if (tTd(0, 4))
dprintf("SIOCGIFCONF failed: %s\n", errstring(errno));
(void) close(s);
+ free(ifc.ifc_buf);
return;
}
/* scan the list of IP address */
if (tTd(0, 40))
dprintf("scanning for interface specific names, ifc_len=%d\n",
ifc.ifc_len);
for (i = 0; i < ifc.ifc_len; )
{
int af;
struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
# if NETINET6
char *addr;
struct in6_addr ia6;
# endif /* NETINET6 */
struct in_addr ia;
# ifdef SIOCGIFFLAGS
struct ifreq ifrf;
# endif /* SIOCGIFFLAGS */
char ip_addr[256];
# if NETINET6
char buf6[INET6_ADDRSTRLEN];
# endif /* NETINET6 */
/*
** If we don't have a complete ifr structure,
** don't try to use it.
*/
if ((ifc.ifc_len - i) < sizeof *ifr)
break;
# ifdef BSD4_4_SOCKADDR
if (sa->sa.sa_len > sizeof ifr->ifr_addr)
i += sizeof ifr->ifr_name + sa->sa.sa_len;
else
# endif /* BSD4_4_SOCKADDR */
i += sizeof *ifr;
if (tTd(0, 20))
dprintf("%s\n", anynet_ntoa(sa));
af = ifr->ifr_addr.sa_family;
if (af != AF_INET
# if NETINET6
&& af != AF_INET6
# endif /* NETINET6 */
)
continue;
# ifdef SIOCGIFFLAGS
memset(&ifrf, '\0', sizeof(struct ifreq));
(void) strlcpy(ifrf.ifr_name, ifr->ifr_name,
sizeof(ifrf.ifr_name));
(void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
if (tTd(0, 41))
dprintf("\tflags: %lx\n",
(unsigned long) ifrf.ifr_flags);
# define IFRFREF ifrf
# else /* SIOCGIFFLAGS */
# define IFRFREF (*ifr)
# endif /* SIOCGIFFLAGS */
if (!bitset(IFF_UP, IFRFREF.ifr_flags))
continue;
ip_addr[0] = '\0';
/* extract IP address from the list*/
switch (af)
{
case AF_INET:
ia = sa->sin.sin_addr;
if (ia.s_addr == INADDR_ANY ||
ia.s_addr == INADDR_NONE)
{
message("WARNING: interface %s is UP with %s address",
ifr->ifr_name, inet_ntoa(ia));
continue;
}
/* save IP address in text from */
(void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
(int) sizeof ip_addr - 3,
inet_ntoa(ia));
break;
# if NETINET6
case AF_INET6:
ia6 = sa->sin6.sin6_addr;
if (ia6.s6_addr == in6addr_any.s6_addr)
{
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
message("WARNING: interface %s is UP with %s address",
ifr->ifr_name,
addr == NULL ? "(NULL)" : addr);
continue;
}
/* save IP address in text from */
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
if (addr != NULL)
(void) snprintf(ip_addr, sizeof ip_addr,
"[%.*s]",
(int) sizeof ip_addr - 3, addr);
break;
# endif /* NETINET6 */
}
if (ip_addr[0] == '\0')
continue;
if (!wordinclass(ip_addr, 'w'))
{
setclass('w', ip_addr);
if (tTd(0, 4))
dprintf("\ta.k.a.: %s\n", ip_addr);
}
/* skip "loopback" interface "lo" */
if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
continue;
(void) add_hostnames(sa);
}
free(ifc.ifc_buf);
(void) close(s);
# undef IFRFREF
# endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
#endif /* NETINET6 && defined(SIOCGLIFCONF) */
}
/*
** ISLOOPBACK -- is socket address in the loopback net?
**
** Parameters:
** sa -- socket address.
**
** Returns:
** TRUE -- is socket address in the loopback net?
** FALSE -- otherwise
**
*/
bool
isloopback(sa)
SOCKADDR sa;
{
#if NETINET6
if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
return TRUE;
#else /* NETINET6 */
/* XXX how to correctly extract IN_LOOPBACKNET part? */
if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
>> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
return TRUE;
#endif /* NETINET6 */
return FALSE;
}
/*
** GET_NUM_PROCS_ONLINE -- return the number of processors currently online
**
** Parameters:
** none.
**
** Returns:
** The number of processors online.
*/
static int
get_num_procs_online()
{
int nproc = 0;
#ifdef USESYSCTL
# if defined(CTL_HW) && defined(HW_NCPU)
size_t sz;
int mib[2];
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
sz = (size_t) sizeof nproc;
(void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
# endif /* defined(CTL_HW) && defined(HW_NCPUS) */
#else /* USESYSCTL */
# ifdef _SC_NPROCESSORS_ONLN
nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
# else /* _SC_NPROCESSORS_ONLN */
# ifdef __hpux
# include <sys/pstat.h>
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
nproc = psd.psd_proc_cnt;
# endif /* __hpux */
# endif /* _SC_NPROCESSORS_ONLN */
#endif /* USESYSCTL */
if (nproc <= 0)
nproc = 1;
return nproc;
}
/*
** SEED_RANDOM -- seed the random number generator
**
** Parameters:
** none
**
** Returns:
** none
*/
void
seed_random()
{
#if HASSRANDOMDEV
srandomdev();
#else /* HASSRANDOMDEV */
long seed;
struct timeval t;
seed = (long) getpid();
if (gettimeofday(&t, NULL) >= 0)
seed += t.tv_sec + t.tv_usec;
# if HASRANDOM
(void) srandom(seed);
# else /* HASRANDOM */
(void) srand((unsigned int) seed);
# endif /* HASRANDOM */
#endif /* HASSRANDOMDEV */
}
/*
** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
**
** Parameters:
** level -- syslog level
** id -- envelope ID or NULL (NOQUEUE)
** fmt -- format string
** arg... -- arguments as implied by fmt.
**
** Returns:
** none
*/
/* VARARGS3 */
void
#ifdef __STDC__
sm_syslog(int level, const char *id, const char *fmt, ...)
#else /* __STDC__ */
sm_syslog(level, id, fmt, va_alist)
int level;
const char *id;
const char *fmt;
va_dcl
#endif /* __STDC__ */
{
static char *buf = NULL;
static size_t bufsize;
char *begin, *end;
int save_errno;
int seq = 1;
int idlen;
char buf0[MAXLINE];
extern int SnprfOverflow;
extern int SyslogErrno;
extern char *DoprEnd;
VA_LOCAL_DECL
save_errno = SyslogErrno = errno;
if (id == NULL)
id = "NOQUEUE";
else if (strcmp(id, NOQID) == 0)
id = "";
idlen = strlen(id);
if (buf == NULL)
{
buf = buf0;
bufsize = sizeof buf0;
}
for (;;)
{
/* do a virtual vsnprintf into buf */
VA_START(fmt);
buf[0] = 0;
DoprEnd = buf + bufsize - 1;
SnprfOverflow = 0;
sm_dopr(buf, fmt, ap);
*DoprEnd = '\0';
VA_END;
/* end of virtual vsnprintf */
if (SnprfOverflow == 0)
break;
/* String too small, redo with correct size */
bufsize += SnprfOverflow + 1;
if (buf != buf0)
free(buf);
buf = xalloc(bufsize * sizeof (char));
}
if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
{
#if LOG
if (*id == '\0')
syslog(level, "%s", buf);
else
syslog(level, "%s: %s", id, buf);
#else /* LOG */
/*XXX should do something more sensible */
if (*id == '\0')
fprintf(stderr, "%s\n", buf);
else
fprintf(stderr, "%s: %s\n", id, buf);
#endif /* LOG */
if (buf == buf0)
buf = NULL;
errno = save_errno;
return;
}
begin = buf;
while (*begin != '\0' &&
(strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
{
char save;
if (seq == 999)
{
/* Too many messages */
break;
}
end = begin + SYSLOG_BUFSIZE - idlen - 12;
while (end > begin)
{
/* Break on comma or space */
if (*end == ',' || *end == ' ')
{
end++; /* Include separator */
break;
}
end--;
}
/* No separator, break midstring... */
if (end == begin)
end = begin + SYSLOG_BUFSIZE - idlen - 12;
save = *end;
*end = 0;
#if LOG
syslog(level, "%s[%d]: %s ...", id, seq++, begin);
#else /* LOG */
fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
#endif /* LOG */
*end = save;
begin = end;
}
if (seq == 999)
#if LOG
syslog(level, "%s[%d]: log terminated, too many parts",
id, seq);
#else /* LOG */
fprintf(stderr, "%s[%d]: log terminated, too many parts\n",
id, seq);
#endif /* LOG */
else if (*begin != '\0')
#if LOG
syslog(level, "%s[%d]: %s", id, seq, begin);
#else /* LOG */
fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
#endif /* LOG */
if (buf == buf0)
buf = NULL;
errno = save_errno;
}
/*
** HARD_SYSLOG -- call syslog repeatedly until it works
**
** Needed on HP-UX, which apparently doesn't guarantee that
** syslog succeeds during interrupt handlers.
*/
#if defined(__hpux) && !defined(HPUX11)
# define MAXSYSLOGTRIES 100
# undef syslog
# ifdef V4FS
# define XCNST const
# define CAST (const char *)
# else /* V4FS */
# define XCNST
# define CAST
# endif /* V4FS */
void
# ifdef __STDC__
hard_syslog(int pri, XCNST char *msg, ...)
# else /* __STDC__ */
hard_syslog(pri, msg, va_alist)
int pri;
XCNST char *msg;
va_dcl
# endif /* __STDC__ */
{
int i;
char buf[SYSLOG_BUFSIZE];
VA_LOCAL_DECL;
VA_START(msg);
vsnprintf(buf, sizeof buf, msg, ap);
VA_END;
for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
continue;
}
# undef CAST
#endif /* defined(__hpux) && !defined(HPUX11) */
#if NEEDLOCAL_HOSTNAME_LENGTH
/*
** LOCAL_HOSTNAME_LENGTH
**
** This is required to get sendmail to compile against BIND 4.9.x
** on Ultrix.
**
** Unfortunately, a Compaq Y2K patch kit provides it without
** bumping __RES in /usr/include/resolv.h so we can't automatically
** figure out whether it is needed.
*/
int
local_hostname_length(hostname)
char *hostname;
{
int len_host, len_domain;
if (!*_res.defdname)
res_init();
len_host = strlen(hostname);
len_domain = strlen(_res.defdname);
if (len_host > len_domain &&
(strcasecmp(hostname + len_host - len_domain,
_res.defdname) == 0) &&
hostname[len_host - len_domain - 1] == '.')
return len_host - len_domain - 1;
else
return 0;
}
#endif /* NEEDLOCAL_HOSTNAME_LENGTH */
/*
** Compile-Time options
*/
char *CompileOptions[] =
{
#ifdef HESIOD
"HESIOD",
#endif /* HESIOD */
#if HES_GETMAILHOST
"HES_GETMAILHOST",
#endif /* HES_GETMAILHOST */
#ifdef LDAPMAP
"LDAPMAP",
#endif /* LDAPMAP */
#ifdef MAP_NSD
"MAP_NSD",
#endif /* MAP_NSD */
#ifdef MAP_REGEX
"MAP_REGEX",
#endif /* MAP_REGEX */
#if LOG
"LOG",
#endif /* LOG */
#if MATCHGECOS
"MATCHGECOS",
#endif /* MATCHGECOS */
#if MIME7TO8
"MIME7TO8",
#endif /* MIME7TO8 */
#if MIME8TO7
"MIME8TO7",
#endif /* MIME8TO7 */
#if NAMED_BIND
"NAMED_BIND",
#endif /* NAMED_BIND */
#ifdef NDBM
"NDBM",
#endif /* NDBM */
#if NETINET
"NETINET",
#endif /* NETINET */
#if NETINET6
"NETINET6",
#endif /* NETINET6 */
#if NETINFO
"NETINFO",
#endif /* NETINFO */
#if NETISO
"NETISO",
#endif /* NETISO */
#if NETNS
"NETNS",
#endif /* NETNS */
#if NETUNIX
"NETUNIX",
#endif /* NETUNIX */
#if NETX25
"NETX25",
#endif /* NETX25 */
#ifdef NEWDB
"NEWDB",
#endif /* NEWDB */
#ifdef NIS
"NIS",
#endif /* NIS */
#ifdef NISPLUS
"NISPLUS",
#endif /* NISPLUS */
#ifdef PH_MAP
"PH_MAP",
#endif /* PH_MAP */
#if QUEUE
"QUEUE",
#endif /* QUEUE */
#if SASL
"SASL",
#endif /* SASL */
#if SCANF
"SCANF",
#endif /* SCANF */
#if SFIO
"SFIO",
#endif /* SFIO */
#if SMTP
"SMTP",
#endif /* SMTP */
#if SMTPDEBUG
"SMTPDEBUG",
#endif /* SMTPDEBUG */
#if STARTTLS
"STARTTLS",
#endif /* STARTTLS */
#ifdef SUID_ROOT_FILES_OK
"SUID_ROOT_FILES_OK",
#endif /* SUID_ROOT_FILES_OK */
#if TCPWRAPPERS
"TCPWRAPPERS",
#endif /* TCPWRAPPERS */
#if USERDB
"USERDB",
#endif /* USERDB */
#if XDEBUG
"XDEBUG",
#endif /* XDEBUG */
#ifdef XLA
"XLA",
#endif /* XLA */
NULL
};
/*
** OS compile options.
*/
char *OsCompileOptions[] =
{
#if BOGUS_O_EXCL
"BOGUS_O_EXCL",
#endif /* BOGUS_O_EXCL */
#if FAST_PID_RECYCLE
"FAST_PID_RECYCLE",
#endif /* FAST_PID_RECYCLE */
#if HASFCHOWN
"HASFCHOWN",
#endif /* HASFCHOWN */
#if HASFCHMOD
"HASFCHMOD",
#endif /* HASFCHMOD */
#if HASFLOCK
"HASFLOCK",
#endif /* HASFLOCK */
#if HASGETDTABLESIZE
"HASGETDTABLESIZE",
#endif /* HASGETDTABLESIZE */
#if HASGETUSERSHELL
"HASGETUSERSHELL",
#endif /* HASGETUSERSHELL */
#if HASINITGROUPS
"HASINITGROUPS",
#endif /* HASINITGROUPS */
#if HASLSTAT
"HASLSTAT",
#endif /* HASLSTAT */
#if HASRANDOM
"HASRANDOM",
#endif /* HASRANDOM */
#if HASSETLOGIN
"HASSETLOGIN",
#endif /* HASSETLOGIN */
#if HASSETREUID
"HASSETREUID",
#endif /* HASSETREUID */
#if HASSETRLIMIT
"HASSETRLIMIT",
#endif /* HASSETRLIMIT */
#if HASSETSID
"HASSETSID",
#endif /* HASSETSID */
#if HASSETUSERCONTEXT
"HASSETUSERCONTEXT",
#endif /* HASSETUSERCONTEXT */
#if HASSETVBUF
"HASSETVBUF",
#endif /* HASSETVBUF */
#if HASSNPRINTF
"HASSNPRINTF",
#endif /* HASSNPRINTF */
#if HAS_ST_GEN
"HAS_ST_GEN",
#endif /* HAS_ST_GEN */
#if HASSRANDOMDEV
"HASSRANDOMDEV",
#endif /* HASSRANDOMDEV */
#if HASURANDOMDEV
"HASURANDOMDEV",
#endif /* HASURANDOMDEV */
#if HASSTRERROR
"HASSTRERROR",
#endif /* HASSTRERROR */
#if HASULIMIT
"HASULIMIT",
#endif /* HASULIMIT */
#if HASUNAME
"HASUNAME",
#endif /* HASUNAME */
#if HASUNSETENV
"HASUNSETENV",
#endif /* HASUNSETENV */
#if HASWAITPID
"HASWAITPID",
#endif /* HASWAITPID */
#if IDENTPROTO
"IDENTPROTO",
#endif /* IDENTPROTO */
#if IP_SRCROUTE
"IP_SRCROUTE",
#endif /* IP_SRCROUTE */
#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
"LOCK_ON_OPEN",
#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
#if NEEDFSYNC
"NEEDFSYNC",
#endif /* NEEDFSYNC */
#if NOFTRUNCATE
"NOFTRUNCATE",
#endif /* NOFTRUNCATE */
#if RLIMIT_NEEDS_SYS_TIME_H
"RLIMIT_NEEDS_SYS_TIME_H",
#endif /* RLIMIT_NEEDS_SYS_TIME_H */
#if SAFENFSPATHCONF
"SAFENFSPATHCONF",
#endif /* SAFENFSPATHCONF */
#if SECUREWARE
"SECUREWARE",
#endif /* SECUREWARE */
#if SHARE_V1
"SHARE_V1",
#endif /* SHARE_V1 */
#if SIOCGIFCONF_IS_BROKEN
"SIOCGIFCONF_IS_BROKEN",
#endif /* SIOCGIFCONF_IS_BROKEN */
#if SIOCGIFNUM_IS_BROKEN
"SIOCGIFNUM_IS_BROKEN",
#endif /* SIOCGIFNUM_IS_BROKEN */
#if SNPRINTF_IS_BROKEN
"SNPRINTF_IS_BROKEN",
#endif /* SNPRINTF_IS_BROKEN */
#if SO_REUSEADDR_IS_BROKEN
"SO_REUSEADDR_IS_BROKEN",
#endif /* SO_REUSEADDR_IS_BROKEN */
#if SYS5SETPGRP
"SYS5SETPGRP",
#endif /* SYS5SETPGRP */
#if SYSTEM5
"SYSTEM5",
#endif /* SYSTEM5 */
#if USE_SA_SIGACTION
"USE_SA_SIGACTION",
#endif /* USE_SA_SIGACTION */
#if USE_SIGLONGJMP
"USE_SIGLONGJMP",
#endif /* USE_SIGLONGJMP */
#if USESETEUID
"USESETEUID",
#endif /* USESETEUID */
NULL
};
Index: head/contrib/sendmail/src/conf.h
===================================================================
--- head/contrib/sendmail/src/conf.h (revision 66496)
+++ head/contrib/sendmail/src/conf.h (revision 66497)
@@ -1,2802 +1,2809 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*
- * $Id: conf.h,v 8.496.4.20 2000/07/15 17:35:19 gshapiro Exp $
+ * $Id: conf.h,v 8.496.4.25 2000/08/08 23:50:40 ca Exp $
*/
/* $FreeBSD$ */
/*
** CONF.H -- All user-configurable parameters for sendmail
**
** Send updates to sendmail@Sendmail.ORG so they will be
** included in the next release.
*/
#ifndef CONF_H
#define CONF_H 1
#ifdef __GNUC__
struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#endif /* __GNUC__ */
# include <sys/param.h>
# include <sys/types.h>
# if SFIO && defined(SF_APPEND)
# undef SF_APPEND /* Both sfio/stdio.h and sys/stat.h define it */
# endif /* SFIO && defined(SF_APPEND) */
# include <sys/stat.h>
# ifndef __QNX__
/* in QNX this grabs bogus LOCK_* manifests */
# include <sys/file.h>
# endif /* ! __QNX__ */
# include <sys/wait.h>
# include <limits.h>
# include <fcntl.h>
# include <signal.h>
# include <netdb.h>
# include <pwd.h>
# include <grp.h>
/* make sure TOBUFSIZ isn't larger than system limit for size of exec() args */
#ifdef ARG_MAX
# if ARG_MAX > 4096
# define SM_ARG_MAX 4096
# else /* ARG_MAX > 4096 */
# define SM_ARG_MAX ARG_MAX
# endif /* ARG_MAX > 4096 */
#else /* ARG_MAX */
# define SM_ARG_MAX 4096
#endif /* ARG_MAX */
/**********************************************************************
** Table sizes, etc....
** There shouldn't be much need to change these....
**********************************************************************/
#define MAXLINE 2048 /* max line length */
#define MAXNAME 256 /* max length of a name */
#define MAXPV 256 /* max # of parms to mailers */
#define MAXATOM 1000 /* max atoms per address */
#define MAXRWSETS 200 /* max # of sets of rewriting rules */
#define MAXPRIORITIES 25 /* max values for Precedence: field */
#define MAXMXHOSTS 100 /* max # of MX records for one host */
#define SMTPLINELIM 990 /* maximum SMTP line length */
#define MAXKEY 128 /* maximum size of a database key */
#define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */
#define MAXUSERENVIRON 100 /* max envars saved, must be >= 3 */
#define MAXALIASDB 12 /* max # of alias databases */
#define MAXMAPSTACK 12 /* max # of stacked or sequenced maps */
#if _FFR_MILTER
# define MAXFILTERS 25 /* max # of milter filters */
# define MAXFILTERMACROS 50 /* max # of macros per milter cmd */
#endif /* _FFR_MILTER */
#define MAXSMTPARGS 20 /* max # of ESMTP args for MAIL/RCPT */
#define MAXTOCLASS 8 /* max # of message timeout classes */
#define MAXRESTOTYPES 3 /* max # of resolver timeout types */
#define MAXMIMEARGS 20 /* max args in Content-Type: */
#define MAXMIMENESTING 20 /* max MIME multipart nesting */
#define QUEUESEGSIZE 1000 /* increment for queue size */
#define MAXQFNAME 20 /* max qf file name length */
#define MACBUFSIZE 4096 /* max expanded macro buffer size */
#define TOBUFSIZE SM_ARG_MAX /* max buffer to hold address list */
#define MAXSHORTSTR 203 /* max short string length */
#define MAXMACNAMELEN 25 /* max macro name length */
#define MAXMACROID 0377 /* max macro id number */
#ifndef MAXHDRSLEN
# define MAXHDRSLEN (32 * 1024) /* max size of message headers */
#endif /* ! MAXHDRSLEN */
#define MAXDAEMONS 10 /* max number of ports to listen to */
#ifndef MAXINTERFACES
# define MAXINTERFACES 512 /* number of interfaces to probe */
#endif /* MAXINTERFACES */
#ifndef MAXSYMLINKS
# define MAXSYMLINKS 32 /* max number of symlinks in a path */
#endif /* ! MAXSYMLINKS */
#define MAXLINKPATHLEN (MAXPATHLEN * MAXSYMLINKS) /* max link-expanded file */
#define DATA_PROGRESS_TIMEOUT 300 /* how ofter to check DATA progress */
#define ENHSCLEN 10 /* max len of enhanced status code */
#if _FFR_DYNAMIC_TOBUF
# define DEFAULT_MAX_RCPT 100 /* max number of RCPTs per envelope */
#endif /* _FFR_DYNAMIC_TOBUF */
#if SASL
# ifndef AUTH_MECHANISMS
# if STARTTLS && _FFR_EXT_MECH
# define AUTH_MECHANISMS "EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
# else /* STARTTLS && _FFR_EXT_MECH */
# define AUTH_MECHANISMS "GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
# endif /* STARTTLS && _FFR_EXT_MECH */
# endif /* ! AUTH_MECHANISMS */
#endif /* SASL */
#ifdef LDAPMAP
# define LDAPMAP_MAX_ATTR 64
# define LDAPMAP_MAX_FILTER 1024
# define LDAPMAP_MAX_PASSWD 256
#endif /* LDAPMAP */
/**********************************************************************
** Compilation options.
** #define these to 1 if they are available;
** #define them to 0 otherwise.
** All can be overridden from Makefile.
**********************************************************************/
#ifndef NETINET
# define NETINET 1 /* include internet support */
#endif /* ! NETINET */
#ifndef NETINET6
# define NETINET6 0 /* do not include IPv6 support */
#endif /* ! NETINET6 */
#ifndef NETISO
# define NETISO 0 /* do not include ISO socket support */
#endif /* ! NETISO */
#ifndef NAMED_BIND
# define NAMED_BIND 1 /* use Berkeley Internet Domain Server */
#endif /* ! NAMED_BIND */
#ifndef XDEBUG
# define XDEBUG 1 /* enable extended debugging */
#endif /* ! XDEBUG */
#ifndef MATCHGECOS
# define MATCHGECOS 1 /* match user names from gecos field */
#endif /* ! MATCHGECOS */
#ifndef DSN
# define DSN 1 /* include delivery status notification code */
#endif /* ! DSN */
#if !defined(USERDB) && (defined(NEWDB) || defined(HESIOD))
# define USERDB 1 /* look in user database */
#endif /* !defined(USERDB) && (defined(NEWDB) || defined(HESIOD)) */
#ifndef MIME8TO7
# define MIME8TO7 1 /* 8->7 bit MIME conversions */
#endif /* ! MIME8TO7 */
#ifndef MIME7TO8
# define MIME7TO8 1 /* 7->8 bit MIME conversions */
#endif /* ! MIME7TO8 */
/**********************************************************************
** "Hard" compilation options.
** #define these if they are available; comment them out otherwise.
** These cannot be overridden from the Makefile, and should really not
** be turned off unless absolutely necessary.
**********************************************************************/
#define LOG 1 /* enable logging -- don't turn off */
/**********************************************************************
** End of site-specific configuration.
**********************************************************************/
/*
** General "standard C" defines.
**
** These may be undone later, to cope with systems that claim to
** be Standard C but aren't. Gcc is the biggest offender -- it
** doesn't realize that the library is part of the language.
**
** Life would be much easier if we could get rid of this sort
** of bozo problems.
*/
#ifdef __STDC__
# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
#endif /* __STDC__ */
/*
** Assume you have standard calls; can be #undefed below if necessary.
*/
#ifndef HASLSTAT
# define HASLSTAT 1 /* has lstat(2) call */
#endif /* ! HASLSTAT */
/**********************************************************************
** Operating system configuration.
**
** Unless you are porting to a new OS, you shouldn't have to
** change these.
**********************************************************************/
/*
** HP-UX -- tested for 8.07, 9.00, and 9.01.
**
** If V4FS is defined, compile for HP-UX 10.0.
** 11.x support from Richard Allen <ra@hp.is>.
*/
#ifdef __hpux
/* common definitions for HP-UX 9.x and 10.x */
# undef m_flags /* conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h on HP 300 */
# define SYSTEM5 1 /* include all the System V defines */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
# define seteuid(e) setresuid(-1, e, -1)
# define IP_SRCROUTE 1 /* can check IP source routing */
# define LA_TYPE LA_HPUX
# define SPT_TYPE SPT_PSTAT
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# define GIDSET_T gid_t
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
# endif /* ! HASGETUSERSHELL */
# ifdef HPUX11
# define HASFCHOWN 1 /* has fchown(2) */
# define HASSNPRINTF 1 /* has snprintf(3) */
# ifndef BROKEN_RES_SEARCH
# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
# endif /* ! BROKEN_RES_SEARCH */
# else /* HPUX11 */
# ifndef NOT_SENDMAIL
# define syslog hard_syslog
# endif /* ! NOT_SENDMAIL */
# endif /* HPUX11 */
# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
# ifdef V4FS
/* HP-UX 10.x */
# define _PATH_UNIX "/stand/vmunix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# ifndef IDENTPROTO
# define IDENTPROTO 1 /* TCP/IP implementation fixed in 10.0 */
# endif /* ! IDENTPROTO */
# include <sys/mpctl.h> /* for mpctl() in get_num_procs_online() */
# else /* V4FS */
/* HP-UX 9.x */
# define _PATH_UNIX "/hp-ux"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# ifdef __STDC__
extern void hard_syslog(int, char *, ...);
# else /* __STDC__ */
extern void hard_syslog();
# endif /* __STDC__ */
# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
# endif /* V4FS */
#endif /* __hpux */
/*
** IBM AIX 4.x
*/
#ifdef _AIX4
# define _AIX3 1 /* pull in AIX3 stuff */
# define BSD4_4_SOCKADDR /* has sa_len */
# define USESETEUID 1 /* seteuid(2) works */
# define TZ_TYPE TZ_NAME /* use tzname[] vector */
# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
# if _AIX4 >= 40200
# define HASSETREUID 1 /* setreuid(2) works as of AIX 4.2 */
# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
# endif /* _AIX4 >= 40200 */
# if _AIX4 >= 40300
# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
# endif /* _AIX4 >= 40300 */
# if defined(_ILS_MACROS) /* IBM versions aren't side-effect clean */
# undef isascii
# define isascii(c) !(c & ~0177)
# undef isdigit
# define isdigit(__a) (_IS(__a,_ISDIGIT))
# undef isspace
# define isspace(__a) (_IS(__a,_ISSPACE))
# endif /* defined(_ILS_MACROS) */
#endif /* _AIX4 */
/*
** IBM AIX 3.x -- actually tested for 3.2.3
*/
#ifdef _AIX3
# include <paths.h>
# include <sys/machine.h> /* to get byte order */
# include <sys/select.h>
# define HASFCHOWN 1 /* has fchown(2) */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
# define GIDSET_T gid_t
# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# define LA_TYPE LA_INT
# define FSHIFT 16
# define LA_AVENRUN "avenrun"
#endif /* _AIX3 */
/*
** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773
**
** From Mark Whetzel <markw@wg.waii.com>.
*/
#ifdef AIX /* AIX/RT compiler pre-defines this */
# include <paths.h>
# include <sys/time.h> /* AIX/RT resource.h does NOT include this */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define HASFCHMOD 0 /* does not have fchmod(2) syscall */
# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */
# define HASSETVBUF 1 /* use setvbuf(2) system call */
# define HASSETRLIMIT 0 /* does not have setrlimit call */
# define HASFLOCK 0 /* does not have flock call - use fcntl */
# define HASULIMIT 1 /* use ulimit instead of setrlimit call */
# define NEEDGETOPT 1 /* Do we need theirs or ours */
# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */
# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */
# define GIDSET_T int
# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */
# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
# define ARBPTR_T int *
# define void int
typedef int pid_t;
/* RTisms for BSD compatibility, specified in the Makefile
define BSD 1
define BSD_INCLUDES 1
define BSD_REMAP_SIGNAL_TO_SIGVEC
RTisms needed above */
/* make this sendmail in a completely different place */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/local/newmail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* AIX */
/*
** Silicon Graphics IRIX
**
** Compiles on 4.0.1.
**
** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0).
** Use IRIX5 instead of IRIX for IRIX 5.x.
**
** This version tries to be adaptive using _MIPS_SIM:
** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2
** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2
** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2
**
** _MIPS_SIM is 1 also on IRIX 5.3
**
** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>.
** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
*/
#if defined(__sgi)
# ifndef IRIX
# define IRIX
# endif /* ! IRIX */
# if _MIPS_SIM > 0 && !defined(IRIX5)
# define IRIX5 /* IRIX5 or IRIX6 */
# endif /* _MIPS_SIM > 0 && !defined(IRIX5) */
# if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64)
# define IRIX6 /* IRIX6 */
# endif /* _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64) */
#endif /* defined(__sgi) */
#ifdef IRIX
# define SYSTEM5 1 /* this is a System-V derived system */
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define IP_SRCROUTE 1 /* can check IP source routing */
# define setpgid BSDsetpgrp
# define GIDSET_T gid_t
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define SYSLOG_BUFSIZE 512
# ifdef IRIX6
# define STAT64 1
# define QUAD_T unsigned long long
# define LA_TYPE LA_IRIX6 /* figure out at run time */
# define SAFENFSPATHCONF 0 /* pathconf(2) lies on NFS filesystems */
# else /* IRIX6 */
# define LA_TYPE LA_INT
# ifdef IRIX64
# define STAT64 1
# define QUAD_T unsigned long long
# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */
# else /* IRIX64 */
# define STAT64 0
# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
# endif /* IRIX64 */
# endif /* IRIX6 */
# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
# include <sys/cdefs.h>
# include <paths.h>
# define ARGV_T char *const *
# define HASFCHOWN 1 /* has fchown(2) */
# define HASSETRLIMIT 1 /* has setrlimit(2) syscall */
# define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */
# define HASSTRERROR 1 /* has strerror(3) */
# else /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
# define ARGV_T const char **
# define WAITUNION 1 /* use "union wait" as wait argument type */
# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
#endif /* IRIX */
/*
** SunOS and Solaris
**
** Tested on SunOS 4.1.x (a.k.a. Solaris 1.1.x) and
** Solaris 2.4 (a.k.a. SunOS 5.4).
*/
#if defined(sun) && !defined(BSD)
# include <sys/time.h>
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define IP_SRCROUTE 1 /* can check IP source routing */
# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
# ifndef HASFCHOWN
# define HASFCHOWN 1 /* fchown(2) */
# endif /* ! HASFCHOWN */
# ifdef SOLARIS_2_3
# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */
# endif /* SOLARIS_2_3 */
# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1 /* unknown Solaris version */
# endif /* defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4)) */
# ifdef SOLARIS
/* Solaris 2.x (a.k.a. SunOS 5.x) */
# ifndef __svr4__
# define __svr4__ /* use all System V Release 4 defines below */
# endif /* ! __svr4__ */
# define GIDSET_T gid_t
# define USE_SA_SIGACTION 1 /* use sa_sigaction field */
# ifndef _PATH_UNIX
# define _PATH_UNIX "/dev/ksyms"
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# ifndef _PATH_HOSTS
# define _PATH_HOSTS "/etc/inet/hosts"
# endif /* ! _PATH_HOSTS */
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
# endif /* ! SYSLOG_BUFSIZE */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TZNAME
# endif /* ! TZ_TYPE */
# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
# define USESETEUID 1 /* seteuid works as of 2.3 */
# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205)
# define HASSETREUID 1 /* setreuid works as of 2.5 */
# if SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700)
# ifndef LA_TYPE
# define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */
# endif /* ! LA_TYPE */
# ifndef RANDOMSHIFT /* random() doesn't work well (sometimes) */
# define RANDOMSHIFT 8
# endif /* RANDOMSHIFT */
# endif /* SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700) */
# else /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
# ifndef HASRANDOM
# define HASRANDOM 0 /* doesn't have random(3) */
# endif /* ! HASRANDOM */
# endif /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
+# else /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
+ typedef int int32_t;
# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
# if SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207)
# ifndef LA_TYPE
# include <sys/loadavg.h>
# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */
# endif /* ! LA_TYPE */
# define HASGETUSERSHELL 1 /* getusershell(3c) bug fixed in 2.7 */
# endif /* SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207) */
# if SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208)
-# undef NETINET6
-# define NETINET6 1 /* IPv6 added in 2.8 */
# define HASSTRL 1 /* str*(3) added in 2.8 */
+# undef _PATH_SENDMAILPID /* tmpfs /var/run added in 2.8 */
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
# endif /* SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208) */
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */
# endif /* ! HASGETUSERSHELL */
# else /* SOLARIS */
/* SunOS 4.0.3 or 4.1.x */
# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
# define HASSETREUID 1 /* has setreuid(2) call */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
# include <memory.h>
# include <vfork.h>
# ifdef __GNUC__
# define strtoul strtol /* gcc library bogosity */
# endif /* __GNUC__ */
# define memmove(d, s, l) (bcopy((s), (d), (l)))
# ifdef SUNOS403
/* special tweaking for SunOS 4.0.3 */
# include <malloc.h>
# define BSD4_3 1 /* 4.3 BSD-based */
# define NEEDSTRSTR 1 /* need emulation of strstr(3) routine */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# undef WIFEXITED
# undef WEXITSTATUS
# undef HASUNAME
# define setpgid setpgrp
# define MODE_T int
typedef int pid_t;
extern char *getenv();
# else /* SUNOS403 */
/* 4.1.x specifics */
# define HASSETSID 1 /* has Posix setsid(2) call */
# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
# endif /* SUNOS403 */
# endif /* SOLARIS */
# ifndef LA_TYPE
# define LA_TYPE LA_INT
# endif /* ! LA_TYPE */
#endif /* defined(sun) && !defined(BSD) */
/*
** DG/UX
**
** Tested on 5.4.2 and 5.4.3. Use DGUX_5_4_2 to get the
** older support.
** 5.4.3 changes from Mark T. Robinson <mtr@ornl.gov>.
*/
#ifdef DGUX_5_4_2
# define DGUX 1
#endif /* DGUX_5_4_2 */
#ifdef DGUX
# define SYSTEM5 1
# define LA_TYPE LA_DGUX
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASSETSID 1 /* has Posix setsid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) */
# define HASSNPRINTF 1 /* has snprintf(3) */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# define SPT_TYPE SPT_NONE /* don't use setproctitle */
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
/* these include files must be included early on DG/UX */
# include <netinet/in.h>
# include <arpa/inet.h>
/* compiler doesn't understand const? */
# define const
# ifdef DGUX_5_4_2
# define inet_addr dgux_inet_addr
extern long dgux_inet_addr();
# endif /* DGUX_5_4_2 */
#endif /* DGUX */
/*
** Digital Ultrix 4.2A or 4.3
**
** Apparently, fcntl locking is broken on 4.2A, in that locks are
** not dropped when the process exits. This causes major problems,
** so flock is the only alternative.
*/
#ifdef ultrix
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASFCHOWN 1 /* has fchown(2) syscall */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# ifndef BROKEN_RES_SEARCH
# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
# endif /* ! BROKEN_RES_SEARCH */
# if !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621
# define NEEDLOCAL_HOSTNAME_LENGTH 1 /* see sendmail/README */
# endif /* !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621 */
# ifdef vax
# define LA_TYPE LA_FLOAT
# else /* vax */
# define LA_TYPE LA_INT
# define LA_AVENRUN "avenrun"
# endif /* vax */
# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* pre-4.4 TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# define SYSLOG_BUFSIZE 256
#endif /* ultrix */
/*
** OSF/1 for KSR.
**
** Contributed by Todd C. Miller <Todd.Miller@cs.colorado.edu>
*/
#ifdef __ksr__
# define __osf__ 1 /* get OSF/1 defines below */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
# endif /* ! TZ_TYPE */
#endif /* __ksr__ */
/*
** OSF/1 for Intel Paragon.
**
** Contributed by Jeff A. Earickson <jeff@ssd.intel.com>
** of Intel Scalable Systems Divison.
*/
#ifdef __PARAGON__
# define __osf__ 1 /* get OSF/1 defines below */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
# endif /* ! TZ_TYPE */
# define GIDSET_T gid_t
# define MAXNAMLEN NAME_MAX
#endif /* __PARAGON__ */
/*
** Tru64 UNIX, formerly known as Digital UNIX, formerly known as DEC OSF/1
**
** Tested for 3.2 and 4.0.
*/
#ifdef __osf__
# define HASUNAME 1 /* has uname(2) call */
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASFCHOWN 1 /* has fchown(2) syscall */
# define HASSETLOGIN 1 /* has setlogin(2) */
# define IP_SRCROUTE 1 /* can check IP source routing */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# define GIDSET_T gid_t
# if _FFR_MILTER
# define SM_INT32 int /* 32bit integer */
# endif /* _FFR_MILTER */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define LA_TYPE LA_ALPHAOSF
# define SFS_TYPE SFS_STATVFS /* use <sys/statvfs.h> statfs() impl */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* __osf__ */
/*
** NeXTstep
*/
#ifdef NeXT
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define NEEDPUTENV 2 /* need putenv(3) call; no setenv(3) call */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# define UID_T int /* compiler gripes on uid_t */
# define GID_T int /* ditto for gid_t */
# define MODE_T int /* and mode_t */
# define setpgid setpgrp
# ifndef NOT_SENDMAIL
# define sleep sleepX
# endif /* ! NOT_SENDMAIL */
# ifndef LA_TYPE
# define LA_TYPE LA_MACH
# endif /* ! LA_TYPE */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# ifndef _POSIX_SOURCE
typedef int pid_t;
# undef WEXITSTATUS
# undef WIFEXITED
# undef WIFSTOPPED
# undef WTERMSIG
# endif /* ! _POSIX_SOURCE */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/sendmail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# ifdef TCPWRAPPERS
# ifndef HASUNSETENV
# define HASUNSETENV 1
# endif /* ! HASUNSETENV */
# undef NEEDPUTENV
# endif /* TCPWRAPPERS */
#endif /* NeXT */
/*
** Apple Rhapsody
** Contributed by Wilfredo Sanchez <wsanchez@apple.com>
**
** Also used for Apple Darwin support.
*/
#if defined(DARWIN)
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASFLOCK 1 /* has flock(2) syscall */
# define HASUNAME 1 /* has uname(2) syscall */
# define HASUNSETENV 1
# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
# define HASINITGROUPS 1
# define HASSETVBUF 1
# define HASSETREUID 1
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASLSTAT 1
# define HASSETRLIMIT 1
# define HASWAITPID 1
# define HASSTRERROR 1 /* has strerror(3) */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define HASSTRERROR 1 /* has strerror(3) */
# define HASGETDTABLESIZE 1
# define HASGETUSERSHELL 1
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define BSD4_4_SOCKADDR /* has sa_len */
# define NETLINK 1 /* supports AF_LINK */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# define GIDSET_T gid_t
# define LA_TYPE LA_SUBR /* use getloadavg(3) */
# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
# define SPT_TYPE SPT_PSSTRINGS
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
#endif /* DARWIN */
/*
** 4.4 BSD
**
** See also BSD defines.
*/
#if defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__)
# include <paths.h>
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define HASSTRERROR 1 /* has strerror(3) */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# include <sys/cdefs.h>
# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
# define BSD4_4_SOCKADDR /* has sa_len */
# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
# define NETLINK 1 /* supports AF_LINK */
# ifndef LA_TYPE
# define LA_TYPE LA_SUBR
# endif /* ! LA_TYPE */
# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
# define SPT_TYPE SPT_PSSTRINGS /* use PS_STRINGS pointer */
#endif /* defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__) */
/*
** BSD/OS (was BSD/386) (all versions)
** From Tony Sanders, BSDI
*/
#ifdef __bsdi__
# include <paths.h>
# define HASUNSETENV 1 /* has the unsetenv(3) call */
# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASSETLOGIN 1 /* has setlogin(2) */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define HASUNAME 1 /* has uname(2) syscall */
# define HASSTRERROR 1 /* has strerror(3) */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# include <sys/cdefs.h>
# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
# define BSD4_4_SOCKADDR /* has sa_len */
# define NETLINK 1 /* supports AF_LINK */
# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
# ifndef LA_TYPE
# define LA_TYPE LA_SUBR
# endif /* ! LA_TYPE */
# define GIDSET_T gid_t
# define QUAD_T quad_t
# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312
/* version 1.1 or later */
# undef SPT_TYPE
# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
# else /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
/* version 1.0 or earlier */
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 /* on 3.x */
# define HASSETUSERCONTEXT 1 /* has setusercontext */
# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 */
#endif /* __bsdi__ */
/*
** QNX 4.2x
** Contributed by Glen McCready <glen@qnx.com>.
**
** Should work with all versions of QNX.
*/
#if defined(__QNX__)
# include <unix.h>
# include <sys/select.h>
# undef NGROUPS_MAX
# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASSTRERROR 1 /* has strerror(3) */
# define HASFLOCK 0
# undef HASINITGROUPS /* has initgroups(3) call */
# define NEEDGETOPT 1 /* use sendmail's getopt */
# define IP_SRCROUTE 1 /* can check IP source routing */
# define TZ_TYPE TZ_TMNAME /* use tmname variable */
# define GIDSET_T gid_t
# define LA_TYPE LA_ZERO
# define SFS_TYPE SFS_NONE
# define SPT_TYPE SPT_REUSEARGV
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# define HASGETUSERSHELL 0
# define E_PSEUDOBASE 512
# define _FILE_H_INCLUDED
#endif /* defined(__QNX__) */
/*
** FreeBSD / NetBSD / OpenBSD (all architectures, all versions)
**
** 4.3BSD clone, closer to 4.4BSD for FreeBSD 1.x and NetBSD 0.9x
** 4.4BSD-Lite based for FreeBSD 2.x and NetBSD 1.x
**
** See also BSD defines.
*/
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <paths.h>
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASFCHOWN 1 /* fchown(2) */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define HASUNAME 1 /* has uname(2) syscall */
# define HASSTRERROR 1 /* has strerror(3) */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
# include <sys/cdefs.h>
# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
# define BSD4_4_SOCKADDR /* has sa_len */
# define NETLINK 1 /* supports AF_LINK */
# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
# define GIDSET_T gid_t
# define QUAD_T unsigned long long
# define SFIO_STDIO_COMPAT 1 /* can use RES_DEBUG */
# ifndef LA_TYPE
# define LA_TYPE LA_SUBR
# endif /* ! LA_TYPE */
# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
# if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1)
# undef SPT_TYPE
# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
# endif /* defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) */
# if defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3))
# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
# endif /* defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3)) */
# if defined(__FreeBSD__)
# define HASSETLOGIN 1 /* has setlogin(2) */
# if __FreeBSD_version >= 227001
# define HASSRANDOMDEV 1 /* has srandomdev(3) */
# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
# endif /* __FreeBSD_version >= 227001 */
# undef SPT_TYPE
# if __FreeBSD__ >= 2
# include <osreldate.h>
# if __FreeBSD_version >= 199512 /* 2.2-current when it appeared */
# include <libutil.h>
# define SPT_TYPE SPT_BUILTIN
# endif /* __FreeBSD_version >= 199512 */
# if __FreeBSD_version >= 222000 /* 2.2.2-release and later */
# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
# endif /* __FreeBSD_version >= 222000 */
# if __FreeBSD_version >= 330000 /* 3.3.0-release and later */
# ifndef HASSTRL
# define HASSTRL 1 /* has strlc{py,at}(3) functions */
# endif /* HASSTRL */
# endif /* __FreeBSD_version >= 330000 */
# define USESYSCTL 1 /* use sysctl(3) for getting ncpus */
# include <sys/sysctl.h>
# endif /* __FreeBSD__ >= 2 */
# ifndef SPT_TYPE
# define SPT_TYPE SPT_REUSEARGV
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# endif /* ! SPT_TYPE */
# endif /* defined(__FreeBSD__) */
# if defined(__OpenBSD__)
# undef SPT_TYPE
# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
# define HASSETLOGIN 1 /* has setlogin(2) */
# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
# if OpenBSD < 199912
# define HASSTRL 0 /* strlcat(3) is broken in 2.5 and earlier */
# else /* OpenBSD < 199912 */
# define HASSTRL 1 /* has strlc{py,at}(3) functions */
# endif /* OpenBSD < 199912 */
# endif /* defined(__OpenBSD__) */
#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) */
/*
** Mach386
**
** For mt Xinu's Mach386 system.
*/
#if defined(MACH) && defined(i386) && !defined(__GNU__)
# define MACH386 1
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define NEEDSTRTOL 1 /* need the strtol() function */
# define setpgid setpgrp
# ifndef LA_TYPE
# define LA_TYPE LA_FLOAT
# endif /* ! LA_TYPE */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# undef HASSETVBUF /* don't actually have setvbuf(3) */
# undef WEXITSTATUS
# undef WIFEXITED
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* defined(MACH) && defined(i386) && !defined(__GNU__) */
/*
** GNU OS (hurd)
** Largely BSD & posix compatible.
** Port contributed by Miles Bader <miles@gnu.ai.mit.edu>.
** Updated by Mark Kettenis <kettenis@wins.uva.nl>.
*/
#if defined(__GNU__) && !defined(NeXT)
# include <paths.h>
# define HASFCHMOD 1 /* has fchmod(2) call */
# define HASFCHOWN 1 /* has fchown(2) call */
# define HASUNAME 1 /* has uname(2) call */
# define HASUNSETENV 1 /* has unsetenv(3) call */
# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define HASSTRERROR 1 /* has strerror(3) */
# define GIDSET_T gid_t
# define SOCKADDR_LEN_T socklen_t
# define SOCKOPT_LEN_T socklen_t
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ > 1) || __GLIBC__ > 2
# define LA_TYPE LA_SUBR
# else
# define LA_TYPE LA_MACH
/* GNU uses mach[34], which renames some rpcs from mach2.x. */
# define host_self mach_host_self
# endif
# define SFS_TYPE SFS_STATFS
# define SPT_TYPE SPT_CHANGEARGV
# define ERRLIST_PREDEFINED 1 /* don't declare sys_errlist */
# define BSD4_4_SOCKADDR 1 /* has sa_len */
# define SIOCGIFCONF_IS_BROKEN 1 /* SIOCGFCONF doesn't work */
# define HAS_IN_H 1 /* GNU has netinet/in.h. */
/* GNU has no MAXPATHLEN; ideally the code should be changed to not use it. */
# define MAXPATHLEN 2048
#endif /* defined(__GNU__) && !defined(NeXT) */
/*
** 4.3 BSD -- this is for very old systems
**
** Should work for mt Xinu MORE/BSD and Mips UMIPS-BSD 2.1.
**
** You'll also have to install a new resolver library.
** I don't guarantee that support for this environment is complete.
*/
#if defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd)
# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define ARBPTR_T char *
# define setpgid setpgrp
# ifndef LA_TYPE
# define LA_TYPE LA_FLOAT
# endif /* ! LA_TYPE */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# undef WEXITSTATUS
# undef WIFEXITED
typedef short pid_t;
#endif /* defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) */
/*
** SCO Unix
**
** This includes three parts:
**
** The first is for SCO OpenServer 5.
** (Contributed by Keith Reynolds <keithr@sco.COM>).
**
** SCO OpenServer 5 has a compiler version number macro,
** which we can use to figure out what version we're on.
** This may have to change in future releases.
**
** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0.
** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>).
**
** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier.
*/
/* SCO OpenServer 5 */
#if _SCO_DS >= 1
# include <paths.h>
# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM returns bogus value */
# define HASSNPRINTF 1 /* has snprintf(3) call */
# define HASFCHMOD 1 /* has fchmod(2) call */
# define HASFCHOWN 1 /* has fchown(2) call */
# define HASSETRLIMIT 1 /* has setrlimit(2) call */
# define USESETEUID 1 /* has seteuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
# define RLIMIT_NEEDS_SYS_TIME_H 1
# ifndef LA_TYPE
# define LA_TYPE LA_DEVSHORT
# endif /* ! LA_TYPE */
# define _PATH_AVENRUN "/dev/table/avenrun"
# ifndef _SCO_unix_4_2
# define _SCO_unix_4_2
# else /* ! _SCO_unix_4_2 */
# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
# endif /* ! _SCO_unix_4_2 */
#endif /* _SCO_DS >= 1 */
/* SCO UNIX 3.2v4.2/Open Desktop 3.0 */
#ifdef _SCO_unix_4_2
# define _SCO_unix_
# define HASSETREUID 1 /* has setreuid(2) call */
#endif /* _SCO_unix_4_2 */
/* SCO UNIX 3.2v4.0 Open Desktop 2.0 and earlier */
#ifdef _SCO_unix_
# include <sys/stream.h> /* needed for IP_SRCROUTE */
# define SYSTEM5 1 /* include all the System V defines */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define NOFTRUNCATE 0 /* has (simulated) ftruncate call */
# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
# define MAXPATHLEN PATHSIZE
# define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define SPT_TYPE SPT_SCO /* write kernel u. area */
# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */
# define UID_T uid_t
# define GID_T gid_t
# define GIDSET_T gid_t
# define _PATH_UNIX "/unix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
/* stuff fixed in later releases */
# ifndef _SCO_unix_4_2
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# endif /* ! _SCO_unix_4_2 */
# ifndef _SCO_DS
# define ftruncate chsize /* use chsize(2) to emulate ftruncate */
# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
# define NETUNIX 0 /* no unix domain socket support */
# define LA_TYPE LA_SHORT
# endif /* ! _SCO_DS */
#endif /* _SCO_unix_ */
/*
** ISC (SunSoft) Unix.
**
** Contributed by J.J. Bailey <jjb@jagware.bcc.com>
*/
#ifdef ISC_UNIX
# include <net/errno.h>
# include <sys/stream.h> /* needed for IP_SRCROUTE */
# include <sys/bsdtypes.h>
# define SYSTEM5 1 /* include all the System V defines */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define HASSETREUID 1 /* has setreuid(2) call */
# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
# define NETUNIX 0 /* no unix domain socket support */
# define MAXPATHLEN 1024
# define LA_TYPE LA_SHORT
# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define _PATH_UNIX "/unix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* ISC_UNIX */
/*
** Altos System V (5.3.1)
** Contributed by Tim Rice <tim@trr.metro.net>.
*/
#ifdef ALTOS_SYSTEM_V
# include <sys/stream.h>
# include <limits.h>
# define SYSTEM5 1 /* include all the System V defines */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# define NEEDFSYNC 1 /* no fsync(2) in system library */
# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
# define MAXPATHLEN PATH_MAX
# define LA_TYPE LA_SHORT
# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
# define NETUNIX 0 /* no unix domain socket support */
# undef WIFEXITED
# undef WEXITSTATUS
# define strtoul strtol /* gcc library bogosity */
typedef unsigned short uid_t;
typedef unsigned short gid_t;
typedef short pid_t;
typedef unsigned long mode_t;
/* some stuff that should have been in the include files */
extern char *malloc();
extern struct passwd *getpwent();
extern struct passwd *getpwnam();
extern struct passwd *getpwuid();
extern char *getenv();
extern struct group *getgrgid();
extern struct group *getgrnam();
#endif /* ALTOS_SYSTEM_V */
/*
** ConvexOS 11.0 and later
**
** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this
** works on 9.1 as well.
**
** ConvexOS 11.5 and later, should work on 11.0 as defined.
** For pre-ConvexOOS 11.0, define NEEDGETOPT, undef IDENTPROTO
**
** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp.
** (now the CONVEX Technologies Center of Hewlett Packard)
*/
#ifdef _CONVEX_SOURCE
# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */
# define HASINITGROUPS 1 /* has initgroups(3) */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASSETSID 1 /* has POSIX setsid(2) call */
# define HASUNSETENV 1 /* has unsetenv(3) */
# define HASFLOCK 1 /* has flock(2) */
# define HASSETRLIMIT 1 /* has setrlimit(2) */
# define HASSETREUID 1 /* has setreuid(2) */
# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */
# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */
# define NEEDGETOPT 0 /* need replacement for getopt(3) */
# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
# define LA_TYPE LA_FLOAT
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef S_IREAD
# define S_IREAD _S_IREAD
# define S_IWRITE _S_IWRITE
# define S_IEXEC _S_IEXEC
# define S_IFMT _S_IFMT
# define S_IFCHR _S_IFCHR
# define S_IFBLK _S_IFBLK
# endif /* ! S_IREAD */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TIMEZONE
# endif /* ! TZ_TYPE */
# ifndef IDENTPROTO
# define IDENTPROTO 1
# endif /* ! IDENTPROTO */
# ifndef SHARE_V1
# define SHARE_V1 1 /* version 1 of the fair share scheduler */
# endif /* ! SHARE_V1 */
# if !defined(__GNUC__ )
# define UID_T int /* GNUC gets it right, ConvexC botches */
# define GID_T int /* GNUC gets it right, ConvexC botches */
# endif /* !defined(__GNUC__ ) */
# if SECUREWARE
# define FORK fork /* SecureWare wants the real fork! */
# else /* SECUREWARE */
# define FORK vfork /* the rest of the OS versions don't care */
# endif /* SECUREWARE */
#endif /* _CONVEX_SOURCE */
/*
** RISC/os 4.52
**
** Gives a ton of warning messages, but otherwise compiles.
*/
#ifdef RISCOS
# define HASUNSETENV 1 /* has unsetenv(3) call */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define NEEDPUTENV 1 /* need putenv(3) call */
# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# define LA_TYPE LA_INT
# define LA_AVENRUN "avenrun"
# define _PATH_UNIX "/unix"
# undef WIFEXITED
# define setpgid setpgrp
typedef int pid_t;
# define SIGFUNC_DEFINED
# define SIGFUNC_RETURN (0)
# define SIGFUNC_DECL int
typedef int (*sigfunc_t)();
extern char *getenv();
extern void *malloc();
/* added for RISC/os 4.01...which is dumber than 4.50 */
# ifdef RISCOS_4_0
# ifndef ARBPTR_T
# define ARBPTR_T char *
# endif /* ! ARBPTR_T */
# undef HASFLOCK
# define HASFLOCK 0
# endif /* RISCOS_4_0 */
# include <sys/time.h>
#endif /* RISCOS */
/*
** Linux 0.99pl10 and above...
**
** Thanks to, in reverse order of contact:
**
** John Kennedy <warlock@csuchico.edu>
** Andrew Pam <avatar@aus.xanadu.com>
** Florian La Roche <rzsfl@rz.uni-sb.de>
** Karl London <karl@borg.demon.co.uk>
**
** Last compiled against: [07/21/98 @ 11:47:34 AM (Tuesday)]
** sendmail 8.9.1 bind-8.1.2 db-2.4.14
** gcc-2.8.1 glibc-2.0.94 linux-2.1.109
**
** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style
** file locking is no longer allowed. In particular, make sure
** your DBM library and sendmail are both using either flock(2)
** *or* fcntl(2) file locking, but not both.
*/
#ifdef __linux__
# include <linux/version.h>
# if !defined(KERNEL_VERSION) /* not defined in 2.0.x kernel series */
# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
# endif /* KERNEL_VERSION */
# define BSD 1 /* include BSD defines */
# define USESETEUID 0 /* Have it due to POSIX, but doesn't work */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASUNSETENV 1 /* has unsetenv(3) call */
# ifndef HASSNPRINTF
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# endif /* ! HASSNPRINTF */
# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
# define GIDSET_T gid_t /* from <linux/types.h> */
# define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */
# ifndef IP_SRCROUTE
# define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */
# endif /* ! IP_SRCROUTE */
# ifndef HAS_IN_H
# define HAS_IN_H 1 /* use netinet/in.h */
# endif /* ! HAS_IN_H */
# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
# ifndef HASFLOCK
# if LINUX_VERSION_CODE < 66399
# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */
# else /* LINUX_VERSION_CODE < 66399 */
# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */
# endif /* LINUX_VERSION_CODE < 66399 */
# endif /* ! HASFLOCK */
# ifndef LA_TYPE
# define LA_TYPE LA_PROCSTR
# endif /* ! LA_TYPE */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,0))
# ifndef HASURANDOMDEV
# define HASURANDOMDEV 1 /* 2.0 (at least) has linux/drivers/char/random.c */
# endif /* ! HASURANDOMDEV */
# endif /* LINUX_VERSION_CODE */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_NONE /* no standard for Linux */
# endif /* ! TZ_TYPE */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# include <sys/sysmacros.h>
# undef atol /* wounded in <stdlib.h> */
# if NETINET6
/*
** Linux doesn't have a good way to tell userland what interfaces are
** IPv6-capable. Therefore, the BIND resolver can not determine if there
** are IPv6 interfaces to honor AI_ADDRCONFIG. Unfortunately, it assumes
** that none are present. (Excuse the macro name ADDRCONFIG_IS_BROKEN.)
*/
# define ADDRCONFIG_IS_BROKEN 1
/*
** Indirectly included from glibc's <feature.h>. IPv6 support is native
** in 2.1 and later, but the APIs appear before the functions.
*/
# if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
# define GLIBC_VERSION ((__GLIBC__ << 8) + __GLIBC_MINOR__)
# if (GLIBC_VERSION >= 0x201)
# undef IPPROTO_ICMPV6 /* linux #defines, glibc enums */
# else /* (GLIBC_VERSION >= 0x201) */
# include <linux/in6.h> /* IPv6 support */
# endif /* (GLIBC_VERSION >= 0x201) */
# if (GLIBC_VERSION == 0x201 && !defined(NEEDSGETIPNODE))
/* Have APIs in <netdb.h>, but no support in glibc */
# define NEEDSGETIPNODE 1
# endif /* (GLIBC_VERSION == 0x201 && ! NEEDSGETIPNODE) */
# undef GLIBC_VERSION
# endif /* defined(__GLIBC__) && defined(__GLIBC_MINOR__) */
# endif /* NETINET6 */
# ifndef HASFCHOWN
# define HASFCHOWN 1 /* fchown(2) */
# endif /* ! HASFCHOWN */
#endif /* __linux__ */
/*
** DELL SVR4 Issue 2.2, and others
** From Kimmo Suominen <kim@grendel.lut.fi>
**
** It's on #ifdef DELL_SVR4 because Solaris also gets __svr4__
** defined, and the definitions conflict.
**
** Peter Wemm <peter@perth.DIALix.oz.au> claims that the setreuid
** trick works on DELL 2.2 (SVR4.0/386 version 4.0) and ESIX 4.0.3A
** (SVR4.0/386 version 3.0).
*/
#ifdef DELL_SVR4
/* no changes necessary */
/* see general __svr4__ defines below */
#endif /* DELL_SVR4 */
/*
** Apple A/UX 3.0
*/
#ifdef _AUX_SOURCE
# include <sys/sysmacros.h>
# define BSD /* has BSD routines */
# define HASSETRLIMIT 0 /* ... but not setrlimit(2) */
# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASSETVBUF 1 /* has setvbuf(3) in libc */
# define HASSTRERROR 1 /* has strerror(3) */
# define SIGFUNC_DEFINED /* sigfunc_t already defined */
# define SIGFUNC_RETURN /* POSIX-mode */
# define SIGFUNC_DECL void /* POSIX-mode */
# define ERRLIST_PREDEFINED 1
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# ifndef LA_TYPE
# define LA_TYPE LA_INT
# define FSHIFT 16
# endif /* ! LA_TYPE */
# define LA_AVENRUN "avenrun"
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# define TZ_TYPE TZ_TZNAME
# ifndef _PATH_UNIX
# define _PATH_UNIX "/unix" /* should be in <paths.h> */
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# undef WIFEXITED
# undef WEXITSTATUS
#endif /* _AUX_SOURCE */
/*
** Encore UMAX V
**
** Not extensively tested.
*/
#ifdef UMAXV
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
# define MAXPATHLEN PATH_MAX
extern struct passwd *getpwent(), *getpwnam(), *getpwuid();
extern struct group *getgrent(), *getgrnam(), *getgrgid();
# undef WIFEXITED
# undef WEXITSTATUS
#endif /* UMAXV */
/*
** Stardent Titan 3000 running TitanOS 4.2.
**
** Must be compiled in "cc -43" mode.
**
** From Kate Hedstrom <kate@ahab.rutgers.edu>.
**
** Note the tweaking below after the BSD defines are set.
*/
#ifdef titan
# define setpgid setpgrp
typedef int pid_t;
# undef WIFEXITED
# undef WEXITSTATUS
#endif /* titan */
/*
** Sequent DYNIX 3.2.0
**
** From Jim Davis <jdavis@cs.arizona.edu>.
*/
#ifdef sequent
# define BSD 1
# define HASUNSETENV 1
# define BSD4_3 1 /* to get signal() in conf.c */
# define WAITUNION 1
# define LA_TYPE LA_FLOAT
# ifdef _POSIX_VERSION
# undef _POSIX_VERSION /* set in <unistd.h> */
# endif /* _POSIX_VERSION */
# undef HASSETVBUF /* don't actually have setvbuf(3) */
# define setpgid setpgrp
/* Have to redefine WIFEXITED to take an int, to work with waitfor() */
# undef WIFEXITED
# define WIFEXITED(s) (((union wait*)&(s))->w_stopval != WSTOPPED && \
((union wait*)&(s))->w_termsig == 0)
# define WEXITSTATUS(s) (((union wait*)&(s))->w_retcode)
typedef int pid_t;
# define isgraph(c) (isprint(c) && (c != ' '))
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# ifndef _PATH_UNIX
# define _PATH_UNIX "/dynix"
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
#endif /* sequent */
/*
** Sequent DYNIX/ptx v2.0 (and higher)
**
** For DYNIX/ptx v1.x, undefine HASSETREUID.
**
** From Tim Wright <timw@sequent.com>.
** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995,
** for DYNIX/ptx 4.0.2.
*/
#ifdef _SEQUENT_
# include <sys/stream.h>
# define SYSTEM5 1 /* include all the System V defines */
# define HASSETSID 1 /* has POSIX setsid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define GIDSET_T gid_t
# define LA_TYPE LA_INT
# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
# define SPT_TYPE SPT_NONE /* don't use setproctitle */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* _SEQUENT_ */
/*
** Cray Unicos
**
** Ported by David L. Kensiski, Sterling Sofware <kensiski@nas.nasa.gov>
*/
#ifdef UNICOS
# define SYSTEM5 1 /* include all the System V defines */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define MAXPATHLEN PATHSIZE
# define LA_TYPE LA_ZERO
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
# define SFS_BAVAIL f_bfree /* alternate field name */
#endif /* UNICOS */
/*
** Apollo DomainOS
**
** From Todd Martin <tmartint@tus.ssi1.com> & Don Lewis <gdonl@gv.ssi1.com>
**
** 15 Jan 1994; updated 2 Aug 1995
**
*/
#ifdef apollo
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(2) call */
# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
# define SPT_TYPE SPT_NONE /* don't use setproctitle */
# define LA_TYPE LA_SUBR /* use getloadavg.c */
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define TZ_TYPE TZ_TZNAME
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# undef S_IFSOCK /* S_IFSOCK and S_IFIFO are the same */
# undef S_IFIFO
# define S_IFIFO 0010000
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# define RLIMIT_NEEDS_SYS_TIME_H 1
# if defined(NGROUPS_MAX) && !NGROUPS_MAX
# undef NGROUPS_MAX
# endif /* defined(NGROUPS_MAX) && !NGROUPS_MAX */
#endif /* apollo */
/*
** System V Rel 5.x (a.k.a Unixware7 w/o BSD-Compatibility Libs ie. native)
**
** Contributed by Paul Gampe <paulg@apnic.net>
*/
#ifdef __svr5__
# include <sys/mkdev.h>
# define __svr4__
# define SYS5SIGNALS 1
# define HASSETSID 1
# define HASSETREUID 1
# define HASWAITPID 1
# define HASGETDTABLESIZE 1
# define GIDSET_T gid_t
# define SOCKADDR_LEN_T size_t
# define SOCKOPT_LEN_T size_t
# ifndef _PATH_UNIX
# define _PATH_UNIX "/stand/unix"
# endif /* ! _PATH_UNIX */
# define SPT_PADCHAR '\0' /* pad process title with nulls */
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 1024 /* unsure */
# endif /* SYSLOG_BUFSIZE */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* __svr5__ */
/* ###################################################################### */
/*
** UnixWare 2.x
*/
#ifdef UNIXWARE2
# define UNIXWARE 1
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
#endif /* UNIXWARE2 */
/*
** UnixWare 1.1.2.
**
** Updated by Petr Lampa <lampa@fee.vutbr.cz>.
** From Evan Champion <evanc@spatial.synapse.org>.
*/
#ifdef UNIXWARE
# include <sys/mkdev.h>
# define SYSTEM5 1
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# define HASSETREUID 1
# define HASSETSID 1
# define HASINITGROUPS 1
# define GIDSET_T gid_t
# define SLEEP_T unsigned
# define SFS_TYPE SFS_STATVFS
# define LA_TYPE LA_ZERO
# undef WIFEXITED
# undef WEXITSTATUS
# ifndef _PATH_UNIX
# define _PATH_UNIX "/unix"
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# define SYSLOG_BUFSIZE 128
#endif /* UNIXWARE */
/*
** Intergraph CLIX 3.1
**
** From Paul Southworth <pauls@locust.cic.net>
*/
#ifdef CLIX
# define SYSTEM5 1 /* looks like System V */
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# endif /* ! HASGETUSERSHELL */
# define DEV_BSIZE 512 /* device block size not defined */
# define GIDSET_T gid_t
# undef LOG /* syslog not available */
# define NEEDFSYNC 1 /* no fsync in system library */
# define GETSHORT _getshort
#endif /* CLIX */
/*
** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP
**
** From Kevin Darcy <kevin@tech.mis.cfc.com>.
*/
#ifdef NCR_MP_RAS2
# include <sys/sockio.h>
# define __svr4__
# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
# define SYSLOG_BUFSIZE 1024
# define SPT_TYPE SPT_NONE
#endif /* NCR_MP_RAS2 */
/*
** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP
**
** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
*/
#ifdef NCR_MP_RAS3
# define __svr4__
# define HASFCHOWN 1 /* has fchown(2) call */
# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM has non-std interface */
# define SO_REUSEADDR_IS_BROKEN 1 /* doesn't work if accept() fails */
# define SYSLOG_BUFSIZE 1024
# define SPT_TYPE SPT_NONE
# ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE
# define _XOPEN_SOURCE_EXTENDED 1
# include <sys/resource.h>
# undef _XOPEN_SOURCE
# undef _XOPEN_SOURCE_EXTENDED
# endif /* ! _XOPEN_SOURCE */
#endif /* NCR_MP_RAS3 */
/*
** Tandem NonStop-UX SVR4
**
** From Rick McCarty <mccarty@mpd.tandem.com>.
*/
#ifdef NonStop_UX_BXX
# define __svr4__
#endif /* NonStop_UX_BXX */
/*
** Hitachi 3050R/3050RX and 3500 Workstations running HI-UX/WE2.
**
** Tested for 1.04, 1.03
** From Akihiro Hashimoto ("Hash") <hash@dominic.ipc.chiba-u.ac.jp>.
**
** Tested for 4.02, 6.10 and 7.10
** From Motonori NAKAMURA <motonori@media.kyoto-u.ac.jp>.
*/
#if !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE))
# define SYSTEM5 1 /* include all the System V defines */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define HASFCHMOD 1 /* has fchmod(2) syscall */
# define setreuid(r, e) setresuid(r, e, -1)
# define LA_TYPE LA_FLOAT
# define SPT_TYPE SPT_PSTAT
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# ifndef HASSETVBUF
# define HASSETVBUF /* HI-UX has no setlinebuf */
# endif /* ! HASSETVBUF */
# ifndef GIDSET_T
# define GIDSET_T gid_t
# endif /* ! GIDSET_T */
# ifndef _PATH_UNIX
# define _PATH_UNIX "/HI-UX"
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
# endif /* ! HASGETUSERSHELL */
# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
/*
** avoid m_flags conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h
** on HIUX 3050
*/
# undef m_flags
# ifdef __STDC__
extern int syslog(int, char *, ...);
# else /* __STDC__ */
extern int syslog();
# endif /* __STDC__ */
#endif /* !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE)) */
/*
** Amdahl UTS System V 2.1.5 (SVr3-based)
**
** From: Janet Jackson <janet@dialix.oz.au>.
*/
#ifdef _UTS
# include <sys/sysmacros.h>
# undef HASLSTAT /* has symlinks, but they cause problems */
# define NEEDFSYNC 1 /* system fsync(2) fails on non-EFS filesys */
# define SYS5SIGNALS 1 /* System V signal semantics */
# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
# define HASUNAME 1 /* use System V uname(2) system call */
# define HASINITGROUPS 1 /* has initgroups(3) function */
# define HASSETVBUF 1 /* has setvbuf(3) function */
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* does not have getusershell(3) function */
# endif /* ! HASGETUSERSHELL */
# define GIDSET_T gid_t /* type of 2nd arg to getgroups(2) isn't int */
# define LA_TYPE LA_ZERO /* doesn't have load average */
# define SFS_TYPE SFS_4ARGS /* use 4-arg statfs() */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define _PATH_UNIX "/unix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
#endif /* _UTS */
/*
** Cray Computer Corporation's CSOS
**
** From Scott Bolte <scott@craycos.com>.
*/
#ifdef _CRAYCOM
# define SYSTEM5 1 /* include all the System V defines */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define NEEDFSYNC 1 /* no fsync in system library */
# define MAXPATHLEN PATHSIZE
# define LA_TYPE LA_ZERO
# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
# define SFS_BAVAIL f_bfree /* alternate field name */
# define _POSIX_CHOWN_RESTRICTED -1
extern struct group *getgrent(), *getgrnam(), *getgrgid();
#endif /* _CRAYCOM */
/*
** Sony NEWS-OS 4.2.1R and 6.0.3
**
** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
*/
#ifdef sony_news
# ifndef __svr4
/* NEWS-OS 4.2.1R */
# ifndef BSD
# define BSD /* has BSD routines */
# endif /* ! BSD */
# define HASUNSETENV 1 /* has unsetenv(2) call */
# undef HASSETVBUF /* don't actually have setvbuf(3) */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# define LA_TYPE LA_INT
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# define setpgid setpgrp
# undef WIFEXITED
# undef WEXITSTATUS
# define MODE_T int /* system include files have no mode_t */
typedef int pid_t;
typedef int (*sigfunc_t)();
# define SIGFUNC_DEFINED
# define SIGFUNC_RETURN (0)
# define SIGFUNC_DECL int
# else /* ! __svr4 */
/* NEWS-OS 6.0.3 with /bin/cc */
# ifndef __svr4__
# define __svr4__ /* use all System V Release 4 defines below */
# endif /* ! __svr4__ */
# define HASSETSID 1 /* has Posix setsid(2) call */
# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
# ifndef SPT_TYPE
# define SPT_TYPE SPT_SYSMIPS /* use sysmips() (OS 6.0.2 or later) */
# endif /* ! SPT_TYPE */
# define GIDSET_T gid_t
# undef WIFEXITED
# undef WEXITSTATUS
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 256
# endif /* ! SYSLOG_BUFSIZE */
# define _PATH_UNIX "/stand/unix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# endif /* ! __svr4 */
#endif /* sony_news */
/*
** Omron LUNA/UNIOS-B 3.0, LUNA2/Mach and LUNA88K Mach
**
** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
*/
#ifdef luna
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
# define HASUNSETENV 1 /* has unsetenv(2) call */
# define NEEDPUTENV 1 /* need putenv(3) call */
# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
# define WAITUNION 1 /* use "union wait" as wait argument type */
# ifdef uniosb
# include <sys/time.h>
# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
# define LA_TYPE LA_INT
# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
# endif /* uniosb */
# ifdef luna2
# define LA_TYPE LA_SUBR
# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
# endif /* luna2 */
# ifdef luna88k
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define LA_TYPE LA_INT
# endif /* luna88k */
# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
# define setpgid setpgrp
# undef WIFEXITED
# undef WEXITSTATUS
typedef int pid_t;
typedef int (*sigfunc_t)();
# define SIGFUNC_DEFINED
# define SIGFUNC_RETURN (0)
# define SIGFUNC_DECL int
extern char *getenv();
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
#endif /* luna */
/*
** NEC EWS-UX/V 4.2 (with /usr/ucb/cc)
**
** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
*/
#if defined(nec_ews_svr4) || defined(_nec_ews_svr4)
# ifndef __svr4__
# define __svr4__ /* use all System V Release 4 defines below */
# endif /* ! __svr4__ */
# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
# define HASSETSID 1 /* has Posix setsid(2) call */
# define LA_TYPE LA_READKSYM /* use MIOC_READSYM ioctl */
# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
# define GIDSET_T gid_t
# undef WIFEXITED
# undef WEXITSTATUS
# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
# endif /* ! SYSLOG_BUFSIZE */
#endif /* defined(nec_ews_svr4) || defined(_nec_ews_svr4) */
/*
** Fujitsu/ICL UXP/DS (For the DS/90 Series)
**
** From Diego R. Lopez <drlopez@cica.es>.
** Additional changes from Fumio Moriya and Toshiaki Nomura of the
** Fujitsu Fresoftware group <dsfrsoft@oai6.yk.fujitsu.co.jp>.
*/
#ifdef __uxp__
# include <arpa/nameser.h>
# include <sys/sysmacros.h>
# include <sys/mkdev.h>
# define __svr4__
# define HASGETUSERSHELL 0
# define HASFLOCK 0
# if UXPDS == 10
# define HASSNPRINTF 0 /* no snprintf(3) or vsnprintf(3) */
# else /* UXPDS == 10 */
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# endif /* UXPDS == 10 */
# define _PATH_UNIX "/stand/unix"
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
#endif /* __uxp__ */
/*
** Pyramid DC/OSx
**
** From Earle Ake <akee@wpdiss1.wpafb.af.mil>.
*/
#ifdef DCOSx
# define GIDSET_T gid_t
# ifndef IDENTPROTO
# define IDENTPROTO 0 /* TCP/IP implementation is broken */
# endif /* ! IDENTPROTO */
#endif /* DCOSx */
/*
** Concurrent Computer Corporation Maxion
**
** From Donald R. Laster Jr. <laster@access.digex.net>.
*/
#ifdef __MAXION__
# include <sys/stream.h>
# define __svr4__ 1 /* SVR4.2MP */
# define HASSETREUID 1 /* have setreuid(2) */
# define HASLSTAT 1 /* have lstat(2) */
# define HASSETRLIMIT 1 /* have setrlimit(2) */
# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */
# define HASSNPRINTF 1 /* have snprintf(3) */
# define HASGETUSERSHELL 1 /* have getusershell(3) */
# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
# define SLEEP_T unsigned
# define SFS_TYPE SFS_STATVFS
# define SFS_BAVAIL f_bavail
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */
# endif /* ! SYSLOG_BUFSIZE */
# undef WUNTRACED
# undef WIFEXITED
# undef WIFSIGNALED
# undef WIFSTOPPED
# undef WEXITSTATUS
# undef WTERMSIG
# undef WSTOPSIG
#endif /* __MAXION__ */
/*
** Harris Nighthawk PowerUX (nh6000 box)
**
** Contributed by Bob Miorelli, Pratt & Whitney <miorelli@pweh.com>
*/
#ifdef _PowerUX
# ifndef __svr4__
# define __svr4__
# endif /* ! __svr4__ */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# define SYSLOG_BUFSIZE 1024
# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
# define LA_TYPE LA_ZERO
typedef struct msgb mblk_t;
# undef offsetof /* avoid stddefs.h and sys/sysmacros.h conflict */
#endif /* _PowerUX */
/*
** Siemens Nixdorf Informationssysteme AG SINIX
**
** Contributed by Gerald Rinske <Gerald.Rinske@mch.sni.de>
** of Siemens Business Services VAS.
*/
#ifdef sinix
# define HASRANDOM 0 /* has random(3) */
# define SYSLOG_BUFSIZE 1024
#endif /* sinix */
/*
** CRAY T3E
**
** Contributed by Manu Mahonen <mailadm@csc.fi>
** of Center for Scientific Computing.
*/
#ifdef _CRAY
# define GET_IPOPT_DST(dst) *(struct in_addr *)&(dst)
#endif /* _CRAY */
/*
** Motorola 922, MC88110, UNIX SYSTEM V/88 Release 4.0 Version 4.3
**
** Contributed by Sergey Rusanov <rsm@utfoms.udmnet.ru>
*/
#ifdef MOTO
# define HASFCHMOD 1
# define HASSETRLIMIT 0
# define HASSETSID 1
# define HASSETREUID 1
# define HASULIMIT 1
# define HASWAITPID 1
# define HASGETDTABLESIZE 1
# define HASGETUSERSHELL 1
# define IP_SRCROUTE 0
# define IDENTPROTO 0
# define RES_DNSRCH_VARIABLE _res_dnsrch
# define _PATH_UNIX "/unix"
# define _PATH_VENDOR_CF "/etc/sendmail.cf"
# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
#endif /* MOTO */
/**********************************************************************
** End of Per-Operating System defines
**********************************************************************/
/**********************************************************************
** More general defines
**********************************************************************/
/* general BSD defines */
#ifdef BSD
# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
# define HASSETREUID 1 /* has setreuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# ifndef IP_SRCROUTE
# define IP_SRCROUTE 1 /* can check IP source routing */
# endif /* ! IP_SRCROUTE */
# ifndef HASSETRLIMIT
# define HASSETRLIMIT 1 /* has setrlimit(2) call */
# endif /* ! HASSETRLIMIT */
# ifndef HASFLOCK
# define HASFLOCK 1 /* has flock(2) call */
# endif /* ! HASFLOCK */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone variable */
# endif /* ! TZ_TYPE */
#endif /* BSD */
/* general System V Release 4 defines */
#ifdef __svr4__
# define SYSTEM5 1
# define USESETEUID 1 /* has usable seteuid(2) call */
# define HASINITGROUPS 1 /* has initgroups(3) call */
# define BSD_COMP 1 /* get BSD ioctl calls */
# ifndef HASSETRLIMIT
# define HASSETRLIMIT 1 /* has setrlimit(2) call */
# endif /* ! HASSETRLIMIT */
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
# endif /* ! HASGETUSERSHELL */
# ifndef HASFCHMOD
# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */
# endif /* ! HASFCHMOD */
# ifndef _PATH_UNIX
# define _PATH_UNIX "/unix"
# endif /* ! _PATH_UNIX */
# ifndef _PATH_VENDOR_CF
# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
# endif /* ! _PATH_VENDOR_CF */
# ifndef _PATH_SENDMAILPID
# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
# endif /* ! _PATH_SENDMAILPID */
# ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 128
# endif /* ! SYSLOG_BUFSIZE */
# ifndef SFS_TYPE
# define SFS_TYPE SFS_STATVFS
# endif /* ! SFS_TYPE */
# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
#endif /* __svr4__ */
/* general System V defines */
#ifdef SYSTEM5
# include <sys/sysmacros.h>
# define HASUNAME 1 /* use System V uname(2) system call */
# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
# ifndef HASULIMIT
# define HASULIMIT 1 /* has the ulimit(2) syscall */
# endif /* ! HASULIMIT */
# ifndef LA_TYPE
# ifdef MIOC_READKSYM
# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
# else /* MIOC_READKSYM */
# define LA_TYPE LA_INT /* assume integer load average */
# endif /* MIOC_READKSYM */
# endif /* ! LA_TYPE */
# ifndef SFS_TYPE
# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
# endif /* ! SFS_TYPE */
# ifndef TZ_TYPE
# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
# endif /* ! TZ_TYPE */
#endif /* SYSTEM5 */
/* general POSIX defines */
#ifdef _POSIX_VERSION
# define HASSETSID 1 /* has Posix setsid(2) call */
# define HASWAITPID 1 /* has Posix waitpid(2) call */
# if _POSIX_VERSION >= 199500 && !defined(USESETEUID)
# define USESETEUID 1 /* has usable seteuid(2) call */
# endif /* _POSIX_VERSION >= 199500 && !defined(USESETEUID) */
#endif /* _POSIX_VERSION */
/*
** Tweaking for systems that (for example) claim to be BSD or POSIX
** but don't have all the standard BSD or POSIX routines (boo hiss).
*/
#ifdef titan
# undef HASINITGROUPS /* doesn't have initgroups(3) call */
#endif /* titan */
#ifdef _CRAYCOM
# undef HASSETSID /* despite POSIX claim, doesn't have setsid */
#endif /* _CRAYCOM */
#ifdef MOTO
# undef USESETEUID
#endif /* MOTO */
/*
** Due to a "feature" in some operating systems such as Ultrix 4.3 and
** HPUX 8.0, if you receive a "No route to host" message (ICMP message
** ICMP_UNREACH_HOST) on _any_ connection, all connections to that host
** are closed. Some firewalls return this error if you try to connect
** to the IDENT port (113), so you can't receive email from these hosts
** on these systems. The firewall really should use a more specific
** message such as ICMP_UNREACH_PROTOCOL or _PORT or _FILTER_PROHIB. If
** not explicitly set to zero above, default it on.
*/
#ifndef IDENTPROTO
# define IDENTPROTO 1 /* use IDENT proto (RFC 1413) */
#endif /* ! IDENTPROTO */
#ifndef IP_SRCROUTE
# define IP_SRCROUTE 1 /* Detect IP source routing */
#endif /* ! IP_SRCROUTE */
#ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 1 /* libc has getusershell(3) call */
#endif /* ! HASGETUSERSHELL */
#ifndef NETUNIX
# define NETUNIX 1 /* include unix domain support */
#endif /* ! NETUNIX */
#ifndef HASRANDOM
# define HASRANDOM 1 /* has random(3) support */
#endif /* ! HASRANDOM */
#ifndef HASFLOCK
# define HASFLOCK 0 /* assume no flock(2) support */
#endif /* ! HASFLOCK */
#ifndef HASSETREUID
# define HASSETREUID 0 /* assume no setreuid(2) call */
#endif /* ! HASSETREUID */
#ifndef HASFCHMOD
# define HASFCHMOD 0 /* assume no fchmod(2) syscall */
#endif /* ! HASFCHMOD */
#ifndef USESETEUID
# define USESETEUID 0 /* assume no seteuid(2) call or no saved ids */
#endif /* ! USESETEUID */
#ifndef HASSETRLIMIT
# define HASSETRLIMIT 0 /* assume no setrlimit(2) support */
#endif /* ! HASSETRLIMIT */
#ifndef HASULIMIT
# define HASULIMIT 0 /* assume no ulimit(2) support */
#endif /* ! HASULIMIT */
#ifndef SECUREWARE
# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */
#endif /* ! SECUREWARE */
#ifndef USE_SIGLONGJMP
# define USE_SIGLONGJMP 0 /* assume setjmp handles signals properly */
#endif /* ! USE_SIGLONGJMP */
#ifndef FDSET_CAST
# define FDSET_CAST /* (empty) cast for fd_set arg to select */
#endif /* ! FDSET_CAST */
/*
** Pick a mailer setuid method for changing the current uid
*/
#define USE_SETEUID 0
#define USE_SETREUID 1
#define USE_SETUID 2
#if USESETEUID
# define MAILER_SETUID_METHOD USE_SETEUID
#else /* USESETEUID */
# if HASSETREUID
# define MAILER_SETUID_METHOD USE_SETREUID
# else /* HASSETREUID */
# define MAILER_SETUID_METHOD USE_SETUID
# endif /* HASSETREUID */
#endif /* USESETEUID */
/*
** If no type for argument two of getgroups call is defined, assume
** it's an integer -- unfortunately, there seem to be several choices
** here.
*/
#ifndef GIDSET_T
# define GIDSET_T int
#endif /* ! GIDSET_T */
#ifndef UID_T
# define UID_T uid_t
#endif /* ! UID_T */
#ifndef GID_T
# define GID_T gid_t
#endif /* ! GID_T */
#ifndef SIZE_T
# define SIZE_T size_t
#endif /* ! SIZE_T */
#ifndef MODE_T
# define MODE_T mode_t
#endif /* ! MODE_T */
#ifndef ARGV_T
# define ARGV_T char **
#endif /* ! ARGV_T */
#ifndef SOCKADDR_LEN_T
# define SOCKADDR_LEN_T int
#endif /* ! SOCKADDR_LEN_T */
#ifndef SOCKOPT_LEN_T
# define SOCKOPT_LEN_T int
#endif /* ! SOCKOPT_LEN_T */
#ifndef QUAD_T
# define QUAD_T unsigned long
#endif /* ! QUAD_T */
/**********************************************************************
** Remaining definitions should never have to be changed. They are
** primarily to provide back compatibility for older systems -- for
** example, it includes some POSIX compatibility definitions
**********************************************************************/
/* System 5 compatibility */
#ifndef S_ISREG
# define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG)
#endif /* ! S_ISREG */
#ifndef S_ISDIR
# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR)
#endif /* ! S_ISDIR */
#if !defined(S_ISLNK) && defined(S_IFLNK)
# define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK)
#endif /* !defined(S_ISLNK) && defined(S_IFLNK) */
#if !defined(S_ISFIFO)
# if defined(S_IFIFO)
# define S_ISFIFO(foo) ((foo & S_IFMT) == S_IFIFO)
# else /* defined(S_IFIFO) */
# define S_ISFIFO(foo) FALSE
# endif /* defined(S_IFIFO) */
#endif /* !defined(S_ISFIFO) */
#ifndef S_IRUSR
# define S_IRUSR 0400
#endif /* ! S_IRUSR */
#ifndef S_IWUSR
# define S_IWUSR 0200
#endif /* ! S_IWUSR */
#ifndef S_IRGRP
# define S_IRGRP 0040
#endif /* ! S_IRGRP */
#ifndef S_IWGRP
# define S_IWGRP 0020
#endif /* ! S_IWGRP */
#ifndef S_IROTH
# define S_IROTH 0004
#endif /* ! S_IROTH */
#ifndef S_IWOTH
# define S_IWOTH 0002
#endif /* ! S_IWOTH */
/* close-on-exec flag */
#ifndef FD_CLOEXEC
# define FD_CLOEXEC 1
#endif /* ! FD_CLOEXEC */
/*
** Older systems don't have this error code -- it should be in
** /usr/include/sysexits.h.
*/
#ifndef EX_CONFIG
# define EX_CONFIG 78 /* configuration error */
#endif /* ! EX_CONFIG */
/* pseudo-codes */
#define EX_QUIT 22 /* drop out of server immediately */
#define EX_RESTART 23 /* restart sendmail daemon */
#define EX_SHUTDOWN 24 /* shutdown sendmail daemon */
/* pseudo-code used for mci_setstat */
#define EX_NOTSTICKY -5 /* don't save persistent status */
/*
** An "impossible" file mode to indicate that the file does not exist.
*/
#define ST_MODE_NOFILE 0171147 /* unlikely to occur */
/* type of arbitrary pointer */
#ifndef ARBPTR_T
# define ARBPTR_T void *
#endif /* ! ARBPTR_T */
#ifndef __P
# include "sendmail/cdefs.h"
#endif /* ! __P */
#if HESIOD && !defined(NAMED_BIND)
# define NAMED_BIND 1 /* not one without the other */
#endif /* HESIOD && !defined(NAMED_BIND) */
# if NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno )
extern int h_errno;
# endif /* NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno ) */
#ifdef LDAPMAP
# include <sys/time.h>
# include <lber.h>
# include <ldap.h>
/* Some LDAP constants */
# define LDAPMAP_FALSE 0
# define LDAPMAP_TRUE 1
/*
** ldap_init(3) is broken in Umich 3.x and OpenLDAP 1.0/1.1.
** Use the lack of LDAP_OPT_SIZELIMIT to detect old API implementations
** and assume (falsely) that all old API implementations are broken.
** (OpenLDAP 1.2 and later have a working ldap_init(), add -DUSE_LDAP_INIT)
*/
# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT)
# define USE_LDAP_INIT 1
# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT) */
/*
** LDAP_OPT_SIZELIMIT is not defined under Umich 3.x nor OpenLDAP 1.x,
** hence ldap_set_option() must not exist.
*/
# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION)
# define USE_LDAP_SET_OPTION 1
# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION) */
#endif /* LDAPMAP */
/*
** Do some required dependencies
*/
#if NETINET || NETINET6 || NETISO
# ifndef SMTP
# define SMTP 1 /* enable user and server SMTP */
# endif /* ! SMTP */
# ifndef QUEUE
# define QUEUE 1 /* enable queueing */
# endif /* ! QUEUE */
# ifndef DAEMON
# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */
# endif /* ! DAEMON */
#endif /* NETINET || NETINET6 || NETISO */
/*
** Arrange to use either varargs or stdargs
*/
#ifdef __STDC__
# include <stdarg.h>
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap, f)
# define VA_END va_end(ap)
#else /* __STDC__ */
# include <varargs.h>
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap)
# define VA_END va_end(ap)
#endif /* __STDC__ */
#if HASUNAME
# include <sys/utsname.h>
# ifdef newstr
# undef newstr
# endif /* newstr */
#else /* HASUNAME */
# define NODE_LENGTH 32
struct utsname
{
char nodename[NODE_LENGTH + 1];
};
#endif /* HASUNAME */
#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V)
# define MAXHOSTNAMELEN 256
#endif /* !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V) */
#if !defined(SIGCHLD) && defined(SIGCLD)
# define SIGCHLD SIGCLD
#endif /* !defined(SIGCHLD) && defined(SIGCLD) */
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif /* ! STDIN_FILENO */
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif /* ! STDOUT_FILENO */
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif /* ! STDERR_FILENO */
#ifndef LOCK_SH
# define LOCK_SH 0x01 /* shared lock */
# define LOCK_EX 0x02 /* exclusive lock */
# define LOCK_NB 0x04 /* non-blocking lock */
# define LOCK_UN 0x08 /* unlock */
#endif /* ! LOCK_SH */
#ifndef S_IXOTH
# define S_IXOTH (S_IEXEC >> 6)
#endif /* ! S_IXOTH */
#ifndef S_IXGRP
# define S_IXGRP (S_IEXEC >> 3)
#endif /* ! S_IXGRP */
#ifndef S_IXUSR
# define S_IXUSR (S_IEXEC)
#endif /* ! S_IXUSR */
#ifndef SEEK_SET
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
#endif /* ! SEEK_SET */
#ifndef SIG_ERR
# define SIG_ERR ((void (*)()) -1)
#endif /* ! SIG_ERR */
#ifndef WEXITSTATUS
# define WEXITSTATUS(st) (((st) >> 8) & 0377)
#endif /* ! WEXITSTATUS */
#ifndef WIFEXITED
# define WIFEXITED(st) (((st) & 0377) == 0)
#endif /* ! WIFEXITED */
#ifndef WIFSTOPPED
# define WIFSTOPPED(st) (((st) & 0100) == 0)
#endif /* ! WIFSTOPPED */
#ifndef WCOREDUMP
# define WCOREDUMP(st) (((st) & 0200) != 0)
#endif /* ! WCOREDUMP */
#ifndef WTERMSIG
# define WTERMSIG(st) (((st) & 0177))
#endif /* ! WTERMSIG */
#ifndef SIGFUNC_DEFINED
typedef void (*sigfunc_t) __P((int));
#endif /* ! SIGFUNC_DEFINED */
#ifndef SIGFUNC_RETURN
# define SIGFUNC_RETURN
#endif /* ! SIGFUNC_RETURN */
#ifndef SIGFUNC_DECL
# define SIGFUNC_DECL void
#endif /* ! SIGFUNC_DECL */
/* size of syslog buffer */
#ifndef SYSLOG_BUFSIZE
# define SYSLOG_BUFSIZE 1024
#endif /* ! SYSLOG_BUFSIZE */
/*
** Size of prescan buffer.
** Despite comments in the _sendmail_ book, this probably should
** not be changed; there are some hard-to-define dependencies.
*/
#define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */
/* fork routine -- set above using #ifdef _osname_ or in Makefile */
#ifndef FORK
# define FORK fork /* function to call to fork mailer */
#endif /* ! FORK */
/* random routine -- set above using #ifdef _osname_ or in Makefile */
#if HASRANDOM
# define get_random() random()
#else /* HASRANDOM */
# define get_random() ((long) rand())
# ifndef RANDOMSHIFT
# define RANDOMSHIFT 8
# endif /* RANDOMSHIFT */
#endif /* HASRANDOM */
/*
** Default to using scanf in readcf.
*/
#ifndef SCANF
# define SCANF 1
#endif /* ! SCANF */
#if _FFR_MILTER
/* 32 bit type */
# ifndef SM_INT32
# define SM_INT32 int32_t
# endif /* SM_INT32 */
#endif /* _FFR_MILTER */
/*
** SVr4 and similar systems use different routines for setjmp/longjmp
** with signal support
*/
#if USE_SIGLONGJMP
# ifdef jmp_buf
# undef jmp_buf
# endif /* jmp_buf */
# define jmp_buf sigjmp_buf
# ifdef setjmp
# undef setjmp
# endif /* setjmp */
# define setjmp(env) sigsetjmp(env, 1)
# ifdef longjmp
# undef longjmp
# endif /* longjmp */
# define longjmp(env, val) siglongjmp(env, val)
#endif /* USE_SIGLONGJMP */
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
# define NGROUPS_MAX NGROUPS /* POSIX naming convention */
#endif /* !defined(NGROUPS_MAX) && defined(NGROUPS) */
/*
** Some snprintf() implementations are rumored not to NUL terminate.
*/
#if SNPRINTF_IS_BROKEN
# ifdef snprintf
# undef snprintf
# endif /* snprintf */
# define snprintf sm_snprintf
# ifdef vsnprintf
# undef vsnprintf
# endif /* vsnprintf */
# define vsnprintf sm_vsnprintf
#endif /* SNPRINTF_IS_BROKEN */
/*
** If we don't have a system syslog, simulate it.
*/
#if !LOG
# define LOG_EMERG 0 /* system is unusable */
# define LOG_ALERT 1 /* action must be taken immediately */
# define LOG_CRIT 2 /* critical conditions */
# define LOG_ERR 3 /* error conditions */
# define LOG_WARNING 4 /* warning conditions */
# define LOG_NOTICE 5 /* normal but significant condition */
# define LOG_INFO 6 /* informational */
# define LOG_DEBUG 7 /* debug-level messages */
#endif /* !LOG */
-#if SFIO && defined(ERRLIST_PREDEFINED)
-# undef ERRLIST_PREDEFINED
-#endif /* SFIO && defined(ERRLIST_PREDEFINED) */
+#if SFIO
+# ifdef ERRLIST_PREDEFINED
+# undef ERRLIST_PREDEFINED
+# endif /* ERRLIST_PREDEFINED */
+# if !HASSNPRINTF
+# define HASSNPRINTF 1 /* sfio includes snprintf() */
+# endif /* !HASSNPRINTF */
+#endif /* SFIO */
#ifndef SFIO_STDIO_COMPAT
# define SFIO_STDIO_COMPAT 0
#endif /* ! SFIO_STDIO_COMPAT */
#endif /* CONF_H */
Index: head/contrib/sendmail/src/headers.c
===================================================================
--- head/contrib/sendmail/src/headers.c (revision 66496)
+++ head/contrib/sendmail/src/headers.c (revision 66497)
@@ -1,1878 +1,1876 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
-static char id[] = "@(#)$Id: headers.c,v 8.203.4.6 2000/07/19 02:53:32 ca Exp $";
+static char id[] = "@(#)$Id: headers.c,v 8.203.4.7 2000/08/22 21:50:36 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
#include <sendmail.h>
static bool fix_mime_header __P((char *));
static int priencode __P((char *));
static void put_vanilla_header __P((HDR *, char *, MCI *));
/*
** SETUPHEADERS -- initialize headers in symbol table
**
** Parameters:
** none
**
** Returns:
** none
*/
void
setupheaders()
{
struct hdrinfo *hi;
STAB *s;
for (hi = HdrInfo; hi->hi_field != NULL; hi++)
{
s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
s->s_header.hi_flags = hi->hi_flags;
s->s_header.hi_ruleset = NULL;
}
}
/*
** CHOMPHEADER -- process and save a header line.
**
** Called by collect, readcf, and readqf to deal with header lines.
**
** Parameters:
** line -- header as a text line.
-** pflag -- flags:
-** CHHDR_DEF: this is a default value.
-** CHHDR_CHECK: call rulesets.
+** pflag -- flags for chompheader() (from sendmail.h)
** hdrp -- a pointer to the place to save the header.
** e -- the envelope including this header.
**
** Returns:
** flags for this header.
**
** Side Effects:
** The header is saved on the header list.
** Contents of 'line' are destroyed.
*/
static struct hdrinfo NormalHeader = { NULL, 0, NULL };
u_long
chompheader(line, pflag, hdrp, e)
char *line;
int pflag;
HDR **hdrp;
register ENVELOPE *e;
{
u_char mid = '\0';
register char *p;
register HDR *h;
HDR **hp;
char *fname;
char *fvalue;
bool cond = FALSE;
bool dropfrom;
bool headeronly;
STAB *s;
struct hdrinfo *hi;
bool nullheader = FALSE;
BITMAP256 mopts;
if (tTd(31, 6))
{
dprintf("chompheader: ");
xputs(line);
dprintf("\n");
}
headeronly = hdrp != NULL;
if (!headeronly)
hdrp = &e->e_header;
/* strip off options */
clrbitmap(mopts);
p = line;
if (!bitset(pflag, CHHDR_USER) && *p == '?')
{
int c;
register char *q;
q = strchr(++p, '?');
if (q == NULL)
goto hse;
*q = '\0';
c = *p & 0377;
/* possibly macro conditional */
if (c == MACROEXPAND)
{
/* catch ?$? */
if (*++p == '\0')
{
*q = '?';
goto hse;
}
mid = (u_char) *p++;
/* catch ?$abc? */
if (*p != '\0')
{
*q = '?';
goto hse;
}
}
else if (*p == '$')
{
/* catch ?$? */
if (*++p == '\0')
{
*q = '?';
goto hse;
}
mid = (u_char)macid(p, NULL);
if (bitset(0200, mid))
p += strlen(macname(mid)) + 2;
else
p++;
/* catch ?$abc? */
if (*p != '\0')
{
*q = '?';
goto hse;
}
}
else
{
while (*p != '\0')
{
if (!isascii(*p))
{
*q = '?';
goto hse;
}
setbitn(*p, mopts);
cond = TRUE;
p++;
}
}
p = q + 1;
}
/* find canonical name */
fname = p;
while (isascii(*p) && isgraph(*p) && *p != ':')
p++;
fvalue = p;
while (isascii(*p) && isspace(*p))
p++;
if (*p++ != ':' || fname == fvalue)
{
hse:
syserr("553 5.3.0 header syntax error, line \"%s\"", line);
return 0;
}
*fvalue = '\0';
/* strip field value on front */
if (*p == ' ')
p++;
fvalue = p;
/* if the field is null, go ahead and use the default */
while (isascii(*p) && isspace(*p))
p++;
if (*p == '\0')
nullheader = TRUE;
/* security scan: long field names are end-of-header */
if (strlen(fname) > 100)
return H_EOH;
/* check to see if it represents a ruleset call */
if (bitset(pflag, CHHDR_DEF))
{
char hbuf[50];
(void) expand(fvalue, hbuf, sizeof hbuf, e);
for (p = hbuf; isascii(*p) && isspace(*p); )
p++;
if ((*p++ & 0377) == CALLSUBR)
{
auto char *endp;
bool strc;
strc = *p == '+'; /* strip comments? */
if (strc)
++p;
if (strtorwset(p, &endp, ST_ENTER) > 0)
{
*endp = '\0';
s = stab(fname, ST_HEADER, ST_ENTER);
s->s_header.hi_ruleset = newstr(p);
if (!strc)
s->s_header.hi_flags |= H_STRIPCOMM;
}
return 0;
}
}
/* see if it is a known type */
s = stab(fname, ST_HEADER, ST_FIND);
if (s != NULL)
hi = &s->s_header;
else
hi = &NormalHeader;
if (tTd(31, 9))
{
if (s == NULL)
dprintf("no header flags match\n");
else
dprintf("header match, flags=%lx, ruleset=%s\n",
hi->hi_flags,
hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
}
/* see if this is a resent message */
if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
bitset(H_RESENT, hi->hi_flags))
e->e_flags |= EF_RESENT;
/* if this is an Errors-To: header keep track of it now */
if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
bitset(H_ERRORSTO, hi->hi_flags))
(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
/* if this means "end of header" quit now */
if (!headeronly && bitset(H_EOH, hi->hi_flags))
return hi->hi_flags;
/*
** Horrible hack to work around problem with Lotus Notes SMTP
** mail gateway, which generates From: headers with newlines in
** them and the <address> on the second line. Although this is
** legal RFC 822, many MUAs don't handle this properly and thus
** never find the actual address.
*/
if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
{
while ((p = strchr(fvalue, '\n')) != NULL)
*p = ' ';
}
/*
** If there is a check ruleset, verify it against the header.
*/
if (bitset(pflag, CHHDR_CHECK))
{
bool stripcom = FALSE;
char *rs;
/* no ruleset? look for default */
rs = hi->hi_ruleset;
if (rs == NULL)
{
s = stab("*", ST_HEADER, ST_FIND);
if (s != NULL)
{
rs = (&s->s_header)->hi_ruleset;
stripcom = bitset((&s->s_header)->hi_flags,
H_STRIPCOMM);
}
}
else
stripcom = bitset(hi->hi_flags, H_STRIPCOMM);
if (rs != NULL)
{
int l;
char qval[MAXNAME];
char hlen[16];
char *sp, *dp;
dp = qval;
l = 0;
dp[l++] = '"';
for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++)
{
switch(*sp)
{
case '\011': /* ht */
case '\012': /* nl */
case '\013': /* vt */
case '\014': /* np */
case '\015': /* cr */
dp[l++] = ' ';
break;
case '"':
dp[l++] = '\\';
/* FALLTHROUGH */
default:
dp[l++] = *sp;
break;
}
}
dp[l++] = '"';
dp[l++] = '\0';
l = strlen(fvalue);
snprintf(hlen, sizeof hlen, "%d", l);
define(macid("{hdrlen}", NULL), newstr(hlen), e);
if (l >= MAXNAME)
{
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"Warning: truncated header '%s' before check with '%s' len=%d max=%d",
fname, rs, l, MAXNAME);
}
if ((sp = macvalue(macid("{currHeader}", NULL), e)) !=
NULL)
free(sp);
define(macid("{currHeader}", NULL), newstr(qval), e);
define(macid("{hdr_name}", NULL), newstr(fname), e);
(void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4);
}
}
/*
** Drop explicit From: if same as what we would generate.
** This is to make MH (which doesn't always give a full name)
** insert the full name information in all circumstances.
*/
dropfrom = FALSE;
p = "resent-from";
if (!bitset(EF_RESENT, e->e_flags))
p += 7;
if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
!bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
{
if (tTd(31, 2))
{
dprintf("comparing header from (%s) against default (%s or %s)\n",
fvalue, e->e_from.q_paddr, e->e_from.q_user);
}
if (e->e_from.q_paddr != NULL &&
e->e_from.q_mailer != NULL &&
bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
(strcmp(fvalue, e->e_from.q_paddr) == 0 ||
strcmp(fvalue, e->e_from.q_user) == 0))
dropfrom = TRUE;
}
/* delete default value for this header */
for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
{
if (strcasecmp(fname, h->h_field) == 0 &&
!bitset(H_USER, h->h_flags) &&
!bitset(H_FORCE, h->h_flags))
{
if (nullheader)
{
/* user-supplied value was null */
return 0;
}
if (dropfrom)
{
/* make this look like the user entered it */
h->h_flags |= H_USER;
return hi->hi_flags;
}
h->h_value = NULL;
if (!cond)
{
/* copy conditions from default case */
memmove((char *)mopts, (char *)h->h_mflags,
sizeof mopts);
}
h->h_macro = mid;
}
}
/* create a new node */
h = (HDR *) xalloc(sizeof *h);
h->h_field = newstr(fname);
h->h_value = newstr(fvalue);
h->h_link = NULL;
memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
h->h_macro = mid;
*hp = h;
h->h_flags = hi->hi_flags;
- if (bitset(pflag, CHHDR_USER))
+ if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
h->h_flags |= H_USER;
/* strip EOH flag if parsing MIME headers */
if (headeronly)
h->h_flags &= ~H_EOH;
if (bitset(pflag, CHHDR_DEF))
h->h_flags |= H_DEFAULT;
if (cond || mid != '\0')
h->h_flags |= H_CHECK;
/* hack to see if this is a new format message */
if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
bitset(H_RCPT|H_FROM, h->h_flags) &&
(strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
{
e->e_flags &= ~EF_OLDSTYLE;
}
return h->h_flags;
}
/*
** ADDHEADER -- add a header entry to the end of the queue.
**
** This bypasses the special checking of chompheader.
**
** Parameters:
** field -- the name of the header field.
** value -- the value of the field.
** flags -- flags to add to h_flags.
** hdrlist -- an indirect pointer to the header structure list.
**
** Returns:
** none.
**
** Side Effects:
** adds the field on the list of headers for this envelope.
*/
void
addheader(field, value, flags, hdrlist)
char *field;
char *value;
int flags;
HDR **hdrlist;
{
register HDR *h;
STAB *s;
HDR **hp;
/* find info struct */
s = stab(field, ST_HEADER, ST_FIND);
/* find current place in list -- keep back pointer? */
for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
{
if (strcasecmp(field, h->h_field) == 0)
break;
}
/* allocate space for new header */
h = (HDR *) xalloc(sizeof *h);
h->h_field = field;
h->h_value = newstr(value);
h->h_link = *hp;
h->h_flags = flags;
if (s != NULL)
h->h_flags |= s->s_header.hi_flags;
clrbitmap(h->h_mflags);
h->h_macro = '\0';
*hp = h;
}
/*
** HVALUE -- return value of a header.
**
** Only "real" fields (i.e., ones that have not been supplied
** as a default) are used.
**
** Parameters:
** field -- the field name.
** header -- the header list.
**
** Returns:
** pointer to the value part.
** NULL if not found.
**
** Side Effects:
** none.
*/
char *
hvalue(field, header)
char *field;
HDR *header;
{
register HDR *h;
for (h = header; h != NULL; h = h->h_link)
{
if (!bitset(H_DEFAULT, h->h_flags) &&
strcasecmp(h->h_field, field) == 0)
return h->h_value;
}
return NULL;
}
/*
** ISHEADER -- predicate telling if argument is a header.
**
** A line is a header if it has a single word followed by
** optional white space followed by a colon.
**
** Header fields beginning with two dashes, although technically
** permitted by RFC822, are automatically rejected in order
** to make MIME work out. Without this we could have a technically
** legal header such as ``--"foo:bar"'' that would also be a legal
** MIME separator.
**
** Parameters:
** h -- string to check for possible headerness.
**
** Returns:
** TRUE if h is a header.
** FALSE otherwise.
**
** Side Effects:
** none.
*/
bool
isheader(h)
char *h;
{
register char *s = h;
if (s[0] == '-' && s[1] == '-')
return FALSE;
while (*s > ' ' && *s != ':' && *s != '\0')
s++;
if (h == s)
return FALSE;
/* following technically violates RFC822 */
while (isascii(*s) && isspace(*s))
s++;
return (*s == ':');
}
/*
** EATHEADER -- run through the stored header and extract info.
**
** Parameters:
** e -- the envelope to process.
** full -- if set, do full processing (e.g., compute
** message priority). This should not be set
** when reading a queue file because some info
** needed to compute the priority is wrong.
**
** Returns:
** none.
**
** Side Effects:
** Sets a bunch of global variables from information
** in the collected header.
** Aborts the message if the hop count is exceeded.
*/
void
eatheader(e, full)
register ENVELOPE *e;
bool full;
{
register HDR *h;
register char *p;
int hopcnt = 0;
char *msgid;
char buf[MAXLINE];
/*
** Set up macros for possible expansion in headers.
*/
define('f', e->e_sender, e);
define('g', e->e_sender, e);
if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
define('u', e->e_origrcpt, e);
else
define('u', NULL, e);
/* full name of from person */
p = hvalue("full-name", e->e_header);
if (p != NULL)
{
if (!rfc822_string(p))
{
/*
** Quote a full name with special characters
** as a comment so crackaddr() doesn't destroy
** the name portion of the address.
*/
p = addquotes(p);
}
define('x', p, e);
}
if (tTd(32, 1))
dprintf("----- collected header -----\n");
msgid = NULL;
for (h = e->e_header; h != NULL; h = h->h_link)
{
if (tTd(32, 1))
dprintf("%s: ", h->h_field);
if (h->h_value == NULL)
{
if (tTd(32, 1))
dprintf("<NULL>\n");
continue;
}
/* do early binding */
if (bitset(H_DEFAULT, h->h_flags) &&
!bitset(H_BINDLATE, h->h_flags))
{
if (tTd(32, 1))
{
dprintf("(");
xputs(h->h_value);
dprintf(") ");
}
expand(h->h_value, buf, sizeof buf, e);
if (buf[0] != '\0')
{
if (bitset(H_FROM, h->h_flags))
expand(crackaddr(buf), buf, sizeof buf, e);
h->h_value = newstr(buf);
h->h_flags &= ~H_DEFAULT;
}
}
if (tTd(32, 1))
{
xputs(h->h_value);
dprintf("\n");
}
/* count the number of times it has been processed */
if (bitset(H_TRACE, h->h_flags))
hopcnt++;
/* send to this person if we so desire */
if (GrabTo && bitset(H_RCPT, h->h_flags) &&
!bitset(H_DEFAULT, h->h_flags) &&
(!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
{
#if 0
int saveflags = e->e_flags;
#endif /* 0 */
(void) sendtolist(h->h_value, NULLADDR,
&e->e_sendqueue, 0, e);
#if 0
/*
** Change functionality so a fatal error on an
** address doesn't affect the entire envelope.
*/
/* delete fatal errors generated by this address */
if (!bitset(EF_FATALERRS, saveflags))
e->e_flags &= ~EF_FATALERRS;
#endif /* 0 */
}
/* save the message-id for logging */
p = "resent-message-id";
if (!bitset(EF_RESENT, e->e_flags))
p += 7;
if (strcasecmp(h->h_field, p) == 0)
{
msgid = h->h_value;
while (isascii(*msgid) && isspace(*msgid))
msgid++;
}
}
if (tTd(32, 1))
dprintf("----------------------------\n");
/* if we are just verifying (that is, sendmail -t -bv), drop out now */
if (OpMode == MD_VERIFY)
return;
/* store hop count */
if (hopcnt > e->e_hopcount)
e->e_hopcount = hopcnt;
/* message priority */
p = hvalue("precedence", e->e_header);
if (p != NULL)
e->e_class = priencode(p);
if (e->e_class < 0)
e->e_timeoutclass = TOC_NONURGENT;
else if (e->e_class > 0)
e->e_timeoutclass = TOC_URGENT;
if (full)
{
e->e_msgpriority = e->e_msgsize
- e->e_class * WkClassFact
+ e->e_nrcpts * WkRecipFact;
}
/* message timeout priority */
p = hvalue("priority", e->e_header);
if (p != NULL)
{
/* (this should be in the configuration file) */
if (strcasecmp(p, "urgent") == 0)
e->e_timeoutclass = TOC_URGENT;
else if (strcasecmp(p, "normal") == 0)
e->e_timeoutclass = TOC_NORMAL;
else if (strcasecmp(p, "non-urgent") == 0)
e->e_timeoutclass = TOC_NONURGENT;
}
/* date message originated */
p = hvalue("posted-date", e->e_header);
if (p == NULL)
p = hvalue("date", e->e_header);
if (p != NULL)
define('a', p, e);
/* check to see if this is a MIME message */
if ((e->e_bodytype != NULL &&
strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
hvalue("MIME-Version", e->e_header) != NULL)
{
e->e_flags |= EF_IS_MIME;
if (HasEightBits)
e->e_bodytype = "8BITMIME";
}
else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
{
/* this may be an RFC 1049 message */
p = strpbrk(p, ";/");
if (p == NULL || *p == ';')
{
/* yep, it is */
e->e_flags |= EF_DONT_MIME;
}
}
/*
** From person in antiquated ARPANET mode
** required by UK Grey Book e-mail gateways (sigh)
*/
if (OpMode == MD_ARPAFTP)
{
register struct hdrinfo *hi;
for (hi = HdrInfo; hi->hi_field != NULL; hi++)
{
if (bitset(H_FROM, hi->hi_flags) &&
(!bitset(H_RESENT, hi->hi_flags) ||
bitset(EF_RESENT, e->e_flags)) &&
(p = hvalue(hi->hi_field, e->e_header)) != NULL)
break;
}
if (hi->hi_field != NULL)
{
if (tTd(32, 2))
dprintf("eatheader: setsender(*%s == %s)\n",
hi->hi_field, p);
setsender(p, e, NULL, '\0', TRUE);
}
}
/*
** Log collection information.
*/
if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
logsender(e, msgid);
e->e_flags &= ~EF_LOGSENDER;
}
/*
** LOGSENDER -- log sender information
**
** Parameters:
** e -- the envelope to log
** msgid -- the message id
**
** Returns:
** none
*/
void
logsender(e, msgid)
register ENVELOPE *e;
char *msgid;
{
char *name;
register char *sbp;
register char *p;
int l;
char hbuf[MAXNAME + 1];
char sbuf[MAXLINE + 1];
char mbuf[MAXNAME + 1];
/* don't allow newlines in the message-id */
if (msgid != NULL)
{
l = strlen(msgid);
if (l > sizeof mbuf - 1)
l = sizeof mbuf - 1;
memmove(mbuf, msgid, l);
mbuf[l] = '\0';
p = mbuf;
while ((p = strchr(p, '\n')) != NULL)
*p++ = ' ';
}
if (bitset(EF_RESPONSE, e->e_flags))
name = "[RESPONSE]";
else if ((name = macvalue('_', e)) != NULL)
/* EMPTY */
;
else if (RealHostName == NULL)
name = "localhost";
else if (RealHostName[0] == '[')
name = RealHostName;
else
{
name = hbuf;
(void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
if (RealHostAddr.sa.sa_family != 0)
{
p = &hbuf[strlen(hbuf)];
(void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
anynet_ntoa(&RealHostAddr));
}
}
/* some versions of syslog only take 5 printf args */
#if (SYSLOG_BUFSIZE) >= 256
sbp = sbuf;
snprintf(sbp, SPACELEFT(sbuf, sbp),
"from=%.200s, size=%ld, class=%d, nrcpts=%d",
e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
e->e_msgsize, e->e_class, e->e_nrcpts);
sbp += strlen(sbp);
if (msgid != NULL)
{
snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
sbp += strlen(sbp);
}
if (e->e_bodytype != NULL)
{
(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
e->e_bodytype);
sbp += strlen(sbp);
}
p = macvalue('r', e);
if (p != NULL)
{
(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
sbp += strlen(sbp);
}
p = macvalue(macid("{daemon_name}", NULL), e);
if (p != NULL)
{
(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p);
sbp += strlen(sbp);
}
# if SASL
p = macvalue(macid("{auth_type}", NULL), e);
if (p != NULL)
{
(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p);
sbp += strlen(sbp);
}
p = macvalue(macid("{auth_author}", NULL), e);
if (p != NULL)
{
(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p);
sbp += strlen(sbp);
}
# endif /* SASL */
sm_syslog(LOG_INFO, e->e_id,
"%.850s, relay=%.100s",
sbuf, name);
#else /* (SYSLOG_BUFSIZE) >= 256 */
sm_syslog(LOG_INFO, e->e_id,
"from=%s",
e->e_from.q_paddr == NULL ? "<NONE>"
: shortenstring(e->e_from.q_paddr, 83));
sm_syslog(LOG_INFO, e->e_id,
"size=%ld, class=%ld, nrcpts=%d",
e->e_msgsize, e->e_class, e->e_nrcpts);
if (msgid != NULL)
sm_syslog(LOG_INFO, e->e_id,
"msgid=%s",
shortenstring(mbuf, 83));
sbp = sbuf;
*sbp = '\0';
if (e->e_bodytype != NULL)
{
snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
sbp += strlen(sbp);
}
p = macvalue('r', e);
if (p != NULL)
{
snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
sbp += strlen(sbp);
}
sm_syslog(LOG_INFO, e->e_id,
"%.400srelay=%.100s", sbuf, name);
#endif /* (SYSLOG_BUFSIZE) >= 256 */
}
/*
** PRIENCODE -- encode external priority names into internal values.
**
** Parameters:
** p -- priority in ascii.
**
** Returns:
** priority as a numeric level.
**
** Side Effects:
** none.
*/
static int
priencode(p)
char *p;
{
register int i;
for (i = 0; i < NumPriorities; i++)
{
if (strcasecmp(p, Priorities[i].pri_name) == 0)
return Priorities[i].pri_val;
}
/* unknown priority */
return 0;
}
/*
** CRACKADDR -- parse an address and turn it into a macro
**
** This doesn't actually parse the address -- it just extracts
** it and replaces it with "$g". The parse is totally ad hoc
** and isn't even guaranteed to leave something syntactically
** identical to what it started with. However, it does leave
** something semantically identical.
**
** This algorithm has been cleaned up to handle a wider range
** of cases -- notably quoted and backslash escaped strings.
** This modification makes it substantially better at preserving
** the original syntax.
**
** Parameters:
** addr -- the address to be cracked.
**
** Returns:
** a pointer to the new version.
**
** Side Effects:
** none.
**
** Warning:
** The return value is saved in local storage and should
** be copied if it is to be reused.
*/
char *
crackaddr(addr)
register char *addr;
{
register char *p;
register char c;
int cmtlev;
int realcmtlev;
int anglelev, realanglelev;
int copylev;
int bracklev;
bool qmode;
bool realqmode;
bool skipping;
bool putgmac = FALSE;
bool quoteit = FALSE;
bool gotangle = FALSE;
bool gotcolon = FALSE;
register char *bp;
char *buflim;
char *bufhead;
char *addrhead;
static char buf[MAXNAME + 1];
if (tTd(33, 1))
dprintf("crackaddr(%s)\n", addr);
/* strip leading spaces */
while (*addr != '\0' && isascii(*addr) && isspace(*addr))
addr++;
/*
** Start by assuming we have no angle brackets. This will be
** adjusted later if we find them.
*/
bp = bufhead = buf;
buflim = &buf[sizeof buf - 7];
p = addrhead = addr;
copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
bracklev = 0;
qmode = realqmode = FALSE;
while ((c = *p++) != '\0')
{
/*
** If the buffer is overful, go into a special "skipping"
** mode that tries to keep legal syntax but doesn't actually
** output things.
*/
skipping = bp >= buflim;
if (copylev > 0 && !skipping)
*bp++ = c;
/* check for backslash escapes */
if (c == '\\')
{
/* arrange to quote the address */
if (cmtlev <= 0 && !qmode)
quoteit = TRUE;
if ((c = *p++) == '\0')
{
/* too far */
p--;
goto putg;
}
if (copylev > 0 && !skipping)
*bp++ = c;
goto putg;
}
/* check for quoted strings */
if (c == '"' && cmtlev <= 0)
{
qmode = !qmode;
if (copylev > 0 && !skipping)
realqmode = !realqmode;
continue;
}
if (qmode)
goto putg;
/* check for comments */
if (c == '(')
{
cmtlev++;
/* allow space for closing paren */
if (!skipping)
{
buflim--;
realcmtlev++;
if (copylev++ <= 0)
{
if (bp != bufhead)
*bp++ = ' ';
*bp++ = c;
}
}
}
if (cmtlev > 0)
{
if (c == ')')
{
cmtlev--;
copylev--;
if (!skipping)
{
realcmtlev--;
buflim++;
}
}
continue;
}
else if (c == ')')
{
/* syntax error: unmatched ) */
if (copylev > 0 && !skipping)
bp--;
}
/* count nesting on [ ... ] (for IPv6 domain literals) */
if (c == '[')
bracklev++;
else if (c == ']')
bracklev--;
/* check for group: list; syntax */
if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
!gotcolon && !ColonOkInAddr)
{
register char *q;
/*
** Check for DECnet phase IV ``::'' (host::user)
** or ** DECnet phase V ``:.'' syntaxes. The latter
** covers ``user@DEC:.tay.myhost'' and
** ``DEC:.tay.myhost::user'' syntaxes (bletch).
*/
if (*p == ':' || *p == '.')
{
if (cmtlev <= 0 && !qmode)
quoteit = TRUE;
if (copylev > 0 && !skipping)
{
*bp++ = c;
*bp++ = *p;
}
p++;
goto putg;
}
gotcolon = TRUE;
bp = bufhead;
if (quoteit)
{
*bp++ = '"';
/* back up over the ':' and any spaces */
--p;
while (isascii(*--p) && isspace(*p))
continue;
p++;
}
for (q = addrhead; q < p; )
{
c = *q++;
if (bp < buflim)
{
if (quoteit && c == '"')
*bp++ = '\\';
*bp++ = c;
}
}
if (quoteit)
{
if (bp == &bufhead[1])
bp--;
else
*bp++ = '"';
while ((c = *p++) != ':')
{
if (bp < buflim)
*bp++ = c;
}
*bp++ = c;
}
/* any trailing white space is part of group: */
while (isascii(*p) && isspace(*p) && bp < buflim)
*bp++ = *p++;
copylev = 0;
putgmac = quoteit = FALSE;
bufhead = bp;
addrhead = p;
continue;
}
if (c == ';' && copylev <= 0 && !ColonOkInAddr)
{
if (bp < buflim)
*bp++ = c;
}
/* check for characters that may have to be quoted */
if (strchr(MustQuoteChars, c) != NULL)
{
/*
** If these occur as the phrase part of a <>
** construct, but are not inside of () or already
** quoted, they will have to be quoted. Note that
** now (but don't actually do the quoting).
*/
if (cmtlev <= 0 && !qmode)
quoteit = TRUE;
}
/* check for angle brackets */
if (c == '<')
{
register char *q;
/* assume first of two angles is bogus */
if (gotangle)
quoteit = TRUE;
gotangle = TRUE;
/* oops -- have to change our mind */
anglelev = 1;
if (!skipping)
realanglelev = 1;
bp = bufhead;
if (quoteit)
{
*bp++ = '"';
/* back up over the '<' and any spaces */
--p;
while (isascii(*--p) && isspace(*p))
continue;
p++;
}
for (q = addrhead; q < p; )
{
c = *q++;
if (bp < buflim)
{
if (quoteit && c == '"')
*bp++ = '\\';
*bp++ = c;
}
}
if (quoteit)
{
if (bp == &buf[1])
bp--;
else
*bp++ = '"';
while ((c = *p++) != '<')
{
if (bp < buflim)
*bp++ = c;
}
*bp++ = c;
}
copylev = 0;
putgmac = quoteit = FALSE;
continue;
}
if (c == '>')
{
if (anglelev > 0)
{
anglelev--;
if (!skipping)
{
realanglelev--;
buflim++;
}
}
else if (!skipping)
{
/* syntax error: unmatched > */
if (copylev > 0)
bp--;
quoteit = TRUE;
continue;
}
if (copylev++ <= 0)
*bp++ = c;
continue;
}
/* must be a real address character */
putg:
if (copylev <= 0 && !putgmac)
{
if (bp > bufhead && bp[-1] == ')')
*bp++ = ' ';
*bp++ = MACROEXPAND;
*bp++ = 'g';
putgmac = TRUE;
}
}
/* repair any syntactic damage */
if (realqmode)
*bp++ = '"';
while (realcmtlev-- > 0)
*bp++ = ')';
while (realanglelev-- > 0)
*bp++ = '>';
*bp++ = '\0';
if (tTd(33, 1))
{
dprintf("crackaddr=>`");
xputs(buf);
dprintf("'\n");
}
return buf;
}
/*
** PUTHEADER -- put the header part of a message from the in-core copy
**
** Parameters:
** mci -- the connection information.
** hdr -- the header to put.
** e -- envelope to use.
** flags -- MIME conversion flags.
**
** Returns:
** none.
**
** Side Effects:
** none.
*/
/*
* Macro for fast max (not available in e.g. DG/UX, 386/ix).
*/
#ifndef MAX
# define MAX(a,b) (((a)>(b))?(a):(b))
#endif /* ! MAX */
void
putheader(mci, hdr, e, flags)
register MCI *mci;
HDR *hdr;
register ENVELOPE *e;
int flags;
{
register HDR *h;
char buf[MAX(MAXLINE,BUFSIZ)];
char obuf[MAXLINE];
if (tTd(34, 1))
dprintf("--- putheader, mailer = %s ---\n",
mci->mci_mailer->m_name);
/*
** If we're in MIME mode, we're not really in the header of the
** message, just the header of one of the parts of the body of
** the message. Therefore MCIF_INHEADER should not be turned on.
*/
if (!bitset(MCIF_INMIME, mci->mci_flags))
mci->mci_flags |= MCIF_INHEADER;
for (h = hdr; h != NULL; h = h->h_link)
{
register char *p = h->h_value;
if (tTd(34, 11))
{
dprintf(" %s: ", h->h_field);
xputs(p);
}
/* Skip empty headers */
if (h->h_value == NULL)
continue;
/* heuristic shortening of MIME fields to avoid MUA overflows */
if (MaxMimeFieldLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMEFieldHeaders}", NULL)))
{
if (fix_mime_header(h->h_value))
{
sm_syslog(LOG_ALERT, e->e_id,
"Truncated MIME %s header due to field size (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated MIME %s header due to field size (possible attack)\n",
h->h_field);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMETextHeaders}", NULL)))
{
if (strlen(h->h_value) > (size_t)MaxMimeHeaderLength)
{
h->h_value[MaxMimeHeaderLength - 1] = '\0';
sm_syslog(LOG_ALERT, e->e_id,
"Truncated long MIME %s header (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated long MIME %s header (possible attack)\n",
h->h_field);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
macid("{checkMIMEHeaders}", NULL)))
{
if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength))
{
sm_syslog(LOG_ALERT, e->e_id,
"Truncated long MIME %s header (possible attack)",
h->h_field);
if (tTd(34, 11))
dprintf(" truncated long MIME %s header (possible attack)\n",
h->h_field);
}
}
/*
** Suppress Content-Transfer-Encoding: if we are MIMEing
** and we are potentially converting from 8 bit to 7 bit
** MIME. If converting, add a new CTE header in
** mime8to7().
*/
if (bitset(H_CTE, h->h_flags) &&
bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
mci->mci_flags) &&
!bitset(M87F_NO8TO7, flags))
{
if (tTd(34, 11))
dprintf(" (skipped (content-transfer-encoding))\n");
continue;
}
if (bitset(MCIF_INMIME, mci->mci_flags))
{
if (tTd(34, 11))
dprintf("\n");
put_vanilla_header(h, p, mci);
continue;
}
if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
!bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
(h->h_macro == '\0' ||
macvalue(h->h_macro & 0377, e) == NULL))
{
if (tTd(34, 11))
dprintf(" (skipped)\n");
continue;
}
/* handle Resent-... headers specially */
if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
{
if (tTd(34, 11))
dprintf(" (skipped (resent))\n");
continue;
}
/* suppress return receipts if requested */
if (bitset(H_RECEIPTTO, h->h_flags) &&
(RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
{
if (tTd(34, 11))
dprintf(" (skipped (receipt))\n");
continue;
}
/* macro expand value if generated internally */
if (bitset(H_DEFAULT, h->h_flags) ||
bitset(H_BINDLATE, h->h_flags))
{
expand(p, buf, sizeof buf, e);
p = buf;
if (*p == '\0')
{
if (tTd(34, 11))
dprintf(" (skipped -- null value)\n");
continue;
}
}
if (bitset(H_BCC, h->h_flags))
{
/* Bcc: field -- either truncate or delete */
if (bitset(EF_DELETE_BCC, e->e_flags))
{
if (tTd(34, 11))
dprintf(" (skipped -- bcc)\n");
}
else
{
/* no other recipient headers: truncate value */
(void) snprintf(obuf, sizeof obuf, "%s:",
h->h_field);
putline(obuf, mci);
}
continue;
}
if (tTd(34, 11))
dprintf("\n");
if (bitset(H_FROM|H_RCPT, h->h_flags))
{
/* address field */
bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
if (bitset(H_FROM, h->h_flags))
oldstyle = FALSE;
commaize(h, p, oldstyle, mci, e);
}
else
{
put_vanilla_header(h, p, mci);
}
}
/*
** If we are converting this to a MIME message, add the
** MIME headers (but not in MIME mode!).
*/
#if MIME8TO7
if (bitset(MM_MIME8BIT, MimeMode) &&
bitset(EF_HAS8BIT, e->e_flags) &&
!bitset(EF_DONT_MIME, e->e_flags) &&
!bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
!bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
hvalue("MIME-Version", e->e_header) == NULL)
{
putline("MIME-Version: 1.0", mci);
if (hvalue("Content-Type", e->e_header) == NULL)
{
snprintf(obuf, sizeof obuf,
"Content-Type: text/plain; charset=%s",
defcharset(e));
putline(obuf, mci);
}
if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
putline("Content-Transfer-Encoding: 8bit", mci);
}
#endif /* MIME8TO7 */
}
/*
** PUT_VANILLA_HEADER -- output a fairly ordinary header
**
** Parameters:
** h -- the structure describing this header
** v -- the value of this header
** mci -- the connection info for output
**
** Returns:
** none.
*/
static void
put_vanilla_header(h, v, mci)
HDR *h;
char *v;
MCI *mci;
{
register char *nlp;
register char *obp;
int putflags;
char obuf[MAXLINE];
putflags = PXLF_HEADER;
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
(void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
obp = obuf + strlen(obuf);
while ((nlp = strchr(v, '\n')) != NULL)
{
int l;
l = nlp - v;
if (SPACELEFT(obuf, obp) - 1 < (size_t)l)
l = SPACELEFT(obuf, obp) - 1;
snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
putxline(obuf, strlen(obuf), mci, putflags);
v += l + 1;
obp = obuf;
if (*v != ' ' && *v != '\t')
*obp++ = ' ';
}
snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
(int) sizeof obuf - (obp - obuf) - 1, v);
putxline(obuf, strlen(obuf), mci, putflags);
}
/*
** COMMAIZE -- output a header field, making a comma-translated list.
**
** Parameters:
** h -- the header field to output.
** p -- the value to put in it.
** oldstyle -- TRUE if this is an old style header.
** mci -- the connection information.
** e -- the envelope containing the message.
**
** Returns:
** none.
**
** Side Effects:
** outputs "p" to file "fp".
*/
void
commaize(h, p, oldstyle, mci, e)
register HDR *h;
register char *p;
bool oldstyle;
register MCI *mci;
register ENVELOPE *e;
{
register char *obp;
int opos;
int omax;
bool firstone = TRUE;
int putflags = PXLF_HEADER;
char obuf[MAXLINE + 3];
/*
** Output the address list translated by the
** mailer and with commas.
*/
if (tTd(14, 2))
dprintf("commaize(%s: %s)\n", h->h_field, p);
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
obp = obuf;
(void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
opos = strlen(h->h_field) + 2;
if (opos > 202)
opos = 202;
obp += opos;
omax = mci->mci_mailer->m_linelimit - 2;
if (omax < 0 || omax > 78)
omax = 78;
/*
** Run through the list of values.
*/
while (*p != '\0')
{
register char *name;
register int c;
char savechar;
int flags;
auto int status;
/*
** Find the end of the name. New style names
** end with a comma, old style names end with
** a space character. However, spaces do not
** necessarily delimit an old-style name -- at
** signs mean keep going.
*/
/* find end of name */
while ((isascii(*p) && isspace(*p)) || *p == ',')
p++;
name = p;
for (;;)
{
auto char *oldp;
char pvpbuf[PSBUFSIZE];
(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
sizeof pvpbuf, &oldp, NULL);
p = oldp;
/* look to see if we have an at sign */
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
if (*p != '@')
{
p = oldp;
break;
}
p += *p == '@' ? 1 : 2;
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
}
/* at the end of one complete name */
/* strip off trailing white space */
while (p >= name &&
((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
p--;
if (++p == name)
continue;
savechar = *p;
*p = '\0';
/* translate the name to be relative */
flags = RF_HEADERADDR|RF_ADDDOMAIN;
if (bitset(H_FROM, h->h_flags))
flags |= RF_SENDERADDR;
#if USERDB
else if (e->e_from.q_mailer != NULL &&
bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
{
char *q;
q = udbsender(name);
if (q != NULL)
name = q;
}
#endif /* USERDB */
status = EX_OK;
name = remotename(name, mci->mci_mailer, flags, &status, e);
if (*name == '\0')
{
*p = savechar;
continue;
}
name = denlstring(name, FALSE, TRUE);
/*
** record data progress so DNS timeouts
** don't cause DATA timeouts
*/
DataProgress = TRUE;
/* output the name with nice formatting */
opos += strlen(name);
if (!firstone)
opos += 2;
if (opos > omax && !firstone)
{
snprintf(obp, SPACELEFT(obuf, obp), ",\n");
putxline(obuf, strlen(obuf), mci, putflags);
obp = obuf;
(void) strlcpy(obp, " ", sizeof obp);
opos = strlen(obp);
obp += opos;
opos += strlen(name);
}
else if (!firstone)
{
snprintf(obp, SPACELEFT(obuf, obp), ", ");
obp += 2;
}
while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
*obp++ = c;
firstone = FALSE;
*p = savechar;
}
*obp = '\0';
putxline(obuf, strlen(obuf), mci, putflags);
}
/*
** COPYHEADER -- copy header list
**
** This routine is the equivalent of newstr for header lists
**
** Parameters:
** header -- list of header structures to copy.
**
** Returns:
** a copy of 'header'.
**
** Side Effects:
** none.
*/
HDR *
copyheader(header)
register HDR *header;
{
register HDR *newhdr;
HDR *ret;
register HDR **tail = &ret;
while (header != NULL)
{
newhdr = (HDR *) xalloc(sizeof *newhdr);
STRUCTCOPY(*header, *newhdr);
*tail = newhdr;
tail = &newhdr->h_link;
header = header->h_link;
}
*tail = NULL;
return ret;
}
/*
** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
**
** Run through all of the parameters of a MIME header and
** possibly truncate and rebalance the parameter according
** to MaxMimeFieldLength.
**
** Parameters:
** string -- the full header
**
** Returns:
** TRUE if the header was modified, FALSE otherwise
**
** Side Effects:
** string modified in place
*/
static bool
fix_mime_header(string)
char *string;
{
bool modified = FALSE;
char *begin = string;
char *end;
if (string == NULL || *string == '\0')
return FALSE;
/* Split on each ';' */
while ((end = find_character(begin, ';')) != NULL)
{
char save = *end;
char *bp;
*end = '\0';
/* Shorten individual parameter */
if (shorten_rfc822_string(begin, MaxMimeFieldLength))
modified = TRUE;
/* Collapse the possibly shortened string with rest */
bp = begin + strlen(begin);
if (bp != end)
{
char *ep = end;
*end = save;
end = bp;
/* copy character by character due to overlap */
while (*ep != '\0')
*bp++ = *ep++;
*bp = '\0';
}
else
*end = save;
if (*end == '\0')
break;
/* Move past ';' */
begin = end + 1;
}
return modified;
}
Index: head/contrib/sendmail/src/mailq.1
===================================================================
--- head/contrib/sendmail/src/mailq.1 (revision 66496)
+++ head/contrib/sendmail/src/mailq.1 (revision 66497)
@@ -1,78 +1,78 @@
-.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
.\" Copyright (c) 1985, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" By using this file, you agree to the terms and conditions set
.\" forth in the LICENSE file which can be found at the top level of
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: mailq.1,v 8.14.28.1 2000/07/14 05:07:01 gshapiro Exp $
+.\" $Id: mailq.1,v 8.14.28.2 2000/09/17 17:04:27 gshapiro Exp $
.\"
.\" $FreeBSD$
.\"
-.TH MAILQ 1 "$Date: 2000/07/14 05:07:01 $"
+.TH MAILQ 1 "$Date: 2000/09/17 17:04:27 $"
.SH NAME
.B mailq
\- print the mail queue
.SH SYNOPSIS
.B mailq
.RB [ \-v ]
.SH DESCRIPTION
.B Mailq
prints a summary of the mail messages queued for future delivery.
.PP
The first line printed for each message
shows the internal identifier used on this host
for the message with a possible status character,
the size of the message in bytes,
the date and time the message was accepted into the queue,
and the envelope sender of the message.
The second line shows the error message that caused this message
to be retained in the queue;
it will not be present if the message is being processed
for the first time.
The status characters are either
.B *
to indicate the job is being processed;
.B X
to indicate that the load is too high to process the job; and
.B -
to indicate that the job is too young to process.
The following lines show message recipients,
one per line.
.PP
The options are as follows:
.TP
.B \-v
Print verbose information.
This adds the priority of the message and
a single character indicator (``+'' or blank)
indicating whether a warning message has been sent
on the first line of the message.
Additionally, extra lines may be intermixed with the recipients
indicating the ``controlling user'' information;
this shows who will own any programs that are executed
on behalf of this message
and the name of the alias this command expanded from, if any.
.PP
The
.B mailq
utility exits 0 on success, and >0 if an error occurs.
.SH NOTES
.Nm Mailq
is identical to
.Dq Li "sendmail -bp" .
Most of the options which apply to
.Xr sendmail 8
also apply to
.Nm mailq .
.SH SEE ALSO
sendmail(8)
.SH HISTORY
The
.B mailq
command appeared in
4.0BSD.
Index: head/contrib/sendmail/src/savemail.c
===================================================================
--- head/contrib/sendmail/src/savemail.c (revision 66496)
+++ head/contrib/sendmail/src/savemail.c (revision 66497)
@@ -1,1612 +1,1614 @@
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
-static char id[] = "@(#)$Id: savemail.c,v 8.212.4.3 2000/06/13 07:16:26 gshapiro Exp $";
+static char id[] = "@(#)$Id: savemail.c,v 8.212.4.5 2000/08/22 22:46:00 gshapiro Exp $";
#endif /* ! lint */
/* $FreeBSD$ */
#include <sendmail.h>
static void errbody __P((MCI *, ENVELOPE *, char *));
static bool pruneroute __P((char *));
/*
** SAVEMAIL -- Save mail on error
**
** If mailing back errors, mail it back to the originator
** together with an error message; otherwise, just put it in
** dead.letter in the user's home directory (if he exists on
** this machine).
**
** Parameters:
** e -- the envelope containing the message in error.
** sendbody -- if TRUE, also send back the body of the
** message; otherwise just send the header.
**
** Returns:
** none
**
** Side Effects:
** Saves the letter, by writing or mailing it back to the
** sender, or by putting it in dead.letter in her home
** directory.
*/
/* defines for state machine */
#define ESM_REPORT 0 /* report to sender's terminal */
#define ESM_MAIL 1 /* mail back to sender */
#define ESM_QUIET 2 /* mail has already been returned */
#define ESM_DEADLETTER 3 /* save in ~/dead.letter */
#define ESM_POSTMASTER 4 /* return to postmaster */
#define ESM_DEADLETTERDROP 5 /* save in DeadLetterDrop */
#define ESM_PANIC 6 /* call loseqfile() */
#define ESM_DONE 7 /* message is successfully delivered */
void
savemail(e, sendbody)
register ENVELOPE *e;
bool sendbody;
{
register struct passwd *pw;
register FILE *fp;
int state;
auto ADDRESS *q = NULL;
register char *p;
MCI mcibuf;
int flags;
long sff;
char buf[MAXLINE + 1];
if (tTd(6, 1))
{
dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
ExitStat);
printaddr(&e->e_from, FALSE);
}
if (e->e_id == NULL)
{
/* can't return a message with no id */
return;
}
/*
** In the unhappy event we don't know who to return the mail
** to, make someone up.
*/
if (e->e_from.q_paddr == NULL)
{
e->e_sender = "Postmaster";
if (parseaddr(e->e_sender, &e->e_from,
RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
{
syserr("553 5.3.5 Cannot parse Postmaster!");
finis(TRUE, EX_SOFTWARE);
}
}
e->e_to = NULL;
/*
** Basic state machine.
**
** This machine runs through the following states:
**
** ESM_QUIET Errors have already been printed iff the
** sender is local.
** ESM_REPORT Report directly to the sender's terminal.
** ESM_MAIL Mail response to the sender.
** ESM_DEADLETTER Save response in ~/dead.letter.
** ESM_POSTMASTER Mail response to the postmaster.
** ESM_DEADLETTERDROP
** If DeadLetterDrop set, save it there.
** ESM_PANIC Save response anywhere possible.
*/
/* determine starting state */
switch (e->e_errormode)
{
case EM_WRITE:
state = ESM_REPORT;
break;
case EM_BERKNET:
case EM_MAIL:
state = ESM_MAIL;
break;
case EM_PRINT:
case '\0':
state = ESM_QUIET;
break;
case EM_QUIET:
/* no need to return anything at all */
return;
default:
syserr("554 5.3.0 savemail: bogus errormode x%x\n",
e->e_errormode);
state = ESM_MAIL;
break;
}
/* if this is already an error response, send to postmaster */
if (bitset(EF_RESPONSE, e->e_flags))
{
if (e->e_parent != NULL &&
bitset(EF_RESPONSE, e->e_parent->e_flags))
{
/* got an error sending a response -- can it */
return;
}
state = ESM_POSTMASTER;
}
while (state != ESM_DONE)
{
if (tTd(6, 5))
dprintf(" state %d\n", state);
switch (state)
{
case ESM_QUIET:
if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
state = ESM_DEADLETTER;
else
state = ESM_MAIL;
break;
case ESM_REPORT:
/*
** If the user is still logged in on the same terminal,
** then write the error messages back to hir (sic).
*/
p = ttypath();
if (p == NULL || freopen(p, "w", stdout) == NULL)
{
state = ESM_MAIL;
break;
}
expand("\201n", buf, sizeof buf, e);
printf("\r\nMessage from %s...\r\n", buf);
printf("Errors occurred while sending mail.\r\n");
if (e->e_xfp != NULL)
{
(void) bfrewind(e->e_xfp);
printf("Transcript follows:\r\n");
while (fgets(buf, sizeof buf, e->e_xfp) != NULL &&
!ferror(stdout))
(void) fputs(buf, stdout);
}
else
{
syserr("Cannot open %s", queuename(e, 'x'));
printf("Transcript of session is unavailable.\r\n");
}
printf("Original message will be saved in dead.letter.\r\n");
state = ESM_DEADLETTER;
break;
case ESM_MAIL:
/*
** If mailing back, do it.
** Throw away all further output. Don't alias,
** since this could cause loops, e.g., if joe
** mails to joe@x, and for some reason the network
** for @x is down, then the response gets sent to
** joe@x, which gives a response, etc. Also force
** the mail to be delivered even if a version of
** it has already been sent to the sender.
**
** If this is a configuration or local software
** error, send to the local postmaster as well,
** since the originator can't do anything
** about it anyway. Note that this is a full
** copy of the message (intentionally) so that
** the Postmaster can forward things along.
*/
if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
{
(void) sendtolist("postmaster",
NULLADDR, &e->e_errorqueue, 0, e);
}
if (!emptyaddr(&e->e_from))
{
char from[TOBUFSIZE];
if (strlen(e->e_from.q_paddr) >= sizeof from)
{
state = ESM_POSTMASTER;
break;
}
(void) strlcpy(from, e->e_from.q_paddr,
sizeof from);
if (!DontPruneRoutes && pruneroute(from))
{
ADDRESS *a;
for (a = e->e_errorqueue; a != NULL;
a = a->q_next)
{
if (sameaddr(a, &e->e_from))
a->q_state = QS_DUPLICATE;
}
}
(void) sendtolist(from, NULLADDR,
&e->e_errorqueue, 0, e);
}
/*
** Deliver a non-delivery report to the
** Postmaster-designate (not necessarily
** Postmaster). This does not include the
** body of the message, for privacy reasons.
** You really shouldn't need this.
*/
e->e_flags |= EF_PM_NOTIFY;
/* check to see if there are any good addresses */
for (q = e->e_errorqueue; q != NULL; q = q->q_next)
{
if (QS_IS_SENDABLE(q->q_state))
break;
}
if (q == NULL)
{
/* this is an error-error */
state = ESM_POSTMASTER;
break;
}
if (returntosender(e->e_message, e->e_errorqueue,
sendbody ? RTSF_SEND_BODY
: RTSF_NO_BODY,
e) == 0)
{
state = ESM_DONE;
break;
}
/* didn't work -- return to postmaster */
state = ESM_POSTMASTER;
break;
case ESM_POSTMASTER:
/*
** Similar to previous case, but to system postmaster.
*/
q = NULL;
expand(DoubleBounceAddr, buf, sizeof buf, e);
if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
{
syserr("553 5.3.0 cannot parse %s!", buf);
ExitStat = EX_SOFTWARE;
state = ESM_DEADLETTERDROP;
break;
}
flags = RTSF_PM_BOUNCE;
if (sendbody)
flags |= RTSF_SEND_BODY;
if (returntosender(e->e_message, q, flags, e) == 0)
{
state = ESM_DONE;
break;
}
/* didn't work -- last resort */
state = ESM_DEADLETTERDROP;
break;
case ESM_DEADLETTER:
/*
** Save the message in dead.letter.
** If we weren't mailing back, and the user is
** local, we should save the message in
** ~/dead.letter so that the poor person doesn't
** have to type it over again -- and we all know
** what poor typists UNIX users are.
*/
p = NULL;
if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
{
if (e->e_from.q_home != NULL)
p = e->e_from.q_home;
- else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
+ else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL &&
+ *pw->pw_dir != '\0')
p = pw->pw_dir;
}
if (p == NULL || e->e_dfp == NULL)
{
/* no local directory or no data file */
state = ESM_MAIL;
break;
}
/* we have a home directory; write dead.letter */
define('z', p, e);
/* get the sender for the UnixFromLine */
p = macvalue('g', e);
define('g', e->e_sender, e);
expand("\201z/dead.letter", buf, sizeof buf, e);
sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
if (RealUid == 0)
sff |= SFF_ROOTOK;
e->e_to = buf;
if (writable(buf, NULL, sff) &&
mailfile(buf, FileMailer, NULL, sff, e) == EX_OK)
{
int oldverb = Verbose;
if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
Verbose = 1;
if (Verbose > 0)
message("Saved message in %s", buf);
Verbose = oldverb;
define('g', p, e);
state = ESM_DONE;
break;
}
define('g', p, e);
state = ESM_MAIL;
break;
case ESM_DEADLETTERDROP:
/*
** Log the mail in DeadLetterDrop file.
*/
if (e->e_class < 0)
{
state = ESM_DONE;
break;
}
if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
DeadLetterDrop == NULL ||
DeadLetterDrop[0] == '\0')
{
state = ESM_PANIC;
break;
}
sff = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
if (!writable(DeadLetterDrop, NULL, sff) ||
(fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
FileMode, sff)) == NULL)
{
state = ESM_PANIC;
break;
}
memset(&mcibuf, '\0', sizeof mcibuf);
mcibuf.mci_out = fp;
mcibuf.mci_mailer = FileMailer;
if (bitnset(M_7BITS, FileMailer->m_flags))
mcibuf.mci_flags |= MCIF_7BIT;
/* get the sender for the UnixFromLine */
p = macvalue('g', e);
define('g', e->e_sender, e);
putfromline(&mcibuf, e);
(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
(*e->e_putbody)(&mcibuf, e, NULL);
putline("\n", &mcibuf);
(void) fflush(fp);
if (ferror(fp) ||
fclose(fp) < 0)
state = ESM_PANIC;
else
{
int oldverb = Verbose;
if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
Verbose = 1;
if (Verbose > 0)
message("Saved message in %s",
DeadLetterDrop);
Verbose = oldverb;
if (LogLevel > 3)
sm_syslog(LOG_NOTICE, e->e_id,
"Saved message in %s",
DeadLetterDrop);
state = ESM_DONE;
}
define('g', p, e);
break;
default:
syserr("554 5.3.5 savemail: unknown state %d", state);
/* FALLTHROUGH */
case ESM_PANIC:
/* leave the locked queue & transcript files around */
loseqfile(e, "savemail panic");
+ errno = 0;
syserr("!554 savemail: cannot save rejected email anywhere");
}
}
}
/*
** RETURNTOSENDER -- return a message to the sender with an error.
**
** Parameters:
** msg -- the explanatory message.
** returnq -- the queue of people to send the message to.
** flags -- flags tweaking the operation:
** RTSF_SENDBODY -- include body of message (otherwise
** just send the header).
** RTSF_PMBOUNCE -- this is a postmaster bounce.
** e -- the current envelope.
**
** Returns:
** zero -- if everything went ok.
** else -- some error.
**
** Side Effects:
** Returns the current message to the sender via
** mail.
*/
#define MAXRETURNS 6 /* max depth of returning messages */
#define ERRORFUDGE 100 /* nominal size of error message text */
int
returntosender(msg, returnq, flags, e)
char *msg;
ADDRESS *returnq;
int flags;
register ENVELOPE *e;
{
register ENVELOPE *ee;
ENVELOPE *oldcur = CurEnv;
ENVELOPE errenvelope;
static int returndepth = 0;
register ADDRESS *q;
char *p;
char buf[MAXNAME + 1];
if (returnq == NULL)
return -1;
if (msg == NULL)
msg = "Unable to deliver mail";
if (tTd(6, 1))
{
dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=",
msg, returndepth, (u_long) e);
printaddr(returnq, TRUE);
if (tTd(6, 20))
{
dprintf("Sendq=");
printaddr(e->e_sendqueue, TRUE);
}
}
if (++returndepth >= MAXRETURNS)
{
if (returndepth != MAXRETURNS)
syserr("554 5.3.0 returntosender: infinite recursion on %s",
returnq->q_paddr);
/* don't "unrecurse" and fake a clean exit */
/* returndepth--; */
return 0;
}
define('g', e->e_sender, e);
define('u', NULL, e);
/* initialize error envelope */
ee = newenvelope(&errenvelope, e);
define('a', "\201b", ee);
define('r', "", ee);
define('s', "localhost", ee);
define('_', "localhost", ee);
#if SASL
define(macid("{auth_type}", NULL), "", ee);
define(macid("{auth_authen}", NULL), "", ee);
define(macid("{auth_author}", NULL), "", ee);
define(macid("{auth_ssf}", NULL), "", ee);
#endif /* SASL */
#if STARTTLS
define(macid("{cert_issuer}", NULL), "", ee);
define(macid("{cert_subject}", NULL), "", ee);
define(macid("{cipher_bits}", NULL), "", ee);
define(macid("{cipher}", NULL), "", ee);
define(macid("{tls_version}", NULL), "", ee);
define(macid("{verify}", NULL), "", ee);
# if _FFR_TLS_1
define(macid("{alg_bits}", NULL), "", ee);
define(macid("{cn_issuer}", NULL), "", ee);
define(macid("{cn_subject}", NULL), "", ee);
# endif /* _FFR_TLS_1 */
#endif /* STARTTLS */
ee->e_puthdr = putheader;
ee->e_putbody = errbody;
ee->e_flags |= EF_RESPONSE|EF_METOO;
if (!bitset(EF_OLDSTYLE, e->e_flags))
ee->e_flags &= ~EF_OLDSTYLE;
if (bitset(EF_DONT_MIME, e->e_flags))
{
ee->e_flags |= EF_DONT_MIME;
/*
** If we can't convert to MIME and we don't pass
** 8-bit, we can't send the body.
*/
if (bitset(EF_HAS8BIT, e->e_flags) &&
!bitset(MM_PASS8BIT, MimeMode))
flags &= ~RTSF_SEND_BODY;
}
ee->e_sendqueue = returnq;
ee->e_msgsize = ERRORFUDGE;
if (bitset(RTSF_SEND_BODY, flags) &&
!bitset(PRIV_NOBODYRETN, PrivacyFlags))
ee->e_msgsize += e->e_msgsize;
else
ee->e_flags |= EF_NO_BODY_RETN;
initsys(ee);
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
#endif /* NAMED_BIND */
for (q = returnq; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state))
continue;
q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
q->q_flags |= QPINGONFAILURE;
if (!QS_IS_DEAD(q->q_state))
ee->e_nrcpts++;
if (q->q_alias == NULL)
addheader("To", q->q_paddr, 0, &ee->e_header);
}
if (LogLevel > 5)
{
if (bitset(EF_RESPONSE, e->e_flags))
p = "return to sender";
else if (bitset(EF_WARNING, e->e_flags))
p = "sender notify";
else if (bitset(RTSF_PM_BOUNCE, flags))
p = "postmaster notify";
else
p = "DSN";
sm_syslog(LOG_INFO, e->e_id,
"%s: %s: %s",
ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
}
if (SendMIMEErrors)
{
addheader("MIME-Version", "1.0", 0, &ee->e_header);
(void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
ee->e_id, (long) curtime(), MyHostName);
ee->e_msgboundary = newstr(buf);
(void) snprintf(buf, sizeof buf,
#if DSN
"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
#else /* DSN */
"multipart/mixed; boundary=\"%s\"",
#endif /* DSN */
ee->e_msgboundary);
addheader("Content-Type", buf, 0, &ee->e_header);
p = hvalue("Content-Transfer-Encoding", e->e_header);
if (p != NULL && strcasecmp(p, "binary") != 0)
p = NULL;
if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
p = "8bit";
if (p != NULL)
addheader("Content-Transfer-Encoding",
p, 0, &ee->e_header);
}
if (strncmp(msg, "Warning:", 8) == 0)
{
addheader("Subject", msg, 0, &ee->e_header);
p = "warning-timeout";
}
else if (strncmp(msg, "Postmaster warning:", 19) == 0)
{
addheader("Subject", msg, 0, &ee->e_header);
p = "postmaster-warning";
}
else if (strcmp(msg, "Return receipt") == 0)
{
addheader("Subject", msg, 0, &ee->e_header);
p = "return-receipt";
}
else if (bitset(RTSF_PM_BOUNCE, flags))
{
snprintf(buf, sizeof buf,
"Postmaster notify: see transcript for details");
addheader("Subject", buf, 0, &ee->e_header);
p = "postmaster-notification";
}
else
{
snprintf(buf, sizeof buf,
"Returned mail: see transcript for details");
addheader("Subject", buf, 0, &ee->e_header);
p = "failure";
}
(void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
addheader("Auto-Submitted", buf, 0, &ee->e_header);
/* fake up an address header for the from person */
expand("\201n", buf, sizeof buf, e);
if (parseaddr(buf, &ee->e_from,
RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
{
syserr("553 5.3.5 Can't parse myself!");
ExitStat = EX_SOFTWARE;
returndepth--;
return -1;
}
ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
ee->e_from.q_flags |= QPINGONFAILURE;
ee->e_sender = ee->e_from.q_paddr;
/* push state into submessage */
CurEnv = ee;
define('f', "\201n", ee);
define('x', "Mail Delivery Subsystem", ee);
eatheader(ee, TRUE);
/* mark statistics */
markstats(ee, NULLADDR, FALSE);
/* actually deliver the error message */
sendall(ee, SM_DELIVER);
/* restore state */
dropenvelope(ee, TRUE);
CurEnv = oldcur;
returndepth--;
/* check for delivery errors */
if (ee->e_parent == NULL ||
!bitset(EF_RESPONSE, ee->e_parent->e_flags))
return 0;
for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_ATTEMPTED(q->q_state))
return 0;
}
return -1;
}
/*
** ERRBODY -- output the body of an error message.
**
** Typically this is a copy of the transcript plus a copy of the
** original offending message.
**
** Parameters:
** mci -- the mailer connection information.
** e -- the envelope we are working in.
** separator -- any possible MIME separator.
**
** Returns:
** none
**
** Side Effects:
** Outputs the body of an error message.
*/
/* ARGSUSED2 */
static void
errbody(mci, e, separator)
register MCI *mci;
register ENVELOPE *e;
char *separator;
{
bool printheader;
bool sendbody;
bool pm_notify;
int save_errno;
register FILE *xfile;
char *p;
register ADDRESS *q = NULL;
char buf[MAXLINE];
if (bitset(MCIF_INHEADER, mci->mci_flags))
{
putline("", mci);
mci->mci_flags &= ~MCIF_INHEADER;
}
if (e->e_parent == NULL)
{
syserr("errbody: null parent");
putline(" ----- Original message lost -----\n", mci);
return;
}
/*
** Output MIME header.
*/
if (e->e_msgboundary != NULL)
{
putline("This is a MIME-encapsulated message", mci);
putline("", mci);
(void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
putline(buf, mci);
putline("", mci);
}
/*
** Output introductory information.
*/
pm_notify = FALSE;
p = hvalue("subject", e->e_header);
if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
pm_notify = TRUE;
else
{
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state))
break;
}
}
if (!pm_notify && q == NULL &&
!bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
{
putline(" **********************************************",
mci);
putline(" ** THIS IS A WARNING MESSAGE ONLY **",
mci);
putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
mci);
putline(" **********************************************",
mci);
putline("", mci);
}
snprintf(buf, sizeof buf, "The original message was received at %s",
arpadate(ctime(&e->e_parent->e_ctime)));
putline(buf, mci);
expand("from \201_", buf, sizeof buf, e->e_parent);
putline(buf, mci);
/* include id in postmaster copies */
if (pm_notify && e->e_parent->e_id != NULL)
{
snprintf(buf, sizeof buf, "with id %s", e->e_parent->e_id);
putline(buf, mci);
}
putline("", mci);
/*
** Output error message header (if specified and available).
*/
if (ErrMsgFile != NULL &&
!bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
{
if (*ErrMsgFile == '/')
{
long sff = SFF_ROOTOK|SFF_REGONLY;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
if (!bitnset(DBS_ERRORHEADERINUNSAFEDIRPATH,
DontBlameSendmail))
sff |= SFF_SAFEDIRPATH;
xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
if (xfile != NULL)
{
while (fgets(buf, sizeof buf, xfile) != NULL)
{
translate_dollars(buf);
expand(buf, buf, sizeof buf, e);
putline(buf, mci);
}
(void) fclose(xfile);
putline("\n", mci);
}
}
else
{
expand(ErrMsgFile, buf, sizeof buf, e);
putline(buf, mci);
putline("", mci);
}
}
/*
** Output message introduction
*/
printheader = TRUE;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (!QS_IS_BADADDR(q->q_state) ||
!bitset(QPINGONFAILURE, q->q_flags))
continue;
if (printheader)
{
putline(" ----- The following addresses had permanent fatal errors -----",
mci);
printheader = FALSE;
}
snprintf(buf, sizeof buf, "%s",
shortenstring(q->q_paddr, MAXSHORTSTR));
putline(buf, mci);
if (q->q_rstatus != NULL)
{
snprintf(buf, sizeof buf, " (reason: %s)",
shortenstring(exitstat(q->q_rstatus),
MAXSHORTSTR));
putline(buf, mci);
}
if (q->q_alias != NULL)
{
snprintf(buf, sizeof buf, " (expanded from: %s)",
shortenstring(q->q_alias->q_paddr,
MAXSHORTSTR));
putline(buf, mci);
}
}
if (!printheader)
putline("", mci);
printheader = TRUE;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state) ||
!bitset(QPRIMARY, q->q_flags) ||
!bitset(QDELAYED, q->q_flags))
continue;
if (printheader)
{
putline(" ----- The following addresses had transient non-fatal errors -----",
mci);
printheader = FALSE;
}
snprintf(buf, sizeof buf, "%s",
shortenstring(q->q_paddr, MAXSHORTSTR));
putline(buf, mci);
if (q->q_alias != NULL)
{
snprintf(buf, sizeof buf, " (expanded from: %s)",
shortenstring(q->q_alias->q_paddr,
MAXSHORTSTR));
putline(buf, mci);
}
}
if (!printheader)
putline("", mci);
printheader = TRUE;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state) ||
!bitset(QPRIMARY, q->q_flags) ||
bitset(QDELAYED, q->q_flags))
continue;
else if (!bitset(QPINGONSUCCESS, q->q_flags))
continue;
else if (bitset(QRELAYED, q->q_flags))
p = "relayed to non-DSN-aware mailer";
else if (bitset(QDELIVERED, q->q_flags))
{
if (bitset(QEXPANDED, q->q_flags))
p = "successfully delivered to mailing list";
else
p = "successfully delivered to mailbox";
}
else if (bitset(QEXPANDED, q->q_flags))
p = "expanded by alias";
else
continue;
if (printheader)
{
putline(" ----- The following addresses had successful delivery notifications -----",
mci);
printheader = FALSE;
}
snprintf(buf, sizeof buf, "%s (%s)",
shortenstring(q->q_paddr, MAXSHORTSTR), p);
putline(buf, mci);
if (q->q_alias != NULL)
{
snprintf(buf, sizeof buf, " (expanded from: %s)",
shortenstring(q->q_alias->q_paddr,
MAXSHORTSTR));
putline(buf, mci);
}
}
if (!printheader)
putline("", mci);
/*
** Output transcript of errors
*/
(void) fflush(stdout);
if (e->e_parent->e_xfp == NULL)
{
putline(" ----- Transcript of session is unavailable -----\n",
mci);
}
else
{
printheader = TRUE;
(void) bfrewind(e->e_parent->e_xfp);
if (e->e_xfp != NULL)
(void) fflush(e->e_xfp);
while (fgets(buf, sizeof buf, e->e_parent->e_xfp) != NULL)
{
if (printheader)
putline(" ----- Transcript of session follows -----\n",
mci);
printheader = FALSE;
putline(buf, mci);
}
}
errno = 0;
#if DSN
/*
** Output machine-readable version.
*/
if (e->e_msgboundary != NULL)
{
putline("", mci);
(void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
putline(buf, mci);
putline("Content-Type: message/delivery-status", mci);
putline("", mci);
/*
** Output per-message information.
*/
/* original envelope id from MAIL FROM: line */
if (e->e_parent->e_envid != NULL)
{
(void) snprintf(buf, sizeof buf,
"Original-Envelope-Id: %.800s",
xuntextify(e->e_parent->e_envid));
putline(buf, mci);
}
/* Reporting-MTA: is us (required) */
(void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName);
putline(buf, mci);
/* DSN-Gateway: not relevant since we are not translating */
/* Received-From-MTA: shows where we got this message from */
if (RealHostName != NULL)
{
/* XXX use $s for type? */
if (e->e_parent->e_from.q_mailer == NULL ||
(p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
p = "dns";
(void) snprintf(buf, sizeof buf,
"Received-From-MTA: %s; %.800s",
p, RealHostName);
putline(buf, mci);
}
/* Arrival-Date: -- when it arrived here */
(void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
arpadate(ctime(&e->e_parent->e_ctime)));
putline(buf, mci);
/*
** Output per-address information.
*/
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
register ADDRESS *r;
char *action;
if (QS_IS_BADADDR(q->q_state))
action = "failed";
else if (!bitset(QPRIMARY, q->q_flags))
continue;
else if (bitset(QDELIVERED, q->q_flags))
{
if (bitset(QEXPANDED, q->q_flags))
action = "delivered (to mailing list)";
else
action = "delivered (to mailbox)";
}
else if (bitset(QRELAYED, q->q_flags))
action = "relayed (to non-DSN-aware mailer)";
else if (bitset(QEXPANDED, q->q_flags))
action = "expanded (to multi-recipient alias)";
else if (bitset(QDELAYED, q->q_flags))
action = "delayed";
else
continue;
putline("", mci);
/* Original-Recipient: -- passed from on high */
if (q->q_orcpt != NULL)
{
(void) snprintf(buf, sizeof buf,
"Original-Recipient: %.800s",
q->q_orcpt);
putline(buf, mci);
}
/* Final-Recipient: -- the name from the RCPT command */
p = e->e_parent->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
for (r = q; r->q_alias != NULL; r = r->q_alias)
continue;
if (strcasecmp(p, "rfc822") != 0)
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
r->q_mailer->m_addrtype,
r->q_user);
}
else if (strchr(r->q_user, '@') != NULL)
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
p, r->q_user);
}
else if (strchr(r->q_paddr, '@') != NULL)
{
char *qp;
bool b;
qp = r->q_paddr;
/* strip brackets from address */
b = FALSE;
if (*qp == '<')
{
b = qp[strlen(qp) - 1] == '>';
if (b)
qp[strlen(qp) - 1] = '\0';
qp++;
}
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
p, qp);
/* undo damage */
if (b)
qp[strlen(qp)] = '>';
}
else
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.700s@%.100s",
p, r->q_user, MyHostName);
}
putline(buf, mci);
/* X-Actual-Recipient: -- the real problem address */
if (r != q && q->q_user[0] != '\0')
{
if (q->q_mailer != NULL &&
q->q_mailer->m_addrtype != NULL)
p = q->q_mailer->m_addrtype;
else
p = "rfc822";
if (strcasecmp(p, "rfc822") == 0 &&
strchr(q->q_user, '@') == NULL)
{
(void) snprintf(buf, sizeof buf,
"X-Actual-Recipient: %s; %.700s@%.100s",
p, q->q_user,
MyHostName);
}
else
{
(void) snprintf(buf, sizeof buf,
"X-Actual-Recipient: %s; %.800s",
p, q->q_user);
}
putline(buf, mci);
}
/* Action: -- what happened? */
snprintf(buf, sizeof buf, "Action: %s", action);
putline(buf, mci);
/* Status: -- what _really_ happened? */
if (q->q_status != NULL)
p = q->q_status;
else if (QS_IS_BADADDR(q->q_state))
p = "5.0.0";
else if (QS_IS_QUEUEUP(q->q_state))
p = "4.0.0";
else
p = "2.0.0";
snprintf(buf, sizeof buf, "Status: %s", p);
putline(buf, mci);
/* Remote-MTA: -- who was I talking to? */
if (q->q_statmta != NULL)
{
if (q->q_mailer == NULL ||
(p = q->q_mailer->m_mtatype) == NULL)
p = "dns";
(void) snprintf(buf, sizeof buf,
"Remote-MTA: %s; %.800s",
p, q->q_statmta);
p = &buf[strlen(buf) - 1];
if (*p == '.')
*p = '\0';
putline(buf, mci);
}
/* Diagnostic-Code: -- actual result from other end */
if (q->q_rstatus != NULL)
{
p = q->q_mailer->m_diagtype;
if (p == NULL)
p = "smtp";
(void) snprintf(buf, sizeof buf,
"Diagnostic-Code: %s; %.800s",
p, q->q_rstatus);
putline(buf, mci);
}
/* Last-Attempt-Date: -- fine granularity */
if (q->q_statdate == (time_t) 0L)
q->q_statdate = curtime();
(void) snprintf(buf, sizeof buf,
"Last-Attempt-Date: %s",
arpadate(ctime(&q->q_statdate)));
putline(buf, mci);
/* Will-Retry-Until: -- for delayed messages only */
if (QS_IS_QUEUEUP(q->q_state))
{
time_t xdate;
xdate = e->e_parent->e_ctime +
TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
snprintf(buf, sizeof buf,
"Will-Retry-Until: %s",
arpadate(ctime(&xdate)));
putline(buf, mci);
}
}
}
#endif /* DSN */
/*
** Output text of original message
*/
putline("", mci);
if (bitset(EF_HAS_DF, e->e_parent->e_flags))
{
sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
!bitset(EF_NO_BODY_RETN, e->e_flags);
if (e->e_msgboundary == NULL)
{
if (sendbody)
putline(" ----- Original message follows -----\n", mci);
else
putline(" ----- Message header follows -----\n", mci);
}
else
{
(void) snprintf(buf, sizeof buf, "--%s",
e->e_msgboundary);
putline(buf, mci);
(void) snprintf(buf, sizeof buf, "Content-Type: %s",
sendbody ? "message/rfc822"
: "text/rfc822-headers");
putline(buf, mci);
p = hvalue("Content-Transfer-Encoding",
e->e_parent->e_header);
if (p != NULL && strcasecmp(p, "binary") != 0)
p = NULL;
if (p == NULL &&
bitset(EF_HAS8BIT, e->e_parent->e_flags))
p = "8bit";
if (p != NULL)
{
(void) snprintf(buf, sizeof buf,
"Content-Transfer-Encoding: %s",
p);
putline(buf, mci);
}
}
putline("", mci);
save_errno = errno;
putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
errno = save_errno;
if (sendbody)
putbody(mci, e->e_parent, e->e_msgboundary);
else if (e->e_msgboundary == NULL)
{
putline("", mci);
putline(" ----- Message body suppressed -----", mci);
}
}
else if (e->e_msgboundary == NULL)
{
putline(" ----- No message was collected -----\n", mci);
}
if (e->e_msgboundary != NULL)
{
putline("", mci);
(void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
putline(buf, mci);
}
putline("", mci);
(void) fflush(mci->mci_out);
/*
** Cleanup and exit
*/
if (errno != 0)
syserr("errbody: I/O error");
}
/*
** SMTPTODSN -- convert SMTP to DSN status code
**
** Parameters:
** smtpstat -- the smtp status code (e.g., 550).
**
** Returns:
** The DSN version of the status code.
*/
char *
smtptodsn(smtpstat)
int smtpstat;
{
if (smtpstat < 0)
return "4.4.2";
switch (smtpstat)
{
case 450: /* Req mail action not taken: mailbox unavailable */
return "4.2.0";
case 451: /* Req action aborted: local error in processing */
return "4.3.0";
case 452: /* Req action not taken: insufficient sys storage */
return "4.3.1";
case 500: /* Syntax error, command unrecognized */
return "5.5.2";
case 501: /* Syntax error in parameters or arguments */
return "5.5.4";
case 502: /* Command not implemented */
return "5.5.1";
case 503: /* Bad sequence of commands */
return "5.5.1";
case 504: /* Command parameter not implemented */
return "5.5.4";
case 550: /* Req mail action not taken: mailbox unavailable */
return "5.2.0";
case 551: /* User not local; please try <...> */
return "5.1.6";
case 552: /* Req mail action aborted: exceeded storage alloc */
return "5.2.2";
case 553: /* Req action not taken: mailbox name not allowed */
return "5.1.0";
case 554: /* Transaction failed */
return "5.0.0";
}
if ((smtpstat / 100) == 2)
return "2.0.0";
if ((smtpstat / 100) == 4)
return "4.0.0";
return "5.0.0";
}
/*
** XTEXTIFY -- take regular text and turn it into DSN-style xtext
**
** Parameters:
** t -- the text to convert.
** taboo -- additional characters that must be encoded.
**
** Returns:
** The xtext-ified version of the same string.
*/
char *
xtextify(t, taboo)
register char *t;
char *taboo;
{
register char *p;
int l;
int nbogus;
static char *bp = NULL;
static int bplen = 0;
if (taboo == NULL)
taboo = "";
/* figure out how long this xtext will have to be */
nbogus = l = 0;
for (p = t; *p != '\0'; p++)
{
register int c = (*p & 0xff);
/* ASCII dependence here -- this is the way the spec words it */
if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
strchr(taboo, c) != NULL)
nbogus++;
l++;
}
if (nbogus == 0)
return t;
l += nbogus * 2 + 1;
/* now allocate space if necessary for the new string */
if (l > bplen)
{
if (bp != NULL)
free(bp);
bp = xalloc(l);
bplen = l;
}
/* ok, copy the text with byte expansion */
for (p = bp; *t != '\0'; )
{
register int c = (*t++ & 0xff);
/* ASCII dependence here -- this is the way the spec words it */
if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
strchr(taboo, c) != NULL)
{
*p++ = '+';
*p++ = "0123456789ABCDEF"[c >> 4];
*p++ = "0123456789ABCDEF"[c & 0xf];
}
else
*p++ = c;
}
*p = '\0';
return bp;
}
/*
** XUNTEXTIFY -- take xtext and turn it into plain text
**
** Parameters:
** t -- the xtextified text.
**
** Returns:
** The decoded text. No attempt is made to deal with
** null strings in the resulting text.
*/
char *
xuntextify(t)
register char *t;
{
register char *p;
int l;
static char *bp = NULL;
static int bplen = 0;
/* heuristic -- if no plus sign, just return the input */
if (strchr(t, '+') == NULL)
return t;
/* xtext is always longer than decoded text */
l = strlen(t);
if (l > bplen)
{
if (bp != NULL)
free(bp);
bp = xalloc(l);
bplen = l;
}
/* ok, copy the text with byte compression */
for (p = bp; *t != '\0'; t++)
{
register int c = *t & 0xff;
if (c != '+')
{
*p++ = c;
continue;
}
c = *++t & 0xff;
if (!isascii(c) || !isxdigit(c))
{
/* error -- first digit is not hex */
usrerr("bogus xtext: +%c", c);
t--;
continue;
}
if (isdigit(c))
c -= '0';
else if (isupper(c))
c -= 'A' - 10;
else
c -= 'a' - 10;
*p = c << 4;
c = *++t & 0xff;
if (!isascii(c) || !isxdigit(c))
{
/* error -- second digit is not hex */
usrerr("bogus xtext: +%x%c", *p >> 4, c);
t--;
continue;
}
if (isdigit(c))
c -= '0';
else if (isupper(c))
c -= 'A' - 10;
else
c -= 'a' - 10;
*p++ |= c;
}
*p = '\0';
return bp;
}
/*
** XTEXTOK -- check if a string is legal xtext
**
** Xtext is used in Delivery Status Notifications. The spec was
** taken from RFC 1891, ``SMTP Service Extension for Delivery
** Status Notifications''.
**
** Parameters:
** s -- the string to check.
**
** Returns:
** TRUE -- if 's' is legal xtext.
** FALSE -- if it has any illegal characters in it.
*/
bool
xtextok(s)
char *s;
{
int c;
while ((c = *s++) != '\0')
{
if (c == '+')
{
c = *s++;
if (!isascii(c) || !isxdigit(c))
return FALSE;
c = *s++;
if (!isascii(c) || !isxdigit(c))
return FALSE;
}
else if (c < '!' || c > '~' || c == '=')
return FALSE;
}
return TRUE;
}
/*
** PRUNEROUTE -- prune an RFC-822 source route
**
** Trims down a source route to the last internet-registered hop.
** This is encouraged by RFC 1123 section 5.3.3.
**
** Parameters:
** addr -- the address
**
** Returns:
** TRUE -- address was modified
** FALSE -- address could not be pruned
**
** Side Effects:
** modifies addr in-place
*/
static bool
pruneroute(addr)
char *addr;
{
#if NAMED_BIND
char *start, *at, *comma;
char c;
int rcode;
int i;
char hostbuf[BUFSIZ];
char *mxhosts[MAXMXHOSTS + 1];
/* check to see if this is really a route-addr */
if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
return FALSE;
start = strchr(addr, ':');
at = strrchr(addr, '@');
if (start == NULL || at == NULL || at < start)
return FALSE;
/* slice off the angle brackets */
i = strlen(at + 1);
if (i >= (SIZE_T) sizeof hostbuf)
return FALSE;
(void) strlcpy(hostbuf, at + 1, sizeof hostbuf);
hostbuf[i - 1] = '\0';
while (start)
{
if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0)
{
(void) strlcpy(addr + 1, start + 1, strlen(addr) - 1);
return TRUE;
}
c = *start;
*start = '\0';
comma = strrchr(addr, ',');
if (comma != NULL && comma[1] == '@' &&
strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
(void) strlcpy(hostbuf, comma + 2, sizeof hostbuf);
else
comma = NULL;
*start = c;
start = comma;
}
#endif /* NAMED_BIND */
return FALSE;
}
Index: head/contrib/sendmail/src/sendmail.8
===================================================================
--- head/contrib/sendmail/src/sendmail.8 (revision 66496)
+++ head/contrib/sendmail/src/sendmail.8 (revision 66497)
@@ -1,687 +1,692 @@
.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" By using this file, you agree to the terms and conditions set
.\" forth in the LICENSE file which can be found at the top level of
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: sendmail.8,v 8.36 2000/02/01 05:49:57 gshapiro Exp $
+.\" $Id: sendmail.8,v 8.36.8.2 2000/09/07 21:14:00 ca Exp $
.\"
.\" $FreeBSD$
.\"
-.TH SENDMAIL 8 "$Date: 2000/02/01 05:49:57 $"
+.TH SENDMAIL 8 "$Date: 2000/09/07 21:14:00 $"
.SH NAME
.B sendmail
\- an electronic mail transport agent
.SH SYNOPSIS
.B sendmail
.RI [ flags "] [" "address ..." ]
.br
.B newaliases
.br
.B mailq
.RB [ \-v ]
.br
.B hoststat
.br
.B purgestat
.br
.B smtpd
.SH DESCRIPTION
.B Sendmail
sends a message to one or more
.I recipients,
routing the message over whatever networks
are necessary.
.B Sendmail
does internetwork forwarding as necessary
to deliver the message to the correct place.
.PP
.B Sendmail
is not intended as a user interface routine;
other programs provide user-friendly
front ends;
.B sendmail
is used only to deliver pre-formatted messages.
.PP
With no flags,
.B sendmail
reads its standard input
up to an end-of-file
or a line consisting only of a single dot
and sends a copy of the message found there
to all of the addresses listed.
It determines the network(s) to use
based on the syntax and contents of the addresses.
.PP
Local addresses are looked up in a file
and aliased appropriately.
Aliasing can be prevented by preceding the address
with a backslash.
Beginning with 8.10, the sender is included in any alias
expansions, e.g.,
if `john' sends to `group',
and `group' includes `john' in the expansion,
then the letter will also be delivered to `john'.
.SS Parameters
.TP
.BI \-B type
Set the body type to
.IR type .
Current legal values are
7BIT
or
8BITMIME.
.TP
.B \-ba
Go into
ARPANET
mode. All input lines must end with a CR-LF,
and all messages will be generated with a CR-LF at the end.
Also,
the ``From:'' and ``Sender:''
fields are examined for the name of the sender.
.TP
.B \-bd
Run as a daemon. This requires Berkeley
IPC.
.B Sendmail
will fork and run in background
listening on socket 25 for incoming
SMTP
connections.
This is normally run from
/etc/rc.
.TP
.B \-bD
Same as
.B \-bd
except runs in foreground.
.TP
.B \-bh
Print the persistent host status database.
.TP
.B \-bH
Purge expired entries from the persistent host status database.
.TP
.B \-bi
Initialize the alias database.
.TP
.B \-bm
Deliver mail in the usual way (default).
.TP
.B \-bp
Print a listing of the queue.
.TP
.B \-bs
Use the
SMTP
protocol as described in
RFC821
on standard input and output.
This flag implies all the operations of the
.B \-ba
flag that are compatible with
SMTP.
.TP
.B \-bt
Run in address test mode.
This mode reads addresses and shows the steps in parsing;
it is used for debugging configuration tables.
.TP
.B \-bv
Verify names only \- do not try to collect or deliver a message.
Verify mode is normally used for validating
users or mailing lists.
.TP
.BI \-C file
Use alternate configuration file.
.B Sendmail
refuses to run as root if an alternate configuration file is specified.
.TP
.BI \-d X
Set debugging value to
.IR X .
.ne 1i
.TP
.BI \-F fullname
Set the full name of the sender.
.TP
.BI \-f name
Sets the name of the ``from'' person
(i.e., the envelope sender of the mail).
This address may also be used in the From: header
if that header is missing during initial submission.
The envelope sender address is used as the recipient
for delivery status notifications
and may also appear in a Return-Path: header.
.B \-f
should only be used
by ``trusted'' users
(normally
.IR root ", " daemon ,
and
.IR network )
or if the person you are trying to become
is the same as the person you are.
Otherwise,
an X-Authentication-Warning header
will be added to the message.
.TP
+.BI \-G
+Relay (gateway) submission of a message,
+e.g., when
+.BR rmail
+calls
+.B sendmail .
+.TP
.BI \-h N
Set the hop count to
.IR N .
The hop count is incremented every time the mail is
processed.
When it reaches a limit,
the mail is returned with an error message,
the victim of an aliasing loop.
If not specified,
``Received:'' lines in the message are counted.
.TP
.B \-i
Ignore dots alone on lines by themselves in incoming messages.
This should be set if you are reading data from a file.
.TP
.BI "\-L " tag
Set the identifier used in syslog messages to the supplied
.IR tag .
.TP
.BI "\-N " dsn
Set delivery status notification conditions to
.IR dsn ,
which can be
`never'
for no notifications
or a comma separated list of the values
`failure'
to be notified if delivery failed,
`delay'
to be notified if delivery is delayed, and
`success'
to be notified when the message is successfully delivered.
.TP
.B \-n
Don't do aliasing.
.TP
\fB\-O\fP \fIoption\fR=\fIvalue\fR
Set option
.I option
to the specified
.IR value .
This form uses long names. See below for more details.
.TP
.BI \-o "x value"
Set option
.I x
to the specified
.IR value .
This form uses single character names only.
The short names are not described in this manual page;
see the
.I "Sendmail Installation and Operation Guide"
for details.
.TP
.BI \-p protocol
Set the name of the protocol used to receive the message.
This can be a simple protocol name such as ``UUCP''
or a protocol and hostname, such as ``UUCP:ucbvax''.
.TP
\fB\-q\fR[\fItime\fR]
Processed saved messages in the queue at given intervals.
If
.I time
is omitted, process the queue once.
.I Time
is given as a tagged number,
with
`s'
being seconds,
`m'
being minutes,
`h'
being hours,
`d'
being days,
and
`w'
being weeks.
For example,
`\-q1h30m'
or
`\-q90m'
would both set the timeout to one hour thirty minutes.
If
.I time
is specified,
.B sendmail
will run in the background.
This option can be used safely with
.BR \-bd .
.TP
.BI \-qI substr
Limit processed jobs to those containing
.I substr
as a substring of the queue id.
.TP
.BI \-qR substr
Limit processed jobs to those containing
.I substr
as a substring of one of the recipients.
.TP
.BI \-qS substr
Limit processed jobs to those containing
.I substr
as a substring of the sender.
.TP
.BI "\-R " return
Set the amount of the message to be returned
if the message bounces.
The
.I return
parameter can be
`full'
to return the entire message or
`hdrs'
to return only the headers.
In the latter case also local bounces return only the headers.
.TP
.BI \-r name
An alternate and obsolete form of the
.B \-f
flag.
.TP
.B \-t
Read message for recipients.
To:, Cc:, and Bcc: lines will be scanned for recipient addresses.
The Bcc: line will be deleted before transmission.
.TP
.B \-U
Initial (user) submission. This should
.I always
be set when called from a user agent such as
.B Mail
or
.B exmh
and
.I never
be set when called by a network delivery agent such as
.BR rmail .
.TP
.BI "\-V " envid
Set the original envelope id.
This is propagated across SMTP to servers that support DSNs
and is returned in DSN-compliant error messages.
.TP
.B \-v
Go into verbose mode.
Alias expansions will be announced, etc.
.TP
.BI "\-X " logfile
Log all traffic in and out of mailers in the indicated log file.
This should only be used as a last resort
for debugging mailer bugs.
It will log a lot of data very quickly.
.TP
.B \-\-
Stop processing command flags and use the rest of the arguments as
addresses.
.SS Options
There are also a number of processing options that may be set.
Normally these will only be used by a system administrator.
Options may be set either on the command line
using the
.B \-o
flag (for short names), the
.B \-O
flag (for long names),
or in the configuration file.
This is a partial list limited to those options that are likely to be useful
on the command line
and only shows the long names;
for a complete list (and details), consult the
.IR "Sendmail Installation and Operation Guide" .
The options are:
.TP
.RI AliasFile= file
Use alternate alias file.
.TP
HoldExpensive
On mailers that are considered ``expensive'' to connect to,
don't initiate immediate connection.
This requires queueing.
.TP
.RI CheckpointInterval= N
Checkpoint the queue file after every
.I N
successful deliveries (default 10).
This avoids excessive duplicate deliveries
when sending to long mailing lists
interrupted by system crashes.
.ne 1i
.TP
.RI DeliveryMode= x
Set the delivery mode to
.IR x .
Delivery modes are
`i'
for interactive (synchronous) delivery,
`b'
for background (asynchronous) delivery,
`q'
for queue only \- i.e.,
actual delivery is done the next time the queue is run, and
`d'
for deferred \- the same as
`q'
except that database lookups for maps which have set the \-D option
(default for the host map) are avoided.
.TP
.RI ErrorMode= x
Set error processing to mode
.IR x .
Valid modes are
`m'
to mail back the error message,
`w'
to ``write''
back the error message
(or mail it back if the sender is not logged in),
`p'
to print the errors on the terminal
(default),
`q'
to throw away error messages
(only exit status is returned),
and
`e'
to do special processing for the BerkNet.
If the text of the message is not mailed back
by
modes
`m'
or
`w'
and if the sender is local to this machine,
a copy of the message is appended to the file
.I dead.letter
in the sender's home directory.
.TP
SaveFromLine
Save
UNIX-style
From lines at the front of messages.
.TP
.RI MaxHopCount= N
The maximum number of times a message is allowed to ``hop''
before we decide it is in a loop.
.TP
IgnoreDots
Do not take dots on a line by themselves
as a message terminator.
.TP
SendMimeErrors
Send error messages in MIME format.
If not set, the DSN (Delivery Status Notification) SMTP extension
is disabled.
.TP
.RI ConnectionCacheTimeout= timeout
Set connection cache timeout.
.TP
.RI ConnectionCacheSize= N
Set connection cache size.
.TP
.RI LogLevel= n
The log level.
.TP
.RI MeToo= False
Don't send to ``me'' (the sender) if I am in an alias expansion.
.TP
CheckAliases
Validate the right hand side of aliases during a
newaliases(1)
command.
.TP
OldStyleHeaders
If set, this message may have
old style headers.
If not set,
this message is guaranteed to have new style headers
(i.e., commas instead of spaces between addresses).
If set, an adaptive algorithm is used that will correctly
determine the header format in most cases.
.TP
.RI QueueDirectory= queuedir
Select the directory in which to queue messages.
.TP
.RI StatusFile= file
Save statistics in the named file.
.TP
.RI Timeout.queuereturn= time
Set the timeout on undelivered messages in the queue to the specified time.
After delivery has failed
(e.g., because of a host being down)
for this amount of time,
failed messages will be returned to the sender.
The default is five days.
.TP
.RI UserDatabaseSpec= userdatabase
If set, a user database is consulted to get forwarding information.
You can consider this an adjunct to the aliasing mechanism,
except that the database is intended to be distributed;
aliases are local to a particular host.
This may not be available if your sendmail does not have the
USERDB
option compiled in.
.TP
ForkEachJob
Fork each job during queue runs.
May be convenient on memory-poor machines.
.TP
SevenBitInput
Strip incoming messages to seven bits.
.TP
.RI EightBitMode= mode
Set the handling of eight bit input to seven bit destinations to
.IR mode :
m
(mimefy) will convert to seven-bit MIME format,
p
(pass) will pass it as eight bits (but violates protocols),
and
s
(strict) will bounce the message.
.TP
.RI MinQueueAge= timeout
Sets how long a job must ferment in the queue between attempts to send it.
.TP
.RI DefaultCharSet= charset
Sets the default character set used to label 8-bit data
that is not otherwise labelled.
.TP
.RI DialDelay= sleeptime
If opening a connection fails,
sleep for
.I sleeptime
seconds and try again.
Useful on dial-on-demand sites.
.TP
.RI NoRecipientAction= action
Set the behaviour when there are no recipient headers (To:, Cc: or
Bcc:) in the message to
.IR action :
none
leaves the message unchanged,
add-to
adds a To: header with the envelope recipients,
add-apparently-to
adds an Apparently-To: header with the envelope recipients,
add-bcc
adds an empty Bcc: header, and
add-to-undisclosed
adds a header reading
`To: undisclosed-recipients:;'.
.TP
.RI MaxDaemonChildren= N
Sets the maximum number of children that an incoming SMTP daemon
will allow to spawn at any time to
.IR N .
.TP
.RI ConnectionRateThrottle= N
Sets the maximum number of connections per second to the SMTP port to
.IR N .
.PP
In aliases,
the first character of a name may be
a vertical bar to cause interpretation of
the rest of the name as a command
to pipe the mail to.
It may be necessary to quote the name
to keep
.B sendmail
from suppressing the blanks from between arguments.
For example, a common alias is:
.IP
msgs: "|/usr/bin/msgs -s"
.PP
Aliases may also have the syntax
.RI ``:include: filename ''
to ask
.B sendmail
to read the named file for a list of recipients.
For example, an alias such as:
.IP
poets: ":include:/usr/local/lib/poets.list"
.PP
would read
.I /usr/local/lib/poets.list
for the list of addresses making up the group.
.PP
.B Sendmail
returns an exit status
describing what it did.
The codes are defined in
.RI < sysexits.h >:
.TP
EX_OK
Successful completion on all addresses.
.TP
EX_NOUSER
User name not recognized.
.TP
EX_UNAVAILABLE
Catchall meaning necessary resources
were not available.
.TP
EX_SYNTAX
Syntax error in address.
.TP
EX_SOFTWARE
Internal software error,
including bad arguments.
.TP
EX_OSERR
Temporary operating system error,
such as
``cannot fork''.
.TP
EX_NOHOST
Host name not recognized.
.TP
EX_TEMPFAIL
Message could not be sent immediately,
but was queued.
.PP
If invoked as
.BR newaliases ,
.B sendmail
will rebuild the alias database. If invoked as
.BR mailq ,
.B sendmail
will print the contents of the mail queue.
If invoked as
.BR hoststat ,
.B sendmail
will print the persistent host status database.
If invoked as
.BR purgestat ,
.B sendmail
will purge expired entries from the persistent host status database.
If invoked as
.BR smtpd ,
.B sendmail
will act as a daemon, as if the
.B \-bd
option were specified.
.SH NOTES
.B sendmail
often gets blamed for many problems
that are actually the result of other problems,
such as overly permissive modes on directories.
For this reason,
.B sendmail
checks the modes on system directories and files
to determine if they can be trusted.
Although these checks can be turned off
and your system security reduced by setting the
.BR DontBlameSendmail
option,
the permission problems should be fixed.
For more information, see:
.I http://www.sendmail.org/tips/DontBlameSendmail.html
.SH FILES
Except for the file
.I /etc/mail/sendmail.cf
itself the following pathnames are all specified in
.IR /etc/mail/sendmail.cf .
Thus,
these values are only approximations.
.PP
.TP
/etc/mail/aliases
raw data for alias names
.TP
/etc/mail/aliases.db
data base of alias names
.TP
/etc/mail/sendmail.cf
configuration file
.TP
/etc/mail/helpfile
help file
.TP
/etc/mail/statistics
collected statistics
.TP
/var/spool/mqueue/*
temp files
.SH SEE ALSO
mail(1),
syslog(3),
aliases(5),
mailaddr(7),
mail.local(8),
rc(8),
rmail(8)
.PP
DARPA
Internet Request For Comments
.IR RFC819 ,
.IR RFC821 ,
.IR RFC822 .
-.IR "Sendmail \- An Internetwork Mail Router" ,
-No. 9, SMM.
.IR "Sendmail Installation and Operation Guide" ,
No. 8, SMM.
.PP
http://www.sendmail.org/
.SH HISTORY
The
.B sendmail
command appeared in
4.2BSD.

File Metadata

Mime Type
application/octet-stream
Expires
Wed, Oct 15, 5:13 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23708676
Default Alt Text
(422 KB)

Event Timeline