xref: /freebsd/contrib/sendmail/src/main.c (revision d39bd2c1)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2006, 2008, 2009, 2011 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1440266059SGregory Neil Shapiro #define _DEFINE
1540266059SGregory Neil Shapiro #include <sendmail.h>
16d0cef73dSGregory Neil Shapiro #include <sm/sendmail.h>
1740266059SGregory Neil Shapiro #include <sm/xtrap.h>
1840266059SGregory Neil Shapiro #include <sm/signal.h>
195b0945b5SGregory Neil Shapiro #include <tls.h>
202fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
212fb4f839SGregory Neil Shapiro # include <sm/ixlen.h>
222fb4f839SGregory Neil Shapiro #endif
232fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
242fb4f839SGregory Neil Shapiro # include <sm/notify.h>
252fb4f839SGregory Neil Shapiro #endif
2640266059SGregory Neil Shapiro 
27c2aa98e2SPeter Wemm #ifndef lint
2840266059SGregory Neil Shapiro SM_UNUSED(static char copyright[]) =
295dd76dd0SGregory Neil Shapiro "@(#) Copyright (c) 1998-2013 Proofpoint, Inc. and its suppliers.\n\
3006f25ae9SGregory Neil Shapiro 	All rights reserved.\n\
31c2aa98e2SPeter Wemm      Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.\n\
32c2aa98e2SPeter Wemm      Copyright (c) 1988, 1993\n\
33c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
3406f25ae9SGregory Neil Shapiro #endif /* ! lint */
35c2aa98e2SPeter Wemm 
364313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: main.c,v 8.988 2013-11-23 02:52:37 gshapiro Exp $")
3706f25ae9SGregory Neil Shapiro 
3806f25ae9SGregory Neil Shapiro 
3906f25ae9SGregory Neil Shapiro #if NETINET || NETINET6
40c2aa98e2SPeter Wemm # include <arpa/inet.h>
415b0945b5SGregory Neil Shapiro # if DANE
425b0945b5SGregory Neil Shapiro #  include "sm_resolve.h"
435b0945b5SGregory Neil Shapiro # endif
445b0945b5SGregory Neil Shapiro #endif
4506f25ae9SGregory Neil Shapiro 
4640266059SGregory Neil Shapiro /* for getcfname() */
4740266059SGregory Neil Shapiro #include <sendmail/pathnames.h>
485b0945b5SGregory Neil Shapiro #include <ratectrl.h>
4940266059SGregory Neil Shapiro 
5040266059SGregory Neil Shapiro static SM_DEBUG_T
5140266059SGregory Neil Shapiro DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
5240266059SGregory Neil Shapiro 	"@(#)$Debug: no_persistent_restart - don't restart, log only $");
5340266059SGregory Neil Shapiro 
5406f25ae9SGregory Neil Shapiro static void	dump_class __P((STAB *, int));
5506f25ae9SGregory Neil Shapiro static void	obsolete __P((char **));
5606f25ae9SGregory Neil Shapiro static void	testmodeline __P((char *, ENVELOPE *));
5740266059SGregory Neil Shapiro static char	*getextenv __P((const char *));
5840266059SGregory Neil Shapiro static void	sm_printoptions __P((char **));
5940266059SGregory Neil Shapiro static SIGFUNC_DECL	intindebug __P((int));
6040266059SGregory Neil Shapiro static SIGFUNC_DECL	sighup __P((int));
6140266059SGregory Neil Shapiro static SIGFUNC_DECL	sigpipe __P((int));
6240266059SGregory Neil Shapiro static SIGFUNC_DECL	sigterm __P((int));
6340266059SGregory Neil Shapiro #ifdef SIGUSR1
6440266059SGregory Neil Shapiro static SIGFUNC_DECL	sigusr1 __P((int));
655b0945b5SGregory Neil Shapiro #endif
66c2aa98e2SPeter Wemm 
67c2aa98e2SPeter Wemm /*
68c2aa98e2SPeter Wemm **  SENDMAIL -- Post mail to a set of destinations.
69c2aa98e2SPeter Wemm **
70c2aa98e2SPeter Wemm **	This is the basic mail router.  All user mail programs should
71c2aa98e2SPeter Wemm **	call this routine to actually deliver mail.  Sendmail in
72c2aa98e2SPeter Wemm **	turn calls a bunch of mail servers that do the real work of
73c2aa98e2SPeter Wemm **	delivering the mail.
74c2aa98e2SPeter Wemm **
7506f25ae9SGregory Neil Shapiro **	Sendmail is driven by settings read in from /etc/mail/sendmail.cf
76c2aa98e2SPeter Wemm **	(read by readcf.c).
77c2aa98e2SPeter Wemm **
78c2aa98e2SPeter Wemm **	Usage:
79c2aa98e2SPeter Wemm **		/usr/lib/sendmail [flags] addr ...
80c2aa98e2SPeter Wemm **
81c2aa98e2SPeter Wemm **		See the associated documentation for details.
82c2aa98e2SPeter Wemm **
8340266059SGregory Neil Shapiro **	Authors:
84c2aa98e2SPeter Wemm **		Eric Allman, UCB/INGRES (until 10/81).
85c2aa98e2SPeter Wemm **			     Britton-Lee, Inc., purveyors of fine
86c2aa98e2SPeter Wemm **				database computers (11/81 - 10/88).
87c2aa98e2SPeter Wemm **			     International Computer Science Institute
88c2aa98e2SPeter Wemm **				(11/88 - 9/89).
89c2aa98e2SPeter Wemm **			     UCB/Mammoth Project (10/89 - 7/95).
90c2aa98e2SPeter Wemm **			     InReference, Inc. (8/95 - 1/97).
915dd76dd0SGregory Neil Shapiro **			     Sendmail, Inc. (1/98 - 9/13).
92d9986b26SGregory Neil Shapiro **		The support of my employers is gratefully acknowledged.
93c2aa98e2SPeter Wemm **			Few of them (Britton-Lee in particular) have had
94c2aa98e2SPeter Wemm **			anything to gain from my involvement in this project.
9540266059SGregory Neil Shapiro **
9640266059SGregory Neil Shapiro **		Gregory Neil Shapiro,
9740266059SGregory Neil Shapiro **			Worcester Polytechnic Institute	(until 3/98).
985dd76dd0SGregory Neil Shapiro **			Sendmail, Inc. (3/98 - 10/13).
995dd76dd0SGregory Neil Shapiro **			Proofpoint, Inc. (10/13 - present).
10040266059SGregory Neil Shapiro **
10140266059SGregory Neil Shapiro **		Claus Assmann,
1025dd76dd0SGregory Neil Shapiro **			Sendmail, Inc. (12/98 - 10/13).
1035dd76dd0SGregory Neil Shapiro **			Proofpoint, Inc. (10/13 - present).
104c2aa98e2SPeter Wemm */
105c2aa98e2SPeter Wemm 
106c2aa98e2SPeter Wemm char		*FullName;	/* sender's full name */
107c2aa98e2SPeter Wemm ENVELOPE	BlankEnvelope;	/* a "blank" envelope */
10806f25ae9SGregory Neil Shapiro static ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */
109c2aa98e2SPeter Wemm ADDRESS		NullAddress =	/* a null address */
110c2aa98e2SPeter Wemm 		{ "", "", NULL, "" };
111c2aa98e2SPeter Wemm char		*CommandLineArgs;	/* command line args for pid file */
11240266059SGregory Neil Shapiro bool		Warn_Q_option = false;	/* warn about Q option use */
11306f25ae9SGregory Neil Shapiro static int	MissingFds = 0;	/* bit map of fds missing on startup */
11440266059SGregory Neil Shapiro char		*Mbdb = "pw";	/* mailbox database defaults to /etc/passwd */
115c2aa98e2SPeter Wemm 
116c2aa98e2SPeter Wemm #ifdef NGROUPS_MAX
117c2aa98e2SPeter Wemm GIDSET_T	InitialGidSet[NGROUPS_MAX];
1185b0945b5SGregory Neil Shapiro #endif
119c2aa98e2SPeter Wemm 
12040266059SGregory Neil Shapiro #define MAXCONFIGLEVEL	10	/* highest config version level known */
12106f25ae9SGregory Neil Shapiro 
12206f25ae9SGregory Neil Shapiro #if SASL
12306f25ae9SGregory Neil Shapiro static sasl_callback_t srvcallbacks[] =
12406f25ae9SGregory Neil Shapiro {
12535954bbaSHajimu UMEMOTO 	{	SASL_CB_VERIFYFILE,	(sasl_callback_ft)&safesaslfile,	NULL	},
12635954bbaSHajimu UMEMOTO 	{	SASL_CB_PROXY_POLICY,	(sasl_callback_ft)&proxy_policy,	NULL	},
12706f25ae9SGregory Neil Shapiro 	{	SASL_CB_LIST_END,	NULL,		NULL	}
12806f25ae9SGregory Neil Shapiro };
12906f25ae9SGregory Neil Shapiro #endif /* SASL */
13006f25ae9SGregory Neil Shapiro 
13140266059SGregory Neil Shapiro unsigned int	SubmitMode;
13240266059SGregory Neil Shapiro int		SyslogPrefixLen; /* estimated length of syslog prefix */
13340266059SGregory Neil Shapiro #define PIDLEN		6	/* pid length for computing SyslogPrefixLen */
13440266059SGregory Neil Shapiro #ifndef SL_FUDGE
13540266059SGregory Neil Shapiro # define SL_FUDGE	10	/* fudge offset for SyslogPrefixLen */
1365b0945b5SGregory Neil Shapiro #endif
13740266059SGregory Neil Shapiro #define SLDLL		8	/* est. length of default syslog label */
13840266059SGregory Neil Shapiro 
13940266059SGregory Neil Shapiro 
14040266059SGregory Neil Shapiro /* Some options are dangerous to allow users to use in non-submit mode */
14140266059SGregory Neil Shapiro #define CHECK_AGAINST_OPMODE(cmd)					\
14240266059SGregory Neil Shapiro {									\
14340266059SGregory Neil Shapiro 	if (extraprivs &&						\
14440266059SGregory Neil Shapiro 	    OpMode != MD_DELIVER && OpMode != MD_SMTP &&		\
1459bd497b8SGregory Neil Shapiro 	    OpMode != MD_ARPAFTP && OpMode != MD_CHECKCONFIG &&		\
14640266059SGregory Neil Shapiro 	    OpMode != MD_VERIFY && OpMode != MD_TEST)			\
14740266059SGregory Neil Shapiro 	{								\
14840266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
14940266059SGregory Neil Shapiro 				     "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
15040266059SGregory Neil Shapiro 		       (cmd));						\
15140266059SGregory Neil Shapiro 		break;							\
15240266059SGregory Neil Shapiro 	}								\
15340266059SGregory Neil Shapiro 	if (extraprivs && queuerun)					\
15440266059SGregory Neil Shapiro 	{								\
15540266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
15640266059SGregory Neil Shapiro 				     "WARNING: Ignoring submission mode -%c option with -q\n", \
15740266059SGregory Neil Shapiro 		       (cmd));						\
15840266059SGregory Neil Shapiro 		break;							\
15940266059SGregory Neil Shapiro 	}								\
16040266059SGregory Neil Shapiro }
161c2aa98e2SPeter Wemm 
162c2aa98e2SPeter Wemm int
main(argc,argv,envp)163c2aa98e2SPeter Wemm main(argc, argv, envp)
164c2aa98e2SPeter Wemm 	int argc;
165c2aa98e2SPeter Wemm 	char **argv;
166c2aa98e2SPeter Wemm 	char **envp;
167c2aa98e2SPeter Wemm {
1682fb4f839SGregory Neil Shapiro 	char *p;
169c2aa98e2SPeter Wemm 	char **av;
170c2aa98e2SPeter Wemm 	extern char Version[];
1712fb4f839SGregory Neil Shapiro 	char *ep, *fromaddr;
1722fb4f839SGregory Neil Shapiro #if USE_EAI
1732fb4f839SGregory Neil Shapiro 	char *fromaddr_x;
1742fb4f839SGregory Neil Shapiro #else
1752fb4f839SGregory Neil Shapiro # define fromaddr_x fromaddr
1762fb4f839SGregory Neil Shapiro #endif
177c2aa98e2SPeter Wemm 	STAB *st;
178c2aa98e2SPeter Wemm 	register int i;
179c2aa98e2SPeter Wemm 	int j;
18006f25ae9SGregory Neil Shapiro 	int dp;
18140266059SGregory Neil Shapiro 	int fill_errno;
18240266059SGregory Neil Shapiro 	int qgrp = NOQGRP;		/* queue group to process */
18340266059SGregory Neil Shapiro 	bool safecf = true;
18406f25ae9SGregory Neil Shapiro 	BITMAP256 *p_flags = NULL;	/* daemon flags */
18540266059SGregory Neil Shapiro 	bool warn_C_flag = false;
18640266059SGregory Neil Shapiro 	bool auth = true;		/* whether to set e_auth_param */
187c2aa98e2SPeter Wemm 	char warn_f_flag = '\0';
18840266059SGregory Neil Shapiro 	bool run_in_foreground = false;	/* -bD mode */
18940266059SGregory Neil Shapiro 	bool queuerun = false, debug = false;
190c2aa98e2SPeter Wemm 	struct passwd *pw;
191c2aa98e2SPeter Wemm 	struct hostent *hp;
192c2aa98e2SPeter Wemm 	char *nullserver = NULL;
19306f25ae9SGregory Neil Shapiro 	char *authinfo = NULL;
19406f25ae9SGregory Neil Shapiro 	char *sysloglabel = NULL;	/* label for syslog */
19540266059SGregory Neil Shapiro 	char *conffile = NULL;		/* name of .cf file */
19640266059SGregory Neil Shapiro 	char *queuegroup = NULL;	/* queue group to process */
19740266059SGregory Neil Shapiro 	char *quarantining = NULL;	/* quarantine queue items? */
19840266059SGregory Neil Shapiro 	bool extraprivs;
19940266059SGregory Neil Shapiro 	bool forged, negate;
20040266059SGregory Neil Shapiro 	bool queuepersistent = false;	/* queue runner process runs forever */
20140266059SGregory Neil Shapiro 	bool foregroundqueue = false;	/* queue run in foreground */
20240266059SGregory Neil Shapiro 	bool save_val;			/* to save some bool var. */
20340266059SGregory Neil Shapiro 	int cftype;			/* which cf file to use? */
204e92d3f3fSGregory Neil Shapiro 	SM_FILE_T *smdebug;
20540266059SGregory Neil Shapiro 	static time_t starttime = 0;	/* when was process started */
20606f25ae9SGregory Neil Shapiro 	struct stat traf_st;		/* for TrafficLog FIFO check */
20740266059SGregory Neil Shapiro 	char buf[MAXLINE];
208c2aa98e2SPeter Wemm 	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */
2092fb4f839SGregory Neil Shapiro 	static char rnamebuf[MAXNAME];	/* holds RealUserName */ /* EAI:ok */
210c2aa98e2SPeter Wemm 	char *emptyenviron[1];
21142e5d165SGregory Neil Shapiro #if STARTTLS
21242e5d165SGregory Neil Shapiro 	bool tls_ok;
2135b0945b5SGregory Neil Shapiro #endif
214c2aa98e2SPeter Wemm 	QUEUE_CHAR *new;
21540266059SGregory Neil Shapiro 	ENVELOPE *e;
216c2aa98e2SPeter Wemm 	extern int DtableSize;
217c2aa98e2SPeter Wemm 	extern int optind;
218c2aa98e2SPeter Wemm 	extern int opterr;
219c2aa98e2SPeter Wemm 	extern char *optarg;
220c2aa98e2SPeter Wemm 	extern char **environ;
22140266059SGregory Neil Shapiro #if SASL
22240266059SGregory Neil Shapiro 	extern void sm_sasl_init __P((void));
2235b0945b5SGregory Neil Shapiro #endif
22440266059SGregory Neil Shapiro 
22540266059SGregory Neil Shapiro #if USE_ENVIRON
22640266059SGregory Neil Shapiro 	envp = environ;
2275b0945b5SGregory Neil Shapiro #endif
22840266059SGregory Neil Shapiro 
22940266059SGregory Neil Shapiro 	/* turn off profiling */
23040266059SGregory Neil Shapiro 	SM_PROF(0);
23140266059SGregory Neil Shapiro 
23240266059SGregory Neil Shapiro 	/* install default exception handler */
23340266059SGregory Neil Shapiro 	sm_exc_newthread(fatal_error);
234c2aa98e2SPeter Wemm 
23513bd1963SGregory Neil Shapiro 	/* set the default in/out channel so errors reported to screen */
23613bd1963SGregory Neil Shapiro 	InChannel = smioin;
23713bd1963SGregory Neil Shapiro 	OutChannel = smioout;
23813bd1963SGregory Neil Shapiro 
239c2aa98e2SPeter Wemm 	/*
240c2aa98e2SPeter Wemm 	**  Check to see if we reentered.
241c2aa98e2SPeter Wemm 	**	This would normally happen if e_putheader or e_putbody
242c2aa98e2SPeter Wemm 	**	were NULL when invoked.
243c2aa98e2SPeter Wemm 	*/
244c2aa98e2SPeter Wemm 
24540266059SGregory Neil Shapiro 	if (starttime != 0)
246c2aa98e2SPeter Wemm 	{
247c2aa98e2SPeter Wemm 		syserr("main: reentered!");
248c2aa98e2SPeter Wemm 		abort();
249c2aa98e2SPeter Wemm 	}
25040266059SGregory Neil Shapiro 	starttime = curtime();
251c2aa98e2SPeter Wemm 
252c2aa98e2SPeter Wemm 	/* avoid null pointer dereferences */
253d0cef73dSGregory Neil Shapiro 	TermEscape.te_rv_on = TermEscape.te_under_on = TermEscape.te_normal = "";
254c2aa98e2SPeter Wemm 
25540266059SGregory Neil Shapiro 	RealUid = getuid();
25640266059SGregory Neil Shapiro 	RealGid = getgid();
25740266059SGregory Neil Shapiro 
25840266059SGregory Neil Shapiro 	/* Check if sendmail is running with extra privs */
25940266059SGregory Neil Shapiro 	extraprivs = (RealUid != 0 &&
26040266059SGregory Neil Shapiro 		      (geteuid() != getuid() || getegid() != getgid()));
26140266059SGregory Neil Shapiro 
26240266059SGregory Neil Shapiro 	CurrentPid = getpid();
26340266059SGregory Neil Shapiro 
26440266059SGregory Neil Shapiro 	/* get whatever .cf file is right for the opmode */
26540266059SGregory Neil Shapiro 	cftype = SM_GET_RIGHT_CF;
26640266059SGregory Neil Shapiro 
26740266059SGregory Neil Shapiro 	/* in 4.4BSD, the table can be huge; impose a reasonable limit */
26840266059SGregory Neil Shapiro 	DtableSize = getdtsize();
26940266059SGregory Neil Shapiro 	if (DtableSize > 256)
27040266059SGregory Neil Shapiro 		DtableSize = 256;
27140266059SGregory Neil Shapiro 
27240266059SGregory Neil Shapiro 	/*
27340266059SGregory Neil Shapiro 	**  Be sure we have enough file descriptors.
27440266059SGregory Neil Shapiro 	**	But also be sure that 0, 1, & 2 are open.
27540266059SGregory Neil Shapiro 	*/
27640266059SGregory Neil Shapiro 
27740266059SGregory Neil Shapiro 	/* reset errno and fill_errno; the latter is used way down below */
27840266059SGregory Neil Shapiro 	errno = fill_errno = 0;
27940266059SGregory Neil Shapiro 	fill_fd(STDIN_FILENO, NULL);
28040266059SGregory Neil Shapiro 	if (errno != 0)
28140266059SGregory Neil Shapiro 		fill_errno = errno;
28240266059SGregory Neil Shapiro 	fill_fd(STDOUT_FILENO, NULL);
28340266059SGregory Neil Shapiro 	if (errno != 0)
28440266059SGregory Neil Shapiro 		fill_errno = errno;
28540266059SGregory Neil Shapiro 	fill_fd(STDERR_FILENO, NULL);
28640266059SGregory Neil Shapiro 	if (errno != 0)
28740266059SGregory Neil Shapiro 		fill_errno = errno;
28840266059SGregory Neil Shapiro 
289e92d3f3fSGregory Neil Shapiro 	sm_closefrom(STDERR_FILENO + 1, DtableSize);
29040266059SGregory Neil Shapiro 	errno = 0;
291e92d3f3fSGregory Neil Shapiro 	smdebug = NULL;
29240266059SGregory Neil Shapiro 
29340266059SGregory Neil Shapiro #if LOG
29440266059SGregory Neil Shapiro # ifndef SM_LOG_STR
29540266059SGregory Neil Shapiro #  define SM_LOG_STR	"sendmail"
2965b0945b5SGregory Neil Shapiro # endif
29740266059SGregory Neil Shapiro # ifdef LOG_MAIL
29840266059SGregory Neil Shapiro 	openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
2995b0945b5SGregory Neil Shapiro # else
30040266059SGregory Neil Shapiro 	openlog(SM_LOG_STR, LOG_PID);
3015b0945b5SGregory Neil Shapiro # endif
30240266059SGregory Neil Shapiro #endif /* LOG */
30340266059SGregory Neil Shapiro 
3048774250cSGregory Neil Shapiro 	/*
3058774250cSGregory Neil Shapiro 	**  Seed the random number generator.
3068774250cSGregory Neil Shapiro 	**  Used for queue file names, picking a queue directory, and
3078774250cSGregory Neil Shapiro 	**  MX randomization.
3088774250cSGregory Neil Shapiro 	*/
3098774250cSGregory Neil Shapiro 
3108774250cSGregory Neil Shapiro 	seed_random();
3118774250cSGregory Neil Shapiro 
312c2aa98e2SPeter Wemm 	/* do machine-dependent initializations */
313c2aa98e2SPeter Wemm 	init_md(argc, argv);
314c2aa98e2SPeter Wemm 
31506f25ae9SGregory Neil Shapiro 
31640266059SGregory Neil Shapiro 	SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;
317c2aa98e2SPeter Wemm 
318c2aa98e2SPeter Wemm 	/* reset status from syserr() calls for missing file descriptors */
319c2aa98e2SPeter Wemm 	Errors = 0;
320c2aa98e2SPeter Wemm 	ExitStat = EX_OK;
321c2aa98e2SPeter Wemm 
32206f25ae9SGregory Neil Shapiro 	SubmitMode = SUBMIT_UNKNOWN;
323e3793f76SGregory Neil Shapiro #if _FFR_LOCAL_DAEMON
324e3793f76SGregory Neil Shapiro 	LocalDaemon = false;
3256f9c8e5bSGregory Neil Shapiro # if NETINET6
3266f9c8e5bSGregory Neil Shapiro 	V6LoopbackAddrFound = false;
3275b0945b5SGregory Neil Shapiro # endif
3285b0945b5SGregory Neil Shapiro #endif
329c2aa98e2SPeter Wemm 	checkfd012("after openlog");
33006f25ae9SGregory Neil Shapiro 
331d0cef73dSGregory Neil Shapiro 	tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1");
332c2aa98e2SPeter Wemm 
333c2aa98e2SPeter Wemm #ifdef NGROUPS_MAX
334c2aa98e2SPeter Wemm 	/* save initial group set for future checks */
335c2aa98e2SPeter Wemm 	i = getgroups(NGROUPS_MAX, InitialGidSet);
33640266059SGregory Neil Shapiro 	if (i <= 0)
33740266059SGregory Neil Shapiro 	{
338c2aa98e2SPeter Wemm 		InitialGidSet[0] = (GID_T) -1;
33940266059SGregory Neil Shapiro 		i = 0;
34040266059SGregory Neil Shapiro 	}
341c2aa98e2SPeter Wemm 	while (i < NGROUPS_MAX)
342c2aa98e2SPeter Wemm 		InitialGidSet[i++] = InitialGidSet[0];
34306f25ae9SGregory Neil Shapiro #endif /* NGROUPS_MAX */
344c2aa98e2SPeter Wemm 
345c2aa98e2SPeter Wemm 	/* drop group id privileges (RunAsUser not yet set) */
34640266059SGregory Neil Shapiro 	dp = drop_privileges(false);
34706f25ae9SGregory Neil Shapiro 	setstat(dp);
348c2aa98e2SPeter Wemm 
349c2aa98e2SPeter Wemm #ifdef SIGUSR1
3508774250cSGregory Neil Shapiro 	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
351605302a5SGregory Neil Shapiro 	if (!extraprivs)
3528774250cSGregory Neil Shapiro 	{
353c2aa98e2SPeter Wemm 		/* arrange to dump state on user-1 signal */
35440266059SGregory Neil Shapiro 		(void) sm_signal(SIGUSR1, sigusr1);
3558774250cSGregory Neil Shapiro 	}
356605302a5SGregory Neil Shapiro 	else
357605302a5SGregory Neil Shapiro 	{
358605302a5SGregory Neil Shapiro 		/* ignore user-1 signal */
359605302a5SGregory Neil Shapiro 		(void) sm_signal(SIGUSR1, SIG_IGN);
360605302a5SGregory Neil Shapiro 	}
36106f25ae9SGregory Neil Shapiro #endif /* SIGUSR1 */
362c2aa98e2SPeter Wemm 
363c2aa98e2SPeter Wemm 	/* initialize for setproctitle */
364c2aa98e2SPeter Wemm 	initsetproctitle(argc, argv, envp);
365c2aa98e2SPeter Wemm 
366c2aa98e2SPeter Wemm 	/* Handle any non-getoptable constructions. */
367c2aa98e2SPeter Wemm 	obsolete(argv);
368c2aa98e2SPeter Wemm 
369c2aa98e2SPeter Wemm 	/*
370c2aa98e2SPeter Wemm 	**  Do a quick prescan of the argument list.
371c2aa98e2SPeter Wemm 	*/
372c2aa98e2SPeter Wemm 
37306f25ae9SGregory Neil Shapiro 
37440266059SGregory Neil Shapiro 	/* find initial opMode */
37540266059SGregory Neil Shapiro 	OpMode = MD_DELIVER;
37640266059SGregory Neil Shapiro 	av = argv;
37740266059SGregory Neil Shapiro 	p = strrchr(*av, '/');
37840266059SGregory Neil Shapiro 	if (p++ == NULL)
37940266059SGregory Neil Shapiro 		p = *av;
38040266059SGregory Neil Shapiro 	if (strcmp(p, "newaliases") == 0)
38140266059SGregory Neil Shapiro 		OpMode = MD_INITALIAS;
38240266059SGregory Neil Shapiro 	else if (strcmp(p, "mailq") == 0)
38340266059SGregory Neil Shapiro 		OpMode = MD_PRINT;
38440266059SGregory Neil Shapiro 	else if (strcmp(p, "smtpd") == 0)
38540266059SGregory Neil Shapiro 		OpMode = MD_DAEMON;
38640266059SGregory Neil Shapiro 	else if (strcmp(p, "hoststat") == 0)
38740266059SGregory Neil Shapiro 		OpMode = MD_HOSTSTAT;
38840266059SGregory Neil Shapiro 	else if (strcmp(p, "purgestat") == 0)
38940266059SGregory Neil Shapiro 		OpMode = MD_PURGESTAT;
39040266059SGregory Neil Shapiro 
391c2aa98e2SPeter Wemm #if defined(__osf__) || defined(_AIX3)
3922fb4f839SGregory Neil Shapiro # define OPTIONS	"A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtUV:vX:x"
3932fb4f839SGregory Neil Shapiro #endif
394c2aa98e2SPeter Wemm #if defined(sony_news)
3952fb4f839SGregory Neil Shapiro # define OPTIONS	"A:B:b:C:cD:d:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:Q:q:R:r:sTtUV:vX:"
3962fb4f839SGregory Neil Shapiro #endif
397c2aa98e2SPeter Wemm #ifndef OPTIONS
3982fb4f839SGregory Neil Shapiro # define OPTIONS	"A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtUV:vX:"
3995b0945b5SGregory Neil Shapiro #endif
40040266059SGregory Neil Shapiro 
4015ef517c0SGregory Neil Shapiro 	/* Set to 0 to allow -b; need to check optarg before using it! */
402c2aa98e2SPeter Wemm 	opterr = 0;
403c2aa98e2SPeter Wemm 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
404c2aa98e2SPeter Wemm 	{
405c2aa98e2SPeter Wemm 		switch (j)
406c2aa98e2SPeter Wemm 		{
40740266059SGregory Neil Shapiro 		  case 'b':	/* operations mode */
408605302a5SGregory Neil Shapiro 			j = (optarg == NULL) ? ' ' : *optarg;
409605302a5SGregory Neil Shapiro 			switch (j)
410c2aa98e2SPeter Wemm 			{
41140266059SGregory Neil Shapiro 			  case MD_DAEMON:
41240266059SGregory Neil Shapiro 			  case MD_FGDAEMON:
41340266059SGregory Neil Shapiro 			  case MD_SMTP:
41440266059SGregory Neil Shapiro 			  case MD_INITALIAS:
41540266059SGregory Neil Shapiro 			  case MD_DELIVER:
41640266059SGregory Neil Shapiro 			  case MD_VERIFY:
41740266059SGregory Neil Shapiro 			  case MD_TEST:
41840266059SGregory Neil Shapiro 			  case MD_PRINT:
41940266059SGregory Neil Shapiro 			  case MD_PRINTNQE:
42040266059SGregory Neil Shapiro 			  case MD_HOSTSTAT:
42140266059SGregory Neil Shapiro 			  case MD_PURGESTAT:
42240266059SGregory Neil Shapiro 			  case MD_ARPAFTP:
4239bd497b8SGregory Neil Shapiro 			  case MD_CHECKCONFIG:
42440266059SGregory Neil Shapiro 				OpMode = j;
425c2aa98e2SPeter Wemm 				break;
42640266059SGregory Neil Shapiro 
4272fb4f839SGregory Neil Shapiro 			  case MD_SHOWCONFIG:
4282fb4f839SGregory Neil Shapiro 				showcfopts();
4292fb4f839SGregory Neil Shapiro 				return EX_OK;
430e3793f76SGregory Neil Shapiro #if _FFR_LOCAL_DAEMON
431e3793f76SGregory Neil Shapiro 			  case MD_LOCAL:
432e3793f76SGregory Neil Shapiro 				OpMode = MD_DAEMON;
433e3793f76SGregory Neil Shapiro 				LocalDaemon = true;
434e3793f76SGregory Neil Shapiro 				break;
435e3793f76SGregory Neil Shapiro #endif /* _FFR_LOCAL_DAEMON */
436e3793f76SGregory Neil Shapiro 
43740266059SGregory Neil Shapiro 			  case MD_FREEZE:
43840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
43940266059SGregory Neil Shapiro 						     "Frozen configurations unsupported\n");
44040266059SGregory Neil Shapiro 				return EX_USAGE;
44140266059SGregory Neil Shapiro 
44240266059SGregory Neil Shapiro 			  default:
44340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
44440266059SGregory Neil Shapiro 						     "Invalid operation mode %c\n",
44540266059SGregory Neil Shapiro 						     j);
44640266059SGregory Neil Shapiro 				return EX_USAGE;
447c2aa98e2SPeter Wemm 			}
44840266059SGregory Neil Shapiro 			break;
44940266059SGregory Neil Shapiro 
450e92d3f3fSGregory Neil Shapiro 		  case 'D':
451e92d3f3fSGregory Neil Shapiro 			if (debug)
452e92d3f3fSGregory Neil Shapiro 			{
453e92d3f3fSGregory Neil Shapiro 				errno = 0;
454e92d3f3fSGregory Neil Shapiro 				syserr("-D file must be before -d");
455e92d3f3fSGregory Neil Shapiro 				ExitStat = EX_USAGE;
456e92d3f3fSGregory Neil Shapiro 				break;
457e92d3f3fSGregory Neil Shapiro 			}
458e92d3f3fSGregory Neil Shapiro 			dp = drop_privileges(true);
459e92d3f3fSGregory Neil Shapiro 			setstat(dp);
460e92d3f3fSGregory Neil Shapiro 			smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
461e92d3f3fSGregory Neil Shapiro 					    optarg, SM_IO_APPEND, NULL);
462e92d3f3fSGregory Neil Shapiro 			if (smdebug == NULL)
463e92d3f3fSGregory Neil Shapiro 			{
464e92d3f3fSGregory Neil Shapiro 				syserr("cannot open %s", optarg);
465e92d3f3fSGregory Neil Shapiro 				ExitStat = EX_CANTCREAT;
466e92d3f3fSGregory Neil Shapiro 				break;
467e92d3f3fSGregory Neil Shapiro 			}
468e92d3f3fSGregory Neil Shapiro 			sm_debug_setfile(smdebug);
469e92d3f3fSGregory Neil Shapiro 			break;
470e92d3f3fSGregory Neil Shapiro 
47140266059SGregory Neil Shapiro 		  case 'd':
47240266059SGregory Neil Shapiro 			debug = true;
473c2aa98e2SPeter Wemm 			tTflag(optarg);
474e92d3f3fSGregory Neil Shapiro 			(void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT,
47540266059SGregory Neil Shapiro 					     (char *) NULL, SM_IO_NBF,
47640266059SGregory Neil Shapiro 					     SM_IO_BUFSIZ);
477c2aa98e2SPeter Wemm 			break;
47806f25ae9SGregory Neil Shapiro 
47906f25ae9SGregory Neil Shapiro 		  case 'G':	/* relay (gateway) submission */
48040266059SGregory Neil Shapiro 			SubmitMode = SUBMIT_MTA;
48106f25ae9SGregory Neil Shapiro 			break;
48206f25ae9SGregory Neil Shapiro 
48306f25ae9SGregory Neil Shapiro 		  case 'L':
4845ef517c0SGregory Neil Shapiro 			if (optarg == NULL)
4855ef517c0SGregory Neil Shapiro 			{
4865ef517c0SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4875ef517c0SGregory Neil Shapiro 						     "option requires an argument -- '%c'",
4885ef517c0SGregory Neil Shapiro 						     (char) j);
4895ef517c0SGregory Neil Shapiro 				return EX_USAGE;
4905ef517c0SGregory Neil Shapiro 			}
491e92d3f3fSGregory Neil Shapiro 			j = SM_MIN(strlen(optarg), 32) + 1;
4922fb4f839SGregory Neil Shapiro 			sysloglabel = sm_malloc_tagged_x(j, "sysloglabel", 0, 0);
49340266059SGregory Neil Shapiro 			(void) sm_strlcpy(sysloglabel, optarg, j);
49440266059SGregory Neil Shapiro 			SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +
49540266059SGregory Neil Shapiro 					  SL_FUDGE + j;
49606f25ae9SGregory Neil Shapiro 			break;
49706f25ae9SGregory Neil Shapiro 
49840266059SGregory Neil Shapiro 		  case 'Q':
49940266059SGregory Neil Shapiro 		  case 'q':
50040266059SGregory Neil Shapiro 			/* just check if it is there */
50140266059SGregory Neil Shapiro 			queuerun = true;
50206f25ae9SGregory Neil Shapiro 			break;
503c2aa98e2SPeter Wemm 		}
504c2aa98e2SPeter Wemm 	}
505c2aa98e2SPeter Wemm 	opterr = 1;
506c2aa98e2SPeter Wemm 
50740266059SGregory Neil Shapiro 	/* Don't leak queue information via debug flags */
50840266059SGregory Neil Shapiro 	if (extraprivs && queuerun && debug)
50940266059SGregory Neil Shapiro 	{
51040266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
51140266059SGregory Neil Shapiro 				     "WARNING: Can not use -d with -q.  Disabling debugging.\n");
512e92d3f3fSGregory Neil Shapiro 		sm_debug_close();
51340266059SGregory Neil Shapiro 		sm_debug_setfile(NULL);
514d0cef73dSGregory Neil Shapiro 		(void) memset(tTdvect, '\0', sizeof(tTdvect));
51540266059SGregory Neil Shapiro 	}
51640266059SGregory Neil Shapiro 
5178774250cSGregory Neil Shapiro #if LOG
51806f25ae9SGregory Neil Shapiro 	if (sysloglabel != NULL)
51906f25ae9SGregory Neil Shapiro 	{
5208774250cSGregory Neil Shapiro 		/* Sanitize the string */
5218774250cSGregory Neil Shapiro 		for (p = sysloglabel; *p != '\0'; p++)
5228774250cSGregory Neil Shapiro 		{
5238774250cSGregory Neil Shapiro 			if (!isascii(*p) || !isprint(*p) || *p == '%')
5248774250cSGregory Neil Shapiro 				*p = '*';
5258774250cSGregory Neil Shapiro 		}
52606f25ae9SGregory Neil Shapiro 		closelog();
52706f25ae9SGregory Neil Shapiro # ifdef LOG_MAIL
52806f25ae9SGregory Neil Shapiro 		openlog(sysloglabel, LOG_PID, LOG_MAIL);
5295b0945b5SGregory Neil Shapiro # else
53006f25ae9SGregory Neil Shapiro 		openlog(sysloglabel, LOG_PID);
5315b0945b5SGregory Neil Shapiro # endif
53206f25ae9SGregory Neil Shapiro 	}
5338774250cSGregory Neil Shapiro #endif /* LOG */
53406f25ae9SGregory Neil Shapiro 
535c2aa98e2SPeter Wemm 	/* set up the blank envelope */
536c2aa98e2SPeter Wemm 	BlankEnvelope.e_puthdr = putheader;
537c2aa98e2SPeter Wemm 	BlankEnvelope.e_putbody = putbody;
538c2aa98e2SPeter Wemm 	BlankEnvelope.e_xfp = NULL;
539c2aa98e2SPeter Wemm 	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
540c2aa98e2SPeter Wemm 	CurEnv = &BlankEnvelope;
541c2aa98e2SPeter Wemm 	STRUCTCOPY(NullAddress, MainEnvelope.e_from);
542c2aa98e2SPeter Wemm 
543c2aa98e2SPeter Wemm 	/*
544c2aa98e2SPeter Wemm 	**  Set default values for variables.
545c2aa98e2SPeter Wemm 	**	These cannot be in initialized data space.
546c2aa98e2SPeter Wemm 	*/
547c2aa98e2SPeter Wemm 
548c2aa98e2SPeter Wemm 	setdefaults(&BlankEnvelope);
54940266059SGregory Neil Shapiro 	initmacros(&BlankEnvelope);
550c2aa98e2SPeter Wemm 
55140266059SGregory Neil Shapiro 	/* reset macro */
55240266059SGregory Neil Shapiro 	set_op_mode(OpMode);
553af9557fdSGregory Neil Shapiro 	if (OpMode == MD_DAEMON)
554af9557fdSGregory Neil Shapiro 		DaemonPid = CurrentPid;	/* needed for finis() to work */
555c2aa98e2SPeter Wemm 
556c2aa98e2SPeter Wemm 	pw = sm_getpwuid(RealUid);
557c2aa98e2SPeter Wemm 	if (pw != NULL)
558d0cef73dSGregory Neil Shapiro 		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof(rnamebuf));
559c2aa98e2SPeter Wemm 	else
560d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(rnamebuf, sizeof(rnamebuf), "Unknown UID %d",
56106f25ae9SGregory Neil Shapiro 				   (int) RealUid);
56206f25ae9SGregory Neil Shapiro 
563c2aa98e2SPeter Wemm 	RealUserName = rnamebuf;
564c2aa98e2SPeter Wemm 
565c2aa98e2SPeter Wemm 	if (tTd(0, 101))
566c2aa98e2SPeter Wemm 	{
56740266059SGregory Neil Shapiro 		sm_dprintf("Version %s\n", Version);
56840266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
56940266059SGregory Neil Shapiro 		/* NOTREACHED */
570c2aa98e2SPeter Wemm 	}
571c2aa98e2SPeter Wemm 
572c2aa98e2SPeter Wemm 	/*
57340266059SGregory Neil Shapiro 	**  if running non-set-user-ID binary as non-root, pretend
574c2aa98e2SPeter Wemm 	**  we are the RunAsUid
575c2aa98e2SPeter Wemm 	*/
5768774250cSGregory Neil Shapiro 
577c2aa98e2SPeter Wemm 	if (RealUid != 0 && geteuid() == RealUid)
578c2aa98e2SPeter Wemm 	{
579c2aa98e2SPeter Wemm 		if (tTd(47, 1))
58040266059SGregory Neil Shapiro 			sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",
581c2aa98e2SPeter Wemm 				   (int) RealUid);
582c2aa98e2SPeter Wemm 		RunAsUid = RealUid;
583c2aa98e2SPeter Wemm 	}
584c2aa98e2SPeter Wemm 	else if (geteuid() != 0)
585c2aa98e2SPeter Wemm 		RunAsUid = geteuid();
586c2aa98e2SPeter Wemm 
58740266059SGregory Neil Shapiro 	EffGid = getegid();
58840266059SGregory Neil Shapiro 	if (RealUid != 0 && EffGid == RealGid)
589c2aa98e2SPeter Wemm 		RunAsGid = RealGid;
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	if (tTd(47, 5))
592c2aa98e2SPeter Wemm 	{
59340266059SGregory Neil Shapiro 		sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
59406f25ae9SGregory Neil Shapiro 			   (int) geteuid(), (int) getuid(),
59506f25ae9SGregory Neil Shapiro 			   (int) getegid(), (int) getgid());
59640266059SGregory Neil Shapiro 		sm_dprintf("main: RunAsUser = %d:%d\n",
59706f25ae9SGregory Neil Shapiro 			   (int) RunAsUid, (int) RunAsGid);
598c2aa98e2SPeter Wemm 	}
599c2aa98e2SPeter Wemm 
600c2aa98e2SPeter Wemm 	/* save command line arguments */
60106f25ae9SGregory Neil Shapiro 	j = 0;
602c2aa98e2SPeter Wemm 	for (av = argv; *av != NULL; )
60306f25ae9SGregory Neil Shapiro 		j += strlen(*av++) + 1;
6042fb4f839SGregory Neil Shapiro 	SaveArgv = (char **) sm_malloc_tagged_x(sizeof(char *) * (argc + 1),
6052fb4f839SGregory Neil Shapiro 					"argv", 0, 0);
6062fb4f839SGregory Neil Shapiro 	CommandLineArgs = sm_malloc_tagged_x(j, "cliargs", 0, 0);
607c2aa98e2SPeter Wemm 	p = CommandLineArgs;
608c2aa98e2SPeter Wemm 	for (av = argv, i = 0; *av != NULL; )
609c2aa98e2SPeter Wemm 	{
61006f25ae9SGregory Neil Shapiro 		int h;
61106f25ae9SGregory Neil Shapiro 
612c2aa98e2SPeter Wemm 		SaveArgv[i++] = newstr(*av);
613c2aa98e2SPeter Wemm 		if (av != argv)
614c2aa98e2SPeter Wemm 			*p++ = ' ';
61540266059SGregory Neil Shapiro 		(void) sm_strlcpy(p, *av++, j);
61606f25ae9SGregory Neil Shapiro 		h = strlen(p);
61706f25ae9SGregory Neil Shapiro 		p += h;
61806f25ae9SGregory Neil Shapiro 		j -= h + 1;
619c2aa98e2SPeter Wemm 	}
620c2aa98e2SPeter Wemm 	SaveArgv[i] = NULL;
621c2aa98e2SPeter Wemm 
622c2aa98e2SPeter Wemm 	if (tTd(0, 1))
623c2aa98e2SPeter Wemm 	{
624c2aa98e2SPeter Wemm 		extern char *CompileOptions[];
625c2aa98e2SPeter Wemm 
62640266059SGregory Neil Shapiro 		sm_dprintf("Version %s\n Compiled with:", Version);
62740266059SGregory Neil Shapiro 		sm_printoptions(CompileOptions);
628c2aa98e2SPeter Wemm 	}
629c2aa98e2SPeter Wemm 	if (tTd(0, 10))
630c2aa98e2SPeter Wemm 	{
631c2aa98e2SPeter Wemm 		extern char *OsCompileOptions[];
632c2aa98e2SPeter Wemm 
63340266059SGregory Neil Shapiro 		sm_dprintf("    OS Defines:");
63440266059SGregory Neil Shapiro 		sm_printoptions(OsCompileOptions);
635c2aa98e2SPeter Wemm #ifdef _PATH_UNIX
63640266059SGregory Neil Shapiro 		sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
6375b0945b5SGregory Neil Shapiro #endif
63840266059SGregory Neil Shapiro 
63940266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (default for MSP)\n",
64040266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
64140266059SGregory Neil Shapiro 				     conffile));
64240266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (default for MTA)\n",
64340266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,
64440266059SGregory Neil Shapiro 				     conffile));
64540266059SGregory Neil Shapiro 		sm_dprintf("      Pid file:\t%s (default)\n", PidFile);
646c2aa98e2SPeter Wemm 	}
647c2aa98e2SPeter Wemm 
64840266059SGregory Neil Shapiro 	if (tTd(0, 12))
64940266059SGregory Neil Shapiro 	{
65040266059SGregory Neil Shapiro 		extern char *SmCompileOptions[];
65140266059SGregory Neil Shapiro 
65240266059SGregory Neil Shapiro 		sm_dprintf(" libsm Defines:");
65340266059SGregory Neil Shapiro 		sm_printoptions(SmCompileOptions);
65440266059SGregory Neil Shapiro 	}
65540266059SGregory Neil Shapiro 
65640266059SGregory Neil Shapiro 	if (tTd(0, 13))
65740266059SGregory Neil Shapiro 	{
65840266059SGregory Neil Shapiro 		extern char *FFRCompileOptions[];
65940266059SGregory Neil Shapiro 
66040266059SGregory Neil Shapiro 		sm_dprintf("   FFR Defines:");
66140266059SGregory Neil Shapiro 		sm_printoptions(FFRCompileOptions);
66240266059SGregory Neil Shapiro 	}
66340266059SGregory Neil Shapiro 
664da7d7b9cSGregory Neil Shapiro #if STARTTLS
665da7d7b9cSGregory Neil Shapiro 	if (tTd(0, 14))
666da7d7b9cSGregory Neil Shapiro 	{
667da7d7b9cSGregory Neil Shapiro 		/* exit(EX_CONFIG) if different? */
668da7d7b9cSGregory Neil Shapiro 		sm_dprintf("       OpenSSL: compiled 0x%08x\n",
669da7d7b9cSGregory Neil Shapiro 			   (uint) OPENSSL_VERSION_NUMBER);
670da7d7b9cSGregory Neil Shapiro 		sm_dprintf("       OpenSSL: linked   0x%08x\n",
6715b0945b5SGregory Neil Shapiro 			   (uint) TLS_version_num());
672da7d7b9cSGregory Neil Shapiro 	}
673d39bd2c1SGregory Neil Shapiro #  if defined(LIBRESSL_VERSION_NUMBER)
674d39bd2c1SGregory Neil Shapiro 	if (tTd(0, 15))
675d39bd2c1SGregory Neil Shapiro 		sm_dprintf("       LibreSSL: compiled 0x%08x\n",
676d39bd2c1SGregory Neil Shapiro 			   (uint) LIBRESSL_VERSION_NUMBER);
677d39bd2c1SGregory Neil Shapiro #  endif
678da7d7b9cSGregory Neil Shapiro #endif /* STARTTLS */
679da7d7b9cSGregory Neil Shapiro 
680c2aa98e2SPeter Wemm 	/* clear sendmail's environment */
681c2aa98e2SPeter Wemm 	ExternalEnviron = environ;
682c2aa98e2SPeter Wemm 	emptyenviron[0] = NULL;
683c2aa98e2SPeter Wemm 	environ = emptyenviron;
684c2aa98e2SPeter Wemm 
685c2aa98e2SPeter Wemm 	/*
686c2aa98e2SPeter Wemm 	**  restore any original TZ setting until TimeZoneSpec has been
687c2aa98e2SPeter Wemm 	**  determined - or early log messages may get bogus time stamps
688c2aa98e2SPeter Wemm 	*/
68940266059SGregory Neil Shapiro 
690c2aa98e2SPeter Wemm 	if ((p = getextenv("TZ")) != NULL)
691c2aa98e2SPeter Wemm 	{
692c2aa98e2SPeter Wemm 		char *tz;
693c2aa98e2SPeter Wemm 		int tzlen;
694c2aa98e2SPeter Wemm 
69540266059SGregory Neil Shapiro 		/* XXX check for reasonable length? */
696c2aa98e2SPeter Wemm 		tzlen = strlen(p) + 4;
697c2aa98e2SPeter Wemm 		tz = xalloc(tzlen);
69840266059SGregory Neil Shapiro 		(void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);
69940266059SGregory Neil Shapiro 
70040266059SGregory Neil Shapiro 		/* XXX check return code? */
70106f25ae9SGregory Neil Shapiro 		(void) putenv(tz);
702c2aa98e2SPeter Wemm 	}
703c2aa98e2SPeter Wemm 
704c2aa98e2SPeter Wemm 	/* prime the child environment */
7054e4196cbSGregory Neil Shapiro 	sm_setuserenv("AGENT", "sendmail");
7068774250cSGregory Neil Shapiro 
70740266059SGregory Neil Shapiro 	(void) sm_signal(SIGPIPE, SIG_IGN);
708c2aa98e2SPeter Wemm 	OldUmask = umask(022);
709c2aa98e2SPeter Wemm 	FullName = getextenv("NAME");
7106a2f2ff3SGregory Neil Shapiro 	if (FullName != NULL)
7116a2f2ff3SGregory Neil Shapiro 		FullName = newstr(FullName);
712c2aa98e2SPeter Wemm 
713c2aa98e2SPeter Wemm 	/*
714c2aa98e2SPeter Wemm 	**  Initialize name server if it is going to be used.
715c2aa98e2SPeter Wemm 	*/
716c2aa98e2SPeter Wemm 
717c2aa98e2SPeter Wemm #if NAMED_BIND
718c2aa98e2SPeter Wemm 	if (!bitset(RES_INIT, _res.options))
71906f25ae9SGregory Neil Shapiro 		(void) res_init();
720c2aa98e2SPeter Wemm 	if (tTd(8, 8))
721c2aa98e2SPeter Wemm 		_res.options |= RES_DEBUG;
722c2aa98e2SPeter Wemm 	else
723c2aa98e2SPeter Wemm 		_res.options &= ~RES_DEBUG;
724c2aa98e2SPeter Wemm # ifdef RES_NOALIASES
725c2aa98e2SPeter Wemm 	_res.options |= RES_NOALIASES;
7265b0945b5SGregory Neil Shapiro # endif
72706f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
72806f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
72906f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
73006f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
73106f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
73206f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
73306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
734c2aa98e2SPeter Wemm 
735c2aa98e2SPeter Wemm 	errno = 0;
7362fb4f839SGregory Neil Shapiro 	fromaddr = NULL;
737c2aa98e2SPeter Wemm 
738c2aa98e2SPeter Wemm 	/* initialize some macros, etc. */
73940266059SGregory Neil Shapiro 	init_vendor_macros(&BlankEnvelope);
740c2aa98e2SPeter Wemm 
741c2aa98e2SPeter Wemm 	/* version */
74240266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);
743c2aa98e2SPeter Wemm 
744c2aa98e2SPeter Wemm 	/* hostname */
745d0cef73dSGregory Neil Shapiro 	hp = myhostname(jbuf, sizeof(jbuf));
746c2aa98e2SPeter Wemm 	if (jbuf[0] != '\0')
747c2aa98e2SPeter Wemm 	{
748c2aa98e2SPeter Wemm 		struct utsname utsname;
749c2aa98e2SPeter Wemm 
750c2aa98e2SPeter Wemm 		if (tTd(0, 4))
75140266059SGregory Neil Shapiro 			sm_dprintf("Canonical name: %s\n", jbuf);
7522fb4f839SGregory Neil Shapiro #if USE_EAI
7532fb4f839SGregory Neil Shapiro 		if (!addr_is_ascii(jbuf))
7542fb4f839SGregory Neil Shapiro 		{
7552fb4f839SGregory Neil Shapiro 			usrerr("hostname %s must be ASCII", jbuf);
7562fb4f839SGregory Neil Shapiro 			finis(false, true, EX_CONFIG);
7572fb4f839SGregory Neil Shapiro 			/* NOTREACHED */
7582fb4f839SGregory Neil Shapiro 		}
7592fb4f839SGregory Neil Shapiro #endif
76040266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);
76140266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);
762c2aa98e2SPeter Wemm 		setclass('w', jbuf);
763c2aa98e2SPeter Wemm 
764c2aa98e2SPeter Wemm 		p = strchr(jbuf, '.');
765e92d3f3fSGregory Neil Shapiro 		if (p != NULL && p[1] != '\0')
766e92d3f3fSGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]);
767c2aa98e2SPeter Wemm 
768c2aa98e2SPeter Wemm 		if (uname(&utsname) >= 0)
769c2aa98e2SPeter Wemm 			p = utsname.nodename;
770c2aa98e2SPeter Wemm 		else
771c2aa98e2SPeter Wemm 		{
772c2aa98e2SPeter Wemm 			if (tTd(0, 22))
77340266059SGregory Neil Shapiro 				sm_dprintf("uname failed (%s)\n",
77440266059SGregory Neil Shapiro 					   sm_errstring(errno));
775c2aa98e2SPeter Wemm 			p = jbuf;
7762fb4f839SGregory Neil Shapiro 			p = makelower_a(&p, NULL);
777c2aa98e2SPeter Wemm 		}
778c2aa98e2SPeter Wemm 		if (tTd(0, 4))
77940266059SGregory Neil Shapiro 			sm_dprintf(" UUCP nodename: %s\n", p);
78040266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);
781c2aa98e2SPeter Wemm 		setclass('k', p);
782c2aa98e2SPeter Wemm 		setclass('w', p);
7832fb4f839SGregory Neil Shapiro 		if (p != utsname.nodename && p != jbuf)
7842fb4f839SGregory Neil Shapiro 			SM_FREE(p);
785c2aa98e2SPeter Wemm 	}
786c2aa98e2SPeter Wemm 	if (hp != NULL)
787c2aa98e2SPeter Wemm 	{
788c2aa98e2SPeter Wemm 		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
789c2aa98e2SPeter Wemm 		{
790c2aa98e2SPeter Wemm 			if (tTd(0, 4))
79140266059SGregory Neil Shapiro 				sm_dprintf("\ta.k.a.: %s\n", *av);
792c2aa98e2SPeter Wemm 			setclass('w', *av);
793c2aa98e2SPeter Wemm 		}
79406f25ae9SGregory Neil Shapiro #if NETINET || NETINET6
79540266059SGregory Neil Shapiro 		for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)
796c2aa98e2SPeter Wemm 		{
79706f25ae9SGregory Neil Shapiro # if NETINET6
79806f25ae9SGregory Neil Shapiro 			char *addr;
79906f25ae9SGregory Neil Shapiro 			char buf6[INET6_ADDRSTRLEN];
80006f25ae9SGregory Neil Shapiro 			struct in6_addr ia6;
80106f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
80206f25ae9SGregory Neil Shapiro # if NETINET
80306f25ae9SGregory Neil Shapiro 			struct in_addr ia;
8045b0945b5SGregory Neil Shapiro # endif
805c2aa98e2SPeter Wemm 			char ipbuf[103];
806c2aa98e2SPeter Wemm 
80706f25ae9SGregory Neil Shapiro 			ipbuf[0] = '\0';
80806f25ae9SGregory Neil Shapiro 			switch (hp->h_addrtype)
80906f25ae9SGregory Neil Shapiro 			{
81006f25ae9SGregory Neil Shapiro # if NETINET
81106f25ae9SGregory Neil Shapiro 			  case AF_INET:
81206f25ae9SGregory Neil Shapiro 				if (hp->h_length != INADDRSZ)
81306f25ae9SGregory Neil Shapiro 					break;
81406f25ae9SGregory Neil Shapiro 
81506f25ae9SGregory Neil Shapiro 				memmove(&ia, hp->h_addr_list[i], INADDRSZ);
816d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(ipbuf, sizeof(ipbuf),
81706f25ae9SGregory Neil Shapiro 						   "[%.100s]", inet_ntoa(ia));
81806f25ae9SGregory Neil Shapiro 				break;
81906f25ae9SGregory Neil Shapiro # endif /* NETINET */
82006f25ae9SGregory Neil Shapiro 
82106f25ae9SGregory Neil Shapiro # if NETINET6
82206f25ae9SGregory Neil Shapiro 			  case AF_INET6:
82306f25ae9SGregory Neil Shapiro 				if (hp->h_length != IN6ADDRSZ)
82406f25ae9SGregory Neil Shapiro 					break;
82506f25ae9SGregory Neil Shapiro 
82606f25ae9SGregory Neil Shapiro 				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
827d0cef73dSGregory Neil Shapiro 				addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
82806f25ae9SGregory Neil Shapiro 				if (addr != NULL)
829d0cef73dSGregory Neil Shapiro 					(void) sm_snprintf(ipbuf, sizeof(ipbuf),
83006f25ae9SGregory Neil Shapiro 							   "[%.100s]", addr);
83106f25ae9SGregory Neil Shapiro 				break;
83206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
83306f25ae9SGregory Neil Shapiro 			}
83406f25ae9SGregory Neil Shapiro 			if (ipbuf[0] == '\0')
83506f25ae9SGregory Neil Shapiro 				break;
83606f25ae9SGregory Neil Shapiro 
837c2aa98e2SPeter Wemm 			if (tTd(0, 4))
83840266059SGregory Neil Shapiro 				sm_dprintf("\ta.k.a.: %s\n", ipbuf);
839c2aa98e2SPeter Wemm 			setclass('w', ipbuf);
840c2aa98e2SPeter Wemm 		}
84106f25ae9SGregory Neil Shapiro #endif /* NETINET || NETINET6 */
84240266059SGregory Neil Shapiro #if NETINET6
843193538b7SGregory Neil Shapiro 		freehostent(hp);
844193538b7SGregory Neil Shapiro 		hp = NULL;
8455b0945b5SGregory Neil Shapiro #endif
846c2aa98e2SPeter Wemm 	}
847c2aa98e2SPeter Wemm 
848c2aa98e2SPeter Wemm 	/* current time */
84940266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));
85040266059SGregory Neil Shapiro 
85106f25ae9SGregory Neil Shapiro 	/* current load average */
85240266059SGregory Neil Shapiro 	sm_getla();
853c2aa98e2SPeter Wemm 
854c2aa98e2SPeter Wemm 	QueueLimitRecipient = (QUEUE_CHAR *) NULL;
855c2aa98e2SPeter Wemm 	QueueLimitSender = (QUEUE_CHAR *) NULL;
856c2aa98e2SPeter Wemm 	QueueLimitId = (QUEUE_CHAR *) NULL;
85740266059SGregory Neil Shapiro 	QueueLimitQuarantine = (QUEUE_CHAR *) NULL;
858c2aa98e2SPeter Wemm 
859c2aa98e2SPeter Wemm 	/*
860c2aa98e2SPeter Wemm 	**  Crack argv.
861c2aa98e2SPeter Wemm 	*/
862c2aa98e2SPeter Wemm 
863c2aa98e2SPeter Wemm 	optind = 1;
864c2aa98e2SPeter Wemm 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
865c2aa98e2SPeter Wemm 	{
866c2aa98e2SPeter Wemm 		switch (j)
867c2aa98e2SPeter Wemm 		{
868c2aa98e2SPeter Wemm 		  case 'b':	/* operations mode */
86940266059SGregory Neil Shapiro 			/* already done */
870c2aa98e2SPeter Wemm 			break;
871c2aa98e2SPeter Wemm 
87240266059SGregory Neil Shapiro 		  case 'A':	/* use Alternate sendmail/submit.cf */
87340266059SGregory Neil Shapiro 			cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF
87440266059SGregory Neil Shapiro 						  : SM_GET_SENDMAIL_CF;
875c2aa98e2SPeter Wemm 			break;
876c2aa98e2SPeter Wemm 
877c2aa98e2SPeter Wemm 		  case 'B':	/* body type */
87840266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
87940266059SGregory Neil Shapiro 			BlankEnvelope.e_bodytype = newstr(optarg);
880c2aa98e2SPeter Wemm 			break;
881c2aa98e2SPeter Wemm 
882c2aa98e2SPeter Wemm 		  case 'C':	/* select configuration file (already done) */
883c2aa98e2SPeter Wemm 			if (RealUid != 0)
88440266059SGregory Neil Shapiro 				warn_C_flag = true;
88540266059SGregory Neil Shapiro 			conffile = newstr(optarg);
88640266059SGregory Neil Shapiro 			dp = drop_privileges(true);
88706f25ae9SGregory Neil Shapiro 			setstat(dp);
88840266059SGregory Neil Shapiro 			safecf = false;
889c2aa98e2SPeter Wemm 			break;
890c2aa98e2SPeter Wemm 
891e92d3f3fSGregory Neil Shapiro 		  case 'D':
89240266059SGregory Neil Shapiro 		  case 'd':	/* debugging */
89340266059SGregory Neil Shapiro 			/* already done */
894c2aa98e2SPeter Wemm 			break;
895c2aa98e2SPeter Wemm 
8962fb4f839SGregory Neil Shapiro 		  case 'f':	/* fromaddr address */
897c2aa98e2SPeter Wemm 		  case 'r':	/* obsolete -f flag */
89840266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
8992fb4f839SGregory Neil Shapiro 			if (fromaddr != NULL)
900c2aa98e2SPeter Wemm 			{
901c2aa98e2SPeter Wemm 				usrerr("More than one \"from\" person");
902c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
903c2aa98e2SPeter Wemm 				break;
904c2aa98e2SPeter Wemm 			}
90513bd1963SGregory Neil Shapiro 			if (optarg[0] == '\0')
9062fb4f839SGregory Neil Shapiro 				fromaddr = newstr("<>");
90713bd1963SGregory Neil Shapiro 			else
9082fb4f839SGregory Neil Shapiro 				fromaddr = newstr(denlstring(optarg, true, true));
9092fb4f839SGregory Neil Shapiro 			if (strcmp(RealUserName, fromaddr) != 0)
910c2aa98e2SPeter Wemm 				warn_f_flag = j;
911c2aa98e2SPeter Wemm 			break;
912c2aa98e2SPeter Wemm 
913c2aa98e2SPeter Wemm 		  case 'F':	/* set full name */
91440266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
915c2aa98e2SPeter Wemm 			FullName = newstr(optarg);
916c2aa98e2SPeter Wemm 			break;
917c2aa98e2SPeter Wemm 
91806f25ae9SGregory Neil Shapiro 		  case 'G':	/* relay (gateway) submission */
91906f25ae9SGregory Neil Shapiro 			/* already set */
92040266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
92106f25ae9SGregory Neil Shapiro 			break;
92206f25ae9SGregory Neil Shapiro 
923c2aa98e2SPeter Wemm 		  case 'h':	/* hop count */
92440266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
92540266059SGregory Neil Shapiro 			BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,
92640266059SGregory Neil Shapiro 								  10);
927d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf), "%d",
92840266059SGregory Neil Shapiro 					   BlankEnvelope.e_hopcount);
92940266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);
93040266059SGregory Neil Shapiro 
931c2aa98e2SPeter Wemm 			if (*ep)
932c2aa98e2SPeter Wemm 			{
933c2aa98e2SPeter Wemm 				usrerr("Bad hop count (%s)", optarg);
934c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
935c2aa98e2SPeter Wemm 			}
936c2aa98e2SPeter Wemm 			break;
937c2aa98e2SPeter Wemm 
93806f25ae9SGregory Neil Shapiro 		  case 'L':	/* program label */
93906f25ae9SGregory Neil Shapiro 			/* already set */
94006f25ae9SGregory Neil Shapiro 			break;
94106f25ae9SGregory Neil Shapiro 
942c2aa98e2SPeter Wemm 		  case 'n':	/* don't alias */
94340266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
94440266059SGregory Neil Shapiro 			NoAlias = true;
945c2aa98e2SPeter Wemm 			break;
946c2aa98e2SPeter Wemm 
947c2aa98e2SPeter Wemm 		  case 'N':	/* delivery status notifications */
94840266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
949c2aa98e2SPeter Wemm 			DefaultNotify |= QHASNOTIFY;
95040266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
95140266059SGregory Neil Shapiro 				macid("{dsn_notify}"), optarg);
9522fb4f839SGregory Neil Shapiro 			if (SM_STRCASEEQ(optarg, "never"))
953c2aa98e2SPeter Wemm 				break;
954c2aa98e2SPeter Wemm 			for (p = optarg; p != NULL; optarg = p)
955c2aa98e2SPeter Wemm 			{
956c2aa98e2SPeter Wemm 				p = strchr(p, ',');
957c2aa98e2SPeter Wemm 				if (p != NULL)
958c2aa98e2SPeter Wemm 					*p++ = '\0';
9592fb4f839SGregory Neil Shapiro 				if (SM_STRCASEEQ(optarg, "success"))
960c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONSUCCESS;
9612fb4f839SGregory Neil Shapiro 				else if (SM_STRCASEEQ(optarg, "failure"))
962c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONFAILURE;
9632fb4f839SGregory Neil Shapiro 				else if (SM_STRCASEEQ(optarg, "delay"))
964c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONDELAY;
965c2aa98e2SPeter Wemm 				else
966c2aa98e2SPeter Wemm 				{
967c2aa98e2SPeter Wemm 					usrerr("Invalid -N argument");
968c2aa98e2SPeter Wemm 					ExitStat = EX_USAGE;
969c2aa98e2SPeter Wemm 				}
970c2aa98e2SPeter Wemm 			}
971c2aa98e2SPeter Wemm 			break;
972c2aa98e2SPeter Wemm 
973c2aa98e2SPeter Wemm 		  case 'o':	/* set option */
97440266059SGregory Neil Shapiro 			setoption(*optarg, optarg + 1, false, true,
97540266059SGregory Neil Shapiro 				  &BlankEnvelope);
976c2aa98e2SPeter Wemm 			break;
977c2aa98e2SPeter Wemm 
978c2aa98e2SPeter Wemm 		  case 'O':	/* set option (long form) */
97940266059SGregory Neil Shapiro 			setoption(' ', optarg, false, true, &BlankEnvelope);
980c2aa98e2SPeter Wemm 			break;
981c2aa98e2SPeter Wemm 
982c2aa98e2SPeter Wemm 		  case 'p':	/* set protocol */
98340266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
984c2aa98e2SPeter Wemm 			p = strchr(optarg, ':');
985c2aa98e2SPeter Wemm 			if (p != NULL)
986c2aa98e2SPeter Wemm 			{
987c2aa98e2SPeter Wemm 				*p++ = '\0';
988c2aa98e2SPeter Wemm 				if (*p != '\0')
989c2aa98e2SPeter Wemm 				{
990a7ec597cSGregory Neil Shapiro 					i = strlen(p) + 1;
991a7ec597cSGregory Neil Shapiro 					ep = sm_malloc_x(i);
992a7ec597cSGregory Neil Shapiro 					cleanstrcpy(ep, p, i);
99340266059SGregory Neil Shapiro 					macdefine(&BlankEnvelope.e_macro,
99440266059SGregory Neil Shapiro 						  A_HEAP, 's', ep);
995c2aa98e2SPeter Wemm 				}
996c2aa98e2SPeter Wemm 			}
997c2aa98e2SPeter Wemm 			if (*optarg != '\0')
998c2aa98e2SPeter Wemm 			{
999a7ec597cSGregory Neil Shapiro 				i = strlen(optarg) + 1;
1000a7ec597cSGregory Neil Shapiro 				ep = sm_malloc_x(i);
1001a7ec597cSGregory Neil Shapiro 				cleanstrcpy(ep, optarg, i);
100240266059SGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_HEAP,
100340266059SGregory Neil Shapiro 					  'r', ep);
1004c2aa98e2SPeter Wemm 			}
1005c2aa98e2SPeter Wemm 			break;
1006c2aa98e2SPeter Wemm 
100740266059SGregory Neil Shapiro 		  case 'Q':	/* change quarantining on queued items */
100840266059SGregory Neil Shapiro 			/* sanity check */
100940266059SGregory Neil Shapiro 			if (OpMode != MD_DELIVER &&
101040266059SGregory Neil Shapiro 			    OpMode != MD_QUEUERUN)
101140266059SGregory Neil Shapiro 			{
101240266059SGregory Neil Shapiro 				usrerr("Can not use -Q with -b%c", OpMode);
101340266059SGregory Neil Shapiro 				ExitStat = EX_USAGE;
101440266059SGregory Neil Shapiro 				break;
101540266059SGregory Neil Shapiro 			}
101640266059SGregory Neil Shapiro 
101740266059SGregory Neil Shapiro 			if (OpMode == MD_DELIVER)
101840266059SGregory Neil Shapiro 				set_op_mode(MD_QUEUERUN);
101940266059SGregory Neil Shapiro 
102040266059SGregory Neil Shapiro 			FullName = NULL;
102140266059SGregory Neil Shapiro 
102240266059SGregory Neil Shapiro 			quarantining = newstr(optarg);
102340266059SGregory Neil Shapiro 			break;
102440266059SGregory Neil Shapiro 
1025c2aa98e2SPeter Wemm 		  case 'q':	/* run queue files at intervals */
102606f25ae9SGregory Neil Shapiro 			/* sanity check */
102706f25ae9SGregory Neil Shapiro 			if (OpMode != MD_DELIVER &&
102806f25ae9SGregory Neil Shapiro 			    OpMode != MD_DAEMON &&
102906f25ae9SGregory Neil Shapiro 			    OpMode != MD_FGDAEMON &&
103006f25ae9SGregory Neil Shapiro 			    OpMode != MD_PRINT &&
103140266059SGregory Neil Shapiro 			    OpMode != MD_PRINTNQE &&
103206f25ae9SGregory Neil Shapiro 			    OpMode != MD_QUEUERUN)
103306f25ae9SGregory Neil Shapiro 			{
103406f25ae9SGregory Neil Shapiro 				usrerr("Can not use -q with -b%c", OpMode);
103506f25ae9SGregory Neil Shapiro 				ExitStat = EX_USAGE;
103606f25ae9SGregory Neil Shapiro 				break;
103706f25ae9SGregory Neil Shapiro 			}
103806f25ae9SGregory Neil Shapiro 
103906f25ae9SGregory Neil Shapiro 			/* don't override -bd, -bD or -bp */
104006f25ae9SGregory Neil Shapiro 			if (OpMode == MD_DELIVER)
104140266059SGregory Neil Shapiro 				set_op_mode(MD_QUEUERUN);
104206f25ae9SGregory Neil Shapiro 
1043c2aa98e2SPeter Wemm 			FullName = NULL;
104440266059SGregory Neil Shapiro 			negate = optarg[0] == '!';
104540266059SGregory Neil Shapiro 			if (negate)
104640266059SGregory Neil Shapiro 			{
104740266059SGregory Neil Shapiro 				/* negate meaning of pattern match */
104840266059SGregory Neil Shapiro 				optarg++; /* skip '!' for next switch */
104940266059SGregory Neil Shapiro 			}
105006f25ae9SGregory Neil Shapiro 
1051c2aa98e2SPeter Wemm 			switch (optarg[0])
1052c2aa98e2SPeter Wemm 			{
105340266059SGregory Neil Shapiro 			  case 'G': /* Limit by queue group name */
105440266059SGregory Neil Shapiro 				if (negate)
105540266059SGregory Neil Shapiro 				{
105640266059SGregory Neil Shapiro 					usrerr("Can not use -q!G");
105740266059SGregory Neil Shapiro 					ExitStat = EX_USAGE;
105840266059SGregory Neil Shapiro 					break;
105940266059SGregory Neil Shapiro 				}
106040266059SGregory Neil Shapiro 				if (queuegroup != NULL)
106140266059SGregory Neil Shapiro 				{
106240266059SGregory Neil Shapiro 					usrerr("Can not use multiple -qG options");
106340266059SGregory Neil Shapiro 					ExitStat = EX_USAGE;
106440266059SGregory Neil Shapiro 					break;
106540266059SGregory Neil Shapiro 				}
106640266059SGregory Neil Shapiro 				queuegroup = newstr(&optarg[1]);
106740266059SGregory Neil Shapiro 				break;
106840266059SGregory Neil Shapiro 
106940266059SGregory Neil Shapiro 			  case 'I': /* Limit by ID */
1070d0cef73dSGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1071c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
107240266059SGregory Neil Shapiro 				new->queue_negate = negate;
1073c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitId;
1074c2aa98e2SPeter Wemm 				QueueLimitId = new;
1075c2aa98e2SPeter Wemm 				break;
1076c2aa98e2SPeter Wemm 
107740266059SGregory Neil Shapiro 			  case 'R': /* Limit by recipient */
1078d0cef73dSGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1079c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
108040266059SGregory Neil Shapiro 				new->queue_negate = negate;
1081c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitRecipient;
1082c2aa98e2SPeter Wemm 				QueueLimitRecipient = new;
1083c2aa98e2SPeter Wemm 				break;
1084c2aa98e2SPeter Wemm 
108540266059SGregory Neil Shapiro 			  case 'S': /* Limit by sender */
1086d0cef73dSGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1087c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
108840266059SGregory Neil Shapiro 				new->queue_negate = negate;
1089c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitSender;
1090c2aa98e2SPeter Wemm 				QueueLimitSender = new;
1091c2aa98e2SPeter Wemm 				break;
1092c2aa98e2SPeter Wemm 
109340266059SGregory Neil Shapiro 			  case 'f': /* foreground queue run */
109440266059SGregory Neil Shapiro 				foregroundqueue  = true;
109540266059SGregory Neil Shapiro 				break;
109640266059SGregory Neil Shapiro 
109740266059SGregory Neil Shapiro 			  case 'Q': /* Limit by quarantine message */
109840266059SGregory Neil Shapiro 				if (optarg[1] != '\0')
109940266059SGregory Neil Shapiro 				{
1100d0cef73dSGregory Neil Shapiro 					new = (QUEUE_CHAR *) xalloc(sizeof(*new));
110140266059SGregory Neil Shapiro 					new->queue_match = newstr(&optarg[1]);
110240266059SGregory Neil Shapiro 					new->queue_negate = negate;
110340266059SGregory Neil Shapiro 					new->queue_next = QueueLimitQuarantine;
110440266059SGregory Neil Shapiro 					QueueLimitQuarantine = new;
110540266059SGregory Neil Shapiro 				}
110640266059SGregory Neil Shapiro 				QueueMode = QM_QUARANTINE;
110740266059SGregory Neil Shapiro 				break;
110840266059SGregory Neil Shapiro 
110940266059SGregory Neil Shapiro 			  case 'L': /* act on lost items */
111040266059SGregory Neil Shapiro 				QueueMode = QM_LOST;
111140266059SGregory Neil Shapiro 				break;
111240266059SGregory Neil Shapiro 
111340266059SGregory Neil Shapiro 			  case 'p': /* Persistent queue */
111440266059SGregory Neil Shapiro 				queuepersistent = true;
111540266059SGregory Neil Shapiro 				if (QueueIntvl == 0)
111640266059SGregory Neil Shapiro 					QueueIntvl = 1;
111740266059SGregory Neil Shapiro 				if (optarg[1] == '\0')
111840266059SGregory Neil Shapiro 					break;
111940266059SGregory Neil Shapiro 				++optarg;
112040266059SGregory Neil Shapiro 				/* FALLTHROUGH */
112140266059SGregory Neil Shapiro 
1122c2aa98e2SPeter Wemm 			  default:
112306f25ae9SGregory Neil Shapiro 				i = Errors;
1124c2aa98e2SPeter Wemm 				QueueIntvl = convtime(optarg, 'm');
1125739ac4d4SGregory Neil Shapiro 				if (QueueIntvl < 0)
1126739ac4d4SGregory Neil Shapiro 				{
1127739ac4d4SGregory Neil Shapiro 					usrerr("Invalid -q value");
1128739ac4d4SGregory Neil Shapiro 					ExitStat = EX_USAGE;
1129739ac4d4SGregory Neil Shapiro 				}
113006f25ae9SGregory Neil Shapiro 
113106f25ae9SGregory Neil Shapiro 				/* check for bad conversion */
113206f25ae9SGregory Neil Shapiro 				if (i < Errors)
113306f25ae9SGregory Neil Shapiro 					ExitStat = EX_USAGE;
1134c2aa98e2SPeter Wemm 				break;
1135c2aa98e2SPeter Wemm 			}
1136c2aa98e2SPeter Wemm 			break;
1137c2aa98e2SPeter Wemm 
1138c2aa98e2SPeter Wemm 		  case 'R':	/* DSN RET: what to return */
113940266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
114040266059SGregory Neil Shapiro 			if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))
1141c2aa98e2SPeter Wemm 			{
1142c2aa98e2SPeter Wemm 				usrerr("Duplicate -R flag");
1143c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1144c2aa98e2SPeter Wemm 				break;
1145c2aa98e2SPeter Wemm 			}
114640266059SGregory Neil Shapiro 			BlankEnvelope.e_flags |= EF_RET_PARAM;
11472fb4f839SGregory Neil Shapiro 			if (SM_STRCASEEQ(optarg, "hdrs"))
114840266059SGregory Neil Shapiro 				BlankEnvelope.e_flags |= EF_NO_BODY_RETN;
11492fb4f839SGregory Neil Shapiro 			else if (!SM_STRCASEEQ(optarg, "full"))
1150c2aa98e2SPeter Wemm 			{
1151c2aa98e2SPeter Wemm 				usrerr("Invalid -R value");
1152c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1153c2aa98e2SPeter Wemm 			}
115440266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
115540266059SGregory Neil Shapiro 				  macid("{dsn_ret}"), optarg);
1156c2aa98e2SPeter Wemm 			break;
1157c2aa98e2SPeter Wemm 
1158c2aa98e2SPeter Wemm 		  case 't':	/* read recipients from message */
115940266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
116040266059SGregory Neil Shapiro 			GrabTo = true;
1161c2aa98e2SPeter Wemm 			break;
1162c2aa98e2SPeter Wemm 
11632fb4f839SGregory Neil Shapiro #if USE_EAI
11642fb4f839SGregory Neil Shapiro 		  case 'U':
11652fb4f839SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
11662fb4f839SGregory Neil Shapiro 			BlankEnvelope.e_smtputf8 = true;
11672fb4f839SGregory Neil Shapiro 			break;
11682fb4f839SGregory Neil Shapiro #endif
11692fb4f839SGregory Neil Shapiro 
1170c2aa98e2SPeter Wemm 		  case 'V':	/* DSN ENVID: set "original" envelope id */
117140266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
1172c2aa98e2SPeter Wemm 			if (!xtextok(optarg))
1173c2aa98e2SPeter Wemm 			{
1174c2aa98e2SPeter Wemm 				usrerr("Invalid syntax in -V flag");
1175c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1176c2aa98e2SPeter Wemm 			}
1177c2aa98e2SPeter Wemm 			else
117806f25ae9SGregory Neil Shapiro 			{
117940266059SGregory Neil Shapiro 				BlankEnvelope.e_envid = newstr(optarg);
118040266059SGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
118140266059SGregory Neil Shapiro 					  macid("{dsn_envid}"), optarg);
118206f25ae9SGregory Neil Shapiro 			}
1183c2aa98e2SPeter Wemm 			break;
1184c2aa98e2SPeter Wemm 
1185c2aa98e2SPeter Wemm 		  case 'X':	/* traffic log file */
118640266059SGregory Neil Shapiro 			dp = drop_privileges(true);
118706f25ae9SGregory Neil Shapiro 			setstat(dp);
118806f25ae9SGregory Neil Shapiro 			if (stat(optarg, &traf_st) == 0 &&
118906f25ae9SGregory Neil Shapiro 			    S_ISFIFO(traf_st.st_mode))
119040266059SGregory Neil Shapiro 				TrafficLogFile = sm_io_open(SmFtStdio,
119140266059SGregory Neil Shapiro 							    SM_TIME_DEFAULT,
119240266059SGregory Neil Shapiro 							    optarg,
119340266059SGregory Neil Shapiro 							    SM_IO_WRONLY, NULL);
119406f25ae9SGregory Neil Shapiro 			else
119540266059SGregory Neil Shapiro 				TrafficLogFile = sm_io_open(SmFtStdio,
119640266059SGregory Neil Shapiro 							    SM_TIME_DEFAULT,
119740266059SGregory Neil Shapiro 							    optarg,
119840266059SGregory Neil Shapiro 							    SM_IO_APPEND, NULL);
1199c2aa98e2SPeter Wemm 			if (TrafficLogFile == NULL)
1200c2aa98e2SPeter Wemm 			{
1201c2aa98e2SPeter Wemm 				syserr("cannot open %s", optarg);
1202c2aa98e2SPeter Wemm 				ExitStat = EX_CANTCREAT;
1203c2aa98e2SPeter Wemm 				break;
1204c2aa98e2SPeter Wemm 			}
120540266059SGregory Neil Shapiro 			(void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,
120640266059SGregory Neil Shapiro 					     NULL, SM_IO_LBF, 0);
1207c2aa98e2SPeter Wemm 			break;
1208c2aa98e2SPeter Wemm 
1209c2aa98e2SPeter Wemm 			/* compatibility flags */
1210c2aa98e2SPeter Wemm 		  case 'c':	/* connect to non-local mailers */
1211c2aa98e2SPeter Wemm 		  case 'i':	/* don't let dot stop me */
1212c2aa98e2SPeter Wemm 		  case 'm':	/* send to me too */
1213c2aa98e2SPeter Wemm 		  case 'T':	/* set timeout interval */
1214c2aa98e2SPeter Wemm 		  case 'v':	/* give blow-by-blow description */
121540266059SGregory Neil Shapiro 			setoption(j, "T", false, true, &BlankEnvelope);
1216c2aa98e2SPeter Wemm 			break;
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 		  case 'e':	/* error message disposition */
1219c2aa98e2SPeter Wemm 		  case 'M':	/* define macro */
122040266059SGregory Neil Shapiro 			setoption(j, optarg, false, true, &BlankEnvelope);
1221c2aa98e2SPeter Wemm 			break;
1222c2aa98e2SPeter Wemm 
1223c2aa98e2SPeter Wemm 		  case 's':	/* save From lines in headers */
122440266059SGregory Neil Shapiro 			setoption('f', "T", false, true, &BlankEnvelope);
1225c2aa98e2SPeter Wemm 			break;
1226c2aa98e2SPeter Wemm 
1227c2aa98e2SPeter Wemm #ifdef DBM
1228c2aa98e2SPeter Wemm 		  case 'I':	/* initialize alias DBM file */
122940266059SGregory Neil Shapiro 			set_op_mode(MD_INITALIAS);
1230c2aa98e2SPeter Wemm 			break;
1231c2aa98e2SPeter Wemm #endif /* DBM */
1232c2aa98e2SPeter Wemm 
1233c2aa98e2SPeter Wemm #if defined(__osf__) || defined(_AIX3)
1234c2aa98e2SPeter Wemm 		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */
1235c2aa98e2SPeter Wemm 			break;
12365b0945b5SGregory Neil Shapiro #endif
1237c2aa98e2SPeter Wemm #if defined(sony_news)
1238c2aa98e2SPeter Wemm 		  case 'E':
1239c2aa98e2SPeter Wemm 		  case 'J':	/* ignore flags for Japanese code conversion
124006f25ae9SGregory Neil Shapiro 				   implemented on Sony NEWS */
1241c2aa98e2SPeter Wemm 			break;
124206f25ae9SGregory Neil Shapiro #endif /* defined(sony_news) */
1243c2aa98e2SPeter Wemm 
1244c2aa98e2SPeter Wemm 		  default:
124540266059SGregory Neil Shapiro 			finis(true, true, EX_USAGE);
124640266059SGregory Neil Shapiro 			/* NOTREACHED */
1247c2aa98e2SPeter Wemm 			break;
1248c2aa98e2SPeter Wemm 		}
1249c2aa98e2SPeter Wemm 	}
1250c2aa98e2SPeter Wemm 
125140266059SGregory Neil Shapiro 	/* if we've had errors so far, exit now */
12529bd497b8SGregory Neil Shapiro 	if ((ExitStat != EX_OK && OpMode != MD_TEST && OpMode != MD_CHECKCONFIG) ||
125340266059SGregory Neil Shapiro 	    ExitStat == EX_OSERR)
125406f25ae9SGregory Neil Shapiro 	{
125540266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
125640266059SGregory Neil Shapiro 		/* NOTREACHED */
125706f25ae9SGregory Neil Shapiro 	}
125806f25ae9SGregory Neil Shapiro 
125940266059SGregory Neil Shapiro 	if (bitset(SUBMIT_MTA, SubmitMode))
126006f25ae9SGregory Neil Shapiro 	{
1261739ac4d4SGregory Neil Shapiro 		/* If set daemon_flags on command line, don't reset it */
1262739ac4d4SGregory Neil Shapiro 		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
126340266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_PERM,
126440266059SGregory Neil Shapiro 				  macid("{daemon_flags}"), "CC f");
126506f25ae9SGregory Neil Shapiro 	}
126640266059SGregory Neil Shapiro 	else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)
126706f25ae9SGregory Neil Shapiro 	{
126840266059SGregory Neil Shapiro 		SubmitMode = SUBMIT_MSA;
1269739ac4d4SGregory Neil Shapiro 
1270739ac4d4SGregory Neil Shapiro 		/* If set daemon_flags on command line, don't reset it */
1271739ac4d4SGregory Neil Shapiro 		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
127240266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_PERM,
127340266059SGregory Neil Shapiro 				  macid("{daemon_flags}"), "c u");
127406f25ae9SGregory Neil Shapiro 	}
127506f25ae9SGregory Neil Shapiro 
1276c2aa98e2SPeter Wemm 	/*
1277c2aa98e2SPeter Wemm 	**  Do basic initialization.
1278c2aa98e2SPeter Wemm 	**	Read system control file.
1279c2aa98e2SPeter Wemm 	**	Extract special fields for local use.
1280c2aa98e2SPeter Wemm 	*/
1281c2aa98e2SPeter Wemm 
1282c2aa98e2SPeter Wemm 	checkfd012("before readcf");
128340266059SGregory Neil Shapiro 	vendor_pre_defaults(&BlankEnvelope);
128406f25ae9SGregory Neil Shapiro 
128540266059SGregory Neil Shapiro 	readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
128640266059SGregory Neil Shapiro 			 safecf, &BlankEnvelope);
128740266059SGregory Neil Shapiro #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
128840266059SGregory Neil Shapiro 	ConfigFileRead = true;
12895b0945b5SGregory Neil Shapiro #endif
129040266059SGregory Neil Shapiro 	vendor_post_defaults(&BlankEnvelope);
129140266059SGregory Neil Shapiro 
129240266059SGregory Neil Shapiro 	/* now we can complain about missing fds */
129340266059SGregory Neil Shapiro 	if (MissingFds != 0 && LogLevel > 8)
129440266059SGregory Neil Shapiro 	{
129540266059SGregory Neil Shapiro 		char mbuf[MAXLINE];
129640266059SGregory Neil Shapiro 
129740266059SGregory Neil Shapiro 		mbuf[0] = '\0';
129840266059SGregory Neil Shapiro 		if (bitset(1 << STDIN_FILENO, MissingFds))
1299d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stdin", sizeof(mbuf));
130040266059SGregory Neil Shapiro 		if (bitset(1 << STDOUT_FILENO, MissingFds))
1301d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stdout", sizeof(mbuf));
130240266059SGregory Neil Shapiro 		if (bitset(1 << STDERR_FILENO, MissingFds))
1303d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stderr", sizeof(mbuf));
130440266059SGregory Neil Shapiro 
130540266059SGregory Neil Shapiro 		/* Notice: fill_errno is from high above: fill_fd() */
130640266059SGregory Neil Shapiro 		sm_syslog(LOG_WARNING, NOQID,
130740266059SGregory Neil Shapiro 			  "File descriptors missing on startup: %s; %s",
130840266059SGregory Neil Shapiro 			  &mbuf[2], sm_errstring(fill_errno));
130940266059SGregory Neil Shapiro 	}
1310c2aa98e2SPeter Wemm 
13118774250cSGregory Neil Shapiro 	/* Remove the ability for a normal user to send signals */
131240266059SGregory Neil Shapiro 	if (RealUid != 0 && RealUid != geteuid())
13138774250cSGregory Neil Shapiro 	{
13148774250cSGregory Neil Shapiro 		uid_t new_uid = geteuid();
13158774250cSGregory Neil Shapiro 
13168774250cSGregory Neil Shapiro #if HASSETREUID
13178774250cSGregory Neil Shapiro 		/*
13188774250cSGregory Neil Shapiro 		**  Since we can differentiate between uid and euid,
13198774250cSGregory Neil Shapiro 		**  make the uid a different user so the real user
13208774250cSGregory Neil Shapiro 		**  can't send signals.  However, it doesn't need to be
13218774250cSGregory Neil Shapiro 		**  root (euid has root).
13228774250cSGregory Neil Shapiro 		*/
13238774250cSGregory Neil Shapiro 
13248774250cSGregory Neil Shapiro 		if (new_uid == 0)
13258774250cSGregory Neil Shapiro 			new_uid = DefUid;
13268774250cSGregory Neil Shapiro 		if (tTd(47, 5))
132740266059SGregory Neil Shapiro 			sm_dprintf("Changing real uid to %d\n", (int) new_uid);
13288774250cSGregory Neil Shapiro 		if (setreuid(new_uid, geteuid()) < 0)
13298774250cSGregory Neil Shapiro 		{
13308774250cSGregory Neil Shapiro 			syserr("main: setreuid(%d, %d) failed",
13318774250cSGregory Neil Shapiro 			       (int) new_uid, (int) geteuid());
133240266059SGregory Neil Shapiro 			finis(false, true, EX_OSERR);
13338774250cSGregory Neil Shapiro 			/* NOTREACHED */
13348774250cSGregory Neil Shapiro 		}
13358774250cSGregory Neil Shapiro 		if (tTd(47, 10))
133640266059SGregory Neil Shapiro 			sm_dprintf("Now running as e/ruid %d:%d\n",
13378774250cSGregory Neil Shapiro 				   (int) geteuid(), (int) getuid());
13388774250cSGregory Neil Shapiro #else /* HASSETREUID */
13398774250cSGregory Neil Shapiro 		/*
13408774250cSGregory Neil Shapiro 		**  Have to change both effective and real so need to
13418774250cSGregory Neil Shapiro 		**  change them both to effective to keep privs.
13428774250cSGregory Neil Shapiro 		*/
13438774250cSGregory Neil Shapiro 
13448774250cSGregory Neil Shapiro 		if (tTd(47, 5))
134540266059SGregory Neil Shapiro 			sm_dprintf("Changing uid to %d\n", (int) new_uid);
13468774250cSGregory Neil Shapiro 		if (setuid(new_uid) < 0)
13478774250cSGregory Neil Shapiro 		{
13488774250cSGregory Neil Shapiro 			syserr("main: setuid(%d) failed", (int) new_uid);
134940266059SGregory Neil Shapiro 			finis(false, true, EX_OSERR);
13508774250cSGregory Neil Shapiro 			/* NOTREACHED */
13518774250cSGregory Neil Shapiro 		}
13528774250cSGregory Neil Shapiro 		if (tTd(47, 10))
135340266059SGregory Neil Shapiro 			sm_dprintf("Now running as e/ruid %d:%d\n",
13548774250cSGregory Neil Shapiro 				   (int) geteuid(), (int) getuid());
13558774250cSGregory Neil Shapiro #endif /* HASSETREUID */
13568774250cSGregory Neil Shapiro 	}
13578774250cSGregory Neil Shapiro 
135840266059SGregory Neil Shapiro #if NAMED_BIND
1359e92d3f3fSGregory Neil Shapiro 	if (FallbackMX != NULL)
1360e92d3f3fSGregory Neil Shapiro 		(void) getfallbackmxrr(FallbackMX);
13615b0945b5SGregory Neil Shapiro #endif
136240266059SGregory Neil Shapiro 
13636f9c8e5bSGregory Neil Shapiro 	if (SuperSafe == SAFE_INTERACTIVE && !SM_IS_INTERACTIVE(CurEnv->e_sendmode))
136440266059SGregory Neil Shapiro 	{
136540266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
136640266059SGregory Neil Shapiro 				     "WARNING: SuperSafe=interactive should only be used with\n         DeliveryMode=interactive\n");
136740266059SGregory Neil Shapiro 	}
136840266059SGregory Neil Shapiro 
136940266059SGregory Neil Shapiro 	if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))
137040266059SGregory Neil Shapiro 	{
137140266059SGregory Neil Shapiro 		usrerr("Mail submission program cannot be used as daemon");
137240266059SGregory Neil Shapiro 		finis(false, true, EX_USAGE);
137340266059SGregory Neil Shapiro 	}
137440266059SGregory Neil Shapiro 
137540266059SGregory Neil Shapiro 	if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||
137640266059SGregory Neil Shapiro 	    OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||
137740266059SGregory Neil Shapiro 	    OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)
137840266059SGregory Neil Shapiro 		makeworkgroups();
137940266059SGregory Neil Shapiro 
13802fb4f839SGregory Neil Shapiro #if USE_EAI
1381d39bd2c1SGregory Neil Shapiro 	if (!SMTP_UTF8 && MainEnvelope.e_smtputf8)
13822fb4f839SGregory Neil Shapiro 	{
13832fb4f839SGregory Neil Shapiro 		usrerr("-U requires SMTPUTF8");
13842fb4f839SGregory Neil Shapiro 		finis(false, true, EX_USAGE);
13852fb4f839SGregory Neil Shapiro 	}
13862fb4f839SGregory Neil Shapiro #endif
13872fb4f839SGregory Neil Shapiro 
13888774250cSGregory Neil Shapiro 	/* set up the basic signal handlers */
138940266059SGregory Neil Shapiro 	if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)
139040266059SGregory Neil Shapiro 		(void) sm_signal(SIGINT, intsig);
139140266059SGregory Neil Shapiro 	(void) sm_signal(SIGTERM, intsig);
13928774250cSGregory Neil Shapiro 
1393c2aa98e2SPeter Wemm 	/* Enforce use of local time (null string overrides this) */
1394c2aa98e2SPeter Wemm 	if (TimeZoneSpec == NULL)
1395c2aa98e2SPeter Wemm 		unsetenv("TZ");
1396c2aa98e2SPeter Wemm 	else if (TimeZoneSpec[0] != '\0')
13974e4196cbSGregory Neil Shapiro 		sm_setuserenv("TZ", TimeZoneSpec);
1398c2aa98e2SPeter Wemm 	else
13994e4196cbSGregory Neil Shapiro 		sm_setuserenv("TZ", NULL);
1400c2aa98e2SPeter Wemm 	tzset();
1401c2aa98e2SPeter Wemm 
140240266059SGregory Neil Shapiro 	/* initialize mailbox database */
140340266059SGregory Neil Shapiro 	i = sm_mbdb_initialize(Mbdb);
140440266059SGregory Neil Shapiro 	if (i != EX_OK)
140540266059SGregory Neil Shapiro 	{
140640266059SGregory Neil Shapiro 		usrerr("Can't initialize mailbox database \"%s\": %s",
140740266059SGregory Neil Shapiro 		       Mbdb, sm_strexit(i));
140840266059SGregory Neil Shapiro 		ExitStat = i;
140940266059SGregory Neil Shapiro 	}
141040266059SGregory Neil Shapiro 
1411c2aa98e2SPeter Wemm 	/* avoid denial-of-service attacks */
1412c2aa98e2SPeter Wemm 	resetlimits();
1413c2aa98e2SPeter Wemm 
141440266059SGregory Neil Shapiro 	if (OpMode == MD_TEST)
141540266059SGregory Neil Shapiro 	{
141640266059SGregory Neil Shapiro 		/* can't be done after readcf if RunAs* is used */
141740266059SGregory Neil Shapiro 		dp = drop_privileges(true);
141840266059SGregory Neil Shapiro 		if (dp != EX_OK)
141940266059SGregory Neil Shapiro 		{
142040266059SGregory Neil Shapiro 			finis(false, true, dp);
142140266059SGregory Neil Shapiro 			/* NOTREACHED */
142240266059SGregory Neil Shapiro 		}
142340266059SGregory Neil Shapiro 	}
142440266059SGregory Neil Shapiro 	else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
1425c2aa98e2SPeter Wemm 	{
1426c2aa98e2SPeter Wemm 		/* drop privileges -- daemon mode done after socket/bind */
142740266059SGregory Neil Shapiro 		dp = drop_privileges(false);
142806f25ae9SGregory Neil Shapiro 		setstat(dp);
142940266059SGregory Neil Shapiro 		if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))
143040266059SGregory Neil Shapiro 		{
143140266059SGregory Neil Shapiro 			usrerr("Mail submission program must have RunAsUser set to non root user");
143240266059SGregory Neil Shapiro 			finis(false, true, EX_CONFIG);
143340266059SGregory Neil Shapiro 			/* NOTREACHED */
143440266059SGregory Neil Shapiro 		}
1435c2aa98e2SPeter Wemm 	}
1436c2aa98e2SPeter Wemm 
143706f25ae9SGregory Neil Shapiro #if NAMED_BIND
143806f25ae9SGregory Neil Shapiro 	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
143906f25ae9SGregory Neil Shapiro 	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
14405b0945b5SGregory Neil Shapiro #endif
144106f25ae9SGregory Neil Shapiro 
1442c2aa98e2SPeter Wemm 	/*
1443c2aa98e2SPeter Wemm 	**  Find our real host name for future logging.
1444c2aa98e2SPeter Wemm 	*/
1445c2aa98e2SPeter Wemm 
144606f25ae9SGregory Neil Shapiro 	authinfo = getauthinfo(STDIN_FILENO, &forged);
144740266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
1448c2aa98e2SPeter Wemm 
1449c2aa98e2SPeter Wemm 	/* suppress error printing if errors mailed back or whatever */
145040266059SGregory Neil Shapiro 	if (BlankEnvelope.e_errormode != EM_PRINT)
145140266059SGregory Neil Shapiro 		HoldErrs = true;
1452c2aa98e2SPeter Wemm 
1453c2aa98e2SPeter Wemm 	/* set up the $=m class now, after .cf has a chance to redefine $m */
1454d0cef73dSGregory Neil Shapiro 	expand("\201m", jbuf, sizeof(jbuf), &BlankEnvelope);
1455602a2b1bSGregory Neil Shapiro 	if (jbuf[0] != '\0')
1456c2aa98e2SPeter Wemm 		setclass('m', jbuf);
1457c2aa98e2SPeter Wemm 
1458c2aa98e2SPeter Wemm 	/* probe interfaces and locate any additional names */
145940266059SGregory Neil Shapiro 	if (DontProbeInterfaces != DPI_PROBENONE)
1460c2aa98e2SPeter Wemm 		load_if_names();
1461c2aa98e2SPeter Wemm 
146240266059SGregory Neil Shapiro 	if (tTd(0, 10))
146340266059SGregory Neil Shapiro 	{
146413bd1963SGregory Neil Shapiro 		char pidpath[MAXPATHLEN];
146513bd1963SGregory Neil Shapiro 
146640266059SGregory Neil Shapiro 		/* Now we know which .cf file we use */
146740266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (selected)\n",
146840266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, cftype, conffile));
1469d0cef73dSGregory Neil Shapiro 		expand(PidFile, pidpath, sizeof(pidpath), &BlankEnvelope);
147013bd1963SGregory Neil Shapiro 		sm_dprintf("      Pid file:\t%s (selected)\n", pidpath);
147140266059SGregory Neil Shapiro 	}
147240266059SGregory Neil Shapiro 
1473c2aa98e2SPeter Wemm 	if (tTd(0, 1))
1474c2aa98e2SPeter Wemm 	{
147540266059SGregory Neil Shapiro 		sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
147640266059SGregory Neil Shapiro 		sm_dprintf("\n      (short domain name) $w = ");
1477e92d3f3fSGregory Neil Shapiro 		xputs(sm_debug_file(), macvalue('w', &BlankEnvelope));
147840266059SGregory Neil Shapiro 		sm_dprintf("\n  (canonical domain name) $j = ");
1479e92d3f3fSGregory Neil Shapiro 		xputs(sm_debug_file(), macvalue('j', &BlankEnvelope));
148040266059SGregory Neil Shapiro 		sm_dprintf("\n         (subdomain name) $m = ");
1481e92d3f3fSGregory Neil Shapiro 		xputs(sm_debug_file(), macvalue('m', &BlankEnvelope));
148240266059SGregory Neil Shapiro 		sm_dprintf("\n              (node name) $k = ");
1483e92d3f3fSGregory Neil Shapiro 		xputs(sm_debug_file(), macvalue('k', &BlankEnvelope));
148440266059SGregory Neil Shapiro 		sm_dprintf("\n========================================================\n\n");
1485c2aa98e2SPeter Wemm 	}
1486c2aa98e2SPeter Wemm 
1487c2aa98e2SPeter Wemm 	/*
1488c2aa98e2SPeter Wemm 	**  Do more command line checking -- these are things that
1489c2aa98e2SPeter Wemm 	**  have to modify the results of reading the config file.
1490c2aa98e2SPeter Wemm 	*/
1491c2aa98e2SPeter Wemm 
1492c2aa98e2SPeter Wemm 	/* process authorization warnings from command line */
1493c2aa98e2SPeter Wemm 	if (warn_C_flag)
149440266059SGregory Neil Shapiro 		auth_warning(&BlankEnvelope, "Processed by %s with -C %s",
149540266059SGregory Neil Shapiro 			     RealUserName, conffile);
149606f25ae9SGregory Neil Shapiro 	if (Warn_Q_option && !wordinclass(RealUserName, 't'))
149740266059SGregory Neil Shapiro 		auth_warning(&BlankEnvelope, "Processed from queue %s",
149840266059SGregory Neil Shapiro 			     QueueDir);
149940266059SGregory Neil Shapiro 	if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&
150040266059SGregory Neil Shapiro 	    RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)
150140266059SGregory Neil Shapiro 		sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",
150240266059SGregory Neil Shapiro 			  (int) RealUid);
1503c2aa98e2SPeter Wemm 
1504c2aa98e2SPeter Wemm 	/* check body type for legality */
150540266059SGregory Neil Shapiro 	i = check_bodytype(BlankEnvelope.e_bodytype);
150640266059SGregory Neil Shapiro 	if (i == BODYTYPE_ILLEGAL)
1507c2aa98e2SPeter Wemm 	{
150840266059SGregory Neil Shapiro 		usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
150940266059SGregory Neil Shapiro 		BlankEnvelope.e_bodytype = NULL;
1510c2aa98e2SPeter Wemm 	}
1511d39bd2c1SGregory Neil Shapiro 	else if (BODYTYPE_7BIT == i)
1512d39bd2c1SGregory Neil Shapiro 		BlankEnvelope.e_flags |= EF_7BITBODY;
1513c2aa98e2SPeter Wemm 
1514c2aa98e2SPeter Wemm 	/* tweak default DSN notifications */
1515c2aa98e2SPeter Wemm 	if (DefaultNotify == 0)
1516c2aa98e2SPeter Wemm 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1517c2aa98e2SPeter Wemm 
1518c2aa98e2SPeter Wemm 	/* check for sane configuration level */
1519c2aa98e2SPeter Wemm 	if (ConfigLevel > MAXCONFIGLEVEL)
1520c2aa98e2SPeter Wemm 	{
1521c2aa98e2SPeter Wemm 		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1522c2aa98e2SPeter Wemm 		       ConfigLevel, Version, MAXCONFIGLEVEL);
1523c2aa98e2SPeter Wemm 	}
1524c2aa98e2SPeter Wemm 
1525c2aa98e2SPeter Wemm 	/* need MCI cache to have persistence */
1526c2aa98e2SPeter Wemm 	if (HostStatDir != NULL && MaxMciCache == 0)
1527c2aa98e2SPeter Wemm 	{
1528c2aa98e2SPeter Wemm 		HostStatDir = NULL;
152940266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
153040266059SGregory Neil Shapiro 				     "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1531c2aa98e2SPeter Wemm 	}
1532c2aa98e2SPeter Wemm 
1533c2aa98e2SPeter Wemm 	/* need HostStatusDir in order to have SingleThreadDelivery */
1534c2aa98e2SPeter Wemm 	if (SingleThreadDelivery && HostStatDir == NULL)
1535c2aa98e2SPeter Wemm 	{
153640266059SGregory Neil Shapiro 		SingleThreadDelivery = false;
153740266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
153840266059SGregory Neil Shapiro 				     "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1539c2aa98e2SPeter Wemm 	}
1540c2aa98e2SPeter Wemm 
15414e4196cbSGregory Neil Shapiro #if _FFR_MEMSTAT
15424e4196cbSGregory Neil Shapiro 	j = sm_memstat_open();
15434e4196cbSGregory Neil Shapiro 	if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4)
15444e4196cbSGregory Neil Shapiro 	{
15454e4196cbSGregory Neil Shapiro 		sm_syslog(LOG_WARNING, NOQID,
15464e4196cbSGregory Neil Shapiro 			  "cannot get memory statistics, settings ignored, error=%d"
15474e4196cbSGregory Neil Shapiro 			  , j);
15484e4196cbSGregory Neil Shapiro 	}
15494e4196cbSGregory Neil Shapiro #endif /* _FFR_MEMSTAT */
15504e4196cbSGregory Neil Shapiro 
1551c2aa98e2SPeter Wemm 	/* check for permissions */
155240266059SGregory Neil Shapiro 	if (RealUid != 0 &&
1553065a643dSPeter Wemm 	    RealUid != TrustedUid)
1554c2aa98e2SPeter Wemm 	{
155540266059SGregory Neil Shapiro 		char *action = NULL;
155640266059SGregory Neil Shapiro 
155740266059SGregory Neil Shapiro 		switch (OpMode)
155840266059SGregory Neil Shapiro 		{
155940266059SGregory Neil Shapiro 		  case MD_QUEUERUN:
156040266059SGregory Neil Shapiro 			if (quarantining != NULL)
156140266059SGregory Neil Shapiro 				action = "quarantine jobs";
156240266059SGregory Neil Shapiro 			else
1563e92d3f3fSGregory Neil Shapiro 			{
156440266059SGregory Neil Shapiro 				/* Normal users can do a single queue run */
156540266059SGregory Neil Shapiro 				if (QueueIntvl == 0)
156640266059SGregory Neil Shapiro 					break;
1567e92d3f3fSGregory Neil Shapiro 			}
156840266059SGregory Neil Shapiro 
156940266059SGregory Neil Shapiro 			/* but not persistent queue runners */
157040266059SGregory Neil Shapiro 			if (action == NULL)
157140266059SGregory Neil Shapiro 				action = "start a queue runner daemon";
157240266059SGregory Neil Shapiro 			/* FALLTHROUGH */
157340266059SGregory Neil Shapiro 
157440266059SGregory Neil Shapiro 		  case MD_PURGESTAT:
157540266059SGregory Neil Shapiro 			if (action == NULL)
157640266059SGregory Neil Shapiro 				action = "purge host status";
157740266059SGregory Neil Shapiro 			/* FALLTHROUGH */
157840266059SGregory Neil Shapiro 
157940266059SGregory Neil Shapiro 		  case MD_DAEMON:
158040266059SGregory Neil Shapiro 		  case MD_FGDAEMON:
158140266059SGregory Neil Shapiro 			if (action == NULL)
158240266059SGregory Neil Shapiro 				action = "run daemon";
158340266059SGregory Neil Shapiro 
158440266059SGregory Neil Shapiro 			if (tTd(65, 1))
158540266059SGregory Neil Shapiro 				sm_dprintf("Deny user %d attempt to %s\n",
158640266059SGregory Neil Shapiro 					   (int) RealUid, action);
158740266059SGregory Neil Shapiro 
1588c2aa98e2SPeter Wemm 			if (LogLevel > 1)
1589c2aa98e2SPeter Wemm 				sm_syslog(LOG_ALERT, NOQID,
1590c2aa98e2SPeter Wemm 					  "user %d attempted to %s",
159140266059SGregory Neil Shapiro 					  (int) RealUid, action);
159240266059SGregory Neil Shapiro 			HoldErrs = false;
159340266059SGregory Neil Shapiro 			usrerr("Permission denied (real uid not trusted)");
159440266059SGregory Neil Shapiro 			finis(false, true, EX_USAGE);
159540266059SGregory Neil Shapiro 			/* NOTREACHED */
159640266059SGregory Neil Shapiro 			break;
159740266059SGregory Neil Shapiro 
159840266059SGregory Neil Shapiro 		  case MD_VERIFY:
159940266059SGregory Neil Shapiro 			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))
1600b518ca7dSPeter Wemm 			{
160140266059SGregory Neil Shapiro 				/*
160240266059SGregory Neil Shapiro 				**  If -bv and RestrictExpand,
160340266059SGregory Neil Shapiro 				**  drop privs to prevent normal
160440266059SGregory Neil Shapiro 				**  users from reading private
160540266059SGregory Neil Shapiro 				**  aliases/forwards/:include:s
160640266059SGregory Neil Shapiro 				*/
160740266059SGregory Neil Shapiro 
160840266059SGregory Neil Shapiro 				if (tTd(65, 1))
160940266059SGregory Neil Shapiro 					sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",
161040266059SGregory Neil Shapiro 						   (int) RealUid);
161140266059SGregory Neil Shapiro 
161240266059SGregory Neil Shapiro 				dp = drop_privileges(true);
161340266059SGregory Neil Shapiro 
161440266059SGregory Neil Shapiro 				/* Fake address safety */
161540266059SGregory Neil Shapiro 				if (tTd(65, 1))
161640266059SGregory Neil Shapiro 					sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");
161740266059SGregory Neil Shapiro 				setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);
161840266059SGregory Neil Shapiro 
161940266059SGregory Neil Shapiro 				if (dp != EX_OK)
162040266059SGregory Neil Shapiro 				{
162140266059SGregory Neil Shapiro 					if (tTd(65, 1))
162240266059SGregory Neil Shapiro 						sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",
162340266059SGregory Neil Shapiro 							   (int) RealUid);
162440266059SGregory Neil Shapiro 					CurEnv->e_id = NULL;
162540266059SGregory Neil Shapiro 					finis(true, true, dp);
162640266059SGregory Neil Shapiro 					/* NOTREACHED */
162740266059SGregory Neil Shapiro 				}
162840266059SGregory Neil Shapiro 			}
162940266059SGregory Neil Shapiro 			break;
163040266059SGregory Neil Shapiro 
163140266059SGregory Neil Shapiro 		  case MD_TEST:
16329bd497b8SGregory Neil Shapiro 		  case MD_CHECKCONFIG:
163340266059SGregory Neil Shapiro 		  case MD_PRINT:
163440266059SGregory Neil Shapiro 		  case MD_PRINTNQE:
163540266059SGregory Neil Shapiro 		  case MD_FREEZE:
163640266059SGregory Neil Shapiro 		  case MD_HOSTSTAT:
163740266059SGregory Neil Shapiro 			/* Nothing special to check */
163840266059SGregory Neil Shapiro 			break;
163940266059SGregory Neil Shapiro 
164040266059SGregory Neil Shapiro 		  case MD_INITALIAS:
164140266059SGregory Neil Shapiro 			if (!wordinclass(RealUserName, 't'))
164240266059SGregory Neil Shapiro 			{
164340266059SGregory Neil Shapiro 				if (tTd(65, 1))
164440266059SGregory Neil Shapiro 					sm_dprintf("Deny user %d attempt to rebuild the alias map\n",
164540266059SGregory Neil Shapiro 						   (int) RealUid);
1646b518ca7dSPeter Wemm 				if (LogLevel > 1)
1647b518ca7dSPeter Wemm 					sm_syslog(LOG_ALERT, NOQID,
1648b518ca7dSPeter Wemm 						  "user %d attempted to rebuild the alias map",
164940266059SGregory Neil Shapiro 						  (int) RealUid);
165040266059SGregory Neil Shapiro 				HoldErrs = false;
165140266059SGregory Neil Shapiro 				usrerr("Permission denied (real uid not trusted)");
165240266059SGregory Neil Shapiro 				finis(false, true, EX_USAGE);
165340266059SGregory Neil Shapiro 				/* NOTREACHED */
165440266059SGregory Neil Shapiro 			}
165540266059SGregory Neil Shapiro 			if (UseMSP)
165640266059SGregory Neil Shapiro 			{
165740266059SGregory Neil Shapiro 				HoldErrs = false;
165840266059SGregory Neil Shapiro 				usrerr("User %d cannot rebuild aliases in mail submission program",
165940266059SGregory Neil Shapiro 				       (int) RealUid);
166040266059SGregory Neil Shapiro 				finis(false, true, EX_USAGE);
166140266059SGregory Neil Shapiro 				/* NOTREACHED */
166240266059SGregory Neil Shapiro 			}
166340266059SGregory Neil Shapiro 			/* FALLTHROUGH */
166440266059SGregory Neil Shapiro 
166540266059SGregory Neil Shapiro 		  default:
166640266059SGregory Neil Shapiro 			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&
166740266059SGregory Neil Shapiro 			    Verbose != 0)
166840266059SGregory Neil Shapiro 			{
166940266059SGregory Neil Shapiro 				/*
167040266059SGregory Neil Shapiro 				**  If -v and RestrictExpand, reset
167140266059SGregory Neil Shapiro 				**  Verbose to prevent normal users
167240266059SGregory Neil Shapiro 				**  from seeing the expansion of
167340266059SGregory Neil Shapiro 				**  aliases/forwards/:include:s
167440266059SGregory Neil Shapiro 				*/
167540266059SGregory Neil Shapiro 
167640266059SGregory Neil Shapiro 				if (tTd(65, 1))
167740266059SGregory Neil Shapiro 					sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",
167840266059SGregory Neil Shapiro 						   (int) RealUid);
167940266059SGregory Neil Shapiro 				Verbose = 0;
168040266059SGregory Neil Shapiro 			}
168140266059SGregory Neil Shapiro 			break;
168240266059SGregory Neil Shapiro 		}
1683b518ca7dSPeter Wemm 	}
1684c2aa98e2SPeter Wemm 
1685c2aa98e2SPeter Wemm 	if (MeToo)
1686c2aa98e2SPeter Wemm 		BlankEnvelope.e_flags |= EF_METOO;
1687c2aa98e2SPeter Wemm 
1688c2aa98e2SPeter Wemm 	switch (OpMode)
1689c2aa98e2SPeter Wemm 	{
1690c2aa98e2SPeter Wemm 	  case MD_TEST:
1691c2aa98e2SPeter Wemm 		/* don't have persistent host status in test mode */
1692c2aa98e2SPeter Wemm 		HostStatDir = NULL;
16939bd497b8SGregory Neil Shapiro 		/* FALLTHROUGH */
16949bd497b8SGregory Neil Shapiro 
16959bd497b8SGregory Neil Shapiro 	  case MD_CHECKCONFIG:
1696c2aa98e2SPeter Wemm 		if (Verbose == 0)
1697c2aa98e2SPeter Wemm 			Verbose = 2;
169840266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
169940266059SGregory Neil Shapiro 		HoldErrs = false;
1700c2aa98e2SPeter Wemm 		break;
1701c2aa98e2SPeter Wemm 
1702c2aa98e2SPeter Wemm 	  case MD_VERIFY:
170340266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
170440266059SGregory Neil Shapiro 		HoldErrs = false;
1705c2aa98e2SPeter Wemm 		/* arrange to exit cleanly on hangup signal */
170640266059SGregory Neil Shapiro 		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
170740266059SGregory Neil Shapiro 			(void) sm_signal(SIGHUP, intsig);
170840266059SGregory Neil Shapiro 		if (geteuid() != 0)
170940266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
171040266059SGregory Neil Shapiro 					     "Notice: -bv may give misleading output for non-privileged user\n");
1711c2aa98e2SPeter Wemm 		break;
1712c2aa98e2SPeter Wemm 
1713c2aa98e2SPeter Wemm 	  case MD_FGDAEMON:
171440266059SGregory Neil Shapiro 		run_in_foreground = true;
171540266059SGregory Neil Shapiro 		set_op_mode(MD_DAEMON);
171606f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
1717c2aa98e2SPeter Wemm 
1718c2aa98e2SPeter Wemm 	  case MD_DAEMON:
171940266059SGregory Neil Shapiro 		vendor_daemon_setup(&BlankEnvelope);
1720c2aa98e2SPeter Wemm 
1721c2aa98e2SPeter Wemm 		/* remove things that don't make sense in daemon mode */
1722c2aa98e2SPeter Wemm 		FullName = NULL;
172340266059SGregory Neil Shapiro 		GrabTo = false;
1724c2aa98e2SPeter Wemm 
1725c2aa98e2SPeter Wemm 		/* arrange to restart on hangup signal */
1726c2aa98e2SPeter Wemm 		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1727c2aa98e2SPeter Wemm 			sm_syslog(LOG_WARNING, NOQID,
1728c2aa98e2SPeter Wemm 				  "daemon invoked without full pathname; kill -1 won't work");
1729c2aa98e2SPeter Wemm 		break;
1730c2aa98e2SPeter Wemm 
1731c2aa98e2SPeter Wemm 	  case MD_INITALIAS:
1732c2aa98e2SPeter Wemm 		Verbose = 2;
173340266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
173440266059SGregory Neil Shapiro 		HoldErrs = false;
173506f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
1736c2aa98e2SPeter Wemm 
1737c2aa98e2SPeter Wemm 	  default:
1738c2aa98e2SPeter Wemm 		/* arrange to exit cleanly on hangup signal */
173940266059SGregory Neil Shapiro 		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
174040266059SGregory Neil Shapiro 			(void) sm_signal(SIGHUP, intsig);
1741c2aa98e2SPeter Wemm 		break;
1742c2aa98e2SPeter Wemm 	}
1743c2aa98e2SPeter Wemm 
1744c2aa98e2SPeter Wemm 	/* special considerations for FullName */
1745c2aa98e2SPeter Wemm 	if (FullName != NULL)
1746c2aa98e2SPeter Wemm 	{
1747c2aa98e2SPeter Wemm 		char *full = NULL;
1748c2aa98e2SPeter Wemm 
1749c2aa98e2SPeter Wemm 		/* full names can't have newlines */
1750c2aa98e2SPeter Wemm 		if (strchr(FullName, '\n') != NULL)
1751c2aa98e2SPeter Wemm 		{
175240266059SGregory Neil Shapiro 			full = newstr(denlstring(FullName, true, true));
1753602a2b1bSGregory Neil Shapiro 			FullName = full;
1754c2aa98e2SPeter Wemm 		}
1755602a2b1bSGregory Neil Shapiro 
1756c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1757c2aa98e2SPeter Wemm 		if (!rfc822_string(FullName))
1758c2aa98e2SPeter Wemm 		{
1759c2aa98e2SPeter Wemm 			/*
1760c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
1761c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
1762c2aa98e2SPeter Wemm 			**  the name portion of the address.
1763c2aa98e2SPeter Wemm 			*/
1764602a2b1bSGregory Neil Shapiro 
176540266059SGregory Neil Shapiro 			FullName = addquotes(FullName, NULL);
1766c2aa98e2SPeter Wemm 			if (full != NULL)
176740266059SGregory Neil Shapiro 				sm_free(full);  /* XXX */
1768c2aa98e2SPeter Wemm 		}
1769c2aa98e2SPeter Wemm 	}
1770c2aa98e2SPeter Wemm 
1771c2aa98e2SPeter Wemm 	/* do heuristic mode adjustment */
1772c2aa98e2SPeter Wemm 	if (Verbose)
1773c2aa98e2SPeter Wemm 	{
1774c2aa98e2SPeter Wemm 		/* turn off noconnect option */
177540266059SGregory Neil Shapiro 		setoption('c', "F", true, false, &BlankEnvelope);
1776c2aa98e2SPeter Wemm 
1777c2aa98e2SPeter Wemm 		/* turn on interactive delivery */
177840266059SGregory Neil Shapiro 		setoption('d', "", true, false, &BlankEnvelope);
1779c2aa98e2SPeter Wemm 	}
1780c2aa98e2SPeter Wemm 
1781065a643dSPeter Wemm #ifdef VENDOR_CODE
1782065a643dSPeter Wemm 	/* check for vendor mismatch */
1783065a643dSPeter Wemm 	if (VendorCode != VENDOR_CODE)
1784065a643dSPeter Wemm 	{
1785065a643dSPeter Wemm 		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1786065a643dSPeter Wemm 			getvendor(VENDOR_CODE), getvendor(VendorCode));
1787065a643dSPeter Wemm 	}
178806f25ae9SGregory Neil Shapiro #endif /* VENDOR_CODE */
1789065a643dSPeter Wemm 
1790c2aa98e2SPeter Wemm 	/* check for out of date configuration level */
1791c2aa98e2SPeter Wemm 	if (ConfigLevel < MAXCONFIGLEVEL)
1792c2aa98e2SPeter Wemm 	{
1793c2aa98e2SPeter Wemm 		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1794c2aa98e2SPeter Wemm 			Version, MAXCONFIGLEVEL, ConfigLevel);
1795c2aa98e2SPeter Wemm 	}
1796c2aa98e2SPeter Wemm 
1797c2aa98e2SPeter Wemm 	if (ConfigLevel < 3)
179840266059SGregory Neil Shapiro 		UseErrorsTo = true;
1799c2aa98e2SPeter Wemm 
1800c2aa98e2SPeter Wemm 	/* set options that were previous macros */
1801c2aa98e2SPeter Wemm 	if (SmtpGreeting == NULL)
1802c2aa98e2SPeter Wemm 	{
180340266059SGregory Neil Shapiro 		if (ConfigLevel < 7 &&
180440266059SGregory Neil Shapiro 		    (p = macvalue('e', &BlankEnvelope)) != NULL)
1805c2aa98e2SPeter Wemm 			SmtpGreeting = newstr(p);
1806c2aa98e2SPeter Wemm 		else
1807c2aa98e2SPeter Wemm 			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1808c2aa98e2SPeter Wemm 	}
1809c2aa98e2SPeter Wemm 	if (UnixFromLine == NULL)
1810c2aa98e2SPeter Wemm 	{
181140266059SGregory Neil Shapiro 		if (ConfigLevel < 7 &&
181240266059SGregory Neil Shapiro 		    (p = macvalue('l', &BlankEnvelope)) != NULL)
1813c2aa98e2SPeter Wemm 			UnixFromLine = newstr(p);
1814c2aa98e2SPeter Wemm 		else
1815c2aa98e2SPeter Wemm 			UnixFromLine = "From \201g  \201d";
1816c2aa98e2SPeter Wemm 	}
181706f25ae9SGregory Neil Shapiro 	SmtpError[0] = '\0';
1818c2aa98e2SPeter Wemm 
1819c2aa98e2SPeter Wemm 	/* our name for SMTP codes */
1820d0cef73dSGregory Neil Shapiro 	expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
1821602a2b1bSGregory Neil Shapiro 	if (jbuf[0] == '\0')
182240266059SGregory Neil Shapiro 		PSTRSET(MyHostName, "localhost");
1823602a2b1bSGregory Neil Shapiro 	else
182440266059SGregory Neil Shapiro 		PSTRSET(MyHostName, jbuf);
1825602a2b1bSGregory Neil Shapiro 	if (strchr(MyHostName, '.') == NULL)
1826e92d3f3fSGregory Neil Shapiro 		message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?",
1827602a2b1bSGregory Neil Shapiro 			MyHostName);
1828c2aa98e2SPeter Wemm 
1829c2aa98e2SPeter Wemm 	/* make certain that this name is part of the $=w class */
1830c2aa98e2SPeter Wemm 	setclass('w', MyHostName);
1831c2aa98e2SPeter Wemm 
183240266059SGregory Neil Shapiro 	/* fill in the structure of the *default* queue */
183340266059SGregory Neil Shapiro 	st = stab("mqueue", ST_QUEUE, ST_FIND);
183440266059SGregory Neil Shapiro 	if (st == NULL)
183540266059SGregory Neil Shapiro 		syserr("No default queue (mqueue) defined");
183640266059SGregory Neil Shapiro 	else
183740266059SGregory Neil Shapiro 		set_def_queueval(st->s_quegrp, true);
183840266059SGregory Neil Shapiro 
1839c2aa98e2SPeter Wemm 	/* the indices of built-in mailers */
1840c2aa98e2SPeter Wemm 	st = stab("local", ST_MAILER, ST_FIND);
1841c2aa98e2SPeter Wemm 	if (st != NULL)
1842c2aa98e2SPeter Wemm 		LocalMailer = st->s_mailer;
1843c2aa98e2SPeter Wemm 	else if (OpMode != MD_TEST || !warn_C_flag)
1844c2aa98e2SPeter Wemm 		syserr("No local mailer defined");
1845c2aa98e2SPeter Wemm 
1846c2aa98e2SPeter Wemm 	st = stab("prog", ST_MAILER, ST_FIND);
1847c2aa98e2SPeter Wemm 	if (st == NULL)
1848c2aa98e2SPeter Wemm 		syserr("No prog mailer defined");
1849c2aa98e2SPeter Wemm 	else
1850c2aa98e2SPeter Wemm 	{
1851c2aa98e2SPeter Wemm 		ProgMailer = st->s_mailer;
1852c2aa98e2SPeter Wemm 		clrbitn(M_MUSER, ProgMailer->m_flags);
1853c2aa98e2SPeter Wemm 	}
1854c2aa98e2SPeter Wemm 
1855c2aa98e2SPeter Wemm 	st = stab("*file*", ST_MAILER, ST_FIND);
1856c2aa98e2SPeter Wemm 	if (st == NULL)
1857c2aa98e2SPeter Wemm 		syserr("No *file* mailer defined");
1858c2aa98e2SPeter Wemm 	else
1859c2aa98e2SPeter Wemm 	{
1860c2aa98e2SPeter Wemm 		FileMailer = st->s_mailer;
1861c2aa98e2SPeter Wemm 		clrbitn(M_MUSER, FileMailer->m_flags);
1862c2aa98e2SPeter Wemm 	}
1863c2aa98e2SPeter Wemm 
1864c2aa98e2SPeter Wemm 	st = stab("*include*", ST_MAILER, ST_FIND);
1865c2aa98e2SPeter Wemm 	if (st == NULL)
1866c2aa98e2SPeter Wemm 		syserr("No *include* mailer defined");
1867c2aa98e2SPeter Wemm 	else
1868c2aa98e2SPeter Wemm 		InclMailer = st->s_mailer;
1869c2aa98e2SPeter Wemm 
1870c2aa98e2SPeter Wemm 	if (ConfigLevel < 6)
1871c2aa98e2SPeter Wemm 	{
1872c2aa98e2SPeter Wemm 		/* heuristic tweaking of local mailer for back compat */
1873c2aa98e2SPeter Wemm 		if (LocalMailer != NULL)
1874c2aa98e2SPeter Wemm 		{
1875c2aa98e2SPeter Wemm 			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1876c2aa98e2SPeter Wemm 			setbitn(M_HASPWENT, LocalMailer->m_flags);
1877c2aa98e2SPeter Wemm 			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1878c2aa98e2SPeter Wemm 			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1879c2aa98e2SPeter Wemm 			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1880c2aa98e2SPeter Wemm 			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1881c2aa98e2SPeter Wemm 			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1882c2aa98e2SPeter Wemm 		}
1883c2aa98e2SPeter Wemm 		if (ProgMailer != NULL)
1884c2aa98e2SPeter Wemm 			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1885c2aa98e2SPeter Wemm 		if (FileMailer != NULL)
1886c2aa98e2SPeter Wemm 			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1887c2aa98e2SPeter Wemm 	}
1888c2aa98e2SPeter Wemm 	if (ConfigLevel < 7)
1889c2aa98e2SPeter Wemm 	{
1890c2aa98e2SPeter Wemm 		if (LocalMailer != NULL)
1891c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, LocalMailer->m_flags);
1892c2aa98e2SPeter Wemm 		if (ProgMailer != NULL)
1893c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, ProgMailer->m_flags);
1894c2aa98e2SPeter Wemm 		if (FileMailer != NULL)
1895c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, FileMailer->m_flags);
1896c2aa98e2SPeter Wemm 	}
1897c2aa98e2SPeter Wemm 
1898c2aa98e2SPeter Wemm 	/* MIME Content-Types that cannot be transfer encoded */
1899c2aa98e2SPeter Wemm 	setclass('n', "multipart/signed");
1900c2aa98e2SPeter Wemm 
1901c2aa98e2SPeter Wemm 	/* MIME message/xxx subtypes that can be treated as messages */
1902c2aa98e2SPeter Wemm 	setclass('s', "rfc822");
19032fb4f839SGregory Neil Shapiro #if USE_EAI
19045b0945b5SGregory Neil Shapiro 	setclass('s', "global");
19055b0945b5SGregory Neil Shapiro #endif
1906c2aa98e2SPeter Wemm 
1907c2aa98e2SPeter Wemm 	/* MIME Content-Transfer-Encodings that can be encoded */
1908c2aa98e2SPeter Wemm 	setclass('e', "7bit");
1909c2aa98e2SPeter Wemm 	setclass('e', "8bit");
1910c2aa98e2SPeter Wemm 	setclass('e', "binary");
1911c2aa98e2SPeter Wemm 
1912c2aa98e2SPeter Wemm #ifdef USE_B_CLASS
1913c2aa98e2SPeter Wemm 	/* MIME Content-Types that should be treated as binary */
1914c2aa98e2SPeter Wemm 	setclass('b', "image");
1915c2aa98e2SPeter Wemm 	setclass('b', "audio");
1916c2aa98e2SPeter Wemm 	setclass('b', "video");
1917c2aa98e2SPeter Wemm 	setclass('b', "application/octet-stream");
191806f25ae9SGregory Neil Shapiro #endif /* USE_B_CLASS */
1919c2aa98e2SPeter Wemm 
1920065a643dSPeter Wemm 	/* MIME headers which have fields to check for overflow */
192140266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");
192240266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEFieldHeaders}"), "content-type");
1923065a643dSPeter Wemm 
1924065a643dSPeter Wemm 	/* MIME headers to check for length overflow */
192540266059SGregory Neil Shapiro 	setclass(macid("{checkMIMETextHeaders}"), "content-description");
1926065a643dSPeter Wemm 
1927065a643dSPeter Wemm 	/* MIME headers to check for overflow and rebalance */
192840266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-disposition");
192940266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-id");
193040266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");
193140266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-type");
193240266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "mime-version");
193306f25ae9SGregory Neil Shapiro 
193440266059SGregory Neil Shapiro 	/* Macros to save in the queue file -- don't remove any */
193540266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "r");
193640266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "s");
193740266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "_");
193840266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "{if_addr}");
193940266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "{daemon_flags}");
1940065a643dSPeter Wemm 
1941c2aa98e2SPeter Wemm 	/* operate in queue directory */
194240266059SGregory Neil Shapiro 	if (QueueDir == NULL || *QueueDir == '\0')
1943c2aa98e2SPeter Wemm 	{
1944c2aa98e2SPeter Wemm 		if (OpMode != MD_TEST)
1945c2aa98e2SPeter Wemm 		{
1946c2aa98e2SPeter Wemm 			syserr("QueueDirectory (Q) option must be set");
1947c2aa98e2SPeter Wemm 			ExitStat = EX_CONFIG;
1948c2aa98e2SPeter Wemm 		}
1949c2aa98e2SPeter Wemm 	}
1950c2aa98e2SPeter Wemm 	else
1951c2aa98e2SPeter Wemm 	{
195206f25ae9SGregory Neil Shapiro 		if (OpMode != MD_TEST)
195340266059SGregory Neil Shapiro 			setup_queues(OpMode == MD_DAEMON);
1954c2aa98e2SPeter Wemm 	}
1955c2aa98e2SPeter Wemm 
1956c2aa98e2SPeter Wemm 	/* check host status directory for validity */
195740266059SGregory Neil Shapiro 	if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))
1958c2aa98e2SPeter Wemm 	{
1959c2aa98e2SPeter Wemm 		/* cannot use this value */
196040266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
196140266059SGregory Neil Shapiro 				     "Warning: Cannot use HostStatusDirectory = %s: %s\n",
196240266059SGregory Neil Shapiro 				     HostStatDir, sm_errstring(errno));
1963c2aa98e2SPeter Wemm 		HostStatDir = NULL;
1964c2aa98e2SPeter Wemm 	}
1965c2aa98e2SPeter Wemm 
196640266059SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN &&
196740266059SGregory Neil Shapiro 	    RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1968c2aa98e2SPeter Wemm 	{
1969c2aa98e2SPeter Wemm 		struct stat stbuf;
1970c2aa98e2SPeter Wemm 
1971c2aa98e2SPeter Wemm 		/* check to see if we own the queue directory */
1972c2aa98e2SPeter Wemm 		if (stat(".", &stbuf) < 0)
1973c2aa98e2SPeter Wemm 			syserr("main: cannot stat %s", QueueDir);
1974c2aa98e2SPeter Wemm 		if (stbuf.st_uid != RealUid)
1975c2aa98e2SPeter Wemm 		{
1976c2aa98e2SPeter Wemm 			/* nope, really a botch */
197740266059SGregory Neil Shapiro 			HoldErrs = false;
1978c2aa98e2SPeter Wemm 			usrerr("You do not have permission to process the queue");
197940266059SGregory Neil Shapiro 			finis(false, true, EX_NOPERM);
198040266059SGregory Neil Shapiro 			/* NOTREACHED */
1981c2aa98e2SPeter Wemm 		}
1982c2aa98e2SPeter Wemm 	}
1983c2aa98e2SPeter Wemm 
198440266059SGregory Neil Shapiro #if MILTER
198506f25ae9SGregory Neil Shapiro 	/* sanity checks on milter filters */
198606f25ae9SGregory Neil Shapiro 	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
198740266059SGregory Neil Shapiro 	{
198840266059SGregory Neil Shapiro 		milter_config(InputFilterList, InputFilters, MAXFILTERS);
198940266059SGregory Neil Shapiro 		setup_daemon_milters();
199040266059SGregory Neil Shapiro 	}
199140266059SGregory Neil Shapiro #endif /* MILTER */
199206f25ae9SGregory Neil Shapiro 
199340266059SGregory Neil Shapiro 	/* Convert queuegroup string to qgrp number */
199440266059SGregory Neil Shapiro 	if (queuegroup != NULL)
199540266059SGregory Neil Shapiro 	{
199640266059SGregory Neil Shapiro 		qgrp = name2qid(queuegroup);
199740266059SGregory Neil Shapiro 		if (qgrp == NOQGRP)
199840266059SGregory Neil Shapiro 		{
199940266059SGregory Neil Shapiro 			HoldErrs = false;
200040266059SGregory Neil Shapiro 			usrerr("Queue group %s unknown", queuegroup);
200140266059SGregory Neil Shapiro 			finis(false, true, ExitStat);
200240266059SGregory Neil Shapiro 			/* NOTREACHED */
200340266059SGregory Neil Shapiro 		}
200440266059SGregory Neil Shapiro 	}
200542e5d165SGregory Neil Shapiro 
20069bd497b8SGregory Neil Shapiro 	/* if checking config or have had errors so far, exit now */
20079bd497b8SGregory Neil Shapiro 	if (OpMode == MD_CHECKCONFIG || (ExitStat != EX_OK && OpMode != MD_TEST))
200840266059SGregory Neil Shapiro 	{
200940266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
201040266059SGregory Neil Shapiro 		/* NOTREACHED */
201140266059SGregory Neil Shapiro 	}
201240266059SGregory Neil Shapiro 
201340266059SGregory Neil Shapiro #if SASL
201440266059SGregory Neil Shapiro 	/* sendmail specific SASL initialization */
201540266059SGregory Neil Shapiro 	sm_sasl_init();
20165b0945b5SGregory Neil Shapiro #endif
2017c2aa98e2SPeter Wemm 
2018c2aa98e2SPeter Wemm 	checkfd012("before main() initmaps");
2019c2aa98e2SPeter Wemm 
2020c2aa98e2SPeter Wemm 	/*
2021c2aa98e2SPeter Wemm 	**  Do operation-mode-dependent initialization.
2022c2aa98e2SPeter Wemm 	*/
2023c2aa98e2SPeter Wemm 
2024c2aa98e2SPeter Wemm 	switch (OpMode)
2025c2aa98e2SPeter Wemm 	{
2026c2aa98e2SPeter Wemm 	  case MD_PRINT:
2027c2aa98e2SPeter Wemm 		/* print the queue */
202840266059SGregory Neil Shapiro 		HoldErrs = false;
20299bd497b8SGregory Neil Shapiro 		(void) dropenvelope(&BlankEnvelope, true, false);
203040266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
203140266059SGregory Neil Shapiro 		if (qgrp != NOQGRP)
203240266059SGregory Neil Shapiro 		{
203340266059SGregory Neil Shapiro 			/* Selecting a particular queue group to run */
203440266059SGregory Neil Shapiro 			for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
203540266059SGregory Neil Shapiro 			{
203640266059SGregory Neil Shapiro 				if (StopRequest)
203740266059SGregory Neil Shapiro 					stop_sendmail();
203840266059SGregory Neil Shapiro 				(void) print_single_queue(qgrp, j);
203940266059SGregory Neil Shapiro 			}
204040266059SGregory Neil Shapiro 			finis(false, true, EX_OK);
204140266059SGregory Neil Shapiro 			/* NOTREACHED */
204240266059SGregory Neil Shapiro 		}
2043c2aa98e2SPeter Wemm 		printqueue();
204440266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
204540266059SGregory Neil Shapiro 		/* NOTREACHED */
2046065a643dSPeter Wemm 		break;
2047c2aa98e2SPeter Wemm 
204840266059SGregory Neil Shapiro 	  case MD_PRINTNQE:
204940266059SGregory Neil Shapiro 		/* print number of entries in queue */
20509bd497b8SGregory Neil Shapiro 		(void) dropenvelope(&BlankEnvelope, true, false);
205140266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
205240266059SGregory Neil Shapiro 		printnqe(smioout, NULL);
205340266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
205440266059SGregory Neil Shapiro 		/* NOTREACHED */
205540266059SGregory Neil Shapiro 		break;
205640266059SGregory Neil Shapiro 
205740266059SGregory Neil Shapiro 	  case MD_QUEUERUN:
205840266059SGregory Neil Shapiro 		/* only handle quarantining here */
205940266059SGregory Neil Shapiro 		if (quarantining == NULL)
206040266059SGregory Neil Shapiro 			break;
206140266059SGregory Neil Shapiro 
206240266059SGregory Neil Shapiro 		if (QueueMode != QM_QUARANTINE &&
206340266059SGregory Neil Shapiro 		    QueueMode != QM_NORMAL)
206440266059SGregory Neil Shapiro 		{
206540266059SGregory Neil Shapiro 			HoldErrs = false;
206640266059SGregory Neil Shapiro 			usrerr("Can not use -Q with -q%c", QueueMode);
206740266059SGregory Neil Shapiro 			ExitStat = EX_USAGE;
206840266059SGregory Neil Shapiro 			finis(false, true, ExitStat);
206940266059SGregory Neil Shapiro 			/* NOTREACHED */
207040266059SGregory Neil Shapiro 		}
207140266059SGregory Neil Shapiro 		quarantine_queue(quarantining, qgrp);
207240266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
207340266059SGregory Neil Shapiro 		break;
207440266059SGregory Neil Shapiro 
2075c2aa98e2SPeter Wemm 	  case MD_HOSTSTAT:
207640266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
207706f25ae9SGregory Neil Shapiro 		(void) mci_traverse_persistent(mci_print_persistent, NULL);
207840266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
207940266059SGregory Neil Shapiro 		/* NOTREACHED */
2080c2aa98e2SPeter Wemm 		break;
2081c2aa98e2SPeter Wemm 
2082c2aa98e2SPeter Wemm 	  case MD_PURGESTAT:
208306f25ae9SGregory Neil Shapiro 		(void) mci_traverse_persistent(mci_purge_persistent, NULL);
208440266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
208540266059SGregory Neil Shapiro 		/* NOTREACHED */
2086c2aa98e2SPeter Wemm 		break;
2087c2aa98e2SPeter Wemm 
2088c2aa98e2SPeter Wemm 	  case MD_INITALIAS:
2089065a643dSPeter Wemm 		/* initialize maps */
209006f25ae9SGregory Neil Shapiro 		initmaps();
209140266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
209240266059SGregory Neil Shapiro 		/* NOTREACHED */
2093065a643dSPeter Wemm 		break;
2094c2aa98e2SPeter Wemm 
2095c2aa98e2SPeter Wemm 	  case MD_SMTP:
2096c2aa98e2SPeter Wemm 	  case MD_DAEMON:
2097c2aa98e2SPeter Wemm 		/* reset DSN parameters */
2098c2aa98e2SPeter Wemm 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
209940266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
210040266059SGregory Neil Shapiro 			  macid("{dsn_notify}"), NULL);
210140266059SGregory Neil Shapiro 		BlankEnvelope.e_envid = NULL;
210240266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
210340266059SGregory Neil Shapiro 			  macid("{dsn_envid}"), NULL);
210440266059SGregory Neil Shapiro 		BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
210540266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
210640266059SGregory Neil Shapiro 			  macid("{dsn_ret}"), NULL);
2107c2aa98e2SPeter Wemm 
2108065a643dSPeter Wemm 		/* don't open maps for daemon -- done below in child */
2109c2aa98e2SPeter Wemm 		break;
2110c2aa98e2SPeter Wemm 	}
2111c2aa98e2SPeter Wemm 
2112c2aa98e2SPeter Wemm 	if (tTd(0, 15))
2113c2aa98e2SPeter Wemm 	{
2114c2aa98e2SPeter Wemm 		/* print configuration table (or at least part of it) */
2115c2aa98e2SPeter Wemm 		if (tTd(0, 90))
2116c2aa98e2SPeter Wemm 			printrules();
2117c2aa98e2SPeter Wemm 		for (i = 0; i < MAXMAILERS; i++)
2118c2aa98e2SPeter Wemm 		{
2119c2aa98e2SPeter Wemm 			if (Mailer[i] != NULL)
2120e92d3f3fSGregory Neil Shapiro 				printmailer(sm_debug_file(), Mailer[i]);
2121c2aa98e2SPeter Wemm 		}
2122c2aa98e2SPeter Wemm 	}
2123c2aa98e2SPeter Wemm 
2124c2aa98e2SPeter Wemm 	/*
2125c2aa98e2SPeter Wemm 	**  Switch to the main envelope.
2126c2aa98e2SPeter Wemm 	*/
2127c2aa98e2SPeter Wemm 
212840266059SGregory Neil Shapiro 	CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,
212940266059SGregory Neil Shapiro 			     sm_rpool_new_x(NULL));
2130c2aa98e2SPeter Wemm 	MainEnvelope.e_flags = BlankEnvelope.e_flags;
2131c2aa98e2SPeter Wemm 
2132c2aa98e2SPeter Wemm 	/*
2133c2aa98e2SPeter Wemm 	**  If test mode, read addresses from stdin and process.
2134c2aa98e2SPeter Wemm 	*/
2135c2aa98e2SPeter Wemm 
2136c2aa98e2SPeter Wemm 	if (OpMode == MD_TEST)
2137c2aa98e2SPeter Wemm 	{
213840266059SGregory Neil Shapiro 		if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))
2139c2aa98e2SPeter Wemm 			Verbose = 2;
2140c2aa98e2SPeter Wemm 
2141c2aa98e2SPeter Wemm 		if (Verbose)
2142c2aa98e2SPeter Wemm 		{
214340266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
214440266059SGregory Neil Shapiro 				     "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
214540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
214640266059SGregory Neil Shapiro 				     "Enter <ruleset> <address>\n");
2147c2aa98e2SPeter Wemm 		}
214840266059SGregory Neil Shapiro 		macdefine(&(MainEnvelope.e_macro), A_PERM,
214940266059SGregory Neil Shapiro 			  macid("{addr_type}"), "e r");
2150c2aa98e2SPeter Wemm 		for (;;)
2151c2aa98e2SPeter Wemm 		{
215240266059SGregory Neil Shapiro 			SM_TRY
215340266059SGregory Neil Shapiro 			{
215440266059SGregory Neil Shapiro 				(void) sm_signal(SIGINT, intindebug);
215540266059SGregory Neil Shapiro 				(void) sm_releasesignal(SIGINT);
2156c2aa98e2SPeter Wemm 				if (Verbose == 2)
215740266059SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout,
215840266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
215940266059SGregory Neil Shapiro 							     "> ");
216040266059SGregory Neil Shapiro 				(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
216140266059SGregory Neil Shapiro 				if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,
2162552d4955SGregory Neil Shapiro 						sizeof(buf)) < 0)
216340266059SGregory Neil Shapiro 					testmodeline("/quit", &MainEnvelope);
2164c2aa98e2SPeter Wemm 				p = strchr(buf, '\n');
2165c2aa98e2SPeter Wemm 				if (p != NULL)
2166c2aa98e2SPeter Wemm 					*p = '\0';
2167c2aa98e2SPeter Wemm 				if (Verbose < 2)
216840266059SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout,
216940266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
217040266059SGregory Neil Shapiro 							     "> %s\n", buf);
217140266059SGregory Neil Shapiro 				testmodeline(buf, &MainEnvelope);
217240266059SGregory Neil Shapiro 			}
217340266059SGregory Neil Shapiro 			SM_EXCEPT(exc, "[!F]*")
217440266059SGregory Neil Shapiro 			{
217540266059SGregory Neil Shapiro 				/*
217640266059SGregory Neil Shapiro 				**  8.10 just prints \n on interrupt.
217740266059SGregory Neil Shapiro 				**  I'm printing the exception here in case
217840266059SGregory Neil Shapiro 				**  sendmail is extended to raise additional
217940266059SGregory Neil Shapiro 				**  exceptions in this context.
218040266059SGregory Neil Shapiro 				*/
218140266059SGregory Neil Shapiro 
218240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
218340266059SGregory Neil Shapiro 						     "\n");
218440266059SGregory Neil Shapiro 				sm_exc_print(exc, smioout);
218540266059SGregory Neil Shapiro 			}
218640266059SGregory Neil Shapiro 			SM_END_TRY
2187c2aa98e2SPeter Wemm 		}
2188c2aa98e2SPeter Wemm 	}
2189c2aa98e2SPeter Wemm 
219006f25ae9SGregory Neil Shapiro #if STARTTLS
219140266059SGregory Neil Shapiro 	tls_ok = true;
2192d0cef73dSGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER ||
2193d0cef73dSGregory Neil Shapiro 	    OpMode == MD_ARPAFTP)
219440266059SGregory Neil Shapiro 	{
219540266059SGregory Neil Shapiro 		/* check whether STARTTLS is turned off for the client */
219640266059SGregory Neil Shapiro 		if (chkclientmodifiers(D_NOTLS))
219740266059SGregory Neil Shapiro 			tls_ok = false;
219840266059SGregory Neil Shapiro 	}
219940266059SGregory Neil Shapiro 	else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||
220040266059SGregory Neil Shapiro 		 OpMode == MD_SMTP)
220140266059SGregory Neil Shapiro 	{
22029bd497b8SGregory Neil Shapiro 		/* check whether STARTTLS is turned off */
22039bd497b8SGregory Neil Shapiro 		if (chkdaemonmodifiers(D_NOTLS) && chkclientmodifiers(D_NOTLS))
220440266059SGregory Neil Shapiro 			tls_ok = false;
220540266059SGregory Neil Shapiro 	}
220640266059SGregory Neil Shapiro 	else	/* other modes don't need STARTTLS */
220740266059SGregory Neil Shapiro 		tls_ok = false;
220806f25ae9SGregory Neil Shapiro 
220940266059SGregory Neil Shapiro 	if (tls_ok)
221040266059SGregory Neil Shapiro 	{
221140266059SGregory Neil Shapiro 		/* basic TLS initialization */
22125b0945b5SGregory Neil Shapiro 		j = init_tls_library(FipsMode);
22135b0945b5SGregory Neil Shapiro 		if (j < 0)
2214552d4955SGregory Neil Shapiro 		{
2215552d4955SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
22165b0945b5SGregory Neil Shapiro 				     "ERROR: TLS failed to initialize\n");
2217552d4955SGregory Neil Shapiro 			exit(EX_USAGE);
2218552d4955SGregory Neil Shapiro 		}
22195b0945b5SGregory Neil Shapiro 		if (j > 0)
22205b0945b5SGregory Neil Shapiro 			tls_ok = false;
222140266059SGregory Neil Shapiro 	}
222240266059SGregory Neil Shapiro 
222340266059SGregory Neil Shapiro 	if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
222440266059SGregory Neil Shapiro 	{
222540266059SGregory Neil Shapiro 		/* disable TLS for client */
222640266059SGregory Neil Shapiro 		setclttls(false);
222740266059SGregory Neil Shapiro 	}
222840266059SGregory Neil Shapiro #endif /* STARTTLS */
222940266059SGregory Neil Shapiro 
2230c2aa98e2SPeter Wemm 	/*
2231c2aa98e2SPeter Wemm 	**  If collecting stuff from the queue, go start doing that.
2232c2aa98e2SPeter Wemm 	*/
2233c2aa98e2SPeter Wemm 
223406f25ae9SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
2235c2aa98e2SPeter Wemm 	{
223640266059SGregory Neil Shapiro 		pid_t pid = -1;
223740266059SGregory Neil Shapiro 
223806f25ae9SGregory Neil Shapiro #if STARTTLS
223906f25ae9SGregory Neil Shapiro 		/* init TLS for client, ignore result for now */
224040266059SGregory Neil Shapiro 		(void) initclttls(tls_ok);
22415b0945b5SGregory Neil Shapiro #endif
224240266059SGregory Neil Shapiro 
224340266059SGregory Neil Shapiro 		/*
224440266059SGregory Neil Shapiro 		**  The parent process of the caller of runqueue() needs
224540266059SGregory Neil Shapiro 		**  to stay around for a possible SIGTERM. The SIGTERM will
224640266059SGregory Neil Shapiro 		**  tell this process that all of the queue runners children
224740266059SGregory Neil Shapiro 		**  need to be sent SIGTERM as well. At the same time, we
224840266059SGregory Neil Shapiro 		**  want to return control to the command line. So we do an
224940266059SGregory Neil Shapiro 		**  extra fork().
225040266059SGregory Neil Shapiro 		*/
225140266059SGregory Neil Shapiro 
225240266059SGregory Neil Shapiro 		if (Verbose || foregroundqueue || (pid = fork()) <= 0)
225340266059SGregory Neil Shapiro 		{
225440266059SGregory Neil Shapiro 			/*
225540266059SGregory Neil Shapiro 			**  If the fork() failed we should still try to do
225640266059SGregory Neil Shapiro 			**  the queue run. If it succeeded then the child
225740266059SGregory Neil Shapiro 			**  is going to start the run and wait for all
225840266059SGregory Neil Shapiro 			**  of the children to finish.
225940266059SGregory Neil Shapiro 			*/
226040266059SGregory Neil Shapiro 
226140266059SGregory Neil Shapiro 			if (pid == 0)
226240266059SGregory Neil Shapiro 			{
226340266059SGregory Neil Shapiro 				/* Reset global flags */
226440266059SGregory Neil Shapiro 				RestartRequest = NULL;
226540266059SGregory Neil Shapiro 				ShutdownRequest = NULL;
226640266059SGregory Neil Shapiro 				PendingSignal = 0;
226740266059SGregory Neil Shapiro 
226840266059SGregory Neil Shapiro 				/* disconnect from terminal */
226940266059SGregory Neil Shapiro 				disconnect(2, CurEnv);
2270c2aa98e2SPeter Wemm 			}
227140266059SGregory Neil Shapiro 
227240266059SGregory Neil Shapiro 			CurrentPid = getpid();
227340266059SGregory Neil Shapiro 			if (qgrp != NOQGRP)
227440266059SGregory Neil Shapiro 			{
227513bd1963SGregory Neil Shapiro 				int rwgflags = RWG_NONE;
227613bd1963SGregory Neil Shapiro 
227740266059SGregory Neil Shapiro 				/*
227840266059SGregory Neil Shapiro 				**  To run a specific queue group mark it to
227940266059SGregory Neil Shapiro 				**  be run, select the work group it's in and
228040266059SGregory Neil Shapiro 				**  increment the work counter.
228140266059SGregory Neil Shapiro 				*/
228240266059SGregory Neil Shapiro 
2283605302a5SGregory Neil Shapiro 				for (i = 0; i < NumQueue && Queue[i] != NULL;
2284605302a5SGregory Neil Shapiro 				     i++)
2285605302a5SGregory Neil Shapiro 					Queue[i]->qg_nextrun = (time_t) -1;
2286605302a5SGregory Neil Shapiro 				Queue[qgrp]->qg_nextrun = 0;
228713bd1963SGregory Neil Shapiro 				if (Verbose)
228813bd1963SGregory Neil Shapiro 					rwgflags |= RWG_VERBOSE;
228913bd1963SGregory Neil Shapiro 				if (queuepersistent)
229013bd1963SGregory Neil Shapiro 					rwgflags |= RWG_PERSISTENT;
229113bd1963SGregory Neil Shapiro 				rwgflags |= RWG_FORCE;
229240266059SGregory Neil Shapiro 				(void) run_work_group(Queue[qgrp]->qg_wgrp,
229313bd1963SGregory Neil Shapiro 						      rwgflags);
229440266059SGregory Neil Shapiro 			}
229540266059SGregory Neil Shapiro 			else
229640266059SGregory Neil Shapiro 				(void) runqueue(false, Verbose,
229740266059SGregory Neil Shapiro 						queuepersistent, true);
229840266059SGregory Neil Shapiro 
229940266059SGregory Neil Shapiro 			/* set the title to make it easier to find */
230040266059SGregory Neil Shapiro 			sm_setproctitle(true, CurEnv, "Queue control");
230140266059SGregory Neil Shapiro 			(void) sm_signal(SIGCHLD, SIG_DFL);
230240266059SGregory Neil Shapiro 			while (CurChildren > 0)
230340266059SGregory Neil Shapiro 			{
230440266059SGregory Neil Shapiro 				int status;
230540266059SGregory Neil Shapiro 				pid_t ret;
230640266059SGregory Neil Shapiro 
2307323f6dcbSGregory Neil Shapiro 				errno = 0;
230840266059SGregory Neil Shapiro 				while ((ret = sm_wait(&status)) <= 0)
2309323f6dcbSGregory Neil Shapiro 				{
2310323f6dcbSGregory Neil Shapiro 					if (errno == ECHILD)
2311323f6dcbSGregory Neil Shapiro 					{
2312323f6dcbSGregory Neil Shapiro 						/*
2313323f6dcbSGregory Neil Shapiro 						**  Oops... something got messed
2314323f6dcbSGregory Neil Shapiro 						**  up really bad. Waiting for
2315323f6dcbSGregory Neil Shapiro 						**  non-existent children
2316323f6dcbSGregory Neil Shapiro 						**  shouldn't happen. Let's get
2317323f6dcbSGregory Neil Shapiro 						**  out of here.
2318323f6dcbSGregory Neil Shapiro 						*/
2319323f6dcbSGregory Neil Shapiro 
2320323f6dcbSGregory Neil Shapiro 						CurChildren = 0;
2321323f6dcbSGregory Neil Shapiro 						break;
2322323f6dcbSGregory Neil Shapiro 					}
232340266059SGregory Neil Shapiro 					continue;
2324323f6dcbSGregory Neil Shapiro 				}
2325323f6dcbSGregory Neil Shapiro 
2326323f6dcbSGregory Neil Shapiro 				/* something is really really wrong */
2327323f6dcbSGregory Neil Shapiro 				if (errno == ECHILD)
2328323f6dcbSGregory Neil Shapiro 				{
2329323f6dcbSGregory Neil Shapiro 					sm_syslog(LOG_ERR, NOQID,
2330323f6dcbSGregory Neil Shapiro 						  "queue control process: lost all children: wait returned ECHILD");
2331323f6dcbSGregory Neil Shapiro 					break;
2332323f6dcbSGregory Neil Shapiro 				}
233340266059SGregory Neil Shapiro 
233440266059SGregory Neil Shapiro 				/* Only drop when a child gives status */
233540266059SGregory Neil Shapiro 				if (WIFSTOPPED(status))
233640266059SGregory Neil Shapiro 					continue;
233740266059SGregory Neil Shapiro 
233840266059SGregory Neil Shapiro 				proc_list_drop(ret, status, NULL);
233940266059SGregory Neil Shapiro 			}
234040266059SGregory Neil Shapiro 		}
234140266059SGregory Neil Shapiro 		finis(true, true, ExitStat);
234240266059SGregory Neil Shapiro 		/* NOTREACHED */
234340266059SGregory Neil Shapiro 	}
2344c2aa98e2SPeter Wemm 
2345193538b7SGregory Neil Shapiro #if SASL
2346193538b7SGregory Neil Shapiro 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2347193538b7SGregory Neil Shapiro 	{
234840266059SGregory Neil Shapiro 		/* check whether AUTH is turned off for the server */
234940266059SGregory Neil Shapiro 		if (!chkdaemonmodifiers(D_NOAUTH) &&
235040266059SGregory Neil Shapiro 		    (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
2351193538b7SGregory Neil Shapiro 			syserr("!sasl_server_init failed! [%s]",
2352193538b7SGregory Neil Shapiro 				sasl_errstring(i, NULL, NULL));
2353193538b7SGregory Neil Shapiro 	}
2354193538b7SGregory Neil Shapiro #endif /* SASL */
2355193538b7SGregory Neil Shapiro 
23562fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
23572fb4f839SGregory Neil Shapiro 	if (OpMode == MD_DAEMON && SM_TRIGGER == BlankEnvelope.e_sendmode)
23582fb4f839SGregory Neil Shapiro 	{
23592fb4f839SGregory Neil Shapiro 		i = sm_notify_init(0);
23602fb4f839SGregory Neil Shapiro 		if (i != 0)
23612fb4f839SGregory Neil Shapiro 			syserr("sm_notify_init() failed=%d", i);
23622fb4f839SGregory Neil Shapiro 	}
23632fb4f839SGregory Neil Shapiro #endif
23642fb4f839SGregory Neil Shapiro 
236540266059SGregory Neil Shapiro 	if (OpMode == MD_SMTP)
236640266059SGregory Neil Shapiro 	{
236740266059SGregory Neil Shapiro 		proc_list_add(CurrentPid, "Sendmail SMTP Agent",
2368e92d3f3fSGregory Neil Shapiro 			      PROC_DAEMON, 0, -1, NULL);
236940266059SGregory Neil Shapiro 
237040266059SGregory Neil Shapiro 		/* clean up background delivery children */
237140266059SGregory Neil Shapiro 		(void) sm_signal(SIGCHLD, reapchild);
237240266059SGregory Neil Shapiro 	}
237340266059SGregory Neil Shapiro 
2374c2aa98e2SPeter Wemm 	/*
2375c2aa98e2SPeter Wemm 	**  If a daemon, wait for a request.
23762fb4f839SGregory Neil Shapiro 	**	getrequests() will return in a child (unless -d93.100 is used).
23772fb4f839SGregory Neil Shapiro 	**	If we should also be processing the queue,
23782fb4f839SGregory Neil Shapiro 	**		start doing it in background.
2379c2aa98e2SPeter Wemm 	**	We check for any errors that might have happened
2380c2aa98e2SPeter Wemm 	**		during startup.
2381c2aa98e2SPeter Wemm 	*/
2382c2aa98e2SPeter Wemm 
2383739ac4d4SGregory Neil Shapiro 	if (OpMode == MD_DAEMON || QueueIntvl > 0)
2384c2aa98e2SPeter Wemm 	{
2385c2aa98e2SPeter Wemm 		char dtype[200];
2386c2aa98e2SPeter Wemm 
23873a3ef73dSGregory Neil Shapiro 		/* avoid cleanup in finis(), DaemonPid will be set below */
23883a3ef73dSGregory Neil Shapiro 		DaemonPid = 0;
2389c2aa98e2SPeter Wemm 		if (!run_in_foreground && !tTd(99, 100))
2390c2aa98e2SPeter Wemm 		{
2391c2aa98e2SPeter Wemm 			/* put us in background */
2392c2aa98e2SPeter Wemm 			i = fork();
2393c2aa98e2SPeter Wemm 			if (i < 0)
2394c2aa98e2SPeter Wemm 				syserr("daemon: cannot fork");
2395c2aa98e2SPeter Wemm 			if (i != 0)
239640266059SGregory Neil Shapiro 			{
239740266059SGregory Neil Shapiro 				finis(false, true, EX_OK);
239840266059SGregory Neil Shapiro 				/* NOTREACHED */
239940266059SGregory Neil Shapiro 			}
240040266059SGregory Neil Shapiro 
240140266059SGregory Neil Shapiro 			/*
240240266059SGregory Neil Shapiro 			**  Initialize exception stack and default exception
240340266059SGregory Neil Shapiro 			**  handler for child process.
240440266059SGregory Neil Shapiro 			*/
240540266059SGregory Neil Shapiro 
240640266059SGregory Neil Shapiro 			/* Reset global flags */
240740266059SGregory Neil Shapiro 			RestartRequest = NULL;
240840266059SGregory Neil Shapiro 			RestartWorkGroup = false;
240940266059SGregory Neil Shapiro 			ShutdownRequest = NULL;
241040266059SGregory Neil Shapiro 			PendingSignal = 0;
241140266059SGregory Neil Shapiro 			CurrentPid = getpid();
241240266059SGregory Neil Shapiro 
241340266059SGregory Neil Shapiro 			sm_exc_newthread(fatal_error);
2414c2aa98e2SPeter Wemm 
2415c2aa98e2SPeter Wemm 			/* disconnect from our controlling tty */
241640266059SGregory Neil Shapiro 			disconnect(2, &MainEnvelope);
2417c2aa98e2SPeter Wemm 		}
2418c2aa98e2SPeter Wemm 
2419c2aa98e2SPeter Wemm 		dtype[0] = '\0';
2420c2aa98e2SPeter Wemm 		if (OpMode == MD_DAEMON)
24213a3ef73dSGregory Neil Shapiro 		{
2422d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(dtype, "+SMTP", sizeof(dtype));
24233a3ef73dSGregory Neil Shapiro 			DaemonPid = CurrentPid;
24243a3ef73dSGregory Neil Shapiro 		}
2425739ac4d4SGregory Neil Shapiro 		if (QueueIntvl > 0)
2426c2aa98e2SPeter Wemm 		{
242740266059SGregory Neil Shapiro 			(void) sm_strlcat2(dtype,
242840266059SGregory Neil Shapiro 					   queuepersistent
242940266059SGregory Neil Shapiro 					   ? "+persistent-queueing@"
243040266059SGregory Neil Shapiro 					   : "+queueing@",
243140266059SGregory Neil Shapiro 					   pintvl(QueueIntvl, true),
2432d0cef73dSGregory Neil Shapiro 					   sizeof(dtype));
2433c2aa98e2SPeter Wemm 		}
2434c2aa98e2SPeter Wemm 		if (tTd(0, 1))
2435d0cef73dSGregory Neil Shapiro 			(void) sm_strlcat(dtype, "+debugging", sizeof(dtype));
2436c2aa98e2SPeter Wemm 
2437c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, NOQID,
2438c2aa98e2SPeter Wemm 			  "starting daemon (%s): %s", Version, dtype + 1);
243940266059SGregory Neil Shapiro #if XLA
2440c2aa98e2SPeter Wemm 		xla_create_file();
24415b0945b5SGregory Neil Shapiro #endif
244206f25ae9SGregory Neil Shapiro 
244306f25ae9SGregory Neil Shapiro 		/* save daemon type in a macro for possible PidFile use */
244440266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
244540266059SGregory Neil Shapiro 			macid("{daemon_info}"), dtype + 1);
244606f25ae9SGregory Neil Shapiro 
244706f25ae9SGregory Neil Shapiro 		/* save queue interval in a macro for possible PidFile use */
244840266059SGregory Neil Shapiro 		macdefine(&MainEnvelope.e_macro, A_TEMP,
244940266059SGregory Neil Shapiro 			macid("{queue_interval}"), pintvl(QueueIntvl, true));
2450c2aa98e2SPeter Wemm 
245140266059SGregory Neil Shapiro 		/* workaround: can't seem to release the signal in the parent */
245240266059SGregory Neil Shapiro 		(void) sm_signal(SIGHUP, sighup);
245340266059SGregory Neil Shapiro 		(void) sm_releasesignal(SIGHUP);
245440266059SGregory Neil Shapiro 		(void) sm_signal(SIGTERM, sigterm);
245540266059SGregory Neil Shapiro 
24562fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
24572fb4f839SGregory Neil Shapiro 		if (SM_TRIGGER == BlankEnvelope.e_sendmode)
24582fb4f839SGregory Neil Shapiro 			qm();
24592fb4f839SGregory Neil Shapiro #endif
24602fb4f839SGregory Neil Shapiro 
2461739ac4d4SGregory Neil Shapiro 		if (QueueIntvl > 0)
2462c2aa98e2SPeter Wemm 		{
2463ffb83623SGregory Neil Shapiro #if _FFR_RUNPQG
2464ffb83623SGregory Neil Shapiro 			if (qgrp != NOQGRP)
2465ffb83623SGregory Neil Shapiro 			{
2466ffb83623SGregory Neil Shapiro 				int rwgflags = RWG_NONE;
2467ffb83623SGregory Neil Shapiro 
2468ffb83623SGregory Neil Shapiro 				/*
2469ffb83623SGregory Neil Shapiro 				**  To run a specific queue group mark it to
2470ffb83623SGregory Neil Shapiro 				**  be run, select the work group it's in and
2471ffb83623SGregory Neil Shapiro 				**  increment the work counter.
2472ffb83623SGregory Neil Shapiro 				*/
2473ffb83623SGregory Neil Shapiro 
2474ffb83623SGregory Neil Shapiro 				for (i = 0; i < NumQueue && Queue[i] != NULL;
2475ffb83623SGregory Neil Shapiro 				     i++)
2476ffb83623SGregory Neil Shapiro 					Queue[i]->qg_nextrun = (time_t) -1;
2477ffb83623SGregory Neil Shapiro 				Queue[qgrp]->qg_nextrun = 0;
2478ffb83623SGregory Neil Shapiro 				if (Verbose)
2479ffb83623SGregory Neil Shapiro 					rwgflags |= RWG_VERBOSE;
2480ffb83623SGregory Neil Shapiro 				if (queuepersistent)
2481ffb83623SGregory Neil Shapiro 					rwgflags |= RWG_PERSISTENT;
2482ffb83623SGregory Neil Shapiro 				rwgflags |= RWG_FORCE;
2483ffb83623SGregory Neil Shapiro 				(void) run_work_group(Queue[qgrp]->qg_wgrp,
2484ffb83623SGregory Neil Shapiro 						      rwgflags);
2485ffb83623SGregory Neil Shapiro 			}
2486ffb83623SGregory Neil Shapiro 			else
2487ffb83623SGregory Neil Shapiro #endif /* _FFR_RUNPQG */
2488ffb83623SGregory Neil Shapiro 				(void) runqueue(true, false, queuepersistent,
2489ffb83623SGregory Neil Shapiro 						true);
249040266059SGregory Neil Shapiro 
249140266059SGregory Neil Shapiro 			/*
249240266059SGregory Neil Shapiro 			**  If queuepersistent but not in daemon mode then
249340266059SGregory Neil Shapiro 			**  we're going to do the queue runner monitoring here.
249440266059SGregory Neil Shapiro 			**  If in daemon mode then the monitoring will happen
249540266059SGregory Neil Shapiro 			**  elsewhere.
249640266059SGregory Neil Shapiro 			*/
249740266059SGregory Neil Shapiro 
249840266059SGregory Neil Shapiro 			if (OpMode != MD_DAEMON && queuepersistent)
249940266059SGregory Neil Shapiro 			{
2500e92d3f3fSGregory Neil Shapiro 				/*
2501e92d3f3fSGregory Neil Shapiro 				**  Write the pid to file
2502e92d3f3fSGregory Neil Shapiro 				**  XXX Overwrites sendmail.pid
2503e92d3f3fSGregory Neil Shapiro 				*/
2504e92d3f3fSGregory Neil Shapiro 
2505e92d3f3fSGregory Neil Shapiro 				log_sendmail_pid(&MainEnvelope);
2506e92d3f3fSGregory Neil Shapiro 
250740266059SGregory Neil Shapiro 				/* set the title to make it easier to find */
250840266059SGregory Neil Shapiro 				sm_setproctitle(true, CurEnv, "Queue control");
250940266059SGregory Neil Shapiro 				(void) sm_signal(SIGCHLD, SIG_DFL);
251040266059SGregory Neil Shapiro 				while (CurChildren > 0)
251140266059SGregory Neil Shapiro 				{
251240266059SGregory Neil Shapiro 					int status;
251340266059SGregory Neil Shapiro 					pid_t ret;
251440266059SGregory Neil Shapiro 					int group;
251540266059SGregory Neil Shapiro 
2516a7ec597cSGregory Neil Shapiro 					CHECK_RESTART;
2517323f6dcbSGregory Neil Shapiro 					errno = 0;
251840266059SGregory Neil Shapiro 					while ((ret = sm_wait(&status)) <= 0)
2519323f6dcbSGregory Neil Shapiro 					{
2520323f6dcbSGregory Neil Shapiro 						/*
2521323f6dcbSGregory Neil Shapiro 						**  Waiting for non-existent
2522323f6dcbSGregory Neil Shapiro 						**  children shouldn't happen.
2523323f6dcbSGregory Neil Shapiro 						**  Let's get out of here if
2524323f6dcbSGregory Neil Shapiro 						**  it occurs.
2525323f6dcbSGregory Neil Shapiro 						*/
2526323f6dcbSGregory Neil Shapiro 
2527323f6dcbSGregory Neil Shapiro 						if (errno == ECHILD)
2528323f6dcbSGregory Neil Shapiro 						{
2529323f6dcbSGregory Neil Shapiro 							CurChildren = 0;
2530323f6dcbSGregory Neil Shapiro 							break;
2531323f6dcbSGregory Neil Shapiro 						}
253240266059SGregory Neil Shapiro 						continue;
2533323f6dcbSGregory Neil Shapiro 					}
2534323f6dcbSGregory Neil Shapiro 
2535323f6dcbSGregory Neil Shapiro 					/* something is really really wrong */
2536323f6dcbSGregory Neil Shapiro 					if (errno == ECHILD)
2537323f6dcbSGregory Neil Shapiro 					{
2538323f6dcbSGregory Neil Shapiro 						sm_syslog(LOG_ERR, NOQID,
2539323f6dcbSGregory Neil Shapiro 							  "persistent queue runner control process: lost all children: wait returned ECHILD");
2540323f6dcbSGregory Neil Shapiro 						break;
2541323f6dcbSGregory Neil Shapiro 					}
254240266059SGregory Neil Shapiro 
254340266059SGregory Neil Shapiro 					if (WIFSTOPPED(status))
254440266059SGregory Neil Shapiro 						continue;
254540266059SGregory Neil Shapiro 
254640266059SGregory Neil Shapiro 					/* Probe only on a child status */
254740266059SGregory Neil Shapiro 					proc_list_drop(ret, status, &group);
254840266059SGregory Neil Shapiro 
254940266059SGregory Neil Shapiro 					if (WIFSIGNALED(status))
255040266059SGregory Neil Shapiro 					{
255140266059SGregory Neil Shapiro 						if (WCOREDUMP(status))
255240266059SGregory Neil Shapiro 						{
255340266059SGregory Neil Shapiro 							sm_syslog(LOG_ERR, NOQID,
255440266059SGregory Neil Shapiro 								  "persistent queue runner=%d core dumped, signal=%d",
255540266059SGregory Neil Shapiro 								  group, WTERMSIG(status));
255640266059SGregory Neil Shapiro 
2557a7ec597cSGregory Neil Shapiro 							/* don't restart this */
2558a7ec597cSGregory Neil Shapiro 							mark_work_group_restart(
2559a7ec597cSGregory Neil Shapiro 								group, -1);
256040266059SGregory Neil Shapiro 							continue;
256140266059SGregory Neil Shapiro 						}
256240266059SGregory Neil Shapiro 
256340266059SGregory Neil Shapiro 						sm_syslog(LOG_ERR, NOQID,
2564d0cef73dSGregory Neil Shapiro 							  "persistent queue runner=%d died, pid=%ld, signal=%d",
2565d0cef73dSGregory Neil Shapiro 							  group, (long) ret,
2566d0cef73dSGregory Neil Shapiro 							  WTERMSIG(status));
256740266059SGregory Neil Shapiro 					}
256840266059SGregory Neil Shapiro 
256940266059SGregory Neil Shapiro 					/*
257040266059SGregory Neil Shapiro 					**  When debugging active, don't
257140266059SGregory Neil Shapiro 					**  restart the persistent queues.
257240266059SGregory Neil Shapiro 					**  But do log this as info.
257340266059SGregory Neil Shapiro 					*/
257440266059SGregory Neil Shapiro 
257540266059SGregory Neil Shapiro 					if (sm_debug_active(&DebugNoPRestart,
257640266059SGregory Neil Shapiro 							    1))
257740266059SGregory Neil Shapiro 					{
257840266059SGregory Neil Shapiro 						sm_syslog(LOG_DEBUG, NOQID,
257940266059SGregory Neil Shapiro 							  "persistent queue runner=%d, exited",
258040266059SGregory Neil Shapiro 							  group);
2581a7ec597cSGregory Neil Shapiro 						mark_work_group_restart(group,
2582a7ec597cSGregory Neil Shapiro 									-1);
258340266059SGregory Neil Shapiro 					}
2584d0cef73dSGregory Neil Shapiro 					CHECK_RESTART;
258540266059SGregory Neil Shapiro 				}
258640266059SGregory Neil Shapiro 				finis(true, true, ExitStat);
258740266059SGregory Neil Shapiro 				/* NOTREACHED */
258840266059SGregory Neil Shapiro 			}
258940266059SGregory Neil Shapiro 
2590c2aa98e2SPeter Wemm 			if (OpMode != MD_DAEMON)
2591c2aa98e2SPeter Wemm 			{
259240266059SGregory Neil Shapiro 				char qtype[200];
259340266059SGregory Neil Shapiro 
259440266059SGregory Neil Shapiro 				/*
259540266059SGregory Neil Shapiro 				**  Write the pid to file
259640266059SGregory Neil Shapiro 				**  XXX Overwrites sendmail.pid
259740266059SGregory Neil Shapiro 				*/
259840266059SGregory Neil Shapiro 
259940266059SGregory Neil Shapiro 				log_sendmail_pid(&MainEnvelope);
260040266059SGregory Neil Shapiro 
260140266059SGregory Neil Shapiro 				/* set the title to make it easier to find */
260240266059SGregory Neil Shapiro 				qtype[0] = '\0';
2603d0cef73dSGregory Neil Shapiro 				(void) sm_strlcpyn(qtype, sizeof(qtype), 4,
260440266059SGregory Neil Shapiro 						   "Queue runner@",
260540266059SGregory Neil Shapiro 						   pintvl(QueueIntvl, true),
260640266059SGregory Neil Shapiro 						   " for ",
260740266059SGregory Neil Shapiro 						   QueueDir);
260840266059SGregory Neil Shapiro 				sm_setproctitle(true, CurEnv, qtype);
2609c2aa98e2SPeter Wemm 				for (;;)
2610c2aa98e2SPeter Wemm 				{
261106f25ae9SGregory Neil Shapiro 					(void) pause();
2612e92d3f3fSGregory Neil Shapiro 
2613a7ec597cSGregory Neil Shapiro 					CHECK_RESTART;
2614e92d3f3fSGregory Neil Shapiro 
261540266059SGregory Neil Shapiro 					if (doqueuerun())
261640266059SGregory Neil Shapiro 						(void) runqueue(true, false,
261740266059SGregory Neil Shapiro 								false, false);
261840266059SGregory Neil Shapiro 				}
261940266059SGregory Neil Shapiro 			}
262040266059SGregory Neil Shapiro 		}
26219bd497b8SGregory Neil Shapiro 		(void) dropenvelope(&MainEnvelope, true, false);
262240266059SGregory Neil Shapiro 
262306f25ae9SGregory Neil Shapiro #if STARTTLS
262406f25ae9SGregory Neil Shapiro 		/* init TLS for server, ignore result for now */
262540266059SGregory Neil Shapiro 		(void) initsrvtls(tls_ok);
26265b0945b5SGregory Neil Shapiro #endif
262740266059SGregory Neil Shapiro 	nextreq:
262840266059SGregory Neil Shapiro 		p_flags = getrequests(&MainEnvelope);
2629c2aa98e2SPeter Wemm 
2630c2aa98e2SPeter Wemm 		/* drop privileges */
263140266059SGregory Neil Shapiro 		(void) drop_privileges(false);
2632c2aa98e2SPeter Wemm 
2633c2aa98e2SPeter Wemm 		/*
2634c2aa98e2SPeter Wemm 		**  Get authentication data
263540266059SGregory Neil Shapiro 		**  Set _ macro in BlankEnvelope before calling newenvelope().
2636c2aa98e2SPeter Wemm 		*/
2637c2aa98e2SPeter Wemm 
2638da7d7b9cSGregory Neil Shapiro #if _FFR_XCNCT
2639da7d7b9cSGregory Neil Shapiro 		if (bitnset(D_XCNCT, *p_flags) || bitnset(D_XCNCT_M, *p_flags))
2640da7d7b9cSGregory Neil Shapiro 		{
2641da7d7b9cSGregory Neil Shapiro 			/* copied from getauthinfo() */
2642da7d7b9cSGregory Neil Shapiro 			if (RealHostName == NULL)
2643da7d7b9cSGregory Neil Shapiro 			{
2644da7d7b9cSGregory Neil Shapiro 				RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
2645da7d7b9cSGregory Neil Shapiro 				if (strlen(RealHostName) > MAXNAME)
2646da7d7b9cSGregory Neil Shapiro 					RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
2647da7d7b9cSGregory Neil Shapiro 			}
2648da7d7b9cSGregory Neil Shapiro 			snprintf(buf, sizeof(buf), "%s [%s]",
2649da7d7b9cSGregory Neil Shapiro 				RealHostName, anynet_ntoa(&RealHostAddr));
2650da7d7b9cSGregory Neil Shapiro 
2651da7d7b9cSGregory Neil Shapiro 			forged = bitnset(D_XCNCT_M, *p_flags);
2652da7d7b9cSGregory Neil Shapiro 			if (forged)
2653da7d7b9cSGregory Neil Shapiro 			{
2654da7d7b9cSGregory Neil Shapiro 				(void) sm_strlcat(buf, " (may be forged)",
2655da7d7b9cSGregory Neil Shapiro 						sizeof(buf));
2656da7d7b9cSGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_PERM,
2657da7d7b9cSGregory Neil Shapiro 					  macid("{client_resolve}"), "FORGED");
2658da7d7b9cSGregory Neil Shapiro 			}
2659da7d7b9cSGregory Neil Shapiro 
2660da7d7b9cSGregory Neil Shapiro 			/* HACK! variable used only two times right below */
2661da7d7b9cSGregory Neil Shapiro 			authinfo = buf;
2662da7d7b9cSGregory Neil Shapiro 			if (tTd(75, 9))
2663da7d7b9cSGregory Neil Shapiro 				sm_syslog(LOG_INFO, NOQID,
2664d39bd2c1SGregory Neil Shapiro 					"main: where=not_calling_getauthinfo, RealHostAddr=%s, RealHostName=%s",
2665d39bd2c1SGregory Neil Shapiro 					anynet_ntoa(&RealHostAddr), RealHostName);
2666da7d7b9cSGregory Neil Shapiro 		}
2667da7d7b9cSGregory Neil Shapiro 		else
2668da7d7b9cSGregory Neil Shapiro 		/* WARNING: "non-braced" else */
2669da7d7b9cSGregory Neil Shapiro #endif /* _FFR_XCNCT */
267040266059SGregory Neil Shapiro 		authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
267140266059SGregory Neil Shapiro 						     NULL), &forged);
267240266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
2673ba00ec3dSGregory Neil Shapiro 		if (tTd(75, 9))
2674ba00ec3dSGregory Neil Shapiro 			sm_syslog(LOG_INFO, NOQID,
2675ba00ec3dSGregory Neil Shapiro 				"main: where=after_getauthinfo, RealHostAddr=%s",
2676ba00ec3dSGregory Neil Shapiro 				anynet_ntoa(&RealHostAddr));
267740266059SGregory Neil Shapiro 
267840266059SGregory Neil Shapiro 		/* at this point we are in a child: reset state */
267940266059SGregory Neil Shapiro 		sm_rpool_free(MainEnvelope.e_rpool);
268040266059SGregory Neil Shapiro 		(void) newenvelope(&MainEnvelope, &MainEnvelope,
268140266059SGregory Neil Shapiro 				   sm_rpool_new_x(NULL));
2682c2aa98e2SPeter Wemm 	}
2683c2aa98e2SPeter Wemm 
268406f25ae9SGregory Neil Shapiro 	if (LogLevel > 9)
268506f25ae9SGregory Neil Shapiro 	{
26865b0945b5SGregory Neil Shapiro 		p = authinfo;
26875b0945b5SGregory Neil Shapiro 		if (NULL == p)
26885b0945b5SGregory Neil Shapiro 		{
26895b0945b5SGregory Neil Shapiro 			if (NULL != RealHostName)
26905b0945b5SGregory Neil Shapiro 				p = RealHostName;
26915b0945b5SGregory Neil Shapiro 			else
26925b0945b5SGregory Neil Shapiro 				p = anynet_ntoa(&RealHostAddr);
26935b0945b5SGregory Neil Shapiro 			if (NULL == p)
26945b0945b5SGregory Neil Shapiro 				p = "unknown";
26955b0945b5SGregory Neil Shapiro 		}
26965b0945b5SGregory Neil Shapiro 
269706f25ae9SGregory Neil Shapiro 		/* log connection information */
26985b0945b5SGregory Neil Shapiro 		sm_syslog(LOG_INFO, NULL, "connect from %s", p);
269906f25ae9SGregory Neil Shapiro 	}
270006f25ae9SGregory Neil Shapiro 
2701c2aa98e2SPeter Wemm 	/*
2702c2aa98e2SPeter Wemm 	**  If running SMTP protocol, start collecting and executing
2703c2aa98e2SPeter Wemm 	**  commands.  This will never return.
2704c2aa98e2SPeter Wemm 	*/
2705c2aa98e2SPeter Wemm 
2706c2aa98e2SPeter Wemm 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2707c2aa98e2SPeter Wemm 	{
2708c2aa98e2SPeter Wemm 		char pbuf[20];
2709c2aa98e2SPeter Wemm 
2710c2aa98e2SPeter Wemm 		/*
2711c2aa98e2SPeter Wemm 		**  Save some macros for check_* rulesets.
2712c2aa98e2SPeter Wemm 		*/
2713c2aa98e2SPeter Wemm 
2714c2aa98e2SPeter Wemm 		if (forged)
2715c2aa98e2SPeter Wemm 		{
2716c2aa98e2SPeter Wemm 			char ipbuf[103];
2717c2aa98e2SPeter Wemm 
2718d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(ipbuf, sizeof(ipbuf), "[%.100s]",
271906f25ae9SGregory Neil Shapiro 					   anynet_ntoa(&RealHostAddr));
272040266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
272140266059SGregory Neil Shapiro 				  macid("{client_name}"), ipbuf);
2722c2aa98e2SPeter Wemm 		}
2723c2aa98e2SPeter Wemm 		else
272440266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_PERM,
272540266059SGregory Neil Shapiro 				  macid("{client_name}"), RealHostName);
2726e92d3f3fSGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2727e92d3f3fSGregory Neil Shapiro 			  macid("{client_ptr}"), RealHostName);
272840266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
272940266059SGregory Neil Shapiro 			  macid("{client_addr}"), anynet_ntoa(&RealHostAddr));
273040266059SGregory Neil Shapiro 		sm_getla();
2731c2aa98e2SPeter Wemm 
273206f25ae9SGregory Neil Shapiro 		switch (RealHostAddr.sa.sa_family)
273306f25ae9SGregory Neil Shapiro 		{
273406f25ae9SGregory Neil Shapiro #if NETINET
273506f25ae9SGregory Neil Shapiro 		  case AF_INET:
2736d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof(pbuf), "%d",
2737da7d7b9cSGregory Neil Shapiro 					   ntohs(RealHostAddr.sin.sin_port));
273806f25ae9SGregory Neil Shapiro 			break;
273906f25ae9SGregory Neil Shapiro #endif /* NETINET */
274006f25ae9SGregory Neil Shapiro #if NETINET6
274106f25ae9SGregory Neil Shapiro 		  case AF_INET6:
2742d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof(pbuf), "%d",
2743da7d7b9cSGregory Neil Shapiro 					   ntohs(RealHostAddr.sin6.sin6_port));
274406f25ae9SGregory Neil Shapiro 			break;
274506f25ae9SGregory Neil Shapiro #endif /* NETINET6 */
274606f25ae9SGregory Neil Shapiro 		  default:
2747d0cef73dSGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof(pbuf), "0");
274806f25ae9SGregory Neil Shapiro 			break;
274906f25ae9SGregory Neil Shapiro 		}
275040266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
275140266059SGregory Neil Shapiro 			macid("{client_port}"), pbuf);
275206f25ae9SGregory Neil Shapiro 
2753c2aa98e2SPeter Wemm 		if (OpMode == MD_DAEMON)
2754c2aa98e2SPeter Wemm 		{
2755d0cef73dSGregory Neil Shapiro 			ENVELOPE *saved_env;
2756d0cef73dSGregory Neil Shapiro 
2757c2aa98e2SPeter Wemm 			/* validate the connection */
275840266059SGregory Neil Shapiro 			HoldErrs = true;
2759d0cef73dSGregory Neil Shapiro 			saved_env = CurEnv;
2760d0cef73dSGregory Neil Shapiro 			CurEnv = &BlankEnvelope;
2761c2aa98e2SPeter Wemm 			nullserver = validate_connection(&RealHostAddr,
2762e92d3f3fSGregory Neil Shapiro 						macvalue(macid("{client_name}"),
2763d0cef73dSGregory Neil Shapiro 							&BlankEnvelope),
2764d0cef73dSGregory Neil Shapiro 						&BlankEnvelope);
2765d0cef73dSGregory Neil Shapiro 			if (bitset(EF_DISCARD, BlankEnvelope.e_flags))
2766d0cef73dSGregory Neil Shapiro 				MainEnvelope.e_flags |= EF_DISCARD;
2767d0cef73dSGregory Neil Shapiro 			CurEnv = saved_env;
276840266059SGregory Neil Shapiro 			HoldErrs = false;
2769c2aa98e2SPeter Wemm 		}
277006f25ae9SGregory Neil Shapiro 		else if (p_flags == NULL)
277106f25ae9SGregory Neil Shapiro 		{
2772d0cef73dSGregory Neil Shapiro 			p_flags = (BITMAP256 *) xalloc(sizeof(*p_flags));
277306f25ae9SGregory Neil Shapiro 			clrbitmap(p_flags);
277406f25ae9SGregory Neil Shapiro 		}
277506f25ae9SGregory Neil Shapiro #if STARTTLS
277606f25ae9SGregory Neil Shapiro 		if (OpMode == MD_SMTP)
277740266059SGregory Neil Shapiro 			(void) initsrvtls(tls_ok);
27785b0945b5SGregory Neil Shapiro #endif
2779193538b7SGregory Neil Shapiro 
278040266059SGregory Neil Shapiro 		/* turn off profiling */
278140266059SGregory Neil Shapiro 		SM_PROF(1);
278240266059SGregory Neil Shapiro 		smtp(nullserver, *p_flags, &MainEnvelope);
278313bd1963SGregory Neil Shapiro 
278413bd1963SGregory Neil Shapiro 		if (tTd(93, 100))
278513bd1963SGregory Neil Shapiro 		{
278640266059SGregory Neil Shapiro 			/* turn off profiling */
278740266059SGregory Neil Shapiro 			SM_PROF(0);
278840266059SGregory Neil Shapiro 			if (OpMode == MD_DAEMON)
278940266059SGregory Neil Shapiro 				goto nextreq;
279013bd1963SGregory Neil Shapiro 		}
2791c2aa98e2SPeter Wemm 	}
2792c2aa98e2SPeter Wemm 
279340266059SGregory Neil Shapiro 	sm_rpool_free(MainEnvelope.e_rpool);
279440266059SGregory Neil Shapiro 	clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));
2795c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
2796c2aa98e2SPeter Wemm 	{
279740266059SGregory Neil Shapiro 		set_delivery_mode(SM_VERIFY, &MainEnvelope);
2798c2aa98e2SPeter Wemm 		PostMasterCopy = NULL;
2799c2aa98e2SPeter Wemm 	}
2800c2aa98e2SPeter Wemm 	else
2801c2aa98e2SPeter Wemm 	{
2802c2aa98e2SPeter Wemm 		/* interactive -- all errors are global */
280340266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
2804c2aa98e2SPeter Wemm 	}
2805c2aa98e2SPeter Wemm 
2806c2aa98e2SPeter Wemm 	/*
2807c2aa98e2SPeter Wemm 	**  Do basic system initialization and set the sender
2808c2aa98e2SPeter Wemm 	*/
2809c2aa98e2SPeter Wemm 
281040266059SGregory Neil Shapiro 	initsys(&MainEnvelope);
281140266059SGregory Neil Shapiro 	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");
281240266059SGregory Neil Shapiro 	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");
28132fb4f839SGregory Neil Shapiro #if USE_EAI
28142fb4f839SGregory Neil Shapiro 	fromaddr_x = fromaddr;	/* for logging - see below -- just in case */
28152fb4f839SGregory Neil Shapiro 	if (fromaddr != NULL && (MainEnvelope.e_smtputf8 ||
28162fb4f839SGregory Neil Shapiro 			(MainEnvelope.e_smtputf8 = !asciistr(fromaddr))))
28172fb4f839SGregory Neil Shapiro 	{
28182fb4f839SGregory Neil Shapiro 		/* not very efficient: asciistr() may be called above already */
2819d39bd2c1SGregory Neil Shapiro 		if (!SMTP_UTF8 && !asciistr(fromaddr))
28202fb4f839SGregory Neil Shapiro 		{
28212fb4f839SGregory Neil Shapiro 			usrerr("non-ASCII sender address %s requires SMTPUTF8",
28222fb4f839SGregory Neil Shapiro 				fromaddr);
28232fb4f839SGregory Neil Shapiro 			finis(false, true, EX_USAGE);
28242fb4f839SGregory Neil Shapiro 		}
28252fb4f839SGregory Neil Shapiro 		j = 0;
28262fb4f839SGregory Neil Shapiro 		fromaddr = quote_internal_chars(fromaddr, NULL, &j, NULL);
28272fb4f839SGregory Neil Shapiro 	}
28282fb4f839SGregory Neil Shapiro #endif
28292fb4f839SGregory Neil Shapiro 	setsender(fromaddr, &MainEnvelope, NULL, '\0', false);
283006f25ae9SGregory Neil Shapiro 	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
283140266059SGregory Neil Shapiro 	    (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||
283240266059SGregory Neil Shapiro 	     strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))
283306f25ae9SGregory Neil Shapiro 	{
283440266059SGregory Neil Shapiro 		auth_warning(&MainEnvelope, "%s set sender to %s using -%c",
28352fb4f839SGregory Neil Shapiro 			     RealUserName, fromaddr_x, warn_f_flag);
283606f25ae9SGregory Neil Shapiro #if SASL
283740266059SGregory Neil Shapiro 		auth = false;
28385b0945b5SGregory Neil Shapiro #endif
283906f25ae9SGregory Neil Shapiro 	}
284006f25ae9SGregory Neil Shapiro 	if (auth)
284106f25ae9SGregory Neil Shapiro 	{
284206f25ae9SGregory Neil Shapiro 		char *fv;
284306f25ae9SGregory Neil Shapiro 
284406f25ae9SGregory Neil Shapiro 		/* set the initial sender for AUTH= to $f@$j */
284540266059SGregory Neil Shapiro 		fv = macvalue('f', &MainEnvelope);
284606f25ae9SGregory Neil Shapiro 		if (fv == NULL || *fv == '\0')
284740266059SGregory Neil Shapiro 			MainEnvelope.e_auth_param = NULL;
284806f25ae9SGregory Neil Shapiro 		else
284906f25ae9SGregory Neil Shapiro 		{
285006f25ae9SGregory Neil Shapiro 			if (strchr(fv, '@') == NULL)
285106f25ae9SGregory Neil Shapiro 			{
285240266059SGregory Neil Shapiro 				i = strlen(fv) + strlen(macvalue('j',
285340266059SGregory Neil Shapiro 							&MainEnvelope)) + 2;
285440266059SGregory Neil Shapiro 				p = sm_malloc_x(i);
285540266059SGregory Neil Shapiro 				(void) sm_strlcpyn(p, i, 3, fv, "@",
285640266059SGregory Neil Shapiro 						   macvalue('j',
285740266059SGregory Neil Shapiro 							    &MainEnvelope));
285806f25ae9SGregory Neil Shapiro 			}
285906f25ae9SGregory Neil Shapiro 			else
286040266059SGregory Neil Shapiro 				p = sm_strdup_x(fv);
286140266059SGregory Neil Shapiro 			MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,
286240266059SGregory Neil Shapiro 								      xtextify(p, "="));
286340266059SGregory Neil Shapiro 			sm_free(p);  /* XXX */
286406f25ae9SGregory Neil Shapiro 		}
286506f25ae9SGregory Neil Shapiro 	}
286640266059SGregory Neil Shapiro 	if (macvalue('s', &MainEnvelope) == NULL)
286740266059SGregory Neil Shapiro 		macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);
2868c2aa98e2SPeter Wemm 
286940266059SGregory Neil Shapiro 	av = argv + optind;
2870c2aa98e2SPeter Wemm 	if (*av == NULL && !GrabTo)
2871c2aa98e2SPeter Wemm 	{
287240266059SGregory Neil Shapiro 		MainEnvelope.e_to = NULL;
287340266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS;
287440266059SGregory Neil Shapiro 		HoldErrs = false;
287540266059SGregory Neil Shapiro 		SuperSafe = SAFE_NO;
2876c2aa98e2SPeter Wemm 		usrerr("Recipient names must be specified");
2877c2aa98e2SPeter Wemm 
2878c2aa98e2SPeter Wemm 		/* collect body for UUCP return */
2879c2aa98e2SPeter Wemm 		if (OpMode != MD_VERIFY)
2880d39bd2c1SGregory Neil Shapiro 			collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope,
2881d39bd2c1SGregory Neil Shapiro 				true);
288240266059SGregory Neil Shapiro 		finis(true, true, EX_USAGE);
288340266059SGregory Neil Shapiro 		/* NOTREACHED */
2884c2aa98e2SPeter Wemm 	}
2885c2aa98e2SPeter Wemm 
2886c2aa98e2SPeter Wemm 	/*
2887c2aa98e2SPeter Wemm 	**  Scan argv and deliver the message to everyone.
2888c2aa98e2SPeter Wemm 	*/
2889c2aa98e2SPeter Wemm 
289040266059SGregory Neil Shapiro 	save_val = LogUsrErrs;
289140266059SGregory Neil Shapiro 	LogUsrErrs = true;
289240266059SGregory Neil Shapiro 	sendtoargv(av, &MainEnvelope);
289340266059SGregory Neil Shapiro 	LogUsrErrs = save_val;
2894c2aa98e2SPeter Wemm 
2895c2aa98e2SPeter Wemm 	/* if we have had errors sofar, arrange a meaningful exit stat */
2896c2aa98e2SPeter Wemm 	if (Errors > 0 && ExitStat == EX_OK)
2897c2aa98e2SPeter Wemm 		ExitStat = EX_USAGE;
2898c2aa98e2SPeter Wemm 
2899c2aa98e2SPeter Wemm #if _FFR_FIX_DASHT
2900c2aa98e2SPeter Wemm 	/*
2901c2aa98e2SPeter Wemm 	**  If using -t, force not sending to argv recipients, even
2902c2aa98e2SPeter Wemm 	**  if they are mentioned in the headers.
2903c2aa98e2SPeter Wemm 	*/
2904c2aa98e2SPeter Wemm 
2905c2aa98e2SPeter Wemm 	if (GrabTo)
2906c2aa98e2SPeter Wemm 	{
2907c2aa98e2SPeter Wemm 		ADDRESS *q;
2908c2aa98e2SPeter Wemm 
290940266059SGregory Neil Shapiro 		for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)
291006f25ae9SGregory Neil Shapiro 			q->q_state = QS_REMOVED;
2911c2aa98e2SPeter Wemm 	}
291206f25ae9SGregory Neil Shapiro #endif /* _FFR_FIX_DASHT */
2913c2aa98e2SPeter Wemm 
2914c2aa98e2SPeter Wemm 	/*
2915c2aa98e2SPeter Wemm 	**  Read the input mail.
2916c2aa98e2SPeter Wemm 	*/
2917c2aa98e2SPeter Wemm 
291840266059SGregory Neil Shapiro 	MainEnvelope.e_to = NULL;
2919c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY || GrabTo)
2920c2aa98e2SPeter Wemm 	{
292140266059SGregory Neil Shapiro 		int savederrors;
292240266059SGregory Neil Shapiro 		unsigned long savedflags;
2923c2aa98e2SPeter Wemm 
292440266059SGregory Neil Shapiro 		savederrors = Errors;
292540266059SGregory Neil Shapiro 		savedflags = MainEnvelope.e_flags & EF_FATALERRS;
292640266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS;
292740266059SGregory Neil Shapiro 		MainEnvelope.e_flags &= ~EF_FATALERRS;
292806f25ae9SGregory Neil Shapiro 		Errors = 0;
292906f25ae9SGregory Neil Shapiro 		buffer_errors();
2930d39bd2c1SGregory Neil Shapiro 		collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope, true);
2931c2aa98e2SPeter Wemm 
293206f25ae9SGregory Neil Shapiro 		/* header checks failed */
293306f25ae9SGregory Neil Shapiro 		if (Errors > 0)
2934c2aa98e2SPeter Wemm 		{
293540266059SGregory Neil Shapiro   giveup:
293640266059SGregory Neil Shapiro 			if (!GrabTo)
293740266059SGregory Neil Shapiro 			{
293806f25ae9SGregory Neil Shapiro 				/* Log who the mail would have gone to */
293940266059SGregory Neil Shapiro 				logundelrcpts(&MainEnvelope,
294040266059SGregory Neil Shapiro 					      MainEnvelope.e_message,
294140266059SGregory Neil Shapiro 					      8, false);
294206f25ae9SGregory Neil Shapiro 			}
294340266059SGregory Neil Shapiro 			flush_errors(true);
294440266059SGregory Neil Shapiro 			finis(true, true, ExitStat);
2945c2aa98e2SPeter Wemm 			/* NOTREACHED */
2946c2aa98e2SPeter Wemm 			return -1;
2947c2aa98e2SPeter Wemm 		}
294806f25ae9SGregory Neil Shapiro 
294906f25ae9SGregory Neil Shapiro 		/* bail out if message too large */
295040266059SGregory Neil Shapiro 		if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))
295106f25ae9SGregory Neil Shapiro 		{
295240266059SGregory Neil Shapiro 			finis(true, true, ExitStat != EX_OK ? ExitStat
295340266059SGregory Neil Shapiro 							    : EX_DATAERR);
295406f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
295506f25ae9SGregory Neil Shapiro 			return -1;
295606f25ae9SGregory Neil Shapiro 		}
295794c01205SGregory Neil Shapiro 
295894c01205SGregory Neil Shapiro 		/* set message size */
2959d0cef73dSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "%ld",
2960ba00ec3dSGregory Neil Shapiro 				   PRT_NONNEGL(MainEnvelope.e_msgsize));
296194c01205SGregory Neil Shapiro 		macdefine(&MainEnvelope.e_macro, A_TEMP,
296294c01205SGregory Neil Shapiro 			  macid("{msg_size}"), buf);
296394c01205SGregory Neil Shapiro 
296406f25ae9SGregory Neil Shapiro 		Errors = savederrors;
296540266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= savedflags;
2966c2aa98e2SPeter Wemm 	}
2967c2aa98e2SPeter Wemm 	errno = 0;
2968c2aa98e2SPeter Wemm 
2969c2aa98e2SPeter Wemm 	if (tTd(1, 1))
297040266059SGregory Neil Shapiro 		sm_dprintf("From person = \"%s\"\n",
297140266059SGregory Neil Shapiro 			   MainEnvelope.e_from.q_paddr);
297240266059SGregory Neil Shapiro 
297340266059SGregory Neil Shapiro 	/* Check if quarantining stats should be updated */
297440266059SGregory Neil Shapiro 	if (MainEnvelope.e_quarmsg != NULL)
297540266059SGregory Neil Shapiro 		markstats(&MainEnvelope, NULL, STATS_QUARANTINE);
2976c2aa98e2SPeter Wemm 
2977c2aa98e2SPeter Wemm 	/*
2978c2aa98e2SPeter Wemm 	**  Actually send everything.
2979c2aa98e2SPeter Wemm 	**	If verifying, just ack.
2980c2aa98e2SPeter Wemm 	*/
2981c2aa98e2SPeter Wemm 
298240266059SGregory Neil Shapiro 	if (Errors == 0)
298340266059SGregory Neil Shapiro 	{
298440266059SGregory Neil Shapiro 		if (!split_by_recipient(&MainEnvelope) &&
298540266059SGregory Neil Shapiro 		    bitset(EF_FATALERRS, MainEnvelope.e_flags))
298640266059SGregory Neil Shapiro 			goto giveup;
298740266059SGregory Neil Shapiro 	}
298840266059SGregory Neil Shapiro 
298940266059SGregory Neil Shapiro 	/* make sure we deliver at least the first envelope */
299040266059SGregory Neil Shapiro 	i = FastSplit > 0 ? 0 : -1;
299140266059SGregory Neil Shapiro 	for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)
299240266059SGregory Neil Shapiro 	{
299340266059SGregory Neil Shapiro 		ENVELOPE *next;
299440266059SGregory Neil Shapiro 
299540266059SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
2996c2aa98e2SPeter Wemm 		if (tTd(1, 5))
2997c2aa98e2SPeter Wemm 		{
299840266059SGregory Neil Shapiro 			sm_dprintf("main[%d]: QS_SENDER ", i);
2999e92d3f3fSGregory Neil Shapiro 			printaddr(sm_debug_file(), &e->e_from, false);
3000c2aa98e2SPeter Wemm 		}
300140266059SGregory Neil Shapiro 		e->e_to = NULL;
300240266059SGregory Neil Shapiro 		sm_getla();
300340266059SGregory Neil Shapiro 		GrabTo = false;
300406f25ae9SGregory Neil Shapiro #if NAMED_BIND
300506f25ae9SGregory Neil Shapiro 		_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
300606f25ae9SGregory Neil Shapiro 		_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
30075b0945b5SGregory Neil Shapiro #endif
300840266059SGregory Neil Shapiro 		next = e->e_sibling;
300940266059SGregory Neil Shapiro 		e->e_sibling = NULL;
301040266059SGregory Neil Shapiro 
301140266059SGregory Neil Shapiro 		/* after FastSplit envelopes: queue up */
301240266059SGregory Neil Shapiro 		sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);
301340266059SGregory Neil Shapiro 		e->e_sibling = next;
301440266059SGregory Neil Shapiro 	}
3015c2aa98e2SPeter Wemm 
3016c2aa98e2SPeter Wemm 	/*
3017c2aa98e2SPeter Wemm 	**  All done.
3018c2aa98e2SPeter Wemm 	**	Don't send return error message if in VERIFY mode.
3019c2aa98e2SPeter Wemm 	*/
3020c2aa98e2SPeter Wemm 
302140266059SGregory Neil Shapiro 	finis(true, true, ExitStat);
3022c2aa98e2SPeter Wemm 	/* NOTREACHED */
302306f25ae9SGregory Neil Shapiro 	return ExitStat;
3024c2aa98e2SPeter Wemm }
302540266059SGregory Neil Shapiro /*
30268774250cSGregory Neil Shapiro **  STOP_SENDMAIL -- Stop the running program
30278774250cSGregory Neil Shapiro **
30288774250cSGregory Neil Shapiro **	Parameters:
30298774250cSGregory Neil Shapiro **		none.
30308774250cSGregory Neil Shapiro **
30318774250cSGregory Neil Shapiro **	Returns:
30328774250cSGregory Neil Shapiro **		none.
30338774250cSGregory Neil Shapiro **
30348774250cSGregory Neil Shapiro **	Side Effects:
30358774250cSGregory Neil Shapiro **		exits.
30368774250cSGregory Neil Shapiro */
30378774250cSGregory Neil Shapiro 
30388774250cSGregory Neil Shapiro void
stop_sendmail()30398774250cSGregory Neil Shapiro stop_sendmail()
30408774250cSGregory Neil Shapiro {
30418774250cSGregory Neil Shapiro 	/* reset uid for process accounting */
30428774250cSGregory Neil Shapiro 	endpwent();
30438774250cSGregory Neil Shapiro 	(void) setuid(RealUid);
30448774250cSGregory Neil Shapiro 	exit(EX_OK);
3045065a643dSPeter Wemm }
304640266059SGregory Neil Shapiro /*
304740266059SGregory Neil Shapiro **  FINIS -- Clean up and exit.
304840266059SGregory Neil Shapiro **
304940266059SGregory Neil Shapiro **	Parameters:
305040266059SGregory Neil Shapiro **		drop -- whether or not to drop CurEnv envelope
305140266059SGregory Neil Shapiro **		cleanup -- call exit() or _exit()?
305240266059SGregory Neil Shapiro **		exitstat -- exit status to use for exit() call
305340266059SGregory Neil Shapiro **
305440266059SGregory Neil Shapiro **	Returns:
305540266059SGregory Neil Shapiro **		never
305640266059SGregory Neil Shapiro **
305740266059SGregory Neil Shapiro **	Side Effects:
305840266059SGregory Neil Shapiro **		exits sendmail
305940266059SGregory Neil Shapiro */
3060c2aa98e2SPeter Wemm 
306140266059SGregory Neil Shapiro void
finis(drop,cleanup,exitstat)306240266059SGregory Neil Shapiro finis(drop, cleanup, exitstat)
306340266059SGregory Neil Shapiro 	bool drop;
306440266059SGregory Neil Shapiro 	bool cleanup;
306540266059SGregory Neil Shapiro 	volatile int exitstat;
306640266059SGregory Neil Shapiro {
3067e92d3f3fSGregory Neil Shapiro 	char pidpath[MAXPATHLEN];
3068af9557fdSGregory Neil Shapiro 	pid_t pid;
306994c01205SGregory Neil Shapiro 
307040266059SGregory Neil Shapiro 	/* Still want to process new timeouts added below */
307140266059SGregory Neil Shapiro 	sm_clear_events();
307240266059SGregory Neil Shapiro 	(void) sm_releasesignal(SIGALRM);
307340266059SGregory Neil Shapiro 
30745b0945b5SGregory Neil Shapiro #if RATECTL_DEBUG || _FFR_OCC
30755b0945b5SGregory Neil Shapiro 	/* do this only in "main" process */
30765b0945b5SGregory Neil Shapiro 	if (DaemonPid == getpid())
30775b0945b5SGregory Neil Shapiro 	{
30785b0945b5SGregory Neil Shapiro 		SM_FILE_T *fp;
30795b0945b5SGregory Neil Shapiro 
30805b0945b5SGregory Neil Shapiro 		fp = sm_debug_file();
30815b0945b5SGregory Neil Shapiro 		if (fp != NULL)
30825b0945b5SGregory Neil Shapiro 			dump_ch(fp);
30835b0945b5SGregory Neil Shapiro 	}
30842fb4f839SGregory Neil Shapiro #endif /* RATECTL_DEBUG || _FFR_OCC */
30852fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
30862fb4f839SGregory Neil Shapiro 	if (OpMode == MD_DAEMON && SM_TRIGGER == BlankEnvelope.e_sendmode)
30872fb4f839SGregory Neil Shapiro 		sm_notify_stop(DaemonPid == getpid(), 0);
30885b0945b5SGregory Neil Shapiro #endif
308940266059SGregory Neil Shapiro 	if (tTd(2, 1))
309040266059SGregory Neil Shapiro 	{
309140266059SGregory Neil Shapiro 		sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
309240266059SGregory Neil Shapiro 			   exitstat,
309340266059SGregory Neil Shapiro 			   CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
309440266059SGregory Neil Shapiro 		printenvflags(CurEnv);
309540266059SGregory Neil Shapiro 	}
309640266059SGregory Neil Shapiro 	if (tTd(2, 9))
309740266059SGregory Neil Shapiro 		printopenfds(false);
309840266059SGregory Neil Shapiro 
309940266059SGregory Neil Shapiro 	SM_TRY
310040266059SGregory Neil Shapiro 		/*
310140266059SGregory Neil Shapiro 		**  Clean up.  This might raise E:mta.quickabort
310240266059SGregory Neil Shapiro 		*/
310340266059SGregory Neil Shapiro 
310440266059SGregory Neil Shapiro 		/* clean up temp files */
310540266059SGregory Neil Shapiro 		CurEnv->e_to = NULL;
310640266059SGregory Neil Shapiro 		if (drop)
310740266059SGregory Neil Shapiro 		{
310840266059SGregory Neil Shapiro 			if (CurEnv->e_id != NULL)
310940266059SGregory Neil Shapiro 			{
31109bd497b8SGregory Neil Shapiro 				int r;
31119bd497b8SGregory Neil Shapiro 
31129bd497b8SGregory Neil Shapiro 				r = dropenvelope(CurEnv, true, false);
31139bd497b8SGregory Neil Shapiro 				if (exitstat == EX_OK)
31149bd497b8SGregory Neil Shapiro 					exitstat = r;
311540266059SGregory Neil Shapiro 				sm_rpool_free(CurEnv->e_rpool);
311640266059SGregory Neil Shapiro 				CurEnv->e_rpool = NULL;
31173a3ef73dSGregory Neil Shapiro 
3118d0cef73dSGregory Neil Shapiro 				/* these may have pointed to the rpool */
31193a3ef73dSGregory Neil Shapiro 				CurEnv->e_to = NULL;
3120d0cef73dSGregory Neil Shapiro 				CurEnv->e_message = NULL;
3121d0cef73dSGregory Neil Shapiro 				CurEnv->e_statmsg = NULL;
3122d0cef73dSGregory Neil Shapiro 				CurEnv->e_quarmsg = NULL;
3123d0cef73dSGregory Neil Shapiro 				CurEnv->e_bodytype = NULL;
3124d0cef73dSGregory Neil Shapiro 				CurEnv->e_id = NULL;
3125d0cef73dSGregory Neil Shapiro 				CurEnv->e_envid = NULL;
3126d0cef73dSGregory Neil Shapiro 				CurEnv->e_auth_param = NULL;
312740266059SGregory Neil Shapiro 			}
312840266059SGregory Neil Shapiro 			else
312940266059SGregory Neil Shapiro 				poststats(StatFile);
313040266059SGregory Neil Shapiro 		}
313140266059SGregory Neil Shapiro 
313240266059SGregory Neil Shapiro 		/* flush any cached connections */
313340266059SGregory Neil Shapiro 		mci_flush(true, NULL);
313440266059SGregory Neil Shapiro 
313540266059SGregory Neil Shapiro 		/* close maps belonging to this pid */
313640266059SGregory Neil Shapiro 		closemaps(false);
313740266059SGregory Neil Shapiro 
313840266059SGregory Neil Shapiro #if USERDB
313940266059SGregory Neil Shapiro 		/* close UserDatabase */
314040266059SGregory Neil Shapiro 		_udbx_close();
31415b0945b5SGregory Neil Shapiro #endif
314240266059SGregory Neil Shapiro 
314340266059SGregory Neil Shapiro #if SASL
314440266059SGregory Neil Shapiro 		stop_sasl_client();
31455b0945b5SGregory Neil Shapiro #endif
314640266059SGregory Neil Shapiro 
314740266059SGregory Neil Shapiro #if XLA
314840266059SGregory Neil Shapiro 		/* clean up extended load average stuff */
314940266059SGregory Neil Shapiro 		xla_all_end();
31505b0945b5SGregory Neil Shapiro #endif
315140266059SGregory Neil Shapiro 
315240266059SGregory Neil Shapiro 	SM_FINALLY
315340266059SGregory Neil Shapiro 		/*
315440266059SGregory Neil Shapiro 		**  And exit.
315540266059SGregory Neil Shapiro 		*/
315640266059SGregory Neil Shapiro 
315740266059SGregory Neil Shapiro 		if (LogLevel > 78)
315840266059SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",
315940266059SGregory Neil Shapiro 				  (int) CurrentPid);
316040266059SGregory Neil Shapiro 		if (exitstat == EX_TEMPFAIL ||
316140266059SGregory Neil Shapiro 		    CurEnv->e_errormode == EM_BERKNET)
316240266059SGregory Neil Shapiro 			exitstat = EX_OK;
316340266059SGregory Neil Shapiro 
316440266059SGregory Neil Shapiro 		/* XXX clean up queues and related data structures */
316540266059SGregory Neil Shapiro 		cleanup_queues();
3166af9557fdSGregory Neil Shapiro 		pid = getpid();
316740266059SGregory Neil Shapiro #if SM_CONF_SHM
3168af9557fdSGregory Neil Shapiro 		cleanup_shm(DaemonPid == pid);
31695b0945b5SGregory Neil Shapiro #endif
317040266059SGregory Neil Shapiro 
3171e92d3f3fSGregory Neil Shapiro 		/* close locked pid file */
3172e92d3f3fSGregory Neil Shapiro 		close_sendmail_pid();
3173e92d3f3fSGregory Neil Shapiro 
3174af9557fdSGregory Neil Shapiro 		if (DaemonPid == pid || PidFilePid == pid)
3175e92d3f3fSGregory Neil Shapiro 		{
3176e92d3f3fSGregory Neil Shapiro 			/* blow away the pid file */
3177d0cef73dSGregory Neil Shapiro 			expand(PidFile, pidpath, sizeof(pidpath), CurEnv);
3178e92d3f3fSGregory Neil Shapiro 			(void) unlink(pidpath);
3179e92d3f3fSGregory Neil Shapiro 		}
3180e92d3f3fSGregory Neil Shapiro 
318140266059SGregory Neil Shapiro 		/* reset uid for process accounting */
318240266059SGregory Neil Shapiro 		endpwent();
318340266059SGregory Neil Shapiro 		sm_mbdb_terminate();
31844e4196cbSGregory Neil Shapiro #if _FFR_MEMSTAT
31854e4196cbSGregory Neil Shapiro 		(void) sm_memstat_close();
31865b0945b5SGregory Neil Shapiro #endif
318740266059SGregory Neil Shapiro 		(void) setuid(RealUid);
318840266059SGregory Neil Shapiro #if SM_HEAP_CHECK
31892fb4f839SGregory Neil Shapiro # if SM_HEAP_CHECK > 1
31902fb4f839SGregory Neil Shapiro 		/* seems this is not always free()? */
31912fb4f839SGregory Neil Shapiro 		sm_rpool_free(CurEnv->e_rpool);
31922fb4f839SGregory Neil Shapiro # endif
319340266059SGregory Neil Shapiro 		/* dump the heap, if we are checking for memory leaks */
319440266059SGregory Neil Shapiro 		if (sm_debug_active(&SmHeapCheck, 2))
319540266059SGregory Neil Shapiro 			sm_heap_report(smioout,
319640266059SGregory Neil Shapiro 				       sm_debug_level(&SmHeapCheck) - 1);
31975b0945b5SGregory Neil Shapiro #endif
319840266059SGregory Neil Shapiro 		if (sm_debug_active(&SmXtrapReport, 1))
319940266059SGregory Neil Shapiro 			sm_dprintf("xtrap count = %d\n", SmXtrapCount);
320040266059SGregory Neil Shapiro 		if (cleanup)
320140266059SGregory Neil Shapiro 			exit(exitstat);
320240266059SGregory Neil Shapiro 		else
320340266059SGregory Neil Shapiro 			_exit(exitstat);
320440266059SGregory Neil Shapiro 	SM_END_TRY
320540266059SGregory Neil Shapiro }
320640266059SGregory Neil Shapiro /*
32078774250cSGregory Neil Shapiro **  INTINDEBUG -- signal handler for SIGINT in -bt mode
32088774250cSGregory Neil Shapiro **
32098774250cSGregory Neil Shapiro **	Parameters:
32108774250cSGregory Neil Shapiro **		sig -- incoming signal.
32118774250cSGregory Neil Shapiro **
32128774250cSGregory Neil Shapiro **	Returns:
32138774250cSGregory Neil Shapiro **		none.
32148774250cSGregory Neil Shapiro **
32158774250cSGregory Neil Shapiro **	Side Effects:
32168774250cSGregory Neil Shapiro **		longjmps back to test mode loop.
32178774250cSGregory Neil Shapiro **
32188774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
32198774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
32208774250cSGregory Neil Shapiro **		DOING.
32218774250cSGregory Neil Shapiro */
32228774250cSGregory Neil Shapiro 
322340266059SGregory Neil Shapiro /* Type of an exception generated on SIGINT during address test mode.  */
322440266059SGregory Neil Shapiro static const SM_EXC_TYPE_T EtypeInterrupt =
322540266059SGregory Neil Shapiro {
322640266059SGregory Neil Shapiro 	SmExcTypeMagic,
322740266059SGregory Neil Shapiro 	"S:mta.interrupt",
322840266059SGregory Neil Shapiro 	"",
322940266059SGregory Neil Shapiro 	sm_etype_printf,
323040266059SGregory Neil Shapiro 	"interrupt",
323140266059SGregory Neil Shapiro };
323240266059SGregory Neil Shapiro 
3233c2aa98e2SPeter Wemm /* ARGSUSED */
32348774250cSGregory Neil Shapiro static SIGFUNC_DECL
intindebug(sig)3235c2aa98e2SPeter Wemm intindebug(sig)
3236c2aa98e2SPeter Wemm 	int sig;
3237c2aa98e2SPeter Wemm {
32388774250cSGregory Neil Shapiro 	int save_errno = errno;
32398774250cSGregory Neil Shapiro 
32408774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, intindebug);
32418774250cSGregory Neil Shapiro 	errno = save_errno;
32428774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
32438774250cSGregory Neil Shapiro 	errno = save_errno;
324440266059SGregory Neil Shapiro 	sm_exc_raisenew_x(&EtypeInterrupt);
324540266059SGregory Neil Shapiro 	errno = save_errno;
3246c2aa98e2SPeter Wemm 	return SIGFUNC_RETURN;
3247c2aa98e2SPeter Wemm }
324840266059SGregory Neil Shapiro /*
324940266059SGregory Neil Shapiro **  SIGTERM -- SIGTERM handler for the daemon
32508774250cSGregory Neil Shapiro **
32518774250cSGregory Neil Shapiro **	Parameters:
32528774250cSGregory Neil Shapiro **		sig -- signal number.
32538774250cSGregory Neil Shapiro **
32548774250cSGregory Neil Shapiro **	Returns:
32558774250cSGregory Neil Shapiro **		none.
32568774250cSGregory Neil Shapiro **
32578774250cSGregory Neil Shapiro **	Side Effects:
32588774250cSGregory Neil Shapiro **		Sets ShutdownRequest which will hopefully trigger
32598774250cSGregory Neil Shapiro **		the daemon to exit.
32608774250cSGregory Neil Shapiro **
32618774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
32628774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
32638774250cSGregory Neil Shapiro **		DOING.
32648774250cSGregory Neil Shapiro */
32658774250cSGregory Neil Shapiro 
32668774250cSGregory Neil Shapiro /* ARGSUSED */
32678774250cSGregory Neil Shapiro static SIGFUNC_DECL
sigterm(sig)326840266059SGregory Neil Shapiro sigterm(sig)
32698774250cSGregory Neil Shapiro 	int sig;
32708774250cSGregory Neil Shapiro {
32718774250cSGregory Neil Shapiro 	int save_errno = errno;
32728774250cSGregory Neil Shapiro 
327340266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigterm);
32748774250cSGregory Neil Shapiro 	ShutdownRequest = "signal";
32758774250cSGregory Neil Shapiro 	errno = save_errno;
3276d39bd2c1SGregory Neil Shapiro #if _FFR_DMTRIGGER
3277d39bd2c1SGregory Neil Shapiro 	/* temporary? */
3278d39bd2c1SGregory Neil Shapiro 	proc_list_signal(PROC_QM, sig);
3279d39bd2c1SGregory Neil Shapiro #endif
32808774250cSGregory Neil Shapiro 	return SIGFUNC_RETURN;
32818774250cSGregory Neil Shapiro }
328240266059SGregory Neil Shapiro /*
328340266059SGregory Neil Shapiro **  SIGHUP -- handle a SIGHUP signal
32848774250cSGregory Neil Shapiro **
32858774250cSGregory Neil Shapiro **	Parameters:
328640266059SGregory Neil Shapiro **		sig -- incoming signal.
32878774250cSGregory Neil Shapiro **
32888774250cSGregory Neil Shapiro **	Returns:
32898774250cSGregory Neil Shapiro **		none.
32908774250cSGregory Neil Shapiro **
32918774250cSGregory Neil Shapiro **	Side Effects:
329240266059SGregory Neil Shapiro **		Sets RestartRequest which should cause the daemon
329340266059SGregory Neil Shapiro **		to restart.
329440266059SGregory Neil Shapiro **
329540266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
329640266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
329740266059SGregory Neil Shapiro **		DOING.
32988774250cSGregory Neil Shapiro */
32998774250cSGregory Neil Shapiro 
330040266059SGregory Neil Shapiro /* ARGSUSED */
330140266059SGregory Neil Shapiro static SIGFUNC_DECL
sighup(sig)330240266059SGregory Neil Shapiro sighup(sig)
330340266059SGregory Neil Shapiro 	int sig;
33048774250cSGregory Neil Shapiro {
330540266059SGregory Neil Shapiro 	int save_errno = errno;
33068774250cSGregory Neil Shapiro 
330740266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sighup);
330840266059SGregory Neil Shapiro 	RestartRequest = "signal";
330940266059SGregory Neil Shapiro 	errno = save_errno;
331040266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
33118774250cSGregory Neil Shapiro }
331240266059SGregory Neil Shapiro /*
331340266059SGregory Neil Shapiro **  SIGPIPE -- signal handler for SIGPIPE
331440266059SGregory Neil Shapiro **
331540266059SGregory Neil Shapiro **	Parameters:
331640266059SGregory Neil Shapiro **		sig -- incoming signal.
331740266059SGregory Neil Shapiro **
331840266059SGregory Neil Shapiro **	Returns:
331940266059SGregory Neil Shapiro **		none.
332040266059SGregory Neil Shapiro **
332140266059SGregory Neil Shapiro **	Side Effects:
332240266059SGregory Neil Shapiro **		Sets StopRequest which should cause the mailq/hoststatus
332340266059SGregory Neil Shapiro **		display to stop.
332440266059SGregory Neil Shapiro **
332540266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
332640266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
332740266059SGregory Neil Shapiro **		DOING.
332840266059SGregory Neil Shapiro */
332940266059SGregory Neil Shapiro 
333040266059SGregory Neil Shapiro /* ARGSUSED */
333140266059SGregory Neil Shapiro static SIGFUNC_DECL
sigpipe(sig)333240266059SGregory Neil Shapiro sigpipe(sig)
333340266059SGregory Neil Shapiro 	int sig;
333440266059SGregory Neil Shapiro {
333540266059SGregory Neil Shapiro 	int save_errno = errno;
333640266059SGregory Neil Shapiro 
333740266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigpipe);
333840266059SGregory Neil Shapiro 	StopRequest = true;
333940266059SGregory Neil Shapiro 	errno = save_errno;
334040266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
334140266059SGregory Neil Shapiro }
334240266059SGregory Neil Shapiro /*
3343c2aa98e2SPeter Wemm **  INTSIG -- clean up on interrupt
3344c2aa98e2SPeter Wemm **
334506f25ae9SGregory Neil Shapiro **	This just arranges to exit.  It pessimizes in that it
3346c2aa98e2SPeter Wemm **	may resend a message.
3347c2aa98e2SPeter Wemm **
3348c2aa98e2SPeter Wemm **	Parameters:
33496f9c8e5bSGregory Neil Shapiro **		sig -- incoming signal.
3350c2aa98e2SPeter Wemm **
3351c2aa98e2SPeter Wemm **	Returns:
3352c2aa98e2SPeter Wemm **		none.
3353c2aa98e2SPeter Wemm **
3354c2aa98e2SPeter Wemm **	Side Effects:
3355c2aa98e2SPeter Wemm **		Unlocks the current job.
33568774250cSGregory Neil Shapiro **
33578774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
33588774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
33598774250cSGregory Neil Shapiro **		DOING.
3360c2aa98e2SPeter Wemm */
3361c2aa98e2SPeter Wemm 
3362c2aa98e2SPeter Wemm /* ARGSUSED */
3363c2aa98e2SPeter Wemm SIGFUNC_DECL
intsig(sig)3364c2aa98e2SPeter Wemm intsig(sig)
3365c2aa98e2SPeter Wemm 	int sig;
3366c2aa98e2SPeter Wemm {
336740266059SGregory Neil Shapiro 	bool drop = false;
33688774250cSGregory Neil Shapiro 	int save_errno = errno;
336906f25ae9SGregory Neil Shapiro 
33708774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, intsig);
33718774250cSGregory Neil Shapiro 	errno = save_errno;
33728774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
337340266059SGregory Neil Shapiro 	sm_allsignals(true);
33746f9c8e5bSGregory Neil Shapiro 	IntSig = true;
337540266059SGregory Neil Shapiro 
3376c2aa98e2SPeter Wemm 	FileName = NULL;
337706f25ae9SGregory Neil Shapiro 
337806f25ae9SGregory Neil Shapiro 	/* Clean-up on aborted stdin message submission */
33796f9c8e5bSGregory Neil Shapiro 	if  (OpMode == MD_SMTP ||
338006f25ae9SGregory Neil Shapiro 	     OpMode == MD_DELIVER ||
33816f9c8e5bSGregory Neil Shapiro 	     OpMode == MD_ARPAFTP)
338206f25ae9SGregory Neil Shapiro 	{
33836f9c8e5bSGregory Neil Shapiro 		if (CurEnv->e_id != NULL)
33846f9c8e5bSGregory Neil Shapiro 		{
33856f9c8e5bSGregory Neil Shapiro 			char *fn;
338606f25ae9SGregory Neil Shapiro 
33876f9c8e5bSGregory Neil Shapiro 			fn = queuename(CurEnv, DATAFL_LETTER);
33886f9c8e5bSGregory Neil Shapiro 			if (fn != NULL)
33896f9c8e5bSGregory Neil Shapiro 				(void) unlink(fn);
33906f9c8e5bSGregory Neil Shapiro 			fn = queuename(CurEnv, ANYQFL_LETTER);
33916f9c8e5bSGregory Neil Shapiro 			if (fn != NULL)
33926f9c8e5bSGregory Neil Shapiro 				(void) unlink(fn);
339306f25ae9SGregory Neil Shapiro 		}
33946f9c8e5bSGregory Neil Shapiro 		_exit(EX_OK);
33956f9c8e5bSGregory Neil Shapiro 		/* NOTREACHED */
33966f9c8e5bSGregory Neil Shapiro 	}
33976f9c8e5bSGregory Neil Shapiro 
33986f9c8e5bSGregory Neil Shapiro 	if (sig != 0 && LogLevel > 79)
33996f9c8e5bSGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
34006f9c8e5bSGregory Neil Shapiro 	if (OpMode != MD_TEST)
340106f25ae9SGregory Neil Shapiro 		unlockqueue(CurEnv);
3402c2aa98e2SPeter Wemm 
340340266059SGregory Neil Shapiro 	finis(drop, false, EX_OK);
340440266059SGregory Neil Shapiro 	/* NOTREACHED */
3405c2aa98e2SPeter Wemm }
340640266059SGregory Neil Shapiro /*
3407c2aa98e2SPeter Wemm **  DISCONNECT -- remove our connection with any foreground process
3408c2aa98e2SPeter Wemm **
3409c2aa98e2SPeter Wemm **	Parameters:
3410c2aa98e2SPeter Wemm **		droplev -- how "deeply" we should drop the line.
3411c2aa98e2SPeter Wemm **			0 -- ignore signals, mail back errors, make sure
3412c2aa98e2SPeter Wemm **			     output goes to stdout.
341306f25ae9SGregory Neil Shapiro **			1 -- also, make stdout go to /dev/null.
3414c2aa98e2SPeter Wemm **			2 -- also, disconnect from controlling terminal
3415c2aa98e2SPeter Wemm **			     (only for daemon mode).
3416c2aa98e2SPeter Wemm **		e -- the current envelope.
3417c2aa98e2SPeter Wemm **
3418c2aa98e2SPeter Wemm **	Returns:
3419c2aa98e2SPeter Wemm **		none
3420c2aa98e2SPeter Wemm **
3421c2aa98e2SPeter Wemm **	Side Effects:
3422d39bd2c1SGregory Neil Shapiro **		Try to insure that we are immune to vagaries of
3423c2aa98e2SPeter Wemm **		the controlling tty.
3424c2aa98e2SPeter Wemm */
3425c2aa98e2SPeter Wemm 
3426c2aa98e2SPeter Wemm void
disconnect(droplev,e)3427c2aa98e2SPeter Wemm disconnect(droplev, e)
3428c2aa98e2SPeter Wemm 	int droplev;
3429c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3430c2aa98e2SPeter Wemm {
34312fb4f839SGregory Neil Shapiro #define LOGID(e) (((e) != NULL && (e)->e_id != NULL) ? (e)->e_id : NOQID)
3432c2aa98e2SPeter Wemm 	int fd;
3433c2aa98e2SPeter Wemm 
3434c2aa98e2SPeter Wemm 	if (tTd(52, 1))
343540266059SGregory Neil Shapiro 		sm_dprintf("disconnect: In %d Out %d, e=%p\n",
343640266059SGregory Neil Shapiro 			   sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
34375b0945b5SGregory Neil Shapiro 			   sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL),
34385b0945b5SGregory Neil Shapiro 			   (void *)e);
3439c2aa98e2SPeter Wemm 	if (tTd(52, 100))
3440c2aa98e2SPeter Wemm 	{
344140266059SGregory Neil Shapiro 		sm_dprintf("don't\n");
3442c2aa98e2SPeter Wemm 		return;
3443c2aa98e2SPeter Wemm 	}
3444c2aa98e2SPeter Wemm 	if (LogLevel > 93)
34452fb4f839SGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, LOGID(e),
3446c2aa98e2SPeter Wemm 			  "disconnect level %d",
3447c2aa98e2SPeter Wemm 			  droplev);
3448c2aa98e2SPeter Wemm 
3449c2aa98e2SPeter Wemm 	/* be sure we don't get nasty signals */
345040266059SGregory Neil Shapiro 	(void) sm_signal(SIGINT, SIG_IGN);
345140266059SGregory Neil Shapiro 	(void) sm_signal(SIGQUIT, SIG_IGN);
3452c2aa98e2SPeter Wemm 
3453c2aa98e2SPeter Wemm 	/* we can't communicate with our caller, so.... */
345440266059SGregory Neil Shapiro 	HoldErrs = true;
3455c2aa98e2SPeter Wemm 	CurEnv->e_errormode = EM_MAIL;
3456c2aa98e2SPeter Wemm 	Verbose = 0;
345740266059SGregory Neil Shapiro 	DisConnected = true;
3458c2aa98e2SPeter Wemm 
3459c2aa98e2SPeter Wemm 	/* all input from /dev/null */
346040266059SGregory Neil Shapiro 	if (InChannel != smioin)
3461c2aa98e2SPeter Wemm 	{
346240266059SGregory Neil Shapiro 		(void) sm_io_close(InChannel, SM_TIME_DEFAULT);
346340266059SGregory Neil Shapiro 		InChannel = smioin;
3464c2aa98e2SPeter Wemm 	}
346540266059SGregory Neil Shapiro 	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
346640266059SGregory Neil Shapiro 			 SM_IO_RDONLY, NULL, smioin) == NULL)
34672fb4f839SGregory Neil Shapiro 		sm_syslog(LOG_ERR, LOGID(e),
346840266059SGregory Neil Shapiro 			  "disconnect: sm_io_reopen(\"%s\") failed: %s",
346940266059SGregory Neil Shapiro 			  SM_PATH_DEVNULL, sm_errstring(errno));
3470c2aa98e2SPeter Wemm 
347140266059SGregory Neil Shapiro 	/*
347240266059SGregory Neil Shapiro 	**  output to the transcript
347340266059SGregory Neil Shapiro 	**	We also compare the fd numbers here since OutChannel
347440266059SGregory Neil Shapiro 	**	might be a layer on top of smioout due to encryption
347540266059SGregory Neil Shapiro 	**	(see sfsasl.c).
347640266059SGregory Neil Shapiro 	*/
347740266059SGregory Neil Shapiro 
347840266059SGregory Neil Shapiro 	if (OutChannel != smioout &&
347940266059SGregory Neil Shapiro 	    sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=
348040266059SGregory Neil Shapiro 	    sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))
3481c2aa98e2SPeter Wemm 	{
348240266059SGregory Neil Shapiro 		(void) sm_io_close(OutChannel, SM_TIME_DEFAULT);
348340266059SGregory Neil Shapiro 		OutChannel = smioout;
348440266059SGregory Neil Shapiro 
348540266059SGregory Neil Shapiro #if 0
348640266059SGregory Neil Shapiro 		/*
348740266059SGregory Neil Shapiro 		**  Has smioout been closed? Reopen it.
348840266059SGregory Neil Shapiro 		**	This shouldn't happen anymore, the code is here
348940266059SGregory Neil Shapiro 		**	just as a reminder.
349040266059SGregory Neil Shapiro 		*/
349140266059SGregory Neil Shapiro 
349240266059SGregory Neil Shapiro 		if (smioout->sm_magic == NULL &&
349340266059SGregory Neil Shapiro 		    sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
349440266059SGregory Neil Shapiro 				 SM_IO_WRONLY, NULL, smioout) == NULL)
34952fb4f839SGregory Neil Shapiro 			sm_syslog(LOG_ERR, LOGID(e),
349640266059SGregory Neil Shapiro 				  "disconnect: sm_io_reopen(\"%s\") failed: %s",
349740266059SGregory Neil Shapiro 				  SM_PATH_DEVNULL, sm_errstring(errno));
349840266059SGregory Neil Shapiro #endif /* 0 */
3499c2aa98e2SPeter Wemm 	}
3500c2aa98e2SPeter Wemm 	if (droplev > 0)
3501c2aa98e2SPeter Wemm 	{
350240266059SGregory Neil Shapiro 		fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);
3503c2aa98e2SPeter Wemm 		if (fd == -1)
3504af9557fdSGregory Neil Shapiro 		{
35052fb4f839SGregory Neil Shapiro 			sm_syslog(LOG_ERR, LOGID(e),
350640266059SGregory Neil Shapiro 				  "disconnect: open(\"%s\") failed: %s",
350740266059SGregory Neil Shapiro 				  SM_PATH_DEVNULL, sm_errstring(errno));
3508af9557fdSGregory Neil Shapiro 		}
350940266059SGregory Neil Shapiro 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
3510af9557fdSGregory Neil Shapiro 		if (fd >= 0)
3511af9557fdSGregory Neil Shapiro 		{
351206f25ae9SGregory Neil Shapiro 			(void) dup2(fd, STDOUT_FILENO);
351306f25ae9SGregory Neil Shapiro 			(void) dup2(fd, STDERR_FILENO);
351406f25ae9SGregory Neil Shapiro 			(void) close(fd);
3515c2aa98e2SPeter Wemm 		}
3516af9557fdSGregory Neil Shapiro 	}
3517c2aa98e2SPeter Wemm 
3518c2aa98e2SPeter Wemm 	/* drop our controlling TTY completely if possible */
3519c2aa98e2SPeter Wemm 	if (droplev > 1)
3520c2aa98e2SPeter Wemm 	{
3521c2aa98e2SPeter Wemm 		(void) setsid();
3522c2aa98e2SPeter Wemm 		errno = 0;
3523c2aa98e2SPeter Wemm 	}
3524c2aa98e2SPeter Wemm 
3525c2aa98e2SPeter Wemm 	checkfd012("disconnect");
3526c2aa98e2SPeter Wemm 
3527c2aa98e2SPeter Wemm 	if (LogLevel > 71)
35282fb4f839SGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, LOGID(e), "in background, pid=%d",
352940266059SGregory Neil Shapiro 			  (int) CurrentPid);
3530c2aa98e2SPeter Wemm 
3531c2aa98e2SPeter Wemm 	errno = 0;
3532c2aa98e2SPeter Wemm }
3533c2aa98e2SPeter Wemm 
3534c2aa98e2SPeter Wemm static void
obsolete(argv)3535c2aa98e2SPeter Wemm obsolete(argv)
3536c2aa98e2SPeter Wemm 	char *argv[];
3537c2aa98e2SPeter Wemm {
3538c2aa98e2SPeter Wemm 	register char *ap;
3539c2aa98e2SPeter Wemm 	register char *op;
3540c2aa98e2SPeter Wemm 
3541c2aa98e2SPeter Wemm 	while ((ap = *++argv) != NULL)
3542c2aa98e2SPeter Wemm 	{
3543c2aa98e2SPeter Wemm 		/* Return if "--" or not an option of any form. */
3544c2aa98e2SPeter Wemm 		if (ap[0] != '-' || ap[1] == '-')
3545c2aa98e2SPeter Wemm 			return;
3546c2aa98e2SPeter Wemm 
354740266059SGregory Neil Shapiro 		/* Don't allow users to use "-Q." or "-Q ." */
354840266059SGregory Neil Shapiro 		if ((ap[1] == 'Q' && ap[2] == '.') ||
354940266059SGregory Neil Shapiro 		    (ap[1] == 'Q' && argv[1] != NULL &&
355040266059SGregory Neil Shapiro 		     argv[1][0] == '.' && argv[1][1] == '\0'))
355140266059SGregory Neil Shapiro 		{
355240266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
355340266059SGregory Neil Shapiro 					     "Can not use -Q.\n");
355440266059SGregory Neil Shapiro 			exit(EX_USAGE);
355540266059SGregory Neil Shapiro 		}
355640266059SGregory Neil Shapiro 
3557c2aa98e2SPeter Wemm 		/* skip over options that do have a value */
3558c2aa98e2SPeter Wemm 		op = strchr(OPTIONS, ap[1]);
3559c2aa98e2SPeter Wemm 		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
3560c2aa98e2SPeter Wemm 		    ap[1] != 'd' &&
3561c2aa98e2SPeter Wemm #if defined(sony_news)
3562c2aa98e2SPeter Wemm 		    ap[1] != 'E' && ap[1] != 'J' &&
35635b0945b5SGregory Neil Shapiro #endif
3564c2aa98e2SPeter Wemm 		    argv[1] != NULL && argv[1][0] != '-')
3565c2aa98e2SPeter Wemm 		{
3566c2aa98e2SPeter Wemm 			argv++;
3567c2aa98e2SPeter Wemm 			continue;
3568c2aa98e2SPeter Wemm 		}
3569c2aa98e2SPeter Wemm 
3570c2aa98e2SPeter Wemm 		/* If -C doesn't have an argument, use sendmail.cf. */
3571c2aa98e2SPeter Wemm #define __DEFPATH	"sendmail.cf"
3572c2aa98e2SPeter Wemm 		if (ap[1] == 'C' && ap[2] == '\0')
3573c2aa98e2SPeter Wemm 		{
3574c2aa98e2SPeter Wemm 			*argv = xalloc(sizeof(__DEFPATH) + 2);
357540266059SGregory Neil Shapiro 			(void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,
357640266059SGregory Neil Shapiro 					   "-C", __DEFPATH);
3577c2aa98e2SPeter Wemm 		}
3578c2aa98e2SPeter Wemm 
3579c2aa98e2SPeter Wemm 		/* If -q doesn't have an argument, run it once. */
3580c2aa98e2SPeter Wemm 		if (ap[1] == 'q' && ap[2] == '\0')
3581c2aa98e2SPeter Wemm 			*argv = "-q0";
3582c2aa98e2SPeter Wemm 
358340266059SGregory Neil Shapiro 		/* If -Q doesn't have an argument, disable quarantining */
358440266059SGregory Neil Shapiro 		if (ap[1] == 'Q' && ap[2] == '\0')
358540266059SGregory Neil Shapiro 			*argv = "-Q.";
358640266059SGregory Neil Shapiro 
3587c2aa98e2SPeter Wemm 		/* if -d doesn't have an argument, use 0-99.1 */
3588c2aa98e2SPeter Wemm 		if (ap[1] == 'd' && ap[2] == '\0')
3589c2aa98e2SPeter Wemm 			*argv = "-d0-99.1";
3590c2aa98e2SPeter Wemm 
3591c2aa98e2SPeter Wemm #if defined(sony_news)
3592c2aa98e2SPeter Wemm 		/* if -E doesn't have an argument, use -EC */
3593c2aa98e2SPeter Wemm 		if (ap[1] == 'E' && ap[2] == '\0')
3594c2aa98e2SPeter Wemm 			*argv = "-EC";
3595c2aa98e2SPeter Wemm 
3596c2aa98e2SPeter Wemm 		/* if -J doesn't have an argument, use -JJ */
3597c2aa98e2SPeter Wemm 		if (ap[1] == 'J' && ap[2] == '\0')
3598c2aa98e2SPeter Wemm 			*argv = "-JJ";
359906f25ae9SGregory Neil Shapiro #endif /* defined(sony_news) */
3600c2aa98e2SPeter Wemm 	}
3601c2aa98e2SPeter Wemm }
360240266059SGregory Neil Shapiro /*
3603c2aa98e2SPeter Wemm **  AUTH_WARNING -- specify authorization warning
3604c2aa98e2SPeter Wemm **
3605c2aa98e2SPeter Wemm **	Parameters:
3606c2aa98e2SPeter Wemm **		e -- the current envelope.
3607c2aa98e2SPeter Wemm **		msg -- the text of the message.
3608c2aa98e2SPeter Wemm **		args -- arguments to the message.
3609c2aa98e2SPeter Wemm **
3610c2aa98e2SPeter Wemm **	Returns:
3611c2aa98e2SPeter Wemm **		none.
3612c2aa98e2SPeter Wemm */
3613c2aa98e2SPeter Wemm 
3614c2aa98e2SPeter Wemm void
3615c2aa98e2SPeter Wemm #ifdef __STDC__
auth_warning(register ENVELOPE * e,const char * msg,...)3616c2aa98e2SPeter Wemm auth_warning(register ENVELOPE *e, const char *msg, ...)
361706f25ae9SGregory Neil Shapiro #else /* __STDC__ */
3618c2aa98e2SPeter Wemm auth_warning(e, msg, va_alist)
3619c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3620c2aa98e2SPeter Wemm 	const char *msg;
3621c2aa98e2SPeter Wemm 	va_dcl
362206f25ae9SGregory Neil Shapiro #endif /* __STDC__ */
3623c2aa98e2SPeter Wemm {
3624c2aa98e2SPeter Wemm 	char buf[MAXLINE];
362540266059SGregory Neil Shapiro 	SM_VA_LOCAL_DECL
36262fb4f839SGregory Neil Shapiro 	char *p;
3627c2aa98e2SPeter Wemm 	static char hostbuf[48];
3628c2aa98e2SPeter Wemm 
36292fb4f839SGregory Neil Shapiro 	if (!bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
36302fb4f839SGregory Neil Shapiro 		return;
36312fb4f839SGregory Neil Shapiro 
3632c2aa98e2SPeter Wemm 	if (hostbuf[0] == '\0')
3633193538b7SGregory Neil Shapiro 	{
3634193538b7SGregory Neil Shapiro 		struct hostent *hp;
3635193538b7SGregory Neil Shapiro 
3636d0cef73dSGregory Neil Shapiro 		hp = myhostname(hostbuf, sizeof(hostbuf));
363740266059SGregory Neil Shapiro #if NETINET6
3638193538b7SGregory Neil Shapiro 		if (hp != NULL)
3639193538b7SGregory Neil Shapiro 		{
3640193538b7SGregory Neil Shapiro 			freehostent(hp);
3641193538b7SGregory Neil Shapiro 			hp = NULL;
3642193538b7SGregory Neil Shapiro 		}
364340266059SGregory Neil Shapiro #endif /* NETINET6 */
3644193538b7SGregory Neil Shapiro 	}
3645c2aa98e2SPeter Wemm 
3646d0cef73dSGregory Neil Shapiro 	(void) sm_strlcpyn(buf, sizeof(buf), 2, hostbuf, ": ");
3647c2aa98e2SPeter Wemm 	p = &buf[strlen(buf)];
364840266059SGregory Neil Shapiro 	SM_VA_START(ap, msg);
364940266059SGregory Neil Shapiro 	(void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);
365040266059SGregory Neil Shapiro 	SM_VA_END(ap);
3651d0cef73dSGregory Neil Shapiro 	addheader("X-Authentication-Warning", buf, 0, e, true);
3652c2aa98e2SPeter Wemm 	if (LogLevel > 3)
3653c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
36542fb4f839SGregory Neil Shapiro 			  "Authentication-Warning: %.400s", buf);
3655c2aa98e2SPeter Wemm }
365640266059SGregory Neil Shapiro /*
3657c2aa98e2SPeter Wemm **  GETEXTENV -- get from external environment
3658c2aa98e2SPeter Wemm **
3659c2aa98e2SPeter Wemm **	Parameters:
3660c2aa98e2SPeter Wemm **		envar -- the name of the variable to retrieve
3661c2aa98e2SPeter Wemm **
3662c2aa98e2SPeter Wemm **	Returns:
3663c2aa98e2SPeter Wemm **		The value, if any.
3664c2aa98e2SPeter Wemm */
3665c2aa98e2SPeter Wemm 
366640266059SGregory Neil Shapiro static char *
getextenv(envar)3667c2aa98e2SPeter Wemm getextenv(envar)
3668c2aa98e2SPeter Wemm 	const char *envar;
3669c2aa98e2SPeter Wemm {
3670c2aa98e2SPeter Wemm 	char **envp;
3671c2aa98e2SPeter Wemm 	int l;
3672c2aa98e2SPeter Wemm 
3673c2aa98e2SPeter Wemm 	l = strlen(envar);
3674959366dcSGregory Neil Shapiro 	for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++)
3675c2aa98e2SPeter Wemm 	{
3676c2aa98e2SPeter Wemm 		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
3677c2aa98e2SPeter Wemm 			return &(*envp)[l + 1];
3678c2aa98e2SPeter Wemm 	}
3679c2aa98e2SPeter Wemm 	return NULL;
3680c2aa98e2SPeter Wemm }
368140266059SGregory Neil Shapiro /*
36824e4196cbSGregory Neil Shapiro **  SM_SETUSERENV -- set an environment variable in the propagated environment
3683c2aa98e2SPeter Wemm **
3684c2aa98e2SPeter Wemm **	Parameters:
3685c2aa98e2SPeter Wemm **		envar -- the name of the environment variable.
3686c2aa98e2SPeter Wemm **		value -- the value to which it should be set.  If
3687c2aa98e2SPeter Wemm **			null, this is extracted from the incoming
3688c2aa98e2SPeter Wemm **			environment.  If that is not set, the call
36894e4196cbSGregory Neil Shapiro **			to sm_setuserenv is ignored.
3690c2aa98e2SPeter Wemm **
3691c2aa98e2SPeter Wemm **	Returns:
3692c2aa98e2SPeter Wemm **		none.
3693c2aa98e2SPeter Wemm */
3694c2aa98e2SPeter Wemm 
3695c2aa98e2SPeter Wemm void
sm_setuserenv(envar,value)36964e4196cbSGregory Neil Shapiro sm_setuserenv(envar, value)
3697c2aa98e2SPeter Wemm 	const char *envar;
3698c2aa98e2SPeter Wemm 	const char *value;
3699c2aa98e2SPeter Wemm {
370006f25ae9SGregory Neil Shapiro 	int i, l;
3701c2aa98e2SPeter Wemm 	char **evp = UserEnviron;
3702c2aa98e2SPeter Wemm 	char *p;
3703c2aa98e2SPeter Wemm 
3704c2aa98e2SPeter Wemm 	if (value == NULL)
3705c2aa98e2SPeter Wemm 	{
3706c2aa98e2SPeter Wemm 		value = getextenv(envar);
3707c2aa98e2SPeter Wemm 		if (value == NULL)
3708c2aa98e2SPeter Wemm 			return;
3709c2aa98e2SPeter Wemm 	}
3710c2aa98e2SPeter Wemm 
371140266059SGregory Neil Shapiro 	/* XXX enforce reasonable size? */
371206f25ae9SGregory Neil Shapiro 	i = strlen(envar) + 1;
371306f25ae9SGregory Neil Shapiro 	l = strlen(value) + i + 1;
37142fb4f839SGregory Neil Shapiro 	p = (char *) sm_malloc_tagged_x(l, "setuserenv", 0, 0);
371540266059SGregory Neil Shapiro 	(void) sm_strlcpyn(p, l, 3, envar, "=", value);
3716c2aa98e2SPeter Wemm 
3717c2aa98e2SPeter Wemm 	while (*evp != NULL && strncmp(*evp, p, i) != 0)
3718c2aa98e2SPeter Wemm 		evp++;
3719c2aa98e2SPeter Wemm 	if (*evp != NULL)
3720c2aa98e2SPeter Wemm 	{
3721c2aa98e2SPeter Wemm 		*evp++ = p;
3722c2aa98e2SPeter Wemm 	}
3723c2aa98e2SPeter Wemm 	else if (evp < &UserEnviron[MAXUSERENVIRON])
3724c2aa98e2SPeter Wemm 	{
3725c2aa98e2SPeter Wemm 		*evp++ = p;
3726c2aa98e2SPeter Wemm 		*evp = NULL;
3727c2aa98e2SPeter Wemm 	}
3728c2aa98e2SPeter Wemm 
3729c2aa98e2SPeter Wemm 	/* make sure it is in our environment as well */
3730c2aa98e2SPeter Wemm 	if (putenv(p) < 0)
37314e4196cbSGregory Neil Shapiro 		syserr("sm_setuserenv: putenv(%s) failed", p);
3732c2aa98e2SPeter Wemm }
373340266059SGregory Neil Shapiro /*
3734c2aa98e2SPeter Wemm **  DUMPSTATE -- dump state
3735c2aa98e2SPeter Wemm **
3736c2aa98e2SPeter Wemm **	For debugging.
3737c2aa98e2SPeter Wemm */
3738c2aa98e2SPeter Wemm 
3739c2aa98e2SPeter Wemm void
dumpstate(when)3740c2aa98e2SPeter Wemm dumpstate(when)
3741c2aa98e2SPeter Wemm 	char *when;
3742c2aa98e2SPeter Wemm {
3743c2aa98e2SPeter Wemm 	register char *j = macvalue('j', CurEnv);
3744c2aa98e2SPeter Wemm 	int rs;
374506f25ae9SGregory Neil Shapiro 	extern int NextMacroId;
3746c2aa98e2SPeter Wemm 
3747c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id,
3748c2aa98e2SPeter Wemm 		  "--- dumping state on %s: $j = %s ---",
3749c2aa98e2SPeter Wemm 		  when,
3750c2aa98e2SPeter Wemm 		  j == NULL ? "<NULL>" : j);
3751c2aa98e2SPeter Wemm 	if (j != NULL)
3752c2aa98e2SPeter Wemm 	{
3753c2aa98e2SPeter Wemm 		if (!wordinclass(j, 'w'))
3754c2aa98e2SPeter Wemm 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
3755c2aa98e2SPeter Wemm 				  "*** $j not in $=w ***");
3756c2aa98e2SPeter Wemm 	}
3757c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
375840266059SGregory Neil Shapiro 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)",
375906f25ae9SGregory Neil Shapiro 		  NextMacroId, MAXMACROID);
3760c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
376140266059SGregory Neil Shapiro 	printopenfds(true);
3762c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
3763e92d3f3fSGregory Neil Shapiro 	mci_dump_all(smioout, true);
3764c2aa98e2SPeter Wemm 	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
3765c2aa98e2SPeter Wemm 	if (rs > 0)
3766c2aa98e2SPeter Wemm 	{
376706f25ae9SGregory Neil Shapiro 		int status;
3768c2aa98e2SPeter Wemm 		register char **pvp;
3769c2aa98e2SPeter Wemm 		char *pv[MAXATOM + 1];
3770c2aa98e2SPeter Wemm 
3771c2aa98e2SPeter Wemm 		pv[0] = NULL;
377240266059SGregory Neil Shapiro 		status = REWRITE(pv, rs, CurEnv);
3773c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
3774c2aa98e2SPeter Wemm 			  "--- ruleset debug_dumpstate returns stat %d, pv: ---",
377506f25ae9SGregory Neil Shapiro 			  status);
3776c2aa98e2SPeter Wemm 		for (pvp = pv; *pvp != NULL; pvp++)
3777c2aa98e2SPeter Wemm 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
3778c2aa98e2SPeter Wemm 	}
3779c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
3780c2aa98e2SPeter Wemm }
378140266059SGregory Neil Shapiro 
378213058a91SGregory Neil Shapiro #ifdef SIGUSR1
378340266059SGregory Neil Shapiro /*
37848774250cSGregory Neil Shapiro **  SIGUSR1 -- Signal a request to dump state.
37858774250cSGregory Neil Shapiro **
37868774250cSGregory Neil Shapiro **	Parameters:
37878774250cSGregory Neil Shapiro **		sig -- calling signal.
37888774250cSGregory Neil Shapiro **
37898774250cSGregory Neil Shapiro **	Returns:
37908774250cSGregory Neil Shapiro **		none.
37918774250cSGregory Neil Shapiro **
37928774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
37938774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
37948774250cSGregory Neil Shapiro **		DOING.
37958774250cSGregory Neil Shapiro **
37968774250cSGregory Neil Shapiro **		XXX: More work is needed for this signal handler.
37978774250cSGregory Neil Shapiro */
3798c2aa98e2SPeter Wemm 
3799c2aa98e2SPeter Wemm /* ARGSUSED */
38008774250cSGregory Neil Shapiro static SIGFUNC_DECL
sigusr1(sig)3801c2aa98e2SPeter Wemm sigusr1(sig)
3802c2aa98e2SPeter Wemm 	int sig;
3803c2aa98e2SPeter Wemm {
38048774250cSGregory Neil Shapiro 	int save_errno = errno;
38058774250cSGregory Neil Shapiro 
38068774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigusr1);
38078774250cSGregory Neil Shapiro 	errno = save_errno;
38088774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
3809c2aa98e2SPeter Wemm 	dumpstate("user signal");
381040266059SGregory Neil Shapiro # if SM_HEAP_CHECK
381140266059SGregory Neil Shapiro 	dumpstab();
38125b0945b5SGregory Neil Shapiro # endif
38138774250cSGregory Neil Shapiro 	errno = save_errno;
3814c2aa98e2SPeter Wemm 	return SIGFUNC_RETURN;
3815c2aa98e2SPeter Wemm }
381613058a91SGregory Neil Shapiro #endif /* SIGUSR1 */
381740266059SGregory Neil Shapiro 
381840266059SGregory Neil Shapiro /*
3819c2aa98e2SPeter Wemm **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
3820c2aa98e2SPeter Wemm **
3821c2aa98e2SPeter Wemm **	Parameters:
3822c2aa98e2SPeter Wemm **		to_real_uid -- if set, drop to the real uid instead
3823c2aa98e2SPeter Wemm **			of the RunAsUser.
3824c2aa98e2SPeter Wemm **
3825c2aa98e2SPeter Wemm **	Returns:
3826c2aa98e2SPeter Wemm **		EX_OSERR if the setuid failed.
3827c2aa98e2SPeter Wemm **		EX_OK otherwise.
3828c2aa98e2SPeter Wemm */
3829c2aa98e2SPeter Wemm 
3830c2aa98e2SPeter Wemm int
drop_privileges(to_real_uid)3831c2aa98e2SPeter Wemm drop_privileges(to_real_uid)
3832c2aa98e2SPeter Wemm 	bool to_real_uid;
3833c2aa98e2SPeter Wemm {
3834c2aa98e2SPeter Wemm 	int rval = EX_OK;
3835c2aa98e2SPeter Wemm 	GIDSET_T emptygidset[1];
3836c2aa98e2SPeter Wemm 
3837c2aa98e2SPeter Wemm 	if (tTd(47, 1))
3838da7d7b9cSGregory Neil Shapiro 		sm_dprintf("drop_privileges(%d): Real[UG]id=%ld:%ld, get[ug]id=%ld:%ld, gete[ug]id=%ld:%ld, RunAs[UG]id=%ld:%ld\n",
383940266059SGregory Neil Shapiro 			   (int) to_real_uid,
3840da7d7b9cSGregory Neil Shapiro 			   (long) RealUid, (long) RealGid,
3841da7d7b9cSGregory Neil Shapiro 			   (long) getuid(), (long) getgid(),
3842da7d7b9cSGregory Neil Shapiro 			   (long) geteuid(), (long) getegid(),
3843da7d7b9cSGregory Neil Shapiro 			   (long) RunAsUid, (long) RunAsGid);
3844c2aa98e2SPeter Wemm 
3845c2aa98e2SPeter Wemm 	if (to_real_uid)
3846c2aa98e2SPeter Wemm 	{
3847c2aa98e2SPeter Wemm 		RunAsUserName = RealUserName;
3848c2aa98e2SPeter Wemm 		RunAsUid = RealUid;
3849c2aa98e2SPeter Wemm 		RunAsGid = RealGid;
3850605302a5SGregory Neil Shapiro 		EffGid = RunAsGid;
3851c2aa98e2SPeter Wemm 	}
3852c2aa98e2SPeter Wemm 
3853c2aa98e2SPeter Wemm 	/* make sure no one can grab open descriptors for secret files */
3854c2aa98e2SPeter Wemm 	endpwent();
385540266059SGregory Neil Shapiro 	sm_mbdb_terminate();
3856c2aa98e2SPeter Wemm 
3857c2aa98e2SPeter Wemm 	/* reset group permissions; these can be set later */
3858c2aa98e2SPeter Wemm 	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
385940266059SGregory Neil Shapiro 
386040266059SGregory Neil Shapiro 	/*
386140266059SGregory Neil Shapiro 	**  Notice:  on some OS (Linux...) the setgroups() call causes
386240266059SGregory Neil Shapiro 	**	a logfile entry if sendmail is not run by root.
386340266059SGregory Neil Shapiro 	**	However, it is unclear (no POSIX standard) whether
386440266059SGregory Neil Shapiro 	**	setgroups() can only succeed if executed by root.
386540266059SGregory Neil Shapiro 	**	So for now we keep it as it is; if you want to change it, use
386640266059SGregory Neil Shapiro 	**  if (geteuid() == 0 && setgroups(1, emptygidset) == -1)
386740266059SGregory Neil Shapiro 	*/
386840266059SGregory Neil Shapiro 
3869c2aa98e2SPeter Wemm 	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
387006f25ae9SGregory Neil Shapiro 	{
387106f25ae9SGregory Neil Shapiro 		syserr("drop_privileges: setgroups(1, %d) failed",
387206f25ae9SGregory Neil Shapiro 		       (int) emptygidset[0]);
3873c2aa98e2SPeter Wemm 		rval = EX_OSERR;
387406f25ae9SGregory Neil Shapiro 	}
3875c2aa98e2SPeter Wemm 
387640266059SGregory Neil Shapiro 	/* reset primary group id */
387740266059SGregory Neil Shapiro 	if (to_real_uid)
387806f25ae9SGregory Neil Shapiro 	{
387940266059SGregory Neil Shapiro 		/*
388040266059SGregory Neil Shapiro 		**  Drop gid to real gid.
388140266059SGregory Neil Shapiro 		**  On some OS we must reset the effective[/real[/saved]] gid,
388240266059SGregory Neil Shapiro 		**  and then use setgid() to finally drop all group privileges.
388340266059SGregory Neil Shapiro 		**  Later on we check whether we can get back the
388440266059SGregory Neil Shapiro 		**  effective gid.
388540266059SGregory Neil Shapiro 		*/
388640266059SGregory Neil Shapiro 
388740266059SGregory Neil Shapiro #if HASSETEGID
388840266059SGregory Neil Shapiro 		if (setegid(RunAsGid) < 0)
388940266059SGregory Neil Shapiro 		{
389040266059SGregory Neil Shapiro 			syserr("drop_privileges: setegid(%d) failed",
389140266059SGregory Neil Shapiro 			       (int) RunAsGid);
3892c2aa98e2SPeter Wemm 			rval = EX_OSERR;
389306f25ae9SGregory Neil Shapiro 		}
389440266059SGregory Neil Shapiro #else /* HASSETEGID */
389540266059SGregory Neil Shapiro # if HASSETREGID
389640266059SGregory Neil Shapiro 		if (setregid(RunAsGid, RunAsGid) < 0)
389740266059SGregory Neil Shapiro 		{
389840266059SGregory Neil Shapiro 			syserr("drop_privileges: setregid(%d, %d) failed",
389940266059SGregory Neil Shapiro 			       (int) RunAsGid, (int) RunAsGid);
390040266059SGregory Neil Shapiro 			rval = EX_OSERR;
390140266059SGregory Neil Shapiro 		}
390240266059SGregory Neil Shapiro # else /* HASSETREGID */
390340266059SGregory Neil Shapiro #  if HASSETRESGID
390440266059SGregory Neil Shapiro 		if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0)
390540266059SGregory Neil Shapiro 		{
390640266059SGregory Neil Shapiro 			syserr("drop_privileges: setresgid(%d, %d, %d) failed",
390740266059SGregory Neil Shapiro 			       (int) RunAsGid, (int) RunAsGid, (int) RunAsGid);
390840266059SGregory Neil Shapiro 			rval = EX_OSERR;
390940266059SGregory Neil Shapiro 		}
391040266059SGregory Neil Shapiro #  endif /* HASSETRESGID */
391140266059SGregory Neil Shapiro # endif /* HASSETREGID */
391240266059SGregory Neil Shapiro #endif /* HASSETEGID */
391340266059SGregory Neil Shapiro 	}
391440266059SGregory Neil Shapiro 	if (rval == EX_OK && (to_real_uid || RunAsGid != 0))
391540266059SGregory Neil Shapiro 	{
391640266059SGregory Neil Shapiro 		if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid))
391740266059SGregory Neil Shapiro 		{
3918da7d7b9cSGregory Neil Shapiro 			syserr("drop_privileges: setgid(%ld) failed",
3919da7d7b9cSGregory Neil Shapiro 			       (long) RunAsGid);
392040266059SGregory Neil Shapiro 			rval = EX_OSERR;
392140266059SGregory Neil Shapiro 		}
392240266059SGregory Neil Shapiro 		errno = 0;
392340266059SGregory Neil Shapiro 		if (rval == EX_OK && getegid() != RunAsGid)
392440266059SGregory Neil Shapiro 		{
3925da7d7b9cSGregory Neil Shapiro 			syserr("drop_privileges: Unable to set effective gid=%ld to RunAsGid=%ld",
3926da7d7b9cSGregory Neil Shapiro 			       (long) getegid(), (long) RunAsGid);
392740266059SGregory Neil Shapiro 			rval = EX_OSERR;
392840266059SGregory Neil Shapiro 		}
392940266059SGregory Neil Shapiro 	}
393040266059SGregory Neil Shapiro 
393140266059SGregory Neil Shapiro 	/* fiddle with uid */
393206f25ae9SGregory Neil Shapiro 	if (to_real_uid || RunAsUid != 0)
393306f25ae9SGregory Neil Shapiro 	{
3934605302a5SGregory Neil Shapiro 		uid_t euid;
393506f25ae9SGregory Neil Shapiro 
393640266059SGregory Neil Shapiro 		/*
393740266059SGregory Neil Shapiro 		**  Try to setuid(RunAsUid).
393840266059SGregory Neil Shapiro 		**  euid must be RunAsUid,
3939605302a5SGregory Neil Shapiro 		**  ruid must be RunAsUid unless (e|r)uid wasn't 0
3940605302a5SGregory Neil Shapiro 		**	and we didn't have to drop privileges to the real uid.
394140266059SGregory Neil Shapiro 		*/
394240266059SGregory Neil Shapiro 
394340266059SGregory Neil Shapiro 		if (setuid(RunAsUid) < 0 ||
3944605302a5SGregory Neil Shapiro 		    geteuid() != RunAsUid ||
394540266059SGregory Neil Shapiro 		    (getuid() != RunAsUid &&
3946605302a5SGregory Neil Shapiro 		     (to_real_uid || geteuid() == 0 || getuid() == 0)))
394740266059SGregory Neil Shapiro 		{
394840266059SGregory Neil Shapiro #if HASSETREUID
394940266059SGregory Neil Shapiro 			/*
395040266059SGregory Neil Shapiro 			**  if ruid != RunAsUid, euid == RunAsUid, then
395140266059SGregory Neil Shapiro 			**  try resetting just the real uid, then using
395240266059SGregory Neil Shapiro 			**  setuid() to drop the saved-uid as well.
395340266059SGregory Neil Shapiro 			*/
395440266059SGregory Neil Shapiro 
3955605302a5SGregory Neil Shapiro 			if (geteuid() == RunAsUid)
395640266059SGregory Neil Shapiro 			{
395740266059SGregory Neil Shapiro 				if (setreuid(RunAsUid, -1) < 0)
395840266059SGregory Neil Shapiro 				{
395940266059SGregory Neil Shapiro 					syserr("drop_privileges: setreuid(%d, -1) failed",
396040266059SGregory Neil Shapiro 					       (int) RunAsUid);
396140266059SGregory Neil Shapiro 					rval = EX_OSERR;
396240266059SGregory Neil Shapiro 				}
396306f25ae9SGregory Neil Shapiro 				if (setuid(RunAsUid) < 0)
396406f25ae9SGregory Neil Shapiro 				{
396540266059SGregory Neil Shapiro 					syserr("drop_privileges: second setuid(%d) attempt failed",
396640266059SGregory Neil Shapiro 					       (int) RunAsUid);
396740266059SGregory Neil Shapiro 					rval = EX_OSERR;
396840266059SGregory Neil Shapiro 				}
396940266059SGregory Neil Shapiro 			}
397040266059SGregory Neil Shapiro 			else
397140266059SGregory Neil Shapiro #endif /* HASSETREUID */
397240266059SGregory Neil Shapiro 			{
397306f25ae9SGregory Neil Shapiro 				syserr("drop_privileges: setuid(%d) failed",
397406f25ae9SGregory Neil Shapiro 				       (int) RunAsUid);
3975c2aa98e2SPeter Wemm 				rval = EX_OSERR;
397606f25ae9SGregory Neil Shapiro 			}
397740266059SGregory Neil Shapiro 		}
3978605302a5SGregory Neil Shapiro 		euid = geteuid();
397940266059SGregory Neil Shapiro 		if (RunAsUid != 0 && setuid(0) == 0)
398006f25ae9SGregory Neil Shapiro 		{
398106f25ae9SGregory Neil Shapiro 			/*
398206f25ae9SGregory Neil Shapiro 			**  Believe it or not, the Linux capability model
398306f25ae9SGregory Neil Shapiro 			**  allows a non-root process to override setuid()
398406f25ae9SGregory Neil Shapiro 			**  on a process running as root and prevent that
398506f25ae9SGregory Neil Shapiro 			**  process from dropping privileges.
398606f25ae9SGregory Neil Shapiro 			*/
398706f25ae9SGregory Neil Shapiro 
398806f25ae9SGregory Neil Shapiro 			syserr("drop_privileges: setuid(0) succeeded (when it should not)");
398906f25ae9SGregory Neil Shapiro 			rval = EX_OSERR;
399006f25ae9SGregory Neil Shapiro 		}
399106f25ae9SGregory Neil Shapiro 		else if (RunAsUid != euid && setuid(euid) == 0)
399206f25ae9SGregory Neil Shapiro 		{
399306f25ae9SGregory Neil Shapiro 			/*
399406f25ae9SGregory Neil Shapiro 			**  Some operating systems will keep the saved-uid
399506f25ae9SGregory Neil Shapiro 			**  if a non-root effective-uid calls setuid(real-uid)
399606f25ae9SGregory Neil Shapiro 			**  making it possible to set it back again later.
399706f25ae9SGregory Neil Shapiro 			*/
399806f25ae9SGregory Neil Shapiro 
399940266059SGregory Neil Shapiro 			syserr("drop_privileges: Unable to drop non-root set-user-ID privileges");
400006f25ae9SGregory Neil Shapiro 			rval = EX_OSERR;
400106f25ae9SGregory Neil Shapiro 		}
400206f25ae9SGregory Neil Shapiro 	}
400340266059SGregory Neil Shapiro 
400440266059SGregory Neil Shapiro 	if ((to_real_uid || RunAsGid != 0) &&
400540266059SGregory Neil Shapiro 	    rval == EX_OK && RunAsGid != EffGid &&
400640266059SGregory Neil Shapiro 	    getuid() != 0 && geteuid() != 0)
400740266059SGregory Neil Shapiro 	{
400840266059SGregory Neil Shapiro 		errno = 0;
400940266059SGregory Neil Shapiro 		if (setgid(EffGid) == 0)
401040266059SGregory Neil Shapiro 		{
401140266059SGregory Neil Shapiro 			syserr("drop_privileges: setgid(%d) succeeded (when it should not)",
401240266059SGregory Neil Shapiro 			       (int) EffGid);
401340266059SGregory Neil Shapiro 			rval = EX_OSERR;
401440266059SGregory Neil Shapiro 		}
401540266059SGregory Neil Shapiro 	}
401640266059SGregory Neil Shapiro 
4017c2aa98e2SPeter Wemm 	if (tTd(47, 5))
4018c2aa98e2SPeter Wemm 	{
401940266059SGregory Neil Shapiro 		sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
402006f25ae9SGregory Neil Shapiro 			   (int) geteuid(), (int) getuid(),
402106f25ae9SGregory Neil Shapiro 			   (int) getegid(), (int) getgid());
402240266059SGregory Neil Shapiro 		sm_dprintf("drop_privileges: RunAsUser = %d:%d\n",
402306f25ae9SGregory Neil Shapiro 			   (int) RunAsUid, (int) RunAsGid);
402406f25ae9SGregory Neil Shapiro 		if (tTd(47, 10))
402540266059SGregory Neil Shapiro 			sm_dprintf("drop_privileges: rval = %d\n", rval);
4026c2aa98e2SPeter Wemm 	}
4027c2aa98e2SPeter Wemm 	return rval;
4028c2aa98e2SPeter Wemm }
402940266059SGregory Neil Shapiro /*
4030c2aa98e2SPeter Wemm **  FILL_FD -- make sure a file descriptor has been properly allocated
4031c2aa98e2SPeter Wemm **
4032c2aa98e2SPeter Wemm **	Used to make sure that stdin/out/err are allocated on startup
4033c2aa98e2SPeter Wemm **
4034c2aa98e2SPeter Wemm **	Parameters:
4035c2aa98e2SPeter Wemm **		fd -- the file descriptor to be filled.
4036c2aa98e2SPeter Wemm **		where -- a string used for logging.  If NULL, this is
4037c2aa98e2SPeter Wemm **			being called on startup, and logging should
4038c2aa98e2SPeter Wemm **			not be done.
4039c2aa98e2SPeter Wemm **
4040c2aa98e2SPeter Wemm **	Returns:
4041c2aa98e2SPeter Wemm **		none
404240266059SGregory Neil Shapiro **
404340266059SGregory Neil Shapiro **	Side Effects:
404440266059SGregory Neil Shapiro **		possibly changes MissingFds
4045c2aa98e2SPeter Wemm */
4046c2aa98e2SPeter Wemm 
4047c2aa98e2SPeter Wemm void
fill_fd(fd,where)4048c2aa98e2SPeter Wemm fill_fd(fd, where)
4049c2aa98e2SPeter Wemm 	int fd;
4050c2aa98e2SPeter Wemm 	char *where;
4051c2aa98e2SPeter Wemm {
4052c2aa98e2SPeter Wemm 	int i;
4053c2aa98e2SPeter Wemm 	struct stat stbuf;
4054c2aa98e2SPeter Wemm 
4055c2aa98e2SPeter Wemm 	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
4056c2aa98e2SPeter Wemm 		return;
4057c2aa98e2SPeter Wemm 
4058c2aa98e2SPeter Wemm 	if (where != NULL)
4059c2aa98e2SPeter Wemm 		syserr("fill_fd: %s: fd %d not open", where, fd);
4060c2aa98e2SPeter Wemm 	else
4061c2aa98e2SPeter Wemm 		MissingFds |= 1 << fd;
406240266059SGregory Neil Shapiro 	i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666);
4063c2aa98e2SPeter Wemm 	if (i < 0)
4064c2aa98e2SPeter Wemm 	{
406540266059SGregory Neil Shapiro 		syserr("!fill_fd: %s: cannot open %s",
406640266059SGregory Neil Shapiro 		       where == NULL ? "startup" : where, SM_PATH_DEVNULL);
4067c2aa98e2SPeter Wemm 	}
4068c2aa98e2SPeter Wemm 	if (fd != i)
4069c2aa98e2SPeter Wemm 	{
4070c2aa98e2SPeter Wemm 		(void) dup2(i, fd);
4071c2aa98e2SPeter Wemm 		(void) close(i);
4072c2aa98e2SPeter Wemm 	}
4073c2aa98e2SPeter Wemm }
407440266059SGregory Neil Shapiro /*
407540266059SGregory Neil Shapiro **  SM_PRINTOPTIONS -- print options
407640266059SGregory Neil Shapiro **
407740266059SGregory Neil Shapiro **	Parameters:
407840266059SGregory Neil Shapiro **		options -- array of options.
407940266059SGregory Neil Shapiro **
408040266059SGregory Neil Shapiro **	Returns:
408140266059SGregory Neil Shapiro **		none.
408240266059SGregory Neil Shapiro */
408340266059SGregory Neil Shapiro 
408440266059SGregory Neil Shapiro static void
sm_printoptions(options)408540266059SGregory Neil Shapiro sm_printoptions(options)
408640266059SGregory Neil Shapiro 	char **options;
408740266059SGregory Neil Shapiro {
408840266059SGregory Neil Shapiro 	int ll;
408940266059SGregory Neil Shapiro 	char **av;
409040266059SGregory Neil Shapiro 
409140266059SGregory Neil Shapiro 	av = options;
409240266059SGregory Neil Shapiro 	ll = 7;
409340266059SGregory Neil Shapiro 	while (*av != NULL)
409440266059SGregory Neil Shapiro 	{
409540266059SGregory Neil Shapiro 		if (ll + strlen(*av) > 63)
409640266059SGregory Neil Shapiro 		{
409740266059SGregory Neil Shapiro 			sm_dprintf("\n");
409840266059SGregory Neil Shapiro 			ll = 0;
409940266059SGregory Neil Shapiro 		}
410040266059SGregory Neil Shapiro 		if (ll == 0)
410140266059SGregory Neil Shapiro 			sm_dprintf("\t\t");
410240266059SGregory Neil Shapiro 		else
410340266059SGregory Neil Shapiro 			sm_dprintf(" ");
410440266059SGregory Neil Shapiro 		sm_dprintf("%s", *av);
410540266059SGregory Neil Shapiro 		ll += strlen(*av++) + 1;
410640266059SGregory Neil Shapiro 	}
410740266059SGregory Neil Shapiro 	sm_dprintf("\n");
410840266059SGregory Neil Shapiro }
4109d0cef73dSGregory Neil Shapiro 
4110d0cef73dSGregory Neil Shapiro /*
4111d0cef73dSGregory Neil Shapiro **  TO8BIT -- convert \octal sequences in a test mode input line
4112d0cef73dSGregory Neil Shapiro **
4113d0cef73dSGregory Neil Shapiro **	Parameters:
4114d0cef73dSGregory Neil Shapiro **		str -- the input line.
41152fb4f839SGregory Neil Shapiro **		mq -- "quote" meta chars?
4116d0cef73dSGregory Neil Shapiro **
4117d0cef73dSGregory Neil Shapiro **	Returns:
41182fb4f839SGregory Neil Shapiro **		meta quoting performed?
4119d0cef73dSGregory Neil Shapiro **
4120d0cef73dSGregory Neil Shapiro **	Side Effects:
41212fb4f839SGregory Neil Shapiro **		replaces \0octal in str with octal value,
41222fb4f839SGregory Neil Shapiro **		optionally (meta) quotes meta chars.
4123d0cef73dSGregory Neil Shapiro */
4124d0cef73dSGregory Neil Shapiro 
41252fb4f839SGregory Neil Shapiro static bool to8bit __P((char *, bool));
4126d0cef73dSGregory Neil Shapiro 
4127d0cef73dSGregory Neil Shapiro static bool
to8bit(str,mq)41282fb4f839SGregory Neil Shapiro to8bit(str, mq)
4129d0cef73dSGregory Neil Shapiro 	char *str;
41302fb4f839SGregory Neil Shapiro 	bool mq;
4131d0cef73dSGregory Neil Shapiro {
4132d0cef73dSGregory Neil Shapiro 	int c, len;
4133d0cef73dSGregory Neil Shapiro 	char *out, *in;
4134d0cef73dSGregory Neil Shapiro 
4135d0cef73dSGregory Neil Shapiro 	if (str == NULL)
4136d0cef73dSGregory Neil Shapiro 		return false;
4137d0cef73dSGregory Neil Shapiro 	in = out = str;
4138d0cef73dSGregory Neil Shapiro 	len = 0;
4139d0cef73dSGregory Neil Shapiro 	while ((c = (*str++ & 0377)) != '\0')
4140d0cef73dSGregory Neil Shapiro 	{
4141d0cef73dSGregory Neil Shapiro 		int oct, nxtc;
4142d0cef73dSGregory Neil Shapiro 
4143d0cef73dSGregory Neil Shapiro 		++len;
4144d0cef73dSGregory Neil Shapiro 		if (c == '\\' &&
4145d0cef73dSGregory Neil Shapiro 		    (nxtc = (*str & 0377)) == '0')
4146d0cef73dSGregory Neil Shapiro 		{
4147d0cef73dSGregory Neil Shapiro 			oct = 0;
4148d0cef73dSGregory Neil Shapiro 			while ((nxtc = (*str & 0377)) != '\0' &&
4149d0cef73dSGregory Neil Shapiro 				isascii(nxtc) && isdigit(nxtc))
4150d0cef73dSGregory Neil Shapiro 			{
4151d0cef73dSGregory Neil Shapiro 				oct <<= 3;
4152d0cef73dSGregory Neil Shapiro 				oct += nxtc - '0';
4153d0cef73dSGregory Neil Shapiro 				++str;
4154d0cef73dSGregory Neil Shapiro 				++len;
4155d0cef73dSGregory Neil Shapiro 			}
41562fb4f839SGregory Neil Shapiro 			mq = true;
4157d0cef73dSGregory Neil Shapiro 			c = oct;
4158d0cef73dSGregory Neil Shapiro 		}
4159d0cef73dSGregory Neil Shapiro 		*out++ = c;
4160d0cef73dSGregory Neil Shapiro 	}
4161d0cef73dSGregory Neil Shapiro 	*out++ = c;
41622fb4f839SGregory Neil Shapiro 	if (mq)
4163d0cef73dSGregory Neil Shapiro 	{
4164d0cef73dSGregory Neil Shapiro 		char *q;
4165d0cef73dSGregory Neil Shapiro 
41662fb4f839SGregory Neil Shapiro 		q = quote_internal_chars(in, in, &len, NULL);
4167d0cef73dSGregory Neil Shapiro 		if (q != in)
4168d0cef73dSGregory Neil Shapiro 			sm_strlcpy(in, q, len);
4169d0cef73dSGregory Neil Shapiro 	}
41702fb4f839SGregory Neil Shapiro 	return mq;
4171d0cef73dSGregory Neil Shapiro }
4172d0cef73dSGregory Neil Shapiro 
417340266059SGregory Neil Shapiro /*
4174c2aa98e2SPeter Wemm **  TESTMODELINE -- process a test mode input line
4175c2aa98e2SPeter Wemm **
4176c2aa98e2SPeter Wemm **	Parameters:
4177c2aa98e2SPeter Wemm **		line -- the input line.
4178c2aa98e2SPeter Wemm **		e -- the current environment.
4179c2aa98e2SPeter Wemm **	Syntax:
4180c2aa98e2SPeter Wemm **		#  a comment
4181c2aa98e2SPeter Wemm **		.X process X as a configuration line
4182c2aa98e2SPeter Wemm **		=X dump a configuration item (such as mailers)
4183c2aa98e2SPeter Wemm **		$X dump a macro or class
4184c2aa98e2SPeter Wemm **		/X try an activity
4185c2aa98e2SPeter Wemm **		X  normal process through rule set X
4186c2aa98e2SPeter Wemm */
4187c2aa98e2SPeter Wemm 
418806f25ae9SGregory Neil Shapiro static void
testmodeline(line,e)4189c2aa98e2SPeter Wemm testmodeline(line, e)
4190c2aa98e2SPeter Wemm 	char *line;
4191c2aa98e2SPeter Wemm 	ENVELOPE *e;
4192c2aa98e2SPeter Wemm {
4193c2aa98e2SPeter Wemm 	register char *p;
4194c2aa98e2SPeter Wemm 	char *q;
4195c2aa98e2SPeter Wemm 	auto char *delimptr;
4196c2aa98e2SPeter Wemm 	int mid;
4197c2aa98e2SPeter Wemm 	int i, rs;
4198c2aa98e2SPeter Wemm 	STAB *map;
4199c2aa98e2SPeter Wemm 	char **s;
4200c2aa98e2SPeter Wemm 	struct rewrite *rw;
4201c2aa98e2SPeter Wemm 	ADDRESS a;
4202d0cef73dSGregory Neil Shapiro 	char *lbp;
4203d0cef73dSGregory Neil Shapiro 	auto int lbs;
4204c2aa98e2SPeter Wemm 	static int tryflags = RF_COPYNONE;
4205c2aa98e2SPeter Wemm 	char exbuf[MAXLINE];
4206d0cef73dSGregory Neil Shapiro 	char lbuf[MAXLINE];
420740266059SGregory Neil Shapiro 	extern unsigned char TokTypeNoC[];
4208d0cef73dSGregory Neil Shapiro 	bool eightbit;
42092fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
42102fb4f839SGregory Neil Shapiro 	int len = sizeof(exbuf);
42112fb4f839SGregory Neil Shapiro #endif
4212d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
4213d39bd2c1SGregory Neil Shapiro 	extern void t_hostsig __P((ADDRESS *, char *, MAILER *));
4214d39bd2c1SGregory Neil Shapiro 	extern void t_parsehostsig __P((char *, MAILER *));
4215d39bd2c1SGregory Neil Shapiro #endif
421642e5d165SGregory Neil Shapiro 
421742e5d165SGregory Neil Shapiro 	/* skip leading spaces */
421842e5d165SGregory Neil Shapiro 	while (*line == ' ')
421942e5d165SGregory Neil Shapiro 		line++;
422042e5d165SGregory Neil Shapiro 
4221d0cef73dSGregory Neil Shapiro 	lbp = NULL;
4222d0cef73dSGregory Neil Shapiro 	eightbit = false;
4223d39bd2c1SGregory Neil Shapiro 	maps_reset_chged("testmodeline");
4224c2aa98e2SPeter Wemm 	switch (line[0])
4225c2aa98e2SPeter Wemm 	{
4226c2aa98e2SPeter Wemm 	  case '#':
422706f25ae9SGregory Neil Shapiro 	  case '\0':
4228c2aa98e2SPeter Wemm 		return;
4229c2aa98e2SPeter Wemm 
4230c2aa98e2SPeter Wemm 	  case '?':
423106f25ae9SGregory Neil Shapiro 		help("-bt", e);
4232c2aa98e2SPeter Wemm 		return;
4233c2aa98e2SPeter Wemm 
4234c2aa98e2SPeter Wemm 	  case '.':		/* config-style settings */
4235c2aa98e2SPeter Wemm 		switch (line[1])
4236c2aa98e2SPeter Wemm 		{
4237c2aa98e2SPeter Wemm 		  case 'D':
423840266059SGregory Neil Shapiro 			mid = macid_parse(&line[2], &delimptr);
4239193538b7SGregory Neil Shapiro 			if (mid == 0)
4240c2aa98e2SPeter Wemm 				return;
4241d0cef73dSGregory Neil Shapiro 			lbs = sizeof(lbuf);
4242d0cef73dSGregory Neil Shapiro 			lbp = translate_dollars(delimptr, lbuf, &lbs);
4243d0cef73dSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, mid, lbp);
4244d0cef73dSGregory Neil Shapiro 			if (lbp != lbuf)
4245d0cef73dSGregory Neil Shapiro 				SM_FREE(lbp);
4246c2aa98e2SPeter Wemm 			break;
4247c2aa98e2SPeter Wemm 
4248c2aa98e2SPeter Wemm 		  case 'C':
4249c2aa98e2SPeter Wemm 			if (line[2] == '\0')	/* not to call syserr() */
4250c2aa98e2SPeter Wemm 				return;
4251c2aa98e2SPeter Wemm 
425240266059SGregory Neil Shapiro 			mid = macid_parse(&line[2], &delimptr);
4253193538b7SGregory Neil Shapiro 			if (mid == 0)
4254c2aa98e2SPeter Wemm 				return;
4255d0cef73dSGregory Neil Shapiro 			lbs = sizeof(lbuf);
4256d0cef73dSGregory Neil Shapiro 			lbp = translate_dollars(delimptr, lbuf, &lbs);
4257d0cef73dSGregory Neil Shapiro 			expand(lbp, exbuf, sizeof(exbuf), e);
4258d0cef73dSGregory Neil Shapiro 			if (lbp != lbuf)
4259d0cef73dSGregory Neil Shapiro 				SM_FREE(lbp);
4260c2aa98e2SPeter Wemm 			p = exbuf;
4261c2aa98e2SPeter Wemm 			while (*p != '\0')
4262c2aa98e2SPeter Wemm 			{
4263c2aa98e2SPeter Wemm 				register char *wd;
4264c2aa98e2SPeter Wemm 				char delim;
4265c2aa98e2SPeter Wemm 
42665b0945b5SGregory Neil Shapiro 				while (*p != '\0' && SM_ISSPACE(*p))
4267c2aa98e2SPeter Wemm 					p++;
4268c2aa98e2SPeter Wemm 				wd = p;
42695b0945b5SGregory Neil Shapiro 				while (*p != '\0' && !(SM_ISSPACE(*p)))
4270c2aa98e2SPeter Wemm 					p++;
4271c2aa98e2SPeter Wemm 				delim = *p;
4272c2aa98e2SPeter Wemm 				*p = '\0';
4273c2aa98e2SPeter Wemm 				if (wd[0] != '\0')
4274c2aa98e2SPeter Wemm 					setclass(mid, wd);
4275c2aa98e2SPeter Wemm 				*p = delim;
4276c2aa98e2SPeter Wemm 			}
4277c2aa98e2SPeter Wemm 			break;
4278c2aa98e2SPeter Wemm 
4279c2aa98e2SPeter Wemm 		  case '\0':
428040266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
428140266059SGregory Neil Shapiro 					     "Usage: .[DC]macro value(s)\n");
4282c2aa98e2SPeter Wemm 			break;
4283c2aa98e2SPeter Wemm 
4284c2aa98e2SPeter Wemm 		  default:
428540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
428640266059SGregory Neil Shapiro 					     "Unknown \".\" command %s\n", line);
4287c2aa98e2SPeter Wemm 			break;
4288c2aa98e2SPeter Wemm 		}
4289c2aa98e2SPeter Wemm 		return;
4290c2aa98e2SPeter Wemm 
4291c2aa98e2SPeter Wemm 	  case '=':		/* config-style settings */
4292c2aa98e2SPeter Wemm 		switch (line[1])
4293c2aa98e2SPeter Wemm 		{
4294c2aa98e2SPeter Wemm 		  case 'S':		/* dump rule set */
4295c2aa98e2SPeter Wemm 			rs = strtorwset(&line[2], NULL, ST_FIND);
4296c2aa98e2SPeter Wemm 			if (rs < 0)
4297c2aa98e2SPeter Wemm 			{
429840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
429940266059SGregory Neil Shapiro 						     "Undefined ruleset %s\n", &line[2]);
4300c2aa98e2SPeter Wemm 				return;
4301c2aa98e2SPeter Wemm 			}
4302c2aa98e2SPeter Wemm 			rw = RewriteRules[rs];
4303c2aa98e2SPeter Wemm 			if (rw == NULL)
4304c2aa98e2SPeter Wemm 				return;
4305c2aa98e2SPeter Wemm 			do
4306c2aa98e2SPeter Wemm 			{
430740266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
430840266059SGregory Neil Shapiro 						  'R');
4309c2aa98e2SPeter Wemm 				s = rw->r_lhs;
4310c2aa98e2SPeter Wemm 				while (*s != NULL)
4311c2aa98e2SPeter Wemm 				{
4312e92d3f3fSGregory Neil Shapiro 					xputs(smioout, *s++);
431340266059SGregory Neil Shapiro 					(void) sm_io_putc(smioout,
431440266059SGregory Neil Shapiro 							  SM_TIME_DEFAULT, ' ');
4315c2aa98e2SPeter Wemm 				}
431640266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
431740266059SGregory Neil Shapiro 						  '\t');
431840266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
431940266059SGregory Neil Shapiro 						  '\t');
4320c2aa98e2SPeter Wemm 				s = rw->r_rhs;
4321c2aa98e2SPeter Wemm 				while (*s != NULL)
4322c2aa98e2SPeter Wemm 				{
4323e92d3f3fSGregory Neil Shapiro 					xputs(smioout, *s++);
432440266059SGregory Neil Shapiro 					(void) sm_io_putc(smioout,
432540266059SGregory Neil Shapiro 							  SM_TIME_DEFAULT, ' ');
4326c2aa98e2SPeter Wemm 				}
432740266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
432840266059SGregory Neil Shapiro 						  '\n');
4329c2aa98e2SPeter Wemm 			} while ((rw = rw->r_next) != NULL);
4330c2aa98e2SPeter Wemm 			break;
4331c2aa98e2SPeter Wemm 
4332c2aa98e2SPeter Wemm 		  case 'M':
4333c2aa98e2SPeter Wemm 			for (i = 0; i < MAXMAILERS; i++)
4334c2aa98e2SPeter Wemm 			{
4335c2aa98e2SPeter Wemm 				if (Mailer[i] != NULL)
4336e92d3f3fSGregory Neil Shapiro 					printmailer(smioout, Mailer[i]);
4337c2aa98e2SPeter Wemm 			}
4338c2aa98e2SPeter Wemm 			break;
4339c2aa98e2SPeter Wemm 
4340c2aa98e2SPeter Wemm 		  case '\0':
434140266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
434240266059SGregory Neil Shapiro 					     "Usage: =Sruleset or =M\n");
4343c2aa98e2SPeter Wemm 			break;
4344c2aa98e2SPeter Wemm 
4345c2aa98e2SPeter Wemm 		  default:
434640266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
434740266059SGregory Neil Shapiro 					     "Unknown \"=\" command %s\n", line);
4348c2aa98e2SPeter Wemm 			break;
4349c2aa98e2SPeter Wemm 		}
4350c2aa98e2SPeter Wemm 		return;
4351c2aa98e2SPeter Wemm 
4352c2aa98e2SPeter Wemm 	  case '-':		/* set command-line-like opts */
4353c2aa98e2SPeter Wemm 		switch (line[1])
4354c2aa98e2SPeter Wemm 		{
4355c2aa98e2SPeter Wemm 		  case 'd':
4356c2aa98e2SPeter Wemm 			tTflag(&line[2]);
4357c2aa98e2SPeter Wemm 			break;
4358c2aa98e2SPeter Wemm 
4359c2aa98e2SPeter Wemm 		  case '\0':
436040266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
436140266059SGregory Neil Shapiro 					     "Usage: -d{debug arguments}\n");
4362c2aa98e2SPeter Wemm 			break;
4363c2aa98e2SPeter Wemm 
4364c2aa98e2SPeter Wemm 		  default:
436540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
436640266059SGregory Neil Shapiro 					     "Unknown \"-\" command %s\n", line);
4367c2aa98e2SPeter Wemm 			break;
4368c2aa98e2SPeter Wemm 		}
4369c2aa98e2SPeter Wemm 		return;
4370c2aa98e2SPeter Wemm 
4371c2aa98e2SPeter Wemm 	  case '$':
4372c2aa98e2SPeter Wemm 		if (line[1] == '=')
4373c2aa98e2SPeter Wemm 		{
4374d39bd2c1SGregory Neil Shapiro #if _FFR_DYN_CLASS
4375d39bd2c1SGregory Neil Shapiro 			MAP *dynmap;
4376d39bd2c1SGregory Neil Shapiro 			STAB *st;
4377d39bd2c1SGregory Neil Shapiro #endif
4378d39bd2c1SGregory Neil Shapiro 
437940266059SGregory Neil Shapiro 			mid = macid(&line[2]);
4380d39bd2c1SGregory Neil Shapiro #if _FFR_DYN_CLASS
4381d39bd2c1SGregory Neil Shapiro 			if (mid != 0 &&
4382d39bd2c1SGregory Neil Shapiro 			    (st = stab(macname(mid), ST_DYNMAP, ST_FIND)) != NULL)
4383d39bd2c1SGregory Neil Shapiro 			{
4384d39bd2c1SGregory Neil Shapiro 				dynmap = &st->s_dynclass;
4385d39bd2c1SGregory Neil Shapiro 				q = dynmap->map_class->map_cname;
4386d39bd2c1SGregory Neil Shapiro 				if (SM_IS_EMPTY(q))
4387d39bd2c1SGregory Neil Shapiro 					q = "implicit";
4388d39bd2c1SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4389d39bd2c1SGregory Neil Shapiro 					"$=%s not possible for a dynamic class, use\n",
4390d39bd2c1SGregory Neil Shapiro 					line + 2);
4391d39bd2c1SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4392d39bd2c1SGregory Neil Shapiro 					"makemap -u %s %s",
4393d39bd2c1SGregory Neil Shapiro 					q, dynmap->map_file);
4394d39bd2c1SGregory Neil Shapiro 				if (!SM_IS_EMPTY(dynmap->map_tag))
4395d39bd2c1SGregory Neil Shapiro 				{
4396d39bd2c1SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4397d39bd2c1SGregory Neil Shapiro 					" | grep -i '^%s:'",
4398d39bd2c1SGregory Neil Shapiro 					dynmap->map_tag);
4399d39bd2c1SGregory Neil Shapiro 				}
4400d39bd2c1SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
4401d39bd2c1SGregory Neil Shapiro 				return;
4402d39bd2c1SGregory Neil Shapiro 			}
4403d39bd2c1SGregory Neil Shapiro #endif
4404193538b7SGregory Neil Shapiro 			if (mid != 0)
4405c2aa98e2SPeter Wemm 				stabapply(dump_class, mid);
4406c2aa98e2SPeter Wemm 			return;
4407c2aa98e2SPeter Wemm 		}
440840266059SGregory Neil Shapiro 		mid = macid(&line[1]);
4409193538b7SGregory Neil Shapiro 		if (mid == 0)
4410c2aa98e2SPeter Wemm 			return;
4411c2aa98e2SPeter Wemm 		p = macvalue(mid, e);
4412c2aa98e2SPeter Wemm 		if (p == NULL)
441340266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
441440266059SGregory Neil Shapiro 					     "Undefined\n");
4415c2aa98e2SPeter Wemm 		else
4416c2aa98e2SPeter Wemm 		{
4417e92d3f3fSGregory Neil Shapiro 			xputs(smioout, p);
441840266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
441940266059SGregory Neil Shapiro 					     "\n");
4420c2aa98e2SPeter Wemm 		}
4421c2aa98e2SPeter Wemm 		return;
4422c2aa98e2SPeter Wemm 
4423c2aa98e2SPeter Wemm 	  case '/':		/* miscellaneous commands */
4424c2aa98e2SPeter Wemm 		p = &line[strlen(line)];
44255b0945b5SGregory Neil Shapiro 		while (--p >= line && SM_ISSPACE(*p))
4426c2aa98e2SPeter Wemm 			*p = '\0';
4427c2aa98e2SPeter Wemm 		p = strpbrk(line, " \t");
4428c2aa98e2SPeter Wemm 		if (p != NULL)
4429c2aa98e2SPeter Wemm 		{
44305b0945b5SGregory Neil Shapiro 			while (SM_ISSPACE(*p))
4431c2aa98e2SPeter Wemm 				*p++ = '\0';
4432c2aa98e2SPeter Wemm 		}
4433c2aa98e2SPeter Wemm 		else
4434c2aa98e2SPeter Wemm 			p = "";
4435c2aa98e2SPeter Wemm 		if (line[1] == '\0')
4436c2aa98e2SPeter Wemm 		{
443740266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
443840266059SGregory Neil Shapiro 					     "Usage: /[canon|map|mx|parse|try|tryflags]\n");
4439c2aa98e2SPeter Wemm 			return;
4440c2aa98e2SPeter Wemm 		}
44412fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(&line[1], "quit"))
444206f25ae9SGregory Neil Shapiro 		{
444306f25ae9SGregory Neil Shapiro 			CurEnv->e_id = NULL;
444440266059SGregory Neil Shapiro 			finis(true, true, ExitStat);
444540266059SGregory Neil Shapiro 			/* NOTREACHED */
444606f25ae9SGregory Neil Shapiro 		}
44472fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(&line[1], "mx"))
4448c2aa98e2SPeter Wemm 		{
4449c2aa98e2SPeter Wemm #if NAMED_BIND
4450c2aa98e2SPeter Wemm 			/* look up MX records */
4451c2aa98e2SPeter Wemm 			int nmx;
4452c2aa98e2SPeter Wemm 			auto int rcode;
4453c2aa98e2SPeter Wemm 			char *mxhosts[MAXMXHOSTS + 1];
4454c2aa98e2SPeter Wemm 
4455c2aa98e2SPeter Wemm 			if (*p == '\0')
4456c2aa98e2SPeter Wemm 			{
445740266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
445840266059SGregory Neil Shapiro 						     "Usage: /mx address\n");
4459c2aa98e2SPeter Wemm 				return;
4460c2aa98e2SPeter Wemm 			}
44615b0945b5SGregory Neil Shapiro 			nmx = getmxrr(p, mxhosts, NULL, TRYFALLBACK, &rcode,
4462d39bd2c1SGregory Neil Shapiro 				      NULL, -1, NULL);
44635b0945b5SGregory Neil Shapiro 			if (nmx == NULLMX)
44645b0945b5SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
44655b0945b5SGregory Neil Shapiro 						     "getmxrr(%s) returns null MX (See RFC7505)\n",
44665b0945b5SGregory Neil Shapiro 						     p);
44675b0945b5SGregory Neil Shapiro 			else
446840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
446940266059SGregory Neil Shapiro 						     "getmxrr(%s) returns %d value(s):\n",
447040266059SGregory Neil Shapiro 						     p, nmx);
4471c2aa98e2SPeter Wemm 			for (i = 0; i < nmx; i++)
447240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
447340266059SGregory Neil Shapiro 						     "\t%s\n", mxhosts[i]);
447406f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */
447540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
447640266059SGregory Neil Shapiro 					     "No MX code compiled in\n");
447706f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
4478c2aa98e2SPeter Wemm 		}
44792fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "canon"))
4480c2aa98e2SPeter Wemm 		{
4481c2aa98e2SPeter Wemm 			char host[MAXHOSTNAMELEN];
4482c2aa98e2SPeter Wemm 
4483c2aa98e2SPeter Wemm 			if (*p == '\0')
4484c2aa98e2SPeter Wemm 			{
448540266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
448640266059SGregory Neil Shapiro 						     "Usage: /canon address\n");
4487c2aa98e2SPeter Wemm 				return;
4488c2aa98e2SPeter Wemm 			}
4489d0cef73dSGregory Neil Shapiro 			else if (sm_strlcpy(host, p, sizeof(host)) >= sizeof(host))
4490c2aa98e2SPeter Wemm 			{
449140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
449240266059SGregory Neil Shapiro 						     "Name too long\n");
4493c2aa98e2SPeter Wemm 				return;
4494c2aa98e2SPeter Wemm 			}
4495d0cef73dSGregory Neil Shapiro 			(void) getcanonname(host, sizeof(host), !HasWildcardMX,
449640266059SGregory Neil Shapiro 					    NULL);
449740266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
449840266059SGregory Neil Shapiro 					     "getcanonname(%s) returns %s\n",
449940266059SGregory Neil Shapiro 					     p, host);
4500c2aa98e2SPeter Wemm 		}
45012fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "map"))
4502c2aa98e2SPeter Wemm 		{
4503c2aa98e2SPeter Wemm 			auto int rcode = EX_OK;
4504c2aa98e2SPeter Wemm 			char *av[2];
4505c2aa98e2SPeter Wemm 
4506c2aa98e2SPeter Wemm 			if (*p == '\0')
4507c2aa98e2SPeter Wemm 			{
450840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
450940266059SGregory Neil Shapiro 						     "Usage: /map mapname key\n");
4510c2aa98e2SPeter Wemm 				return;
4511c2aa98e2SPeter Wemm 			}
45125b0945b5SGregory Neil Shapiro 			for (q = p; *q != '\0' && !(SM_ISSPACE(*q)); q++)
4513c2aa98e2SPeter Wemm 				continue;
4514c2aa98e2SPeter Wemm 			if (*q == '\0')
4515c2aa98e2SPeter Wemm 			{
451640266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
451740266059SGregory Neil Shapiro 						     "No key specified\n");
4518c2aa98e2SPeter Wemm 				return;
4519c2aa98e2SPeter Wemm 			}
4520c2aa98e2SPeter Wemm 			*q++ = '\0';
4521c2aa98e2SPeter Wemm 			map = stab(p, ST_MAP, ST_FIND);
4522c2aa98e2SPeter Wemm 			if (map == NULL)
4523c2aa98e2SPeter Wemm 			{
452440266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
452540266059SGregory Neil Shapiro 						     "Map named \"%s\" not found\n", p);
4526c2aa98e2SPeter Wemm 				return;
4527c2aa98e2SPeter Wemm 			}
452806f25ae9SGregory Neil Shapiro 			if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
452906f25ae9SGregory Neil Shapiro 			    !openmap(&(map->s_map)))
4530c2aa98e2SPeter Wemm 			{
453140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
453240266059SGregory Neil Shapiro 						     "Map named \"%s\" not open\n", p);
4533c2aa98e2SPeter Wemm 				return;
4534c2aa98e2SPeter Wemm 			}
453540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
453640266059SGregory Neil Shapiro 					     "map_lookup: %s (%s) ", p, q);
4537c2aa98e2SPeter Wemm 			av[0] = q;
4538c2aa98e2SPeter Wemm 			av[1] = NULL;
4539c2aa98e2SPeter Wemm 			p = (*map->s_map.map_class->map_lookup)
4540c2aa98e2SPeter Wemm 					(&map->s_map, q, av, &rcode);
4541c2aa98e2SPeter Wemm 			if (p == NULL)
454240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
454340266059SGregory Neil Shapiro 						     "no match (%d)\n",
454440266059SGregory Neil Shapiro 						     rcode);
4545c2aa98e2SPeter Wemm 			else
454640266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
454740266059SGregory Neil Shapiro 						     "returns %s (%d)\n", p,
454840266059SGregory Neil Shapiro 						     rcode);
4549c2aa98e2SPeter Wemm 		}
45502fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "sender"))
45512fb4f839SGregory Neil Shapiro 		{
45522fb4f839SGregory Neil Shapiro 			setsender(p, CurEnv, NULL, '\0', false);
45532fb4f839SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
45542fb4f839SGregory Neil Shapiro 					     "addr=%s\n",
45552fb4f839SGregory Neil Shapiro 					     e->e_from.q_user);
45562fb4f839SGregory Neil Shapiro 		}
45572fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "expand"))
45582fb4f839SGregory Neil Shapiro 		{
45592fb4f839SGregory Neil Shapiro 			if (*p == '\0')
45602fb4f839SGregory Neil Shapiro 			{
45612fb4f839SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
45622fb4f839SGregory Neil Shapiro 						     "Usage: /expand string\n");
45632fb4f839SGregory Neil Shapiro 				return;
45642fb4f839SGregory Neil Shapiro 			}
45652fb4f839SGregory Neil Shapiro 			expand(p, exbuf, sizeof(exbuf), CurEnv);
45662fb4f839SGregory Neil Shapiro 			xputs(smioout, exbuf);
45672fb4f839SGregory Neil Shapiro 		}
45682fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "try"))
4569c2aa98e2SPeter Wemm 		{
4570c2aa98e2SPeter Wemm 			MAILER *m;
457106f25ae9SGregory Neil Shapiro 			STAB *st;
4572c2aa98e2SPeter Wemm 			auto int rcode = EX_OK;
4573c2aa98e2SPeter Wemm 
4574c2aa98e2SPeter Wemm 			q = strpbrk(p, " \t");
4575c2aa98e2SPeter Wemm 			if (q != NULL)
4576c2aa98e2SPeter Wemm 			{
45775b0945b5SGregory Neil Shapiro 				while (SM_ISSPACE(*q))
4578c2aa98e2SPeter Wemm 					*q++ = '\0';
4579c2aa98e2SPeter Wemm 			}
4580c2aa98e2SPeter Wemm 			if (q == NULL || *q == '\0')
4581c2aa98e2SPeter Wemm 			{
458240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
458340266059SGregory Neil Shapiro 						     "Usage: /try mailer address\n");
4584c2aa98e2SPeter Wemm 				return;
4585c2aa98e2SPeter Wemm 			}
458606f25ae9SGregory Neil Shapiro 			st = stab(p, ST_MAILER, ST_FIND);
458706f25ae9SGregory Neil Shapiro 			if (st == NULL)
4588c2aa98e2SPeter Wemm 			{
458940266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
459040266059SGregory Neil Shapiro 						     "Unknown mailer %s\n", p);
4591c2aa98e2SPeter Wemm 				return;
4592c2aa98e2SPeter Wemm 			}
459306f25ae9SGregory Neil Shapiro 			m = st->s_mailer;
459440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
459540266059SGregory Neil Shapiro 					     "Trying %s %s address %s for mailer %s\n",
459640266059SGregory Neil Shapiro 				     bitset(RF_HEADERADDR, tryflags) ? "header"
459740266059SGregory Neil Shapiro 							: "envelope",
459840266059SGregory Neil Shapiro 				     bitset(RF_SENDERADDR, tryflags) ? "sender"
459940266059SGregory Neil Shapiro 							: "recipient", q, p);
46002fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
46012fb4f839SGregory Neil Shapiro 			q = quote_internal_chars(q, exbuf, &len, NULL);
46022fb4f839SGregory Neil Shapiro #endif
4603c2aa98e2SPeter Wemm 			p = remotename(q, m, tryflags, &rcode, CurEnv);
46042fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
46052fb4f839SGregory Neil Shapiro 			dequote_internal_chars(p, exbuf, sizeof(exbuf));
46062fb4f839SGregory Neil Shapiro 			p = exbuf;
46072fb4f839SGregory Neil Shapiro #endif
460840266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
460940266059SGregory Neil Shapiro 					     "Rcode = %d, addr = %s\n",
4610c2aa98e2SPeter Wemm 					     rcode, p == NULL ? "<NULL>" : p);
4611c2aa98e2SPeter Wemm 			e->e_to = NULL;
4612c2aa98e2SPeter Wemm 		}
46132fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "tryflags"))
4614c2aa98e2SPeter Wemm 		{
4615c2aa98e2SPeter Wemm 			if (*p == '\0')
4616c2aa98e2SPeter Wemm 			{
461740266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
461840266059SGregory Neil Shapiro 						     "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
4619c2aa98e2SPeter Wemm 				return;
4620c2aa98e2SPeter Wemm 			}
4621c2aa98e2SPeter Wemm 			for (; *p != '\0'; p++)
4622c2aa98e2SPeter Wemm 			{
4623c2aa98e2SPeter Wemm 				switch (*p)
4624c2aa98e2SPeter Wemm 				{
4625c2aa98e2SPeter Wemm 				  case 'H':
4626c2aa98e2SPeter Wemm 				  case 'h':
4627c2aa98e2SPeter Wemm 					tryflags |= RF_HEADERADDR;
4628c2aa98e2SPeter Wemm 					break;
4629c2aa98e2SPeter Wemm 
4630c2aa98e2SPeter Wemm 				  case 'E':
4631c2aa98e2SPeter Wemm 				  case 'e':
4632c2aa98e2SPeter Wemm 					tryflags &= ~RF_HEADERADDR;
4633c2aa98e2SPeter Wemm 					break;
4634c2aa98e2SPeter Wemm 
4635c2aa98e2SPeter Wemm 				  case 'S':
4636c2aa98e2SPeter Wemm 				  case 's':
4637c2aa98e2SPeter Wemm 					tryflags |= RF_SENDERADDR;
4638c2aa98e2SPeter Wemm 					break;
4639c2aa98e2SPeter Wemm 
4640c2aa98e2SPeter Wemm 				  case 'R':
4641c2aa98e2SPeter Wemm 				  case 'r':
4642c2aa98e2SPeter Wemm 					tryflags &= ~RF_SENDERADDR;
4643c2aa98e2SPeter Wemm 					break;
4644c2aa98e2SPeter Wemm 				}
4645c2aa98e2SPeter Wemm 			}
464606f25ae9SGregory Neil Shapiro 			exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
464706f25ae9SGregory Neil Shapiro 			exbuf[1] = ' ';
464806f25ae9SGregory Neil Shapiro 			exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
464906f25ae9SGregory Neil Shapiro 			exbuf[3] = '\0';
465040266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
465140266059SGregory Neil Shapiro 				macid("{addr_type}"), exbuf);
4652c2aa98e2SPeter Wemm 		}
4653d39bd2c1SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "parse")
4654d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
4655d39bd2c1SGregory Neil Shapiro 			 || SM_STRCASEEQ(&line[1], "hostsig")
4656d39bd2c1SGregory Neil Shapiro #endif
4657d39bd2c1SGregory Neil Shapiro 			)
4658c2aa98e2SPeter Wemm 		{
4659c2aa98e2SPeter Wemm 			if (*p == '\0')
4660c2aa98e2SPeter Wemm 			{
466140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
466240266059SGregory Neil Shapiro 						     "Usage: /parse address\n");
4663c2aa98e2SPeter Wemm 				return;
4664c2aa98e2SPeter Wemm 			}
46652fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
46662fb4f839SGregory Neil Shapiro 			p = quote_internal_chars(p, exbuf, &len, NULL);
46672fb4f839SGregory Neil Shapiro #endif
4668d9986b26SGregory Neil Shapiro 			q = crackaddr(p, e);
466940266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
467040266059SGregory Neil Shapiro 					     "Cracked address = ");
4671e92d3f3fSGregory Neil Shapiro 			xputs(smioout, q);
467240266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
467340266059SGregory Neil Shapiro 					     "\nParsing %s %s address\n",
467440266059SGregory Neil Shapiro 					     bitset(RF_HEADERADDR, tryflags) ?
467540266059SGregory Neil Shapiro 							"header" : "envelope",
467640266059SGregory Neil Shapiro 					     bitset(RF_SENDERADDR, tryflags) ?
467740266059SGregory Neil Shapiro 							"sender" : "recipient");
46782fb4f839SGregory Neil Shapiro /* XXX p must be [i] */
467940266059SGregory Neil Shapiro 			if (parseaddr(p, &a, tryflags, '\0', NULL, e, true)
468040266059SGregory Neil Shapiro 			    == NULL)
468140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
468240266059SGregory Neil Shapiro 						     "Cannot parse\n");
4683c2aa98e2SPeter Wemm 			else if (a.q_host != NULL && a.q_host[0] != '\0')
4684d39bd2c1SGregory Neil Shapiro 			{
4685d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
4686d39bd2c1SGregory Neil Shapiro 				if (SM_STRCASEEQ(&line[1], "hostsig"))
4687d39bd2c1SGregory Neil Shapiro 					t_hostsig(&a, NULL, NULL);
4688d39bd2c1SGregory Neil Shapiro 				else
4689d39bd2c1SGregory Neil Shapiro #endif /* _FFR_TESTS */
4690d39bd2c1SGregory Neil Shapiro 				{
469140266059SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
469240266059SGregory Neil Shapiro 						     "mailer %s, host %s, user %s\n",
469340266059SGregory Neil Shapiro 						     a.q_mailer->m_name,
469440266059SGregory Neil Shapiro 						     a.q_host,
469540266059SGregory Neil Shapiro 						     a.q_user);
4696d39bd2c1SGregory Neil Shapiro 				}
4697d39bd2c1SGregory Neil Shapiro 			}
4698c2aa98e2SPeter Wemm 			else
469940266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
470040266059SGregory Neil Shapiro 						     "mailer %s, user %s\n",
470140266059SGregory Neil Shapiro 						     a.q_mailer->m_name,
470240266059SGregory Neil Shapiro 						     a.q_user);
4703c2aa98e2SPeter Wemm 			e->e_to = NULL;
4704c2aa98e2SPeter Wemm 		}
47052fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "header"))
4706d0cef73dSGregory Neil Shapiro 		{
4707d0cef73dSGregory Neil Shapiro 			unsigned long ul;
4708d0cef73dSGregory Neil Shapiro 
4709d0cef73dSGregory Neil Shapiro 			ul = chompheader(p, CHHDR_CHECK|CHHDR_USER, NULL, e);
4710d0cef73dSGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
47112fb4f839SGregory Neil Shapiro 					     "ul = %#0.8lx\n", ul);
4712d0cef73dSGregory Neil Shapiro 		}
47135dd76dd0SGregory Neil Shapiro #if NETINET || NETINET6
47142fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "gethostbyname"))
47155dd76dd0SGregory Neil Shapiro 		{
47165dd76dd0SGregory Neil Shapiro 			int family = AF_INET;
47175dd76dd0SGregory Neil Shapiro 
47185dd76dd0SGregory Neil Shapiro 			q = strpbrk(p, " \t");
47195dd76dd0SGregory Neil Shapiro 			if (q != NULL)
47205dd76dd0SGregory Neil Shapiro 			{
47215b0945b5SGregory Neil Shapiro 				while (SM_ISSPACE(*q))
47225dd76dd0SGregory Neil Shapiro 					*q++ = '\0';
47235dd76dd0SGregory Neil Shapiro # if NETINET6
47245dd76dd0SGregory Neil Shapiro 				if (*q != '\0' && (strcmp(q, "inet6") == 0 ||
47255dd76dd0SGregory Neil Shapiro 						   strcmp(q, "AAAA") == 0))
47265dd76dd0SGregory Neil Shapiro 					family = AF_INET6;
47275dd76dd0SGregory Neil Shapiro # endif /* NETINET6 */
47285dd76dd0SGregory Neil Shapiro 			}
47295dd76dd0SGregory Neil Shapiro 			(void) sm_gethostbyname(p, family);
47305dd76dd0SGregory Neil Shapiro 		}
47315dd76dd0SGregory Neil Shapiro #endif /* NETINET || NETINET6 */
47325b0945b5SGregory Neil Shapiro #if DANE
47332fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "dnslookup"))
47345b0945b5SGregory Neil Shapiro 		{
47355b0945b5SGregory Neil Shapiro 			DNS_REPLY_T *r;
47365b0945b5SGregory Neil Shapiro 			int rr_type, family;
47375b0945b5SGregory Neil Shapiro 			unsigned int flags;
47385b0945b5SGregory Neil Shapiro 
47395b0945b5SGregory Neil Shapiro 			rr_type = T_A;
47405b0945b5SGregory Neil Shapiro 			family = AF_INET;
47415b0945b5SGregory Neil Shapiro 			flags = RR_AS_TEXT;
47425b0945b5SGregory Neil Shapiro 			q = strpbrk(p, " \t");
47435b0945b5SGregory Neil Shapiro 			if (q != NULL)
47445b0945b5SGregory Neil Shapiro 			{
47455b0945b5SGregory Neil Shapiro 				char *pflags;
47465b0945b5SGregory Neil Shapiro 
47475b0945b5SGregory Neil Shapiro 				while (SM_ISSPACE(*q))
47485b0945b5SGregory Neil Shapiro 					*q++ = '\0';
47495b0945b5SGregory Neil Shapiro 				pflags = strpbrk(q, " \t");
47505b0945b5SGregory Neil Shapiro 				if (pflags != NULL)
47515b0945b5SGregory Neil Shapiro 				{
47525b0945b5SGregory Neil Shapiro 					while (SM_ISSPACE(*pflags))
47535b0945b5SGregory Neil Shapiro 						*pflags++ = '\0';
47545b0945b5SGregory Neil Shapiro 				}
47555b0945b5SGregory Neil Shapiro 				rr_type = dns_string_to_type(q);
47565b0945b5SGregory Neil Shapiro 				if (rr_type == T_A)
47575b0945b5SGregory Neil Shapiro 					family = AF_INET;
47585b0945b5SGregory Neil Shapiro # if NETINET6
47595b0945b5SGregory Neil Shapiro 				if (rr_type == T_AAAA)
47605b0945b5SGregory Neil Shapiro 					family = AF_INET6;
47615b0945b5SGregory Neil Shapiro # endif
47625b0945b5SGregory Neil Shapiro 				while (pflags != NULL && *pflags != '\0' &&
47635b0945b5SGregory Neil Shapiro 					!SM_ISSPACE(*pflags))
47645b0945b5SGregory Neil Shapiro 				{
47655b0945b5SGregory Neil Shapiro 					if (*pflags == 'c')
47665b0945b5SGregory Neil Shapiro 						flags |= RR_NO_CNAME;
47675b0945b5SGregory Neil Shapiro 					else if (*pflags == 'o')
47685b0945b5SGregory Neil Shapiro 						flags |= RR_ONLY_CNAME;
47695b0945b5SGregory Neil Shapiro 					else if (*pflags == 'T')
47705b0945b5SGregory Neil Shapiro 						flags &= ~RR_AS_TEXT;
47715b0945b5SGregory Neil Shapiro 					++pflags;
47725b0945b5SGregory Neil Shapiro 				}
47735b0945b5SGregory Neil Shapiro 			}
47745b0945b5SGregory Neil Shapiro 			r = dns_lookup_int(p, C_IN, rr_type,
47755b0945b5SGregory Neil Shapiro 					0, 0, 0, flags, NULL, NULL);
47765b0945b5SGregory Neil Shapiro 			if (r != NULL && family >= 0)
47775b0945b5SGregory Neil Shapiro 			{
47785b0945b5SGregory Neil Shapiro 				(void) dns2he(r, family);
47795b0945b5SGregory Neil Shapiro 				dns_free_data(r);
47805b0945b5SGregory Neil Shapiro 				r = NULL;
47815b0945b5SGregory Neil Shapiro 			}
47825b0945b5SGregory Neil Shapiro 		}
4783d39bd2c1SGregory Neil Shapiro # if _FFR_TESTS
4784d39bd2c1SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "hostsignature"))
4785d39bd2c1SGregory Neil Shapiro 		{
4786d39bd2c1SGregory Neil Shapiro 			STAB *st;
4787d39bd2c1SGregory Neil Shapiro 			MAILER *m;
4788d39bd2c1SGregory Neil Shapiro 
4789d39bd2c1SGregory Neil Shapiro 			st = stab("esmtp", ST_MAILER, ST_FIND);
4790d39bd2c1SGregory Neil Shapiro 			if (NULL == st)
4791d39bd2c1SGregory Neil Shapiro 			{
4792d39bd2c1SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4793d39bd2c1SGregory Neil Shapiro 						     "Unknown mailer esmtp\n");
4794d39bd2c1SGregory Neil Shapiro 				return;
4795d39bd2c1SGregory Neil Shapiro 			}
4796d39bd2c1SGregory Neil Shapiro 			m = st->s_mailer;
4797d39bd2c1SGregory Neil Shapiro 			if (NULL == m)
4798d39bd2c1SGregory Neil Shapiro 			{
4799d39bd2c1SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4800d39bd2c1SGregory Neil Shapiro 						     "Unknown mailer esmtp\n");
4801d39bd2c1SGregory Neil Shapiro 				return;
4802d39bd2c1SGregory Neil Shapiro 			}
4803d39bd2c1SGregory Neil Shapiro 			t_hostsig(NULL, p, m);
4804d39bd2c1SGregory Neil Shapiro 		}
4805d39bd2c1SGregory Neil Shapiro 		else if (SM_STRCASEEQ(&line[1], "parsesig"))
4806d39bd2c1SGregory Neil Shapiro 			t_parsehostsig(p, NULL);
4807d39bd2c1SGregory Neil Shapiro # endif /* _FFR_TESTS */
48085b0945b5SGregory Neil Shapiro #endif /* DANE */
4809c2aa98e2SPeter Wemm 		else
4810c2aa98e2SPeter Wemm 		{
481140266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
481240266059SGregory Neil Shapiro 					     "Unknown \"/\" command %s\n",
481340266059SGregory Neil Shapiro 					     line);
4814c2aa98e2SPeter Wemm 		}
4815d0cef73dSGregory Neil Shapiro 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
4816c2aa98e2SPeter Wemm 		return;
4817c2aa98e2SPeter Wemm 	}
48185b0945b5SGregory Neil Shapiro 	for (p = line; SM_ISSPACE(*p); p++)
4819c2aa98e2SPeter Wemm 		continue;
4820c2aa98e2SPeter Wemm 	q = p;
48215b0945b5SGregory Neil Shapiro 	while (*p != '\0' && !(SM_ISSPACE(*p)))
4822c2aa98e2SPeter Wemm 		p++;
4823c2aa98e2SPeter Wemm 	if (*p == '\0')
4824c2aa98e2SPeter Wemm 	{
482540266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
482640266059SGregory Neil Shapiro 				     "No address!\n");
4827c2aa98e2SPeter Wemm 		return;
4828c2aa98e2SPeter Wemm 	}
4829c2aa98e2SPeter Wemm 	*p = '\0';
4830d0cef73dSGregory Neil Shapiro 	if (tTd(23, 101))
48312fb4f839SGregory Neil Shapiro 		eightbit = to8bit(p + 1, tTd(23, 102));
483240266059SGregory Neil Shapiro 	if (invalidaddr(p + 1, NULL, true))
4833c2aa98e2SPeter Wemm 		return;
4834c2aa98e2SPeter Wemm 	do
4835c2aa98e2SPeter Wemm 	{
4836c2aa98e2SPeter Wemm 		register char **pvp;
4837c2aa98e2SPeter Wemm 		char pvpbuf[PSBUFSIZE];
4838c2aa98e2SPeter Wemm 
4839d0cef73dSGregory Neil Shapiro 		pvp = prescan(++p, ',', pvpbuf, sizeof(pvpbuf), &delimptr,
48402fb4f839SGregory Neil Shapiro 				tTd(23, 103) ? ExtTokenTab :
4841d0cef73dSGregory Neil Shapiro 			      ConfigLevel >= 9 ? TokTypeNoC : ExtTokenTab, false);
4842c2aa98e2SPeter Wemm 		if (pvp == NULL)
4843c2aa98e2SPeter Wemm 			continue;
4844c2aa98e2SPeter Wemm 		p = q;
4845c2aa98e2SPeter Wemm 		while (*p != '\0')
4846c2aa98e2SPeter Wemm 		{
484706f25ae9SGregory Neil Shapiro 			int status;
4848c2aa98e2SPeter Wemm 
4849c2aa98e2SPeter Wemm 			rs = strtorwset(p, NULL, ST_FIND);
4850c2aa98e2SPeter Wemm 			if (rs < 0)
4851c2aa98e2SPeter Wemm 			{
485240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
485340266059SGregory Neil Shapiro 						     "Undefined ruleset %s\n",
485440266059SGregory Neil Shapiro 						     p);
4855c2aa98e2SPeter Wemm 				break;
4856c2aa98e2SPeter Wemm 			}
485740266059SGregory Neil Shapiro 			status = REWRITE(pvp, rs, e);
485806f25ae9SGregory Neil Shapiro 			if (status != EX_OK)
485940266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
486040266059SGregory Neil Shapiro 						     "== Ruleset %s (%d) status %d\n",
486106f25ae9SGregory Neil Shapiro 						     p, rs, status);
4862d0cef73dSGregory Neil Shapiro 			else if (eightbit)
4863d0cef73dSGregory Neil Shapiro 			{
4864d0cef73dSGregory Neil Shapiro 				cataddr(pvp, NULL, exbuf, sizeof(exbuf), '\0',
4865d0cef73dSGregory Neil Shapiro 					true);
4866d0cef73dSGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4867d0cef73dSGregory Neil Shapiro 						     "cataddr: %s\n",
4868d0cef73dSGregory Neil Shapiro 						     str2prt(exbuf));
4869d0cef73dSGregory Neil Shapiro 			}
4870c2aa98e2SPeter Wemm 			while (*p != '\0' && *p++ != ',')
4871c2aa98e2SPeter Wemm 				continue;
4872c2aa98e2SPeter Wemm 		}
4873c2aa98e2SPeter Wemm 	} while (*(p = delimptr) != '\0');
4874d0cef73dSGregory Neil Shapiro 	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
4875c2aa98e2SPeter Wemm }
4876c2aa98e2SPeter Wemm 
487706f25ae9SGregory Neil Shapiro static void
dump_class(s,id)4878c2aa98e2SPeter Wemm dump_class(s, id)
4879c2aa98e2SPeter Wemm 	register STAB *s;
4880c2aa98e2SPeter Wemm 	int id;
4881c2aa98e2SPeter Wemm {
488240266059SGregory Neil Shapiro 	if (s->s_symtype != ST_CLASS)
4883c2aa98e2SPeter Wemm 		return;
4884193538b7SGregory Neil Shapiro 	if (bitnset(bitidx(id), s->s_class))
488540266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
488640266059SGregory Neil Shapiro 				     "%s\n", s->s_name);
4887c2aa98e2SPeter Wemm }
488840266059SGregory Neil Shapiro 
488940266059SGregory Neil Shapiro /*
489040266059SGregory Neil Shapiro **  An exception type used to create QuickAbort exceptions.
489140266059SGregory Neil Shapiro **  This is my first cut at converting QuickAbort from longjmp to exceptions.
489240266059SGregory Neil Shapiro **  These exceptions have a single integer argument, which is the argument
489340266059SGregory Neil Shapiro **  to longjmp in the original code (either 1 or 2).  I don't know the
489440266059SGregory Neil Shapiro **  significance of 1 vs 2: the calls to setjmp don't care.
489540266059SGregory Neil Shapiro */
489640266059SGregory Neil Shapiro 
489740266059SGregory Neil Shapiro const SM_EXC_TYPE_T EtypeQuickAbort =
489840266059SGregory Neil Shapiro {
489940266059SGregory Neil Shapiro 	SmExcTypeMagic,
490040266059SGregory Neil Shapiro 	"E:mta.quickabort",
490140266059SGregory Neil Shapiro 	"i",
490240266059SGregory Neil Shapiro 	sm_etype_printf,
490340266059SGregory Neil Shapiro 	"quick abort %0",
490440266059SGregory Neil Shapiro };
4905