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