main.c revision 225906
1/*
2 * Copyright (c) 1998-2006, 2008, 2009, 2011 Sendmail, Inc. and its suppliers.
3 *	All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#define _DEFINE
15#include <sendmail.h>
16#include <sm/sendmail.h>
17#include <sm/xtrap.h>
18#include <sm/signal.h>
19
20#ifndef lint
21SM_UNUSED(static char copyright[]) =
22"@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\
23	All rights reserved.\n\
24     Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.\n\
25     Copyright (c) 1988, 1993\n\
26	The Regents of the University of California.  All rights reserved.\n";
27#endif /* ! lint */
28
29SM_RCSID("@(#)$Id: main.c,v 8.976 2011/03/15 23:14:36 ca Exp $")
30
31
32#if NETINET || NETINET6
33# include <arpa/inet.h>
34#endif /* NETINET || NETINET6 */
35
36/* for getcfname() */
37#include <sendmail/pathnames.h>
38
39static SM_DEBUG_T
40DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
41	"@(#)$Debug: no_persistent_restart - don't restart, log only $");
42
43static void	dump_class __P((STAB *, int));
44static void	obsolete __P((char **));
45static void	testmodeline __P((char *, ENVELOPE *));
46static char	*getextenv __P((const char *));
47static void	sm_printoptions __P((char **));
48static SIGFUNC_DECL	intindebug __P((int));
49static SIGFUNC_DECL	sighup __P((int));
50static SIGFUNC_DECL	sigpipe __P((int));
51static SIGFUNC_DECL	sigterm __P((int));
52#ifdef SIGUSR1
53static SIGFUNC_DECL	sigusr1 __P((int));
54#endif /* SIGUSR1 */
55
56/*
57**  SENDMAIL -- Post mail to a set of destinations.
58**
59**	This is the basic mail router.  All user mail programs should
60**	call this routine to actually deliver mail.  Sendmail in
61**	turn calls a bunch of mail servers that do the real work of
62**	delivering the mail.
63**
64**	Sendmail is driven by settings read in from /etc/mail/sendmail.cf
65**	(read by readcf.c).
66**
67**	Usage:
68**		/usr/lib/sendmail [flags] addr ...
69**
70**		See the associated documentation for details.
71**
72**	Authors:
73**		Eric Allman, UCB/INGRES (until 10/81).
74**			     Britton-Lee, Inc., purveyors of fine
75**				database computers (11/81 - 10/88).
76**			     International Computer Science Institute
77**				(11/88 - 9/89).
78**			     UCB/Mammoth Project (10/89 - 7/95).
79**			     InReference, Inc. (8/95 - 1/97).
80**			     Sendmail, Inc. (1/98 - present).
81**		The support of my employers is gratefully acknowledged.
82**			Few of them (Britton-Lee in particular) have had
83**			anything to gain from my involvement in this project.
84**
85**		Gregory Neil Shapiro,
86**			Worcester Polytechnic Institute	(until 3/98).
87**			Sendmail, Inc. (3/98 - present).
88**
89**		Claus Assmann,
90**			Sendmail, Inc. (12/98 - present).
91*/
92
93char		*FullName;	/* sender's full name */
94ENVELOPE	BlankEnvelope;	/* a "blank" envelope */
95static ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */
96ADDRESS		NullAddress =	/* a null address */
97		{ "", "", NULL, "" };
98char		*CommandLineArgs;	/* command line args for pid file */
99bool		Warn_Q_option = false;	/* warn about Q option use */
100static int	MissingFds = 0;	/* bit map of fds missing on startup */
101char		*Mbdb = "pw";	/* mailbox database defaults to /etc/passwd */
102
103#ifdef NGROUPS_MAX
104GIDSET_T	InitialGidSet[NGROUPS_MAX];
105#endif /* NGROUPS_MAX */
106
107#define MAXCONFIGLEVEL	10	/* highest config version level known */
108
109#if SASL
110static sasl_callback_t srvcallbacks[] =
111{
112	{	SASL_CB_VERIFYFILE,	(sasl_callback_ft)&safesaslfile,	NULL	},
113	{	SASL_CB_PROXY_POLICY,	(sasl_callback_ft)&proxy_policy,	NULL	},
114	{	SASL_CB_LIST_END,	NULL,		NULL	}
115};
116#endif /* SASL */
117
118unsigned int	SubmitMode;
119int		SyslogPrefixLen; /* estimated length of syslog prefix */
120#define PIDLEN		6	/* pid length for computing SyslogPrefixLen */
121#ifndef SL_FUDGE
122# define SL_FUDGE	10	/* fudge offset for SyslogPrefixLen */
123#endif /* ! SL_FUDGE */
124#define SLDLL		8	/* est. length of default syslog label */
125
126
127/* Some options are dangerous to allow users to use in non-submit mode */
128#define CHECK_AGAINST_OPMODE(cmd)					\
129{									\
130	if (extraprivs &&						\
131	    OpMode != MD_DELIVER && OpMode != MD_SMTP &&		\
132	    OpMode != MD_ARPAFTP && OpMode != MD_CHECKCONFIG &&		\
133	    OpMode != MD_VERIFY && OpMode != MD_TEST)			\
134	{								\
135		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
136				     "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
137		       (cmd));						\
138		break;							\
139	}								\
140	if (extraprivs && queuerun)					\
141	{								\
142		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\
143				     "WARNING: Ignoring submission mode -%c option with -q\n", \
144		       (cmd));						\
145		break;							\
146	}								\
147}
148
149int
150main(argc, argv, envp)
151	int argc;
152	char **argv;
153	char **envp;
154{
155	register char *p;
156	char **av;
157	extern char Version[];
158	char *ep, *from;
159	STAB *st;
160	register int i;
161	int j;
162	int dp;
163	int fill_errno;
164	int qgrp = NOQGRP;		/* queue group to process */
165	bool safecf = true;
166	BITMAP256 *p_flags = NULL;	/* daemon flags */
167	bool warn_C_flag = false;
168	bool auth = true;		/* whether to set e_auth_param */
169	char warn_f_flag = '\0';
170	bool run_in_foreground = false;	/* -bD mode */
171	bool queuerun = false, debug = false;
172	struct passwd *pw;
173	struct hostent *hp;
174	char *nullserver = NULL;
175	char *authinfo = NULL;
176	char *sysloglabel = NULL;	/* label for syslog */
177	char *conffile = NULL;		/* name of .cf file */
178	char *queuegroup = NULL;	/* queue group to process */
179	char *quarantining = NULL;	/* quarantine queue items? */
180	bool extraprivs;
181	bool forged, negate;
182	bool queuepersistent = false;	/* queue runner process runs forever */
183	bool foregroundqueue = false;	/* queue run in foreground */
184	bool save_val;			/* to save some bool var. */
185	int cftype;			/* which cf file to use? */
186	SM_FILE_T *smdebug;
187	static time_t starttime = 0;	/* when was process started */
188	struct stat traf_st;		/* for TrafficLog FIFO check */
189	char buf[MAXLINE];
190	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */
191	static char rnamebuf[MAXNAME];	/* holds RealUserName */
192	char *emptyenviron[1];
193#if STARTTLS
194	bool tls_ok;
195#endif /* STARTTLS */
196	QUEUE_CHAR *new;
197	ENVELOPE *e;
198	extern int DtableSize;
199	extern int optind;
200	extern int opterr;
201	extern char *optarg;
202	extern char **environ;
203#if SASL
204	extern void sm_sasl_init __P((void));
205#endif /* SASL */
206
207#if USE_ENVIRON
208	envp = environ;
209#endif /* USE_ENVIRON */
210
211	/* turn off profiling */
212	SM_PROF(0);
213
214	/* install default exception handler */
215	sm_exc_newthread(fatal_error);
216
217	/* set the default in/out channel so errors reported to screen */
218	InChannel = smioin;
219	OutChannel = smioout;
220
221	/*
222	**  Check to see if we reentered.
223	**	This would normally happen if e_putheader or e_putbody
224	**	were NULL when invoked.
225	*/
226
227	if (starttime != 0)
228	{
229		syserr("main: reentered!");
230		abort();
231	}
232	starttime = curtime();
233
234	/* avoid null pointer dereferences */
235	TermEscape.te_rv_on = TermEscape.te_under_on = TermEscape.te_normal = "";
236
237	RealUid = getuid();
238	RealGid = getgid();
239
240	/* Check if sendmail is running with extra privs */
241	extraprivs = (RealUid != 0 &&
242		      (geteuid() != getuid() || getegid() != getgid()));
243
244	CurrentPid = getpid();
245
246	/* get whatever .cf file is right for the opmode */
247	cftype = SM_GET_RIGHT_CF;
248
249	/* in 4.4BSD, the table can be huge; impose a reasonable limit */
250	DtableSize = getdtsize();
251	if (DtableSize > 256)
252		DtableSize = 256;
253
254	/*
255	**  Be sure we have enough file descriptors.
256	**	But also be sure that 0, 1, & 2 are open.
257	*/
258
259	/* reset errno and fill_errno; the latter is used way down below */
260	errno = fill_errno = 0;
261	fill_fd(STDIN_FILENO, NULL);
262	if (errno != 0)
263		fill_errno = errno;
264	fill_fd(STDOUT_FILENO, NULL);
265	if (errno != 0)
266		fill_errno = errno;
267	fill_fd(STDERR_FILENO, NULL);
268	if (errno != 0)
269		fill_errno = errno;
270
271	sm_closefrom(STDERR_FILENO + 1, DtableSize);
272	errno = 0;
273	smdebug = NULL;
274
275#if LOG
276# ifndef SM_LOG_STR
277#  define SM_LOG_STR	"sendmail"
278# endif /* ! SM_LOG_STR */
279#  ifdef LOG_MAIL
280	openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
281#  else /* LOG_MAIL */
282	openlog(SM_LOG_STR, LOG_PID);
283#  endif /* LOG_MAIL */
284#endif /* LOG */
285
286	/*
287	**  Seed the random number generator.
288	**  Used for queue file names, picking a queue directory, and
289	**  MX randomization.
290	*/
291
292	seed_random();
293
294	/* do machine-dependent initializations */
295	init_md(argc, argv);
296
297
298	SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;
299
300	/* reset status from syserr() calls for missing file descriptors */
301	Errors = 0;
302	ExitStat = EX_OK;
303
304	SubmitMode = SUBMIT_UNKNOWN;
305#if _FFR_LOCAL_DAEMON
306	LocalDaemon = false;
307# if NETINET6
308	V6LoopbackAddrFound = false;
309# endif /* NETINET6 */
310#endif /* _FFR_LOCAL_DAEMON */
311#if XDEBUG
312	checkfd012("after openlog");
313#endif /* XDEBUG */
314
315	tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1");
316
317#ifdef NGROUPS_MAX
318	/* save initial group set for future checks */
319	i = getgroups(NGROUPS_MAX, InitialGidSet);
320	if (i <= 0)
321	{
322		InitialGidSet[0] = (GID_T) -1;
323		i = 0;
324	}
325	while (i < NGROUPS_MAX)
326		InitialGidSet[i++] = InitialGidSet[0];
327#endif /* NGROUPS_MAX */
328
329	/* drop group id privileges (RunAsUser not yet set) */
330	dp = drop_privileges(false);
331	setstat(dp);
332
333#ifdef SIGUSR1
334	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
335	if (!extraprivs)
336	{
337		/* arrange to dump state on user-1 signal */
338		(void) sm_signal(SIGUSR1, sigusr1);
339	}
340	else
341	{
342		/* ignore user-1 signal */
343		(void) sm_signal(SIGUSR1, SIG_IGN);
344	}
345#endif /* SIGUSR1 */
346
347	/* initialize for setproctitle */
348	initsetproctitle(argc, argv, envp);
349
350	/* Handle any non-getoptable constructions. */
351	obsolete(argv);
352
353	/*
354	**  Do a quick prescan of the argument list.
355	*/
356
357
358	/* find initial opMode */
359	OpMode = MD_DELIVER;
360	av = argv;
361	p = strrchr(*av, '/');
362	if (p++ == NULL)
363		p = *av;
364	if (strcmp(p, "newaliases") == 0)
365		OpMode = MD_INITALIAS;
366	else if (strcmp(p, "mailq") == 0)
367		OpMode = MD_PRINT;
368	else if (strcmp(p, "smtpd") == 0)
369		OpMode = MD_DAEMON;
370	else if (strcmp(p, "hoststat") == 0)
371		OpMode = MD_HOSTSTAT;
372	else if (strcmp(p, "purgestat") == 0)
373		OpMode = MD_PURGESTAT;
374
375#if defined(__osf__) || defined(_AIX3)
376# define OPTIONS	"A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:x"
377#endif /* defined(__osf__) || defined(_AIX3) */
378#if defined(sony_news)
379# define OPTIONS	"A:B:b:C:cD:d:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:"
380#endif /* defined(sony_news) */
381#ifndef OPTIONS
382# define OPTIONS	"A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:"
383#endif /* ! OPTIONS */
384
385	/* Set to 0 to allow -b; need to check optarg before using it! */
386	opterr = 0;
387	while ((j = getopt(argc, argv, OPTIONS)) != -1)
388	{
389		switch (j)
390		{
391		  case 'b':	/* operations mode */
392			j = (optarg == NULL) ? ' ' : *optarg;
393			switch (j)
394			{
395			  case MD_DAEMON:
396			  case MD_FGDAEMON:
397			  case MD_SMTP:
398			  case MD_INITALIAS:
399			  case MD_DELIVER:
400			  case MD_VERIFY:
401			  case MD_TEST:
402			  case MD_PRINT:
403			  case MD_PRINTNQE:
404			  case MD_HOSTSTAT:
405			  case MD_PURGESTAT:
406			  case MD_ARPAFTP:
407#if _FFR_CHECKCONFIG
408			  case MD_CHECKCONFIG:
409#endif /* _FFR_CHECKCONFIG */
410				OpMode = j;
411				break;
412
413#if _FFR_LOCAL_DAEMON
414			  case MD_LOCAL:
415				OpMode = MD_DAEMON;
416				LocalDaemon = true;
417				break;
418#endif /* _FFR_LOCAL_DAEMON */
419
420			  case MD_FREEZE:
421				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
422						     "Frozen configurations unsupported\n");
423				return EX_USAGE;
424
425			  default:
426				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
427						     "Invalid operation mode %c\n",
428						     j);
429				return EX_USAGE;
430			}
431			break;
432
433		  case 'D':
434			if (debug)
435			{
436				errno = 0;
437				syserr("-D file must be before -d");
438				ExitStat = EX_USAGE;
439				break;
440			}
441			dp = drop_privileges(true);
442			setstat(dp);
443			smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
444					    optarg, SM_IO_APPEND, NULL);
445			if (smdebug == NULL)
446			{
447				syserr("cannot open %s", optarg);
448				ExitStat = EX_CANTCREAT;
449				break;
450			}
451			sm_debug_setfile(smdebug);
452			break;
453
454		  case 'd':
455			debug = true;
456			tTflag(optarg);
457			(void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT,
458					     (char *) NULL, SM_IO_NBF,
459					     SM_IO_BUFSIZ);
460			break;
461
462		  case 'G':	/* relay (gateway) submission */
463			SubmitMode = SUBMIT_MTA;
464			break;
465
466		  case 'L':
467			if (optarg == NULL)
468			{
469				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
470						     "option requires an argument -- '%c'",
471						     (char) j);
472				return EX_USAGE;
473			}
474			j = SM_MIN(strlen(optarg), 32) + 1;
475			sysloglabel = xalloc(j);
476			(void) sm_strlcpy(sysloglabel, optarg, j);
477			SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +
478					  SL_FUDGE + j;
479			break;
480
481		  case 'Q':
482		  case 'q':
483			/* just check if it is there */
484			queuerun = true;
485			break;
486		}
487	}
488	opterr = 1;
489
490	/* Don't leak queue information via debug flags */
491	if (extraprivs && queuerun && debug)
492	{
493		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
494				     "WARNING: Can not use -d with -q.  Disabling debugging.\n");
495		sm_debug_close();
496		sm_debug_setfile(NULL);
497		(void) memset(tTdvect, '\0', sizeof(tTdvect));
498	}
499
500#if LOG
501	if (sysloglabel != NULL)
502	{
503		/* Sanitize the string */
504		for (p = sysloglabel; *p != '\0'; p++)
505		{
506			if (!isascii(*p) || !isprint(*p) || *p == '%')
507				*p = '*';
508		}
509		closelog();
510#  ifdef LOG_MAIL
511		openlog(sysloglabel, LOG_PID, LOG_MAIL);
512#  else /* LOG_MAIL */
513		openlog(sysloglabel, LOG_PID);
514#  endif /* LOG_MAIL */
515	}
516#endif /* LOG */
517
518	/* set up the blank envelope */
519	BlankEnvelope.e_puthdr = putheader;
520	BlankEnvelope.e_putbody = putbody;
521	BlankEnvelope.e_xfp = NULL;
522	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
523	CurEnv = &BlankEnvelope;
524	STRUCTCOPY(NullAddress, MainEnvelope.e_from);
525
526	/*
527	**  Set default values for variables.
528	**	These cannot be in initialized data space.
529	*/
530
531	setdefaults(&BlankEnvelope);
532	initmacros(&BlankEnvelope);
533
534	/* reset macro */
535	set_op_mode(OpMode);
536	if (OpMode == MD_DAEMON)
537		DaemonPid = CurrentPid;	/* needed for finis() to work */
538
539	pw = sm_getpwuid(RealUid);
540	if (pw != NULL)
541		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof(rnamebuf));
542	else
543		(void) sm_snprintf(rnamebuf, sizeof(rnamebuf), "Unknown UID %d",
544				   (int) RealUid);
545
546	RealUserName = rnamebuf;
547
548	if (tTd(0, 101))
549	{
550		sm_dprintf("Version %s\n", Version);
551		finis(false, true, EX_OK);
552		/* NOTREACHED */
553	}
554
555	/*
556	**  if running non-set-user-ID binary as non-root, pretend
557	**  we are the RunAsUid
558	*/
559
560	if (RealUid != 0 && geteuid() == RealUid)
561	{
562		if (tTd(47, 1))
563			sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",
564				   (int) RealUid);
565		RunAsUid = RealUid;
566	}
567	else if (geteuid() != 0)
568		RunAsUid = geteuid();
569
570	EffGid = getegid();
571	if (RealUid != 0 && EffGid == RealGid)
572		RunAsGid = RealGid;
573
574	if (tTd(47, 5))
575	{
576		sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
577			   (int) geteuid(), (int) getuid(),
578			   (int) getegid(), (int) getgid());
579		sm_dprintf("main: RunAsUser = %d:%d\n",
580			   (int) RunAsUid, (int) RunAsGid);
581	}
582
583	/* save command line arguments */
584	j = 0;
585	for (av = argv; *av != NULL; )
586		j += strlen(*av++) + 1;
587	SaveArgv = (char **) xalloc(sizeof(char *) * (argc + 1));
588	CommandLineArgs = xalloc(j);
589	p = CommandLineArgs;
590	for (av = argv, i = 0; *av != NULL; )
591	{
592		int h;
593
594		SaveArgv[i++] = newstr(*av);
595		if (av != argv)
596			*p++ = ' ';
597		(void) sm_strlcpy(p, *av++, j);
598		h = strlen(p);
599		p += h;
600		j -= h + 1;
601	}
602	SaveArgv[i] = NULL;
603
604	if (tTd(0, 1))
605	{
606		extern char *CompileOptions[];
607
608		sm_dprintf("Version %s\n Compiled with:", Version);
609		sm_printoptions(CompileOptions);
610	}
611	if (tTd(0, 10))
612	{
613		extern char *OsCompileOptions[];
614
615		sm_dprintf("    OS Defines:");
616		sm_printoptions(OsCompileOptions);
617#ifdef _PATH_UNIX
618		sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
619#endif /* _PATH_UNIX */
620
621		sm_dprintf("     Conf file:\t%s (default for MSP)\n",
622			   getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
623				     conffile));
624		sm_dprintf("     Conf file:\t%s (default for MTA)\n",
625			   getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,
626				     conffile));
627		sm_dprintf("      Pid file:\t%s (default)\n", PidFile);
628	}
629
630	if (tTd(0, 12))
631	{
632		extern char *SmCompileOptions[];
633
634		sm_dprintf(" libsm Defines:");
635		sm_printoptions(SmCompileOptions);
636	}
637
638	if (tTd(0, 13))
639	{
640		extern char *FFRCompileOptions[];
641
642		sm_dprintf("   FFR Defines:");
643		sm_printoptions(FFRCompileOptions);
644	}
645
646	/* clear sendmail's environment */
647	ExternalEnviron = environ;
648	emptyenviron[0] = NULL;
649	environ = emptyenviron;
650
651	/*
652	**  restore any original TZ setting until TimeZoneSpec has been
653	**  determined - or early log messages may get bogus time stamps
654	*/
655
656	if ((p = getextenv("TZ")) != NULL)
657	{
658		char *tz;
659		int tzlen;
660
661		/* XXX check for reasonable length? */
662		tzlen = strlen(p) + 4;
663		tz = xalloc(tzlen);
664		(void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);
665
666		/* XXX check return code? */
667		(void) putenv(tz);
668	}
669
670	/* prime the child environment */
671	sm_setuserenv("AGENT", "sendmail");
672
673	(void) sm_signal(SIGPIPE, SIG_IGN);
674	OldUmask = umask(022);
675	FullName = getextenv("NAME");
676	if (FullName != NULL)
677		FullName = newstr(FullName);
678
679	/*
680	**  Initialize name server if it is going to be used.
681	*/
682
683#if NAMED_BIND
684	if (!bitset(RES_INIT, _res.options))
685		(void) res_init();
686	if (tTd(8, 8))
687		_res.options |= RES_DEBUG;
688	else
689		_res.options &= ~RES_DEBUG;
690# ifdef RES_NOALIASES
691	_res.options |= RES_NOALIASES;
692# endif /* RES_NOALIASES */
693	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
694	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
695	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
696	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
697	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
698	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
699#endif /* NAMED_BIND */
700
701	errno = 0;
702	from = NULL;
703
704	/* initialize some macros, etc. */
705	init_vendor_macros(&BlankEnvelope);
706
707	/* version */
708	macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);
709
710	/* hostname */
711	hp = myhostname(jbuf, sizeof(jbuf));
712	if (jbuf[0] != '\0')
713	{
714		struct utsname utsname;
715
716		if (tTd(0, 4))
717			sm_dprintf("Canonical name: %s\n", jbuf);
718		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);
719		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);
720		setclass('w', jbuf);
721
722		p = strchr(jbuf, '.');
723		if (p != NULL && p[1] != '\0')
724			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]);
725
726		if (uname(&utsname) >= 0)
727			p = utsname.nodename;
728		else
729		{
730			if (tTd(0, 22))
731				sm_dprintf("uname failed (%s)\n",
732					   sm_errstring(errno));
733			makelower(jbuf);
734			p = jbuf;
735		}
736		if (tTd(0, 4))
737			sm_dprintf(" UUCP nodename: %s\n", p);
738		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);
739		setclass('k', p);
740		setclass('w', p);
741	}
742	if (hp != NULL)
743	{
744		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
745		{
746			if (tTd(0, 4))
747				sm_dprintf("\ta.k.a.: %s\n", *av);
748			setclass('w', *av);
749		}
750#if NETINET || NETINET6
751		for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)
752		{
753# if NETINET6
754			char *addr;
755			char buf6[INET6_ADDRSTRLEN];
756			struct in6_addr ia6;
757# endif /* NETINET6 */
758# if NETINET
759			struct in_addr ia;
760# endif /* NETINET */
761			char ipbuf[103];
762
763			ipbuf[0] = '\0';
764			switch (hp->h_addrtype)
765			{
766# if NETINET
767			  case AF_INET:
768				if (hp->h_length != INADDRSZ)
769					break;
770
771				memmove(&ia, hp->h_addr_list[i], INADDRSZ);
772				(void) sm_snprintf(ipbuf, sizeof(ipbuf),
773						   "[%.100s]", inet_ntoa(ia));
774				break;
775# endif /* NETINET */
776
777# if NETINET6
778			  case AF_INET6:
779				if (hp->h_length != IN6ADDRSZ)
780					break;
781
782				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
783				addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
784				if (addr != NULL)
785					(void) sm_snprintf(ipbuf, sizeof(ipbuf),
786							   "[%.100s]", addr);
787				break;
788# endif /* NETINET6 */
789			}
790			if (ipbuf[0] == '\0')
791				break;
792
793			if (tTd(0, 4))
794				sm_dprintf("\ta.k.a.: %s\n", ipbuf);
795			setclass('w', ipbuf);
796		}
797#endif /* NETINET || NETINET6 */
798#if NETINET6
799		freehostent(hp);
800		hp = NULL;
801#endif /* NETINET6 */
802	}
803
804	/* current time */
805	macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));
806
807	/* current load average */
808	sm_getla();
809
810	QueueLimitRecipient = (QUEUE_CHAR *) NULL;
811	QueueLimitSender = (QUEUE_CHAR *) NULL;
812	QueueLimitId = (QUEUE_CHAR *) NULL;
813	QueueLimitQuarantine = (QUEUE_CHAR *) NULL;
814
815	/*
816	**  Crack argv.
817	*/
818
819	optind = 1;
820	while ((j = getopt(argc, argv, OPTIONS)) != -1)
821	{
822		switch (j)
823		{
824		  case 'b':	/* operations mode */
825			/* already done */
826			break;
827
828		  case 'A':	/* use Alternate sendmail/submit.cf */
829			cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF
830						  : SM_GET_SENDMAIL_CF;
831			break;
832
833		  case 'B':	/* body type */
834			CHECK_AGAINST_OPMODE(j);
835			BlankEnvelope.e_bodytype = newstr(optarg);
836			break;
837
838		  case 'C':	/* select configuration file (already done) */
839			if (RealUid != 0)
840				warn_C_flag = true;
841			conffile = newstr(optarg);
842			dp = drop_privileges(true);
843			setstat(dp);
844			safecf = false;
845			break;
846
847		  case 'D':
848		  case 'd':	/* debugging */
849			/* already done */
850			break;
851
852		  case 'f':	/* from address */
853		  case 'r':	/* obsolete -f flag */
854			CHECK_AGAINST_OPMODE(j);
855			if (from != NULL)
856			{
857				usrerr("More than one \"from\" person");
858				ExitStat = EX_USAGE;
859				break;
860			}
861			if (optarg[0] == '\0')
862				from = newstr("<>");
863			else
864				from = newstr(denlstring(optarg, true, true));
865			if (strcmp(RealUserName, from) != 0)
866				warn_f_flag = j;
867			break;
868
869		  case 'F':	/* set full name */
870			CHECK_AGAINST_OPMODE(j);
871			FullName = newstr(optarg);
872			break;
873
874		  case 'G':	/* relay (gateway) submission */
875			/* already set */
876			CHECK_AGAINST_OPMODE(j);
877			break;
878
879		  case 'h':	/* hop count */
880			CHECK_AGAINST_OPMODE(j);
881			BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,
882								  10);
883			(void) sm_snprintf(buf, sizeof(buf), "%d",
884					   BlankEnvelope.e_hopcount);
885			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);
886
887			if (*ep)
888			{
889				usrerr("Bad hop count (%s)", optarg);
890				ExitStat = EX_USAGE;
891			}
892			break;
893
894		  case 'L':	/* program label */
895			/* already set */
896			break;
897
898		  case 'n':	/* don't alias */
899			CHECK_AGAINST_OPMODE(j);
900			NoAlias = true;
901			break;
902
903		  case 'N':	/* delivery status notifications */
904			CHECK_AGAINST_OPMODE(j);
905			DefaultNotify |= QHASNOTIFY;
906			macdefine(&BlankEnvelope.e_macro, A_TEMP,
907				macid("{dsn_notify}"), optarg);
908			if (sm_strcasecmp(optarg, "never") == 0)
909				break;
910			for (p = optarg; p != NULL; optarg = p)
911			{
912				p = strchr(p, ',');
913				if (p != NULL)
914					*p++ = '\0';
915				if (sm_strcasecmp(optarg, "success") == 0)
916					DefaultNotify |= QPINGONSUCCESS;
917				else if (sm_strcasecmp(optarg, "failure") == 0)
918					DefaultNotify |= QPINGONFAILURE;
919				else if (sm_strcasecmp(optarg, "delay") == 0)
920					DefaultNotify |= QPINGONDELAY;
921				else
922				{
923					usrerr("Invalid -N argument");
924					ExitStat = EX_USAGE;
925				}
926			}
927			break;
928
929		  case 'o':	/* set option */
930			setoption(*optarg, optarg + 1, false, true,
931				  &BlankEnvelope);
932			break;
933
934		  case 'O':	/* set option (long form) */
935			setoption(' ', optarg, false, true, &BlankEnvelope);
936			break;
937
938		  case 'p':	/* set protocol */
939			CHECK_AGAINST_OPMODE(j);
940			p = strchr(optarg, ':');
941			if (p != NULL)
942			{
943				*p++ = '\0';
944				if (*p != '\0')
945				{
946					i = strlen(p) + 1;
947					ep = sm_malloc_x(i);
948					cleanstrcpy(ep, p, i);
949					macdefine(&BlankEnvelope.e_macro,
950						  A_HEAP, 's', ep);
951				}
952			}
953			if (*optarg != '\0')
954			{
955				i = strlen(optarg) + 1;
956				ep = sm_malloc_x(i);
957				cleanstrcpy(ep, optarg, i);
958				macdefine(&BlankEnvelope.e_macro, A_HEAP,
959					  'r', ep);
960			}
961			break;
962
963		  case 'Q':	/* change quarantining on queued items */
964			/* sanity check */
965			if (OpMode != MD_DELIVER &&
966			    OpMode != MD_QUEUERUN)
967			{
968				usrerr("Can not use -Q with -b%c", OpMode);
969				ExitStat = EX_USAGE;
970				break;
971			}
972
973			if (OpMode == MD_DELIVER)
974				set_op_mode(MD_QUEUERUN);
975
976			FullName = NULL;
977
978			quarantining = newstr(optarg);
979			break;
980
981		  case 'q':	/* run queue files at intervals */
982			/* sanity check */
983			if (OpMode != MD_DELIVER &&
984			    OpMode != MD_DAEMON &&
985			    OpMode != MD_FGDAEMON &&
986			    OpMode != MD_PRINT &&
987			    OpMode != MD_PRINTNQE &&
988			    OpMode != MD_QUEUERUN)
989			{
990				usrerr("Can not use -q with -b%c", OpMode);
991				ExitStat = EX_USAGE;
992				break;
993			}
994
995			/* don't override -bd, -bD or -bp */
996			if (OpMode == MD_DELIVER)
997				set_op_mode(MD_QUEUERUN);
998
999			FullName = NULL;
1000			negate = optarg[0] == '!';
1001			if (negate)
1002			{
1003				/* negate meaning of pattern match */
1004				optarg++; /* skip '!' for next switch */
1005			}
1006
1007			switch (optarg[0])
1008			{
1009			  case 'G': /* Limit by queue group name */
1010				if (negate)
1011				{
1012					usrerr("Can not use -q!G");
1013					ExitStat = EX_USAGE;
1014					break;
1015				}
1016				if (queuegroup != NULL)
1017				{
1018					usrerr("Can not use multiple -qG options");
1019					ExitStat = EX_USAGE;
1020					break;
1021				}
1022				queuegroup = newstr(&optarg[1]);
1023				break;
1024
1025			  case 'I': /* Limit by ID */
1026				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1027				new->queue_match = newstr(&optarg[1]);
1028				new->queue_negate = negate;
1029				new->queue_next = QueueLimitId;
1030				QueueLimitId = new;
1031				break;
1032
1033			  case 'R': /* Limit by recipient */
1034				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1035				new->queue_match = newstr(&optarg[1]);
1036				new->queue_negate = negate;
1037				new->queue_next = QueueLimitRecipient;
1038				QueueLimitRecipient = new;
1039				break;
1040
1041			  case 'S': /* Limit by sender */
1042				new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1043				new->queue_match = newstr(&optarg[1]);
1044				new->queue_negate = negate;
1045				new->queue_next = QueueLimitSender;
1046				QueueLimitSender = new;
1047				break;
1048
1049			  case 'f': /* foreground queue run */
1050				foregroundqueue  = true;
1051				break;
1052
1053			  case 'Q': /* Limit by quarantine message */
1054				if (optarg[1] != '\0')
1055				{
1056					new = (QUEUE_CHAR *) xalloc(sizeof(*new));
1057					new->queue_match = newstr(&optarg[1]);
1058					new->queue_negate = negate;
1059					new->queue_next = QueueLimitQuarantine;
1060					QueueLimitQuarantine = new;
1061				}
1062				QueueMode = QM_QUARANTINE;
1063				break;
1064
1065			  case 'L': /* act on lost items */
1066				QueueMode = QM_LOST;
1067				break;
1068
1069			  case 'p': /* Persistent queue */
1070				queuepersistent = true;
1071				if (QueueIntvl == 0)
1072					QueueIntvl = 1;
1073				if (optarg[1] == '\0')
1074					break;
1075				++optarg;
1076				/* FALLTHROUGH */
1077
1078			  default:
1079				i = Errors;
1080				QueueIntvl = convtime(optarg, 'm');
1081				if (QueueIntvl < 0)
1082				{
1083					usrerr("Invalid -q value");
1084					ExitStat = EX_USAGE;
1085				}
1086
1087				/* check for bad conversion */
1088				if (i < Errors)
1089					ExitStat = EX_USAGE;
1090				break;
1091			}
1092			break;
1093
1094		  case 'R':	/* DSN RET: what to return */
1095			CHECK_AGAINST_OPMODE(j);
1096			if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))
1097			{
1098				usrerr("Duplicate -R flag");
1099				ExitStat = EX_USAGE;
1100				break;
1101			}
1102			BlankEnvelope.e_flags |= EF_RET_PARAM;
1103			if (sm_strcasecmp(optarg, "hdrs") == 0)
1104				BlankEnvelope.e_flags |= EF_NO_BODY_RETN;
1105			else if (sm_strcasecmp(optarg, "full") != 0)
1106			{
1107				usrerr("Invalid -R value");
1108				ExitStat = EX_USAGE;
1109			}
1110			macdefine(&BlankEnvelope.e_macro, A_TEMP,
1111				  macid("{dsn_ret}"), optarg);
1112			break;
1113
1114		  case 't':	/* read recipients from message */
1115			CHECK_AGAINST_OPMODE(j);
1116			GrabTo = true;
1117			break;
1118
1119		  case 'V':	/* DSN ENVID: set "original" envelope id */
1120			CHECK_AGAINST_OPMODE(j);
1121			if (!xtextok(optarg))
1122			{
1123				usrerr("Invalid syntax in -V flag");
1124				ExitStat = EX_USAGE;
1125			}
1126			else
1127			{
1128				BlankEnvelope.e_envid = newstr(optarg);
1129				macdefine(&BlankEnvelope.e_macro, A_TEMP,
1130					  macid("{dsn_envid}"), optarg);
1131			}
1132			break;
1133
1134		  case 'X':	/* traffic log file */
1135			dp = drop_privileges(true);
1136			setstat(dp);
1137			if (stat(optarg, &traf_st) == 0 &&
1138			    S_ISFIFO(traf_st.st_mode))
1139				TrafficLogFile = sm_io_open(SmFtStdio,
1140							    SM_TIME_DEFAULT,
1141							    optarg,
1142							    SM_IO_WRONLY, NULL);
1143			else
1144				TrafficLogFile = sm_io_open(SmFtStdio,
1145							    SM_TIME_DEFAULT,
1146							    optarg,
1147							    SM_IO_APPEND, NULL);
1148			if (TrafficLogFile == NULL)
1149			{
1150				syserr("cannot open %s", optarg);
1151				ExitStat = EX_CANTCREAT;
1152				break;
1153			}
1154			(void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,
1155					     NULL, SM_IO_LBF, 0);
1156			break;
1157
1158			/* compatibility flags */
1159		  case 'c':	/* connect to non-local mailers */
1160		  case 'i':	/* don't let dot stop me */
1161		  case 'm':	/* send to me too */
1162		  case 'T':	/* set timeout interval */
1163		  case 'v':	/* give blow-by-blow description */
1164			setoption(j, "T", false, true, &BlankEnvelope);
1165			break;
1166
1167		  case 'e':	/* error message disposition */
1168		  case 'M':	/* define macro */
1169			setoption(j, optarg, false, true, &BlankEnvelope);
1170			break;
1171
1172		  case 's':	/* save From lines in headers */
1173			setoption('f', "T", false, true, &BlankEnvelope);
1174			break;
1175
1176#ifdef DBM
1177		  case 'I':	/* initialize alias DBM file */
1178			set_op_mode(MD_INITALIAS);
1179			break;
1180#endif /* DBM */
1181
1182#if defined(__osf__) || defined(_AIX3)
1183		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */
1184			break;
1185#endif /* defined(__osf__) || defined(_AIX3) */
1186#if defined(sony_news)
1187		  case 'E':
1188		  case 'J':	/* ignore flags for Japanese code conversion
1189				   implemented on Sony NEWS */
1190			break;
1191#endif /* defined(sony_news) */
1192
1193		  default:
1194			finis(true, true, EX_USAGE);
1195			/* NOTREACHED */
1196			break;
1197		}
1198	}
1199
1200	/* if we've had errors so far, exit now */
1201	if ((ExitStat != EX_OK && OpMode != MD_TEST && OpMode != MD_CHECKCONFIG) ||
1202	    ExitStat == EX_OSERR)
1203	{
1204		finis(false, true, ExitStat);
1205		/* NOTREACHED */
1206	}
1207
1208	if (bitset(SUBMIT_MTA, SubmitMode))
1209	{
1210		/* If set daemon_flags on command line, don't reset it */
1211		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
1212			macdefine(&BlankEnvelope.e_macro, A_PERM,
1213				  macid("{daemon_flags}"), "CC f");
1214	}
1215	else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)
1216	{
1217		SubmitMode = SUBMIT_MSA;
1218
1219		/* If set daemon_flags on command line, don't reset it */
1220		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
1221			macdefine(&BlankEnvelope.e_macro, A_PERM,
1222				  macid("{daemon_flags}"), "c u");
1223	}
1224
1225	/*
1226	**  Do basic initialization.
1227	**	Read system control file.
1228	**	Extract special fields for local use.
1229	*/
1230
1231#if XDEBUG
1232	checkfd012("before readcf");
1233#endif /* XDEBUG */
1234	vendor_pre_defaults(&BlankEnvelope);
1235
1236	readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
1237			 safecf, &BlankEnvelope);
1238#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
1239	ConfigFileRead = true;
1240#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
1241	vendor_post_defaults(&BlankEnvelope);
1242
1243	/* now we can complain about missing fds */
1244	if (MissingFds != 0 && LogLevel > 8)
1245	{
1246		char mbuf[MAXLINE];
1247
1248		mbuf[0] = '\0';
1249		if (bitset(1 << STDIN_FILENO, MissingFds))
1250			(void) sm_strlcat(mbuf, ", stdin", sizeof(mbuf));
1251		if (bitset(1 << STDOUT_FILENO, MissingFds))
1252			(void) sm_strlcat(mbuf, ", stdout", sizeof(mbuf));
1253		if (bitset(1 << STDERR_FILENO, MissingFds))
1254			(void) sm_strlcat(mbuf, ", stderr", sizeof(mbuf));
1255
1256		/* Notice: fill_errno is from high above: fill_fd() */
1257		sm_syslog(LOG_WARNING, NOQID,
1258			  "File descriptors missing on startup: %s; %s",
1259			  &mbuf[2], sm_errstring(fill_errno));
1260	}
1261
1262	/* Remove the ability for a normal user to send signals */
1263	if (RealUid != 0 && RealUid != geteuid())
1264	{
1265		uid_t new_uid = geteuid();
1266
1267#if HASSETREUID
1268		/*
1269		**  Since we can differentiate between uid and euid,
1270		**  make the uid a different user so the real user
1271		**  can't send signals.  However, it doesn't need to be
1272		**  root (euid has root).
1273		*/
1274
1275		if (new_uid == 0)
1276			new_uid = DefUid;
1277		if (tTd(47, 5))
1278			sm_dprintf("Changing real uid to %d\n", (int) new_uid);
1279		if (setreuid(new_uid, geteuid()) < 0)
1280		{
1281			syserr("main: setreuid(%d, %d) failed",
1282			       (int) new_uid, (int) geteuid());
1283			finis(false, true, EX_OSERR);
1284			/* NOTREACHED */
1285		}
1286		if (tTd(47, 10))
1287			sm_dprintf("Now running as e/ruid %d:%d\n",
1288				   (int) geteuid(), (int) getuid());
1289#else /* HASSETREUID */
1290		/*
1291		**  Have to change both effective and real so need to
1292		**  change them both to effective to keep privs.
1293		*/
1294
1295		if (tTd(47, 5))
1296			sm_dprintf("Changing uid to %d\n", (int) new_uid);
1297		if (setuid(new_uid) < 0)
1298		{
1299			syserr("main: setuid(%d) failed", (int) new_uid);
1300			finis(false, true, EX_OSERR);
1301			/* NOTREACHED */
1302		}
1303		if (tTd(47, 10))
1304			sm_dprintf("Now running as e/ruid %d:%d\n",
1305				   (int) geteuid(), (int) getuid());
1306#endif /* HASSETREUID */
1307	}
1308
1309#if NAMED_BIND
1310	if (FallbackMX != NULL)
1311		(void) getfallbackmxrr(FallbackMX);
1312#endif /* NAMED_BIND */
1313
1314	if (SuperSafe == SAFE_INTERACTIVE && !SM_IS_INTERACTIVE(CurEnv->e_sendmode))
1315	{
1316		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1317				     "WARNING: SuperSafe=interactive should only be used with\n         DeliveryMode=interactive\n");
1318	}
1319
1320	if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))
1321	{
1322		usrerr("Mail submission program cannot be used as daemon");
1323		finis(false, true, EX_USAGE);
1324	}
1325
1326	if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||
1327	    OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||
1328	    OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)
1329		makeworkgroups();
1330
1331	/* set up the basic signal handlers */
1332	if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)
1333		(void) sm_signal(SIGINT, intsig);
1334	(void) sm_signal(SIGTERM, intsig);
1335
1336	/* Enforce use of local time (null string overrides this) */
1337	if (TimeZoneSpec == NULL)
1338		unsetenv("TZ");
1339	else if (TimeZoneSpec[0] != '\0')
1340		sm_setuserenv("TZ", TimeZoneSpec);
1341	else
1342		sm_setuserenv("TZ", NULL);
1343	tzset();
1344
1345	/* initialize mailbox database */
1346	i = sm_mbdb_initialize(Mbdb);
1347	if (i != EX_OK)
1348	{
1349		usrerr("Can't initialize mailbox database \"%s\": %s",
1350		       Mbdb, sm_strexit(i));
1351		ExitStat = i;
1352	}
1353
1354	/* avoid denial-of-service attacks */
1355	resetlimits();
1356
1357	if (OpMode == MD_TEST)
1358	{
1359		/* can't be done after readcf if RunAs* is used */
1360		dp = drop_privileges(true);
1361		if (dp != EX_OK)
1362		{
1363			finis(false, true, dp);
1364			/* NOTREACHED */
1365		}
1366	}
1367	else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
1368	{
1369		/* drop privileges -- daemon mode done after socket/bind */
1370		dp = drop_privileges(false);
1371		setstat(dp);
1372		if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))
1373		{
1374			usrerr("Mail submission program must have RunAsUser set to non root user");
1375			finis(false, true, EX_CONFIG);
1376			/* NOTREACHED */
1377		}
1378	}
1379
1380#if NAMED_BIND
1381	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
1382	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
1383#endif /* NAMED_BIND */
1384
1385	/*
1386	**  Find our real host name for future logging.
1387	*/
1388
1389	authinfo = getauthinfo(STDIN_FILENO, &forged);
1390	macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
1391
1392	/* suppress error printing if errors mailed back or whatever */
1393	if (BlankEnvelope.e_errormode != EM_PRINT)
1394		HoldErrs = true;
1395
1396	/* set up the $=m class now, after .cf has a chance to redefine $m */
1397	expand("\201m", jbuf, sizeof(jbuf), &BlankEnvelope);
1398	if (jbuf[0] != '\0')
1399		setclass('m', jbuf);
1400
1401	/* probe interfaces and locate any additional names */
1402	if (DontProbeInterfaces != DPI_PROBENONE)
1403		load_if_names();
1404
1405	if (tTd(0, 10))
1406	{
1407		char pidpath[MAXPATHLEN];
1408
1409		/* Now we know which .cf file we use */
1410		sm_dprintf("     Conf file:\t%s (selected)\n",
1411			   getcfname(OpMode, SubmitMode, cftype, conffile));
1412		expand(PidFile, pidpath, sizeof(pidpath), &BlankEnvelope);
1413		sm_dprintf("      Pid file:\t%s (selected)\n", pidpath);
1414	}
1415
1416	if (tTd(0, 1))
1417	{
1418		sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
1419		sm_dprintf("\n      (short domain name) $w = ");
1420		xputs(sm_debug_file(), macvalue('w', &BlankEnvelope));
1421		sm_dprintf("\n  (canonical domain name) $j = ");
1422		xputs(sm_debug_file(), macvalue('j', &BlankEnvelope));
1423		sm_dprintf("\n         (subdomain name) $m = ");
1424		xputs(sm_debug_file(), macvalue('m', &BlankEnvelope));
1425		sm_dprintf("\n              (node name) $k = ");
1426		xputs(sm_debug_file(), macvalue('k', &BlankEnvelope));
1427		sm_dprintf("\n========================================================\n\n");
1428	}
1429
1430	/*
1431	**  Do more command line checking -- these are things that
1432	**  have to modify the results of reading the config file.
1433	*/
1434
1435	/* process authorization warnings from command line */
1436	if (warn_C_flag)
1437		auth_warning(&BlankEnvelope, "Processed by %s with -C %s",
1438			     RealUserName, conffile);
1439	if (Warn_Q_option && !wordinclass(RealUserName, 't'))
1440		auth_warning(&BlankEnvelope, "Processed from queue %s",
1441			     QueueDir);
1442	if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&
1443	    RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)
1444		sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",
1445			  (int) RealUid);
1446
1447	/* check body type for legality */
1448	i = check_bodytype(BlankEnvelope.e_bodytype);
1449	if (i == BODYTYPE_ILLEGAL)
1450	{
1451		usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
1452		BlankEnvelope.e_bodytype = NULL;
1453	}
1454	else if (i != BODYTYPE_NONE)
1455		SevenBitInput = (i == BODYTYPE_7BIT);
1456
1457	/* tweak default DSN notifications */
1458	if (DefaultNotify == 0)
1459		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1460
1461	/* check for sane configuration level */
1462	if (ConfigLevel > MAXCONFIGLEVEL)
1463	{
1464		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1465		       ConfigLevel, Version, MAXCONFIGLEVEL);
1466	}
1467
1468	/* need MCI cache to have persistence */
1469	if (HostStatDir != NULL && MaxMciCache == 0)
1470	{
1471		HostStatDir = NULL;
1472		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1473				     "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1474	}
1475
1476	/* need HostStatusDir in order to have SingleThreadDelivery */
1477	if (SingleThreadDelivery && HostStatDir == NULL)
1478	{
1479		SingleThreadDelivery = false;
1480		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1481				     "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1482	}
1483
1484#if _FFR_MEMSTAT
1485	j = sm_memstat_open();
1486	if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4)
1487	{
1488		sm_syslog(LOG_WARNING, NOQID,
1489			  "cannot get memory statistics, settings ignored, error=%d"
1490			  , j);
1491	}
1492#endif /* _FFR_MEMSTAT */
1493
1494	/* check for permissions */
1495	if (RealUid != 0 &&
1496	    RealUid != TrustedUid)
1497	{
1498		char *action = NULL;
1499
1500		switch (OpMode)
1501		{
1502		  case MD_QUEUERUN:
1503			if (quarantining != NULL)
1504				action = "quarantine jobs";
1505			else
1506			{
1507				/* Normal users can do a single queue run */
1508				if (QueueIntvl == 0)
1509					break;
1510			}
1511
1512			/* but not persistent queue runners */
1513			if (action == NULL)
1514				action = "start a queue runner daemon";
1515			/* FALLTHROUGH */
1516
1517		  case MD_PURGESTAT:
1518			if (action == NULL)
1519				action = "purge host status";
1520			/* FALLTHROUGH */
1521
1522		  case MD_DAEMON:
1523		  case MD_FGDAEMON:
1524			if (action == NULL)
1525				action = "run daemon";
1526
1527			if (tTd(65, 1))
1528				sm_dprintf("Deny user %d attempt to %s\n",
1529					   (int) RealUid, action);
1530
1531			if (LogLevel > 1)
1532				sm_syslog(LOG_ALERT, NOQID,
1533					  "user %d attempted to %s",
1534					  (int) RealUid, action);
1535			HoldErrs = false;
1536			usrerr("Permission denied (real uid not trusted)");
1537			finis(false, true, EX_USAGE);
1538			/* NOTREACHED */
1539			break;
1540
1541		  case MD_VERIFY:
1542			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))
1543			{
1544				/*
1545				**  If -bv and RestrictExpand,
1546				**  drop privs to prevent normal
1547				**  users from reading private
1548				**  aliases/forwards/:include:s
1549				*/
1550
1551				if (tTd(65, 1))
1552					sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",
1553						   (int) RealUid);
1554
1555				dp = drop_privileges(true);
1556
1557				/* Fake address safety */
1558				if (tTd(65, 1))
1559					sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");
1560				setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);
1561
1562				if (dp != EX_OK)
1563				{
1564					if (tTd(65, 1))
1565						sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",
1566							   (int) RealUid);
1567					CurEnv->e_id = NULL;
1568					finis(true, true, dp);
1569					/* NOTREACHED */
1570				}
1571			}
1572			break;
1573
1574		  case MD_TEST:
1575		  case MD_CHECKCONFIG:
1576		  case MD_PRINT:
1577		  case MD_PRINTNQE:
1578		  case MD_FREEZE:
1579		  case MD_HOSTSTAT:
1580			/* Nothing special to check */
1581			break;
1582
1583		  case MD_INITALIAS:
1584			if (!wordinclass(RealUserName, 't'))
1585			{
1586				if (tTd(65, 1))
1587					sm_dprintf("Deny user %d attempt to rebuild the alias map\n",
1588						   (int) RealUid);
1589				if (LogLevel > 1)
1590					sm_syslog(LOG_ALERT, NOQID,
1591						  "user %d attempted to rebuild the alias map",
1592						  (int) RealUid);
1593				HoldErrs = false;
1594				usrerr("Permission denied (real uid not trusted)");
1595				finis(false, true, EX_USAGE);
1596				/* NOTREACHED */
1597			}
1598			if (UseMSP)
1599			{
1600				HoldErrs = false;
1601				usrerr("User %d cannot rebuild aliases in mail submission program",
1602				       (int) RealUid);
1603				finis(false, true, EX_USAGE);
1604				/* NOTREACHED */
1605			}
1606			/* FALLTHROUGH */
1607
1608		  default:
1609			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&
1610			    Verbose != 0)
1611			{
1612				/*
1613				**  If -v and RestrictExpand, reset
1614				**  Verbose to prevent normal users
1615				**  from seeing the expansion of
1616				**  aliases/forwards/:include:s
1617				*/
1618
1619				if (tTd(65, 1))
1620					sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",
1621						   (int) RealUid);
1622				Verbose = 0;
1623			}
1624			break;
1625		}
1626	}
1627
1628	if (MeToo)
1629		BlankEnvelope.e_flags |= EF_METOO;
1630
1631	switch (OpMode)
1632	{
1633	  case MD_TEST:
1634		/* don't have persistent host status in test mode */
1635		HostStatDir = NULL;
1636		/* FALLTHROUGH */
1637
1638	  case MD_CHECKCONFIG:
1639		if (Verbose == 0)
1640			Verbose = 2;
1641		BlankEnvelope.e_errormode = EM_PRINT;
1642		HoldErrs = false;
1643		break;
1644
1645	  case MD_VERIFY:
1646		BlankEnvelope.e_errormode = EM_PRINT;
1647		HoldErrs = false;
1648		/* arrange to exit cleanly on hangup signal */
1649		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1650			(void) sm_signal(SIGHUP, intsig);
1651		if (geteuid() != 0)
1652			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1653					     "Notice: -bv may give misleading output for non-privileged user\n");
1654		break;
1655
1656	  case MD_FGDAEMON:
1657		run_in_foreground = true;
1658		set_op_mode(MD_DAEMON);
1659		/* FALLTHROUGH */
1660
1661	  case MD_DAEMON:
1662		vendor_daemon_setup(&BlankEnvelope);
1663
1664		/* remove things that don't make sense in daemon mode */
1665		FullName = NULL;
1666		GrabTo = false;
1667
1668		/* arrange to restart on hangup signal */
1669		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1670			sm_syslog(LOG_WARNING, NOQID,
1671				  "daemon invoked without full pathname; kill -1 won't work");
1672		break;
1673
1674	  case MD_INITALIAS:
1675		Verbose = 2;
1676		BlankEnvelope.e_errormode = EM_PRINT;
1677		HoldErrs = false;
1678		/* FALLTHROUGH */
1679
1680	  default:
1681		/* arrange to exit cleanly on hangup signal */
1682		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1683			(void) sm_signal(SIGHUP, intsig);
1684		break;
1685	}
1686
1687	/* special considerations for FullName */
1688	if (FullName != NULL)
1689	{
1690		char *full = NULL;
1691
1692		/* full names can't have newlines */
1693		if (strchr(FullName, '\n') != NULL)
1694		{
1695			full = newstr(denlstring(FullName, true, true));
1696			FullName = full;
1697		}
1698
1699		/* check for characters that may have to be quoted */
1700		if (!rfc822_string(FullName))
1701		{
1702			/*
1703			**  Quote a full name with special characters
1704			**  as a comment so crackaddr() doesn't destroy
1705			**  the name portion of the address.
1706			*/
1707
1708			FullName = addquotes(FullName, NULL);
1709			if (full != NULL)
1710				sm_free(full);  /* XXX */
1711		}
1712	}
1713
1714	/* do heuristic mode adjustment */
1715	if (Verbose)
1716	{
1717		/* turn off noconnect option */
1718		setoption('c', "F", true, false, &BlankEnvelope);
1719
1720		/* turn on interactive delivery */
1721		setoption('d', "", true, false, &BlankEnvelope);
1722	}
1723
1724#ifdef VENDOR_CODE
1725	/* check for vendor mismatch */
1726	if (VendorCode != VENDOR_CODE)
1727	{
1728		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1729			getvendor(VENDOR_CODE), getvendor(VendorCode));
1730	}
1731#endif /* VENDOR_CODE */
1732
1733	/* check for out of date configuration level */
1734	if (ConfigLevel < MAXCONFIGLEVEL)
1735	{
1736		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1737			Version, MAXCONFIGLEVEL, ConfigLevel);
1738	}
1739
1740	if (ConfigLevel < 3)
1741		UseErrorsTo = true;
1742
1743	/* set options that were previous macros */
1744	if (SmtpGreeting == NULL)
1745	{
1746		if (ConfigLevel < 7 &&
1747		    (p = macvalue('e', &BlankEnvelope)) != NULL)
1748			SmtpGreeting = newstr(p);
1749		else
1750			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1751	}
1752	if (UnixFromLine == NULL)
1753	{
1754		if (ConfigLevel < 7 &&
1755		    (p = macvalue('l', &BlankEnvelope)) != NULL)
1756			UnixFromLine = newstr(p);
1757		else
1758			UnixFromLine = "From \201g  \201d";
1759	}
1760	SmtpError[0] = '\0';
1761
1762	/* our name for SMTP codes */
1763	expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
1764	if (jbuf[0] == '\0')
1765		PSTRSET(MyHostName, "localhost");
1766	else
1767		PSTRSET(MyHostName, jbuf);
1768	if (strchr(MyHostName, '.') == NULL)
1769		message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?",
1770			MyHostName);
1771
1772	/* make certain that this name is part of the $=w class */
1773	setclass('w', MyHostName);
1774
1775	/* fill in the structure of the *default* queue */
1776	st = stab("mqueue", ST_QUEUE, ST_FIND);
1777	if (st == NULL)
1778		syserr("No default queue (mqueue) defined");
1779	else
1780		set_def_queueval(st->s_quegrp, true);
1781
1782	/* the indices of built-in mailers */
1783	st = stab("local", ST_MAILER, ST_FIND);
1784	if (st != NULL)
1785		LocalMailer = st->s_mailer;
1786	else if (OpMode != MD_TEST || !warn_C_flag)
1787		syserr("No local mailer defined");
1788
1789	st = stab("prog", ST_MAILER, ST_FIND);
1790	if (st == NULL)
1791		syserr("No prog mailer defined");
1792	else
1793	{
1794		ProgMailer = st->s_mailer;
1795		clrbitn(M_MUSER, ProgMailer->m_flags);
1796	}
1797
1798	st = stab("*file*", ST_MAILER, ST_FIND);
1799	if (st == NULL)
1800		syserr("No *file* mailer defined");
1801	else
1802	{
1803		FileMailer = st->s_mailer;
1804		clrbitn(M_MUSER, FileMailer->m_flags);
1805	}
1806
1807	st = stab("*include*", ST_MAILER, ST_FIND);
1808	if (st == NULL)
1809		syserr("No *include* mailer defined");
1810	else
1811		InclMailer = st->s_mailer;
1812
1813	if (ConfigLevel < 6)
1814	{
1815		/* heuristic tweaking of local mailer for back compat */
1816		if (LocalMailer != NULL)
1817		{
1818			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1819			setbitn(M_HASPWENT, LocalMailer->m_flags);
1820			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1821			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1822			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1823			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1824			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1825		}
1826		if (ProgMailer != NULL)
1827			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1828		if (FileMailer != NULL)
1829			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1830	}
1831	if (ConfigLevel < 7)
1832	{
1833		if (LocalMailer != NULL)
1834			setbitn(M_VRFY250, LocalMailer->m_flags);
1835		if (ProgMailer != NULL)
1836			setbitn(M_VRFY250, ProgMailer->m_flags);
1837		if (FileMailer != NULL)
1838			setbitn(M_VRFY250, FileMailer->m_flags);
1839	}
1840
1841	/* MIME Content-Types that cannot be transfer encoded */
1842	setclass('n', "multipart/signed");
1843
1844	/* MIME message/xxx subtypes that can be treated as messages */
1845	setclass('s', "rfc822");
1846
1847	/* MIME Content-Transfer-Encodings that can be encoded */
1848	setclass('e', "7bit");
1849	setclass('e', "8bit");
1850	setclass('e', "binary");
1851
1852#ifdef USE_B_CLASS
1853	/* MIME Content-Types that should be treated as binary */
1854	setclass('b', "image");
1855	setclass('b', "audio");
1856	setclass('b', "video");
1857	setclass('b', "application/octet-stream");
1858#endif /* USE_B_CLASS */
1859
1860	/* MIME headers which have fields to check for overflow */
1861	setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");
1862	setclass(macid("{checkMIMEFieldHeaders}"), "content-type");
1863
1864	/* MIME headers to check for length overflow */
1865	setclass(macid("{checkMIMETextHeaders}"), "content-description");
1866
1867	/* MIME headers to check for overflow and rebalance */
1868	setclass(macid("{checkMIMEHeaders}"), "content-disposition");
1869	setclass(macid("{checkMIMEHeaders}"), "content-id");
1870	setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");
1871	setclass(macid("{checkMIMEHeaders}"), "content-type");
1872	setclass(macid("{checkMIMEHeaders}"), "mime-version");
1873
1874	/* Macros to save in the queue file -- don't remove any */
1875	setclass(macid("{persistentMacros}"), "r");
1876	setclass(macid("{persistentMacros}"), "s");
1877	setclass(macid("{persistentMacros}"), "_");
1878	setclass(macid("{persistentMacros}"), "{if_addr}");
1879	setclass(macid("{persistentMacros}"), "{daemon_flags}");
1880
1881	/* operate in queue directory */
1882	if (QueueDir == NULL || *QueueDir == '\0')
1883	{
1884		if (OpMode != MD_TEST)
1885		{
1886			syserr("QueueDirectory (Q) option must be set");
1887			ExitStat = EX_CONFIG;
1888		}
1889	}
1890	else
1891	{
1892		if (OpMode != MD_TEST)
1893			setup_queues(OpMode == MD_DAEMON);
1894	}
1895
1896	/* check host status directory for validity */
1897	if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))
1898	{
1899		/* cannot use this value */
1900		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1901				     "Warning: Cannot use HostStatusDirectory = %s: %s\n",
1902				     HostStatDir, sm_errstring(errno));
1903		HostStatDir = NULL;
1904	}
1905
1906	if (OpMode == MD_QUEUERUN &&
1907	    RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1908	{
1909		struct stat stbuf;
1910
1911		/* check to see if we own the queue directory */
1912		if (stat(".", &stbuf) < 0)
1913			syserr("main: cannot stat %s", QueueDir);
1914		if (stbuf.st_uid != RealUid)
1915		{
1916			/* nope, really a botch */
1917			HoldErrs = false;
1918			usrerr("You do not have permission to process the queue");
1919			finis(false, true, EX_NOPERM);
1920			/* NOTREACHED */
1921		}
1922	}
1923
1924#if MILTER
1925	/* sanity checks on milter filters */
1926	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
1927	{
1928		milter_config(InputFilterList, InputFilters, MAXFILTERS);
1929		setup_daemon_milters();
1930	}
1931#endif /* MILTER */
1932
1933	/* Convert queuegroup string to qgrp number */
1934	if (queuegroup != NULL)
1935	{
1936		qgrp = name2qid(queuegroup);
1937		if (qgrp == NOQGRP)
1938		{
1939			HoldErrs = false;
1940			usrerr("Queue group %s unknown", queuegroup);
1941			finis(false, true, ExitStat);
1942			/* NOTREACHED */
1943		}
1944	}
1945
1946	/* if checking config or have had errors so far, exit now */
1947	if (OpMode == MD_CHECKCONFIG || (ExitStat != EX_OK && OpMode != MD_TEST))
1948	{
1949		finis(false, true, ExitStat);
1950		/* NOTREACHED */
1951	}
1952
1953#if SASL
1954	/* sendmail specific SASL initialization */
1955	sm_sasl_init();
1956#endif /* SASL */
1957
1958#if XDEBUG
1959	checkfd012("before main() initmaps");
1960#endif /* XDEBUG */
1961
1962	/*
1963	**  Do operation-mode-dependent initialization.
1964	*/
1965
1966	switch (OpMode)
1967	{
1968	  case MD_PRINT:
1969		/* print the queue */
1970		HoldErrs = false;
1971		(void) dropenvelope(&BlankEnvelope, true, false);
1972		(void) sm_signal(SIGPIPE, sigpipe);
1973		if (qgrp != NOQGRP)
1974		{
1975			int j;
1976
1977			/* Selecting a particular queue group to run */
1978			for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
1979			{
1980				if (StopRequest)
1981					stop_sendmail();
1982				(void) print_single_queue(qgrp, j);
1983			}
1984			finis(false, true, EX_OK);
1985			/* NOTREACHED */
1986		}
1987		printqueue();
1988		finis(false, true, EX_OK);
1989		/* NOTREACHED */
1990		break;
1991
1992	  case MD_PRINTNQE:
1993		/* print number of entries in queue */
1994		(void) dropenvelope(&BlankEnvelope, true, false);
1995		(void) sm_signal(SIGPIPE, sigpipe);
1996		printnqe(smioout, NULL);
1997		finis(false, true, EX_OK);
1998		/* NOTREACHED */
1999		break;
2000
2001	  case MD_QUEUERUN:
2002		/* only handle quarantining here */
2003		if (quarantining == NULL)
2004			break;
2005
2006		if (QueueMode != QM_QUARANTINE &&
2007		    QueueMode != QM_NORMAL)
2008		{
2009			HoldErrs = false;
2010			usrerr("Can not use -Q with -q%c", QueueMode);
2011			ExitStat = EX_USAGE;
2012			finis(false, true, ExitStat);
2013			/* NOTREACHED */
2014		}
2015		quarantine_queue(quarantining, qgrp);
2016		finis(false, true, EX_OK);
2017		break;
2018
2019	  case MD_HOSTSTAT:
2020		(void) sm_signal(SIGPIPE, sigpipe);
2021		(void) mci_traverse_persistent(mci_print_persistent, NULL);
2022		finis(false, true, EX_OK);
2023		/* NOTREACHED */
2024		break;
2025
2026	  case MD_PURGESTAT:
2027		(void) mci_traverse_persistent(mci_purge_persistent, NULL);
2028		finis(false, true, EX_OK);
2029		/* NOTREACHED */
2030		break;
2031
2032	  case MD_INITALIAS:
2033		/* initialize maps */
2034		initmaps();
2035		finis(false, true, ExitStat);
2036		/* NOTREACHED */
2037		break;
2038
2039	  case MD_SMTP:
2040	  case MD_DAEMON:
2041		/* reset DSN parameters */
2042		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
2043		macdefine(&BlankEnvelope.e_macro, A_PERM,
2044			  macid("{dsn_notify}"), NULL);
2045		BlankEnvelope.e_envid = NULL;
2046		macdefine(&BlankEnvelope.e_macro, A_PERM,
2047			  macid("{dsn_envid}"), NULL);
2048		BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
2049		macdefine(&BlankEnvelope.e_macro, A_PERM,
2050			  macid("{dsn_ret}"), NULL);
2051
2052		/* don't open maps for daemon -- done below in child */
2053		break;
2054	}
2055
2056	if (tTd(0, 15))
2057	{
2058		/* print configuration table (or at least part of it) */
2059		if (tTd(0, 90))
2060			printrules();
2061		for (i = 0; i < MAXMAILERS; i++)
2062		{
2063			if (Mailer[i] != NULL)
2064				printmailer(sm_debug_file(), Mailer[i]);
2065		}
2066	}
2067
2068	/*
2069	**  Switch to the main envelope.
2070	*/
2071
2072	CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,
2073			     sm_rpool_new_x(NULL));
2074	MainEnvelope.e_flags = BlankEnvelope.e_flags;
2075
2076	/*
2077	**  If test mode, read addresses from stdin and process.
2078	*/
2079
2080	if (OpMode == MD_TEST)
2081	{
2082		if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))
2083			Verbose = 2;
2084
2085		if (Verbose)
2086		{
2087			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2088				     "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
2089			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2090				     "Enter <ruleset> <address>\n");
2091		}
2092		macdefine(&(MainEnvelope.e_macro), A_PERM,
2093			  macid("{addr_type}"), "e r");
2094		for (;;)
2095		{
2096			SM_TRY
2097			{
2098				(void) sm_signal(SIGINT, intindebug);
2099				(void) sm_releasesignal(SIGINT);
2100				if (Verbose == 2)
2101					(void) sm_io_fprintf(smioout,
2102							     SM_TIME_DEFAULT,
2103							     "> ");
2104				(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
2105				if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,
2106						sizeof(buf)) == NULL)
2107					testmodeline("/quit", &MainEnvelope);
2108				p = strchr(buf, '\n');
2109				if (p != NULL)
2110					*p = '\0';
2111				if (Verbose < 2)
2112					(void) sm_io_fprintf(smioout,
2113							     SM_TIME_DEFAULT,
2114							     "> %s\n", buf);
2115				testmodeline(buf, &MainEnvelope);
2116			}
2117			SM_EXCEPT(exc, "[!F]*")
2118			{
2119				/*
2120				**  8.10 just prints \n on interrupt.
2121				**  I'm printing the exception here in case
2122				**  sendmail is extended to raise additional
2123				**  exceptions in this context.
2124				*/
2125
2126				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2127						     "\n");
2128				sm_exc_print(exc, smioout);
2129			}
2130			SM_END_TRY
2131		}
2132	}
2133
2134#if STARTTLS
2135	tls_ok = true;
2136	if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER ||
2137	    OpMode == MD_ARPAFTP)
2138	{
2139		/* check whether STARTTLS is turned off for the client */
2140		if (chkclientmodifiers(D_NOTLS))
2141			tls_ok = false;
2142	}
2143	else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||
2144		 OpMode == MD_SMTP)
2145	{
2146		/* check whether STARTTLS is turned off */
2147		if (chkdaemonmodifiers(D_NOTLS) && chkclientmodifiers(D_NOTLS))
2148			tls_ok = false;
2149	}
2150	else	/* other modes don't need STARTTLS */
2151		tls_ok = false;
2152
2153	if (tls_ok)
2154	{
2155		/* basic TLS initialization */
2156		tls_ok = init_tls_library();
2157	}
2158
2159	if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
2160	{
2161		/* disable TLS for client */
2162		setclttls(false);
2163	}
2164#endif /* STARTTLS */
2165
2166	/*
2167	**  If collecting stuff from the queue, go start doing that.
2168	*/
2169
2170	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
2171	{
2172		pid_t pid = -1;
2173
2174#if STARTTLS
2175		/* init TLS for client, ignore result for now */
2176		(void) initclttls(tls_ok);
2177#endif /* STARTTLS */
2178
2179		/*
2180		**  The parent process of the caller of runqueue() needs
2181		**  to stay around for a possible SIGTERM. The SIGTERM will
2182		**  tell this process that all of the queue runners children
2183		**  need to be sent SIGTERM as well. At the same time, we
2184		**  want to return control to the command line. So we do an
2185		**  extra fork().
2186		*/
2187
2188		if (Verbose || foregroundqueue || (pid = fork()) <= 0)
2189		{
2190			/*
2191			**  If the fork() failed we should still try to do
2192			**  the queue run. If it succeeded then the child
2193			**  is going to start the run and wait for all
2194			**  of the children to finish.
2195			*/
2196
2197			if (pid == 0)
2198			{
2199				/* Reset global flags */
2200				RestartRequest = NULL;
2201				ShutdownRequest = NULL;
2202				PendingSignal = 0;
2203
2204				/* disconnect from terminal */
2205				disconnect(2, CurEnv);
2206			}
2207
2208			CurrentPid = getpid();
2209			if (qgrp != NOQGRP)
2210			{
2211				int rwgflags = RWG_NONE;
2212
2213				/*
2214				**  To run a specific queue group mark it to
2215				**  be run, select the work group it's in and
2216				**  increment the work counter.
2217				*/
2218
2219				for (i = 0; i < NumQueue && Queue[i] != NULL;
2220				     i++)
2221					Queue[i]->qg_nextrun = (time_t) -1;
2222				Queue[qgrp]->qg_nextrun = 0;
2223				if (Verbose)
2224					rwgflags |= RWG_VERBOSE;
2225				if (queuepersistent)
2226					rwgflags |= RWG_PERSISTENT;
2227				rwgflags |= RWG_FORCE;
2228				(void) run_work_group(Queue[qgrp]->qg_wgrp,
2229						      rwgflags);
2230			}
2231			else
2232				(void) runqueue(false, Verbose,
2233						queuepersistent, true);
2234
2235			/* set the title to make it easier to find */
2236			sm_setproctitle(true, CurEnv, "Queue control");
2237			(void) sm_signal(SIGCHLD, SIG_DFL);
2238			while (CurChildren > 0)
2239			{
2240				int status;
2241				pid_t ret;
2242
2243				errno = 0;
2244				while ((ret = sm_wait(&status)) <= 0)
2245				{
2246					if (errno == ECHILD)
2247					{
2248						/*
2249						**  Oops... something got messed
2250						**  up really bad. Waiting for
2251						**  non-existent children
2252						**  shouldn't happen. Let's get
2253						**  out of here.
2254						*/
2255
2256						CurChildren = 0;
2257						break;
2258					}
2259					continue;
2260				}
2261
2262				/* something is really really wrong */
2263				if (errno == ECHILD)
2264				{
2265					sm_syslog(LOG_ERR, NOQID,
2266						  "queue control process: lost all children: wait returned ECHILD");
2267					break;
2268				}
2269
2270				/* Only drop when a child gives status */
2271				if (WIFSTOPPED(status))
2272					continue;
2273
2274				proc_list_drop(ret, status, NULL);
2275			}
2276		}
2277		finis(true, true, ExitStat);
2278		/* NOTREACHED */
2279	}
2280
2281# if SASL
2282	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2283	{
2284		/* check whether AUTH is turned off for the server */
2285		if (!chkdaemonmodifiers(D_NOAUTH) &&
2286		    (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
2287			syserr("!sasl_server_init failed! [%s]",
2288				sasl_errstring(i, NULL, NULL));
2289	}
2290# endif /* SASL */
2291
2292	if (OpMode == MD_SMTP)
2293	{
2294		proc_list_add(CurrentPid, "Sendmail SMTP Agent",
2295			      PROC_DAEMON, 0, -1, NULL);
2296
2297		/* clean up background delivery children */
2298		(void) sm_signal(SIGCHLD, reapchild);
2299	}
2300
2301	/*
2302	**  If a daemon, wait for a request.
2303	**	getrequests will always return in a child.
2304	**	If we should also be processing the queue, start
2305	**		doing it in background.
2306	**	We check for any errors that might have happened
2307	**		during startup.
2308	*/
2309
2310	if (OpMode == MD_DAEMON || QueueIntvl > 0)
2311	{
2312		char dtype[200];
2313
2314		/* avoid cleanup in finis(), DaemonPid will be set below */
2315		DaemonPid = 0;
2316		if (!run_in_foreground && !tTd(99, 100))
2317		{
2318			/* put us in background */
2319			i = fork();
2320			if (i < 0)
2321				syserr("daemon: cannot fork");
2322			if (i != 0)
2323			{
2324				finis(false, true, EX_OK);
2325				/* NOTREACHED */
2326			}
2327
2328			/*
2329			**  Initialize exception stack and default exception
2330			**  handler for child process.
2331			*/
2332
2333			/* Reset global flags */
2334			RestartRequest = NULL;
2335			RestartWorkGroup = false;
2336			ShutdownRequest = NULL;
2337			PendingSignal = 0;
2338			CurrentPid = getpid();
2339
2340			sm_exc_newthread(fatal_error);
2341
2342			/* disconnect from our controlling tty */
2343			disconnect(2, &MainEnvelope);
2344		}
2345
2346		dtype[0] = '\0';
2347		if (OpMode == MD_DAEMON)
2348		{
2349			(void) sm_strlcat(dtype, "+SMTP", sizeof(dtype));
2350			DaemonPid = CurrentPid;
2351		}
2352		if (QueueIntvl > 0)
2353		{
2354			(void) sm_strlcat2(dtype,
2355					   queuepersistent
2356					   ? "+persistent-queueing@"
2357					   : "+queueing@",
2358					   pintvl(QueueIntvl, true),
2359					   sizeof(dtype));
2360		}
2361		if (tTd(0, 1))
2362			(void) sm_strlcat(dtype, "+debugging", sizeof(dtype));
2363
2364		sm_syslog(LOG_INFO, NOQID,
2365			  "starting daemon (%s): %s", Version, dtype + 1);
2366#if XLA
2367		xla_create_file();
2368#endif /* XLA */
2369
2370		/* save daemon type in a macro for possible PidFile use */
2371		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2372			macid("{daemon_info}"), dtype + 1);
2373
2374		/* save queue interval in a macro for possible PidFile use */
2375		macdefine(&MainEnvelope.e_macro, A_TEMP,
2376			macid("{queue_interval}"), pintvl(QueueIntvl, true));
2377
2378		/* workaround: can't seem to release the signal in the parent */
2379		(void) sm_signal(SIGHUP, sighup);
2380		(void) sm_releasesignal(SIGHUP);
2381		(void) sm_signal(SIGTERM, sigterm);
2382
2383		if (QueueIntvl > 0)
2384		{
2385#if _FFR_RUNPQG
2386			if (qgrp != NOQGRP)
2387			{
2388				int rwgflags = RWG_NONE;
2389
2390				/*
2391				**  To run a specific queue group mark it to
2392				**  be run, select the work group it's in and
2393				**  increment the work counter.
2394				*/
2395
2396				for (i = 0; i < NumQueue && Queue[i] != NULL;
2397				     i++)
2398					Queue[i]->qg_nextrun = (time_t) -1;
2399				Queue[qgrp]->qg_nextrun = 0;
2400				if (Verbose)
2401					rwgflags |= RWG_VERBOSE;
2402				if (queuepersistent)
2403					rwgflags |= RWG_PERSISTENT;
2404				rwgflags |= RWG_FORCE;
2405				(void) run_work_group(Queue[qgrp]->qg_wgrp,
2406						      rwgflags);
2407			}
2408			else
2409#endif /* _FFR_RUNPQG */
2410				(void) runqueue(true, false, queuepersistent,
2411						true);
2412
2413			/*
2414			**  If queuepersistent but not in daemon mode then
2415			**  we're going to do the queue runner monitoring here.
2416			**  If in daemon mode then the monitoring will happen
2417			**  elsewhere.
2418			*/
2419
2420			if (OpMode != MD_DAEMON && queuepersistent)
2421			{
2422				/*
2423				**  Write the pid to file
2424				**  XXX Overwrites sendmail.pid
2425				*/
2426
2427				log_sendmail_pid(&MainEnvelope);
2428
2429				/* set the title to make it easier to find */
2430				sm_setproctitle(true, CurEnv, "Queue control");
2431				(void) sm_signal(SIGCHLD, SIG_DFL);
2432				while (CurChildren > 0)
2433				{
2434					int status;
2435					pid_t ret;
2436					int group;
2437
2438					CHECK_RESTART;
2439					errno = 0;
2440					while ((ret = sm_wait(&status)) <= 0)
2441					{
2442						/*
2443						**  Waiting for non-existent
2444						**  children shouldn't happen.
2445						**  Let's get out of here if
2446						**  it occurs.
2447						*/
2448
2449						if (errno == ECHILD)
2450						{
2451							CurChildren = 0;
2452							break;
2453						}
2454						continue;
2455					}
2456
2457					/* something is really really wrong */
2458					if (errno == ECHILD)
2459					{
2460						sm_syslog(LOG_ERR, NOQID,
2461							  "persistent queue runner control process: lost all children: wait returned ECHILD");
2462						break;
2463					}
2464
2465					if (WIFSTOPPED(status))
2466						continue;
2467
2468					/* Probe only on a child status */
2469					proc_list_drop(ret, status, &group);
2470
2471					if (WIFSIGNALED(status))
2472					{
2473						if (WCOREDUMP(status))
2474						{
2475							sm_syslog(LOG_ERR, NOQID,
2476								  "persistent queue runner=%d core dumped, signal=%d",
2477								  group, WTERMSIG(status));
2478
2479							/* don't restart this */
2480							mark_work_group_restart(
2481								group, -1);
2482							continue;
2483						}
2484
2485						sm_syslog(LOG_ERR, NOQID,
2486							  "persistent queue runner=%d died, pid=%ld, signal=%d",
2487							  group, (long) ret,
2488							  WTERMSIG(status));
2489					}
2490
2491					/*
2492					**  When debugging active, don't
2493					**  restart the persistent queues.
2494					**  But do log this as info.
2495					*/
2496
2497					if (sm_debug_active(&DebugNoPRestart,
2498							    1))
2499					{
2500						sm_syslog(LOG_DEBUG, NOQID,
2501							  "persistent queue runner=%d, exited",
2502							  group);
2503						mark_work_group_restart(group,
2504									-1);
2505					}
2506					CHECK_RESTART;
2507				}
2508				finis(true, true, ExitStat);
2509				/* NOTREACHED */
2510			}
2511
2512			if (OpMode != MD_DAEMON)
2513			{
2514				char qtype[200];
2515
2516				/*
2517				**  Write the pid to file
2518				**  XXX Overwrites sendmail.pid
2519				*/
2520
2521				log_sendmail_pid(&MainEnvelope);
2522
2523				/* set the title to make it easier to find */
2524				qtype[0] = '\0';
2525				(void) sm_strlcpyn(qtype, sizeof(qtype), 4,
2526						   "Queue runner@",
2527						   pintvl(QueueIntvl, true),
2528						   " for ",
2529						   QueueDir);
2530				sm_setproctitle(true, CurEnv, qtype);
2531				for (;;)
2532				{
2533					(void) pause();
2534
2535					CHECK_RESTART;
2536
2537					if (doqueuerun())
2538						(void) runqueue(true, false,
2539								false, false);
2540				}
2541			}
2542		}
2543		(void) dropenvelope(&MainEnvelope, true, false);
2544
2545#if STARTTLS
2546		/* init TLS for server, ignore result for now */
2547		(void) initsrvtls(tls_ok);
2548#endif /* STARTTLS */
2549
2550	nextreq:
2551		p_flags = getrequests(&MainEnvelope);
2552
2553		/* drop privileges */
2554		(void) drop_privileges(false);
2555
2556		/*
2557		**  Get authentication data
2558		**  Set _ macro in BlankEnvelope before calling newenvelope().
2559		*/
2560
2561		authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
2562						     NULL), &forged);
2563		macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
2564
2565		/* at this point we are in a child: reset state */
2566		sm_rpool_free(MainEnvelope.e_rpool);
2567		(void) newenvelope(&MainEnvelope, &MainEnvelope,
2568				   sm_rpool_new_x(NULL));
2569	}
2570
2571	if (LogLevel > 9)
2572	{
2573		/* log connection information */
2574		sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo);
2575	}
2576
2577	/*
2578	**  If running SMTP protocol, start collecting and executing
2579	**  commands.  This will never return.
2580	*/
2581
2582	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2583	{
2584		char pbuf[20];
2585
2586		/*
2587		**  Save some macros for check_* rulesets.
2588		*/
2589
2590		if (forged)
2591		{
2592			char ipbuf[103];
2593
2594			(void) sm_snprintf(ipbuf, sizeof(ipbuf), "[%.100s]",
2595					   anynet_ntoa(&RealHostAddr));
2596			macdefine(&BlankEnvelope.e_macro, A_TEMP,
2597				  macid("{client_name}"), ipbuf);
2598		}
2599		else
2600			macdefine(&BlankEnvelope.e_macro, A_PERM,
2601				  macid("{client_name}"), RealHostName);
2602		macdefine(&BlankEnvelope.e_macro, A_PERM,
2603			  macid("{client_ptr}"), RealHostName);
2604		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2605			  macid("{client_addr}"), anynet_ntoa(&RealHostAddr));
2606		sm_getla();
2607
2608		switch (RealHostAddr.sa.sa_family)
2609		{
2610#if NETINET
2611		  case AF_INET:
2612			(void) sm_snprintf(pbuf, sizeof(pbuf), "%d",
2613					   RealHostAddr.sin.sin_port);
2614			break;
2615#endif /* NETINET */
2616#if NETINET6
2617		  case AF_INET6:
2618			(void) sm_snprintf(pbuf, sizeof(pbuf), "%d",
2619					   RealHostAddr.sin6.sin6_port);
2620			break;
2621#endif /* NETINET6 */
2622		  default:
2623			(void) sm_snprintf(pbuf, sizeof(pbuf), "0");
2624			break;
2625		}
2626		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2627			macid("{client_port}"), pbuf);
2628
2629		if (OpMode == MD_DAEMON)
2630		{
2631			ENVELOPE *saved_env;
2632
2633			/* validate the connection */
2634			HoldErrs = true;
2635			saved_env = CurEnv;
2636			CurEnv = &BlankEnvelope;
2637			nullserver = validate_connection(&RealHostAddr,
2638						macvalue(macid("{client_name}"),
2639							&BlankEnvelope),
2640						&BlankEnvelope);
2641			if (bitset(EF_DISCARD, BlankEnvelope.e_flags))
2642				MainEnvelope.e_flags |= EF_DISCARD;
2643			CurEnv = saved_env;
2644			HoldErrs = false;
2645		}
2646		else if (p_flags == NULL)
2647		{
2648			p_flags = (BITMAP256 *) xalloc(sizeof(*p_flags));
2649			clrbitmap(p_flags);
2650		}
2651#if STARTTLS
2652		if (OpMode == MD_SMTP)
2653			(void) initsrvtls(tls_ok);
2654#endif /* STARTTLS */
2655
2656		/* turn off profiling */
2657		SM_PROF(1);
2658		smtp(nullserver, *p_flags, &MainEnvelope);
2659
2660		if (tTd(93, 100))
2661		{
2662			/* turn off profiling */
2663			SM_PROF(0);
2664			if (OpMode == MD_DAEMON)
2665				goto nextreq;
2666		}
2667	}
2668
2669	sm_rpool_free(MainEnvelope.e_rpool);
2670	clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));
2671	if (OpMode == MD_VERIFY)
2672	{
2673		set_delivery_mode(SM_VERIFY, &MainEnvelope);
2674		PostMasterCopy = NULL;
2675	}
2676	else
2677	{
2678		/* interactive -- all errors are global */
2679		MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
2680	}
2681
2682	/*
2683	**  Do basic system initialization and set the sender
2684	*/
2685
2686	initsys(&MainEnvelope);
2687	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");
2688	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");
2689	setsender(from, &MainEnvelope, NULL, '\0', false);
2690	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
2691	    (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||
2692	     strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))
2693	{
2694		auth_warning(&MainEnvelope, "%s set sender to %s using -%c",
2695			     RealUserName, from, warn_f_flag);
2696#if SASL
2697		auth = false;
2698#endif /* SASL */
2699	}
2700	if (auth)
2701	{
2702		char *fv;
2703
2704		/* set the initial sender for AUTH= to $f@$j */
2705		fv = macvalue('f', &MainEnvelope);
2706		if (fv == NULL || *fv == '\0')
2707			MainEnvelope.e_auth_param = NULL;
2708		else
2709		{
2710			if (strchr(fv, '@') == NULL)
2711			{
2712				i = strlen(fv) + strlen(macvalue('j',
2713							&MainEnvelope)) + 2;
2714				p = sm_malloc_x(i);
2715				(void) sm_strlcpyn(p, i, 3, fv, "@",
2716						   macvalue('j',
2717							    &MainEnvelope));
2718			}
2719			else
2720				p = sm_strdup_x(fv);
2721			MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,
2722								      xtextify(p, "="));
2723			sm_free(p);  /* XXX */
2724		}
2725	}
2726	if (macvalue('s', &MainEnvelope) == NULL)
2727		macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);
2728
2729	av = argv + optind;
2730	if (*av == NULL && !GrabTo)
2731	{
2732		MainEnvelope.e_to = NULL;
2733		MainEnvelope.e_flags |= EF_GLOBALERRS;
2734		HoldErrs = false;
2735		SuperSafe = SAFE_NO;
2736		usrerr("Recipient names must be specified");
2737
2738		/* collect body for UUCP return */
2739		if (OpMode != MD_VERIFY)
2740			collect(InChannel, false, NULL, &MainEnvelope, true);
2741		finis(true, true, EX_USAGE);
2742		/* NOTREACHED */
2743	}
2744
2745	/*
2746	**  Scan argv and deliver the message to everyone.
2747	*/
2748
2749	save_val = LogUsrErrs;
2750	LogUsrErrs = true;
2751	sendtoargv(av, &MainEnvelope);
2752	LogUsrErrs = save_val;
2753
2754	/* if we have had errors sofar, arrange a meaningful exit stat */
2755	if (Errors > 0 && ExitStat == EX_OK)
2756		ExitStat = EX_USAGE;
2757
2758#if _FFR_FIX_DASHT
2759	/*
2760	**  If using -t, force not sending to argv recipients, even
2761	**  if they are mentioned in the headers.
2762	*/
2763
2764	if (GrabTo)
2765	{
2766		ADDRESS *q;
2767
2768		for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)
2769			q->q_state = QS_REMOVED;
2770	}
2771#endif /* _FFR_FIX_DASHT */
2772
2773	/*
2774	**  Read the input mail.
2775	*/
2776
2777	MainEnvelope.e_to = NULL;
2778	if (OpMode != MD_VERIFY || GrabTo)
2779	{
2780		int savederrors;
2781		unsigned long savedflags;
2782
2783		/*
2784		**  workaround for compiler warning on Irix:
2785		**  do not initialize variable in the definition, but
2786		**  later on:
2787		**  warning(1548): transfer of control bypasses
2788		**  initialization of:
2789		**  variable "savederrors" (declared at line 2570)
2790		**  variable "savedflags" (declared at line 2571)
2791		**  goto giveup;
2792		*/
2793
2794		savederrors = Errors;
2795		savedflags = MainEnvelope.e_flags & EF_FATALERRS;
2796		MainEnvelope.e_flags |= EF_GLOBALERRS;
2797		MainEnvelope.e_flags &= ~EF_FATALERRS;
2798		Errors = 0;
2799		buffer_errors();
2800		collect(InChannel, false, NULL, &MainEnvelope, true);
2801
2802		/* header checks failed */
2803		if (Errors > 0)
2804		{
2805  giveup:
2806			if (!GrabTo)
2807			{
2808				/* Log who the mail would have gone to */
2809				logundelrcpts(&MainEnvelope,
2810					      MainEnvelope.e_message,
2811					      8, false);
2812			}
2813			flush_errors(true);
2814			finis(true, true, ExitStat);
2815			/* NOTREACHED */
2816			return -1;
2817		}
2818
2819		/* bail out if message too large */
2820		if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))
2821		{
2822			finis(true, true, ExitStat != EX_OK ? ExitStat
2823							    : EX_DATAERR);
2824			/* NOTREACHED */
2825			return -1;
2826		}
2827
2828		/* set message size */
2829		(void) sm_snprintf(buf, sizeof(buf), "%ld",
2830				   MainEnvelope.e_msgsize);
2831		macdefine(&MainEnvelope.e_macro, A_TEMP,
2832			  macid("{msg_size}"), buf);
2833
2834		Errors = savederrors;
2835		MainEnvelope.e_flags |= savedflags;
2836	}
2837	errno = 0;
2838
2839	if (tTd(1, 1))
2840		sm_dprintf("From person = \"%s\"\n",
2841			   MainEnvelope.e_from.q_paddr);
2842
2843	/* Check if quarantining stats should be updated */
2844	if (MainEnvelope.e_quarmsg != NULL)
2845		markstats(&MainEnvelope, NULL, STATS_QUARANTINE);
2846
2847	/*
2848	**  Actually send everything.
2849	**	If verifying, just ack.
2850	*/
2851
2852	if (Errors == 0)
2853	{
2854		if (!split_by_recipient(&MainEnvelope) &&
2855		    bitset(EF_FATALERRS, MainEnvelope.e_flags))
2856			goto giveup;
2857	}
2858
2859	/* make sure we deliver at least the first envelope */
2860	i = FastSplit > 0 ? 0 : -1;
2861	for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)
2862	{
2863		ENVELOPE *next;
2864
2865		e->e_from.q_state = QS_SENDER;
2866		if (tTd(1, 5))
2867		{
2868			sm_dprintf("main[%d]: QS_SENDER ", i);
2869			printaddr(sm_debug_file(), &e->e_from, false);
2870		}
2871		e->e_to = NULL;
2872		sm_getla();
2873		GrabTo = false;
2874#if NAMED_BIND
2875		_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2876		_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2877#endif /* NAMED_BIND */
2878		next = e->e_sibling;
2879		e->e_sibling = NULL;
2880
2881		/* after FastSplit envelopes: queue up */
2882		sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);
2883		e->e_sibling = next;
2884	}
2885
2886	/*
2887	**  All done.
2888	**	Don't send return error message if in VERIFY mode.
2889	*/
2890
2891	finis(true, true, ExitStat);
2892	/* NOTREACHED */
2893	return ExitStat;
2894}
2895/*
2896**  STOP_SENDMAIL -- Stop the running program
2897**
2898**	Parameters:
2899**		none.
2900**
2901**	Returns:
2902**		none.
2903**
2904**	Side Effects:
2905**		exits.
2906*/
2907
2908void
2909stop_sendmail()
2910{
2911	/* reset uid for process accounting */
2912	endpwent();
2913	(void) setuid(RealUid);
2914	exit(EX_OK);
2915}
2916/*
2917**  FINIS -- Clean up and exit.
2918**
2919**	Parameters:
2920**		drop -- whether or not to drop CurEnv envelope
2921**		cleanup -- call exit() or _exit()?
2922**		exitstat -- exit status to use for exit() call
2923**
2924**	Returns:
2925**		never
2926**
2927**	Side Effects:
2928**		exits sendmail
2929*/
2930
2931void
2932finis(drop, cleanup, exitstat)
2933	bool drop;
2934	bool cleanup;
2935	volatile int exitstat;
2936{
2937	char pidpath[MAXPATHLEN];
2938	pid_t pid;
2939
2940	/* Still want to process new timeouts added below */
2941	sm_clear_events();
2942	(void) sm_releasesignal(SIGALRM);
2943
2944	if (tTd(2, 1))
2945	{
2946		sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
2947			   exitstat,
2948			   CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
2949		printenvflags(CurEnv);
2950	}
2951	if (tTd(2, 9))
2952		printopenfds(false);
2953
2954	SM_TRY
2955		/*
2956		**  Clean up.  This might raise E:mta.quickabort
2957		*/
2958
2959		/* clean up temp files */
2960		CurEnv->e_to = NULL;
2961		if (drop)
2962		{
2963			if (CurEnv->e_id != NULL)
2964			{
2965				int r;
2966
2967				r = dropenvelope(CurEnv, true, false);
2968				if (exitstat == EX_OK)
2969					exitstat = r;
2970				sm_rpool_free(CurEnv->e_rpool);
2971				CurEnv->e_rpool = NULL;
2972
2973				/* these may have pointed to the rpool */
2974				CurEnv->e_to = NULL;
2975				CurEnv->e_message = NULL;
2976				CurEnv->e_statmsg = NULL;
2977				CurEnv->e_quarmsg = NULL;
2978				CurEnv->e_bodytype = NULL;
2979				CurEnv->e_id = NULL;
2980				CurEnv->e_envid = NULL;
2981				CurEnv->e_auth_param = NULL;
2982			}
2983			else
2984				poststats(StatFile);
2985		}
2986
2987		/* flush any cached connections */
2988		mci_flush(true, NULL);
2989
2990		/* close maps belonging to this pid */
2991		closemaps(false);
2992
2993#if USERDB
2994		/* close UserDatabase */
2995		_udbx_close();
2996#endif /* USERDB */
2997
2998#if SASL
2999		stop_sasl_client();
3000#endif /* SASL */
3001
3002#if XLA
3003		/* clean up extended load average stuff */
3004		xla_all_end();
3005#endif /* XLA */
3006
3007	SM_FINALLY
3008		/*
3009		**  And exit.
3010		*/
3011
3012		if (LogLevel > 78)
3013			sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",
3014				  (int) CurrentPid);
3015		if (exitstat == EX_TEMPFAIL ||
3016		    CurEnv->e_errormode == EM_BERKNET)
3017			exitstat = EX_OK;
3018
3019		/* XXX clean up queues and related data structures */
3020		cleanup_queues();
3021		pid = getpid();
3022#if SM_CONF_SHM
3023		cleanup_shm(DaemonPid == pid);
3024#endif /* SM_CONF_SHM */
3025
3026		/* close locked pid file */
3027		close_sendmail_pid();
3028
3029		if (DaemonPid == pid || PidFilePid == pid)
3030		{
3031			/* blow away the pid file */
3032			expand(PidFile, pidpath, sizeof(pidpath), CurEnv);
3033			(void) unlink(pidpath);
3034		}
3035
3036		/* reset uid for process accounting */
3037		endpwent();
3038		sm_mbdb_terminate();
3039#if _FFR_MEMSTAT
3040		(void) sm_memstat_close();
3041#endif /* _FFR_MEMSTAT */
3042		(void) setuid(RealUid);
3043#if SM_HEAP_CHECK
3044		/* dump the heap, if we are checking for memory leaks */
3045		if (sm_debug_active(&SmHeapCheck, 2))
3046			sm_heap_report(smioout,
3047				       sm_debug_level(&SmHeapCheck) - 1);
3048#endif /* SM_HEAP_CHECK */
3049		if (sm_debug_active(&SmXtrapReport, 1))
3050			sm_dprintf("xtrap count = %d\n", SmXtrapCount);
3051		if (cleanup)
3052			exit(exitstat);
3053		else
3054			_exit(exitstat);
3055	SM_END_TRY
3056}
3057/*
3058**  INTINDEBUG -- signal handler for SIGINT in -bt mode
3059**
3060**	Parameters:
3061**		sig -- incoming signal.
3062**
3063**	Returns:
3064**		none.
3065**
3066**	Side Effects:
3067**		longjmps back to test mode loop.
3068**
3069**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3070**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3071**		DOING.
3072*/
3073
3074/* Type of an exception generated on SIGINT during address test mode.  */
3075static const SM_EXC_TYPE_T EtypeInterrupt =
3076{
3077	SmExcTypeMagic,
3078	"S:mta.interrupt",
3079	"",
3080	sm_etype_printf,
3081	"interrupt",
3082};
3083
3084/* ARGSUSED */
3085static SIGFUNC_DECL
3086intindebug(sig)
3087	int sig;
3088{
3089	int save_errno = errno;
3090
3091	FIX_SYSV_SIGNAL(sig, intindebug);
3092	errno = save_errno;
3093	CHECK_CRITICAL(sig);
3094	errno = save_errno;
3095	sm_exc_raisenew_x(&EtypeInterrupt);
3096	errno = save_errno;
3097	return SIGFUNC_RETURN;
3098}
3099/*
3100**  SIGTERM -- SIGTERM handler for the daemon
3101**
3102**	Parameters:
3103**		sig -- signal number.
3104**
3105**	Returns:
3106**		none.
3107**
3108**	Side Effects:
3109**		Sets ShutdownRequest which will hopefully trigger
3110**		the daemon to exit.
3111**
3112**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3113**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3114**		DOING.
3115*/
3116
3117/* ARGSUSED */
3118static SIGFUNC_DECL
3119sigterm(sig)
3120	int sig;
3121{
3122	int save_errno = errno;
3123
3124	FIX_SYSV_SIGNAL(sig, sigterm);
3125	ShutdownRequest = "signal";
3126	errno = save_errno;
3127	return SIGFUNC_RETURN;
3128}
3129/*
3130**  SIGHUP -- handle a SIGHUP signal
3131**
3132**	Parameters:
3133**		sig -- incoming signal.
3134**
3135**	Returns:
3136**		none.
3137**
3138**	Side Effects:
3139**		Sets RestartRequest which should cause the daemon
3140**		to restart.
3141**
3142**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3143**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3144**		DOING.
3145*/
3146
3147/* ARGSUSED */
3148static SIGFUNC_DECL
3149sighup(sig)
3150	int sig;
3151{
3152	int save_errno = errno;
3153
3154	FIX_SYSV_SIGNAL(sig, sighup);
3155	RestartRequest = "signal";
3156	errno = save_errno;
3157	return SIGFUNC_RETURN;
3158}
3159/*
3160**  SIGPIPE -- signal handler for SIGPIPE
3161**
3162**	Parameters:
3163**		sig -- incoming signal.
3164**
3165**	Returns:
3166**		none.
3167**
3168**	Side Effects:
3169**		Sets StopRequest which should cause the mailq/hoststatus
3170**		display to stop.
3171**
3172**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3173**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3174**		DOING.
3175*/
3176
3177/* ARGSUSED */
3178static SIGFUNC_DECL
3179sigpipe(sig)
3180	int sig;
3181{
3182	int save_errno = errno;
3183
3184	FIX_SYSV_SIGNAL(sig, sigpipe);
3185	StopRequest = true;
3186	errno = save_errno;
3187	return SIGFUNC_RETURN;
3188}
3189/*
3190**  INTSIG -- clean up on interrupt
3191**
3192**	This just arranges to exit.  It pessimizes in that it
3193**	may resend a message.
3194**
3195**	Parameters:
3196**		sig -- incoming signal.
3197**
3198**	Returns:
3199**		none.
3200**
3201**	Side Effects:
3202**		Unlocks the current job.
3203**
3204**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3205**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3206**		DOING.
3207*/
3208
3209/* ARGSUSED */
3210SIGFUNC_DECL
3211intsig(sig)
3212	int sig;
3213{
3214	bool drop = false;
3215	int save_errno = errno;
3216
3217	FIX_SYSV_SIGNAL(sig, intsig);
3218	errno = save_errno;
3219	CHECK_CRITICAL(sig);
3220	sm_allsignals(true);
3221	IntSig = true;
3222
3223	FileName = NULL;
3224
3225	/* Clean-up on aborted stdin message submission */
3226	if  (OpMode == MD_SMTP ||
3227	     OpMode == MD_DELIVER ||
3228	     OpMode == MD_ARPAFTP)
3229	{
3230		if (CurEnv->e_id != NULL)
3231		{
3232			char *fn;
3233
3234			fn = queuename(CurEnv, DATAFL_LETTER);
3235			if (fn != NULL)
3236				(void) unlink(fn);
3237			fn = queuename(CurEnv, ANYQFL_LETTER);
3238			if (fn != NULL)
3239				(void) unlink(fn);
3240		}
3241		_exit(EX_OK);
3242		/* NOTREACHED */
3243	}
3244
3245	if (sig != 0 && LogLevel > 79)
3246		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
3247	if (OpMode != MD_TEST)
3248		unlockqueue(CurEnv);
3249
3250	finis(drop, false, EX_OK);
3251	/* NOTREACHED */
3252}
3253/*
3254**  DISCONNECT -- remove our connection with any foreground process
3255**
3256**	Parameters:
3257**		droplev -- how "deeply" we should drop the line.
3258**			0 -- ignore signals, mail back errors, make sure
3259**			     output goes to stdout.
3260**			1 -- also, make stdout go to /dev/null.
3261**			2 -- also, disconnect from controlling terminal
3262**			     (only for daemon mode).
3263**		e -- the current envelope.
3264**
3265**	Returns:
3266**		none
3267**
3268**	Side Effects:
3269**		Trys to insure that we are immune to vagaries of
3270**		the controlling tty.
3271*/
3272
3273void
3274disconnect(droplev, e)
3275	int droplev;
3276	register ENVELOPE *e;
3277{
3278	int fd;
3279
3280	if (tTd(52, 1))
3281		sm_dprintf("disconnect: In %d Out %d, e=%p\n",
3282			   sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
3283			   sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);
3284	if (tTd(52, 100))
3285	{
3286		sm_dprintf("don't\n");
3287		return;
3288	}
3289	if (LogLevel > 93)
3290		sm_syslog(LOG_DEBUG, e->e_id,
3291			  "disconnect level %d",
3292			  droplev);
3293
3294	/* be sure we don't get nasty signals */
3295	(void) sm_signal(SIGINT, SIG_IGN);
3296	(void) sm_signal(SIGQUIT, SIG_IGN);
3297
3298	/* we can't communicate with our caller, so.... */
3299	HoldErrs = true;
3300	CurEnv->e_errormode = EM_MAIL;
3301	Verbose = 0;
3302	DisConnected = true;
3303
3304	/* all input from /dev/null */
3305	if (InChannel != smioin)
3306	{
3307		(void) sm_io_close(InChannel, SM_TIME_DEFAULT);
3308		InChannel = smioin;
3309	}
3310	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
3311			 SM_IO_RDONLY, NULL, smioin) == NULL)
3312		sm_syslog(LOG_ERR, e->e_id,
3313			  "disconnect: sm_io_reopen(\"%s\") failed: %s",
3314			  SM_PATH_DEVNULL, sm_errstring(errno));
3315
3316	/*
3317	**  output to the transcript
3318	**	We also compare the fd numbers here since OutChannel
3319	**	might be a layer on top of smioout due to encryption
3320	**	(see sfsasl.c).
3321	*/
3322
3323	if (OutChannel != smioout &&
3324	    sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=
3325	    sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))
3326	{
3327		(void) sm_io_close(OutChannel, SM_TIME_DEFAULT);
3328		OutChannel = smioout;
3329
3330#if 0
3331		/*
3332		**  Has smioout been closed? Reopen it.
3333		**	This shouldn't happen anymore, the code is here
3334		**	just as a reminder.
3335		*/
3336
3337		if (smioout->sm_magic == NULL &&
3338		    sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
3339				 SM_IO_WRONLY, NULL, smioout) == NULL)
3340			sm_syslog(LOG_ERR, e->e_id,
3341				  "disconnect: sm_io_reopen(\"%s\") failed: %s",
3342				  SM_PATH_DEVNULL, sm_errstring(errno));
3343#endif /* 0 */
3344	}
3345	if (droplev > 0)
3346	{
3347		fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);
3348		if (fd == -1)
3349		{
3350			sm_syslog(LOG_ERR, e->e_id,
3351				  "disconnect: open(\"%s\") failed: %s",
3352				  SM_PATH_DEVNULL, sm_errstring(errno));
3353		}
3354		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
3355		if (fd >= 0)
3356		{
3357			(void) dup2(fd, STDOUT_FILENO);
3358			(void) dup2(fd, STDERR_FILENO);
3359			(void) close(fd);
3360		}
3361	}
3362
3363	/* drop our controlling TTY completely if possible */
3364	if (droplev > 1)
3365	{
3366		(void) setsid();
3367		errno = 0;
3368	}
3369
3370#if XDEBUG
3371	checkfd012("disconnect");
3372#endif /* XDEBUG */
3373
3374	if (LogLevel > 71)
3375		sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",
3376			  (int) CurrentPid);
3377
3378	errno = 0;
3379}
3380
3381static void
3382obsolete(argv)
3383	char *argv[];
3384{
3385	register char *ap;
3386	register char *op;
3387
3388	while ((ap = *++argv) != NULL)
3389	{
3390		/* Return if "--" or not an option of any form. */
3391		if (ap[0] != '-' || ap[1] == '-')
3392			return;
3393
3394		/* Don't allow users to use "-Q." or "-Q ." */
3395		if ((ap[1] == 'Q' && ap[2] == '.') ||
3396		    (ap[1] == 'Q' && argv[1] != NULL &&
3397		     argv[1][0] == '.' && argv[1][1] == '\0'))
3398		{
3399			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3400					     "Can not use -Q.\n");
3401			exit(EX_USAGE);
3402		}
3403
3404		/* skip over options that do have a value */
3405		op = strchr(OPTIONS, ap[1]);
3406		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
3407		    ap[1] != 'd' &&
3408#if defined(sony_news)
3409		    ap[1] != 'E' && ap[1] != 'J' &&
3410#endif /* defined(sony_news) */
3411		    argv[1] != NULL && argv[1][0] != '-')
3412		{
3413			argv++;
3414			continue;
3415		}
3416
3417		/* If -C doesn't have an argument, use sendmail.cf. */
3418#define __DEFPATH	"sendmail.cf"
3419		if (ap[1] == 'C' && ap[2] == '\0')
3420		{
3421			*argv = xalloc(sizeof(__DEFPATH) + 2);
3422			(void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,
3423					   "-C", __DEFPATH);
3424		}
3425
3426		/* If -q doesn't have an argument, run it once. */
3427		if (ap[1] == 'q' && ap[2] == '\0')
3428			*argv = "-q0";
3429
3430		/* If -Q doesn't have an argument, disable quarantining */
3431		if (ap[1] == 'Q' && ap[2] == '\0')
3432			*argv = "-Q.";
3433
3434		/* if -d doesn't have an argument, use 0-99.1 */
3435		if (ap[1] == 'd' && ap[2] == '\0')
3436			*argv = "-d0-99.1";
3437
3438#if defined(sony_news)
3439		/* if -E doesn't have an argument, use -EC */
3440		if (ap[1] == 'E' && ap[2] == '\0')
3441			*argv = "-EC";
3442
3443		/* if -J doesn't have an argument, use -JJ */
3444		if (ap[1] == 'J' && ap[2] == '\0')
3445			*argv = "-JJ";
3446#endif /* defined(sony_news) */
3447	}
3448}
3449/*
3450**  AUTH_WARNING -- specify authorization warning
3451**
3452**	Parameters:
3453**		e -- the current envelope.
3454**		msg -- the text of the message.
3455**		args -- arguments to the message.
3456**
3457**	Returns:
3458**		none.
3459*/
3460
3461void
3462#ifdef __STDC__
3463auth_warning(register ENVELOPE *e, const char *msg, ...)
3464#else /* __STDC__ */
3465auth_warning(e, msg, va_alist)
3466	register ENVELOPE *e;
3467	const char *msg;
3468	va_dcl
3469#endif /* __STDC__ */
3470{
3471	char buf[MAXLINE];
3472	SM_VA_LOCAL_DECL
3473
3474	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
3475	{
3476		register char *p;
3477		static char hostbuf[48];
3478
3479		if (hostbuf[0] == '\0')
3480		{
3481			struct hostent *hp;
3482
3483			hp = myhostname(hostbuf, sizeof(hostbuf));
3484#if NETINET6
3485			if (hp != NULL)
3486			{
3487				freehostent(hp);
3488				hp = NULL;
3489			}
3490#endif /* NETINET6 */
3491		}
3492
3493		(void) sm_strlcpyn(buf, sizeof(buf), 2, hostbuf, ": ");
3494		p = &buf[strlen(buf)];
3495		SM_VA_START(ap, msg);
3496		(void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);
3497		SM_VA_END(ap);
3498		addheader("X-Authentication-Warning", buf, 0, e, true);
3499		if (LogLevel > 3)
3500			sm_syslog(LOG_INFO, e->e_id,
3501				  "Authentication-Warning: %.400s",
3502				  buf);
3503	}
3504}
3505/*
3506**  GETEXTENV -- get from external environment
3507**
3508**	Parameters:
3509**		envar -- the name of the variable to retrieve
3510**
3511**	Returns:
3512**		The value, if any.
3513*/
3514
3515static char *
3516getextenv(envar)
3517	const char *envar;
3518{
3519	char **envp;
3520	int l;
3521
3522	l = strlen(envar);
3523	for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++)
3524	{
3525		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
3526			return &(*envp)[l + 1];
3527	}
3528	return NULL;
3529}
3530/*
3531**  SM_SETUSERENV -- set an environment variable in the propagated environment
3532**
3533**	Parameters:
3534**		envar -- the name of the environment variable.
3535**		value -- the value to which it should be set.  If
3536**			null, this is extracted from the incoming
3537**			environment.  If that is not set, the call
3538**			to sm_setuserenv is ignored.
3539**
3540**	Returns:
3541**		none.
3542*/
3543
3544void
3545sm_setuserenv(envar, value)
3546	const char *envar;
3547	const char *value;
3548{
3549	int i, l;
3550	char **evp = UserEnviron;
3551	char *p;
3552
3553	if (value == NULL)
3554	{
3555		value = getextenv(envar);
3556		if (value == NULL)
3557			return;
3558	}
3559
3560	/* XXX enforce reasonable size? */
3561	i = strlen(envar) + 1;
3562	l = strlen(value) + i + 1;
3563	p = (char *) xalloc(l);
3564	(void) sm_strlcpyn(p, l, 3, envar, "=", value);
3565
3566	while (*evp != NULL && strncmp(*evp, p, i) != 0)
3567		evp++;
3568	if (*evp != NULL)
3569	{
3570		*evp++ = p;
3571	}
3572	else if (evp < &UserEnviron[MAXUSERENVIRON])
3573	{
3574		*evp++ = p;
3575		*evp = NULL;
3576	}
3577
3578	/* make sure it is in our environment as well */
3579	if (putenv(p) < 0)
3580		syserr("sm_setuserenv: putenv(%s) failed", p);
3581}
3582/*
3583**  DUMPSTATE -- dump state
3584**
3585**	For debugging.
3586*/
3587
3588void
3589dumpstate(when)
3590	char *when;
3591{
3592	register char *j = macvalue('j', CurEnv);
3593	int rs;
3594	extern int NextMacroId;
3595
3596	sm_syslog(LOG_DEBUG, CurEnv->e_id,
3597		  "--- dumping state on %s: $j = %s ---",
3598		  when,
3599		  j == NULL ? "<NULL>" : j);
3600	if (j != NULL)
3601	{
3602		if (!wordinclass(j, 'w'))
3603			sm_syslog(LOG_DEBUG, CurEnv->e_id,
3604				  "*** $j not in $=w ***");
3605	}
3606	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
3607	sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)",
3608		  NextMacroId, MAXMACROID);
3609	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
3610	printopenfds(true);
3611	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
3612	mci_dump_all(smioout, true);
3613	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
3614	if (rs > 0)
3615	{
3616		int status;
3617		register char **pvp;
3618		char *pv[MAXATOM + 1];
3619
3620		pv[0] = NULL;
3621		status = REWRITE(pv, rs, CurEnv);
3622		sm_syslog(LOG_DEBUG, CurEnv->e_id,
3623			  "--- ruleset debug_dumpstate returns stat %d, pv: ---",
3624			  status);
3625		for (pvp = pv; *pvp != NULL; pvp++)
3626			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
3627	}
3628	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
3629}
3630
3631#ifdef SIGUSR1
3632/*
3633**  SIGUSR1 -- Signal a request to dump state.
3634**
3635**	Parameters:
3636**		sig -- calling signal.
3637**
3638**	Returns:
3639**		none.
3640**
3641**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3642**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3643**		DOING.
3644**
3645**		XXX: More work is needed for this signal handler.
3646*/
3647
3648/* ARGSUSED */
3649static SIGFUNC_DECL
3650sigusr1(sig)
3651	int sig;
3652{
3653	int save_errno = errno;
3654
3655	FIX_SYSV_SIGNAL(sig, sigusr1);
3656	errno = save_errno;
3657	CHECK_CRITICAL(sig);
3658	dumpstate("user signal");
3659# if SM_HEAP_CHECK
3660	dumpstab();
3661# endif /* SM_HEAP_CHECK */
3662	errno = save_errno;
3663	return SIGFUNC_RETURN;
3664}
3665#endif /* SIGUSR1 */
3666
3667/*
3668**  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
3669**
3670**	Parameters:
3671**		to_real_uid -- if set, drop to the real uid instead
3672**			of the RunAsUser.
3673**
3674**	Returns:
3675**		EX_OSERR if the setuid failed.
3676**		EX_OK otherwise.
3677*/
3678
3679int
3680drop_privileges(to_real_uid)
3681	bool to_real_uid;
3682{
3683	int rval = EX_OK;
3684	GIDSET_T emptygidset[1];
3685
3686	if (tTd(47, 1))
3687		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",
3688			   (int) to_real_uid,
3689			   (int) RealUid, (int) RealGid,
3690			   (int) getuid(), (int) getgid(),
3691			   (int) geteuid(), (int) getegid(),
3692			   (int) RunAsUid, (int) RunAsGid);
3693
3694	if (to_real_uid)
3695	{
3696		RunAsUserName = RealUserName;
3697		RunAsUid = RealUid;
3698		RunAsGid = RealGid;
3699		EffGid = RunAsGid;
3700	}
3701
3702	/* make sure no one can grab open descriptors for secret files */
3703	endpwent();
3704	sm_mbdb_terminate();
3705
3706	/* reset group permissions; these can be set later */
3707	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
3708
3709	/*
3710	**  Notice:  on some OS (Linux...) the setgroups() call causes
3711	**	a logfile entry if sendmail is not run by root.
3712	**	However, it is unclear (no POSIX standard) whether
3713	**	setgroups() can only succeed if executed by root.
3714	**	So for now we keep it as it is; if you want to change it, use
3715	**  if (geteuid() == 0 && setgroups(1, emptygidset) == -1)
3716	*/
3717
3718	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
3719	{
3720		syserr("drop_privileges: setgroups(1, %d) failed",
3721		       (int) emptygidset[0]);
3722		rval = EX_OSERR;
3723	}
3724
3725	/* reset primary group id */
3726	if (to_real_uid)
3727	{
3728		/*
3729		**  Drop gid to real gid.
3730		**  On some OS we must reset the effective[/real[/saved]] gid,
3731		**  and then use setgid() to finally drop all group privileges.
3732		**  Later on we check whether we can get back the
3733		**  effective gid.
3734		*/
3735
3736#if HASSETEGID
3737		if (setegid(RunAsGid) < 0)
3738		{
3739			syserr("drop_privileges: setegid(%d) failed",
3740			       (int) RunAsGid);
3741			rval = EX_OSERR;
3742		}
3743#else /* HASSETEGID */
3744# if HASSETREGID
3745		if (setregid(RunAsGid, RunAsGid) < 0)
3746		{
3747			syserr("drop_privileges: setregid(%d, %d) failed",
3748			       (int) RunAsGid, (int) RunAsGid);
3749			rval = EX_OSERR;
3750		}
3751# else /* HASSETREGID */
3752#  if HASSETRESGID
3753		if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0)
3754		{
3755			syserr("drop_privileges: setresgid(%d, %d, %d) failed",
3756			       (int) RunAsGid, (int) RunAsGid, (int) RunAsGid);
3757			rval = EX_OSERR;
3758		}
3759#  endif /* HASSETRESGID */
3760# endif /* HASSETREGID */
3761#endif /* HASSETEGID */
3762	}
3763	if (rval == EX_OK && (to_real_uid || RunAsGid != 0))
3764	{
3765		if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid))
3766		{
3767			syserr("drop_privileges: setgid(%d) failed",
3768			       (int) RunAsGid);
3769			rval = EX_OSERR;
3770		}
3771		errno = 0;
3772		if (rval == EX_OK && getegid() != RunAsGid)
3773		{
3774			syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d",
3775			       (int) getegid(), (int) RunAsGid);
3776			rval = EX_OSERR;
3777		}
3778	}
3779
3780	/* fiddle with uid */
3781	if (to_real_uid || RunAsUid != 0)
3782	{
3783		uid_t euid;
3784
3785		/*
3786		**  Try to setuid(RunAsUid).
3787		**  euid must be RunAsUid,
3788		**  ruid must be RunAsUid unless (e|r)uid wasn't 0
3789		**	and we didn't have to drop privileges to the real uid.
3790		*/
3791
3792		if (setuid(RunAsUid) < 0 ||
3793		    geteuid() != RunAsUid ||
3794		    (getuid() != RunAsUid &&
3795		     (to_real_uid || geteuid() == 0 || getuid() == 0)))
3796		{
3797#if HASSETREUID
3798			/*
3799			**  if ruid != RunAsUid, euid == RunAsUid, then
3800			**  try resetting just the real uid, then using
3801			**  setuid() to drop the saved-uid as well.
3802			*/
3803
3804			if (geteuid() == RunAsUid)
3805			{
3806				if (setreuid(RunAsUid, -1) < 0)
3807				{
3808					syserr("drop_privileges: setreuid(%d, -1) failed",
3809					       (int) RunAsUid);
3810					rval = EX_OSERR;
3811				}
3812				if (setuid(RunAsUid) < 0)
3813				{
3814					syserr("drop_privileges: second setuid(%d) attempt failed",
3815					       (int) RunAsUid);
3816					rval = EX_OSERR;
3817				}
3818			}
3819			else
3820#endif /* HASSETREUID */
3821			{
3822				syserr("drop_privileges: setuid(%d) failed",
3823				       (int) RunAsUid);
3824				rval = EX_OSERR;
3825			}
3826		}
3827		euid = geteuid();
3828		if (RunAsUid != 0 && setuid(0) == 0)
3829		{
3830			/*
3831			**  Believe it or not, the Linux capability model
3832			**  allows a non-root process to override setuid()
3833			**  on a process running as root and prevent that
3834			**  process from dropping privileges.
3835			*/
3836
3837			syserr("drop_privileges: setuid(0) succeeded (when it should not)");
3838			rval = EX_OSERR;
3839		}
3840		else if (RunAsUid != euid && setuid(euid) == 0)
3841		{
3842			/*
3843			**  Some operating systems will keep the saved-uid
3844			**  if a non-root effective-uid calls setuid(real-uid)
3845			**  making it possible to set it back again later.
3846			*/
3847
3848			syserr("drop_privileges: Unable to drop non-root set-user-ID privileges");
3849			rval = EX_OSERR;
3850		}
3851	}
3852
3853	if ((to_real_uid || RunAsGid != 0) &&
3854	    rval == EX_OK && RunAsGid != EffGid &&
3855	    getuid() != 0 && geteuid() != 0)
3856	{
3857		errno = 0;
3858		if (setgid(EffGid) == 0)
3859		{
3860			syserr("drop_privileges: setgid(%d) succeeded (when it should not)",
3861			       (int) EffGid);
3862			rval = EX_OSERR;
3863		}
3864	}
3865
3866	if (tTd(47, 5))
3867	{
3868		sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
3869			   (int) geteuid(), (int) getuid(),
3870			   (int) getegid(), (int) getgid());
3871		sm_dprintf("drop_privileges: RunAsUser = %d:%d\n",
3872			   (int) RunAsUid, (int) RunAsGid);
3873		if (tTd(47, 10))
3874			sm_dprintf("drop_privileges: rval = %d\n", rval);
3875	}
3876	return rval;
3877}
3878/*
3879**  FILL_FD -- make sure a file descriptor has been properly allocated
3880**
3881**	Used to make sure that stdin/out/err are allocated on startup
3882**
3883**	Parameters:
3884**		fd -- the file descriptor to be filled.
3885**		where -- a string used for logging.  If NULL, this is
3886**			being called on startup, and logging should
3887**			not be done.
3888**
3889**	Returns:
3890**		none
3891**
3892**	Side Effects:
3893**		possibly changes MissingFds
3894*/
3895
3896void
3897fill_fd(fd, where)
3898	int fd;
3899	char *where;
3900{
3901	int i;
3902	struct stat stbuf;
3903
3904	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
3905		return;
3906
3907	if (where != NULL)
3908		syserr("fill_fd: %s: fd %d not open", where, fd);
3909	else
3910		MissingFds |= 1 << fd;
3911	i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666);
3912	if (i < 0)
3913	{
3914		syserr("!fill_fd: %s: cannot open %s",
3915		       where == NULL ? "startup" : where, SM_PATH_DEVNULL);
3916	}
3917	if (fd != i)
3918	{
3919		(void) dup2(i, fd);
3920		(void) close(i);
3921	}
3922}
3923/*
3924**  SM_PRINTOPTIONS -- print options
3925**
3926**	Parameters:
3927**		options -- array of options.
3928**
3929**	Returns:
3930**		none.
3931*/
3932
3933static void
3934sm_printoptions(options)
3935	char **options;
3936{
3937	int ll;
3938	char **av;
3939
3940	av = options;
3941	ll = 7;
3942	while (*av != NULL)
3943	{
3944		if (ll + strlen(*av) > 63)
3945		{
3946			sm_dprintf("\n");
3947			ll = 0;
3948		}
3949		if (ll == 0)
3950			sm_dprintf("\t\t");
3951		else
3952			sm_dprintf(" ");
3953		sm_dprintf("%s", *av);
3954		ll += strlen(*av++) + 1;
3955	}
3956	sm_dprintf("\n");
3957}
3958
3959/*
3960**  TO8BIT -- convert \octal sequences in a test mode input line
3961**
3962**	Parameters:
3963**		str -- the input line.
3964**
3965**	Returns:
3966**		none.
3967**
3968**	Side Effects:
3969**		replaces \0octal in str with octal value.
3970*/
3971
3972static bool to8bit __P((char *));
3973
3974static bool
3975to8bit(str)
3976	char *str;
3977{
3978	int c, len;
3979	char *out, *in;
3980	bool changed;
3981
3982	if (str == NULL)
3983		return false;
3984	in = out = str;
3985	changed = false;
3986	len = 0;
3987	while ((c = (*str++ & 0377)) != '\0')
3988	{
3989		int oct, nxtc;
3990
3991		++len;
3992		if (c == '\\' &&
3993		    (nxtc = (*str & 0377)) == '0')
3994		{
3995			oct = 0;
3996			while ((nxtc = (*str & 0377)) != '\0' &&
3997				isascii(nxtc) && isdigit(nxtc))
3998			{
3999				oct <<= 3;
4000				oct += nxtc - '0';
4001				++str;
4002				++len;
4003			}
4004			changed = true;
4005			c = oct;
4006		}
4007		*out++ = c;
4008	}
4009	*out++ = c;
4010	if (changed)
4011	{
4012		char *q;
4013
4014		q = quote_internal_chars(in, in, &len);
4015		if (q != in)
4016			sm_strlcpy(in, q, len);
4017	}
4018	return changed;
4019}
4020
4021/*
4022**  TESTMODELINE -- process a test mode input line
4023**
4024**	Parameters:
4025**		line -- the input line.
4026**		e -- the current environment.
4027**	Syntax:
4028**		#  a comment
4029**		.X process X as a configuration line
4030**		=X dump a configuration item (such as mailers)
4031**		$X dump a macro or class
4032**		/X try an activity
4033**		X  normal process through rule set X
4034*/
4035
4036static void
4037testmodeline(line, e)
4038	char *line;
4039	ENVELOPE *e;
4040{
4041	register char *p;
4042	char *q;
4043	auto char *delimptr;
4044	int mid;
4045	int i, rs;
4046	STAB *map;
4047	char **s;
4048	struct rewrite *rw;
4049	ADDRESS a;
4050	char *lbp;
4051	auto int lbs;
4052	static int tryflags = RF_COPYNONE;
4053	char exbuf[MAXLINE];
4054	char lbuf[MAXLINE];
4055	extern unsigned char TokTypeNoC[];
4056	bool eightbit;
4057
4058	/* skip leading spaces */
4059	while (*line == ' ')
4060		line++;
4061
4062	lbp = NULL;
4063	eightbit = false;
4064	switch (line[0])
4065	{
4066	  case '#':
4067	  case '\0':
4068		return;
4069
4070	  case '?':
4071		help("-bt", e);
4072		return;
4073
4074	  case '.':		/* config-style settings */
4075		switch (line[1])
4076		{
4077		  case 'D':
4078			mid = macid_parse(&line[2], &delimptr);
4079			if (mid == 0)
4080				return;
4081			lbs = sizeof(lbuf);
4082			lbp = translate_dollars(delimptr, lbuf, &lbs);
4083			macdefine(&e->e_macro, A_TEMP, mid, lbp);
4084			if (lbp != lbuf)
4085				SM_FREE(lbp);
4086			break;
4087
4088		  case 'C':
4089			if (line[2] == '\0')	/* not to call syserr() */
4090				return;
4091
4092			mid = macid_parse(&line[2], &delimptr);
4093			if (mid == 0)
4094				return;
4095			lbs = sizeof(lbuf);
4096			lbp = translate_dollars(delimptr, lbuf, &lbs);
4097			expand(lbp, exbuf, sizeof(exbuf), e);
4098			if (lbp != lbuf)
4099				SM_FREE(lbp);
4100			p = exbuf;
4101			while (*p != '\0')
4102			{
4103				register char *wd;
4104				char delim;
4105
4106				while (*p != '\0' && isascii(*p) && isspace(*p))
4107					p++;
4108				wd = p;
4109				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4110					p++;
4111				delim = *p;
4112				*p = '\0';
4113				if (wd[0] != '\0')
4114					setclass(mid, wd);
4115				*p = delim;
4116			}
4117			break;
4118
4119		  case '\0':
4120			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4121					     "Usage: .[DC]macro value(s)\n");
4122			break;
4123
4124		  default:
4125			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4126					     "Unknown \".\" command %s\n", line);
4127			break;
4128		}
4129		return;
4130
4131	  case '=':		/* config-style settings */
4132		switch (line[1])
4133		{
4134		  case 'S':		/* dump rule set */
4135			rs = strtorwset(&line[2], NULL, ST_FIND);
4136			if (rs < 0)
4137			{
4138				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4139						     "Undefined ruleset %s\n", &line[2]);
4140				return;
4141			}
4142			rw = RewriteRules[rs];
4143			if (rw == NULL)
4144				return;
4145			do
4146			{
4147				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4148						  'R');
4149				s = rw->r_lhs;
4150				while (*s != NULL)
4151				{
4152					xputs(smioout, *s++);
4153					(void) sm_io_putc(smioout,
4154							  SM_TIME_DEFAULT, ' ');
4155				}
4156				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4157						  '\t');
4158				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4159						  '\t');
4160				s = rw->r_rhs;
4161				while (*s != NULL)
4162				{
4163					xputs(smioout, *s++);
4164					(void) sm_io_putc(smioout,
4165							  SM_TIME_DEFAULT, ' ');
4166				}
4167				(void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4168						  '\n');
4169			} while ((rw = rw->r_next) != NULL);
4170			break;
4171
4172		  case 'M':
4173			for (i = 0; i < MAXMAILERS; i++)
4174			{
4175				if (Mailer[i] != NULL)
4176					printmailer(smioout, Mailer[i]);
4177			}
4178			break;
4179
4180		  case '\0':
4181			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4182					     "Usage: =Sruleset or =M\n");
4183			break;
4184
4185		  default:
4186			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4187					     "Unknown \"=\" command %s\n", line);
4188			break;
4189		}
4190		return;
4191
4192	  case '-':		/* set command-line-like opts */
4193		switch (line[1])
4194		{
4195		  case 'd':
4196			tTflag(&line[2]);
4197			break;
4198
4199		  case '\0':
4200			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4201					     "Usage: -d{debug arguments}\n");
4202			break;
4203
4204		  default:
4205			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4206					     "Unknown \"-\" command %s\n", line);
4207			break;
4208		}
4209		return;
4210
4211	  case '$':
4212		if (line[1] == '=')
4213		{
4214			mid = macid(&line[2]);
4215			if (mid != 0)
4216				stabapply(dump_class, mid);
4217			return;
4218		}
4219		mid = macid(&line[1]);
4220		if (mid == 0)
4221			return;
4222		p = macvalue(mid, e);
4223		if (p == NULL)
4224			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4225					     "Undefined\n");
4226		else
4227		{
4228			xputs(smioout, p);
4229			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4230					     "\n");
4231		}
4232		return;
4233
4234	  case '/':		/* miscellaneous commands */
4235		p = &line[strlen(line)];
4236		while (--p >= line && isascii(*p) && isspace(*p))
4237			*p = '\0';
4238		p = strpbrk(line, " \t");
4239		if (p != NULL)
4240		{
4241			while (isascii(*p) && isspace(*p))
4242				*p++ = '\0';
4243		}
4244		else
4245			p = "";
4246		if (line[1] == '\0')
4247		{
4248			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4249					     "Usage: /[canon|map|mx|parse|try|tryflags]\n");
4250			return;
4251		}
4252		if (sm_strcasecmp(&line[1], "quit") == 0)
4253		{
4254			CurEnv->e_id = NULL;
4255			finis(true, true, ExitStat);
4256			/* NOTREACHED */
4257		}
4258		if (sm_strcasecmp(&line[1], "mx") == 0)
4259		{
4260#if NAMED_BIND
4261			/* look up MX records */
4262			int nmx;
4263			auto int rcode;
4264			char *mxhosts[MAXMXHOSTS + 1];
4265
4266			if (*p == '\0')
4267			{
4268				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4269						     "Usage: /mx address\n");
4270				return;
4271			}
4272			nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true,
4273				      NULL);
4274			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4275					     "getmxrr(%s) returns %d value(s):\n",
4276				p, nmx);
4277			for (i = 0; i < nmx; i++)
4278				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4279						     "\t%s\n", mxhosts[i]);
4280#else /* NAMED_BIND */
4281			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4282					     "No MX code compiled in\n");
4283#endif /* NAMED_BIND */
4284		}
4285		else if (sm_strcasecmp(&line[1], "canon") == 0)
4286		{
4287			char host[MAXHOSTNAMELEN];
4288
4289			if (*p == '\0')
4290			{
4291				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4292						     "Usage: /canon address\n");
4293				return;
4294			}
4295			else if (sm_strlcpy(host, p, sizeof(host)) >= sizeof(host))
4296			{
4297				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4298						     "Name too long\n");
4299				return;
4300			}
4301			(void) getcanonname(host, sizeof(host), !HasWildcardMX,
4302					    NULL);
4303			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4304					     "getcanonname(%s) returns %s\n",
4305					     p, host);
4306		}
4307		else if (sm_strcasecmp(&line[1], "map") == 0)
4308		{
4309			auto int rcode = EX_OK;
4310			char *av[2];
4311
4312			if (*p == '\0')
4313			{
4314				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4315						     "Usage: /map mapname key\n");
4316				return;
4317			}
4318			for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q));			     q++)
4319				continue;
4320			if (*q == '\0')
4321			{
4322				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4323						     "No key specified\n");
4324				return;
4325			}
4326			*q++ = '\0';
4327			map = stab(p, ST_MAP, ST_FIND);
4328			if (map == NULL)
4329			{
4330				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4331						     "Map named \"%s\" not found\n", p);
4332				return;
4333			}
4334			if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
4335			    !openmap(&(map->s_map)))
4336			{
4337				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4338						     "Map named \"%s\" not open\n", p);
4339				return;
4340			}
4341			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4342					     "map_lookup: %s (%s) ", p, q);
4343			av[0] = q;
4344			av[1] = NULL;
4345			p = (*map->s_map.map_class->map_lookup)
4346					(&map->s_map, q, av, &rcode);
4347			if (p == NULL)
4348				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4349						     "no match (%d)\n",
4350						     rcode);
4351			else
4352				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4353						     "returns %s (%d)\n", p,
4354						     rcode);
4355		}
4356		else if (sm_strcasecmp(&line[1], "try") == 0)
4357		{
4358			MAILER *m;
4359			STAB *st;
4360			auto int rcode = EX_OK;
4361
4362			q = strpbrk(p, " \t");
4363			if (q != NULL)
4364			{
4365				while (isascii(*q) && isspace(*q))
4366					*q++ = '\0';
4367			}
4368			if (q == NULL || *q == '\0')
4369			{
4370				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4371						     "Usage: /try mailer address\n");
4372				return;
4373			}
4374			st = stab(p, ST_MAILER, ST_FIND);
4375			if (st == NULL)
4376			{
4377				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4378						     "Unknown mailer %s\n", p);
4379				return;
4380			}
4381			m = st->s_mailer;
4382			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4383					     "Trying %s %s address %s for mailer %s\n",
4384				     bitset(RF_HEADERADDR, tryflags) ? "header"
4385							: "envelope",
4386				     bitset(RF_SENDERADDR, tryflags) ? "sender"
4387							: "recipient", q, p);
4388			p = remotename(q, m, tryflags, &rcode, CurEnv);
4389			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4390					     "Rcode = %d, addr = %s\n",
4391					     rcode, p == NULL ? "<NULL>" : p);
4392			e->e_to = NULL;
4393		}
4394		else if (sm_strcasecmp(&line[1], "tryflags") == 0)
4395		{
4396			if (*p == '\0')
4397			{
4398				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4399						     "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
4400				return;
4401			}
4402			for (; *p != '\0'; p++)
4403			{
4404				switch (*p)
4405				{
4406				  case 'H':
4407				  case 'h':
4408					tryflags |= RF_HEADERADDR;
4409					break;
4410
4411				  case 'E':
4412				  case 'e':
4413					tryflags &= ~RF_HEADERADDR;
4414					break;
4415
4416				  case 'S':
4417				  case 's':
4418					tryflags |= RF_SENDERADDR;
4419					break;
4420
4421				  case 'R':
4422				  case 'r':
4423					tryflags &= ~RF_SENDERADDR;
4424					break;
4425				}
4426			}
4427			exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
4428			exbuf[1] = ' ';
4429			exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
4430			exbuf[3] = '\0';
4431			macdefine(&e->e_macro, A_TEMP,
4432				macid("{addr_type}"), exbuf);
4433		}
4434		else if (sm_strcasecmp(&line[1], "parse") == 0)
4435		{
4436			if (*p == '\0')
4437			{
4438				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4439						     "Usage: /parse address\n");
4440				return;
4441			}
4442			q = crackaddr(p, e);
4443			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4444					     "Cracked address = ");
4445			xputs(smioout, q);
4446			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4447					     "\nParsing %s %s address\n",
4448					     bitset(RF_HEADERADDR, tryflags) ?
4449							"header" : "envelope",
4450					     bitset(RF_SENDERADDR, tryflags) ?
4451							"sender" : "recipient");
4452			if (parseaddr(p, &a, tryflags, '\0', NULL, e, true)
4453			    == NULL)
4454				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4455						     "Cannot parse\n");
4456			else if (a.q_host != NULL && a.q_host[0] != '\0')
4457				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4458						     "mailer %s, host %s, user %s\n",
4459						     a.q_mailer->m_name,
4460						     a.q_host,
4461						     a.q_user);
4462			else
4463				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4464						     "mailer %s, user %s\n",
4465						     a.q_mailer->m_name,
4466						     a.q_user);
4467			e->e_to = NULL;
4468		}
4469		else if (sm_strcasecmp(&line[1], "header") == 0)
4470		{
4471			unsigned long ul;
4472
4473			ul = chompheader(p, CHHDR_CHECK|CHHDR_USER, NULL, e);
4474			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4475					     "ul = %lu\n", ul);
4476		}
4477		else
4478		{
4479			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4480					     "Unknown \"/\" command %s\n",
4481					     line);
4482		}
4483		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
4484		return;
4485	}
4486
4487	for (p = line; isascii(*p) && isspace(*p); p++)
4488		continue;
4489	q = p;
4490	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4491		p++;
4492	if (*p == '\0')
4493	{
4494		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4495				     "No address!\n");
4496		return;
4497	}
4498	*p = '\0';
4499	if (tTd(23, 101))
4500		eightbit = to8bit(p + 1);
4501	if (invalidaddr(p + 1, NULL, true))
4502		return;
4503	do
4504	{
4505		register char **pvp;
4506		char pvpbuf[PSBUFSIZE];
4507
4508		pvp = prescan(++p, ',', pvpbuf, sizeof(pvpbuf), &delimptr,
4509			      ConfigLevel >= 9 ? TokTypeNoC : ExtTokenTab, false);
4510		if (pvp == NULL)
4511			continue;
4512		p = q;
4513		while (*p != '\0')
4514		{
4515			int status;
4516
4517			rs = strtorwset(p, NULL, ST_FIND);
4518			if (rs < 0)
4519			{
4520				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4521						     "Undefined ruleset %s\n",
4522						     p);
4523				break;
4524			}
4525			status = REWRITE(pvp, rs, e);
4526			if (status != EX_OK)
4527				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4528						     "== Ruleset %s (%d) status %d\n",
4529						     p, rs, status);
4530			else if (eightbit)
4531			{
4532				cataddr(pvp, NULL, exbuf, sizeof(exbuf), '\0',
4533					true);
4534				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4535						     "cataddr: %s\n",
4536						     str2prt(exbuf));
4537			}
4538			while (*p != '\0' && *p++ != ',')
4539				continue;
4540		}
4541	} while (*(p = delimptr) != '\0');
4542	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
4543}
4544
4545static void
4546dump_class(s, id)
4547	register STAB *s;
4548	int id;
4549{
4550	if (s->s_symtype != ST_CLASS)
4551		return;
4552	if (bitnset(bitidx(id), s->s_class))
4553		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4554				     "%s\n", s->s_name);
4555}
4556
4557/*
4558**  An exception type used to create QuickAbort exceptions.
4559**  This is my first cut at converting QuickAbort from longjmp to exceptions.
4560**  These exceptions have a single integer argument, which is the argument
4561**  to longjmp in the original code (either 1 or 2).  I don't know the
4562**  significance of 1 vs 2: the calls to setjmp don't care.
4563*/
4564
4565const SM_EXC_TYPE_T EtypeQuickAbort =
4566{
4567	SmExcTypeMagic,
4568	"E:mta.quickabort",
4569	"i",
4570	sm_etype_printf,
4571	"quick abort %0",
4572};
4573