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