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