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