xref: /freebsd/contrib/sendmail/src/main.c (revision 40266059)
1c2aa98e2SPeter Wemm /*
2602a2b1bSGregory Neil Shapiro  * Copyright (c) 1998-2001 Sendmail, 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>
1640266059SGregory Neil Shapiro #include <sm/xtrap.h>
1740266059SGregory Neil Shapiro #include <sm/signal.h>
1840266059SGregory Neil Shapiro 
19c2aa98e2SPeter Wemm #ifndef lint
2040266059SGregory Neil Shapiro SM_UNUSED(static char copyright[]) =
21602a2b1bSGregory Neil Shapiro "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
2206f25ae9SGregory Neil Shapiro 	All rights reserved.\n\
23c2aa98e2SPeter Wemm      Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.\n\
24c2aa98e2SPeter Wemm      Copyright (c) 1988, 1993\n\
25c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
2606f25ae9SGregory Neil Shapiro #endif /* ! lint */
27c2aa98e2SPeter Wemm 
2840266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: main.c,v 8.868 2001/12/29 04:54:38 ca Exp $")
2906f25ae9SGregory Neil Shapiro 
3006f25ae9SGregory Neil Shapiro 
3106f25ae9SGregory Neil Shapiro #if NETINET || NETINET6
32c2aa98e2SPeter Wemm # include <arpa/inet.h>
3306f25ae9SGregory Neil Shapiro #endif /* NETINET || NETINET6 */
3406f25ae9SGregory Neil Shapiro 
3540266059SGregory Neil Shapiro /* for getcfname() */
3640266059SGregory Neil Shapiro #include <sendmail/pathnames.h>
3740266059SGregory Neil Shapiro 
3840266059SGregory Neil Shapiro static SM_DEBUG_T
3940266059SGregory Neil Shapiro DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
4040266059SGregory Neil Shapiro 	"@(#)$Debug: no_persistent_restart - don't restart, log only $");
4140266059SGregory Neil Shapiro 
4206f25ae9SGregory Neil Shapiro static void	dump_class __P((STAB *, int));
4306f25ae9SGregory Neil Shapiro static void	obsolete __P((char **));
4406f25ae9SGregory Neil Shapiro static void	testmodeline __P((char *, ENVELOPE *));
4540266059SGregory Neil Shapiro static char	*getextenv __P((const char *));
4640266059SGregory Neil Shapiro static void	sm_printoptions __P((char **));
4740266059SGregory Neil Shapiro static SIGFUNC_DECL	intindebug __P((int));
4840266059SGregory Neil Shapiro static SIGFUNC_DECL	sighup __P((int));
4940266059SGregory Neil Shapiro static SIGFUNC_DECL	sigpipe __P((int));
5040266059SGregory Neil Shapiro static SIGFUNC_DECL	sigterm __P((int));
5140266059SGregory Neil Shapiro #ifdef SIGUSR1
5240266059SGregory Neil Shapiro static SIGFUNC_DECL	sigusr1 __P((int));
5340266059SGregory Neil Shapiro #endif /* SIGUSR1 */
54c2aa98e2SPeter Wemm 
55c2aa98e2SPeter Wemm /*
56c2aa98e2SPeter Wemm **  SENDMAIL -- Post mail to a set of destinations.
57c2aa98e2SPeter Wemm **
58c2aa98e2SPeter Wemm **	This is the basic mail router.  All user mail programs should
59c2aa98e2SPeter Wemm **	call this routine to actually deliver mail.  Sendmail in
60c2aa98e2SPeter Wemm **	turn calls a bunch of mail servers that do the real work of
61c2aa98e2SPeter Wemm **	delivering the mail.
62c2aa98e2SPeter Wemm **
6306f25ae9SGregory Neil Shapiro **	Sendmail is driven by settings read in from /etc/mail/sendmail.cf
64c2aa98e2SPeter Wemm **	(read by readcf.c).
65c2aa98e2SPeter Wemm **
66c2aa98e2SPeter Wemm **	Usage:
67c2aa98e2SPeter Wemm **		/usr/lib/sendmail [flags] addr ...
68c2aa98e2SPeter Wemm **
69c2aa98e2SPeter Wemm **		See the associated documentation for details.
70c2aa98e2SPeter Wemm **
7140266059SGregory Neil Shapiro **	Authors:
72c2aa98e2SPeter Wemm **		Eric Allman, UCB/INGRES (until 10/81).
73c2aa98e2SPeter Wemm **			     Britton-Lee, Inc., purveyors of fine
74c2aa98e2SPeter Wemm **				database computers (11/81 - 10/88).
75c2aa98e2SPeter Wemm **			     International Computer Science Institute
76c2aa98e2SPeter Wemm **				(11/88 - 9/89).
77c2aa98e2SPeter Wemm **			     UCB/Mammoth Project (10/89 - 7/95).
78c2aa98e2SPeter Wemm **			     InReference, Inc. (8/95 - 1/97).
79c2aa98e2SPeter Wemm **			     Sendmail, Inc. (1/98 - present).
80c2aa98e2SPeter Wemm **		The support of the my employers is gratefully acknowledged.
81c2aa98e2SPeter Wemm **			Few of them (Britton-Lee in particular) have had
82c2aa98e2SPeter Wemm **			anything to gain from my involvement in this project.
8340266059SGregory Neil Shapiro **
8440266059SGregory Neil Shapiro **		Gregory Neil Shapiro,
8540266059SGregory Neil Shapiro **			Worcester Polytechnic Institute	(until 3/98).
8640266059SGregory Neil Shapiro **			Sendmail, Inc. (3/98 - present).
8740266059SGregory Neil Shapiro **
8840266059SGregory Neil Shapiro **		Claus Assmann,
8940266059SGregory Neil Shapiro **			Sendmail, Inc. (12/98 - present).
90c2aa98e2SPeter Wemm */
91c2aa98e2SPeter Wemm 
92c2aa98e2SPeter Wemm char		*FullName;	/* sender's full name */
93c2aa98e2SPeter Wemm ENVELOPE	BlankEnvelope;	/* a "blank" envelope */
9406f25ae9SGregory Neil Shapiro static ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */
95c2aa98e2SPeter Wemm ADDRESS		NullAddress =	/* a null address */
96c2aa98e2SPeter Wemm 		{ "", "", NULL, "" };
97c2aa98e2SPeter Wemm char		*CommandLineArgs;	/* command line args for pid file */
9840266059SGregory Neil Shapiro bool		Warn_Q_option = false;	/* warn about Q option use */
9906f25ae9SGregory Neil Shapiro static int	MissingFds = 0;	/* bit map of fds missing on startup */
10040266059SGregory Neil Shapiro char		*Mbdb = "pw";	/* mailbox database defaults to /etc/passwd */
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm #ifdef NGROUPS_MAX
103c2aa98e2SPeter Wemm GIDSET_T	InitialGidSet[NGROUPS_MAX];
10406f25ae9SGregory Neil Shapiro #endif /* NGROUPS_MAX */
105c2aa98e2SPeter Wemm 
10640266059SGregory Neil Shapiro #define MAXCONFIGLEVEL	10	/* highest config version level known */
10706f25ae9SGregory Neil Shapiro 
10806f25ae9SGregory Neil Shapiro #if SASL
10906f25ae9SGregory Neil Shapiro static sasl_callback_t srvcallbacks[] =
11006f25ae9SGregory Neil Shapiro {
11106f25ae9SGregory Neil Shapiro 	{	SASL_CB_VERIFYFILE,	&safesaslfile,	NULL	},
11206f25ae9SGregory Neil Shapiro 	{	SASL_CB_PROXY_POLICY,	&proxy_policy,	NULL	},
11306f25ae9SGregory Neil Shapiro 	{	SASL_CB_LIST_END,	NULL,		NULL	}
11406f25ae9SGregory Neil Shapiro };
11506f25ae9SGregory Neil Shapiro #endif /* SASL */
11606f25ae9SGregory Neil Shapiro 
11740266059SGregory Neil Shapiro unsigned int	SubmitMode;
11840266059SGregory Neil Shapiro int		SyslogPrefixLen; /* estimated length of syslog prefix */
11940266059SGregory Neil Shapiro #define PIDLEN		6	/* pid length for computing SyslogPrefixLen */
12040266059SGregory Neil Shapiro #ifndef SL_FUDGE
12140266059SGregory Neil Shapiro # define SL_FUDGE	10	/* fudge offset for SyslogPrefixLen */
12240266059SGregory Neil Shapiro #endif /* ! SL_FUDGE */
12340266059SGregory Neil Shapiro #define SLDLL		8	/* est. length of default syslog label */
12440266059SGregory Neil Shapiro 
12540266059SGregory Neil Shapiro 
12640266059SGregory Neil Shapiro /* Some options are dangerous to allow users to use in non-submit mode */
12740266059SGregory Neil Shapiro #define CHECK_AGAINST_OPMODE(cmd)					\
12840266059SGregory Neil Shapiro {									\
12940266059SGregory Neil Shapiro 	if (extraprivs &&						\
13040266059SGregory Neil Shapiro 	    OpMode != MD_DELIVER && OpMode != MD_SMTP &&		\
13140266059SGregory Neil Shapiro 	    OpMode != MD_VERIFY && OpMode != MD_TEST)			\
13240266059SGregory Neil Shapiro 	{								\
13340266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
13440266059SGregory Neil Shapiro 				     "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
13540266059SGregory Neil Shapiro 		       (cmd));						\
13640266059SGregory Neil Shapiro 		break;							\
13740266059SGregory Neil Shapiro 	}								\
13840266059SGregory Neil Shapiro 	if (extraprivs && queuerun)					\
13940266059SGregory Neil Shapiro 	{								\
14040266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
14140266059SGregory Neil Shapiro 				     "WARNING: Ignoring submission mode -%c option with -q\n", \
14240266059SGregory Neil Shapiro 		       (cmd));						\
14340266059SGregory Neil Shapiro 		break;							\
14440266059SGregory Neil Shapiro 	}								\
14540266059SGregory Neil Shapiro }
146c2aa98e2SPeter Wemm 
147c2aa98e2SPeter Wemm int
148c2aa98e2SPeter Wemm main(argc, argv, envp)
149c2aa98e2SPeter Wemm 	int argc;
150c2aa98e2SPeter Wemm 	char **argv;
151c2aa98e2SPeter Wemm 	char **envp;
152c2aa98e2SPeter Wemm {
153c2aa98e2SPeter Wemm 	register char *p;
154c2aa98e2SPeter Wemm 	char **av;
155c2aa98e2SPeter Wemm 	extern char Version[];
156c2aa98e2SPeter Wemm 	char *ep, *from;
157c2aa98e2SPeter Wemm 	STAB *st;
158c2aa98e2SPeter Wemm 	register int i;
159c2aa98e2SPeter Wemm 	int j;
16006f25ae9SGregory Neil Shapiro 	int dp;
16140266059SGregory Neil Shapiro 	int fill_errno;
16240266059SGregory Neil Shapiro 	int qgrp = NOQGRP;		/* queue group to process */
16340266059SGregory Neil Shapiro 	bool safecf = true;
16406f25ae9SGregory Neil Shapiro 	BITMAP256 *p_flags = NULL;	/* daemon flags */
16540266059SGregory Neil Shapiro 	bool warn_C_flag = false;
16640266059SGregory Neil Shapiro 	bool auth = true;		/* whether to set e_auth_param */
167c2aa98e2SPeter Wemm 	char warn_f_flag = '\0';
16840266059SGregory Neil Shapiro 	bool run_in_foreground = false;	/* -bD mode */
16940266059SGregory Neil Shapiro 	bool queuerun = false, debug = false;
170c2aa98e2SPeter Wemm 	struct passwd *pw;
171c2aa98e2SPeter Wemm 	struct hostent *hp;
172c2aa98e2SPeter Wemm 	char *nullserver = NULL;
17306f25ae9SGregory Neil Shapiro 	char *authinfo = NULL;
17406f25ae9SGregory Neil Shapiro 	char *sysloglabel = NULL;	/* label for syslog */
17540266059SGregory Neil Shapiro 	char *conffile = NULL;		/* name of .cf file */
17640266059SGregory Neil Shapiro 	char *queuegroup = NULL;	/* queue group to process */
17740266059SGregory Neil Shapiro #if _FFR_QUARANTINE
17840266059SGregory Neil Shapiro 	char *quarantining = NULL;	/* quarantine queue items? */
17940266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
18040266059SGregory Neil Shapiro 	bool extraprivs;
18140266059SGregory Neil Shapiro 	bool forged, negate;
18240266059SGregory Neil Shapiro 	bool queuepersistent = false;	/* queue runner process runs forever */
18340266059SGregory Neil Shapiro 	bool foregroundqueue = false;	/* queue run in foreground */
18440266059SGregory Neil Shapiro 	bool save_val;			/* to save some bool var. */
18540266059SGregory Neil Shapiro 	int cftype;			/* which cf file to use? */
18640266059SGregory Neil Shapiro 	static time_t starttime = 0;	/* when was process started */
18706f25ae9SGregory Neil Shapiro 	struct stat traf_st;		/* for TrafficLog FIFO check */
18840266059SGregory Neil Shapiro 	char buf[MAXLINE];
189c2aa98e2SPeter Wemm 	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */
190c2aa98e2SPeter Wemm 	static char rnamebuf[MAXNAME];	/* holds RealUserName */
191c2aa98e2SPeter Wemm 	char *emptyenviron[1];
19242e5d165SGregory Neil Shapiro #if STARTTLS
19342e5d165SGregory Neil Shapiro 	bool tls_ok;
19442e5d165SGregory Neil Shapiro #endif /* STARTTLS */
195c2aa98e2SPeter Wemm 	QUEUE_CHAR *new;
19640266059SGregory Neil Shapiro 	ENVELOPE *e;
197c2aa98e2SPeter Wemm 	extern int DtableSize;
198c2aa98e2SPeter Wemm 	extern int optind;
199c2aa98e2SPeter Wemm 	extern int opterr;
200c2aa98e2SPeter Wemm 	extern char *optarg;
201c2aa98e2SPeter Wemm 	extern char **environ;
20240266059SGregory Neil Shapiro #if SASL
20340266059SGregory Neil Shapiro 	extern void sm_sasl_init __P((void));
20440266059SGregory Neil Shapiro #endif /* SASL */
20540266059SGregory Neil Shapiro 
20640266059SGregory Neil Shapiro #if USE_ENVIRON
20740266059SGregory Neil Shapiro 	envp = environ;
20840266059SGregory Neil Shapiro #endif /* USE_ENVIRON */
20940266059SGregory Neil Shapiro 
21040266059SGregory Neil Shapiro 	/* turn off profiling */
21140266059SGregory Neil Shapiro 	SM_PROF(0);
21240266059SGregory Neil Shapiro 
21340266059SGregory Neil Shapiro 	/* install default exception handler */
21440266059SGregory Neil Shapiro 	sm_exc_newthread(fatal_error);
215c2aa98e2SPeter Wemm 
216c2aa98e2SPeter Wemm 	/*
217c2aa98e2SPeter Wemm 	**  Check to see if we reentered.
218c2aa98e2SPeter Wemm 	**	This would normally happen if e_putheader or e_putbody
219c2aa98e2SPeter Wemm 	**	were NULL when invoked.
220c2aa98e2SPeter Wemm 	*/
221c2aa98e2SPeter Wemm 
22240266059SGregory Neil Shapiro 	if (starttime != 0)
223c2aa98e2SPeter Wemm 	{
224c2aa98e2SPeter Wemm 		syserr("main: reentered!");
225c2aa98e2SPeter Wemm 		abort();
226c2aa98e2SPeter Wemm 	}
22740266059SGregory Neil Shapiro 	starttime = curtime();
228c2aa98e2SPeter Wemm 
229c2aa98e2SPeter Wemm 	/* avoid null pointer dereferences */
230c2aa98e2SPeter Wemm 	TermEscape.te_rv_on = TermEscape.te_rv_off = "";
231c2aa98e2SPeter Wemm 
23240266059SGregory Neil Shapiro 	RealUid = getuid();
23340266059SGregory Neil Shapiro 	RealGid = getgid();
23440266059SGregory Neil Shapiro 
23540266059SGregory Neil Shapiro 	/* Check if sendmail is running with extra privs */
23640266059SGregory Neil Shapiro 	extraprivs = (RealUid != 0 &&
23740266059SGregory Neil Shapiro 		      (geteuid() != getuid() || getegid() != getgid()));
23840266059SGregory Neil Shapiro 
23940266059SGregory Neil Shapiro 	CurrentPid = getpid();
24040266059SGregory Neil Shapiro 
24140266059SGregory Neil Shapiro 	/* get whatever .cf file is right for the opmode */
24240266059SGregory Neil Shapiro 	cftype = SM_GET_RIGHT_CF;
24340266059SGregory Neil Shapiro 
24440266059SGregory Neil Shapiro 	/* in 4.4BSD, the table can be huge; impose a reasonable limit */
24540266059SGregory Neil Shapiro 	DtableSize = getdtsize();
24640266059SGregory Neil Shapiro 	if (DtableSize > 256)
24740266059SGregory Neil Shapiro 		DtableSize = 256;
24840266059SGregory Neil Shapiro 
24940266059SGregory Neil Shapiro 	/*
25040266059SGregory Neil Shapiro 	**  Be sure we have enough file descriptors.
25140266059SGregory Neil Shapiro 	**	But also be sure that 0, 1, & 2 are open.
25240266059SGregory Neil Shapiro 	*/
25340266059SGregory Neil Shapiro 
25440266059SGregory Neil Shapiro 	/* reset errno and fill_errno; the latter is used way down below */
25540266059SGregory Neil Shapiro 	errno = fill_errno = 0;
25640266059SGregory Neil Shapiro 	fill_fd(STDIN_FILENO, NULL);
25740266059SGregory Neil Shapiro 	if (errno != 0)
25840266059SGregory Neil Shapiro 		fill_errno = errno;
25940266059SGregory Neil Shapiro 	fill_fd(STDOUT_FILENO, NULL);
26040266059SGregory Neil Shapiro 	if (errno != 0)
26140266059SGregory Neil Shapiro 		fill_errno = errno;
26240266059SGregory Neil Shapiro 	fill_fd(STDERR_FILENO, NULL);
26340266059SGregory Neil Shapiro 	if (errno != 0)
26440266059SGregory Neil Shapiro 		fill_errno = errno;
26540266059SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro 	i = DtableSize;
26740266059SGregory Neil Shapiro 	while (--i > 0)
26840266059SGregory Neil Shapiro 	{
26940266059SGregory Neil Shapiro 		if (i != STDIN_FILENO && i != STDOUT_FILENO &&
27040266059SGregory Neil Shapiro 		    i != STDERR_FILENO)
27140266059SGregory Neil Shapiro 			(void) close(i);
27240266059SGregory Neil Shapiro 	}
27340266059SGregory Neil Shapiro 	errno = 0;
27440266059SGregory Neil Shapiro 
27540266059SGregory Neil Shapiro #if LOG
27640266059SGregory Neil Shapiro # ifndef SM_LOG_STR
27740266059SGregory Neil Shapiro #  define SM_LOG_STR	"sendmail"
27840266059SGregory Neil Shapiro # endif /* ! SM_LOG_STR */
27940266059SGregory Neil Shapiro #  ifdef LOG_MAIL
28040266059SGregory Neil Shapiro 	openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
28140266059SGregory Neil Shapiro #  else /* LOG_MAIL */
28240266059SGregory Neil Shapiro 	openlog(SM_LOG_STR, LOG_PID);
28340266059SGregory Neil Shapiro #  endif /* LOG_MAIL */
28440266059SGregory Neil Shapiro #endif /* LOG */
28540266059SGregory Neil Shapiro 
2868774250cSGregory Neil Shapiro 	/*
2878774250cSGregory Neil Shapiro 	**  Seed the random number generator.
2888774250cSGregory Neil Shapiro 	**  Used for queue file names, picking a queue directory, and
2898774250cSGregory Neil Shapiro 	**  MX randomization.
2908774250cSGregory Neil Shapiro 	*/
2918774250cSGregory Neil Shapiro 
2928774250cSGregory Neil Shapiro 	seed_random();
2938774250cSGregory Neil Shapiro 
294c2aa98e2SPeter Wemm 	/* do machine-dependent initializations */
295c2aa98e2SPeter Wemm 	init_md(argc, argv);
296c2aa98e2SPeter Wemm 
29706f25ae9SGregory Neil Shapiro 
29840266059SGregory Neil Shapiro 	SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;
299c2aa98e2SPeter Wemm 
300c2aa98e2SPeter Wemm 	/* reset status from syserr() calls for missing file descriptors */
301c2aa98e2SPeter Wemm 	Errors = 0;
302c2aa98e2SPeter Wemm 	ExitStat = EX_OK;
303c2aa98e2SPeter Wemm 
30406f25ae9SGregory Neil Shapiro 	SubmitMode = SUBMIT_UNKNOWN;
305c2aa98e2SPeter Wemm #if XDEBUG
306c2aa98e2SPeter Wemm 	checkfd012("after openlog");
30706f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
30806f25ae9SGregory Neil Shapiro 
30940266059SGregory Neil Shapiro 	tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1");
310c2aa98e2SPeter Wemm 
311c2aa98e2SPeter Wemm #ifdef NGROUPS_MAX
312c2aa98e2SPeter Wemm 	/* save initial group set for future checks */
313c2aa98e2SPeter Wemm 	i = getgroups(NGROUPS_MAX, InitialGidSet);
31440266059SGregory Neil Shapiro 	if (i <= 0)
31540266059SGregory Neil Shapiro 	{
316c2aa98e2SPeter Wemm 		InitialGidSet[0] = (GID_T) -1;
31740266059SGregory Neil Shapiro 		i = 0;
31840266059SGregory Neil Shapiro 	}
319c2aa98e2SPeter Wemm 	while (i < NGROUPS_MAX)
320c2aa98e2SPeter Wemm 		InitialGidSet[i++] = InitialGidSet[0];
32106f25ae9SGregory Neil Shapiro #endif /* NGROUPS_MAX */
322c2aa98e2SPeter Wemm 
323c2aa98e2SPeter Wemm 	/* drop group id privileges (RunAsUser not yet set) */
32440266059SGregory Neil Shapiro 	dp = drop_privileges(false);
32506f25ae9SGregory Neil Shapiro 	setstat(dp);
326c2aa98e2SPeter Wemm 
327c2aa98e2SPeter Wemm #ifdef SIGUSR1
3288774250cSGregory Neil Shapiro 	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
32940266059SGregory Neil Shapiro 	if (extraprivs)
3308774250cSGregory Neil Shapiro 	{
331c2aa98e2SPeter Wemm 		/* arrange to dump state on user-1 signal */
33240266059SGregory Neil Shapiro 		(void) sm_signal(SIGUSR1, sigusr1);
3338774250cSGregory Neil Shapiro 	}
33406f25ae9SGregory Neil Shapiro #endif /* SIGUSR1 */
335c2aa98e2SPeter Wemm 
336c2aa98e2SPeter Wemm 	/* initialize for setproctitle */
337c2aa98e2SPeter Wemm 	initsetproctitle(argc, argv, envp);
338c2aa98e2SPeter Wemm 
339c2aa98e2SPeter Wemm 	/* Handle any non-getoptable constructions. */
340c2aa98e2SPeter Wemm 	obsolete(argv);
341c2aa98e2SPeter Wemm 
342c2aa98e2SPeter Wemm 	/*
343c2aa98e2SPeter Wemm 	**  Do a quick prescan of the argument list.
344c2aa98e2SPeter Wemm 	*/
345c2aa98e2SPeter Wemm 
34606f25ae9SGregory Neil Shapiro 
34740266059SGregory Neil Shapiro 	/* find initial opMode */
34840266059SGregory Neil Shapiro 	OpMode = MD_DELIVER;
34940266059SGregory Neil Shapiro 	av = argv;
35040266059SGregory Neil Shapiro 	p = strrchr(*av, '/');
35140266059SGregory Neil Shapiro 	if (p++ == NULL)
35240266059SGregory Neil Shapiro 		p = *av;
35340266059SGregory Neil Shapiro 	if (strcmp(p, "newaliases") == 0)
35440266059SGregory Neil Shapiro 		OpMode = MD_INITALIAS;
35540266059SGregory Neil Shapiro 	else if (strcmp(p, "mailq") == 0)
35640266059SGregory Neil Shapiro 		OpMode = MD_PRINT;
35740266059SGregory Neil Shapiro 	else if (strcmp(p, "smtpd") == 0)
35840266059SGregory Neil Shapiro 		OpMode = MD_DAEMON;
35940266059SGregory Neil Shapiro 	else if (strcmp(p, "hoststat") == 0)
36040266059SGregory Neil Shapiro 		OpMode = MD_HOSTSTAT;
36140266059SGregory Neil Shapiro 	else if (strcmp(p, "purgestat") == 0)
36240266059SGregory Neil Shapiro 		OpMode = MD_PURGESTAT;
36340266059SGregory Neil Shapiro 
36440266059SGregory Neil Shapiro #if _FFR_QUARANTINE
365c2aa98e2SPeter Wemm # if defined(__osf__) || defined(_AIX3)
36640266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:xQ:"
36706f25ae9SGregory Neil Shapiro # endif /* defined(__osf__) || defined(_AIX3) */
368c2aa98e2SPeter Wemm # if defined(sony_news)
36940266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"
37006f25ae9SGregory Neil Shapiro # endif /* defined(sony_news) */
371c2aa98e2SPeter Wemm # ifndef OPTIONS
37240266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"
37306f25ae9SGregory Neil Shapiro # endif /* ! OPTIONS */
37440266059SGregory Neil Shapiro #else /* _FFR_QUARANTINE */
37540266059SGregory Neil Shapiro # if defined(__osf__) || defined(_AIX3)
37640266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:x"
37740266059SGregory Neil Shapiro # endif /* defined(__osf__) || defined(_AIX3) */
37840266059SGregory Neil Shapiro # if defined(sony_news)
37940266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:"
38040266059SGregory Neil Shapiro # endif /* defined(sony_news) */
38140266059SGregory Neil Shapiro # ifndef OPTIONS
38240266059SGregory Neil Shapiro #  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:"
38340266059SGregory Neil Shapiro # endif /* ! OPTIONS */
38440266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
38540266059SGregory Neil Shapiro 
386c2aa98e2SPeter Wemm 	opterr = 0;
387c2aa98e2SPeter Wemm 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
388c2aa98e2SPeter Wemm 	{
389c2aa98e2SPeter Wemm 		switch (j)
390c2aa98e2SPeter Wemm 		{
39140266059SGregory Neil Shapiro 		  case 'b':	/* operations mode */
39240266059SGregory Neil Shapiro 			switch (j = *optarg)
393c2aa98e2SPeter Wemm 			{
39440266059SGregory Neil Shapiro 			  case MD_DAEMON:
39540266059SGregory Neil Shapiro 			  case MD_FGDAEMON:
39640266059SGregory Neil Shapiro 			  case MD_SMTP:
39740266059SGregory Neil Shapiro 			  case MD_INITALIAS:
39840266059SGregory Neil Shapiro 			  case MD_DELIVER:
39940266059SGregory Neil Shapiro 			  case MD_VERIFY:
40040266059SGregory Neil Shapiro 			  case MD_TEST:
40140266059SGregory Neil Shapiro 			  case MD_PRINT:
40240266059SGregory Neil Shapiro 			  case MD_PRINTNQE:
40340266059SGregory Neil Shapiro 			  case MD_HOSTSTAT:
40440266059SGregory Neil Shapiro 			  case MD_PURGESTAT:
40540266059SGregory Neil Shapiro 			  case MD_ARPAFTP:
40640266059SGregory Neil Shapiro 				OpMode = j;
407c2aa98e2SPeter Wemm 				break;
40840266059SGregory Neil Shapiro 
40940266059SGregory Neil Shapiro 			  case MD_FREEZE:
41040266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
41140266059SGregory Neil Shapiro 						     "Frozen configurations unsupported\n");
41240266059SGregory Neil Shapiro 				return EX_USAGE;
41340266059SGregory Neil Shapiro 
41440266059SGregory Neil Shapiro 			  default:
41540266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
41640266059SGregory Neil Shapiro 						     "Invalid operation mode %c\n",
41740266059SGregory Neil Shapiro 						     j);
41840266059SGregory Neil Shapiro 				return EX_USAGE;
419c2aa98e2SPeter Wemm 			}
42040266059SGregory Neil Shapiro 			break;
42140266059SGregory Neil Shapiro 
42240266059SGregory Neil Shapiro 		  case 'd':
42340266059SGregory Neil Shapiro 			debug = true;
424c2aa98e2SPeter Wemm 			tTflag(optarg);
42540266059SGregory Neil Shapiro 			(void) sm_io_setvbuf(smioout, SM_TIME_DEFAULT,
42640266059SGregory Neil Shapiro 					     (char *) NULL, SM_IO_NBF,
42740266059SGregory Neil Shapiro 					     SM_IO_BUFSIZ);
428c2aa98e2SPeter Wemm 			break;
42906f25ae9SGregory Neil Shapiro 
43006f25ae9SGregory Neil Shapiro 		  case 'G':	/* relay (gateway) submission */
43140266059SGregory Neil Shapiro 			SubmitMode = SUBMIT_MTA;
43206f25ae9SGregory Neil Shapiro 			break;
43306f25ae9SGregory Neil Shapiro 
43406f25ae9SGregory Neil Shapiro 		  case 'L':
43540266059SGregory Neil Shapiro 			j = SM_MIN(strlen(optarg), 24) + 1;
43606f25ae9SGregory Neil Shapiro 			sysloglabel = xalloc(j);
43740266059SGregory Neil Shapiro 			(void) sm_strlcpy(sysloglabel, optarg, j);
43840266059SGregory Neil Shapiro 			SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +
43940266059SGregory Neil Shapiro 					  SL_FUDGE + j;
44006f25ae9SGregory Neil Shapiro 			break;
44106f25ae9SGregory Neil Shapiro 
44240266059SGregory Neil Shapiro #if _FFR_QUARANTINE
44340266059SGregory Neil Shapiro 		  case 'Q':
44440266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
44540266059SGregory Neil Shapiro 		  case 'q':
44640266059SGregory Neil Shapiro 			/* just check if it is there */
44740266059SGregory Neil Shapiro 			queuerun = true;
44806f25ae9SGregory Neil Shapiro 			break;
449c2aa98e2SPeter Wemm 		}
450c2aa98e2SPeter Wemm 	}
451c2aa98e2SPeter Wemm 	opterr = 1;
452c2aa98e2SPeter Wemm 
45340266059SGregory Neil Shapiro 	/* Don't leak queue information via debug flags */
45440266059SGregory Neil Shapiro 	if (extraprivs && queuerun && debug)
45540266059SGregory Neil Shapiro 	{
45640266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
45740266059SGregory Neil Shapiro 				     "WARNING: Can not use -d with -q.  Disabling debugging.\n");
45840266059SGregory Neil Shapiro 		sm_debug_setfile(NULL);
45940266059SGregory Neil Shapiro 		(void) memset(tTdvect, '\0', sizeof tTdvect);
46040266059SGregory Neil Shapiro 	}
46140266059SGregory Neil Shapiro 
4628774250cSGregory Neil Shapiro #if LOG
46306f25ae9SGregory Neil Shapiro 	if (sysloglabel != NULL)
46406f25ae9SGregory Neil Shapiro 	{
4658774250cSGregory Neil Shapiro 		/* Sanitize the string */
4668774250cSGregory Neil Shapiro 		for (p = sysloglabel; *p != '\0'; p++)
4678774250cSGregory Neil Shapiro 		{
4688774250cSGregory Neil Shapiro 			if (!isascii(*p) || !isprint(*p) || *p == '%')
4698774250cSGregory Neil Shapiro 				*p = '*';
4708774250cSGregory Neil Shapiro 		}
47106f25ae9SGregory Neil Shapiro 		closelog();
47206f25ae9SGregory Neil Shapiro #  ifdef LOG_MAIL
47306f25ae9SGregory Neil Shapiro 		openlog(sysloglabel, LOG_PID, LOG_MAIL);
47406f25ae9SGregory Neil Shapiro #  else /* LOG_MAIL */
47506f25ae9SGregory Neil Shapiro 		openlog(sysloglabel, LOG_PID);
47606f25ae9SGregory Neil Shapiro #  endif /* LOG_MAIL */
47706f25ae9SGregory Neil Shapiro 	}
4788774250cSGregory Neil Shapiro #endif /* LOG */
47906f25ae9SGregory Neil Shapiro 
480c2aa98e2SPeter Wemm 	/* set up the blank envelope */
481c2aa98e2SPeter Wemm 	BlankEnvelope.e_puthdr = putheader;
482c2aa98e2SPeter Wemm 	BlankEnvelope.e_putbody = putbody;
483c2aa98e2SPeter Wemm 	BlankEnvelope.e_xfp = NULL;
484c2aa98e2SPeter Wemm 	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
485c2aa98e2SPeter Wemm 	CurEnv = &BlankEnvelope;
486c2aa98e2SPeter Wemm 	STRUCTCOPY(NullAddress, MainEnvelope.e_from);
487c2aa98e2SPeter Wemm 
488c2aa98e2SPeter Wemm 	/*
489c2aa98e2SPeter Wemm 	**  Set default values for variables.
490c2aa98e2SPeter Wemm 	**	These cannot be in initialized data space.
491c2aa98e2SPeter Wemm 	*/
492c2aa98e2SPeter Wemm 
493c2aa98e2SPeter Wemm 	setdefaults(&BlankEnvelope);
49440266059SGregory Neil Shapiro 	initmacros(&BlankEnvelope);
495c2aa98e2SPeter Wemm 
49640266059SGregory Neil Shapiro 	/* reset macro */
49740266059SGregory Neil Shapiro 	set_op_mode(OpMode);
498c2aa98e2SPeter Wemm 
499c2aa98e2SPeter Wemm 	pw = sm_getpwuid(RealUid);
500c2aa98e2SPeter Wemm 	if (pw != NULL)
50140266059SGregory Neil Shapiro 		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
502c2aa98e2SPeter Wemm 	else
50340266059SGregory Neil Shapiro 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
50406f25ae9SGregory Neil Shapiro 				   (int) RealUid);
50506f25ae9SGregory Neil Shapiro 
506c2aa98e2SPeter Wemm 	RealUserName = rnamebuf;
507c2aa98e2SPeter Wemm 
508c2aa98e2SPeter Wemm 	if (tTd(0, 101))
509c2aa98e2SPeter Wemm 	{
51040266059SGregory Neil Shapiro 		sm_dprintf("Version %s\n", Version);
51140266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
51240266059SGregory Neil Shapiro 		/* NOTREACHED */
513c2aa98e2SPeter Wemm 	}
514c2aa98e2SPeter Wemm 
515c2aa98e2SPeter Wemm 	/*
51640266059SGregory Neil Shapiro 	**  if running non-set-user-ID binary as non-root, pretend
517c2aa98e2SPeter Wemm 	**  we are the RunAsUid
518c2aa98e2SPeter Wemm 	*/
5198774250cSGregory Neil Shapiro 
520c2aa98e2SPeter Wemm 	if (RealUid != 0 && geteuid() == RealUid)
521c2aa98e2SPeter Wemm 	{
522c2aa98e2SPeter Wemm 		if (tTd(47, 1))
52340266059SGregory Neil Shapiro 			sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",
524c2aa98e2SPeter Wemm 				   (int) RealUid);
525c2aa98e2SPeter Wemm 		RunAsUid = RealUid;
526c2aa98e2SPeter Wemm 	}
527c2aa98e2SPeter Wemm 	else if (geteuid() != 0)
528c2aa98e2SPeter Wemm 		RunAsUid = geteuid();
529c2aa98e2SPeter Wemm 
53040266059SGregory Neil Shapiro 	EffGid = getegid();
53140266059SGregory Neil Shapiro 	if (RealUid != 0 && EffGid == RealGid)
532c2aa98e2SPeter Wemm 		RunAsGid = RealGid;
533c2aa98e2SPeter Wemm 
534c2aa98e2SPeter Wemm 	if (tTd(47, 5))
535c2aa98e2SPeter Wemm 	{
53640266059SGregory Neil Shapiro 		sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
53706f25ae9SGregory Neil Shapiro 			   (int) geteuid(), (int) getuid(),
53806f25ae9SGregory Neil Shapiro 			   (int) getegid(), (int) getgid());
53940266059SGregory Neil Shapiro 		sm_dprintf("main: RunAsUser = %d:%d\n",
54006f25ae9SGregory Neil Shapiro 			   (int) RunAsUid, (int) RunAsGid);
541c2aa98e2SPeter Wemm 	}
542c2aa98e2SPeter Wemm 
543c2aa98e2SPeter Wemm 	/* save command line arguments */
54406f25ae9SGregory Neil Shapiro 	j = 0;
545c2aa98e2SPeter Wemm 	for (av = argv; *av != NULL; )
54606f25ae9SGregory Neil Shapiro 		j += strlen(*av++) + 1;
54740266059SGregory Neil Shapiro 	if (j < 0 || j > SM_ARG_MAX)
54840266059SGregory Neil Shapiro 	{
54940266059SGregory Neil Shapiro 		syserr("!Arguments too long");
55040266059SGregory Neil Shapiro 
55140266059SGregory Neil Shapiro 		/* NOTREACHED */
55240266059SGregory Neil Shapiro 		return EX_USAGE;
55340266059SGregory Neil Shapiro 	}
554c2aa98e2SPeter Wemm 	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
55506f25ae9SGregory Neil Shapiro 	CommandLineArgs = xalloc(j);
556c2aa98e2SPeter Wemm 	p = CommandLineArgs;
557c2aa98e2SPeter Wemm 	for (av = argv, i = 0; *av != NULL; )
558c2aa98e2SPeter Wemm 	{
55906f25ae9SGregory Neil Shapiro 		int h;
56006f25ae9SGregory Neil Shapiro 
561c2aa98e2SPeter Wemm 		SaveArgv[i++] = newstr(*av);
562c2aa98e2SPeter Wemm 		if (av != argv)
563c2aa98e2SPeter Wemm 			*p++ = ' ';
56440266059SGregory Neil Shapiro 		(void) sm_strlcpy(p, *av++, j);
56506f25ae9SGregory Neil Shapiro 		h = strlen(p);
56606f25ae9SGregory Neil Shapiro 		p += h;
56706f25ae9SGregory Neil Shapiro 		j -= h + 1;
568c2aa98e2SPeter Wemm 	}
569c2aa98e2SPeter Wemm 	SaveArgv[i] = NULL;
570c2aa98e2SPeter Wemm 
571c2aa98e2SPeter Wemm 	if (tTd(0, 1))
572c2aa98e2SPeter Wemm 	{
573c2aa98e2SPeter Wemm 		extern char *CompileOptions[];
574c2aa98e2SPeter Wemm 
57540266059SGregory Neil Shapiro 		sm_dprintf("Version %s\n Compiled with:", Version);
57640266059SGregory Neil Shapiro 		sm_printoptions(CompileOptions);
577c2aa98e2SPeter Wemm 	}
578c2aa98e2SPeter Wemm 	if (tTd(0, 10))
579c2aa98e2SPeter Wemm 	{
580c2aa98e2SPeter Wemm 		extern char *OsCompileOptions[];
581c2aa98e2SPeter Wemm 
58240266059SGregory Neil Shapiro 		sm_dprintf("    OS Defines:");
58340266059SGregory Neil Shapiro 		sm_printoptions(OsCompileOptions);
584c2aa98e2SPeter Wemm #ifdef _PATH_UNIX
58540266059SGregory Neil Shapiro 		sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
58606f25ae9SGregory Neil Shapiro #endif /* _PATH_UNIX */
58740266059SGregory Neil Shapiro 
58840266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (default for MSP)\n",
58940266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
59040266059SGregory Neil Shapiro 				     conffile));
59140266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (default for MTA)\n",
59240266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,
59340266059SGregory Neil Shapiro 				     conffile));
59440266059SGregory Neil Shapiro 		sm_dprintf("      Pid file:\t%s (default)\n", PidFile);
595c2aa98e2SPeter Wemm 	}
596c2aa98e2SPeter Wemm 
59740266059SGregory Neil Shapiro 	if (tTd(0, 12))
59840266059SGregory Neil Shapiro 	{
59940266059SGregory Neil Shapiro 		extern char *SmCompileOptions[];
60040266059SGregory Neil Shapiro 
60140266059SGregory Neil Shapiro 		sm_dprintf(" libsm Defines:");
60240266059SGregory Neil Shapiro 		sm_printoptions(SmCompileOptions);
60340266059SGregory Neil Shapiro 	}
60440266059SGregory Neil Shapiro 
60540266059SGregory Neil Shapiro 	if (tTd(0, 13))
60640266059SGregory Neil Shapiro 	{
60740266059SGregory Neil Shapiro 		extern char *FFRCompileOptions[];
60840266059SGregory Neil Shapiro 
60940266059SGregory Neil Shapiro 		sm_dprintf("   FFR Defines:");
61040266059SGregory Neil Shapiro 		sm_printoptions(FFRCompileOptions);
61140266059SGregory Neil Shapiro 	}
61240266059SGregory Neil Shapiro 
61340266059SGregory Neil Shapiro 	InChannel = smioin;
61440266059SGregory Neil Shapiro 	OutChannel = smioout;
615c2aa98e2SPeter Wemm 
616c2aa98e2SPeter Wemm 	/* clear sendmail's environment */
617c2aa98e2SPeter Wemm 	ExternalEnviron = environ;
618c2aa98e2SPeter Wemm 	emptyenviron[0] = NULL;
619c2aa98e2SPeter Wemm 	environ = emptyenviron;
620c2aa98e2SPeter Wemm 
621c2aa98e2SPeter Wemm 	/*
622c2aa98e2SPeter Wemm 	**  restore any original TZ setting until TimeZoneSpec has been
623c2aa98e2SPeter Wemm 	**  determined - or early log messages may get bogus time stamps
624c2aa98e2SPeter Wemm 	*/
62540266059SGregory Neil Shapiro 
626c2aa98e2SPeter Wemm 	if ((p = getextenv("TZ")) != NULL)
627c2aa98e2SPeter Wemm 	{
628c2aa98e2SPeter Wemm 		char *tz;
629c2aa98e2SPeter Wemm 		int tzlen;
630c2aa98e2SPeter Wemm 
63140266059SGregory Neil Shapiro 		/* XXX check for reasonable length? */
632c2aa98e2SPeter Wemm 		tzlen = strlen(p) + 4;
633c2aa98e2SPeter Wemm 		tz = xalloc(tzlen);
63440266059SGregory Neil Shapiro 		(void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);
63540266059SGregory Neil Shapiro 
63640266059SGregory Neil Shapiro 		/* XXX check return code? */
63706f25ae9SGregory Neil Shapiro 		(void) putenv(tz);
638c2aa98e2SPeter Wemm 	}
639c2aa98e2SPeter Wemm 
640c2aa98e2SPeter Wemm 	/* prime the child environment */
641c2aa98e2SPeter Wemm 	setuserenv("AGENT", "sendmail");
6428774250cSGregory Neil Shapiro 
64340266059SGregory Neil Shapiro 	(void) sm_signal(SIGPIPE, SIG_IGN);
644c2aa98e2SPeter Wemm 	OldUmask = umask(022);
645c2aa98e2SPeter Wemm 	FullName = getextenv("NAME");
646c2aa98e2SPeter Wemm 
647c2aa98e2SPeter Wemm 	/*
648c2aa98e2SPeter Wemm 	**  Initialize name server if it is going to be used.
649c2aa98e2SPeter Wemm 	*/
650c2aa98e2SPeter Wemm 
651c2aa98e2SPeter Wemm #if NAMED_BIND
652c2aa98e2SPeter Wemm 	if (!bitset(RES_INIT, _res.options))
65306f25ae9SGregory Neil Shapiro 		(void) res_init();
654c2aa98e2SPeter Wemm 	if (tTd(8, 8))
655c2aa98e2SPeter Wemm 		_res.options |= RES_DEBUG;
656c2aa98e2SPeter Wemm 	else
657c2aa98e2SPeter Wemm 		_res.options &= ~RES_DEBUG;
658c2aa98e2SPeter Wemm # ifdef RES_NOALIASES
65940266059SGregory Neil Shapiro 	if (bitset(RES_NOALIASES, _res.options))
66040266059SGregory Neil Shapiro 		ResNoAliases = true;
661c2aa98e2SPeter Wemm 	_res.options |= RES_NOALIASES;
66206f25ae9SGregory Neil Shapiro # endif /* RES_NOALIASES */
66306f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
66406f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
66506f25ae9SGregory Neil Shapiro 	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
66606f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
66706f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
66806f25ae9SGregory Neil Shapiro 	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
66906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
670c2aa98e2SPeter Wemm 
671c2aa98e2SPeter Wemm 	errno = 0;
672c2aa98e2SPeter Wemm 	from = NULL;
673c2aa98e2SPeter Wemm 
674c2aa98e2SPeter Wemm 	/* initialize some macros, etc. */
67540266059SGregory Neil Shapiro 	init_vendor_macros(&BlankEnvelope);
676c2aa98e2SPeter Wemm 
677c2aa98e2SPeter Wemm 	/* version */
67840266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);
679c2aa98e2SPeter Wemm 
680c2aa98e2SPeter Wemm 	/* hostname */
681c2aa98e2SPeter Wemm 	hp = myhostname(jbuf, sizeof jbuf);
682c2aa98e2SPeter Wemm 	if (jbuf[0] != '\0')
683c2aa98e2SPeter Wemm 	{
684c2aa98e2SPeter Wemm 		struct utsname utsname;
685c2aa98e2SPeter Wemm 
686c2aa98e2SPeter Wemm 		if (tTd(0, 4))
68740266059SGregory Neil Shapiro 			sm_dprintf("Canonical name: %s\n", jbuf);
68840266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);
68940266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);
690c2aa98e2SPeter Wemm 		setclass('w', jbuf);
691c2aa98e2SPeter Wemm 
692c2aa98e2SPeter Wemm 		p = strchr(jbuf, '.');
693c2aa98e2SPeter Wemm 		if (p != NULL)
694c2aa98e2SPeter Wemm 		{
695c2aa98e2SPeter Wemm 			if (p[1] != '\0')
696c2aa98e2SPeter Wemm 			{
69740266059SGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm',
69840266059SGregory Neil Shapiro 					  &p[1]);
699c2aa98e2SPeter Wemm 			}
700c2aa98e2SPeter Wemm 			while (p != NULL && strchr(&p[1], '.') != NULL)
701c2aa98e2SPeter Wemm 			{
702c2aa98e2SPeter Wemm 				*p = '\0';
703c2aa98e2SPeter Wemm 				if (tTd(0, 4))
70440266059SGregory Neil Shapiro 					sm_dprintf("\ta.k.a.: %s\n", jbuf);
705c2aa98e2SPeter Wemm 				setclass('w', jbuf);
706c2aa98e2SPeter Wemm 				*p++ = '.';
707c2aa98e2SPeter Wemm 				p = strchr(p, '.');
708c2aa98e2SPeter Wemm 			}
709c2aa98e2SPeter Wemm 		}
710c2aa98e2SPeter Wemm 
711c2aa98e2SPeter Wemm 		if (uname(&utsname) >= 0)
712c2aa98e2SPeter Wemm 			p = utsname.nodename;
713c2aa98e2SPeter Wemm 		else
714c2aa98e2SPeter Wemm 		{
715c2aa98e2SPeter Wemm 			if (tTd(0, 22))
71640266059SGregory Neil Shapiro 				sm_dprintf("uname failed (%s)\n",
71740266059SGregory Neil Shapiro 					   sm_errstring(errno));
718c2aa98e2SPeter Wemm 			makelower(jbuf);
719c2aa98e2SPeter Wemm 			p = jbuf;
720c2aa98e2SPeter Wemm 		}
721c2aa98e2SPeter Wemm 		if (tTd(0, 4))
72240266059SGregory Neil Shapiro 			sm_dprintf(" UUCP nodename: %s\n", p);
72340266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);
724c2aa98e2SPeter Wemm 		setclass('k', p);
725c2aa98e2SPeter Wemm 		setclass('w', p);
726c2aa98e2SPeter Wemm 	}
727c2aa98e2SPeter Wemm 	if (hp != NULL)
728c2aa98e2SPeter Wemm 	{
729c2aa98e2SPeter Wemm 		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
730c2aa98e2SPeter Wemm 		{
731c2aa98e2SPeter Wemm 			if (tTd(0, 4))
73240266059SGregory Neil Shapiro 				sm_dprintf("\ta.k.a.: %s\n", *av);
733c2aa98e2SPeter Wemm 			setclass('w', *av);
734c2aa98e2SPeter Wemm 		}
73506f25ae9SGregory Neil Shapiro #if NETINET || NETINET6
73640266059SGregory Neil Shapiro 		for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)
737c2aa98e2SPeter Wemm 		{
73806f25ae9SGregory Neil Shapiro # if NETINET6
73906f25ae9SGregory Neil Shapiro 			char *addr;
74006f25ae9SGregory Neil Shapiro 			char buf6[INET6_ADDRSTRLEN];
74106f25ae9SGregory Neil Shapiro 			struct in6_addr ia6;
74206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
74306f25ae9SGregory Neil Shapiro # if NETINET
74406f25ae9SGregory Neil Shapiro 			struct in_addr ia;
74506f25ae9SGregory Neil Shapiro # endif /* NETINET */
746c2aa98e2SPeter Wemm 			char ipbuf[103];
747c2aa98e2SPeter Wemm 
74806f25ae9SGregory Neil Shapiro 			ipbuf[0] = '\0';
74906f25ae9SGregory Neil Shapiro 			switch (hp->h_addrtype)
75006f25ae9SGregory Neil Shapiro 			{
75106f25ae9SGregory Neil Shapiro # if NETINET
75206f25ae9SGregory Neil Shapiro 			  case AF_INET:
75306f25ae9SGregory Neil Shapiro 				if (hp->h_length != INADDRSZ)
75406f25ae9SGregory Neil Shapiro 					break;
75506f25ae9SGregory Neil Shapiro 
75606f25ae9SGregory Neil Shapiro 				memmove(&ia, hp->h_addr_list[i], INADDRSZ);
75740266059SGregory Neil Shapiro 				(void) sm_snprintf(ipbuf, sizeof ipbuf,
75806f25ae9SGregory Neil Shapiro 						   "[%.100s]", inet_ntoa(ia));
75906f25ae9SGregory Neil Shapiro 				break;
76006f25ae9SGregory Neil Shapiro # endif /* NETINET */
76106f25ae9SGregory Neil Shapiro 
76206f25ae9SGregory Neil Shapiro # if NETINET6
76306f25ae9SGregory Neil Shapiro 			  case AF_INET6:
76406f25ae9SGregory Neil Shapiro 				if (hp->h_length != IN6ADDRSZ)
76506f25ae9SGregory Neil Shapiro 					break;
76606f25ae9SGregory Neil Shapiro 
76706f25ae9SGregory Neil Shapiro 				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
76806f25ae9SGregory Neil Shapiro 				addr = anynet_ntop(&ia6, buf6, sizeof buf6);
76906f25ae9SGregory Neil Shapiro 				if (addr != NULL)
77040266059SGregory Neil Shapiro 					(void) sm_snprintf(ipbuf, sizeof ipbuf,
77106f25ae9SGregory Neil Shapiro 							   "[%.100s]", addr);
77206f25ae9SGregory Neil Shapiro 				break;
77306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
77406f25ae9SGregory Neil Shapiro 			}
77506f25ae9SGregory Neil Shapiro 			if (ipbuf[0] == '\0')
77606f25ae9SGregory Neil Shapiro 				break;
77706f25ae9SGregory Neil Shapiro 
778c2aa98e2SPeter Wemm 			if (tTd(0, 4))
77940266059SGregory Neil Shapiro 				sm_dprintf("\ta.k.a.: %s\n", ipbuf);
780c2aa98e2SPeter Wemm 			setclass('w', ipbuf);
781c2aa98e2SPeter Wemm 		}
78206f25ae9SGregory Neil Shapiro #endif /* NETINET || NETINET6 */
78340266059SGregory Neil Shapiro #if NETINET6
784193538b7SGregory Neil Shapiro 		freehostent(hp);
785193538b7SGregory Neil Shapiro 		hp = NULL;
78640266059SGregory Neil Shapiro #endif /* NETINET6 */
787c2aa98e2SPeter Wemm 	}
788c2aa98e2SPeter Wemm 
789c2aa98e2SPeter Wemm 	/* current time */
79040266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));
79140266059SGregory Neil Shapiro 
79206f25ae9SGregory Neil Shapiro 	/* current load average */
79340266059SGregory Neil Shapiro 	sm_getla();
794c2aa98e2SPeter Wemm 
795c2aa98e2SPeter Wemm 	QueueLimitRecipient = (QUEUE_CHAR *) NULL;
796c2aa98e2SPeter Wemm 	QueueLimitSender = (QUEUE_CHAR *) NULL;
797c2aa98e2SPeter Wemm 	QueueLimitId = (QUEUE_CHAR *) NULL;
79840266059SGregory Neil Shapiro #if _FFR_QUARANTINE
79940266059SGregory Neil Shapiro 	QueueLimitQuarantine = (QUEUE_CHAR *) NULL;
80040266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
801c2aa98e2SPeter Wemm 
802c2aa98e2SPeter Wemm 	/*
803c2aa98e2SPeter Wemm 	**  Crack argv.
804c2aa98e2SPeter Wemm 	*/
805c2aa98e2SPeter Wemm 
806c2aa98e2SPeter Wemm 	optind = 1;
807c2aa98e2SPeter Wemm 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
808c2aa98e2SPeter Wemm 	{
809c2aa98e2SPeter Wemm 		switch (j)
810c2aa98e2SPeter Wemm 		{
811c2aa98e2SPeter Wemm 		  case 'b':	/* operations mode */
81240266059SGregory Neil Shapiro 			/* already done */
813c2aa98e2SPeter Wemm 			break;
814c2aa98e2SPeter Wemm 
81540266059SGregory Neil Shapiro 		  case 'A':	/* use Alternate sendmail/submit.cf */
81640266059SGregory Neil Shapiro 			cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF
81740266059SGregory Neil Shapiro 						  : SM_GET_SENDMAIL_CF;
818c2aa98e2SPeter Wemm 			break;
819c2aa98e2SPeter Wemm 
820c2aa98e2SPeter Wemm 		  case 'B':	/* body type */
82140266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
82240266059SGregory Neil Shapiro 			BlankEnvelope.e_bodytype = newstr(optarg);
823c2aa98e2SPeter Wemm 			break;
824c2aa98e2SPeter Wemm 
825c2aa98e2SPeter Wemm 		  case 'C':	/* select configuration file (already done) */
826c2aa98e2SPeter Wemm 			if (RealUid != 0)
82740266059SGregory Neil Shapiro 				warn_C_flag = true;
82840266059SGregory Neil Shapiro 			conffile = newstr(optarg);
82940266059SGregory Neil Shapiro 			dp = drop_privileges(true);
83006f25ae9SGregory Neil Shapiro 			setstat(dp);
83140266059SGregory Neil Shapiro 			safecf = false;
832c2aa98e2SPeter Wemm 			break;
833c2aa98e2SPeter Wemm 
83440266059SGregory Neil Shapiro 		  case 'd':	/* debugging */
83540266059SGregory Neil Shapiro 			/* already done */
836c2aa98e2SPeter Wemm 			break;
837c2aa98e2SPeter Wemm 
838c2aa98e2SPeter Wemm 		  case 'f':	/* from address */
839c2aa98e2SPeter Wemm 		  case 'r':	/* obsolete -f flag */
84040266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
841c2aa98e2SPeter Wemm 			if (from != NULL)
842c2aa98e2SPeter Wemm 			{
843c2aa98e2SPeter Wemm 				usrerr("More than one \"from\" person");
844c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
845c2aa98e2SPeter Wemm 				break;
846c2aa98e2SPeter Wemm 			}
84740266059SGregory Neil Shapiro 			from = newstr(denlstring(optarg, true, true));
848c2aa98e2SPeter Wemm 			if (strcmp(RealUserName, from) != 0)
849c2aa98e2SPeter Wemm 				warn_f_flag = j;
850c2aa98e2SPeter Wemm 			break;
851c2aa98e2SPeter Wemm 
852c2aa98e2SPeter Wemm 		  case 'F':	/* set full name */
85340266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
854c2aa98e2SPeter Wemm 			FullName = newstr(optarg);
855c2aa98e2SPeter Wemm 			break;
856c2aa98e2SPeter Wemm 
85706f25ae9SGregory Neil Shapiro 		  case 'G':	/* relay (gateway) submission */
85806f25ae9SGregory Neil Shapiro 			/* already set */
85940266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
86006f25ae9SGregory Neil Shapiro 			break;
86106f25ae9SGregory Neil Shapiro 
862c2aa98e2SPeter Wemm 		  case 'h':	/* hop count */
86340266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
86440266059SGregory Neil Shapiro 			BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,
86540266059SGregory Neil Shapiro 								  10);
86640266059SGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof buf, "%d",
86740266059SGregory Neil Shapiro 					   BlankEnvelope.e_hopcount);
86840266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);
86940266059SGregory Neil Shapiro 
870c2aa98e2SPeter Wemm 			if (*ep)
871c2aa98e2SPeter Wemm 			{
872c2aa98e2SPeter Wemm 				usrerr("Bad hop count (%s)", optarg);
873c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
874c2aa98e2SPeter Wemm 			}
875c2aa98e2SPeter Wemm 			break;
876c2aa98e2SPeter Wemm 
87706f25ae9SGregory Neil Shapiro 		  case 'L':	/* program label */
87806f25ae9SGregory Neil Shapiro 			/* already set */
87906f25ae9SGregory Neil Shapiro 			break;
88006f25ae9SGregory Neil Shapiro 
881c2aa98e2SPeter Wemm 		  case 'n':	/* don't alias */
88240266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
88340266059SGregory Neil Shapiro 			NoAlias = true;
884c2aa98e2SPeter Wemm 			break;
885c2aa98e2SPeter Wemm 
886c2aa98e2SPeter Wemm 		  case 'N':	/* delivery status notifications */
88740266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
888c2aa98e2SPeter Wemm 			DefaultNotify |= QHASNOTIFY;
88940266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
89040266059SGregory Neil Shapiro 				macid("{dsn_notify}"), optarg);
89140266059SGregory Neil Shapiro 			if (sm_strcasecmp(optarg, "never") == 0)
892c2aa98e2SPeter Wemm 				break;
893c2aa98e2SPeter Wemm 			for (p = optarg; p != NULL; optarg = p)
894c2aa98e2SPeter Wemm 			{
895c2aa98e2SPeter Wemm 				p = strchr(p, ',');
896c2aa98e2SPeter Wemm 				if (p != NULL)
897c2aa98e2SPeter Wemm 					*p++ = '\0';
89840266059SGregory Neil Shapiro 				if (sm_strcasecmp(optarg, "success") == 0)
899c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONSUCCESS;
90040266059SGregory Neil Shapiro 				else if (sm_strcasecmp(optarg, "failure") == 0)
901c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONFAILURE;
90240266059SGregory Neil Shapiro 				else if (sm_strcasecmp(optarg, "delay") == 0)
903c2aa98e2SPeter Wemm 					DefaultNotify |= QPINGONDELAY;
904c2aa98e2SPeter Wemm 				else
905c2aa98e2SPeter Wemm 				{
906c2aa98e2SPeter Wemm 					usrerr("Invalid -N argument");
907c2aa98e2SPeter Wemm 					ExitStat = EX_USAGE;
908c2aa98e2SPeter Wemm 				}
909c2aa98e2SPeter Wemm 			}
910c2aa98e2SPeter Wemm 			break;
911c2aa98e2SPeter Wemm 
912c2aa98e2SPeter Wemm 		  case 'o':	/* set option */
91340266059SGregory Neil Shapiro 			setoption(*optarg, optarg + 1, false, true,
91440266059SGregory Neil Shapiro 				  &BlankEnvelope);
915c2aa98e2SPeter Wemm 			break;
916c2aa98e2SPeter Wemm 
917c2aa98e2SPeter Wemm 		  case 'O':	/* set option (long form) */
91840266059SGregory Neil Shapiro 			setoption(' ', optarg, false, true, &BlankEnvelope);
919c2aa98e2SPeter Wemm 			break;
920c2aa98e2SPeter Wemm 
921c2aa98e2SPeter Wemm 		  case 'p':	/* set protocol */
92240266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
923c2aa98e2SPeter Wemm 			p = strchr(optarg, ':');
924c2aa98e2SPeter Wemm 			if (p != NULL)
925c2aa98e2SPeter Wemm 			{
926c2aa98e2SPeter Wemm 				*p++ = '\0';
927c2aa98e2SPeter Wemm 				if (*p != '\0')
928c2aa98e2SPeter Wemm 				{
92940266059SGregory Neil Shapiro 					ep = sm_malloc_x(strlen(p) + 1);
930c2aa98e2SPeter Wemm 					cleanstrcpy(ep, p, MAXNAME);
93140266059SGregory Neil Shapiro 					macdefine(&BlankEnvelope.e_macro,
93240266059SGregory Neil Shapiro 						  A_HEAP, 's', ep);
933c2aa98e2SPeter Wemm 				}
934c2aa98e2SPeter Wemm 			}
935c2aa98e2SPeter Wemm 			if (*optarg != '\0')
936c2aa98e2SPeter Wemm 			{
93740266059SGregory Neil Shapiro 				ep = sm_malloc_x(strlen(optarg) + 1);
938c2aa98e2SPeter Wemm 				cleanstrcpy(ep, optarg, MAXNAME);
93940266059SGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_HEAP,
94040266059SGregory Neil Shapiro 					  'r', ep);
941c2aa98e2SPeter Wemm 			}
942c2aa98e2SPeter Wemm 			break;
943c2aa98e2SPeter Wemm 
94440266059SGregory Neil Shapiro #if _FFR_QUARANTINE
94540266059SGregory Neil Shapiro 		  case 'Q':	/* change quarantining on queued items */
94640266059SGregory Neil Shapiro 			/* sanity check */
94740266059SGregory Neil Shapiro 			if (OpMode != MD_DELIVER &&
94840266059SGregory Neil Shapiro 			    OpMode != MD_QUEUERUN)
94940266059SGregory Neil Shapiro 			{
95040266059SGregory Neil Shapiro 				usrerr("Can not use -Q with -b%c", OpMode);
95140266059SGregory Neil Shapiro 				ExitStat = EX_USAGE;
95240266059SGregory Neil Shapiro 				break;
95340266059SGregory Neil Shapiro 			}
95440266059SGregory Neil Shapiro 
95540266059SGregory Neil Shapiro 			if (OpMode == MD_DELIVER)
95640266059SGregory Neil Shapiro 				set_op_mode(MD_QUEUERUN);
95740266059SGregory Neil Shapiro 
95840266059SGregory Neil Shapiro 			FullName = NULL;
95940266059SGregory Neil Shapiro 
96040266059SGregory Neil Shapiro 			quarantining = newstr(optarg);
96140266059SGregory Neil Shapiro 			break;
96240266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
96340266059SGregory Neil Shapiro 
964c2aa98e2SPeter Wemm 		  case 'q':	/* run queue files at intervals */
96506f25ae9SGregory Neil Shapiro 			/* sanity check */
96606f25ae9SGregory Neil Shapiro 			if (OpMode != MD_DELIVER &&
96706f25ae9SGregory Neil Shapiro 			    OpMode != MD_DAEMON &&
96806f25ae9SGregory Neil Shapiro 			    OpMode != MD_FGDAEMON &&
96906f25ae9SGregory Neil Shapiro 			    OpMode != MD_PRINT &&
97040266059SGregory Neil Shapiro 			    OpMode != MD_PRINTNQE &&
97106f25ae9SGregory Neil Shapiro 			    OpMode != MD_QUEUERUN)
97206f25ae9SGregory Neil Shapiro 			{
97306f25ae9SGregory Neil Shapiro 				usrerr("Can not use -q with -b%c", OpMode);
97406f25ae9SGregory Neil Shapiro 				ExitStat = EX_USAGE;
97506f25ae9SGregory Neil Shapiro 				break;
97606f25ae9SGregory Neil Shapiro 			}
97706f25ae9SGregory Neil Shapiro 
97806f25ae9SGregory Neil Shapiro 			/* don't override -bd, -bD or -bp */
97906f25ae9SGregory Neil Shapiro 			if (OpMode == MD_DELIVER)
98040266059SGregory Neil Shapiro 				set_op_mode(MD_QUEUERUN);
98106f25ae9SGregory Neil Shapiro 
982c2aa98e2SPeter Wemm 			FullName = NULL;
98340266059SGregory Neil Shapiro 			negate = optarg[0] == '!';
98440266059SGregory Neil Shapiro 			if (negate)
98540266059SGregory Neil Shapiro 			{
98640266059SGregory Neil Shapiro 				/* negate meaning of pattern match */
98740266059SGregory Neil Shapiro 				optarg++; /* skip '!' for next switch */
98840266059SGregory Neil Shapiro 			}
98906f25ae9SGregory Neil Shapiro 
990c2aa98e2SPeter Wemm 			switch (optarg[0])
991c2aa98e2SPeter Wemm 			{
99240266059SGregory Neil Shapiro 			  case 'G': /* Limit by queue group name */
99340266059SGregory Neil Shapiro 				if (negate)
99440266059SGregory Neil Shapiro 				{
99540266059SGregory Neil Shapiro 					usrerr("Can not use -q!G");
99640266059SGregory Neil Shapiro 					ExitStat = EX_USAGE;
99740266059SGregory Neil Shapiro 					break;
99840266059SGregory Neil Shapiro 				}
99940266059SGregory Neil Shapiro 				if (queuegroup != NULL)
100040266059SGregory Neil Shapiro 				{
100140266059SGregory Neil Shapiro 					usrerr("Can not use multiple -qG options");
100240266059SGregory Neil Shapiro 					ExitStat = EX_USAGE;
100340266059SGregory Neil Shapiro 					break;
100440266059SGregory Neil Shapiro 				}
100540266059SGregory Neil Shapiro 				queuegroup = newstr(&optarg[1]);
100640266059SGregory Neil Shapiro 				break;
100740266059SGregory Neil Shapiro 
100840266059SGregory Neil Shapiro 			  case 'I': /* Limit by ID */
100906f25ae9SGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
1010c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
101140266059SGregory Neil Shapiro 				new->queue_negate = negate;
1012c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitId;
1013c2aa98e2SPeter Wemm 				QueueLimitId = new;
1014c2aa98e2SPeter Wemm 				break;
1015c2aa98e2SPeter Wemm 
101640266059SGregory Neil Shapiro 			  case 'R': /* Limit by recipient */
101706f25ae9SGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
1018c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
101940266059SGregory Neil Shapiro 				new->queue_negate = negate;
1020c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitRecipient;
1021c2aa98e2SPeter Wemm 				QueueLimitRecipient = new;
1022c2aa98e2SPeter Wemm 				break;
1023c2aa98e2SPeter Wemm 
102440266059SGregory Neil Shapiro 			  case 'S': /* Limit by sender */
102506f25ae9SGregory Neil Shapiro 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
1026c2aa98e2SPeter Wemm 				new->queue_match = newstr(&optarg[1]);
102740266059SGregory Neil Shapiro 				new->queue_negate = negate;
1028c2aa98e2SPeter Wemm 				new->queue_next = QueueLimitSender;
1029c2aa98e2SPeter Wemm 				QueueLimitSender = new;
1030c2aa98e2SPeter Wemm 				break;
1031c2aa98e2SPeter Wemm 
103240266059SGregory Neil Shapiro 			  case 'f': /* foreground queue run */
103340266059SGregory Neil Shapiro 				foregroundqueue  = true;
103440266059SGregory Neil Shapiro 				break;
103540266059SGregory Neil Shapiro 
103640266059SGregory Neil Shapiro #if _FFR_QUARANTINE
103740266059SGregory Neil Shapiro 			  case 'Q': /* Limit by quarantine message */
103840266059SGregory Neil Shapiro 				if (optarg[1] != '\0')
103940266059SGregory Neil Shapiro 				{
104040266059SGregory Neil Shapiro 					new = (QUEUE_CHAR *) xalloc(sizeof *new);
104140266059SGregory Neil Shapiro 					new->queue_match = newstr(&optarg[1]);
104240266059SGregory Neil Shapiro 					new->queue_negate = negate;
104340266059SGregory Neil Shapiro 					new->queue_next = QueueLimitQuarantine;
104440266059SGregory Neil Shapiro 					QueueLimitQuarantine = new;
104540266059SGregory Neil Shapiro 				}
104640266059SGregory Neil Shapiro 				QueueMode = QM_QUARANTINE;
104740266059SGregory Neil Shapiro 				break;
104840266059SGregory Neil Shapiro 
104940266059SGregory Neil Shapiro 			  case 'L': /* act on lost items */
105040266059SGregory Neil Shapiro 				QueueMode = QM_LOST;
105140266059SGregory Neil Shapiro 				break;
105240266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
105340266059SGregory Neil Shapiro 
105440266059SGregory Neil Shapiro 			  case 'p': /* Persistent queue */
105540266059SGregory Neil Shapiro 				queuepersistent = true;
105640266059SGregory Neil Shapiro 				if (QueueIntvl == 0)
105740266059SGregory Neil Shapiro 					QueueIntvl = 1;
105840266059SGregory Neil Shapiro 				if (optarg[1] == '\0')
105940266059SGregory Neil Shapiro 					break;
106040266059SGregory Neil Shapiro 				++optarg;
106140266059SGregory Neil Shapiro 				/* FALLTHROUGH */
106240266059SGregory Neil Shapiro 
1063c2aa98e2SPeter Wemm 			  default:
106406f25ae9SGregory Neil Shapiro 				i = Errors;
1065c2aa98e2SPeter Wemm 				QueueIntvl = convtime(optarg, 'm');
106606f25ae9SGregory Neil Shapiro 
106706f25ae9SGregory Neil Shapiro 				/* check for bad conversion */
106806f25ae9SGregory Neil Shapiro 				if (i < Errors)
106906f25ae9SGregory Neil Shapiro 					ExitStat = EX_USAGE;
1070c2aa98e2SPeter Wemm 				break;
1071c2aa98e2SPeter Wemm 			}
1072c2aa98e2SPeter Wemm 			break;
1073c2aa98e2SPeter Wemm 
1074c2aa98e2SPeter Wemm 		  case 'R':	/* DSN RET: what to return */
107540266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
107640266059SGregory Neil Shapiro 			if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))
1077c2aa98e2SPeter Wemm 			{
1078c2aa98e2SPeter Wemm 				usrerr("Duplicate -R flag");
1079c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1080c2aa98e2SPeter Wemm 				break;
1081c2aa98e2SPeter Wemm 			}
108240266059SGregory Neil Shapiro 			BlankEnvelope.e_flags |= EF_RET_PARAM;
108340266059SGregory Neil Shapiro 			if (sm_strcasecmp(optarg, "hdrs") == 0)
108440266059SGregory Neil Shapiro 				BlankEnvelope.e_flags |= EF_NO_BODY_RETN;
108540266059SGregory Neil Shapiro 			else if (sm_strcasecmp(optarg, "full") != 0)
1086c2aa98e2SPeter Wemm 			{
1087c2aa98e2SPeter Wemm 				usrerr("Invalid -R value");
1088c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1089c2aa98e2SPeter Wemm 			}
109040266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
109140266059SGregory Neil Shapiro 				  macid("{dsn_ret}"), optarg);
1092c2aa98e2SPeter Wemm 			break;
1093c2aa98e2SPeter Wemm 
1094c2aa98e2SPeter Wemm 		  case 't':	/* read recipients from message */
109540266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
109640266059SGregory Neil Shapiro 			GrabTo = true;
1097c2aa98e2SPeter Wemm 			break;
1098c2aa98e2SPeter Wemm 
1099c2aa98e2SPeter Wemm 		  case 'V':	/* DSN ENVID: set "original" envelope id */
110040266059SGregory Neil Shapiro 			CHECK_AGAINST_OPMODE(j);
1101c2aa98e2SPeter Wemm 			if (!xtextok(optarg))
1102c2aa98e2SPeter Wemm 			{
1103c2aa98e2SPeter Wemm 				usrerr("Invalid syntax in -V flag");
1104c2aa98e2SPeter Wemm 				ExitStat = EX_USAGE;
1105c2aa98e2SPeter Wemm 			}
1106c2aa98e2SPeter Wemm 			else
110706f25ae9SGregory Neil Shapiro 			{
110840266059SGregory Neil Shapiro 				BlankEnvelope.e_envid = newstr(optarg);
110940266059SGregory Neil Shapiro 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
111040266059SGregory Neil Shapiro 					  macid("{dsn_envid}"), optarg);
111106f25ae9SGregory Neil Shapiro 			}
1112c2aa98e2SPeter Wemm 			break;
1113c2aa98e2SPeter Wemm 
1114c2aa98e2SPeter Wemm 		  case 'X':	/* traffic log file */
111540266059SGregory Neil Shapiro 			dp = drop_privileges(true);
111606f25ae9SGregory Neil Shapiro 			setstat(dp);
111706f25ae9SGregory Neil Shapiro 			if (stat(optarg, &traf_st) == 0 &&
111806f25ae9SGregory Neil Shapiro 			    S_ISFIFO(traf_st.st_mode))
111940266059SGregory Neil Shapiro 				TrafficLogFile = sm_io_open(SmFtStdio,
112040266059SGregory Neil Shapiro 							    SM_TIME_DEFAULT,
112140266059SGregory Neil Shapiro 							    optarg,
112240266059SGregory Neil Shapiro 							    SM_IO_WRONLY, NULL);
112306f25ae9SGregory Neil Shapiro 			else
112440266059SGregory Neil Shapiro 				TrafficLogFile = sm_io_open(SmFtStdio,
112540266059SGregory Neil Shapiro 							    SM_TIME_DEFAULT,
112640266059SGregory Neil Shapiro 							    optarg,
112740266059SGregory Neil Shapiro 							    SM_IO_APPEND, NULL);
1128c2aa98e2SPeter Wemm 			if (TrafficLogFile == NULL)
1129c2aa98e2SPeter Wemm 			{
1130c2aa98e2SPeter Wemm 				syserr("cannot open %s", optarg);
1131c2aa98e2SPeter Wemm 				ExitStat = EX_CANTCREAT;
1132c2aa98e2SPeter Wemm 				break;
1133c2aa98e2SPeter Wemm 			}
113440266059SGregory Neil Shapiro 			(void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,
113540266059SGregory Neil Shapiro 					     NULL, SM_IO_LBF, 0);
1136c2aa98e2SPeter Wemm 			break;
1137c2aa98e2SPeter Wemm 
1138c2aa98e2SPeter Wemm 			/* compatibility flags */
1139c2aa98e2SPeter Wemm 		  case 'c':	/* connect to non-local mailers */
1140c2aa98e2SPeter Wemm 		  case 'i':	/* don't let dot stop me */
1141c2aa98e2SPeter Wemm 		  case 'm':	/* send to me too */
1142c2aa98e2SPeter Wemm 		  case 'T':	/* set timeout interval */
1143c2aa98e2SPeter Wemm 		  case 'v':	/* give blow-by-blow description */
114440266059SGregory Neil Shapiro 			setoption(j, "T", false, true, &BlankEnvelope);
1145c2aa98e2SPeter Wemm 			break;
1146c2aa98e2SPeter Wemm 
1147c2aa98e2SPeter Wemm 		  case 'e':	/* error message disposition */
1148c2aa98e2SPeter Wemm 		  case 'M':	/* define macro */
114940266059SGregory Neil Shapiro 			setoption(j, optarg, false, true, &BlankEnvelope);
1150c2aa98e2SPeter Wemm 			break;
1151c2aa98e2SPeter Wemm 
1152c2aa98e2SPeter Wemm 		  case 's':	/* save From lines in headers */
115340266059SGregory Neil Shapiro 			setoption('f', "T", false, true, &BlankEnvelope);
1154c2aa98e2SPeter Wemm 			break;
1155c2aa98e2SPeter Wemm 
1156c2aa98e2SPeter Wemm #ifdef DBM
1157c2aa98e2SPeter Wemm 		  case 'I':	/* initialize alias DBM file */
115840266059SGregory Neil Shapiro 			set_op_mode(MD_INITALIAS);
1159c2aa98e2SPeter Wemm 			break;
1160c2aa98e2SPeter Wemm #endif /* DBM */
1161c2aa98e2SPeter Wemm 
1162c2aa98e2SPeter Wemm #if defined(__osf__) || defined(_AIX3)
1163c2aa98e2SPeter Wemm 		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */
1164c2aa98e2SPeter Wemm 			break;
116506f25ae9SGregory Neil Shapiro #endif /* defined(__osf__) || defined(_AIX3) */
1166c2aa98e2SPeter Wemm #if defined(sony_news)
1167c2aa98e2SPeter Wemm 		  case 'E':
1168c2aa98e2SPeter Wemm 		  case 'J':	/* ignore flags for Japanese code conversion
116906f25ae9SGregory Neil Shapiro 				   implemented on Sony NEWS */
1170c2aa98e2SPeter Wemm 			break;
117106f25ae9SGregory Neil Shapiro #endif /* defined(sony_news) */
1172c2aa98e2SPeter Wemm 
1173c2aa98e2SPeter Wemm 		  default:
117440266059SGregory Neil Shapiro 			finis(true, true, EX_USAGE);
117540266059SGregory Neil Shapiro 			/* NOTREACHED */
1176c2aa98e2SPeter Wemm 			break;
1177c2aa98e2SPeter Wemm 		}
1178c2aa98e2SPeter Wemm 	}
1179c2aa98e2SPeter Wemm 
118040266059SGregory Neil Shapiro 	/* if we've had errors so far, exit now */
118140266059SGregory Neil Shapiro 	if ((ExitStat != EX_OK && OpMode != MD_TEST) ||
118240266059SGregory Neil Shapiro 	    ExitStat == EX_OSERR)
118306f25ae9SGregory Neil Shapiro 	{
118440266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
118540266059SGregory Neil Shapiro 		/* NOTREACHED */
118606f25ae9SGregory Neil Shapiro 	}
118706f25ae9SGregory Neil Shapiro 
118840266059SGregory Neil Shapiro 	if (bitset(SUBMIT_MTA, SubmitMode))
118906f25ae9SGregory Neil Shapiro 	{
119040266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
119140266059SGregory Neil Shapiro 			  macid("{daemon_flags}"), "CC f");
119206f25ae9SGregory Neil Shapiro 	}
119340266059SGregory Neil Shapiro 	else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)
119406f25ae9SGregory Neil Shapiro 	{
119540266059SGregory Neil Shapiro 		SubmitMode = SUBMIT_MSA;
119640266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
119740266059SGregory Neil Shapiro 			  macid("{daemon_flags}"), "c u");
119806f25ae9SGregory Neil Shapiro 	}
119906f25ae9SGregory Neil Shapiro 
1200c2aa98e2SPeter Wemm 	/*
1201c2aa98e2SPeter Wemm 	**  Do basic initialization.
1202c2aa98e2SPeter Wemm 	**	Read system control file.
1203c2aa98e2SPeter Wemm 	**	Extract special fields for local use.
1204c2aa98e2SPeter Wemm 	*/
1205c2aa98e2SPeter Wemm 
1206c2aa98e2SPeter Wemm #if XDEBUG
1207c2aa98e2SPeter Wemm 	checkfd012("before readcf");
120806f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
120940266059SGregory Neil Shapiro 	vendor_pre_defaults(&BlankEnvelope);
121006f25ae9SGregory Neil Shapiro 
121140266059SGregory Neil Shapiro 	readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
121240266059SGregory Neil Shapiro 			 safecf, &BlankEnvelope);
121340266059SGregory Neil Shapiro #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
121440266059SGregory Neil Shapiro 	ConfigFileRead = true;
121540266059SGregory Neil Shapiro #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
121640266059SGregory Neil Shapiro 	vendor_post_defaults(&BlankEnvelope);
121740266059SGregory Neil Shapiro 
121840266059SGregory Neil Shapiro 	/* now we can complain about missing fds */
121940266059SGregory Neil Shapiro 	if (MissingFds != 0 && LogLevel > 8)
122040266059SGregory Neil Shapiro 	{
122140266059SGregory Neil Shapiro 		char mbuf[MAXLINE];
122240266059SGregory Neil Shapiro 
122340266059SGregory Neil Shapiro 		mbuf[0] = '\0';
122440266059SGregory Neil Shapiro 		if (bitset(1 << STDIN_FILENO, MissingFds))
122540266059SGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stdin", sizeof mbuf);
122640266059SGregory Neil Shapiro 		if (bitset(1 << STDOUT_FILENO, MissingFds))
122740266059SGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stdout", sizeof mbuf);
122840266059SGregory Neil Shapiro 		if (bitset(1 << STDERR_FILENO, MissingFds))
122940266059SGregory Neil Shapiro 			(void) sm_strlcat(mbuf, ", stderr", sizeof mbuf);
123040266059SGregory Neil Shapiro 
123140266059SGregory Neil Shapiro 		/* Notice: fill_errno is from high above: fill_fd() */
123240266059SGregory Neil Shapiro 		sm_syslog(LOG_WARNING, NOQID,
123340266059SGregory Neil Shapiro 			  "File descriptors missing on startup: %s; %s",
123440266059SGregory Neil Shapiro 			  &mbuf[2], sm_errstring(fill_errno));
123540266059SGregory Neil Shapiro 	}
1236c2aa98e2SPeter Wemm 
12378774250cSGregory Neil Shapiro 	/* Remove the ability for a normal user to send signals */
123840266059SGregory Neil Shapiro 	if (RealUid != 0 && RealUid != geteuid())
12398774250cSGregory Neil Shapiro 	{
12408774250cSGregory Neil Shapiro 		uid_t new_uid = geteuid();
12418774250cSGregory Neil Shapiro 
12428774250cSGregory Neil Shapiro #if HASSETREUID
12438774250cSGregory Neil Shapiro 		/*
12448774250cSGregory Neil Shapiro 		**  Since we can differentiate between uid and euid,
12458774250cSGregory Neil Shapiro 		**  make the uid a different user so the real user
12468774250cSGregory Neil Shapiro 		**  can't send signals.  However, it doesn't need to be
12478774250cSGregory Neil Shapiro 		**  root (euid has root).
12488774250cSGregory Neil Shapiro 		*/
12498774250cSGregory Neil Shapiro 
12508774250cSGregory Neil Shapiro 		if (new_uid == 0)
12518774250cSGregory Neil Shapiro 			new_uid = DefUid;
12528774250cSGregory Neil Shapiro 		if (tTd(47, 5))
125340266059SGregory Neil Shapiro 			sm_dprintf("Changing real uid to %d\n", (int) new_uid);
12548774250cSGregory Neil Shapiro 		if (setreuid(new_uid, geteuid()) < 0)
12558774250cSGregory Neil Shapiro 		{
12568774250cSGregory Neil Shapiro 			syserr("main: setreuid(%d, %d) failed",
12578774250cSGregory Neil Shapiro 			       (int) new_uid, (int) geteuid());
125840266059SGregory Neil Shapiro 			finis(false, true, EX_OSERR);
12598774250cSGregory Neil Shapiro 			/* NOTREACHED */
12608774250cSGregory Neil Shapiro 		}
12618774250cSGregory Neil Shapiro 		if (tTd(47, 10))
126240266059SGregory Neil Shapiro 			sm_dprintf("Now running as e/ruid %d:%d\n",
12638774250cSGregory Neil Shapiro 				   (int) geteuid(), (int) getuid());
12648774250cSGregory Neil Shapiro #else /* HASSETREUID */
12658774250cSGregory Neil Shapiro 		/*
12668774250cSGregory Neil Shapiro 		**  Have to change both effective and real so need to
12678774250cSGregory Neil Shapiro 		**  change them both to effective to keep privs.
12688774250cSGregory Neil Shapiro 		*/
12698774250cSGregory Neil Shapiro 
12708774250cSGregory Neil Shapiro 		if (tTd(47, 5))
127140266059SGregory Neil Shapiro 			sm_dprintf("Changing uid to %d\n", (int) new_uid);
12728774250cSGregory Neil Shapiro 		if (setuid(new_uid) < 0)
12738774250cSGregory Neil Shapiro 		{
12748774250cSGregory Neil Shapiro 			syserr("main: setuid(%d) failed", (int) new_uid);
127540266059SGregory Neil Shapiro 			finis(false, true, EX_OSERR);
12768774250cSGregory Neil Shapiro 			/* NOTREACHED */
12778774250cSGregory Neil Shapiro 		}
12788774250cSGregory Neil Shapiro 		if (tTd(47, 10))
127940266059SGregory Neil Shapiro 			sm_dprintf("Now running as e/ruid %d:%d\n",
12808774250cSGregory Neil Shapiro 				   (int) geteuid(), (int) getuid());
12818774250cSGregory Neil Shapiro #endif /* HASSETREUID */
12828774250cSGregory Neil Shapiro 	}
12838774250cSGregory Neil Shapiro 
128440266059SGregory Neil Shapiro #if NAMED_BIND
128540266059SGregory Neil Shapiro 	if (FallBackMX != NULL)
128640266059SGregory Neil Shapiro 		(void) getfallbackmxrr(FallBackMX);
128740266059SGregory Neil Shapiro #endif /* NAMED_BIND */
128840266059SGregory Neil Shapiro 
128940266059SGregory Neil Shapiro 	if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER)
129040266059SGregory Neil Shapiro 	{
129140266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
129240266059SGregory Neil Shapiro 				     "WARNING: SuperSafe=interactive should only be used with\n         DeliveryMode=interactive\n");
129340266059SGregory Neil Shapiro 	}
129440266059SGregory Neil Shapiro 
129540266059SGregory Neil Shapiro 	if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))
129640266059SGregory Neil Shapiro 	{
129740266059SGregory Neil Shapiro 		usrerr("Mail submission program cannot be used as daemon");
129840266059SGregory Neil Shapiro 		finis(false, true, EX_USAGE);
129940266059SGregory Neil Shapiro 	}
130040266059SGregory Neil Shapiro 
130140266059SGregory Neil Shapiro 	if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||
130240266059SGregory Neil Shapiro 	    OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||
130340266059SGregory Neil Shapiro 	    OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)
130440266059SGregory Neil Shapiro 		makeworkgroups();
130540266059SGregory Neil Shapiro 
13068774250cSGregory Neil Shapiro 	/* set up the basic signal handlers */
130740266059SGregory Neil Shapiro 	if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)
130840266059SGregory Neil Shapiro 		(void) sm_signal(SIGINT, intsig);
130940266059SGregory Neil Shapiro 	(void) sm_signal(SIGTERM, intsig);
13108774250cSGregory Neil Shapiro 
1311c2aa98e2SPeter Wemm 	/* Enforce use of local time (null string overrides this) */
1312c2aa98e2SPeter Wemm 	if (TimeZoneSpec == NULL)
1313c2aa98e2SPeter Wemm 		unsetenv("TZ");
1314c2aa98e2SPeter Wemm 	else if (TimeZoneSpec[0] != '\0')
1315c2aa98e2SPeter Wemm 		setuserenv("TZ", TimeZoneSpec);
1316c2aa98e2SPeter Wemm 	else
1317c2aa98e2SPeter Wemm 		setuserenv("TZ", NULL);
1318c2aa98e2SPeter Wemm 	tzset();
1319c2aa98e2SPeter Wemm 
132040266059SGregory Neil Shapiro 	/* initialize mailbox database */
132140266059SGregory Neil Shapiro 	i = sm_mbdb_initialize(Mbdb);
132240266059SGregory Neil Shapiro 	if (i != EX_OK)
132340266059SGregory Neil Shapiro 	{
132440266059SGregory Neil Shapiro 		usrerr("Can't initialize mailbox database \"%s\": %s",
132540266059SGregory Neil Shapiro 		       Mbdb, sm_strexit(i));
132640266059SGregory Neil Shapiro 		ExitStat = i;
132740266059SGregory Neil Shapiro 	}
132840266059SGregory Neil Shapiro 
1329c2aa98e2SPeter Wemm 	/* avoid denial-of-service attacks */
1330c2aa98e2SPeter Wemm 	resetlimits();
1331c2aa98e2SPeter Wemm 
133240266059SGregory Neil Shapiro 	if (OpMode == MD_TEST)
133340266059SGregory Neil Shapiro 	{
133440266059SGregory Neil Shapiro 		/* can't be done after readcf if RunAs* is used */
133540266059SGregory Neil Shapiro 		dp = drop_privileges(true);
133640266059SGregory Neil Shapiro 		if (dp != EX_OK)
133740266059SGregory Neil Shapiro 		{
133840266059SGregory Neil Shapiro 			finis(false, true, dp);
133940266059SGregory Neil Shapiro 			/* NOTREACHED */
134040266059SGregory Neil Shapiro 		}
134140266059SGregory Neil Shapiro 	}
134240266059SGregory Neil Shapiro 	else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
1343c2aa98e2SPeter Wemm 	{
1344c2aa98e2SPeter Wemm 		/* drop privileges -- daemon mode done after socket/bind */
134540266059SGregory Neil Shapiro 		dp = drop_privileges(false);
134606f25ae9SGregory Neil Shapiro 		setstat(dp);
134740266059SGregory Neil Shapiro 		if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))
134840266059SGregory Neil Shapiro 		{
134940266059SGregory Neil Shapiro 			usrerr("Mail submission program must have RunAsUser set to non root user");
135040266059SGregory Neil Shapiro 			finis(false, true, EX_CONFIG);
135140266059SGregory Neil Shapiro 			/* NOTREACHED */
135240266059SGregory Neil Shapiro 		}
1353c2aa98e2SPeter Wemm 	}
1354c2aa98e2SPeter Wemm 
135506f25ae9SGregory Neil Shapiro #if NAMED_BIND
135606f25ae9SGregory Neil Shapiro 	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
135706f25ae9SGregory Neil Shapiro 	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
135806f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
135906f25ae9SGregory Neil Shapiro 
1360c2aa98e2SPeter Wemm 	/*
1361c2aa98e2SPeter Wemm 	**  Find our real host name for future logging.
1362c2aa98e2SPeter Wemm 	*/
1363c2aa98e2SPeter Wemm 
136406f25ae9SGregory Neil Shapiro 	authinfo = getauthinfo(STDIN_FILENO, &forged);
136540266059SGregory Neil Shapiro 	macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
1366c2aa98e2SPeter Wemm 
1367c2aa98e2SPeter Wemm 	/* suppress error printing if errors mailed back or whatever */
136840266059SGregory Neil Shapiro 	if (BlankEnvelope.e_errormode != EM_PRINT)
136940266059SGregory Neil Shapiro 		HoldErrs = true;
1370c2aa98e2SPeter Wemm 
1371c2aa98e2SPeter Wemm 	/* set up the $=m class now, after .cf has a chance to redefine $m */
137240266059SGregory Neil Shapiro 	expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope);
1373602a2b1bSGregory Neil Shapiro 	if (jbuf[0] != '\0')
1374c2aa98e2SPeter Wemm 		setclass('m', jbuf);
1375c2aa98e2SPeter Wemm 
1376c2aa98e2SPeter Wemm 	/* probe interfaces and locate any additional names */
137740266059SGregory Neil Shapiro 	if (DontProbeInterfaces != DPI_PROBENONE)
1378c2aa98e2SPeter Wemm 		load_if_names();
1379c2aa98e2SPeter Wemm 
138040266059SGregory Neil Shapiro 	if (tTd(0, 10))
138140266059SGregory Neil Shapiro 	{
138240266059SGregory Neil Shapiro 		/* Now we know which .cf file we use */
138340266059SGregory Neil Shapiro 		sm_dprintf("     Conf file:\t%s (selected)\n",
138440266059SGregory Neil Shapiro 			   getcfname(OpMode, SubmitMode, cftype, conffile));
138540266059SGregory Neil Shapiro 		sm_dprintf("      Pid file:\t%s (selected)\n", PidFile);
138640266059SGregory Neil Shapiro 	}
138740266059SGregory Neil Shapiro 
1388c2aa98e2SPeter Wemm 	if (tTd(0, 1))
1389c2aa98e2SPeter Wemm 	{
139040266059SGregory Neil Shapiro 		sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
139140266059SGregory Neil Shapiro 		sm_dprintf("\n      (short domain name) $w = ");
139240266059SGregory Neil Shapiro 		xputs(macvalue('w', &BlankEnvelope));
139340266059SGregory Neil Shapiro 		sm_dprintf("\n  (canonical domain name) $j = ");
139440266059SGregory Neil Shapiro 		xputs(macvalue('j', &BlankEnvelope));
139540266059SGregory Neil Shapiro 		sm_dprintf("\n         (subdomain name) $m = ");
139640266059SGregory Neil Shapiro 		xputs(macvalue('m', &BlankEnvelope));
139740266059SGregory Neil Shapiro 		sm_dprintf("\n              (node name) $k = ");
139840266059SGregory Neil Shapiro 		xputs(macvalue('k', &BlankEnvelope));
139940266059SGregory Neil Shapiro 		sm_dprintf("\n========================================================\n\n");
1400c2aa98e2SPeter Wemm 	}
1401c2aa98e2SPeter Wemm 
1402c2aa98e2SPeter Wemm 	/*
1403c2aa98e2SPeter Wemm 	**  Do more command line checking -- these are things that
1404c2aa98e2SPeter Wemm 	**  have to modify the results of reading the config file.
1405c2aa98e2SPeter Wemm 	*/
1406c2aa98e2SPeter Wemm 
1407c2aa98e2SPeter Wemm 	/* process authorization warnings from command line */
1408c2aa98e2SPeter Wemm 	if (warn_C_flag)
140940266059SGregory Neil Shapiro 		auth_warning(&BlankEnvelope, "Processed by %s with -C %s",
141040266059SGregory Neil Shapiro 			     RealUserName, conffile);
141106f25ae9SGregory Neil Shapiro 	if (Warn_Q_option && !wordinclass(RealUserName, 't'))
141240266059SGregory Neil Shapiro 		auth_warning(&BlankEnvelope, "Processed from queue %s",
141340266059SGregory Neil Shapiro 			     QueueDir);
141440266059SGregory Neil Shapiro 	if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&
141540266059SGregory Neil Shapiro 	    RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)
141640266059SGregory Neil Shapiro 		sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",
141740266059SGregory Neil Shapiro 			  (int) RealUid);
1418c2aa98e2SPeter Wemm 
1419c2aa98e2SPeter Wemm 	/* check body type for legality */
142040266059SGregory Neil Shapiro 	i = check_bodytype(BlankEnvelope.e_bodytype);
142140266059SGregory Neil Shapiro 	if (i == BODYTYPE_ILLEGAL)
1422c2aa98e2SPeter Wemm 	{
142340266059SGregory Neil Shapiro 		usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
142440266059SGregory Neil Shapiro 		BlankEnvelope.e_bodytype = NULL;
1425c2aa98e2SPeter Wemm 	}
142640266059SGregory Neil Shapiro 	else if (i != BODYTYPE_NONE)
142740266059SGregory Neil Shapiro 		SevenBitInput = (i == BODYTYPE_7BIT);
1428c2aa98e2SPeter Wemm 
1429c2aa98e2SPeter Wemm 	/* tweak default DSN notifications */
1430c2aa98e2SPeter Wemm 	if (DefaultNotify == 0)
1431c2aa98e2SPeter Wemm 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1432c2aa98e2SPeter Wemm 
1433c2aa98e2SPeter Wemm 	/* be sure we don't pick up bogus HOSTALIASES environment variable */
143406f25ae9SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN && RealUid != 0)
1435c2aa98e2SPeter Wemm 		(void) unsetenv("HOSTALIASES");
1436c2aa98e2SPeter Wemm 
1437c2aa98e2SPeter Wemm 	/* check for sane configuration level */
1438c2aa98e2SPeter Wemm 	if (ConfigLevel > MAXCONFIGLEVEL)
1439c2aa98e2SPeter Wemm 	{
1440c2aa98e2SPeter Wemm 		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1441c2aa98e2SPeter Wemm 		       ConfigLevel, Version, MAXCONFIGLEVEL);
1442c2aa98e2SPeter Wemm 	}
1443c2aa98e2SPeter Wemm 
1444c2aa98e2SPeter Wemm 	/* need MCI cache to have persistence */
1445c2aa98e2SPeter Wemm 	if (HostStatDir != NULL && MaxMciCache == 0)
1446c2aa98e2SPeter Wemm 	{
1447c2aa98e2SPeter Wemm 		HostStatDir = NULL;
144840266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
144940266059SGregory Neil Shapiro 				     "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1450c2aa98e2SPeter Wemm 	}
1451c2aa98e2SPeter Wemm 
1452c2aa98e2SPeter Wemm 	/* need HostStatusDir in order to have SingleThreadDelivery */
1453c2aa98e2SPeter Wemm 	if (SingleThreadDelivery && HostStatDir == NULL)
1454c2aa98e2SPeter Wemm 	{
145540266059SGregory Neil Shapiro 		SingleThreadDelivery = false;
145640266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
145740266059SGregory Neil Shapiro 				     "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1458c2aa98e2SPeter Wemm 	}
1459c2aa98e2SPeter Wemm 
1460c2aa98e2SPeter Wemm 	/* check for permissions */
146140266059SGregory Neil Shapiro 	if (RealUid != 0 &&
1462065a643dSPeter Wemm 	    RealUid != TrustedUid)
1463c2aa98e2SPeter Wemm 	{
146440266059SGregory Neil Shapiro 		char *action = NULL;
146540266059SGregory Neil Shapiro 
146640266059SGregory Neil Shapiro 		switch (OpMode)
146740266059SGregory Neil Shapiro 		{
146840266059SGregory Neil Shapiro 		  case MD_QUEUERUN:
146940266059SGregory Neil Shapiro #if _FFR_QUARANTINE
147040266059SGregory Neil Shapiro 			if (quarantining != NULL)
147140266059SGregory Neil Shapiro 				action = "quarantine jobs";
147240266059SGregory Neil Shapiro 			else
147340266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
147440266059SGregory Neil Shapiro 			/* Normal users can do a single queue run */
147540266059SGregory Neil Shapiro 			if (QueueIntvl == 0)
147640266059SGregory Neil Shapiro 				break;
147740266059SGregory Neil Shapiro 
147840266059SGregory Neil Shapiro 			/* but not persistent queue runners */
147940266059SGregory Neil Shapiro 			if (action == NULL)
148040266059SGregory Neil Shapiro 				action = "start a queue runner daemon";
148140266059SGregory Neil Shapiro 			/* FALLTHROUGH */
148240266059SGregory Neil Shapiro 
148340266059SGregory Neil Shapiro 		  case MD_PURGESTAT:
148440266059SGregory Neil Shapiro 			if (action == NULL)
148540266059SGregory Neil Shapiro 				action = "purge host status";
148640266059SGregory Neil Shapiro 			/* FALLTHROUGH */
148740266059SGregory Neil Shapiro 
148840266059SGregory Neil Shapiro 		  case MD_DAEMON:
148940266059SGregory Neil Shapiro 		  case MD_FGDAEMON:
149040266059SGregory Neil Shapiro 			if (action == NULL)
149140266059SGregory Neil Shapiro 				action = "run daemon";
149240266059SGregory Neil Shapiro 
149340266059SGregory Neil Shapiro 			if (tTd(65, 1))
149440266059SGregory Neil Shapiro 				sm_dprintf("Deny user %d attempt to %s\n",
149540266059SGregory Neil Shapiro 					   (int) RealUid, action);
149640266059SGregory Neil Shapiro 
1497c2aa98e2SPeter Wemm 			if (LogLevel > 1)
1498c2aa98e2SPeter Wemm 				sm_syslog(LOG_ALERT, NOQID,
1499c2aa98e2SPeter Wemm 					  "user %d attempted to %s",
150040266059SGregory Neil Shapiro 					  (int) RealUid, action);
150140266059SGregory Neil Shapiro 			HoldErrs = false;
150240266059SGregory Neil Shapiro 			usrerr("Permission denied (real uid not trusted)");
150340266059SGregory Neil Shapiro 			finis(false, true, EX_USAGE);
150440266059SGregory Neil Shapiro 			/* NOTREACHED */
150540266059SGregory Neil Shapiro 			break;
150640266059SGregory Neil Shapiro 
150740266059SGregory Neil Shapiro 		  case MD_VERIFY:
150840266059SGregory Neil Shapiro 			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))
1509b518ca7dSPeter Wemm 			{
151040266059SGregory Neil Shapiro 				/*
151140266059SGregory Neil Shapiro 				**  If -bv and RestrictExpand,
151240266059SGregory Neil Shapiro 				**  drop privs to prevent normal
151340266059SGregory Neil Shapiro 				**  users from reading private
151440266059SGregory Neil Shapiro 				**  aliases/forwards/:include:s
151540266059SGregory Neil Shapiro 				*/
151640266059SGregory Neil Shapiro 
151740266059SGregory Neil Shapiro 				if (tTd(65, 1))
151840266059SGregory Neil Shapiro 					sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",
151940266059SGregory Neil Shapiro 						   (int) RealUid);
152040266059SGregory Neil Shapiro 
152140266059SGregory Neil Shapiro 				dp = drop_privileges(true);
152240266059SGregory Neil Shapiro 
152340266059SGregory Neil Shapiro 				/* Fake address safety */
152440266059SGregory Neil Shapiro 				if (tTd(65, 1))
152540266059SGregory Neil Shapiro 					sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");
152640266059SGregory Neil Shapiro 				setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);
152740266059SGregory Neil Shapiro 
152840266059SGregory Neil Shapiro 				if (dp != EX_OK)
152940266059SGregory Neil Shapiro 				{
153040266059SGregory Neil Shapiro 					if (tTd(65, 1))
153140266059SGregory Neil Shapiro 						sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",
153240266059SGregory Neil Shapiro 							   (int) RealUid);
153340266059SGregory Neil Shapiro 					CurEnv->e_id = NULL;
153440266059SGregory Neil Shapiro 					finis(true, true, dp);
153540266059SGregory Neil Shapiro 					/* NOTREACHED */
153640266059SGregory Neil Shapiro 				}
153740266059SGregory Neil Shapiro 			}
153840266059SGregory Neil Shapiro 			break;
153940266059SGregory Neil Shapiro 
154040266059SGregory Neil Shapiro 		  case MD_TEST:
154140266059SGregory Neil Shapiro 		  case MD_PRINT:
154240266059SGregory Neil Shapiro 		  case MD_PRINTNQE:
154340266059SGregory Neil Shapiro 		  case MD_FREEZE:
154440266059SGregory Neil Shapiro 		  case MD_HOSTSTAT:
154540266059SGregory Neil Shapiro 			/* Nothing special to check */
154640266059SGregory Neil Shapiro 			break;
154740266059SGregory Neil Shapiro 
154840266059SGregory Neil Shapiro 		  case MD_INITALIAS:
154940266059SGregory Neil Shapiro 			if (!wordinclass(RealUserName, 't'))
155040266059SGregory Neil Shapiro 			{
155140266059SGregory Neil Shapiro 				if (tTd(65, 1))
155240266059SGregory Neil Shapiro 					sm_dprintf("Deny user %d attempt to rebuild the alias map\n",
155340266059SGregory Neil Shapiro 						   (int) RealUid);
1554b518ca7dSPeter Wemm 				if (LogLevel > 1)
1555b518ca7dSPeter Wemm 					sm_syslog(LOG_ALERT, NOQID,
1556b518ca7dSPeter Wemm 						  "user %d attempted to rebuild the alias map",
155740266059SGregory Neil Shapiro 						  (int) RealUid);
155840266059SGregory Neil Shapiro 				HoldErrs = false;
155940266059SGregory Neil Shapiro 				usrerr("Permission denied (real uid not trusted)");
156040266059SGregory Neil Shapiro 				finis(false, true, EX_USAGE);
156140266059SGregory Neil Shapiro 				/* NOTREACHED */
156240266059SGregory Neil Shapiro 			}
156340266059SGregory Neil Shapiro 			if (UseMSP)
156440266059SGregory Neil Shapiro 			{
156540266059SGregory Neil Shapiro 				HoldErrs = false;
156640266059SGregory Neil Shapiro 				usrerr("User %d cannot rebuild aliases in mail submission program",
156740266059SGregory Neil Shapiro 				       (int) RealUid);
156840266059SGregory Neil Shapiro 				finis(false, true, EX_USAGE);
156940266059SGregory Neil Shapiro 				/* NOTREACHED */
157040266059SGregory Neil Shapiro 			}
157140266059SGregory Neil Shapiro 			/* FALLTHROUGH */
157240266059SGregory Neil Shapiro 
157340266059SGregory Neil Shapiro 		  default:
157440266059SGregory Neil Shapiro 			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&
157540266059SGregory Neil Shapiro 			    Verbose != 0)
157640266059SGregory Neil Shapiro 			{
157740266059SGregory Neil Shapiro 				/*
157840266059SGregory Neil Shapiro 				**  If -v and RestrictExpand, reset
157940266059SGregory Neil Shapiro 				**  Verbose to prevent normal users
158040266059SGregory Neil Shapiro 				**  from seeing the expansion of
158140266059SGregory Neil Shapiro 				**  aliases/forwards/:include:s
158240266059SGregory Neil Shapiro 				*/
158340266059SGregory Neil Shapiro 
158440266059SGregory Neil Shapiro 				if (tTd(65, 1))
158540266059SGregory Neil Shapiro 					sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",
158640266059SGregory Neil Shapiro 						   (int) RealUid);
158740266059SGregory Neil Shapiro 				Verbose = 0;
158840266059SGregory Neil Shapiro 			}
158940266059SGregory Neil Shapiro 			break;
159040266059SGregory Neil Shapiro 		}
1591b518ca7dSPeter Wemm 	}
1592c2aa98e2SPeter Wemm 
1593c2aa98e2SPeter Wemm 	if (MeToo)
1594c2aa98e2SPeter Wemm 		BlankEnvelope.e_flags |= EF_METOO;
1595c2aa98e2SPeter Wemm 
1596c2aa98e2SPeter Wemm 	switch (OpMode)
1597c2aa98e2SPeter Wemm 	{
1598c2aa98e2SPeter Wemm 	  case MD_TEST:
1599c2aa98e2SPeter Wemm 		/* don't have persistent host status in test mode */
1600c2aa98e2SPeter Wemm 		HostStatDir = NULL;
1601c2aa98e2SPeter Wemm 		if (Verbose == 0)
1602c2aa98e2SPeter Wemm 			Verbose = 2;
160340266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
160440266059SGregory Neil Shapiro 		HoldErrs = false;
1605c2aa98e2SPeter Wemm 		break;
1606c2aa98e2SPeter Wemm 
1607c2aa98e2SPeter Wemm 	  case MD_VERIFY:
160840266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
160940266059SGregory Neil Shapiro 		HoldErrs = false;
1610c2aa98e2SPeter Wemm 		/* arrange to exit cleanly on hangup signal */
161140266059SGregory Neil Shapiro 		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
161240266059SGregory Neil Shapiro 			(void) sm_signal(SIGHUP, intsig);
161340266059SGregory Neil Shapiro 		if (geteuid() != 0)
161440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
161540266059SGregory Neil Shapiro 					     "Notice: -bv may give misleading output for non-privileged user\n");
1616c2aa98e2SPeter Wemm 		break;
1617c2aa98e2SPeter Wemm 
1618c2aa98e2SPeter Wemm 	  case MD_FGDAEMON:
161940266059SGregory Neil Shapiro 		run_in_foreground = true;
162040266059SGregory Neil Shapiro 		set_op_mode(MD_DAEMON);
162106f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
1622c2aa98e2SPeter Wemm 
1623c2aa98e2SPeter Wemm 	  case MD_DAEMON:
162440266059SGregory Neil Shapiro 		vendor_daemon_setup(&BlankEnvelope);
1625c2aa98e2SPeter Wemm 
1626c2aa98e2SPeter Wemm 		/* remove things that don't make sense in daemon mode */
1627c2aa98e2SPeter Wemm 		FullName = NULL;
162840266059SGregory Neil Shapiro 		GrabTo = false;
1629c2aa98e2SPeter Wemm 
1630c2aa98e2SPeter Wemm 		/* arrange to restart on hangup signal */
1631c2aa98e2SPeter Wemm 		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1632c2aa98e2SPeter Wemm 			sm_syslog(LOG_WARNING, NOQID,
1633c2aa98e2SPeter Wemm 				  "daemon invoked without full pathname; kill -1 won't work");
1634c2aa98e2SPeter Wemm 		break;
1635c2aa98e2SPeter Wemm 
1636c2aa98e2SPeter Wemm 	  case MD_INITALIAS:
1637c2aa98e2SPeter Wemm 		Verbose = 2;
163840266059SGregory Neil Shapiro 		BlankEnvelope.e_errormode = EM_PRINT;
163940266059SGregory Neil Shapiro 		HoldErrs = false;
164006f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
1641c2aa98e2SPeter Wemm 
1642c2aa98e2SPeter Wemm 	  default:
1643c2aa98e2SPeter Wemm 		/* arrange to exit cleanly on hangup signal */
164440266059SGregory Neil Shapiro 		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
164540266059SGregory Neil Shapiro 			(void) sm_signal(SIGHUP, intsig);
1646c2aa98e2SPeter Wemm 		break;
1647c2aa98e2SPeter Wemm 	}
1648c2aa98e2SPeter Wemm 
1649c2aa98e2SPeter Wemm 	/* special considerations for FullName */
1650c2aa98e2SPeter Wemm 	if (FullName != NULL)
1651c2aa98e2SPeter Wemm 	{
1652c2aa98e2SPeter Wemm 		char *full = NULL;
1653c2aa98e2SPeter Wemm 
1654c2aa98e2SPeter Wemm 		/* full names can't have newlines */
1655c2aa98e2SPeter Wemm 		if (strchr(FullName, '\n') != NULL)
1656c2aa98e2SPeter Wemm 		{
165740266059SGregory Neil Shapiro 			full = newstr(denlstring(FullName, true, true));
1658602a2b1bSGregory Neil Shapiro 			FullName = full;
1659c2aa98e2SPeter Wemm 		}
1660602a2b1bSGregory Neil Shapiro 
1661c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1662c2aa98e2SPeter Wemm 		if (!rfc822_string(FullName))
1663c2aa98e2SPeter Wemm 		{
1664c2aa98e2SPeter Wemm 			/*
1665c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
1666c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
1667c2aa98e2SPeter Wemm 			**  the name portion of the address.
1668c2aa98e2SPeter Wemm 			*/
1669602a2b1bSGregory Neil Shapiro 
167040266059SGregory Neil Shapiro 			FullName = addquotes(FullName, NULL);
1671c2aa98e2SPeter Wemm 			if (full != NULL)
167240266059SGregory Neil Shapiro 				sm_free(full);  /* XXX */
1673c2aa98e2SPeter Wemm 		}
1674c2aa98e2SPeter Wemm 	}
1675c2aa98e2SPeter Wemm 
1676c2aa98e2SPeter Wemm 	/* do heuristic mode adjustment */
1677c2aa98e2SPeter Wemm 	if (Verbose)
1678c2aa98e2SPeter Wemm 	{
1679c2aa98e2SPeter Wemm 		/* turn off noconnect option */
168040266059SGregory Neil Shapiro 		setoption('c', "F", true, false, &BlankEnvelope);
1681c2aa98e2SPeter Wemm 
1682c2aa98e2SPeter Wemm 		/* turn on interactive delivery */
168340266059SGregory Neil Shapiro 		setoption('d', "", true, false, &BlankEnvelope);
1684c2aa98e2SPeter Wemm 	}
1685c2aa98e2SPeter Wemm 
1686065a643dSPeter Wemm #ifdef VENDOR_CODE
1687065a643dSPeter Wemm 	/* check for vendor mismatch */
1688065a643dSPeter Wemm 	if (VendorCode != VENDOR_CODE)
1689065a643dSPeter Wemm 	{
1690065a643dSPeter Wemm 		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1691065a643dSPeter Wemm 			getvendor(VENDOR_CODE), getvendor(VendorCode));
1692065a643dSPeter Wemm 	}
169306f25ae9SGregory Neil Shapiro #endif /* VENDOR_CODE */
1694065a643dSPeter Wemm 
1695c2aa98e2SPeter Wemm 	/* check for out of date configuration level */
1696c2aa98e2SPeter Wemm 	if (ConfigLevel < MAXCONFIGLEVEL)
1697c2aa98e2SPeter Wemm 	{
1698c2aa98e2SPeter Wemm 		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1699c2aa98e2SPeter Wemm 			Version, MAXCONFIGLEVEL, ConfigLevel);
1700c2aa98e2SPeter Wemm 	}
1701c2aa98e2SPeter Wemm 
1702c2aa98e2SPeter Wemm 	if (ConfigLevel < 3)
170340266059SGregory Neil Shapiro 		UseErrorsTo = true;
1704c2aa98e2SPeter Wemm 
1705c2aa98e2SPeter Wemm 	/* set options that were previous macros */
1706c2aa98e2SPeter Wemm 	if (SmtpGreeting == NULL)
1707c2aa98e2SPeter Wemm 	{
170840266059SGregory Neil Shapiro 		if (ConfigLevel < 7 &&
170940266059SGregory Neil Shapiro 		    (p = macvalue('e', &BlankEnvelope)) != NULL)
1710c2aa98e2SPeter Wemm 			SmtpGreeting = newstr(p);
1711c2aa98e2SPeter Wemm 		else
1712c2aa98e2SPeter Wemm 			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1713c2aa98e2SPeter Wemm 	}
1714c2aa98e2SPeter Wemm 	if (UnixFromLine == NULL)
1715c2aa98e2SPeter Wemm 	{
171640266059SGregory Neil Shapiro 		if (ConfigLevel < 7 &&
171740266059SGregory Neil Shapiro 		    (p = macvalue('l', &BlankEnvelope)) != NULL)
1718c2aa98e2SPeter Wemm 			UnixFromLine = newstr(p);
1719c2aa98e2SPeter Wemm 		else
1720c2aa98e2SPeter Wemm 			UnixFromLine = "From \201g  \201d";
1721c2aa98e2SPeter Wemm 	}
172206f25ae9SGregory Neil Shapiro 	SmtpError[0] = '\0';
1723c2aa98e2SPeter Wemm 
1724c2aa98e2SPeter Wemm 	/* our name for SMTP codes */
172540266059SGregory Neil Shapiro 	expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
1726602a2b1bSGregory Neil Shapiro 	if (jbuf[0] == '\0')
172740266059SGregory Neil Shapiro 		PSTRSET(MyHostName, "localhost");
1728602a2b1bSGregory Neil Shapiro 	else
172940266059SGregory Neil Shapiro 		PSTRSET(MyHostName, jbuf);
1730602a2b1bSGregory Neil Shapiro 	if (strchr(MyHostName, '.') == NULL)
1731c2aa98e2SPeter Wemm 		message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1732602a2b1bSGregory Neil Shapiro 			MyHostName);
1733c2aa98e2SPeter Wemm 
1734c2aa98e2SPeter Wemm 	/* make certain that this name is part of the $=w class */
1735c2aa98e2SPeter Wemm 	setclass('w', MyHostName);
1736c2aa98e2SPeter Wemm 
173740266059SGregory Neil Shapiro 	/* fill in the structure of the *default* queue */
173840266059SGregory Neil Shapiro 	st = stab("mqueue", ST_QUEUE, ST_FIND);
173940266059SGregory Neil Shapiro 	if (st == NULL)
174040266059SGregory Neil Shapiro 		syserr("No default queue (mqueue) defined");
174140266059SGregory Neil Shapiro 	else
174240266059SGregory Neil Shapiro 		set_def_queueval(st->s_quegrp, true);
174340266059SGregory Neil Shapiro 
1744c2aa98e2SPeter Wemm 	/* the indices of built-in mailers */
1745c2aa98e2SPeter Wemm 	st = stab("local", ST_MAILER, ST_FIND);
1746c2aa98e2SPeter Wemm 	if (st != NULL)
1747c2aa98e2SPeter Wemm 		LocalMailer = st->s_mailer;
1748c2aa98e2SPeter Wemm 	else if (OpMode != MD_TEST || !warn_C_flag)
1749c2aa98e2SPeter Wemm 		syserr("No local mailer defined");
1750c2aa98e2SPeter Wemm 
1751c2aa98e2SPeter Wemm 	st = stab("prog", ST_MAILER, ST_FIND);
1752c2aa98e2SPeter Wemm 	if (st == NULL)
1753c2aa98e2SPeter Wemm 		syserr("No prog mailer defined");
1754c2aa98e2SPeter Wemm 	else
1755c2aa98e2SPeter Wemm 	{
1756c2aa98e2SPeter Wemm 		ProgMailer = st->s_mailer;
1757c2aa98e2SPeter Wemm 		clrbitn(M_MUSER, ProgMailer->m_flags);
1758c2aa98e2SPeter Wemm 	}
1759c2aa98e2SPeter Wemm 
1760c2aa98e2SPeter Wemm 	st = stab("*file*", ST_MAILER, ST_FIND);
1761c2aa98e2SPeter Wemm 	if (st == NULL)
1762c2aa98e2SPeter Wemm 		syserr("No *file* mailer defined");
1763c2aa98e2SPeter Wemm 	else
1764c2aa98e2SPeter Wemm 	{
1765c2aa98e2SPeter Wemm 		FileMailer = st->s_mailer;
1766c2aa98e2SPeter Wemm 		clrbitn(M_MUSER, FileMailer->m_flags);
1767c2aa98e2SPeter Wemm 	}
1768c2aa98e2SPeter Wemm 
1769c2aa98e2SPeter Wemm 	st = stab("*include*", ST_MAILER, ST_FIND);
1770c2aa98e2SPeter Wemm 	if (st == NULL)
1771c2aa98e2SPeter Wemm 		syserr("No *include* mailer defined");
1772c2aa98e2SPeter Wemm 	else
1773c2aa98e2SPeter Wemm 		InclMailer = st->s_mailer;
1774c2aa98e2SPeter Wemm 
1775c2aa98e2SPeter Wemm 	if (ConfigLevel < 6)
1776c2aa98e2SPeter Wemm 	{
1777c2aa98e2SPeter Wemm 		/* heuristic tweaking of local mailer for back compat */
1778c2aa98e2SPeter Wemm 		if (LocalMailer != NULL)
1779c2aa98e2SPeter Wemm 		{
1780c2aa98e2SPeter Wemm 			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1781c2aa98e2SPeter Wemm 			setbitn(M_HASPWENT, LocalMailer->m_flags);
1782c2aa98e2SPeter Wemm 			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1783c2aa98e2SPeter Wemm 			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1784c2aa98e2SPeter Wemm 			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1785c2aa98e2SPeter Wemm 			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1786c2aa98e2SPeter Wemm 			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1787c2aa98e2SPeter Wemm 		}
1788c2aa98e2SPeter Wemm 		if (ProgMailer != NULL)
1789c2aa98e2SPeter Wemm 			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1790c2aa98e2SPeter Wemm 		if (FileMailer != NULL)
1791c2aa98e2SPeter Wemm 			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1792c2aa98e2SPeter Wemm 	}
1793c2aa98e2SPeter Wemm 	if (ConfigLevel < 7)
1794c2aa98e2SPeter Wemm 	{
1795c2aa98e2SPeter Wemm 		if (LocalMailer != NULL)
1796c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, LocalMailer->m_flags);
1797c2aa98e2SPeter Wemm 		if (ProgMailer != NULL)
1798c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, ProgMailer->m_flags);
1799c2aa98e2SPeter Wemm 		if (FileMailer != NULL)
1800c2aa98e2SPeter Wemm 			setbitn(M_VRFY250, FileMailer->m_flags);
1801c2aa98e2SPeter Wemm 	}
1802c2aa98e2SPeter Wemm 
1803c2aa98e2SPeter Wemm 	/* MIME Content-Types that cannot be transfer encoded */
1804c2aa98e2SPeter Wemm 	setclass('n', "multipart/signed");
1805c2aa98e2SPeter Wemm 
1806c2aa98e2SPeter Wemm 	/* MIME message/xxx subtypes that can be treated as messages */
1807c2aa98e2SPeter Wemm 	setclass('s', "rfc822");
1808c2aa98e2SPeter Wemm 
1809c2aa98e2SPeter Wemm 	/* MIME Content-Transfer-Encodings that can be encoded */
1810c2aa98e2SPeter Wemm 	setclass('e', "7bit");
1811c2aa98e2SPeter Wemm 	setclass('e', "8bit");
1812c2aa98e2SPeter Wemm 	setclass('e', "binary");
1813c2aa98e2SPeter Wemm 
1814c2aa98e2SPeter Wemm #ifdef USE_B_CLASS
1815c2aa98e2SPeter Wemm 	/* MIME Content-Types that should be treated as binary */
1816c2aa98e2SPeter Wemm 	setclass('b', "image");
1817c2aa98e2SPeter Wemm 	setclass('b', "audio");
1818c2aa98e2SPeter Wemm 	setclass('b', "video");
1819c2aa98e2SPeter Wemm 	setclass('b', "application/octet-stream");
182006f25ae9SGregory Neil Shapiro #endif /* USE_B_CLASS */
1821c2aa98e2SPeter Wemm 
1822065a643dSPeter Wemm 	/* MIME headers which have fields to check for overflow */
182340266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");
182440266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEFieldHeaders}"), "content-type");
1825065a643dSPeter Wemm 
1826065a643dSPeter Wemm 	/* MIME headers to check for length overflow */
182740266059SGregory Neil Shapiro 	setclass(macid("{checkMIMETextHeaders}"), "content-description");
1828065a643dSPeter Wemm 
1829065a643dSPeter Wemm 	/* MIME headers to check for overflow and rebalance */
183040266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-disposition");
183140266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-id");
183240266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");
183340266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "content-type");
183440266059SGregory Neil Shapiro 	setclass(macid("{checkMIMEHeaders}"), "mime-version");
183506f25ae9SGregory Neil Shapiro 
183640266059SGregory Neil Shapiro 	/* Macros to save in the queue file -- don't remove any */
183740266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "r");
183840266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "s");
183940266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "_");
184040266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "{if_addr}");
184140266059SGregory Neil Shapiro 	setclass(macid("{persistentMacros}"), "{daemon_flags}");
1842065a643dSPeter Wemm 
1843c2aa98e2SPeter Wemm 	/* operate in queue directory */
184440266059SGregory Neil Shapiro 	if (QueueDir == NULL || *QueueDir == '\0')
1845c2aa98e2SPeter Wemm 	{
1846c2aa98e2SPeter Wemm 		if (OpMode != MD_TEST)
1847c2aa98e2SPeter Wemm 		{
1848c2aa98e2SPeter Wemm 			syserr("QueueDirectory (Q) option must be set");
1849c2aa98e2SPeter Wemm 			ExitStat = EX_CONFIG;
1850c2aa98e2SPeter Wemm 		}
1851c2aa98e2SPeter Wemm 	}
1852c2aa98e2SPeter Wemm 	else
1853c2aa98e2SPeter Wemm 	{
185406f25ae9SGregory Neil Shapiro 		if (OpMode != MD_TEST)
185540266059SGregory Neil Shapiro 			setup_queues(OpMode == MD_DAEMON);
1856c2aa98e2SPeter Wemm 	}
1857c2aa98e2SPeter Wemm 
1858c2aa98e2SPeter Wemm 	/* check host status directory for validity */
185940266059SGregory Neil Shapiro 	if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))
1860c2aa98e2SPeter Wemm 	{
1861c2aa98e2SPeter Wemm 		/* cannot use this value */
186240266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
186340266059SGregory Neil Shapiro 				     "Warning: Cannot use HostStatusDirectory = %s: %s\n",
186440266059SGregory Neil Shapiro 				     HostStatDir, sm_errstring(errno));
1865c2aa98e2SPeter Wemm 		HostStatDir = NULL;
1866c2aa98e2SPeter Wemm 	}
1867c2aa98e2SPeter Wemm 
186840266059SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN &&
186940266059SGregory Neil Shapiro 	    RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1870c2aa98e2SPeter Wemm 	{
1871c2aa98e2SPeter Wemm 		struct stat stbuf;
1872c2aa98e2SPeter Wemm 
1873c2aa98e2SPeter Wemm 		/* check to see if we own the queue directory */
1874c2aa98e2SPeter Wemm 		if (stat(".", &stbuf) < 0)
1875c2aa98e2SPeter Wemm 			syserr("main: cannot stat %s", QueueDir);
1876c2aa98e2SPeter Wemm 		if (stbuf.st_uid != RealUid)
1877c2aa98e2SPeter Wemm 		{
1878c2aa98e2SPeter Wemm 			/* nope, really a botch */
187940266059SGregory Neil Shapiro 			HoldErrs = false;
1880c2aa98e2SPeter Wemm 			usrerr("You do not have permission to process the queue");
188140266059SGregory Neil Shapiro 			finis(false, true, EX_NOPERM);
188240266059SGregory Neil Shapiro 			/* NOTREACHED */
1883c2aa98e2SPeter Wemm 		}
1884c2aa98e2SPeter Wemm 	}
1885c2aa98e2SPeter Wemm 
188640266059SGregory Neil Shapiro #if MILTER
188706f25ae9SGregory Neil Shapiro 	/* sanity checks on milter filters */
188806f25ae9SGregory Neil Shapiro 	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
188940266059SGregory Neil Shapiro 	{
189040266059SGregory Neil Shapiro 		milter_config(InputFilterList, InputFilters, MAXFILTERS);
189140266059SGregory Neil Shapiro # if _FFR_MILTER_PERDAEMON
189240266059SGregory Neil Shapiro 		setup_daemon_milters();
189340266059SGregory Neil Shapiro # endif /* _FFR_MILTER_PERDAEMON */
189440266059SGregory Neil Shapiro 	}
189540266059SGregory Neil Shapiro #endif /* MILTER */
189606f25ae9SGregory Neil Shapiro 
189740266059SGregory Neil Shapiro 	/* Convert queuegroup string to qgrp number */
189840266059SGregory Neil Shapiro 	if (queuegroup != NULL)
189940266059SGregory Neil Shapiro 	{
190040266059SGregory Neil Shapiro 		qgrp = name2qid(queuegroup);
190140266059SGregory Neil Shapiro 		if (qgrp == NOQGRP)
190240266059SGregory Neil Shapiro 		{
190340266059SGregory Neil Shapiro 			HoldErrs = false;
190440266059SGregory Neil Shapiro 			usrerr("Queue group %s unknown", queuegroup);
190540266059SGregory Neil Shapiro 			finis(false, true, ExitStat);
190640266059SGregory Neil Shapiro 			/* NOTREACHED */
190740266059SGregory Neil Shapiro 		}
190840266059SGregory Neil Shapiro 	}
190942e5d165SGregory Neil Shapiro 
1910c2aa98e2SPeter Wemm 	/* if we've had errors so far, exit now */
1911c2aa98e2SPeter Wemm 	if (ExitStat != EX_OK && OpMode != MD_TEST)
191240266059SGregory Neil Shapiro 	{
191340266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
191440266059SGregory Neil Shapiro 		/* NOTREACHED */
191540266059SGregory Neil Shapiro 	}
191640266059SGregory Neil Shapiro 
191740266059SGregory Neil Shapiro #if SASL
191840266059SGregory Neil Shapiro 	/* sendmail specific SASL initialization */
191940266059SGregory Neil Shapiro 	sm_sasl_init();
192040266059SGregory Neil Shapiro #endif /* SASL */
1921c2aa98e2SPeter Wemm 
1922c2aa98e2SPeter Wemm #if XDEBUG
1923c2aa98e2SPeter Wemm 	checkfd012("before main() initmaps");
192406f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
1925c2aa98e2SPeter Wemm 
1926c2aa98e2SPeter Wemm 	/*
1927c2aa98e2SPeter Wemm 	**  Do operation-mode-dependent initialization.
1928c2aa98e2SPeter Wemm 	*/
1929c2aa98e2SPeter Wemm 
1930c2aa98e2SPeter Wemm 	switch (OpMode)
1931c2aa98e2SPeter Wemm 	{
1932c2aa98e2SPeter Wemm 	  case MD_PRINT:
1933c2aa98e2SPeter Wemm 		/* print the queue */
193440266059SGregory Neil Shapiro 		HoldErrs = false;
193540266059SGregory Neil Shapiro 		dropenvelope(&BlankEnvelope, true, false);
193640266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
193740266059SGregory Neil Shapiro 		if (qgrp != NOQGRP)
193840266059SGregory Neil Shapiro 		{
193940266059SGregory Neil Shapiro 			int j;
194040266059SGregory Neil Shapiro 
194140266059SGregory Neil Shapiro 			/* Selecting a particular queue group to run */
194240266059SGregory Neil Shapiro 			for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
194340266059SGregory Neil Shapiro 			{
194440266059SGregory Neil Shapiro 				if (StopRequest)
194540266059SGregory Neil Shapiro 					stop_sendmail();
194640266059SGregory Neil Shapiro 				(void) print_single_queue(qgrp, j);
194740266059SGregory Neil Shapiro 			}
194840266059SGregory Neil Shapiro 			finis(false, true, EX_OK);
194940266059SGregory Neil Shapiro 			/* NOTREACHED */
195040266059SGregory Neil Shapiro 		}
1951c2aa98e2SPeter Wemm 		printqueue();
195240266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
195340266059SGregory Neil Shapiro 		/* NOTREACHED */
1954065a643dSPeter Wemm 		break;
1955c2aa98e2SPeter Wemm 
195640266059SGregory Neil Shapiro 	  case MD_PRINTNQE:
195740266059SGregory Neil Shapiro 		/* print number of entries in queue */
195840266059SGregory Neil Shapiro 		dropenvelope(&BlankEnvelope, true, false);
195940266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
196040266059SGregory Neil Shapiro 		printnqe(smioout, NULL);
196140266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
196240266059SGregory Neil Shapiro 		/* NOTREACHED */
196340266059SGregory Neil Shapiro 		break;
196440266059SGregory Neil Shapiro 
196540266059SGregory Neil Shapiro #if _FFR_QUARANTINE
196640266059SGregory Neil Shapiro 	  case MD_QUEUERUN:
196740266059SGregory Neil Shapiro 		/* only handle quarantining here */
196840266059SGregory Neil Shapiro 		if (quarantining == NULL)
196940266059SGregory Neil Shapiro 			break;
197040266059SGregory Neil Shapiro 
197140266059SGregory Neil Shapiro 		if (QueueMode != QM_QUARANTINE &&
197240266059SGregory Neil Shapiro 		    QueueMode != QM_NORMAL)
197340266059SGregory Neil Shapiro 		{
197440266059SGregory Neil Shapiro 			HoldErrs = false;
197540266059SGregory Neil Shapiro 			usrerr("Can not use -Q with -q%c", QueueMode);
197640266059SGregory Neil Shapiro 			ExitStat = EX_USAGE;
197740266059SGregory Neil Shapiro 			finis(false, true, ExitStat);
197840266059SGregory Neil Shapiro 			/* NOTREACHED */
197940266059SGregory Neil Shapiro 		}
198040266059SGregory Neil Shapiro 		quarantine_queue(quarantining, qgrp);
198140266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
198240266059SGregory Neil Shapiro 		break;
198340266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
198440266059SGregory Neil Shapiro 
1985c2aa98e2SPeter Wemm 	  case MD_HOSTSTAT:
198640266059SGregory Neil Shapiro 		(void) sm_signal(SIGPIPE, sigpipe);
198706f25ae9SGregory Neil Shapiro 		(void) mci_traverse_persistent(mci_print_persistent, NULL);
198840266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
198940266059SGregory Neil Shapiro 		/* NOTREACHED */
1990c2aa98e2SPeter Wemm 		break;
1991c2aa98e2SPeter Wemm 
1992c2aa98e2SPeter Wemm 	  case MD_PURGESTAT:
199306f25ae9SGregory Neil Shapiro 		(void) mci_traverse_persistent(mci_purge_persistent, NULL);
199440266059SGregory Neil Shapiro 		finis(false, true, EX_OK);
199540266059SGregory Neil Shapiro 		/* NOTREACHED */
1996c2aa98e2SPeter Wemm 		break;
1997c2aa98e2SPeter Wemm 
1998c2aa98e2SPeter Wemm 	  case MD_INITALIAS:
1999065a643dSPeter Wemm 		/* initialize maps */
200006f25ae9SGregory Neil Shapiro 		initmaps();
200140266059SGregory Neil Shapiro 		finis(false, true, ExitStat);
200240266059SGregory Neil Shapiro 		/* NOTREACHED */
2003065a643dSPeter Wemm 		break;
2004c2aa98e2SPeter Wemm 
2005c2aa98e2SPeter Wemm 	  case MD_SMTP:
2006c2aa98e2SPeter Wemm 	  case MD_DAEMON:
2007c2aa98e2SPeter Wemm 		/* reset DSN parameters */
2008c2aa98e2SPeter Wemm 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
200940266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
201040266059SGregory Neil Shapiro 			  macid("{dsn_notify}"), NULL);
201140266059SGregory Neil Shapiro 		BlankEnvelope.e_envid = NULL;
201240266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
201340266059SGregory Neil Shapiro 			  macid("{dsn_envid}"), NULL);
201440266059SGregory Neil Shapiro 		BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
201540266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_PERM,
201640266059SGregory Neil Shapiro 			  macid("{dsn_ret}"), NULL);
2017c2aa98e2SPeter Wemm 
2018065a643dSPeter Wemm 		/* don't open maps for daemon -- done below in child */
2019c2aa98e2SPeter Wemm 		break;
2020c2aa98e2SPeter Wemm 	}
2021c2aa98e2SPeter Wemm 
2022c2aa98e2SPeter Wemm 	if (tTd(0, 15))
2023c2aa98e2SPeter Wemm 	{
2024c2aa98e2SPeter Wemm 		/* print configuration table (or at least part of it) */
2025c2aa98e2SPeter Wemm 		if (tTd(0, 90))
2026c2aa98e2SPeter Wemm 			printrules();
2027c2aa98e2SPeter Wemm 		for (i = 0; i < MAXMAILERS; i++)
2028c2aa98e2SPeter Wemm 		{
2029c2aa98e2SPeter Wemm 			if (Mailer[i] != NULL)
2030c2aa98e2SPeter Wemm 				printmailer(Mailer[i]);
2031c2aa98e2SPeter Wemm 		}
2032c2aa98e2SPeter Wemm 	}
2033c2aa98e2SPeter Wemm 
2034c2aa98e2SPeter Wemm 	/*
2035c2aa98e2SPeter Wemm 	**  Switch to the main envelope.
2036c2aa98e2SPeter Wemm 	*/
2037c2aa98e2SPeter Wemm 
203840266059SGregory Neil Shapiro 	CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,
203940266059SGregory Neil Shapiro 			     sm_rpool_new_x(NULL));
2040c2aa98e2SPeter Wemm 	MainEnvelope.e_flags = BlankEnvelope.e_flags;
2041c2aa98e2SPeter Wemm 
2042c2aa98e2SPeter Wemm 	/*
2043c2aa98e2SPeter Wemm 	**  If test mode, read addresses from stdin and process.
2044c2aa98e2SPeter Wemm 	*/
2045c2aa98e2SPeter Wemm 
2046c2aa98e2SPeter Wemm 	if (OpMode == MD_TEST)
2047c2aa98e2SPeter Wemm 	{
204840266059SGregory Neil Shapiro 		if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))
2049c2aa98e2SPeter Wemm 			Verbose = 2;
2050c2aa98e2SPeter Wemm 
2051c2aa98e2SPeter Wemm 		if (Verbose)
2052c2aa98e2SPeter Wemm 		{
205340266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
205440266059SGregory Neil Shapiro 				     "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
205540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
205640266059SGregory Neil Shapiro 				     "Enter <ruleset> <address>\n");
2057c2aa98e2SPeter Wemm 		}
205840266059SGregory Neil Shapiro 		macdefine(&(MainEnvelope.e_macro), A_PERM,
205940266059SGregory Neil Shapiro 			  macid("{addr_type}"), "e r");
2060c2aa98e2SPeter Wemm 		for (;;)
2061c2aa98e2SPeter Wemm 		{
206240266059SGregory Neil Shapiro 			SM_TRY
206340266059SGregory Neil Shapiro 			{
206440266059SGregory Neil Shapiro 				(void) sm_signal(SIGINT, intindebug);
206540266059SGregory Neil Shapiro 				(void) sm_releasesignal(SIGINT);
2066c2aa98e2SPeter Wemm 				if (Verbose == 2)
206740266059SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout,
206840266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
206940266059SGregory Neil Shapiro 							     "> ");
207040266059SGregory Neil Shapiro 				(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
207140266059SGregory Neil Shapiro 				if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,
207240266059SGregory Neil Shapiro 						sizeof buf) == NULL)
207340266059SGregory Neil Shapiro 					testmodeline("/quit", &MainEnvelope);
2074c2aa98e2SPeter Wemm 				p = strchr(buf, '\n');
2075c2aa98e2SPeter Wemm 				if (p != NULL)
2076c2aa98e2SPeter Wemm 					*p = '\0';
2077c2aa98e2SPeter Wemm 				if (Verbose < 2)
207840266059SGregory Neil Shapiro 					(void) sm_io_fprintf(smioout,
207940266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
208040266059SGregory Neil Shapiro 							     "> %s\n", buf);
208140266059SGregory Neil Shapiro 				testmodeline(buf, &MainEnvelope);
208240266059SGregory Neil Shapiro 			}
208340266059SGregory Neil Shapiro 			SM_EXCEPT(exc, "[!F]*")
208440266059SGregory Neil Shapiro 			{
208540266059SGregory Neil Shapiro 				/*
208640266059SGregory Neil Shapiro 				**  8.10 just prints \n on interrupt.
208740266059SGregory Neil Shapiro 				**  I'm printing the exception here in case
208840266059SGregory Neil Shapiro 				**  sendmail is extended to raise additional
208940266059SGregory Neil Shapiro 				**  exceptions in this context.
209040266059SGregory Neil Shapiro 				*/
209140266059SGregory Neil Shapiro 
209240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
209340266059SGregory Neil Shapiro 						     "\n");
209440266059SGregory Neil Shapiro 				sm_exc_print(exc, smioout);
209540266059SGregory Neil Shapiro 			}
209640266059SGregory Neil Shapiro 			SM_END_TRY
2097c2aa98e2SPeter Wemm 		}
2098c2aa98e2SPeter Wemm 	}
2099c2aa98e2SPeter Wemm 
210006f25ae9SGregory Neil Shapiro #if STARTTLS
210140266059SGregory Neil Shapiro 	tls_ok = true;
210240266059SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)
210340266059SGregory Neil Shapiro 	{
210440266059SGregory Neil Shapiro 		/* check whether STARTTLS is turned off for the client */
210540266059SGregory Neil Shapiro 		if (chkclientmodifiers(D_NOTLS))
210640266059SGregory Neil Shapiro 			tls_ok = false;
210740266059SGregory Neil Shapiro 	}
210840266059SGregory Neil Shapiro 	else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||
210940266059SGregory Neil Shapiro 		 OpMode == MD_SMTP)
211040266059SGregory Neil Shapiro 	{
211140266059SGregory Neil Shapiro 		/* check whether STARTTLS is turned off for the server */
211240266059SGregory Neil Shapiro 		if (chkdaemonmodifiers(D_NOTLS))
211340266059SGregory Neil Shapiro 			tls_ok = false;
211440266059SGregory Neil Shapiro 	}
211540266059SGregory Neil Shapiro 	else	/* other modes don't need STARTTLS */
211640266059SGregory Neil Shapiro 		tls_ok = false;
211706f25ae9SGregory Neil Shapiro 
211840266059SGregory Neil Shapiro 	if (tls_ok)
211940266059SGregory Neil Shapiro 	{
212040266059SGregory Neil Shapiro 		/* basic TLS initialization */
212140266059SGregory Neil Shapiro 		tls_ok = init_tls_library();
212240266059SGregory Neil Shapiro 	}
212340266059SGregory Neil Shapiro 
212440266059SGregory Neil Shapiro 	if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
212540266059SGregory Neil Shapiro 	{
212640266059SGregory Neil Shapiro 		/* disable TLS for client */
212740266059SGregory Neil Shapiro 		setclttls(false);
212840266059SGregory Neil Shapiro 	}
212940266059SGregory Neil Shapiro #endif /* STARTTLS */
213040266059SGregory Neil Shapiro 
2131c2aa98e2SPeter Wemm 	/*
2132c2aa98e2SPeter Wemm 	**  If collecting stuff from the queue, go start doing that.
2133c2aa98e2SPeter Wemm 	*/
2134c2aa98e2SPeter Wemm 
213506f25ae9SGregory Neil Shapiro 	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
2136c2aa98e2SPeter Wemm 	{
213740266059SGregory Neil Shapiro 		pid_t pid = -1;
213840266059SGregory Neil Shapiro 
213906f25ae9SGregory Neil Shapiro #if STARTTLS
214006f25ae9SGregory Neil Shapiro 		/* init TLS for client, ignore result for now */
214140266059SGregory Neil Shapiro 		(void) initclttls(tls_ok);
214206f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
214340266059SGregory Neil Shapiro 
214440266059SGregory Neil Shapiro 		/*
214540266059SGregory Neil Shapiro 		**  The parent process of the caller of runqueue() needs
214640266059SGregory Neil Shapiro 		**  to stay around for a possible SIGTERM. The SIGTERM will
214740266059SGregory Neil Shapiro 		**  tell this process that all of the queue runners children
214840266059SGregory Neil Shapiro 		**  need to be sent SIGTERM as well. At the same time, we
214940266059SGregory Neil Shapiro 		**  want to return control to the command line. So we do an
215040266059SGregory Neil Shapiro 		**  extra fork().
215140266059SGregory Neil Shapiro 		*/
215240266059SGregory Neil Shapiro 
215340266059SGregory Neil Shapiro 		if (Verbose || foregroundqueue || (pid = fork()) <= 0)
215440266059SGregory Neil Shapiro 		{
215540266059SGregory Neil Shapiro 			/*
215640266059SGregory Neil Shapiro 			**  If the fork() failed we should still try to do
215740266059SGregory Neil Shapiro 			**  the queue run. If it succeeded then the child
215840266059SGregory Neil Shapiro 			**  is going to start the run and wait for all
215940266059SGregory Neil Shapiro 			**  of the children to finish.
216040266059SGregory Neil Shapiro 			*/
216140266059SGregory Neil Shapiro 
216240266059SGregory Neil Shapiro 			if (pid == 0)
216340266059SGregory Neil Shapiro 			{
216440266059SGregory Neil Shapiro 				/* Reset global flags */
216540266059SGregory Neil Shapiro 				RestartRequest = NULL;
216640266059SGregory Neil Shapiro 				ShutdownRequest = NULL;
216740266059SGregory Neil Shapiro 				PendingSignal = 0;
216840266059SGregory Neil Shapiro 
216940266059SGregory Neil Shapiro 				/* disconnect from terminal */
217040266059SGregory Neil Shapiro 				disconnect(2, CurEnv);
2171c2aa98e2SPeter Wemm 			}
217240266059SGregory Neil Shapiro 
217340266059SGregory Neil Shapiro 			CurrentPid = getpid();
217440266059SGregory Neil Shapiro 			if (qgrp != NOQGRP)
217540266059SGregory Neil Shapiro 			{
217640266059SGregory Neil Shapiro 				/*
217740266059SGregory Neil Shapiro 				**  To run a specific queue group mark it to
217840266059SGregory Neil Shapiro 				**  be run, select the work group it's in and
217940266059SGregory Neil Shapiro 				**  increment the work counter.
218040266059SGregory Neil Shapiro 				*/
218140266059SGregory Neil Shapiro 
218240266059SGregory Neil Shapiro 				runqueueevent(qgrp);
218340266059SGregory Neil Shapiro 				(void) run_work_group(Queue[qgrp]->qg_wgrp,
218440266059SGregory Neil Shapiro 						      false, Verbose,
218540266059SGregory Neil Shapiro 						      queuepersistent, false);
218640266059SGregory Neil Shapiro 			}
218740266059SGregory Neil Shapiro 			else
218840266059SGregory Neil Shapiro 				(void) runqueue(false, Verbose,
218940266059SGregory Neil Shapiro 						queuepersistent, true);
219040266059SGregory Neil Shapiro 
219140266059SGregory Neil Shapiro 			/* set the title to make it easier to find */
219240266059SGregory Neil Shapiro 			sm_setproctitle(true, CurEnv, "Queue control");
219340266059SGregory Neil Shapiro 			(void) sm_signal(SIGCHLD, SIG_DFL);
219440266059SGregory Neil Shapiro 			while (CurChildren > 0)
219540266059SGregory Neil Shapiro 			{
219640266059SGregory Neil Shapiro 				int status;
219740266059SGregory Neil Shapiro 				pid_t ret;
219840266059SGregory Neil Shapiro 
219940266059SGregory Neil Shapiro 				while ((ret = sm_wait(&status)) <= 0)
220040266059SGregory Neil Shapiro 					continue;
220140266059SGregory Neil Shapiro 
220240266059SGregory Neil Shapiro 				/* Only drop when a child gives status */
220340266059SGregory Neil Shapiro 				if (WIFSTOPPED(status))
220440266059SGregory Neil Shapiro 					continue;
220540266059SGregory Neil Shapiro 
220640266059SGregory Neil Shapiro 				proc_list_drop(ret, status, NULL);
220740266059SGregory Neil Shapiro 			}
220840266059SGregory Neil Shapiro 		}
220940266059SGregory Neil Shapiro 		finis(true, true, ExitStat);
221040266059SGregory Neil Shapiro 		/* NOTREACHED */
221140266059SGregory Neil Shapiro 	}
2212c2aa98e2SPeter Wemm 
2213193538b7SGregory Neil Shapiro # if SASL
2214193538b7SGregory Neil Shapiro 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2215193538b7SGregory Neil Shapiro 	{
221640266059SGregory Neil Shapiro 		/* check whether AUTH is turned off for the server */
221740266059SGregory Neil Shapiro 		if (!chkdaemonmodifiers(D_NOAUTH) &&
221840266059SGregory Neil Shapiro 		    (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
2219193538b7SGregory Neil Shapiro 			syserr("!sasl_server_init failed! [%s]",
2220193538b7SGregory Neil Shapiro 				sasl_errstring(i, NULL, NULL));
2221193538b7SGregory Neil Shapiro 	}
2222193538b7SGregory Neil Shapiro # endif /* SASL */
2223193538b7SGregory Neil Shapiro 
222440266059SGregory Neil Shapiro 	if (OpMode == MD_SMTP)
222540266059SGregory Neil Shapiro 	{
222640266059SGregory Neil Shapiro 		proc_list_add(CurrentPid, "Sendmail SMTP Agent",
222740266059SGregory Neil Shapiro 			      PROC_DAEMON, 0, -1);
222840266059SGregory Neil Shapiro 
222940266059SGregory Neil Shapiro 		/* clean up background delivery children */
223040266059SGregory Neil Shapiro 		(void) sm_signal(SIGCHLD, reapchild);
223140266059SGregory Neil Shapiro 	}
223240266059SGregory Neil Shapiro 
2233c2aa98e2SPeter Wemm 	/*
2234c2aa98e2SPeter Wemm 	**  If a daemon, wait for a request.
2235c2aa98e2SPeter Wemm 	**	getrequests will always return in a child.
2236c2aa98e2SPeter Wemm 	**	If we should also be processing the queue, start
2237c2aa98e2SPeter Wemm 	**		doing it in background.
2238c2aa98e2SPeter Wemm 	**	We check for any errors that might have happened
2239c2aa98e2SPeter Wemm 	**		during startup.
2240c2aa98e2SPeter Wemm 	*/
2241c2aa98e2SPeter Wemm 
2242c2aa98e2SPeter Wemm 	if (OpMode == MD_DAEMON || QueueIntvl != 0)
2243c2aa98e2SPeter Wemm 	{
2244c2aa98e2SPeter Wemm 		char dtype[200];
2245c2aa98e2SPeter Wemm 
2246c2aa98e2SPeter Wemm 		if (!run_in_foreground && !tTd(99, 100))
2247c2aa98e2SPeter Wemm 		{
2248c2aa98e2SPeter Wemm 			/* put us in background */
2249c2aa98e2SPeter Wemm 			i = fork();
2250c2aa98e2SPeter Wemm 			if (i < 0)
2251c2aa98e2SPeter Wemm 				syserr("daemon: cannot fork");
2252c2aa98e2SPeter Wemm 			if (i != 0)
225340266059SGregory Neil Shapiro 			{
225440266059SGregory Neil Shapiro 				finis(false, true, EX_OK);
225540266059SGregory Neil Shapiro 				/* NOTREACHED */
225640266059SGregory Neil Shapiro 			}
225740266059SGregory Neil Shapiro 
225840266059SGregory Neil Shapiro 			/*
225940266059SGregory Neil Shapiro 			**  Initialize exception stack and default exception
226040266059SGregory Neil Shapiro 			**  handler for child process.
226140266059SGregory Neil Shapiro 			*/
226240266059SGregory Neil Shapiro 
226340266059SGregory Neil Shapiro 			/* Reset global flags */
226440266059SGregory Neil Shapiro 			RestartRequest = NULL;
226540266059SGregory Neil Shapiro 			RestartWorkGroup = false;
226640266059SGregory Neil Shapiro 			ShutdownRequest = NULL;
226740266059SGregory Neil Shapiro 			PendingSignal = 0;
226840266059SGregory Neil Shapiro 			CurrentPid = getpid();
226940266059SGregory Neil Shapiro 
227040266059SGregory Neil Shapiro 			sm_exc_newthread(fatal_error);
2271c2aa98e2SPeter Wemm 
2272c2aa98e2SPeter Wemm 			/* disconnect from our controlling tty */
227340266059SGregory Neil Shapiro 			disconnect(2, &MainEnvelope);
2274c2aa98e2SPeter Wemm 		}
2275c2aa98e2SPeter Wemm 
2276c2aa98e2SPeter Wemm 		dtype[0] = '\0';
2277c2aa98e2SPeter Wemm 		if (OpMode == MD_DAEMON)
227840266059SGregory Neil Shapiro 		{
227940266059SGregory Neil Shapiro 			(void) sm_strlcat(dtype, "+SMTP", sizeof dtype);
228040266059SGregory Neil Shapiro 			DaemonPid = CurrentPid;
228140266059SGregory Neil Shapiro 		}
2282c2aa98e2SPeter Wemm 		if (QueueIntvl != 0)
2283c2aa98e2SPeter Wemm 		{
228440266059SGregory Neil Shapiro 			(void) sm_strlcat2(dtype,
228540266059SGregory Neil Shapiro 					   queuepersistent
228640266059SGregory Neil Shapiro 					   ? "+persistent-queueing@"
228740266059SGregory Neil Shapiro 					   : "+queueing@",
228840266059SGregory Neil Shapiro 					   pintvl(QueueIntvl, true),
228906f25ae9SGregory Neil Shapiro 					   sizeof dtype);
2290c2aa98e2SPeter Wemm 		}
2291c2aa98e2SPeter Wemm 		if (tTd(0, 1))
229240266059SGregory Neil Shapiro 			(void) sm_strlcat(dtype, "+debugging", sizeof dtype);
2293c2aa98e2SPeter Wemm 
2294c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, NOQID,
2295c2aa98e2SPeter Wemm 			  "starting daemon (%s): %s", Version, dtype + 1);
229640266059SGregory Neil Shapiro #if XLA
2297c2aa98e2SPeter Wemm 		xla_create_file();
229806f25ae9SGregory Neil Shapiro #endif /* XLA */
229906f25ae9SGregory Neil Shapiro 
230006f25ae9SGregory Neil Shapiro 		/* save daemon type in a macro for possible PidFile use */
230140266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
230240266059SGregory Neil Shapiro 			macid("{daemon_info}"), dtype + 1);
230306f25ae9SGregory Neil Shapiro 
230406f25ae9SGregory Neil Shapiro 		/* save queue interval in a macro for possible PidFile use */
230540266059SGregory Neil Shapiro 		macdefine(&MainEnvelope.e_macro, A_TEMP,
230640266059SGregory Neil Shapiro 			macid("{queue_interval}"), pintvl(QueueIntvl, true));
2307c2aa98e2SPeter Wemm 
230840266059SGregory Neil Shapiro 		/* workaround: can't seem to release the signal in the parent */
230940266059SGregory Neil Shapiro 		(void) sm_signal(SIGHUP, sighup);
231040266059SGregory Neil Shapiro 		(void) sm_releasesignal(SIGHUP);
231140266059SGregory Neil Shapiro 		(void) sm_signal(SIGTERM, sigterm);
231240266059SGregory Neil Shapiro 
231306f25ae9SGregory Neil Shapiro 		if (QueueIntvl != 0)
2314c2aa98e2SPeter Wemm 		{
231540266059SGregory Neil Shapiro 			(void) runqueue(true, false, queuepersistent, true);
231640266059SGregory Neil Shapiro 
231740266059SGregory Neil Shapiro 			/*
231840266059SGregory Neil Shapiro 			**  If queuepersistent but not in daemon mode then
231940266059SGregory Neil Shapiro 			**  we're going to do the queue runner monitoring here.
232040266059SGregory Neil Shapiro 			**  If in daemon mode then the monitoring will happen
232140266059SGregory Neil Shapiro 			**  elsewhere.
232240266059SGregory Neil Shapiro 			*/
232340266059SGregory Neil Shapiro 
232440266059SGregory Neil Shapiro 			if (OpMode != MD_DAEMON && queuepersistent)
232540266059SGregory Neil Shapiro 			{
232640266059SGregory Neil Shapiro 				/* set the title to make it easier to find */
232740266059SGregory Neil Shapiro 				sm_setproctitle(true, CurEnv, "Queue control");
232840266059SGregory Neil Shapiro 				(void) sm_signal(SIGCHLD, SIG_DFL);
232940266059SGregory Neil Shapiro 				while (CurChildren > 0)
233040266059SGregory Neil Shapiro 				{
233140266059SGregory Neil Shapiro 					int status;
233240266059SGregory Neil Shapiro 					pid_t ret;
233340266059SGregory Neil Shapiro 					int group;
233440266059SGregory Neil Shapiro 
233540266059SGregory Neil Shapiro 					if (ShutdownRequest != NULL)
233640266059SGregory Neil Shapiro 						shutdown_daemon();
233740266059SGregory Neil Shapiro 					else if (RestartRequest != NULL)
233840266059SGregory Neil Shapiro 						restart_daemon();
233940266059SGregory Neil Shapiro 					else if (RestartWorkGroup)
234040266059SGregory Neil Shapiro 						restart_marked_work_groups();
234140266059SGregory Neil Shapiro 
234240266059SGregory Neil Shapiro 					while ((ret = sm_wait(&status)) <= 0)
234340266059SGregory Neil Shapiro 						continue;
234440266059SGregory Neil Shapiro 
234540266059SGregory Neil Shapiro 					if (WIFSTOPPED(status))
234640266059SGregory Neil Shapiro 						continue;
234740266059SGregory Neil Shapiro 
234840266059SGregory Neil Shapiro 					/* Probe only on a child status */
234940266059SGregory Neil Shapiro 					proc_list_drop(ret, status, &group);
235040266059SGregory Neil Shapiro 
235140266059SGregory Neil Shapiro 					if (WIFSIGNALED(status))
235240266059SGregory Neil Shapiro 					{
235340266059SGregory Neil Shapiro 						if (WCOREDUMP(status))
235440266059SGregory Neil Shapiro 						{
235540266059SGregory Neil Shapiro 							sm_syslog(LOG_ERR, NOQID,
235640266059SGregory Neil Shapiro 								  "persistent queue runner=%d core dumped, signal=%d",
235740266059SGregory Neil Shapiro 								  group, WTERMSIG(status));
235840266059SGregory Neil Shapiro 
235940266059SGregory Neil Shapiro 							/* don't restart this one */
236040266059SGregory Neil Shapiro 							mark_work_group_restart(group, -1);
236140266059SGregory Neil Shapiro 							continue;
236240266059SGregory Neil Shapiro 						}
236340266059SGregory Neil Shapiro 
236440266059SGregory Neil Shapiro 						sm_syslog(LOG_ERR, NOQID,
236540266059SGregory Neil Shapiro 							  "persistent queue runner=%d died, signal=%d",
236640266059SGregory Neil Shapiro 							  group, WTERMSIG(status));
236740266059SGregory Neil Shapiro 					}
236840266059SGregory Neil Shapiro 
236940266059SGregory Neil Shapiro 					/*
237040266059SGregory Neil Shapiro 					**  When debugging active, don't
237140266059SGregory Neil Shapiro 					**  restart the persistent queues.
237240266059SGregory Neil Shapiro 					**  But do log this as info.
237340266059SGregory Neil Shapiro 					*/
237440266059SGregory Neil Shapiro 
237540266059SGregory Neil Shapiro 					if (sm_debug_active(&DebugNoPRestart,
237640266059SGregory Neil Shapiro 							    1))
237740266059SGregory Neil Shapiro 					{
237840266059SGregory Neil Shapiro 						sm_syslog(LOG_DEBUG, NOQID,
237940266059SGregory Neil Shapiro 							  "persistent queue runner=%d, exited",
238040266059SGregory Neil Shapiro 							  group);
238140266059SGregory Neil Shapiro 						mark_work_group_restart(group, -1);
238240266059SGregory Neil Shapiro 					}
238340266059SGregory Neil Shapiro 				}
238440266059SGregory Neil Shapiro 				finis(true, true, ExitStat);
238540266059SGregory Neil Shapiro 				/* NOTREACHED */
238640266059SGregory Neil Shapiro 			}
238740266059SGregory Neil Shapiro 
2388c2aa98e2SPeter Wemm 			if (OpMode != MD_DAEMON)
2389c2aa98e2SPeter Wemm 			{
239040266059SGregory Neil Shapiro 				char qtype[200];
239140266059SGregory Neil Shapiro 
239240266059SGregory Neil Shapiro 				/*
239340266059SGregory Neil Shapiro 				**  Write the pid to file
239440266059SGregory Neil Shapiro 				**  XXX Overwrites sendmail.pid
239540266059SGregory Neil Shapiro 				*/
239640266059SGregory Neil Shapiro 
239740266059SGregory Neil Shapiro 				log_sendmail_pid(&MainEnvelope);
239840266059SGregory Neil Shapiro 
239940266059SGregory Neil Shapiro 				/* set the title to make it easier to find */
240040266059SGregory Neil Shapiro 				qtype[0] = '\0';
240140266059SGregory Neil Shapiro 				(void) sm_strlcpyn(qtype, sizeof qtype, 4,
240240266059SGregory Neil Shapiro 						   "Queue runner@",
240340266059SGregory Neil Shapiro 						   pintvl(QueueIntvl, true),
240440266059SGregory Neil Shapiro 						   " for ",
240540266059SGregory Neil Shapiro 						   QueueDir);
240640266059SGregory Neil Shapiro 				sm_setproctitle(true, CurEnv, qtype);
2407c2aa98e2SPeter Wemm 				for (;;)
2408c2aa98e2SPeter Wemm 				{
240906f25ae9SGregory Neil Shapiro 					(void) pause();
24108774250cSGregory Neil Shapiro 					if (ShutdownRequest != NULL)
24118774250cSGregory Neil Shapiro 						shutdown_daemon();
241240266059SGregory Neil Shapiro 					else if (RestartRequest != NULL)
241340266059SGregory Neil Shapiro 						restart_daemon();
241440266059SGregory Neil Shapiro 					else if (RestartWorkGroup)
241540266059SGregory Neil Shapiro 						restart_marked_work_groups();
2416c2aa98e2SPeter Wemm 
241740266059SGregory Neil Shapiro 					if (doqueuerun())
241840266059SGregory Neil Shapiro 						(void) runqueue(true, false,
241940266059SGregory Neil Shapiro 								false, false);
242040266059SGregory Neil Shapiro 				}
242140266059SGregory Neil Shapiro 			}
242240266059SGregory Neil Shapiro 		}
242340266059SGregory Neil Shapiro 		dropenvelope(&MainEnvelope, true, false);
242440266059SGregory Neil Shapiro 
242506f25ae9SGregory Neil Shapiro #if STARTTLS
242606f25ae9SGregory Neil Shapiro 		/* init TLS for server, ignore result for now */
242740266059SGregory Neil Shapiro 		(void) initsrvtls(tls_ok);
242806f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
242940266059SGregory Neil Shapiro #if PROFILING
243040266059SGregory Neil Shapiro 	nextreq:
243140266059SGregory Neil Shapiro #endif /* PROFILING */
243240266059SGregory Neil Shapiro 		p_flags = getrequests(&MainEnvelope);
2433c2aa98e2SPeter Wemm 
2434c2aa98e2SPeter Wemm 		/* drop privileges */
243540266059SGregory Neil Shapiro 		(void) drop_privileges(false);
2436c2aa98e2SPeter Wemm 
2437c2aa98e2SPeter Wemm 		/*
2438c2aa98e2SPeter Wemm 		**  Get authentication data
243940266059SGregory Neil Shapiro 		**  Set _ macro in BlankEnvelope before calling newenvelope().
2440c2aa98e2SPeter Wemm 		*/
2441c2aa98e2SPeter Wemm 
244240266059SGregory Neil Shapiro 		authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
244340266059SGregory Neil Shapiro 						     NULL), &forged);
244440266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
244540266059SGregory Neil Shapiro 
244640266059SGregory Neil Shapiro 		/* at this point we are in a child: reset state */
244740266059SGregory Neil Shapiro 		sm_rpool_free(MainEnvelope.e_rpool);
244840266059SGregory Neil Shapiro 		(void) newenvelope(&MainEnvelope, &MainEnvelope,
244940266059SGregory Neil Shapiro 				   sm_rpool_new_x(NULL));
2450c2aa98e2SPeter Wemm 	}
2451c2aa98e2SPeter Wemm 
245206f25ae9SGregory Neil Shapiro 	if (LogLevel > 9)
245306f25ae9SGregory Neil Shapiro 	{
245406f25ae9SGregory Neil Shapiro 		/* log connection information */
245506f25ae9SGregory Neil Shapiro 		sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo);
245606f25ae9SGregory Neil Shapiro 	}
245706f25ae9SGregory Neil Shapiro 
2458c2aa98e2SPeter Wemm 	/*
2459c2aa98e2SPeter Wemm 	**  If running SMTP protocol, start collecting and executing
2460c2aa98e2SPeter Wemm 	**  commands.  This will never return.
2461c2aa98e2SPeter Wemm 	*/
2462c2aa98e2SPeter Wemm 
2463c2aa98e2SPeter Wemm 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2464c2aa98e2SPeter Wemm 	{
2465c2aa98e2SPeter Wemm 		char pbuf[20];
2466c2aa98e2SPeter Wemm 
2467c2aa98e2SPeter Wemm 		/*
2468c2aa98e2SPeter Wemm 		**  Save some macros for check_* rulesets.
2469c2aa98e2SPeter Wemm 		*/
2470c2aa98e2SPeter Wemm 
2471c2aa98e2SPeter Wemm 		if (forged)
2472c2aa98e2SPeter Wemm 		{
2473c2aa98e2SPeter Wemm 			char ipbuf[103];
2474c2aa98e2SPeter Wemm 
247540266059SGregory Neil Shapiro 			(void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
247606f25ae9SGregory Neil Shapiro 					   anynet_ntoa(&RealHostAddr));
247740266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_TEMP,
247840266059SGregory Neil Shapiro 				  macid("{client_name}"), ipbuf);
2479c2aa98e2SPeter Wemm 		}
2480c2aa98e2SPeter Wemm 		else
248140266059SGregory Neil Shapiro 			macdefine(&BlankEnvelope.e_macro, A_PERM,
248240266059SGregory Neil Shapiro 				  macid("{client_name}"), RealHostName);
248340266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
248440266059SGregory Neil Shapiro 			  macid("{client_addr}"), anynet_ntoa(&RealHostAddr));
248540266059SGregory Neil Shapiro 		sm_getla();
2486c2aa98e2SPeter Wemm 
248706f25ae9SGregory Neil Shapiro 		switch (RealHostAddr.sa.sa_family)
248806f25ae9SGregory Neil Shapiro 		{
248906f25ae9SGregory Neil Shapiro #if NETINET
249006f25ae9SGregory Neil Shapiro 		  case AF_INET:
249140266059SGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof pbuf, "%d",
249206f25ae9SGregory Neil Shapiro 					   RealHostAddr.sin.sin_port);
249306f25ae9SGregory Neil Shapiro 			break;
249406f25ae9SGregory Neil Shapiro #endif /* NETINET */
249506f25ae9SGregory Neil Shapiro #if NETINET6
249606f25ae9SGregory Neil Shapiro 		  case AF_INET6:
249740266059SGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof pbuf, "%d",
249806f25ae9SGregory Neil Shapiro 					   RealHostAddr.sin6.sin6_port);
249906f25ae9SGregory Neil Shapiro 			break;
250006f25ae9SGregory Neil Shapiro #endif /* NETINET6 */
250106f25ae9SGregory Neil Shapiro 		  default:
250240266059SGregory Neil Shapiro 			(void) sm_snprintf(pbuf, sizeof pbuf, "0");
250306f25ae9SGregory Neil Shapiro 			break;
250406f25ae9SGregory Neil Shapiro 		}
250540266059SGregory Neil Shapiro 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
250640266059SGregory Neil Shapiro 			macid("{client_port}"), pbuf);
250706f25ae9SGregory Neil Shapiro 
2508c2aa98e2SPeter Wemm 		if (OpMode == MD_DAEMON)
2509c2aa98e2SPeter Wemm 		{
2510c2aa98e2SPeter Wemm 			/* validate the connection */
251140266059SGregory Neil Shapiro 			HoldErrs = true;
2512c2aa98e2SPeter Wemm 			nullserver = validate_connection(&RealHostAddr,
251340266059SGregory Neil Shapiro 							 RealHostName,
251440266059SGregory Neil Shapiro 							 &MainEnvelope);
251540266059SGregory Neil Shapiro 			HoldErrs = false;
2516c2aa98e2SPeter Wemm 		}
251706f25ae9SGregory Neil Shapiro 		else if (p_flags == NULL)
251806f25ae9SGregory Neil Shapiro 		{
251906f25ae9SGregory Neil Shapiro 			p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
252006f25ae9SGregory Neil Shapiro 			clrbitmap(p_flags);
252106f25ae9SGregory Neil Shapiro 		}
252206f25ae9SGregory Neil Shapiro #if STARTTLS
252306f25ae9SGregory Neil Shapiro 		if (OpMode == MD_SMTP)
252440266059SGregory Neil Shapiro 			(void) initsrvtls(tls_ok);
252506f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
2526193538b7SGregory Neil Shapiro 
252740266059SGregory Neil Shapiro 		/* turn off profiling */
252840266059SGregory Neil Shapiro 		SM_PROF(1);
252940266059SGregory Neil Shapiro 		smtp(nullserver, *p_flags, &MainEnvelope);
253040266059SGregory Neil Shapiro #if PROFILING
253140266059SGregory Neil Shapiro 		/* turn off profiling */
253240266059SGregory Neil Shapiro 		SM_PROF(0);
253340266059SGregory Neil Shapiro 		if (OpMode == MD_DAEMON)
253440266059SGregory Neil Shapiro 			goto nextreq;
253540266059SGregory Neil Shapiro #endif /* PROFILING */
2536c2aa98e2SPeter Wemm 	}
2537c2aa98e2SPeter Wemm 
253840266059SGregory Neil Shapiro 	sm_rpool_free(MainEnvelope.e_rpool);
253940266059SGregory Neil Shapiro 	clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));
2540c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
2541c2aa98e2SPeter Wemm 	{
254240266059SGregory Neil Shapiro 		set_delivery_mode(SM_VERIFY, &MainEnvelope);
2543c2aa98e2SPeter Wemm 		PostMasterCopy = NULL;
2544c2aa98e2SPeter Wemm 	}
2545c2aa98e2SPeter Wemm 	else
2546c2aa98e2SPeter Wemm 	{
2547c2aa98e2SPeter Wemm 		/* interactive -- all errors are global */
254840266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
2549c2aa98e2SPeter Wemm 	}
2550c2aa98e2SPeter Wemm 
2551c2aa98e2SPeter Wemm 	/*
2552c2aa98e2SPeter Wemm 	**  Do basic system initialization and set the sender
2553c2aa98e2SPeter Wemm 	*/
2554c2aa98e2SPeter Wemm 
255540266059SGregory Neil Shapiro 	initsys(&MainEnvelope);
255640266059SGregory Neil Shapiro 	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");
255740266059SGregory Neil Shapiro 	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");
255840266059SGregory Neil Shapiro 	setsender(from, &MainEnvelope, NULL, '\0', false);
255906f25ae9SGregory Neil Shapiro 	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
256040266059SGregory Neil Shapiro 	    (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||
256140266059SGregory Neil Shapiro 	     strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))
256206f25ae9SGregory Neil Shapiro 	{
256340266059SGregory Neil Shapiro 		auth_warning(&MainEnvelope, "%s set sender to %s using -%c",
2564c2aa98e2SPeter Wemm 			     RealUserName, from, warn_f_flag);
256506f25ae9SGregory Neil Shapiro #if SASL
256640266059SGregory Neil Shapiro 		auth = false;
256706f25ae9SGregory Neil Shapiro #endif /* SASL */
256806f25ae9SGregory Neil Shapiro 	}
256906f25ae9SGregory Neil Shapiro 	if (auth)
257006f25ae9SGregory Neil Shapiro 	{
257106f25ae9SGregory Neil Shapiro 		char *fv;
257206f25ae9SGregory Neil Shapiro 
257306f25ae9SGregory Neil Shapiro 		/* set the initial sender for AUTH= to $f@$j */
257440266059SGregory Neil Shapiro 		fv = macvalue('f', &MainEnvelope);
257506f25ae9SGregory Neil Shapiro 		if (fv == NULL || *fv == '\0')
257640266059SGregory Neil Shapiro 			MainEnvelope.e_auth_param = NULL;
257706f25ae9SGregory Neil Shapiro 		else
257806f25ae9SGregory Neil Shapiro 		{
257906f25ae9SGregory Neil Shapiro 			if (strchr(fv, '@') == NULL)
258006f25ae9SGregory Neil Shapiro 			{
258140266059SGregory Neil Shapiro 				i = strlen(fv) + strlen(macvalue('j',
258240266059SGregory Neil Shapiro 							&MainEnvelope)) + 2;
258340266059SGregory Neil Shapiro 				p = sm_malloc_x(i);
258440266059SGregory Neil Shapiro 				(void) sm_strlcpyn(p, i, 3, fv, "@",
258540266059SGregory Neil Shapiro 						   macvalue('j',
258640266059SGregory Neil Shapiro 							    &MainEnvelope));
258706f25ae9SGregory Neil Shapiro 			}
258806f25ae9SGregory Neil Shapiro 			else
258940266059SGregory Neil Shapiro 				p = sm_strdup_x(fv);
259040266059SGregory Neil Shapiro 			MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,
259140266059SGregory Neil Shapiro 								      xtextify(p, "="));
259240266059SGregory Neil Shapiro 			sm_free(p);  /* XXX */
259306f25ae9SGregory Neil Shapiro 		}
259406f25ae9SGregory Neil Shapiro 	}
259540266059SGregory Neil Shapiro 	if (macvalue('s', &MainEnvelope) == NULL)
259640266059SGregory Neil Shapiro 		macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);
2597c2aa98e2SPeter Wemm 
259840266059SGregory Neil Shapiro 	av = argv + optind;
2599c2aa98e2SPeter Wemm 	if (*av == NULL && !GrabTo)
2600c2aa98e2SPeter Wemm 	{
260140266059SGregory Neil Shapiro 		MainEnvelope.e_to = NULL;
260240266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS;
260340266059SGregory Neil Shapiro 		HoldErrs = false;
260440266059SGregory Neil Shapiro 		SuperSafe = SAFE_NO;
2605c2aa98e2SPeter Wemm 		usrerr("Recipient names must be specified");
2606c2aa98e2SPeter Wemm 
2607c2aa98e2SPeter Wemm 		/* collect body for UUCP return */
2608c2aa98e2SPeter Wemm 		if (OpMode != MD_VERIFY)
260940266059SGregory Neil Shapiro 			collect(InChannel, false, NULL, &MainEnvelope);
261040266059SGregory Neil Shapiro 		finis(true, true, EX_USAGE);
261140266059SGregory Neil Shapiro 		/* NOTREACHED */
2612c2aa98e2SPeter Wemm 	}
2613c2aa98e2SPeter Wemm 
2614c2aa98e2SPeter Wemm 	/*
2615c2aa98e2SPeter Wemm 	**  Scan argv and deliver the message to everyone.
2616c2aa98e2SPeter Wemm 	*/
2617c2aa98e2SPeter Wemm 
261840266059SGregory Neil Shapiro 	save_val = LogUsrErrs;
261940266059SGregory Neil Shapiro 	LogUsrErrs = true;
262040266059SGregory Neil Shapiro 	sendtoargv(av, &MainEnvelope);
262140266059SGregory Neil Shapiro 	LogUsrErrs = save_val;
2622c2aa98e2SPeter Wemm 
2623c2aa98e2SPeter Wemm 	/* if we have had errors sofar, arrange a meaningful exit stat */
2624c2aa98e2SPeter Wemm 	if (Errors > 0 && ExitStat == EX_OK)
2625c2aa98e2SPeter Wemm 		ExitStat = EX_USAGE;
2626c2aa98e2SPeter Wemm 
2627c2aa98e2SPeter Wemm #if _FFR_FIX_DASHT
2628c2aa98e2SPeter Wemm 	/*
2629c2aa98e2SPeter Wemm 	**  If using -t, force not sending to argv recipients, even
2630c2aa98e2SPeter Wemm 	**  if they are mentioned in the headers.
2631c2aa98e2SPeter Wemm 	*/
2632c2aa98e2SPeter Wemm 
2633c2aa98e2SPeter Wemm 	if (GrabTo)
2634c2aa98e2SPeter Wemm 	{
2635c2aa98e2SPeter Wemm 		ADDRESS *q;
2636c2aa98e2SPeter Wemm 
263740266059SGregory Neil Shapiro 		for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)
263806f25ae9SGregory Neil Shapiro 			q->q_state = QS_REMOVED;
2639c2aa98e2SPeter Wemm 	}
264006f25ae9SGregory Neil Shapiro #endif /* _FFR_FIX_DASHT */
2641c2aa98e2SPeter Wemm 
2642c2aa98e2SPeter Wemm 	/*
2643c2aa98e2SPeter Wemm 	**  Read the input mail.
2644c2aa98e2SPeter Wemm 	*/
2645c2aa98e2SPeter Wemm 
264640266059SGregory Neil Shapiro 	MainEnvelope.e_to = NULL;
2647c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY || GrabTo)
2648c2aa98e2SPeter Wemm 	{
264940266059SGregory Neil Shapiro 		int savederrors;
265040266059SGregory Neil Shapiro 		unsigned long savedflags;
2651c2aa98e2SPeter Wemm 
265240266059SGregory Neil Shapiro 		/*
265340266059SGregory Neil Shapiro 		**  workaround for compiler warning on Irix:
265440266059SGregory Neil Shapiro 		**  do not initialize variable in the definition, but
265540266059SGregory Neil Shapiro 		**  later on:
265640266059SGregory Neil Shapiro 		**  warning(1548): transfer of control bypasses
265740266059SGregory Neil Shapiro 		**  initialization of:
265840266059SGregory Neil Shapiro 		**  variable "savederrors" (declared at line 2570)
265940266059SGregory Neil Shapiro 		**  variable "savedflags" (declared at line 2571)
266040266059SGregory Neil Shapiro 		**  goto giveup;
266140266059SGregory Neil Shapiro 		*/
266240266059SGregory Neil Shapiro 
266340266059SGregory Neil Shapiro 		savederrors = Errors;
266440266059SGregory Neil Shapiro 		savedflags = MainEnvelope.e_flags & EF_FATALERRS;
266540266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= EF_GLOBALERRS;
266640266059SGregory Neil Shapiro 		MainEnvelope.e_flags &= ~EF_FATALERRS;
266706f25ae9SGregory Neil Shapiro 		Errors = 0;
266806f25ae9SGregory Neil Shapiro 		buffer_errors();
266940266059SGregory Neil Shapiro 		collect(InChannel, false, NULL, &MainEnvelope);
2670c2aa98e2SPeter Wemm 
267106f25ae9SGregory Neil Shapiro 		/* header checks failed */
267206f25ae9SGregory Neil Shapiro 		if (Errors > 0)
2673c2aa98e2SPeter Wemm 		{
267440266059SGregory Neil Shapiro   giveup:
267540266059SGregory Neil Shapiro 			if (!GrabTo)
267640266059SGregory Neil Shapiro 			{
267706f25ae9SGregory Neil Shapiro 				/* Log who the mail would have gone to */
267840266059SGregory Neil Shapiro 				logundelrcpts(&MainEnvelope,
267940266059SGregory Neil Shapiro 					      MainEnvelope.e_message,
268040266059SGregory Neil Shapiro 					      8, false);
268106f25ae9SGregory Neil Shapiro 			}
268240266059SGregory Neil Shapiro 			flush_errors(true);
268340266059SGregory Neil Shapiro 			finis(true, true, ExitStat);
2684c2aa98e2SPeter Wemm 			/* NOTREACHED */
2685c2aa98e2SPeter Wemm 			return -1;
2686c2aa98e2SPeter Wemm 		}
268706f25ae9SGregory Neil Shapiro 
268806f25ae9SGregory Neil Shapiro 		/* bail out if message too large */
268940266059SGregory Neil Shapiro 		if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))
269006f25ae9SGregory Neil Shapiro 		{
269140266059SGregory Neil Shapiro 			finis(true, true, ExitStat != EX_OK ? ExitStat
269240266059SGregory Neil Shapiro 							    : EX_DATAERR);
269306f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
269406f25ae9SGregory Neil Shapiro 			return -1;
269506f25ae9SGregory Neil Shapiro 		}
269606f25ae9SGregory Neil Shapiro 		Errors = savederrors;
269740266059SGregory Neil Shapiro 		MainEnvelope.e_flags |= savedflags;
2698c2aa98e2SPeter Wemm 	}
2699c2aa98e2SPeter Wemm 	errno = 0;
2700c2aa98e2SPeter Wemm 
2701c2aa98e2SPeter Wemm 	if (tTd(1, 1))
270240266059SGregory Neil Shapiro 		sm_dprintf("From person = \"%s\"\n",
270340266059SGregory Neil Shapiro 			   MainEnvelope.e_from.q_paddr);
270440266059SGregory Neil Shapiro 
270540266059SGregory Neil Shapiro #if _FFR_QUARANTINE
270640266059SGregory Neil Shapiro 	/* Check if quarantining stats should be updated */
270740266059SGregory Neil Shapiro 	if (MainEnvelope.e_quarmsg != NULL)
270840266059SGregory Neil Shapiro 		markstats(&MainEnvelope, NULL, STATS_QUARANTINE);
270940266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
2710c2aa98e2SPeter Wemm 
2711c2aa98e2SPeter Wemm 	/*
2712c2aa98e2SPeter Wemm 	**  Actually send everything.
2713c2aa98e2SPeter Wemm 	**	If verifying, just ack.
2714c2aa98e2SPeter Wemm 	*/
2715c2aa98e2SPeter Wemm 
271640266059SGregory Neil Shapiro 	if (Errors == 0)
271740266059SGregory Neil Shapiro 	{
271840266059SGregory Neil Shapiro 		if (!split_by_recipient(&MainEnvelope) &&
271940266059SGregory Neil Shapiro 		    bitset(EF_FATALERRS, MainEnvelope.e_flags))
272040266059SGregory Neil Shapiro 			goto giveup;
272140266059SGregory Neil Shapiro 	}
272240266059SGregory Neil Shapiro 
272340266059SGregory Neil Shapiro 	/* make sure we deliver at least the first envelope */
272440266059SGregory Neil Shapiro 	i = FastSplit > 0 ? 0 : -1;
272540266059SGregory Neil Shapiro 	for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)
272640266059SGregory Neil Shapiro 	{
272740266059SGregory Neil Shapiro 		ENVELOPE *next;
272840266059SGregory Neil Shapiro 
272940266059SGregory Neil Shapiro 		e->e_from.q_state = QS_SENDER;
2730c2aa98e2SPeter Wemm 		if (tTd(1, 5))
2731c2aa98e2SPeter Wemm 		{
273240266059SGregory Neil Shapiro 			sm_dprintf("main[%d]: QS_SENDER ", i);
273340266059SGregory Neil Shapiro 			printaddr(&e->e_from, false);
2734c2aa98e2SPeter Wemm 		}
273540266059SGregory Neil Shapiro 		e->e_to = NULL;
273640266059SGregory Neil Shapiro 		sm_getla();
273740266059SGregory Neil Shapiro 		GrabTo = false;
273806f25ae9SGregory Neil Shapiro #if NAMED_BIND
273906f25ae9SGregory Neil Shapiro 		_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
274006f25ae9SGregory Neil Shapiro 		_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
274106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
274240266059SGregory Neil Shapiro 		next = e->e_sibling;
274340266059SGregory Neil Shapiro 		e->e_sibling = NULL;
274440266059SGregory Neil Shapiro 
274540266059SGregory Neil Shapiro 		/* after FastSplit envelopes: queue up */
274640266059SGregory Neil Shapiro 		sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);
274740266059SGregory Neil Shapiro 		e->e_sibling = next;
274840266059SGregory Neil Shapiro 	}
2749c2aa98e2SPeter Wemm 
2750c2aa98e2SPeter Wemm 	/*
2751c2aa98e2SPeter Wemm 	**  All done.
2752c2aa98e2SPeter Wemm 	**	Don't send return error message if in VERIFY mode.
2753c2aa98e2SPeter Wemm 	*/
2754c2aa98e2SPeter Wemm 
275540266059SGregory Neil Shapiro 	finis(true, true, ExitStat);
2756c2aa98e2SPeter Wemm 	/* NOTREACHED */
275706f25ae9SGregory Neil Shapiro 	return ExitStat;
2758c2aa98e2SPeter Wemm }
275940266059SGregory Neil Shapiro /*
27608774250cSGregory Neil Shapiro **  STOP_SENDMAIL -- Stop the running program
27618774250cSGregory Neil Shapiro **
27628774250cSGregory Neil Shapiro **	Parameters:
27638774250cSGregory Neil Shapiro **		none.
27648774250cSGregory Neil Shapiro **
27658774250cSGregory Neil Shapiro **	Returns:
27668774250cSGregory Neil Shapiro **		none.
27678774250cSGregory Neil Shapiro **
27688774250cSGregory Neil Shapiro **	Side Effects:
27698774250cSGregory Neil Shapiro **		exits.
27708774250cSGregory Neil Shapiro */
27718774250cSGregory Neil Shapiro 
27728774250cSGregory Neil Shapiro void
27738774250cSGregory Neil Shapiro stop_sendmail()
27748774250cSGregory Neil Shapiro {
27758774250cSGregory Neil Shapiro 	/* reset uid for process accounting */
27768774250cSGregory Neil Shapiro 	endpwent();
27778774250cSGregory Neil Shapiro 	(void) setuid(RealUid);
27788774250cSGregory Neil Shapiro 	exit(EX_OK);
2779065a643dSPeter Wemm }
278040266059SGregory Neil Shapiro /*
278140266059SGregory Neil Shapiro **  FINIS -- Clean up and exit.
278240266059SGregory Neil Shapiro **
278340266059SGregory Neil Shapiro **	Parameters:
278440266059SGregory Neil Shapiro **		drop -- whether or not to drop CurEnv envelope
278540266059SGregory Neil Shapiro **		cleanup -- call exit() or _exit()?
278640266059SGregory Neil Shapiro **		exitstat -- exit status to use for exit() call
278740266059SGregory Neil Shapiro **
278840266059SGregory Neil Shapiro **	Returns:
278940266059SGregory Neil Shapiro **		never
279040266059SGregory Neil Shapiro **
279140266059SGregory Neil Shapiro **	Side Effects:
279240266059SGregory Neil Shapiro **		exits sendmail
279340266059SGregory Neil Shapiro */
2794c2aa98e2SPeter Wemm 
279540266059SGregory Neil Shapiro void
279640266059SGregory Neil Shapiro finis(drop, cleanup, exitstat)
279740266059SGregory Neil Shapiro 	bool drop;
279840266059SGregory Neil Shapiro 	bool cleanup;
279940266059SGregory Neil Shapiro 	volatile int exitstat;
280040266059SGregory Neil Shapiro {
280140266059SGregory Neil Shapiro 	/* Still want to process new timeouts added below */
280240266059SGregory Neil Shapiro 	sm_clear_events();
280340266059SGregory Neil Shapiro 	(void) sm_releasesignal(SIGALRM);
280440266059SGregory Neil Shapiro 
280540266059SGregory Neil Shapiro 	if (tTd(2, 1))
280640266059SGregory Neil Shapiro 	{
280740266059SGregory Neil Shapiro 		sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
280840266059SGregory Neil Shapiro 			   exitstat,
280940266059SGregory Neil Shapiro 			   CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
281040266059SGregory Neil Shapiro 		printenvflags(CurEnv);
281140266059SGregory Neil Shapiro 	}
281240266059SGregory Neil Shapiro 	if (tTd(2, 9))
281340266059SGregory Neil Shapiro 		printopenfds(false);
281440266059SGregory Neil Shapiro 
281540266059SGregory Neil Shapiro 	SM_TRY
281640266059SGregory Neil Shapiro 		/*
281740266059SGregory Neil Shapiro 		**  Clean up.  This might raise E:mta.quickabort
281840266059SGregory Neil Shapiro 		*/
281940266059SGregory Neil Shapiro 
282040266059SGregory Neil Shapiro 		/* clean up temp files */
282140266059SGregory Neil Shapiro 		CurEnv->e_to = NULL;
282240266059SGregory Neil Shapiro 		if (drop)
282340266059SGregory Neil Shapiro 		{
282440266059SGregory Neil Shapiro 			if (CurEnv->e_id != NULL)
282540266059SGregory Neil Shapiro 			{
282640266059SGregory Neil Shapiro 				dropenvelope(CurEnv, true, false);
282740266059SGregory Neil Shapiro 				sm_rpool_free(CurEnv->e_rpool);
282840266059SGregory Neil Shapiro 				CurEnv->e_rpool = NULL;
282940266059SGregory Neil Shapiro 			}
283040266059SGregory Neil Shapiro 			else
283140266059SGregory Neil Shapiro 				poststats(StatFile);
283240266059SGregory Neil Shapiro 		}
283340266059SGregory Neil Shapiro 
283440266059SGregory Neil Shapiro 		/* flush any cached connections */
283540266059SGregory Neil Shapiro 		mci_flush(true, NULL);
283640266059SGregory Neil Shapiro 
283740266059SGregory Neil Shapiro 		/* close maps belonging to this pid */
283840266059SGregory Neil Shapiro 		closemaps(false);
283940266059SGregory Neil Shapiro 
284040266059SGregory Neil Shapiro #if USERDB
284140266059SGregory Neil Shapiro 		/* close UserDatabase */
284240266059SGregory Neil Shapiro 		_udbx_close();
284340266059SGregory Neil Shapiro #endif /* USERDB */
284440266059SGregory Neil Shapiro 
284540266059SGregory Neil Shapiro #if SASL
284640266059SGregory Neil Shapiro 		stop_sasl_client();
284740266059SGregory Neil Shapiro #endif /* SASL */
284840266059SGregory Neil Shapiro 
284940266059SGregory Neil Shapiro #if XLA
285040266059SGregory Neil Shapiro 		/* clean up extended load average stuff */
285140266059SGregory Neil Shapiro 		xla_all_end();
285240266059SGregory Neil Shapiro #endif /* XLA */
285340266059SGregory Neil Shapiro 
285440266059SGregory Neil Shapiro 	SM_FINALLY
285540266059SGregory Neil Shapiro 		/*
285640266059SGregory Neil Shapiro 		**  And exit.
285740266059SGregory Neil Shapiro 		*/
285840266059SGregory Neil Shapiro 
285940266059SGregory Neil Shapiro 		if (LogLevel > 78)
286040266059SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",
286140266059SGregory Neil Shapiro 				  (int) CurrentPid);
286240266059SGregory Neil Shapiro 		if (exitstat == EX_TEMPFAIL ||
286340266059SGregory Neil Shapiro 		    CurEnv->e_errormode == EM_BERKNET)
286440266059SGregory Neil Shapiro 			exitstat = EX_OK;
286540266059SGregory Neil Shapiro 
286640266059SGregory Neil Shapiro 		/* XXX clean up queues and related data structures */
286740266059SGregory Neil Shapiro 		cleanup_queues();
286840266059SGregory Neil Shapiro #if SM_CONF_SHM
286940266059SGregory Neil Shapiro 		cleanup_shm(DaemonPid == getpid());
287040266059SGregory Neil Shapiro #endif /* SM_CONF_SHM */
287140266059SGregory Neil Shapiro 
287240266059SGregory Neil Shapiro 		/* reset uid for process accounting */
287340266059SGregory Neil Shapiro 		endpwent();
287440266059SGregory Neil Shapiro 		sm_mbdb_terminate();
287540266059SGregory Neil Shapiro 		(void) setuid(RealUid);
287640266059SGregory Neil Shapiro #if SM_HEAP_CHECK
287740266059SGregory Neil Shapiro 		/* dump the heap, if we are checking for memory leaks */
287840266059SGregory Neil Shapiro 		if (sm_debug_active(&SmHeapCheck, 2))
287940266059SGregory Neil Shapiro 			sm_heap_report(smioout,
288040266059SGregory Neil Shapiro 				       sm_debug_level(&SmHeapCheck) - 1);
288140266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
288240266059SGregory Neil Shapiro 		if (sm_debug_active(&SmXtrapReport, 1))
288340266059SGregory Neil Shapiro 			sm_dprintf("xtrap count = %d\n", SmXtrapCount);
288440266059SGregory Neil Shapiro 		if (cleanup)
288540266059SGregory Neil Shapiro 			exit(exitstat);
288640266059SGregory Neil Shapiro 		else
288740266059SGregory Neil Shapiro 			_exit(exitstat);
288840266059SGregory Neil Shapiro 	SM_END_TRY
288940266059SGregory Neil Shapiro }
289040266059SGregory Neil Shapiro /*
28918774250cSGregory Neil Shapiro **  INTINDEBUG -- signal handler for SIGINT in -bt mode
28928774250cSGregory Neil Shapiro **
28938774250cSGregory Neil Shapiro **	Parameters:
28948774250cSGregory Neil Shapiro **		sig -- incoming signal.
28958774250cSGregory Neil Shapiro **
28968774250cSGregory Neil Shapiro **	Returns:
28978774250cSGregory Neil Shapiro **		none.
28988774250cSGregory Neil Shapiro **
28998774250cSGregory Neil Shapiro **	Side Effects:
29008774250cSGregory Neil Shapiro **		longjmps back to test mode loop.
29018774250cSGregory Neil Shapiro **
29028774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
29038774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
29048774250cSGregory Neil Shapiro **		DOING.
29058774250cSGregory Neil Shapiro */
29068774250cSGregory Neil Shapiro 
290740266059SGregory Neil Shapiro /* Type of an exception generated on SIGINT during address test mode.  */
290840266059SGregory Neil Shapiro static const SM_EXC_TYPE_T EtypeInterrupt =
290940266059SGregory Neil Shapiro {
291040266059SGregory Neil Shapiro 	SmExcTypeMagic,
291140266059SGregory Neil Shapiro 	"S:mta.interrupt",
291240266059SGregory Neil Shapiro 	"",
291340266059SGregory Neil Shapiro 	sm_etype_printf,
291440266059SGregory Neil Shapiro 	"interrupt",
291540266059SGregory Neil Shapiro };
291640266059SGregory Neil Shapiro 
2917c2aa98e2SPeter Wemm /* ARGSUSED */
29188774250cSGregory Neil Shapiro static SIGFUNC_DECL
2919c2aa98e2SPeter Wemm intindebug(sig)
2920c2aa98e2SPeter Wemm 	int sig;
2921c2aa98e2SPeter Wemm {
29228774250cSGregory Neil Shapiro 	int save_errno = errno;
29238774250cSGregory Neil Shapiro 
29248774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, intindebug);
29258774250cSGregory Neil Shapiro 	errno = save_errno;
29268774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
29278774250cSGregory Neil Shapiro 	errno = save_errno;
292840266059SGregory Neil Shapiro 	sm_exc_raisenew_x(&EtypeInterrupt);
292940266059SGregory Neil Shapiro 	errno = save_errno;
2930c2aa98e2SPeter Wemm 	return SIGFUNC_RETURN;
2931c2aa98e2SPeter Wemm }
293240266059SGregory Neil Shapiro /*
293340266059SGregory Neil Shapiro **  SIGTERM -- SIGTERM handler for the daemon
29348774250cSGregory Neil Shapiro **
29358774250cSGregory Neil Shapiro **	Parameters:
29368774250cSGregory Neil Shapiro **		sig -- signal number.
29378774250cSGregory Neil Shapiro **
29388774250cSGregory Neil Shapiro **	Returns:
29398774250cSGregory Neil Shapiro **		none.
29408774250cSGregory Neil Shapiro **
29418774250cSGregory Neil Shapiro **	Side Effects:
29428774250cSGregory Neil Shapiro **		Sets ShutdownRequest which will hopefully trigger
29438774250cSGregory Neil Shapiro **		the daemon to exit.
29448774250cSGregory Neil Shapiro **
29458774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
29468774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
29478774250cSGregory Neil Shapiro **		DOING.
29488774250cSGregory Neil Shapiro */
29498774250cSGregory Neil Shapiro 
29508774250cSGregory Neil Shapiro /* ARGSUSED */
29518774250cSGregory Neil Shapiro static SIGFUNC_DECL
295240266059SGregory Neil Shapiro sigterm(sig)
29538774250cSGregory Neil Shapiro 	int sig;
29548774250cSGregory Neil Shapiro {
29558774250cSGregory Neil Shapiro 	int save_errno = errno;
29568774250cSGregory Neil Shapiro 
295740266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigterm);
29588774250cSGregory Neil Shapiro 	ShutdownRequest = "signal";
29598774250cSGregory Neil Shapiro 	errno = save_errno;
29608774250cSGregory Neil Shapiro 	return SIGFUNC_RETURN;
29618774250cSGregory Neil Shapiro }
296240266059SGregory Neil Shapiro /*
296340266059SGregory Neil Shapiro **  SIGHUP -- handle a SIGHUP signal
29648774250cSGregory Neil Shapiro **
29658774250cSGregory Neil Shapiro **	Parameters:
296640266059SGregory Neil Shapiro **		sig -- incoming signal.
29678774250cSGregory Neil Shapiro **
29688774250cSGregory Neil Shapiro **	Returns:
29698774250cSGregory Neil Shapiro **		none.
29708774250cSGregory Neil Shapiro **
29718774250cSGregory Neil Shapiro **	Side Effects:
297240266059SGregory Neil Shapiro **		Sets RestartRequest which should cause the daemon
297340266059SGregory Neil Shapiro **		to restart.
297440266059SGregory Neil Shapiro **
297540266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
297640266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
297740266059SGregory Neil Shapiro **		DOING.
29788774250cSGregory Neil Shapiro */
29798774250cSGregory Neil Shapiro 
298040266059SGregory Neil Shapiro /* ARGSUSED */
298140266059SGregory Neil Shapiro static SIGFUNC_DECL
298240266059SGregory Neil Shapiro sighup(sig)
298340266059SGregory Neil Shapiro 	int sig;
29848774250cSGregory Neil Shapiro {
298540266059SGregory Neil Shapiro 	int save_errno = errno;
29868774250cSGregory Neil Shapiro 
298740266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sighup);
298840266059SGregory Neil Shapiro 	RestartRequest = "signal";
298940266059SGregory Neil Shapiro 	errno = save_errno;
299040266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
29918774250cSGregory Neil Shapiro }
299240266059SGregory Neil Shapiro /*
299340266059SGregory Neil Shapiro **  SIGPIPE -- signal handler for SIGPIPE
299440266059SGregory Neil Shapiro **
299540266059SGregory Neil Shapiro **	Parameters:
299640266059SGregory Neil Shapiro **		sig -- incoming signal.
299740266059SGregory Neil Shapiro **
299840266059SGregory Neil Shapiro **	Returns:
299940266059SGregory Neil Shapiro **		none.
300040266059SGregory Neil Shapiro **
300140266059SGregory Neil Shapiro **	Side Effects:
300240266059SGregory Neil Shapiro **		Sets StopRequest which should cause the mailq/hoststatus
300340266059SGregory Neil Shapiro **		display to stop.
300440266059SGregory Neil Shapiro **
300540266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
300640266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
300740266059SGregory Neil Shapiro **		DOING.
300840266059SGregory Neil Shapiro */
300940266059SGregory Neil Shapiro 
301040266059SGregory Neil Shapiro /* ARGSUSED */
301140266059SGregory Neil Shapiro static SIGFUNC_DECL
301240266059SGregory Neil Shapiro sigpipe(sig)
301340266059SGregory Neil Shapiro 	int sig;
301440266059SGregory Neil Shapiro {
301540266059SGregory Neil Shapiro 	int save_errno = errno;
301640266059SGregory Neil Shapiro 
301740266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigpipe);
301840266059SGregory Neil Shapiro 	StopRequest = true;
301940266059SGregory Neil Shapiro 	errno = save_errno;
302040266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
302140266059SGregory Neil Shapiro }
302240266059SGregory Neil Shapiro /*
3023c2aa98e2SPeter Wemm **  INTSIG -- clean up on interrupt
3024c2aa98e2SPeter Wemm **
302506f25ae9SGregory Neil Shapiro **	This just arranges to exit.  It pessimizes in that it
3026c2aa98e2SPeter Wemm **	may resend a message.
3027c2aa98e2SPeter Wemm **
3028c2aa98e2SPeter Wemm **	Parameters:
3029c2aa98e2SPeter Wemm **		none.
3030c2aa98e2SPeter Wemm **
3031c2aa98e2SPeter Wemm **	Returns:
3032c2aa98e2SPeter Wemm **		none.
3033c2aa98e2SPeter Wemm **
3034c2aa98e2SPeter Wemm **	Side Effects:
3035c2aa98e2SPeter Wemm **		Unlocks the current job.
30368774250cSGregory Neil Shapiro **
30378774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
30388774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
30398774250cSGregory Neil Shapiro **		DOING.
30408774250cSGregory Neil Shapiro **
30418774250cSGregory Neil Shapiro **		XXX: More work is needed for this signal handler.
3042c2aa98e2SPeter Wemm */
3043c2aa98e2SPeter Wemm 
3044c2aa98e2SPeter Wemm /* ARGSUSED */
3045c2aa98e2SPeter Wemm SIGFUNC_DECL
3046c2aa98e2SPeter Wemm intsig(sig)
3047c2aa98e2SPeter Wemm 	int sig;
3048c2aa98e2SPeter Wemm {
304940266059SGregory Neil Shapiro 	bool drop = false;
30508774250cSGregory Neil Shapiro 	int save_errno = errno;
305106f25ae9SGregory Neil Shapiro 
30528774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, intsig);
30538774250cSGregory Neil Shapiro 	errno = save_errno;
30548774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
305540266059SGregory Neil Shapiro 	sm_allsignals(true);
305640266059SGregory Neil Shapiro 
305706f25ae9SGregory Neil Shapiro 	if (sig != 0 && LogLevel > 79)
3058c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
3059c2aa98e2SPeter Wemm 	FileName = NULL;
306006f25ae9SGregory Neil Shapiro 
306106f25ae9SGregory Neil Shapiro 	/* Clean-up on aborted stdin message submission */
306206f25ae9SGregory Neil Shapiro 	if (CurEnv->e_id != NULL &&
306306f25ae9SGregory Neil Shapiro 	    (OpMode == MD_SMTP ||
306406f25ae9SGregory Neil Shapiro 	     OpMode == MD_DELIVER ||
306506f25ae9SGregory Neil Shapiro 	     OpMode == MD_ARPAFTP))
306606f25ae9SGregory Neil Shapiro 	{
306706f25ae9SGregory Neil Shapiro 		register ADDRESS *q;
306806f25ae9SGregory Neil Shapiro 
306906f25ae9SGregory Neil Shapiro 		/* don't return an error indication */
307006f25ae9SGregory Neil Shapiro 		CurEnv->e_to = NULL;
307106f25ae9SGregory Neil Shapiro 		CurEnv->e_flags &= ~EF_FATALERRS;
307206f25ae9SGregory Neil Shapiro 		CurEnv->e_flags |= EF_CLRQUEUE;
307306f25ae9SGregory Neil Shapiro 
307406f25ae9SGregory Neil Shapiro 		/*
307506f25ae9SGregory Neil Shapiro 		**  Spin through the addresses and
307606f25ae9SGregory Neil Shapiro 		**  mark them dead to prevent bounces
307706f25ae9SGregory Neil Shapiro 		*/
307806f25ae9SGregory Neil Shapiro 
307906f25ae9SGregory Neil Shapiro 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
308006f25ae9SGregory Neil Shapiro 			q->q_state = QS_DONTSEND;
308106f25ae9SGregory Neil Shapiro 
308240266059SGregory Neil Shapiro 		drop = true;
308306f25ae9SGregory Neil Shapiro 	}
308413058a91SGregory Neil Shapiro 	else if (OpMode != MD_TEST)
308540266059SGregory Neil Shapiro 	{
308606f25ae9SGregory Neil Shapiro 		unlockqueue(CurEnv);
3087c2aa98e2SPeter Wemm 	}
3088c2aa98e2SPeter Wemm 
308940266059SGregory Neil Shapiro 	finis(drop, false, EX_OK);
309040266059SGregory Neil Shapiro 	/* NOTREACHED */
3091c2aa98e2SPeter Wemm }
309240266059SGregory Neil Shapiro /*
3093c2aa98e2SPeter Wemm **  DISCONNECT -- remove our connection with any foreground process
3094c2aa98e2SPeter Wemm **
3095c2aa98e2SPeter Wemm **	Parameters:
3096c2aa98e2SPeter Wemm **		droplev -- how "deeply" we should drop the line.
3097c2aa98e2SPeter Wemm **			0 -- ignore signals, mail back errors, make sure
3098c2aa98e2SPeter Wemm **			     output goes to stdout.
309906f25ae9SGregory Neil Shapiro **			1 -- also, make stdout go to /dev/null.
3100c2aa98e2SPeter Wemm **			2 -- also, disconnect from controlling terminal
3101c2aa98e2SPeter Wemm **			     (only for daemon mode).
3102c2aa98e2SPeter Wemm **		e -- the current envelope.
3103c2aa98e2SPeter Wemm **
3104c2aa98e2SPeter Wemm **	Returns:
3105c2aa98e2SPeter Wemm **		none
3106c2aa98e2SPeter Wemm **
3107c2aa98e2SPeter Wemm **	Side Effects:
3108c2aa98e2SPeter Wemm **		Trys to insure that we are immune to vagaries of
3109c2aa98e2SPeter Wemm **		the controlling tty.
3110c2aa98e2SPeter Wemm */
3111c2aa98e2SPeter Wemm 
3112c2aa98e2SPeter Wemm void
3113c2aa98e2SPeter Wemm disconnect(droplev, e)
3114c2aa98e2SPeter Wemm 	int droplev;
3115c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3116c2aa98e2SPeter Wemm {
3117c2aa98e2SPeter Wemm 	int fd;
3118c2aa98e2SPeter Wemm 
3119c2aa98e2SPeter Wemm 	if (tTd(52, 1))
312040266059SGregory Neil Shapiro 		sm_dprintf("disconnect: In %d Out %d, e=%p\n",
312140266059SGregory Neil Shapiro 			   sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
312240266059SGregory Neil Shapiro 			   sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);
3123c2aa98e2SPeter Wemm 	if (tTd(52, 100))
3124c2aa98e2SPeter Wemm 	{
312540266059SGregory Neil Shapiro 		sm_dprintf("don't\n");
3126c2aa98e2SPeter Wemm 		return;
3127c2aa98e2SPeter Wemm 	}
3128c2aa98e2SPeter Wemm 	if (LogLevel > 93)
3129c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, e->e_id,
3130c2aa98e2SPeter Wemm 			  "disconnect level %d",
3131c2aa98e2SPeter Wemm 			  droplev);
3132c2aa98e2SPeter Wemm 
3133c2aa98e2SPeter Wemm 	/* be sure we don't get nasty signals */
313440266059SGregory Neil Shapiro 	(void) sm_signal(SIGINT, SIG_IGN);
313540266059SGregory Neil Shapiro 	(void) sm_signal(SIGQUIT, SIG_IGN);
3136c2aa98e2SPeter Wemm 
3137c2aa98e2SPeter Wemm 	/* we can't communicate with our caller, so.... */
313840266059SGregory Neil Shapiro 	HoldErrs = true;
3139c2aa98e2SPeter Wemm 	CurEnv->e_errormode = EM_MAIL;
3140c2aa98e2SPeter Wemm 	Verbose = 0;
314140266059SGregory Neil Shapiro 	DisConnected = true;
3142c2aa98e2SPeter Wemm 
3143c2aa98e2SPeter Wemm 	/* all input from /dev/null */
314440266059SGregory Neil Shapiro 	if (InChannel != smioin)
3145c2aa98e2SPeter Wemm 	{
314640266059SGregory Neil Shapiro 		(void) sm_io_close(InChannel, SM_TIME_DEFAULT);
314740266059SGregory Neil Shapiro 		InChannel = smioin;
3148c2aa98e2SPeter Wemm 	}
314940266059SGregory Neil Shapiro 	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
315040266059SGregory Neil Shapiro 			 SM_IO_RDONLY, NULL, smioin) == NULL)
3151c2aa98e2SPeter Wemm 		sm_syslog(LOG_ERR, e->e_id,
315240266059SGregory Neil Shapiro 			  "disconnect: sm_io_reopen(\"%s\") failed: %s",
315340266059SGregory Neil Shapiro 			  SM_PATH_DEVNULL, sm_errstring(errno));
3154c2aa98e2SPeter Wemm 
315540266059SGregory Neil Shapiro 	/*
315640266059SGregory Neil Shapiro 	**  output to the transcript
315740266059SGregory Neil Shapiro 	**	We also compare the fd numbers here since OutChannel
315840266059SGregory Neil Shapiro 	**	might be a layer on top of smioout due to encryption
315940266059SGregory Neil Shapiro 	**	(see sfsasl.c).
316040266059SGregory Neil Shapiro 	*/
316140266059SGregory Neil Shapiro 
316240266059SGregory Neil Shapiro 	if (OutChannel != smioout &&
316340266059SGregory Neil Shapiro 	    sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=
316440266059SGregory Neil Shapiro 	    sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))
3165c2aa98e2SPeter Wemm 	{
316640266059SGregory Neil Shapiro 		(void) sm_io_close(OutChannel, SM_TIME_DEFAULT);
316740266059SGregory Neil Shapiro 		OutChannel = smioout;
316840266059SGregory Neil Shapiro 
316940266059SGregory Neil Shapiro #if 0
317040266059SGregory Neil Shapiro 		/*
317140266059SGregory Neil Shapiro 		**  Has smioout been closed? Reopen it.
317240266059SGregory Neil Shapiro 		**	This shouldn't happen anymore, the code is here
317340266059SGregory Neil Shapiro 		**	just as a reminder.
317440266059SGregory Neil Shapiro 		*/
317540266059SGregory Neil Shapiro 
317640266059SGregory Neil Shapiro 		if (smioout->sm_magic == NULL &&
317740266059SGregory Neil Shapiro 		    sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
317840266059SGregory Neil Shapiro 				 SM_IO_WRONLY, NULL, smioout) == NULL)
317940266059SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
318040266059SGregory Neil Shapiro 				  "disconnect: sm_io_reopen(\"%s\") failed: %s",
318140266059SGregory Neil Shapiro 				  SM_PATH_DEVNULL, sm_errstring(errno));
318240266059SGregory Neil Shapiro #endif /* 0 */
3183c2aa98e2SPeter Wemm 	}
3184c2aa98e2SPeter Wemm 	if (droplev > 0)
3185c2aa98e2SPeter Wemm 	{
318640266059SGregory Neil Shapiro 		fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);
3187c2aa98e2SPeter Wemm 		if (fd == -1)
3188c2aa98e2SPeter Wemm 			sm_syslog(LOG_ERR, e->e_id,
318940266059SGregory Neil Shapiro 				  "disconnect: open(\"%s\") failed: %s",
319040266059SGregory Neil Shapiro 				  SM_PATH_DEVNULL, sm_errstring(errno));
319140266059SGregory Neil Shapiro 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
319206f25ae9SGregory Neil Shapiro 		(void) dup2(fd, STDOUT_FILENO);
319306f25ae9SGregory Neil Shapiro 		(void) dup2(fd, STDERR_FILENO);
319406f25ae9SGregory Neil Shapiro 		(void) close(fd);
3195c2aa98e2SPeter Wemm 	}
3196c2aa98e2SPeter Wemm 
3197c2aa98e2SPeter Wemm 	/* drop our controlling TTY completely if possible */
3198c2aa98e2SPeter Wemm 	if (droplev > 1)
3199c2aa98e2SPeter Wemm 	{
3200c2aa98e2SPeter Wemm 		(void) setsid();
3201c2aa98e2SPeter Wemm 		errno = 0;
3202c2aa98e2SPeter Wemm 	}
3203c2aa98e2SPeter Wemm 
3204c2aa98e2SPeter Wemm #if XDEBUG
3205c2aa98e2SPeter Wemm 	checkfd012("disconnect");
320606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
3207c2aa98e2SPeter Wemm 
3208c2aa98e2SPeter Wemm 	if (LogLevel > 71)
320940266059SGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",
321040266059SGregory Neil Shapiro 			  (int) CurrentPid);
3211c2aa98e2SPeter Wemm 
3212c2aa98e2SPeter Wemm 	errno = 0;
3213c2aa98e2SPeter Wemm }
3214c2aa98e2SPeter Wemm 
3215c2aa98e2SPeter Wemm static void
3216c2aa98e2SPeter Wemm obsolete(argv)
3217c2aa98e2SPeter Wemm 	char *argv[];
3218c2aa98e2SPeter Wemm {
3219c2aa98e2SPeter Wemm 	register char *ap;
3220c2aa98e2SPeter Wemm 	register char *op;
3221c2aa98e2SPeter Wemm 
3222c2aa98e2SPeter Wemm 	while ((ap = *++argv) != NULL)
3223c2aa98e2SPeter Wemm 	{
3224c2aa98e2SPeter Wemm 		/* Return if "--" or not an option of any form. */
3225c2aa98e2SPeter Wemm 		if (ap[0] != '-' || ap[1] == '-')
3226c2aa98e2SPeter Wemm 			return;
3227c2aa98e2SPeter Wemm 
322840266059SGregory Neil Shapiro #if _FFR_QUARANTINE
322940266059SGregory Neil Shapiro 		/* Don't allow users to use "-Q." or "-Q ." */
323040266059SGregory Neil Shapiro 		if ((ap[1] == 'Q' && ap[2] == '.') ||
323140266059SGregory Neil Shapiro 		    (ap[1] == 'Q' && argv[1] != NULL &&
323240266059SGregory Neil Shapiro 		     argv[1][0] == '.' && argv[1][1] == '\0'))
323340266059SGregory Neil Shapiro 		{
323440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
323540266059SGregory Neil Shapiro 					     "Can not use -Q.\n");
323640266059SGregory Neil Shapiro 			exit(EX_USAGE);
323740266059SGregory Neil Shapiro 		}
323840266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
323940266059SGregory Neil Shapiro 
3240c2aa98e2SPeter Wemm 		/* skip over options that do have a value */
3241c2aa98e2SPeter Wemm 		op = strchr(OPTIONS, ap[1]);
3242c2aa98e2SPeter Wemm 		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
3243c2aa98e2SPeter Wemm 		    ap[1] != 'd' &&
3244c2aa98e2SPeter Wemm #if defined(sony_news)
3245c2aa98e2SPeter Wemm 		    ap[1] != 'E' && ap[1] != 'J' &&
324606f25ae9SGregory Neil Shapiro #endif /* defined(sony_news) */
3247c2aa98e2SPeter Wemm 		    argv[1] != NULL && argv[1][0] != '-')
3248c2aa98e2SPeter Wemm 		{
3249c2aa98e2SPeter Wemm 			argv++;
3250c2aa98e2SPeter Wemm 			continue;
3251c2aa98e2SPeter Wemm 		}
3252c2aa98e2SPeter Wemm 
3253c2aa98e2SPeter Wemm 		/* If -C doesn't have an argument, use sendmail.cf. */
3254c2aa98e2SPeter Wemm #define __DEFPATH	"sendmail.cf"
3255c2aa98e2SPeter Wemm 		if (ap[1] == 'C' && ap[2] == '\0')
3256c2aa98e2SPeter Wemm 		{
3257c2aa98e2SPeter Wemm 			*argv = xalloc(sizeof(__DEFPATH) + 2);
325840266059SGregory Neil Shapiro 			(void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,
325940266059SGregory Neil Shapiro 					   "-C", __DEFPATH);
3260c2aa98e2SPeter Wemm 		}
3261c2aa98e2SPeter Wemm 
3262c2aa98e2SPeter Wemm 		/* If -q doesn't have an argument, run it once. */
3263c2aa98e2SPeter Wemm 		if (ap[1] == 'q' && ap[2] == '\0')
3264c2aa98e2SPeter Wemm 			*argv = "-q0";
3265c2aa98e2SPeter Wemm 
326640266059SGregory Neil Shapiro #if _FFR_QUARANTINE
326740266059SGregory Neil Shapiro 		/* If -Q doesn't have an argument, disable quarantining */
326840266059SGregory Neil Shapiro 		if (ap[1] == 'Q' && ap[2] == '\0')
326940266059SGregory Neil Shapiro 			*argv = "-Q.";
327040266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */
327140266059SGregory Neil Shapiro 
3272c2aa98e2SPeter Wemm 		/* if -d doesn't have an argument, use 0-99.1 */
3273c2aa98e2SPeter Wemm 		if (ap[1] == 'd' && ap[2] == '\0')
3274c2aa98e2SPeter Wemm 			*argv = "-d0-99.1";
3275c2aa98e2SPeter Wemm 
3276c2aa98e2SPeter Wemm #if defined(sony_news)
3277c2aa98e2SPeter Wemm 		/* if -E doesn't have an argument, use -EC */
3278c2aa98e2SPeter Wemm 		if (ap[1] == 'E' && ap[2] == '\0')
3279c2aa98e2SPeter Wemm 			*argv = "-EC";
3280c2aa98e2SPeter Wemm 
3281c2aa98e2SPeter Wemm 		/* if -J doesn't have an argument, use -JJ */
3282c2aa98e2SPeter Wemm 		if (ap[1] == 'J' && ap[2] == '\0')
3283c2aa98e2SPeter Wemm 			*argv = "-JJ";
328406f25ae9SGregory Neil Shapiro #endif /* defined(sony_news) */
3285c2aa98e2SPeter Wemm 	}
3286c2aa98e2SPeter Wemm }
328740266059SGregory Neil Shapiro /*
3288c2aa98e2SPeter Wemm **  AUTH_WARNING -- specify authorization warning
3289c2aa98e2SPeter Wemm **
3290c2aa98e2SPeter Wemm **	Parameters:
3291c2aa98e2SPeter Wemm **		e -- the current envelope.
3292c2aa98e2SPeter Wemm **		msg -- the text of the message.
3293c2aa98e2SPeter Wemm **		args -- arguments to the message.
3294c2aa98e2SPeter Wemm **
3295c2aa98e2SPeter Wemm **	Returns:
3296c2aa98e2SPeter Wemm **		none.
3297c2aa98e2SPeter Wemm */
3298c2aa98e2SPeter Wemm 
3299c2aa98e2SPeter Wemm void
3300c2aa98e2SPeter Wemm #ifdef __STDC__
3301c2aa98e2SPeter Wemm auth_warning(register ENVELOPE *e, const char *msg, ...)
330206f25ae9SGregory Neil Shapiro #else /* __STDC__ */
3303c2aa98e2SPeter Wemm auth_warning(e, msg, va_alist)
3304c2aa98e2SPeter Wemm 	register ENVELOPE *e;
3305c2aa98e2SPeter Wemm 	const char *msg;
3306c2aa98e2SPeter Wemm 	va_dcl
330706f25ae9SGregory Neil Shapiro #endif /* __STDC__ */
3308c2aa98e2SPeter Wemm {
3309c2aa98e2SPeter Wemm 	char buf[MAXLINE];
331040266059SGregory Neil Shapiro 	SM_VA_LOCAL_DECL
3311c2aa98e2SPeter Wemm 
3312c2aa98e2SPeter Wemm 	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
3313c2aa98e2SPeter Wemm 	{
3314c2aa98e2SPeter Wemm 		register char *p;
3315c2aa98e2SPeter Wemm 		static char hostbuf[48];
3316c2aa98e2SPeter Wemm 
3317c2aa98e2SPeter Wemm 		if (hostbuf[0] == '\0')
3318193538b7SGregory Neil Shapiro 		{
3319193538b7SGregory Neil Shapiro 			struct hostent *hp;
3320193538b7SGregory Neil Shapiro 
3321193538b7SGregory Neil Shapiro 			hp = myhostname(hostbuf, sizeof hostbuf);
332240266059SGregory Neil Shapiro #if NETINET6
3323193538b7SGregory Neil Shapiro 			if (hp != NULL)
3324193538b7SGregory Neil Shapiro 			{
3325193538b7SGregory Neil Shapiro 				freehostent(hp);
3326193538b7SGregory Neil Shapiro 				hp = NULL;
3327193538b7SGregory Neil Shapiro 			}
332840266059SGregory Neil Shapiro #endif /* NETINET6 */
3329193538b7SGregory Neil Shapiro 		}
3330c2aa98e2SPeter Wemm 
333140266059SGregory Neil Shapiro 		(void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": ");
3332c2aa98e2SPeter Wemm 		p = &buf[strlen(buf)];
333340266059SGregory Neil Shapiro 		SM_VA_START(ap, msg);
333440266059SGregory Neil Shapiro 		(void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);
333540266059SGregory Neil Shapiro 		SM_VA_END(ap);
333640266059SGregory Neil Shapiro 		addheader("X-Authentication-Warning", buf, 0, e);
3337c2aa98e2SPeter Wemm 		if (LogLevel > 3)
3338c2aa98e2SPeter Wemm 			sm_syslog(LOG_INFO, e->e_id,
3339c2aa98e2SPeter Wemm 				  "Authentication-Warning: %.400s",
3340c2aa98e2SPeter Wemm 				  buf);
3341c2aa98e2SPeter Wemm 	}
3342c2aa98e2SPeter Wemm }
334340266059SGregory Neil Shapiro /*
3344c2aa98e2SPeter Wemm **  GETEXTENV -- get from external environment
3345c2aa98e2SPeter Wemm **
3346c2aa98e2SPeter Wemm **	Parameters:
3347c2aa98e2SPeter Wemm **		envar -- the name of the variable to retrieve
3348c2aa98e2SPeter Wemm **
3349c2aa98e2SPeter Wemm **	Returns:
3350c2aa98e2SPeter Wemm **		The value, if any.
3351c2aa98e2SPeter Wemm */
3352c2aa98e2SPeter Wemm 
335340266059SGregory Neil Shapiro static char *
3354c2aa98e2SPeter Wemm getextenv(envar)
3355c2aa98e2SPeter Wemm 	const char *envar;
3356c2aa98e2SPeter Wemm {
3357c2aa98e2SPeter Wemm 	char **envp;
3358c2aa98e2SPeter Wemm 	int l;
3359c2aa98e2SPeter Wemm 
3360c2aa98e2SPeter Wemm 	l = strlen(envar);
3361c2aa98e2SPeter Wemm 	for (envp = ExternalEnviron; *envp != NULL; envp++)
3362c2aa98e2SPeter Wemm 	{
3363c2aa98e2SPeter Wemm 		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
3364c2aa98e2SPeter Wemm 			return &(*envp)[l + 1];
3365c2aa98e2SPeter Wemm 	}
3366c2aa98e2SPeter Wemm 	return NULL;
3367c2aa98e2SPeter Wemm }
336840266059SGregory Neil Shapiro /*
336940266059SGregory Neil Shapiro **  SETUSERENV -- set an environment in the propagated environment
3370c2aa98e2SPeter Wemm **
3371c2aa98e2SPeter Wemm **	Parameters:
3372c2aa98e2SPeter Wemm **		envar -- the name of the environment variable.
3373c2aa98e2SPeter Wemm **		value -- the value to which it should be set.  If
3374c2aa98e2SPeter Wemm **			null, this is extracted from the incoming
3375c2aa98e2SPeter Wemm **			environment.  If that is not set, the call
3376c2aa98e2SPeter Wemm **			to setuserenv is ignored.
3377c2aa98e2SPeter Wemm **
3378c2aa98e2SPeter Wemm **	Returns:
3379c2aa98e2SPeter Wemm **		none.
3380c2aa98e2SPeter Wemm */
3381c2aa98e2SPeter Wemm 
3382c2aa98e2SPeter Wemm void
3383c2aa98e2SPeter Wemm setuserenv(envar, value)
3384c2aa98e2SPeter Wemm 	const char *envar;
3385c2aa98e2SPeter Wemm 	const char *value;
3386c2aa98e2SPeter Wemm {
338706f25ae9SGregory Neil Shapiro 	int i, l;
3388c2aa98e2SPeter Wemm 	char **evp = UserEnviron;
3389c2aa98e2SPeter Wemm 	char *p;
3390c2aa98e2SPeter Wemm 
3391c2aa98e2SPeter Wemm 	if (value == NULL)
3392c2aa98e2SPeter Wemm 	{
3393c2aa98e2SPeter Wemm 		value = getextenv(envar);
3394c2aa98e2SPeter Wemm 		if (value == NULL)
3395c2aa98e2SPeter Wemm 			return;
3396c2aa98e2SPeter Wemm 	}
3397c2aa98e2SPeter Wemm 
339840266059SGregory Neil Shapiro 	/* XXX enforce reasonable size? */
339906f25ae9SGregory Neil Shapiro 	i = strlen(envar) + 1;
340006f25ae9SGregory Neil Shapiro 	l = strlen(value) + i + 1;
340106f25ae9SGregory Neil Shapiro 	p = (char *) xalloc(l);
340240266059SGregory Neil Shapiro 	(void) sm_strlcpyn(p, l, 3, envar, "=", value);
3403c2aa98e2SPeter Wemm 
3404c2aa98e2SPeter Wemm 	while (*evp != NULL && strncmp(*evp, p, i) != 0)
3405c2aa98e2SPeter Wemm 		evp++;
3406c2aa98e2SPeter Wemm 	if (*evp != NULL)
3407c2aa98e2SPeter Wemm 	{
3408c2aa98e2SPeter Wemm 		*evp++ = p;
3409c2aa98e2SPeter Wemm 	}
3410c2aa98e2SPeter Wemm 	else if (evp < &UserEnviron[MAXUSERENVIRON])
3411c2aa98e2SPeter Wemm 	{
3412c2aa98e2SPeter Wemm 		*evp++ = p;
3413c2aa98e2SPeter Wemm 		*evp = NULL;
3414c2aa98e2SPeter Wemm 	}
3415c2aa98e2SPeter Wemm 
3416c2aa98e2SPeter Wemm 	/* make sure it is in our environment as well */
3417c2aa98e2SPeter Wemm 	if (putenv(p) < 0)
3418c2aa98e2SPeter Wemm 		syserr("setuserenv: putenv(%s) failed", p);
3419c2aa98e2SPeter Wemm }
342040266059SGregory Neil Shapiro /*
3421c2aa98e2SPeter Wemm **  DUMPSTATE -- dump state
3422c2aa98e2SPeter Wemm **
3423c2aa98e2SPeter Wemm **	For debugging.
3424c2aa98e2SPeter Wemm */
3425c2aa98e2SPeter Wemm 
3426c2aa98e2SPeter Wemm void
3427c2aa98e2SPeter Wemm dumpstate(when)
3428c2aa98e2SPeter Wemm 	char *when;
3429c2aa98e2SPeter Wemm {
3430c2aa98e2SPeter Wemm 	register char *j = macvalue('j', CurEnv);
3431c2aa98e2SPeter Wemm 	int rs;
343206f25ae9SGregory Neil Shapiro 	extern int NextMacroId;
3433c2aa98e2SPeter Wemm 
3434c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id,
3435c2aa98e2SPeter Wemm 		  "--- dumping state on %s: $j = %s ---",
3436c2aa98e2SPeter Wemm 		  when,
3437c2aa98e2SPeter Wemm 		  j == NULL ? "<NULL>" : j);
3438c2aa98e2SPeter Wemm 	if (j != NULL)
3439c2aa98e2SPeter Wemm 	{
3440c2aa98e2SPeter Wemm 		if (!wordinclass(j, 'w'))
3441c2aa98e2SPeter Wemm 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
3442c2aa98e2SPeter Wemm 				  "*** $j not in $=w ***");
3443c2aa98e2SPeter Wemm 	}
3444c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
344540266059SGregory Neil Shapiro 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)",
344606f25ae9SGregory Neil Shapiro 		  NextMacroId, MAXMACROID);
3447c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
344840266059SGregory Neil Shapiro 	printopenfds(true);
3449c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
345040266059SGregory Neil Shapiro 	mci_dump_all(true);
3451c2aa98e2SPeter Wemm 	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
3452c2aa98e2SPeter Wemm 	if (rs > 0)
3453c2aa98e2SPeter Wemm 	{
345406f25ae9SGregory Neil Shapiro 		int status;
3455c2aa98e2SPeter Wemm 		register char **pvp;
3456c2aa98e2SPeter Wemm 		char *pv[MAXATOM + 1];
3457c2aa98e2SPeter Wemm 
3458c2aa98e2SPeter Wemm 		pv[0] = NULL;
345940266059SGregory Neil Shapiro 		status = REWRITE(pv, rs, CurEnv);
3460c2aa98e2SPeter Wemm 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
3461c2aa98e2SPeter Wemm 			  "--- ruleset debug_dumpstate returns stat %d, pv: ---",
346206f25ae9SGregory Neil Shapiro 			  status);
3463c2aa98e2SPeter Wemm 		for (pvp = pv; *pvp != NULL; pvp++)
3464c2aa98e2SPeter Wemm 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
3465c2aa98e2SPeter Wemm 	}
3466c2aa98e2SPeter Wemm 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
3467c2aa98e2SPeter Wemm }
346840266059SGregory Neil Shapiro 
346913058a91SGregory Neil Shapiro #ifdef SIGUSR1
347040266059SGregory Neil Shapiro /*
34718774250cSGregory Neil Shapiro **  SIGUSR1 -- Signal a request to dump state.
34728774250cSGregory Neil Shapiro **
34738774250cSGregory Neil Shapiro **	Parameters:
34748774250cSGregory Neil Shapiro **		sig -- calling signal.
34758774250cSGregory Neil Shapiro **
34768774250cSGregory Neil Shapiro **	Returns:
34778774250cSGregory Neil Shapiro **		none.
34788774250cSGregory Neil Shapiro **
34798774250cSGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
34808774250cSGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
34818774250cSGregory Neil Shapiro **		DOING.
34828774250cSGregory Neil Shapiro **
34838774250cSGregory Neil Shapiro **		XXX: More work is needed for this signal handler.
34848774250cSGregory Neil Shapiro */
3485c2aa98e2SPeter Wemm 
3486c2aa98e2SPeter Wemm /* ARGSUSED */
34878774250cSGregory Neil Shapiro static SIGFUNC_DECL
3488c2aa98e2SPeter Wemm sigusr1(sig)
3489c2aa98e2SPeter Wemm 	int sig;
3490c2aa98e2SPeter Wemm {
34918774250cSGregory Neil Shapiro 	int save_errno = errno;
349240266059SGregory Neil Shapiro # if SM_HEAP_CHECK
349340266059SGregory Neil Shapiro 	extern void dumpstab __P((void));
349440266059SGregory Neil Shapiro # endif /* SM_HEAP_CHECK */
34958774250cSGregory Neil Shapiro 
34968774250cSGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sigusr1);
34978774250cSGregory Neil Shapiro 	errno = save_errno;
34988774250cSGregory Neil Shapiro 	CHECK_CRITICAL(sig);
3499c2aa98e2SPeter Wemm 	dumpstate("user signal");
350040266059SGregory Neil Shapiro # if SM_HEAP_CHECK
350140266059SGregory Neil Shapiro 	dumpstab();
350240266059SGregory Neil Shapiro # endif /* SM_HEAP_CHECK */
35038774250cSGregory Neil Shapiro 	errno = save_errno;
3504c2aa98e2SPeter Wemm 	return SIGFUNC_RETURN;
3505c2aa98e2SPeter Wemm }
350613058a91SGregory Neil Shapiro #endif /* SIGUSR1 */
350740266059SGregory Neil Shapiro 
350840266059SGregory Neil Shapiro /*
3509c2aa98e2SPeter Wemm **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
3510c2aa98e2SPeter Wemm **
3511c2aa98e2SPeter Wemm **	Parameters:
3512c2aa98e2SPeter Wemm **		to_real_uid -- if set, drop to the real uid instead
3513c2aa98e2SPeter Wemm **			of the RunAsUser.
3514c2aa98e2SPeter Wemm **
3515c2aa98e2SPeter Wemm **	Returns:
3516c2aa98e2SPeter Wemm **		EX_OSERR if the setuid failed.
3517c2aa98e2SPeter Wemm **		EX_OK otherwise.
3518c2aa98e2SPeter Wemm */
3519c2aa98e2SPeter Wemm 
3520c2aa98e2SPeter Wemm int
3521c2aa98e2SPeter Wemm drop_privileges(to_real_uid)
3522c2aa98e2SPeter Wemm 	bool to_real_uid;
3523c2aa98e2SPeter Wemm {
3524c2aa98e2SPeter Wemm 	int rval = EX_OK;
3525c2aa98e2SPeter Wemm 	GIDSET_T emptygidset[1];
3526c2aa98e2SPeter Wemm 
3527c2aa98e2SPeter Wemm 	if (tTd(47, 1))
352840266059SGregory Neil Shapiro 		sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n",
352940266059SGregory Neil Shapiro 			   (int) to_real_uid,
353040266059SGregory Neil Shapiro 			   (int) RealUid, (int) RealGid,
353140266059SGregory Neil Shapiro 			   (int) getuid(), (int) getgid(),
353240266059SGregory Neil Shapiro 			   (int) geteuid(), (int) getegid(),
353340266059SGregory Neil Shapiro 			   (int) RunAsUid, (int) RunAsGid);
3534c2aa98e2SPeter Wemm 
3535c2aa98e2SPeter Wemm 	if (to_real_uid)
3536c2aa98e2SPeter Wemm 	{
3537c2aa98e2SPeter Wemm 		RunAsUserName = RealUserName;
3538c2aa98e2SPeter Wemm 		RunAsUid = RealUid;
3539c2aa98e2SPeter Wemm 		RunAsGid = RealGid;
3540c2aa98e2SPeter Wemm 	}
3541c2aa98e2SPeter Wemm 
3542c2aa98e2SPeter Wemm 	/* make sure no one can grab open descriptors for secret files */
3543c2aa98e2SPeter Wemm 	endpwent();
354440266059SGregory Neil Shapiro 	sm_mbdb_terminate();
3545c2aa98e2SPeter Wemm 
3546c2aa98e2SPeter Wemm 	/* reset group permissions; these can be set later */
3547c2aa98e2SPeter Wemm 	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
354840266059SGregory Neil Shapiro 
354940266059SGregory Neil Shapiro 	/*
355040266059SGregory Neil Shapiro 	**  Notice:  on some OS (Linux...) the setgroups() call causes
355140266059SGregory Neil Shapiro 	**	a logfile entry if sendmail is not run by root.
355240266059SGregory Neil Shapiro 	**	However, it is unclear (no POSIX standard) whether
355340266059SGregory Neil Shapiro 	**	setgroups() can only succeed if executed by root.
355440266059SGregory Neil Shapiro 	**	So for now we keep it as it is; if you want to change it, use
355540266059SGregory Neil Shapiro 	**  if (geteuid() == 0 && setgroups(1, emptygidset) == -1)
355640266059SGregory Neil Shapiro 	*/
355740266059SGregory Neil Shapiro 
3558c2aa98e2SPeter Wemm 	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
355906f25ae9SGregory Neil Shapiro 	{
356006f25ae9SGregory Neil Shapiro 		syserr("drop_privileges: setgroups(1, %d) failed",
356106f25ae9SGregory Neil Shapiro 		       (int) emptygidset[0]);
3562c2aa98e2SPeter Wemm 		rval = EX_OSERR;
356306f25ae9SGregory Neil Shapiro 	}
3564c2aa98e2SPeter Wemm 
356540266059SGregory Neil Shapiro 	/* reset primary group id */
356640266059SGregory Neil Shapiro 	if (to_real_uid)
356706f25ae9SGregory Neil Shapiro 	{
356840266059SGregory Neil Shapiro 		/*
356940266059SGregory Neil Shapiro 		**  Drop gid to real gid.
357040266059SGregory Neil Shapiro 		**  On some OS we must reset the effective[/real[/saved]] gid,
357140266059SGregory Neil Shapiro 		**  and then use setgid() to finally drop all group privileges.
357240266059SGregory Neil Shapiro 		**  Later on we check whether we can get back the
357340266059SGregory Neil Shapiro 		**  effective gid.
357440266059SGregory Neil Shapiro 		*/
357540266059SGregory Neil Shapiro 
357640266059SGregory Neil Shapiro #if HASSETEGID
357740266059SGregory Neil Shapiro 		if (setegid(RunAsGid) < 0)
357840266059SGregory Neil Shapiro 		{
357940266059SGregory Neil Shapiro 			syserr("drop_privileges: setegid(%d) failed",
358040266059SGregory Neil Shapiro 			       (int) RunAsGid);
3581c2aa98e2SPeter Wemm 			rval = EX_OSERR;
358206f25ae9SGregory Neil Shapiro 		}
358340266059SGregory Neil Shapiro #else /* HASSETEGID */
358440266059SGregory Neil Shapiro # if HASSETREGID
358540266059SGregory Neil Shapiro 		if (setregid(RunAsGid, RunAsGid) < 0)
358640266059SGregory Neil Shapiro 		{
358740266059SGregory Neil Shapiro 			syserr("drop_privileges: setregid(%d, %d) failed",
358840266059SGregory Neil Shapiro 			       (int) RunAsGid, (int) RunAsGid);
358940266059SGregory Neil Shapiro 			rval = EX_OSERR;
359040266059SGregory Neil Shapiro 		}
359140266059SGregory Neil Shapiro # else /* HASSETREGID */
359240266059SGregory Neil Shapiro #  if HASSETRESGID
359340266059SGregory Neil Shapiro 		if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0)
359440266059SGregory Neil Shapiro 		{
359540266059SGregory Neil Shapiro 			syserr("drop_privileges: setresgid(%d, %d, %d) failed",
359640266059SGregory Neil Shapiro 			       (int) RunAsGid, (int) RunAsGid, (int) RunAsGid);
359740266059SGregory Neil Shapiro 			rval = EX_OSERR;
359840266059SGregory Neil Shapiro 		}
359940266059SGregory Neil Shapiro #  endif /* HASSETRESGID */
360040266059SGregory Neil Shapiro # endif /* HASSETREGID */
360140266059SGregory Neil Shapiro #endif /* HASSETEGID */
360240266059SGregory Neil Shapiro 	}
360340266059SGregory Neil Shapiro 	if (rval == EX_OK && (to_real_uid || RunAsGid != 0))
360440266059SGregory Neil Shapiro 	{
360540266059SGregory Neil Shapiro 		if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid))
360640266059SGregory Neil Shapiro 		{
360740266059SGregory Neil Shapiro 			syserr("drop_privileges: setgid(%d) failed",
360840266059SGregory Neil Shapiro 			       (int) RunAsGid);
360940266059SGregory Neil Shapiro 			rval = EX_OSERR;
361040266059SGregory Neil Shapiro 		}
361140266059SGregory Neil Shapiro 		errno = 0;
361240266059SGregory Neil Shapiro 		if (rval == EX_OK && getegid() != RunAsGid)
361340266059SGregory Neil Shapiro 		{
361440266059SGregory Neil Shapiro 			syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d",
361540266059SGregory Neil Shapiro 			       (int) getegid(), (int) RunAsGid);
361640266059SGregory Neil Shapiro 			rval = EX_OSERR;
361740266059SGregory Neil Shapiro 		}
361840266059SGregory Neil Shapiro 	}
361940266059SGregory Neil Shapiro 
362040266059SGregory Neil Shapiro 	/* fiddle with uid */
362106f25ae9SGregory Neil Shapiro 	if (to_real_uid || RunAsUid != 0)
362206f25ae9SGregory Neil Shapiro 	{
362306f25ae9SGregory Neil Shapiro 		uid_t euid = geteuid();
362406f25ae9SGregory Neil Shapiro 
362540266059SGregory Neil Shapiro 		/*
362640266059SGregory Neil Shapiro 		**  Try to setuid(RunAsUid).
362740266059SGregory Neil Shapiro 		**  euid must be RunAsUid,
362840266059SGregory Neil Shapiro 		**  ruid must be RunAsUid unless it's the MSP and the euid
362940266059SGregory Neil Shapiro 		**  wasn't 0 and we didn't have to drop privileges to the
363040266059SGregory Neil Shapiro 		**  real uid.
363140266059SGregory Neil Shapiro 		*/
363240266059SGregory Neil Shapiro 
363340266059SGregory Neil Shapiro 		if (setuid(RunAsUid) < 0 ||
363440266059SGregory Neil Shapiro 		    (getuid() != RunAsUid  &&
363540266059SGregory Neil Shapiro 		     (!UseMSP || euid == 0 || to_real_uid )) ||
363640266059SGregory Neil Shapiro 		    geteuid() != RunAsUid)
363740266059SGregory Neil Shapiro 		{
363840266059SGregory Neil Shapiro #if HASSETREUID
363940266059SGregory Neil Shapiro 			/*
364040266059SGregory Neil Shapiro 			**  if ruid != RunAsUid, euid == RunAsUid, then
364140266059SGregory Neil Shapiro 			**  try resetting just the real uid, then using
364240266059SGregory Neil Shapiro 			**  setuid() to drop the saved-uid as well.
364340266059SGregory Neil Shapiro 			*/
364440266059SGregory Neil Shapiro 
364540266059SGregory Neil Shapiro 			if (euid == RunAsUid)
364640266059SGregory Neil Shapiro 			{
364740266059SGregory Neil Shapiro 				if (setreuid(RunAsUid, -1) < 0)
364840266059SGregory Neil Shapiro 				{
364940266059SGregory Neil Shapiro 					syserr("drop_privileges: setreuid(%d, -1) failed",
365040266059SGregory Neil Shapiro 					       (int) RunAsUid);
365140266059SGregory Neil Shapiro 					rval = EX_OSERR;
365240266059SGregory Neil Shapiro 				}
365306f25ae9SGregory Neil Shapiro 				if (setuid(RunAsUid) < 0)
365406f25ae9SGregory Neil Shapiro 				{
365540266059SGregory Neil Shapiro 					syserr("drop_privileges: second setuid(%d) attempt failed",
365640266059SGregory Neil Shapiro 					       (int) RunAsUid);
365740266059SGregory Neil Shapiro 					rval = EX_OSERR;
365840266059SGregory Neil Shapiro 				}
365940266059SGregory Neil Shapiro 			}
366040266059SGregory Neil Shapiro 			else
366140266059SGregory Neil Shapiro #endif /* HASSETREUID */
366240266059SGregory Neil Shapiro 			{
366306f25ae9SGregory Neil Shapiro 				syserr("drop_privileges: setuid(%d) failed",
366406f25ae9SGregory Neil Shapiro 				       (int) RunAsUid);
3665c2aa98e2SPeter Wemm 				rval = EX_OSERR;
366606f25ae9SGregory Neil Shapiro 			}
366740266059SGregory Neil Shapiro 		}
366840266059SGregory Neil Shapiro 		if (RunAsUid != 0 && setuid(0) == 0)
366906f25ae9SGregory Neil Shapiro 		{
367006f25ae9SGregory Neil Shapiro 			/*
367106f25ae9SGregory Neil Shapiro 			**  Believe it or not, the Linux capability model
367206f25ae9SGregory Neil Shapiro 			**  allows a non-root process to override setuid()
367306f25ae9SGregory Neil Shapiro 			**  on a process running as root and prevent that
367406f25ae9SGregory Neil Shapiro 			**  process from dropping privileges.
367506f25ae9SGregory Neil Shapiro 			*/
367606f25ae9SGregory Neil Shapiro 
367706f25ae9SGregory Neil Shapiro 			syserr("drop_privileges: setuid(0) succeeded (when it should not)");
367806f25ae9SGregory Neil Shapiro 			rval = EX_OSERR;
367906f25ae9SGregory Neil Shapiro 		}
368006f25ae9SGregory Neil Shapiro 		else if (RunAsUid != euid && setuid(euid) == 0)
368106f25ae9SGregory Neil Shapiro 		{
368206f25ae9SGregory Neil Shapiro 			/*
368306f25ae9SGregory Neil Shapiro 			**  Some operating systems will keep the saved-uid
368406f25ae9SGregory Neil Shapiro 			**  if a non-root effective-uid calls setuid(real-uid)
368506f25ae9SGregory Neil Shapiro 			**  making it possible to set it back again later.
368606f25ae9SGregory Neil Shapiro 			*/
368706f25ae9SGregory Neil Shapiro 
368840266059SGregory Neil Shapiro 			syserr("drop_privileges: Unable to drop non-root set-user-ID privileges");
368906f25ae9SGregory Neil Shapiro 			rval = EX_OSERR;
369006f25ae9SGregory Neil Shapiro 		}
369106f25ae9SGregory Neil Shapiro 	}
369240266059SGregory Neil Shapiro 
369340266059SGregory Neil Shapiro 	if ((to_real_uid || RunAsGid != 0) &&
369440266059SGregory Neil Shapiro 	    rval == EX_OK && RunAsGid != EffGid &&
369540266059SGregory Neil Shapiro 	    getuid() != 0 && geteuid() != 0)
369640266059SGregory Neil Shapiro 	{
369740266059SGregory Neil Shapiro 		errno = 0;
369840266059SGregory Neil Shapiro 		if (setgid(EffGid) == 0)
369940266059SGregory Neil Shapiro 		{
370040266059SGregory Neil Shapiro 			syserr("drop_privileges: setgid(%d) succeeded (when it should not)",
370140266059SGregory Neil Shapiro 			       (int) EffGid);
370240266059SGregory Neil Shapiro 			rval = EX_OSERR;
370340266059SGregory Neil Shapiro 		}
370440266059SGregory Neil Shapiro 	}
370540266059SGregory Neil Shapiro 
3706c2aa98e2SPeter Wemm 	if (tTd(47, 5))
3707c2aa98e2SPeter Wemm 	{
370840266059SGregory Neil Shapiro 		sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
370906f25ae9SGregory Neil Shapiro 			   (int) geteuid(), (int) getuid(),
371006f25ae9SGregory Neil Shapiro 			   (int) getegid(), (int) getgid());
371140266059SGregory Neil Shapiro 		sm_dprintf("drop_privileges: RunAsUser = %d:%d\n",
371206f25ae9SGregory Neil Shapiro 			   (int) RunAsUid, (int) RunAsGid);
371306f25ae9SGregory Neil Shapiro 		if (tTd(47, 10))
371440266059SGregory Neil Shapiro 			sm_dprintf("drop_privileges: rval = %d\n", rval);
3715c2aa98e2SPeter Wemm 	}
3716c2aa98e2SPeter Wemm 	return rval;
3717c2aa98e2SPeter Wemm }
371840266059SGregory Neil Shapiro /*
3719c2aa98e2SPeter Wemm **  FILL_FD -- make sure a file descriptor has been properly allocated
3720c2aa98e2SPeter Wemm **
3721c2aa98e2SPeter Wemm **	Used to make sure that stdin/out/err are allocated on startup
3722c2aa98e2SPeter Wemm **
3723c2aa98e2SPeter Wemm **	Parameters:
3724c2aa98e2SPeter Wemm **		fd -- the file descriptor to be filled.
3725c2aa98e2SPeter Wemm **		where -- a string used for logging.  If NULL, this is
3726c2aa98e2SPeter Wemm **			being called on startup, and logging should
3727c2aa98e2SPeter Wemm **			not be done.
3728c2aa98e2SPeter Wemm **
3729c2aa98e2SPeter Wemm **	Returns:
3730c2aa98e2SPeter Wemm **		none
373140266059SGregory Neil Shapiro **
373240266059SGregory Neil Shapiro **	Side Effects:
373340266059SGregory Neil Shapiro **		possibly changes MissingFds
3734c2aa98e2SPeter Wemm */
3735c2aa98e2SPeter Wemm 
3736c2aa98e2SPeter Wemm void
3737c2aa98e2SPeter Wemm fill_fd(fd, where)
3738c2aa98e2SPeter Wemm 	int fd;
3739c2aa98e2SPeter Wemm 	char *where;
3740c2aa98e2SPeter Wemm {
3741c2aa98e2SPeter Wemm 	int i;
3742c2aa98e2SPeter Wemm 	struct stat stbuf;
3743c2aa98e2SPeter Wemm 
3744c2aa98e2SPeter Wemm 	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
3745c2aa98e2SPeter Wemm 		return;
3746c2aa98e2SPeter Wemm 
3747c2aa98e2SPeter Wemm 	if (where != NULL)
3748c2aa98e2SPeter Wemm 		syserr("fill_fd: %s: fd %d not open", where, fd);
3749c2aa98e2SPeter Wemm 	else
3750c2aa98e2SPeter Wemm 		MissingFds |= 1 << fd;
375140266059SGregory Neil Shapiro 	i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666);
3752c2aa98e2SPeter Wemm 	if (i < 0)
3753c2aa98e2SPeter Wemm 	{
375440266059SGregory Neil Shapiro 		syserr("!fill_fd: %s: cannot open %s",
375540266059SGregory Neil Shapiro 		       where == NULL ? "startup" : where, SM_PATH_DEVNULL);
3756c2aa98e2SPeter Wemm 	}
3757c2aa98e2SPeter Wemm 	if (fd != i)
3758c2aa98e2SPeter Wemm 	{
3759c2aa98e2SPeter Wemm 		(void) dup2(i, fd);
3760c2aa98e2SPeter Wemm 		(void) close(i);
3761c2aa98e2SPeter Wemm 	}
3762c2aa98e2SPeter Wemm }
376340266059SGregory Neil Shapiro /*
376440266059SGregory Neil Shapiro **  SM_PRINTOPTIONS -- print options
376540266059SGregory Neil Shapiro **
376640266059SGregory Neil Shapiro **	Parameters:
376740266059SGregory Neil Shapiro **		options -- array of options.
376840266059SGregory Neil Shapiro **
376940266059SGregory Neil Shapiro **	Returns:
377040266059SGregory Neil Shapiro **		none.
377140266059SGregory Neil Shapiro */
377240266059SGregory Neil Shapiro 
377340266059SGregory Neil Shapiro static void
377440266059SGregory Neil Shapiro sm_printoptions(options)
377540266059SGregory Neil Shapiro 	char **options;
377640266059SGregory Neil Shapiro {
377740266059SGregory Neil Shapiro 	int ll;
377840266059SGregory Neil Shapiro 	char **av;
377940266059SGregory Neil Shapiro 
378040266059SGregory Neil Shapiro 	av = options;
378140266059SGregory Neil Shapiro 	ll = 7;
378240266059SGregory Neil Shapiro 	while (*av != NULL)
378340266059SGregory Neil Shapiro 	{
378440266059SGregory Neil Shapiro 		if (ll + strlen(*av) > 63)
378540266059SGregory Neil Shapiro 		{
378640266059SGregory Neil Shapiro 			sm_dprintf("\n");
378740266059SGregory Neil Shapiro 			ll = 0;
378840266059SGregory Neil Shapiro 		}
378940266059SGregory Neil Shapiro 		if (ll == 0)
379040266059SGregory Neil Shapiro 			sm_dprintf("\t\t");
379140266059SGregory Neil Shapiro 		else
379240266059SGregory Neil Shapiro 			sm_dprintf(" ");
379340266059SGregory Neil Shapiro 		sm_dprintf("%s", *av);
379440266059SGregory Neil Shapiro 		ll += strlen(*av++) + 1;
379540266059SGregory Neil Shapiro 	}
379640266059SGregory Neil Shapiro 	sm_dprintf("\n");
379740266059SGregory Neil Shapiro }
379840266059SGregory Neil Shapiro /*
3799c2aa98e2SPeter Wemm **  TESTMODELINE -- process a test mode input line
3800c2aa98e2SPeter Wemm **
3801c2aa98e2SPeter Wemm **	Parameters:
3802c2aa98e2SPeter Wemm **		line -- the input line.
3803c2aa98e2SPeter Wemm **		e -- the current environment.
3804c2aa98e2SPeter Wemm **	Syntax:
3805c2aa98e2SPeter Wemm **		#  a comment
3806c2aa98e2SPeter Wemm **		.X process X as a configuration line
3807c2aa98e2SPeter Wemm **		=X dump a configuration item (such as mailers)
3808c2aa98e2SPeter Wemm **		$X dump a macro or class
3809c2aa98e2SPeter Wemm **		/X try an activity
3810c2aa98e2SPeter Wemm **		X  normal process through rule set X
3811c2aa98e2SPeter Wemm */
3812c2aa98e2SPeter Wemm 
381306f25ae9SGregory Neil Shapiro static void
3814c2aa98e2SPeter Wemm testmodeline(line, e)
3815c2aa98e2SPeter Wemm 	char *line;
3816c2aa98e2SPeter Wemm 	ENVELOPE *e;
3817c2aa98e2SPeter Wemm {
3818c2aa98e2SPeter Wemm 	register char *p;
3819c2aa98e2SPeter Wemm 	char *q;
3820c2aa98e2SPeter Wemm 	auto char *delimptr;
3821c2aa98e2SPeter Wemm 	int mid;
3822c2aa98e2SPeter Wemm 	int i, rs;
3823c2aa98e2SPeter Wemm 	STAB *map;
3824c2aa98e2SPeter Wemm 	char **s;
3825c2aa98e2SPeter Wemm 	struct rewrite *rw;
3826c2aa98e2SPeter Wemm 	ADDRESS a;
3827c2aa98e2SPeter Wemm 	static int tryflags = RF_COPYNONE;
3828c2aa98e2SPeter Wemm 	char exbuf[MAXLINE];
382940266059SGregory Neil Shapiro 	extern unsigned char TokTypeNoC[];
383042e5d165SGregory Neil Shapiro 
383142e5d165SGregory Neil Shapiro 	/* skip leading spaces */
383242e5d165SGregory Neil Shapiro 	while (*line == ' ')
383342e5d165SGregory Neil Shapiro 		line++;
383442e5d165SGregory Neil Shapiro 
3835c2aa98e2SPeter Wemm 	switch (line[0])
3836c2aa98e2SPeter Wemm 	{
3837c2aa98e2SPeter Wemm 	  case '#':
383806f25ae9SGregory Neil Shapiro 	  case '\0':
3839c2aa98e2SPeter Wemm 		return;
3840c2aa98e2SPeter Wemm 
3841c2aa98e2SPeter Wemm 	  case '?':
384206f25ae9SGregory Neil Shapiro 		help("-bt", e);
3843c2aa98e2SPeter Wemm 		return;
3844c2aa98e2SPeter Wemm 
3845c2aa98e2SPeter Wemm 	  case '.':		/* config-style settings */
3846c2aa98e2SPeter Wemm 		switch (line[1])
3847c2aa98e2SPeter Wemm 		{
3848c2aa98e2SPeter Wemm 		  case 'D':
384940266059SGregory Neil Shapiro 			mid = macid_parse(&line[2], &delimptr);
3850193538b7SGregory Neil Shapiro 			if (mid == 0)
3851c2aa98e2SPeter Wemm 				return;
3852c2aa98e2SPeter Wemm 			translate_dollars(delimptr);
385340266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, mid, delimptr);
3854c2aa98e2SPeter Wemm 			break;
3855c2aa98e2SPeter Wemm 
3856c2aa98e2SPeter Wemm 		  case 'C':
3857c2aa98e2SPeter Wemm 			if (line[2] == '\0')	/* not to call syserr() */
3858c2aa98e2SPeter Wemm 				return;
3859c2aa98e2SPeter Wemm 
386040266059SGregory Neil Shapiro 			mid = macid_parse(&line[2], &delimptr);
3861193538b7SGregory Neil Shapiro 			if (mid == 0)
3862c2aa98e2SPeter Wemm 				return;
3863c2aa98e2SPeter Wemm 			translate_dollars(delimptr);
3864c2aa98e2SPeter Wemm 			expand(delimptr, exbuf, sizeof exbuf, e);
3865c2aa98e2SPeter Wemm 			p = exbuf;
3866c2aa98e2SPeter Wemm 			while (*p != '\0')
3867c2aa98e2SPeter Wemm 			{
3868c2aa98e2SPeter Wemm 				register char *wd;
3869c2aa98e2SPeter Wemm 				char delim;
3870c2aa98e2SPeter Wemm 
3871c2aa98e2SPeter Wemm 				while (*p != '\0' && isascii(*p) && isspace(*p))
3872c2aa98e2SPeter Wemm 					p++;
3873c2aa98e2SPeter Wemm 				wd = p;
3874c2aa98e2SPeter Wemm 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3875c2aa98e2SPeter Wemm 					p++;
3876c2aa98e2SPeter Wemm 				delim = *p;
3877c2aa98e2SPeter Wemm 				*p = '\0';
3878c2aa98e2SPeter Wemm 				if (wd[0] != '\0')
3879c2aa98e2SPeter Wemm 					setclass(mid, wd);
3880c2aa98e2SPeter Wemm 				*p = delim;
3881c2aa98e2SPeter Wemm 			}
3882c2aa98e2SPeter Wemm 			break;
3883c2aa98e2SPeter Wemm 
3884c2aa98e2SPeter Wemm 		  case '\0':
388540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
388640266059SGregory Neil Shapiro 					     "Usage: .[DC]macro value(s)\n");
3887c2aa98e2SPeter Wemm 			break;
3888c2aa98e2SPeter Wemm 
3889c2aa98e2SPeter Wemm 		  default:
389040266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
389140266059SGregory Neil Shapiro 					     "Unknown \".\" command %s\n", line);
3892c2aa98e2SPeter Wemm 			break;
3893c2aa98e2SPeter Wemm 		}
3894c2aa98e2SPeter Wemm 		return;
3895c2aa98e2SPeter Wemm 
3896c2aa98e2SPeter Wemm 	  case '=':		/* config-style settings */
3897c2aa98e2SPeter Wemm 		switch (line[1])
3898c2aa98e2SPeter Wemm 		{
3899c2aa98e2SPeter Wemm 		  case 'S':		/* dump rule set */
3900c2aa98e2SPeter Wemm 			rs = strtorwset(&line[2], NULL, ST_FIND);
3901c2aa98e2SPeter Wemm 			if (rs < 0)
3902c2aa98e2SPeter Wemm 			{
390340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
390440266059SGregory Neil Shapiro 						     "Undefined ruleset %s\n", &line[2]);
3905c2aa98e2SPeter Wemm 				return;
3906c2aa98e2SPeter Wemm 			}
3907c2aa98e2SPeter Wemm 			rw = RewriteRules[rs];
3908c2aa98e2SPeter Wemm 			if (rw == NULL)
3909c2aa98e2SPeter Wemm 				return;
3910c2aa98e2SPeter Wemm 			do
3911c2aa98e2SPeter Wemm 			{
391240266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
391340266059SGregory Neil Shapiro 						  'R');
3914c2aa98e2SPeter Wemm 				s = rw->r_lhs;
3915c2aa98e2SPeter Wemm 				while (*s != NULL)
3916c2aa98e2SPeter Wemm 				{
3917c2aa98e2SPeter Wemm 					xputs(*s++);
391840266059SGregory Neil Shapiro 					(void) sm_io_putc(smioout,
391940266059SGregory Neil Shapiro 							  SM_TIME_DEFAULT, ' ');
3920c2aa98e2SPeter Wemm 				}
392140266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
392240266059SGregory Neil Shapiro 						  '\t');
392340266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
392440266059SGregory Neil Shapiro 						  '\t');
3925c2aa98e2SPeter Wemm 				s = rw->r_rhs;
3926c2aa98e2SPeter Wemm 				while (*s != NULL)
3927c2aa98e2SPeter Wemm 				{
3928c2aa98e2SPeter Wemm 					xputs(*s++);
392940266059SGregory Neil Shapiro 					(void) sm_io_putc(smioout,
393040266059SGregory Neil Shapiro 							  SM_TIME_DEFAULT, ' ');
3931c2aa98e2SPeter Wemm 				}
393240266059SGregory Neil Shapiro 				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
393340266059SGregory Neil Shapiro 						  '\n');
3934c2aa98e2SPeter Wemm 			} while ((rw = rw->r_next) != NULL);
3935c2aa98e2SPeter Wemm 			break;
3936c2aa98e2SPeter Wemm 
3937c2aa98e2SPeter Wemm 		  case 'M':
3938c2aa98e2SPeter Wemm 			for (i = 0; i < MAXMAILERS; i++)
3939c2aa98e2SPeter Wemm 			{
3940c2aa98e2SPeter Wemm 				if (Mailer[i] != NULL)
3941c2aa98e2SPeter Wemm 					printmailer(Mailer[i]);
3942c2aa98e2SPeter Wemm 			}
3943c2aa98e2SPeter Wemm 			break;
3944c2aa98e2SPeter Wemm 
3945c2aa98e2SPeter Wemm 		  case '\0':
394640266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
394740266059SGregory Neil Shapiro 					     "Usage: =Sruleset or =M\n");
3948c2aa98e2SPeter Wemm 			break;
3949c2aa98e2SPeter Wemm 
3950c2aa98e2SPeter Wemm 		  default:
395140266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
395240266059SGregory Neil Shapiro 					     "Unknown \"=\" command %s\n", line);
3953c2aa98e2SPeter Wemm 			break;
3954c2aa98e2SPeter Wemm 		}
3955c2aa98e2SPeter Wemm 		return;
3956c2aa98e2SPeter Wemm 
3957c2aa98e2SPeter Wemm 	  case '-':		/* set command-line-like opts */
3958c2aa98e2SPeter Wemm 		switch (line[1])
3959c2aa98e2SPeter Wemm 		{
3960c2aa98e2SPeter Wemm 		  case 'd':
3961c2aa98e2SPeter Wemm 			tTflag(&line[2]);
3962c2aa98e2SPeter Wemm 			break;
3963c2aa98e2SPeter Wemm 
3964c2aa98e2SPeter Wemm 		  case '\0':
396540266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
396640266059SGregory Neil Shapiro 					     "Usage: -d{debug arguments}\n");
3967c2aa98e2SPeter Wemm 			break;
3968c2aa98e2SPeter Wemm 
3969c2aa98e2SPeter Wemm 		  default:
397040266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
397140266059SGregory Neil Shapiro 					     "Unknown \"-\" command %s\n", line);
3972c2aa98e2SPeter Wemm 			break;
3973c2aa98e2SPeter Wemm 		}
3974c2aa98e2SPeter Wemm 		return;
3975c2aa98e2SPeter Wemm 
3976c2aa98e2SPeter Wemm 	  case '$':
3977c2aa98e2SPeter Wemm 		if (line[1] == '=')
3978c2aa98e2SPeter Wemm 		{
397940266059SGregory Neil Shapiro 			mid = macid(&line[2]);
3980193538b7SGregory Neil Shapiro 			if (mid != 0)
3981c2aa98e2SPeter Wemm 				stabapply(dump_class, mid);
3982c2aa98e2SPeter Wemm 			return;
3983c2aa98e2SPeter Wemm 		}
398440266059SGregory Neil Shapiro 		mid = macid(&line[1]);
3985193538b7SGregory Neil Shapiro 		if (mid == 0)
3986c2aa98e2SPeter Wemm 			return;
3987c2aa98e2SPeter Wemm 		p = macvalue(mid, e);
3988c2aa98e2SPeter Wemm 		if (p == NULL)
398940266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
399040266059SGregory Neil Shapiro 					     "Undefined\n");
3991c2aa98e2SPeter Wemm 		else
3992c2aa98e2SPeter Wemm 		{
3993c2aa98e2SPeter Wemm 			xputs(p);
399440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
399540266059SGregory Neil Shapiro 					     "\n");
3996c2aa98e2SPeter Wemm 		}
3997c2aa98e2SPeter Wemm 		return;
3998c2aa98e2SPeter Wemm 
3999c2aa98e2SPeter Wemm 	  case '/':		/* miscellaneous commands */
4000c2aa98e2SPeter Wemm 		p = &line[strlen(line)];
4001c2aa98e2SPeter Wemm 		while (--p >= line && isascii(*p) && isspace(*p))
4002c2aa98e2SPeter Wemm 			*p = '\0';
4003c2aa98e2SPeter Wemm 		p = strpbrk(line, " \t");
4004c2aa98e2SPeter Wemm 		if (p != NULL)
4005c2aa98e2SPeter Wemm 		{
4006c2aa98e2SPeter Wemm 			while (isascii(*p) && isspace(*p))
4007c2aa98e2SPeter Wemm 				*p++ = '\0';
4008c2aa98e2SPeter Wemm 		}
4009c2aa98e2SPeter Wemm 		else
4010c2aa98e2SPeter Wemm 			p = "";
4011c2aa98e2SPeter Wemm 		if (line[1] == '\0')
4012c2aa98e2SPeter Wemm 		{
401340266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
401440266059SGregory Neil Shapiro 					     "Usage: /[canon|map|mx|parse|try|tryflags]\n");
4015c2aa98e2SPeter Wemm 			return;
4016c2aa98e2SPeter Wemm 		}
401740266059SGregory Neil Shapiro 		if (sm_strcasecmp(&line[1], "quit") == 0)
401806f25ae9SGregory Neil Shapiro 		{
401906f25ae9SGregory Neil Shapiro 			CurEnv->e_id = NULL;
402040266059SGregory Neil Shapiro 			finis(true, true, ExitStat);
402140266059SGregory Neil Shapiro 			/* NOTREACHED */
402206f25ae9SGregory Neil Shapiro 		}
402340266059SGregory Neil Shapiro 		if (sm_strcasecmp(&line[1], "mx") == 0)
4024c2aa98e2SPeter Wemm 		{
4025c2aa98e2SPeter Wemm #if NAMED_BIND
4026c2aa98e2SPeter Wemm 			/* look up MX records */
4027c2aa98e2SPeter Wemm 			int nmx;
4028c2aa98e2SPeter Wemm 			auto int rcode;
4029c2aa98e2SPeter Wemm 			char *mxhosts[MAXMXHOSTS + 1];
4030c2aa98e2SPeter Wemm 
4031c2aa98e2SPeter Wemm 			if (*p == '\0')
4032c2aa98e2SPeter Wemm 			{
403340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
403440266059SGregory Neil Shapiro 						     "Usage: /mx address\n");
4035c2aa98e2SPeter Wemm 				return;
4036c2aa98e2SPeter Wemm 			}
403740266059SGregory Neil Shapiro 			nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true,
403840266059SGregory Neil Shapiro 				      NULL);
403940266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
404040266059SGregory Neil Shapiro 					     "getmxrr(%s) returns %d value(s):\n",
404140266059SGregory Neil Shapiro 				p, nmx);
4042c2aa98e2SPeter Wemm 			for (i = 0; i < nmx; i++)
404340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
404440266059SGregory Neil Shapiro 						     "\t%s\n", mxhosts[i]);
404506f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */
404640266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
404740266059SGregory Neil Shapiro 					     "No MX code compiled in\n");
404806f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
4049c2aa98e2SPeter Wemm 		}
405040266059SGregory Neil Shapiro 		else if (sm_strcasecmp(&line[1], "canon") == 0)
4051c2aa98e2SPeter Wemm 		{
4052c2aa98e2SPeter Wemm 			char host[MAXHOSTNAMELEN];
4053c2aa98e2SPeter Wemm 
4054c2aa98e2SPeter Wemm 			if (*p == '\0')
4055c2aa98e2SPeter Wemm 			{
405640266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
405740266059SGregory Neil Shapiro 						     "Usage: /canon address\n");
4058c2aa98e2SPeter Wemm 				return;
4059c2aa98e2SPeter Wemm 			}
406040266059SGregory Neil Shapiro 			else if (sm_strlcpy(host, p, sizeof host) >= sizeof host)
4061c2aa98e2SPeter Wemm 			{
406240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
406340266059SGregory Neil Shapiro 						     "Name too long\n");
4064c2aa98e2SPeter Wemm 				return;
4065c2aa98e2SPeter Wemm 			}
406640266059SGregory Neil Shapiro 			(void) getcanonname(host, sizeof host, HasWildcardMX,
406740266059SGregory Neil Shapiro 					    NULL);
406840266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
406940266059SGregory Neil Shapiro 					     "getcanonname(%s) returns %s\n",
407040266059SGregory Neil Shapiro 					     p, host);
4071c2aa98e2SPeter Wemm 		}
407240266059SGregory Neil Shapiro 		else if (sm_strcasecmp(&line[1], "map") == 0)
4073c2aa98e2SPeter Wemm 		{
4074c2aa98e2SPeter Wemm 			auto int rcode = EX_OK;
4075c2aa98e2SPeter Wemm 			char *av[2];
4076c2aa98e2SPeter Wemm 
4077c2aa98e2SPeter Wemm 			if (*p == '\0')
4078c2aa98e2SPeter Wemm 			{
407940266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
408040266059SGregory Neil Shapiro 						     "Usage: /map mapname key\n");
4081c2aa98e2SPeter Wemm 				return;
4082c2aa98e2SPeter Wemm 			}
4083c2aa98e2SPeter Wemm 			for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q));			     q++)
4084c2aa98e2SPeter Wemm 				continue;
4085c2aa98e2SPeter Wemm 			if (*q == '\0')
4086c2aa98e2SPeter Wemm 			{
408740266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
408840266059SGregory Neil Shapiro 						     "No key specified\n");
4089c2aa98e2SPeter Wemm 				return;
4090c2aa98e2SPeter Wemm 			}
4091c2aa98e2SPeter Wemm 			*q++ = '\0';
4092c2aa98e2SPeter Wemm 			map = stab(p, ST_MAP, ST_FIND);
4093c2aa98e2SPeter Wemm 			if (map == NULL)
4094c2aa98e2SPeter Wemm 			{
409540266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
409640266059SGregory Neil Shapiro 						     "Map named \"%s\" not found\n", p);
4097c2aa98e2SPeter Wemm 				return;
4098c2aa98e2SPeter Wemm 			}
409906f25ae9SGregory Neil Shapiro 			if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
410006f25ae9SGregory Neil Shapiro 			    !openmap(&(map->s_map)))
4101c2aa98e2SPeter Wemm 			{
410240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
410340266059SGregory Neil Shapiro 						     "Map named \"%s\" not open\n", p);
4104c2aa98e2SPeter Wemm 				return;
4105c2aa98e2SPeter Wemm 			}
410640266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
410740266059SGregory Neil Shapiro 					     "map_lookup: %s (%s) ", p, q);
4108c2aa98e2SPeter Wemm 			av[0] = q;
4109c2aa98e2SPeter Wemm 			av[1] = NULL;
4110c2aa98e2SPeter Wemm 			p = (*map->s_map.map_class->map_lookup)
4111c2aa98e2SPeter Wemm 					(&map->s_map, q, av, &rcode);
4112c2aa98e2SPeter Wemm 			if (p == NULL)
411340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
411440266059SGregory Neil Shapiro 						     "no match (%d)\n",
411540266059SGregory Neil Shapiro 						     rcode);
4116c2aa98e2SPeter Wemm 			else
411740266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
411840266059SGregory Neil Shapiro 						     "returns %s (%d)\n", p,
411940266059SGregory Neil Shapiro 						     rcode);
4120c2aa98e2SPeter Wemm 		}
412140266059SGregory Neil Shapiro 		else if (sm_strcasecmp(&line[1], "try") == 0)
4122c2aa98e2SPeter Wemm 		{
4123c2aa98e2SPeter Wemm 			MAILER *m;
412406f25ae9SGregory Neil Shapiro 			STAB *st;
4125c2aa98e2SPeter Wemm 			auto int rcode = EX_OK;
4126c2aa98e2SPeter Wemm 
4127c2aa98e2SPeter Wemm 			q = strpbrk(p, " \t");
4128c2aa98e2SPeter Wemm 			if (q != NULL)
4129c2aa98e2SPeter Wemm 			{
4130c2aa98e2SPeter Wemm 				while (isascii(*q) && isspace(*q))
4131c2aa98e2SPeter Wemm 					*q++ = '\0';
4132c2aa98e2SPeter Wemm 			}
4133c2aa98e2SPeter Wemm 			if (q == NULL || *q == '\0')
4134c2aa98e2SPeter Wemm 			{
413540266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
413640266059SGregory Neil Shapiro 						     "Usage: /try mailer address\n");
4137c2aa98e2SPeter Wemm 				return;
4138c2aa98e2SPeter Wemm 			}
413906f25ae9SGregory Neil Shapiro 			st = stab(p, ST_MAILER, ST_FIND);
414006f25ae9SGregory Neil Shapiro 			if (st == NULL)
4141c2aa98e2SPeter Wemm 			{
414240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
414340266059SGregory Neil Shapiro 						     "Unknown mailer %s\n", p);
4144c2aa98e2SPeter Wemm 				return;
4145c2aa98e2SPeter Wemm 			}
414606f25ae9SGregory Neil Shapiro 			m = st->s_mailer;
414740266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
414840266059SGregory Neil Shapiro 					     "Trying %s %s address %s for mailer %s\n",
414940266059SGregory Neil Shapiro 				     bitset(RF_HEADERADDR, tryflags) ? "header"
415040266059SGregory Neil Shapiro 							: "envelope",
415140266059SGregory Neil Shapiro 				     bitset(RF_SENDERADDR, tryflags) ? "sender"
415240266059SGregory Neil Shapiro 							: "recipient", q, p);
4153c2aa98e2SPeter Wemm 			p = remotename(q, m, tryflags, &rcode, CurEnv);
415440266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
415540266059SGregory Neil Shapiro 					     "Rcode = %d, addr = %s\n",
4156c2aa98e2SPeter Wemm 					     rcode, p == NULL ? "<NULL>" : p);
4157c2aa98e2SPeter Wemm 			e->e_to = NULL;
4158c2aa98e2SPeter Wemm 		}
415940266059SGregory Neil Shapiro 		else if (sm_strcasecmp(&line[1], "tryflags") == 0)
4160c2aa98e2SPeter Wemm 		{
4161c2aa98e2SPeter Wemm 			if (*p == '\0')
4162c2aa98e2SPeter Wemm 			{
416340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
416440266059SGregory Neil Shapiro 						     "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
4165c2aa98e2SPeter Wemm 				return;
4166c2aa98e2SPeter Wemm 			}
4167c2aa98e2SPeter Wemm 			for (; *p != '\0'; p++)
4168c2aa98e2SPeter Wemm 			{
4169c2aa98e2SPeter Wemm 				switch (*p)
4170c2aa98e2SPeter Wemm 				{
4171c2aa98e2SPeter Wemm 				  case 'H':
4172c2aa98e2SPeter Wemm 				  case 'h':
4173c2aa98e2SPeter Wemm 					tryflags |= RF_HEADERADDR;
4174c2aa98e2SPeter Wemm 					break;
4175c2aa98e2SPeter Wemm 
4176c2aa98e2SPeter Wemm 				  case 'E':
4177c2aa98e2SPeter Wemm 				  case 'e':
4178c2aa98e2SPeter Wemm 					tryflags &= ~RF_HEADERADDR;
4179c2aa98e2SPeter Wemm 					break;
4180c2aa98e2SPeter Wemm 
4181c2aa98e2SPeter Wemm 				  case 'S':
4182c2aa98e2SPeter Wemm 				  case 's':
4183c2aa98e2SPeter Wemm 					tryflags |= RF_SENDERADDR;
4184c2aa98e2SPeter Wemm 					break;
4185c2aa98e2SPeter Wemm 
4186c2aa98e2SPeter Wemm 				  case 'R':
4187c2aa98e2SPeter Wemm 				  case 'r':
4188c2aa98e2SPeter Wemm 					tryflags &= ~RF_SENDERADDR;
4189c2aa98e2SPeter Wemm 					break;
4190c2aa98e2SPeter Wemm 				}
4191c2aa98e2SPeter Wemm 			}
419206f25ae9SGregory Neil Shapiro 			exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
419306f25ae9SGregory Neil Shapiro 			exbuf[1] = ' ';
419406f25ae9SGregory Neil Shapiro 			exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
419506f25ae9SGregory Neil Shapiro 			exbuf[3] = '\0';
419640266059SGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
419740266059SGregory Neil Shapiro 				macid("{addr_type}"), exbuf);
4198c2aa98e2SPeter Wemm 		}
419940266059SGregory Neil Shapiro 		else if (sm_strcasecmp(&line[1], "parse") == 0)
4200c2aa98e2SPeter Wemm 		{
4201c2aa98e2SPeter Wemm 			if (*p == '\0')
4202c2aa98e2SPeter Wemm 			{
420340266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
420440266059SGregory Neil Shapiro 						     "Usage: /parse address\n");
4205c2aa98e2SPeter Wemm 				return;
4206c2aa98e2SPeter Wemm 			}
4207c2aa98e2SPeter Wemm 			q = crackaddr(p);
420840266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
420940266059SGregory Neil Shapiro 					     "Cracked address = ");
4210c2aa98e2SPeter Wemm 			xputs(q);
421140266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
421240266059SGregory Neil Shapiro 					     "\nParsing %s %s address\n",
421340266059SGregory Neil Shapiro 					     bitset(RF_HEADERADDR, tryflags) ?
421440266059SGregory Neil Shapiro 							"header" : "envelope",
421540266059SGregory Neil Shapiro 					     bitset(RF_SENDERADDR, tryflags) ?
421640266059SGregory Neil Shapiro 							"sender" : "recipient");
421740266059SGregory Neil Shapiro 			if (parseaddr(p, &a, tryflags, '\0', NULL, e, true)
421840266059SGregory Neil Shapiro 			    == NULL)
421940266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
422040266059SGregory Neil Shapiro 						     "Cannot parse\n");
4221c2aa98e2SPeter Wemm 			else if (a.q_host != NULL && a.q_host[0] != '\0')
422240266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
422340266059SGregory Neil Shapiro 						     "mailer %s, host %s, user %s\n",
422440266059SGregory Neil Shapiro 						     a.q_mailer->m_name,
422540266059SGregory Neil Shapiro 						     a.q_host,
422640266059SGregory Neil Shapiro 						     a.q_user);
4227c2aa98e2SPeter Wemm 			else
422840266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
422940266059SGregory Neil Shapiro 						     "mailer %s, user %s\n",
423040266059SGregory Neil Shapiro 						     a.q_mailer->m_name,
423140266059SGregory Neil Shapiro 						     a.q_user);
4232c2aa98e2SPeter Wemm 			e->e_to = NULL;
4233c2aa98e2SPeter Wemm 		}
4234c2aa98e2SPeter Wemm 		else
4235c2aa98e2SPeter Wemm 		{
423640266059SGregory Neil Shapiro 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
423740266059SGregory Neil Shapiro 					     "Unknown \"/\" command %s\n",
423840266059SGregory Neil Shapiro 					     line);
4239c2aa98e2SPeter Wemm 		}
4240c2aa98e2SPeter Wemm 		return;
4241c2aa98e2SPeter Wemm 	}
4242c2aa98e2SPeter Wemm 
4243c2aa98e2SPeter Wemm 	for (p = line; isascii(*p) && isspace(*p); p++)
4244c2aa98e2SPeter Wemm 		continue;
4245c2aa98e2SPeter Wemm 	q = p;
4246c2aa98e2SPeter Wemm 	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4247c2aa98e2SPeter Wemm 		p++;
4248c2aa98e2SPeter Wemm 	if (*p == '\0')
4249c2aa98e2SPeter Wemm 	{
425040266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
425140266059SGregory Neil Shapiro 				     "No address!\n");
4252c2aa98e2SPeter Wemm 		return;
4253c2aa98e2SPeter Wemm 	}
4254c2aa98e2SPeter Wemm 	*p = '\0';
425540266059SGregory Neil Shapiro 	if (invalidaddr(p + 1, NULL, true))
4256c2aa98e2SPeter Wemm 		return;
4257c2aa98e2SPeter Wemm 	do
4258c2aa98e2SPeter Wemm 	{
4259c2aa98e2SPeter Wemm 		register char **pvp;
4260c2aa98e2SPeter Wemm 		char pvpbuf[PSBUFSIZE];
4261c2aa98e2SPeter Wemm 
4262c2aa98e2SPeter Wemm 		pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
426306f25ae9SGregory Neil Shapiro 			      &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL);
4264c2aa98e2SPeter Wemm 		if (pvp == NULL)
4265c2aa98e2SPeter Wemm 			continue;
4266c2aa98e2SPeter Wemm 		p = q;
4267c2aa98e2SPeter Wemm 		while (*p != '\0')
4268c2aa98e2SPeter Wemm 		{
426906f25ae9SGregory Neil Shapiro 			int status;
4270c2aa98e2SPeter Wemm 
4271c2aa98e2SPeter Wemm 			rs = strtorwset(p, NULL, ST_FIND);
4272c2aa98e2SPeter Wemm 			if (rs < 0)
4273c2aa98e2SPeter Wemm 			{
427440266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
427540266059SGregory Neil Shapiro 						     "Undefined ruleset %s\n",
427640266059SGregory Neil Shapiro 						     p);
4277c2aa98e2SPeter Wemm 				break;
4278c2aa98e2SPeter Wemm 			}
427940266059SGregory Neil Shapiro 			status = REWRITE(pvp, rs, e);
428006f25ae9SGregory Neil Shapiro 			if (status != EX_OK)
428140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
428240266059SGregory Neil Shapiro 						     "== Ruleset %s (%d) status %d\n",
428306f25ae9SGregory Neil Shapiro 						     p, rs, status);
4284c2aa98e2SPeter Wemm 			while (*p != '\0' && *p++ != ',')
4285c2aa98e2SPeter Wemm 				continue;
4286c2aa98e2SPeter Wemm 		}
4287c2aa98e2SPeter Wemm 	} while (*(p = delimptr) != '\0');
4288c2aa98e2SPeter Wemm }
4289c2aa98e2SPeter Wemm 
429006f25ae9SGregory Neil Shapiro static void
4291c2aa98e2SPeter Wemm dump_class(s, id)
4292c2aa98e2SPeter Wemm 	register STAB *s;
4293c2aa98e2SPeter Wemm 	int id;
4294c2aa98e2SPeter Wemm {
429540266059SGregory Neil Shapiro 	if (s->s_symtype != ST_CLASS)
4296c2aa98e2SPeter Wemm 		return;
4297193538b7SGregory Neil Shapiro 	if (bitnset(bitidx(id), s->s_class))
429840266059SGregory Neil Shapiro 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
429940266059SGregory Neil Shapiro 				     "%s\n", s->s_name);
4300c2aa98e2SPeter Wemm }
430140266059SGregory Neil Shapiro 
430240266059SGregory Neil Shapiro /*
430340266059SGregory Neil Shapiro **  An exception type used to create QuickAbort exceptions.
430440266059SGregory Neil Shapiro **  This is my first cut at converting QuickAbort from longjmp to exceptions.
430540266059SGregory Neil Shapiro **  These exceptions have a single integer argument, which is the argument
430640266059SGregory Neil Shapiro **  to longjmp in the original code (either 1 or 2).  I don't know the
430740266059SGregory Neil Shapiro **  significance of 1 vs 2: the calls to setjmp don't care.
430840266059SGregory Neil Shapiro */
430940266059SGregory Neil Shapiro 
431040266059SGregory Neil Shapiro const SM_EXC_TYPE_T EtypeQuickAbort =
431140266059SGregory Neil Shapiro {
431240266059SGregory Neil Shapiro 	SmExcTypeMagic,
431340266059SGregory Neil Shapiro 	"E:mta.quickabort",
431440266059SGregory Neil Shapiro 	"i",
431540266059SGregory Neil Shapiro 	sm_etype_printf,
431640266059SGregory Neil Shapiro 	"quick abort %0",
431740266059SGregory Neil Shapiro };
4318