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