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