xref: /freebsd/contrib/sendmail/src/main.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
1 /*
2  * Copyright (c) 1998-2001 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 #ifndef lint
15 static char copyright[] =
16 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
17 	All rights reserved.\n\
18      Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.\n\
19      Copyright (c) 1988, 1993\n\
20 	The Regents of the University of California.  All rights reserved.\n";
21 #endif /* ! lint */
22 
23 #ifndef lint
24 static char id[] = "@(#)$Id: main.c,v 8.485.4.65 2001/07/20 00:53:00 gshapiro Exp $";
25 #endif /* ! lint */
26 
27 #define	_DEFINE
28 
29 #include <sendmail.h>
30 
31 
32 #if NETINET || NETINET6
33 # include <arpa/inet.h>
34 #endif /* NETINET || NETINET6 */
35 
36 static SIGFUNC_DECL	intindebug __P((int));
37 static SIGFUNC_DECL	quiesce __P((int));
38 #ifdef SIGUSR1
39 static SIGFUNC_DECL	sigusr1 __P((int));
40 # endif /* SIGUSR1 */
41 static SIGFUNC_DECL	term_daemon __P((int));
42 static void	dump_class __P((STAB *, int));
43 static void	obsolete __P((char **));
44 static void	testmodeline __P((char *, ENVELOPE *));
45 
46 /*
47 **  SENDMAIL -- Post mail to a set of destinations.
48 **
49 **	This is the basic mail router.  All user mail programs should
50 **	call this routine to actually deliver mail.  Sendmail in
51 **	turn calls a bunch of mail servers that do the real work of
52 **	delivering the mail.
53 **
54 **	Sendmail is driven by settings read in from /etc/mail/sendmail.cf
55 **	(read by readcf.c).
56 **
57 **	Usage:
58 **		/usr/lib/sendmail [flags] addr ...
59 **
60 **		See the associated documentation for details.
61 **
62 **	Author:
63 **		Eric Allman, UCB/INGRES (until 10/81).
64 **			     Britton-Lee, Inc., purveyors of fine
65 **				database computers (11/81 - 10/88).
66 **			     International Computer Science Institute
67 **				(11/88 - 9/89).
68 **			     UCB/Mammoth Project (10/89 - 7/95).
69 **			     InReference, Inc. (8/95 - 1/97).
70 **			     Sendmail, Inc. (1/98 - present).
71 **		The support of the my employers is gratefully acknowledged.
72 **			Few of them (Britton-Lee in particular) have had
73 **			anything to gain from my involvement in this project.
74 */
75 
76 
77 int		NextMailer;	/* "free" index into Mailer struct */
78 char		*FullName;	/* sender's full name */
79 ENVELOPE	BlankEnvelope;	/* a "blank" envelope */
80 static ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */
81 ADDRESS		NullAddress =	/* a null address */
82 		{ "", "", NULL, "" };
83 char		*CommandLineArgs;	/* command line args for pid file */
84 bool		Warn_Q_option = FALSE;	/* warn about Q option use */
85 static int	MissingFds = 0;	/* bit map of fds missing on startup */
86 
87 #ifdef NGROUPS_MAX
88 GIDSET_T	InitialGidSet[NGROUPS_MAX];
89 #endif /* NGROUPS_MAX */
90 
91 #if DAEMON && !SMTP
92 ERROR %%%%   Cannot have DAEMON mode without SMTP   %%%% ERROR
93 #endif /* DAEMON && !SMTP */
94 #if SMTP && !QUEUE
95 ERROR %%%%   Cannot have SMTP mode without QUEUE   %%%% ERROR
96 #endif /* SMTP && !QUEUE */
97 
98 #define MAXCONFIGLEVEL	9	/* highest config version level known */
99 
100 #if SASL
101 static sasl_callback_t srvcallbacks[] =
102 {
103 	{	SASL_CB_VERIFYFILE,	&safesaslfile,	NULL	},
104 	{	SASL_CB_PROXY_POLICY,	&proxy_policy,	NULL	},
105 	{	SASL_CB_LIST_END,	NULL,		NULL	}
106 };
107 
108 #endif /* SASL */
109 
110 int SubmitMode;
111 
112 int
113 main(argc, argv, envp)
114 	int argc;
115 	char **argv;
116 	char **envp;
117 {
118 	register char *p;
119 	char **av;
120 	extern char Version[];
121 	char *ep, *from;
122 	STAB *st;
123 	register int i;
124 	int j;
125 	int dp;
126 	bool safecf = TRUE;
127 	BITMAP256 *p_flags = NULL;	/* daemon flags */
128 	bool warn_C_flag = FALSE;
129 	bool auth = TRUE;		/* whether to set e_auth_param */
130 	char warn_f_flag = '\0';
131 	bool run_in_foreground = FALSE;	/* -bD mode */
132 	static bool reenter = FALSE;
133 	struct passwd *pw;
134 	struct hostent *hp;
135 	char *nullserver = NULL;
136 	char *authinfo = NULL;
137 	char *sysloglabel = NULL;	/* label for syslog */
138 	bool forged;
139 	struct stat traf_st;		/* for TrafficLog FIFO check */
140 	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */
141 	static char rnamebuf[MAXNAME];	/* holds RealUserName */
142 	char *emptyenviron[1];
143 # if STARTTLS
144 	bool tls_ok;
145 # endif /* STARTTLS */
146 	QUEUE_CHAR *new;
147 	extern int DtableSize;
148 	extern int optind;
149 	extern int opterr;
150 	extern char *optarg;
151 	extern char **environ;
152 
153 	/*
154 	**  Check to see if we reentered.
155 	**	This would normally happen if e_putheader or e_putbody
156 	**	were NULL when invoked.
157 	*/
158 
159 	if (reenter)
160 	{
161 		syserr("main: reentered!");
162 		abort();
163 	}
164 	reenter = TRUE;
165 
166 	/* avoid null pointer dereferences */
167 	TermEscape.te_rv_on = TermEscape.te_rv_off = "";
168 
169 	/*
170 	**  Seed the random number generator.
171 	**  Used for queue file names, picking a queue directory, and
172 	**  MX randomization.
173 	*/
174 
175 	seed_random();
176 
177 	/* do machine-dependent initializations */
178 	init_md(argc, argv);
179 
180 
181 	/* in 4.4BSD, the table can be huge; impose a reasonable limit */
182 	DtableSize = getdtsize();
183 	if (DtableSize > 256)
184 		DtableSize = 256;
185 
186 	/*
187 	**  Be sure we have enough file descriptors.
188 	**	But also be sure that 0, 1, & 2 are open.
189 	*/
190 
191 	fill_fd(STDIN_FILENO, NULL);
192 	fill_fd(STDOUT_FILENO, NULL);
193 	fill_fd(STDERR_FILENO, NULL);
194 
195 	i = DtableSize;
196 	while (--i > 0)
197 	{
198 		if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
199 			(void) close(i);
200 	}
201 	errno = 0;
202 
203 #if LOG
204 #  ifdef LOG_MAIL
205 	openlog("sendmail", LOG_PID, LOG_MAIL);
206 #  else /* LOG_MAIL */
207 	openlog("sendmail", LOG_PID);
208 #  endif /* LOG_MAIL */
209 #endif /* LOG */
210 
211 	if (MissingFds != 0)
212 	{
213 		char mbuf[MAXLINE];
214 
215 		mbuf[0] = '\0';
216 		if (bitset(1 << STDIN_FILENO, MissingFds))
217 			(void) strlcat(mbuf, ", stdin", sizeof mbuf);
218 		if (bitset(1 << STDOUT_FILENO, MissingFds))
219 			(void) strlcat(mbuf, ", stdout", sizeof mbuf);
220 		if (bitset(1 << STDERR_FILENO, MissingFds))
221 			(void) strlcat(mbuf, ", stderr", sizeof mbuf);
222 		syserr("File descriptors missing on startup: %s", &mbuf[2]);
223 	}
224 
225 	/* reset status from syserr() calls for missing file descriptors */
226 	Errors = 0;
227 	ExitStat = EX_OK;
228 
229 	SubmitMode = SUBMIT_UNKNOWN;
230 #if XDEBUG
231 	checkfd012("after openlog");
232 #endif /* XDEBUG */
233 
234 	tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
235 
236 #ifdef NGROUPS_MAX
237 	/* save initial group set for future checks */
238 	i = getgroups(NGROUPS_MAX, InitialGidSet);
239 	if (i == 0)
240 		InitialGidSet[0] = (GID_T) -1;
241 	while (i < NGROUPS_MAX)
242 		InitialGidSet[i++] = InitialGidSet[0];
243 #endif /* NGROUPS_MAX */
244 
245 	/* drop group id privileges (RunAsUser not yet set) */
246 	dp = drop_privileges(FALSE);
247 	setstat(dp);
248 
249 # ifdef SIGUSR1
250 	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
251 	if (getuid() == 0 ||
252 	    (getuid() == geteuid() && getgid() == getegid()))
253 	{
254 		/* arrange to dump state on user-1 signal */
255 		(void) setsignal(SIGUSR1, sigusr1);
256 	}
257 # endif /* SIGUSR1 */
258 
259 	/* initialize for setproctitle */
260 	initsetproctitle(argc, argv, envp);
261 
262 	/* Handle any non-getoptable constructions. */
263 	obsolete(argv);
264 
265 	/*
266 	**  Do a quick prescan of the argument list.
267 	*/
268 
269 
270 #if defined(__osf__) || defined(_AIX3)
271 # define OPTIONS	"B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x"
272 #endif /* defined(__osf__) || defined(_AIX3) */
273 #if defined(sony_news)
274 # define OPTIONS	"B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
275 #endif /* defined(sony_news) */
276 #ifndef OPTIONS
277 # define OPTIONS	"B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
278 #endif /* ! OPTIONS */
279 	opterr = 0;
280 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
281 	{
282 		switch (j)
283 		{
284 		  case 'd':
285 			/* hack attack -- see if should use ANSI mode */
286 			if (strcmp(optarg, "ANSI") == 0)
287 			{
288 				TermEscape.te_rv_on = "\033[7m";
289 				TermEscape.te_rv_off = "\033[0m";
290 				break;
291 			}
292 			tTflag(optarg);
293 			setbuf(stdout, (char *) NULL);
294 			break;
295 
296 		  case 'G':	/* relay (gateway) submission */
297 			SubmitMode |= SUBMIT_MTA;
298 			break;
299 
300 		  case 'L':
301 			j = min(strlen(optarg), 24) + 1;
302 			sysloglabel = xalloc(j);
303 			(void) strlcpy(sysloglabel, optarg, j);
304 			break;
305 
306 		  case 'U':	/* initial (user) submission */
307 			SubmitMode |= SUBMIT_MSA;
308 			break;
309 		}
310 	}
311 	opterr = 1;
312 
313 #if LOG
314 	if (sysloglabel != NULL)
315 	{
316 		/* Sanitize the string */
317 		for (p = sysloglabel; *p != '\0'; p++)
318 		{
319 			if (!isascii(*p) || !isprint(*p) || *p == '%')
320 				*p = '*';
321 		}
322 		closelog();
323 #  ifdef LOG_MAIL
324 		openlog(sysloglabel, LOG_PID, LOG_MAIL);
325 #  else /* LOG_MAIL */
326 		openlog(sysloglabel, LOG_PID);
327 #  endif /* LOG_MAIL */
328 	}
329 #endif /* LOG */
330 
331 	/* set up the blank envelope */
332 	BlankEnvelope.e_puthdr = putheader;
333 	BlankEnvelope.e_putbody = putbody;
334 	BlankEnvelope.e_xfp = NULL;
335 	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
336 	CurEnv = &BlankEnvelope;
337 	STRUCTCOPY(NullAddress, MainEnvelope.e_from);
338 
339 	/*
340 	**  Set default values for variables.
341 	**	These cannot be in initialized data space.
342 	*/
343 
344 	setdefaults(&BlankEnvelope);
345 
346 	RealUid = getuid();
347 	RealGid = getgid();
348 
349 	pw = sm_getpwuid(RealUid);
350 	if (pw != NULL)
351 		(void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
352 	else
353 		(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
354 				(int) RealUid);
355 
356 	RealUserName = rnamebuf;
357 
358 	if (tTd(0, 101))
359 	{
360 		dprintf("Version %s\n", Version);
361 		finis(FALSE, EX_OK);
362 	}
363 
364 	/*
365 	**  if running non-setuid binary as non-root, pretend
366 	**  we are the RunAsUid
367 	*/
368 
369 	if (RealUid != 0 && geteuid() == RealUid)
370 	{
371 		if (tTd(47, 1))
372 			dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n",
373 				(int)RealUid);
374 		RunAsUid = RealUid;
375 	}
376 	else if (geteuid() != 0)
377 		RunAsUid = geteuid();
378 
379 	if (RealUid != 0 && getegid() == RealGid)
380 		RunAsGid = RealGid;
381 
382 	if (tTd(47, 5))
383 	{
384 		dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
385 			(int)geteuid(), (int)getuid(),
386 			(int)getegid(), (int)getgid());
387 		dprintf("main: RunAsUser = %d:%d\n",
388 			(int)RunAsUid, (int)RunAsGid);
389 	}
390 
391 	/* save command line arguments */
392 	j = 0;
393 	for (av = argv; *av != NULL; )
394 		j += strlen(*av++) + 1;
395 	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
396 	CommandLineArgs = xalloc(j);
397 	p = CommandLineArgs;
398 	for (av = argv, i = 0; *av != NULL; )
399 	{
400 		int h;
401 
402 		SaveArgv[i++] = newstr(*av);
403 		if (av != argv)
404 			*p++ = ' ';
405 		(void) strlcpy(p, *av++, j);
406 		h = strlen(p);
407 		p += h;
408 		j -= h + 1;
409 	}
410 	SaveArgv[i] = NULL;
411 
412 	if (tTd(0, 1))
413 	{
414 		int ll;
415 		extern char *CompileOptions[];
416 
417 		dprintf("Version %s\n Compiled with:", Version);
418 		av = CompileOptions;
419 		ll = 7;
420 		while (*av != NULL)
421 		{
422 			if (ll + strlen(*av) > 63)
423 			{
424 				dprintf("\n");
425 				ll = 0;
426 			}
427 			if (ll == 0)
428 				dprintf("\t\t");
429 			else
430 				dprintf(" ");
431 			dprintf("%s", *av);
432 			ll += strlen(*av++) + 1;
433 		}
434 		dprintf("\n");
435 	}
436 	if (tTd(0, 10))
437 	{
438 		int ll;
439 		extern char *OsCompileOptions[];
440 
441 		dprintf("    OS Defines:");
442 		av = OsCompileOptions;
443 		ll = 7;
444 		while (*av != NULL)
445 		{
446 			if (ll + strlen(*av) > 63)
447 			{
448 				dprintf("\n");
449 				ll = 0;
450 			}
451 			if (ll == 0)
452 				dprintf("\t\t");
453 			else
454 				dprintf(" ");
455 			dprintf("%s", *av);
456 			ll += strlen(*av++) + 1;
457 		}
458 		dprintf("\n");
459 #ifdef _PATH_UNIX
460 		dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
461 #endif /* _PATH_UNIX */
462 		dprintf(" Def Conf file:\t%s\n", getcfname());
463 		dprintf("  Def Pid file:\t%s\n", PidFile);
464 	}
465 
466 	InChannel = stdin;
467 	OutChannel = stdout;
468 
469 	/* clear sendmail's environment */
470 	ExternalEnviron = environ;
471 	emptyenviron[0] = NULL;
472 	environ = emptyenviron;
473 
474 	/*
475 	**  restore any original TZ setting until TimeZoneSpec has been
476 	**  determined - or early log messages may get bogus time stamps
477 	*/
478 	if ((p = getextenv("TZ")) != NULL)
479 	{
480 		char *tz;
481 		int tzlen;
482 
483 		tzlen = strlen(p) + 4;
484 		tz = xalloc(tzlen);
485 		(void) snprintf(tz, tzlen, "TZ=%s", p);
486 		(void) putenv(tz);
487 	}
488 
489 	/* prime the child environment */
490 	setuserenv("AGENT", "sendmail");
491 	(void) setsignal(SIGPIPE, SIG_IGN);
492 
493 	OldUmask = umask(022);
494 	OpMode = MD_DELIVER;
495 	FullName = getextenv("NAME");
496 
497 	/*
498 	**  Initialize name server if it is going to be used.
499 	*/
500 
501 #if NAMED_BIND
502 	if (!bitset(RES_INIT, _res.options))
503 		(void) res_init();
504 
505 	/*
506 	**  hack to avoid crashes when debugging for the resolver is
507 	**  turned on and sfio is used
508 	*/
509 	if (tTd(8, 8))
510 # if !SFIO || SFIO_STDIO_COMPAT
511 		_res.options |= RES_DEBUG;
512 # else /* !SFIO || SFIO_STDIO_COMPAT */
513 		dprintf("RES_DEBUG not available due to SFIO\n");
514 # endif /* !SFIO || SFIO_STDIO_COMPAT */
515 	else
516 		_res.options &= ~RES_DEBUG;
517 # ifdef RES_NOALIASES
518 	_res.options |= RES_NOALIASES;
519 # endif /* RES_NOALIASES */
520 	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
521 	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
522 	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
523 	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
524 	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
525 	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
526 #endif /* NAMED_BIND */
527 
528 	errno = 0;
529 	from = NULL;
530 
531 	/* initialize some macros, etc. */
532 	initmacros(CurEnv);
533 	init_vendor_macros(CurEnv);
534 
535 	/* version */
536 	define('v', Version, CurEnv);
537 
538 	/* hostname */
539 	hp = myhostname(jbuf, sizeof jbuf);
540 	if (jbuf[0] != '\0')
541 	{
542 		struct	utsname	utsname;
543 
544 		if (tTd(0, 4))
545 			dprintf("canonical name: %s\n", jbuf);
546 		define('w', newstr(jbuf), CurEnv);	/* must be new string */
547 		define('j', newstr(jbuf), CurEnv);
548 		setclass('w', jbuf);
549 
550 		p = strchr(jbuf, '.');
551 		if (p != NULL)
552 		{
553 			if (p[1] != '\0')
554 			{
555 				define('m', newstr(&p[1]), CurEnv);
556 			}
557 			while (p != NULL && strchr(&p[1], '.') != NULL)
558 			{
559 				*p = '\0';
560 				if (tTd(0, 4))
561 					dprintf("\ta.k.a.: %s\n", jbuf);
562 				setclass('w', jbuf);
563 				*p++ = '.';
564 				p = strchr(p, '.');
565 			}
566 		}
567 
568 		if (uname(&utsname) >= 0)
569 			p = utsname.nodename;
570 		else
571 		{
572 			if (tTd(0, 22))
573 				dprintf("uname failed (%s)\n",
574 					errstring(errno));
575 			makelower(jbuf);
576 			p = jbuf;
577 		}
578 		if (tTd(0, 4))
579 			dprintf(" UUCP nodename: %s\n", p);
580 		p = newstr(p);
581 		define('k', p, CurEnv);
582 		setclass('k', p);
583 		setclass('w', p);
584 	}
585 	if (hp != NULL)
586 	{
587 		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
588 		{
589 			if (tTd(0, 4))
590 				dprintf("\ta.k.a.: %s\n", *av);
591 			setclass('w', *av);
592 		}
593 #if NETINET || NETINET6
594 		for (i = 0; hp->h_addr_list[i] != NULL; i++)
595 		{
596 # if NETINET6
597 			char *addr;
598 			char buf6[INET6_ADDRSTRLEN];
599 			struct in6_addr ia6;
600 # endif /* NETINET6 */
601 # if NETINET
602 			struct in_addr ia;
603 # endif /* NETINET */
604 			char ipbuf[103];
605 
606 			ipbuf[0] = '\0';
607 			switch (hp->h_addrtype)
608 			{
609 # if NETINET
610 			  case AF_INET:
611 				if (hp->h_length != INADDRSZ)
612 					break;
613 
614 				memmove(&ia, hp->h_addr_list[i], INADDRSZ);
615 				(void) snprintf(ipbuf,	 sizeof ipbuf,
616 						"[%.100s]", inet_ntoa(ia));
617 				break;
618 # endif /* NETINET */
619 
620 # if NETINET6
621 			  case AF_INET6:
622 				if (hp->h_length != IN6ADDRSZ)
623 					break;
624 
625 				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
626 				addr = anynet_ntop(&ia6, buf6, sizeof buf6);
627 				if (addr != NULL)
628 					(void) snprintf(ipbuf, sizeof ipbuf,
629 							"[%.100s]", addr);
630 				break;
631 # endif /* NETINET6 */
632 			}
633 			if (ipbuf[0] == '\0')
634 				break;
635 
636 			if (tTd(0, 4))
637 				dprintf("\ta.k.a.: %s\n", ipbuf);
638 			setclass('w', ipbuf);
639 		}
640 #endif /* NETINET || NETINET6 */
641 #if _FFR_FREEHOSTENT && NETINET6
642 		freehostent(hp);
643 		hp = NULL;
644 #endif /* _FFR_FREEHOSTENT && NETINET6 */
645 	}
646 
647 	/* current time */
648 	define('b', arpadate((char *) NULL), CurEnv);
649 	/* current load average */
650 	CurrentLA = sm_getla(CurEnv);
651 
652 	QueueLimitRecipient = (QUEUE_CHAR *) NULL;
653 	QueueLimitSender = (QUEUE_CHAR *) NULL;
654 	QueueLimitId = (QUEUE_CHAR *) NULL;
655 
656 	/*
657 	**  Crack argv.
658 	*/
659 
660 	av = argv;
661 	p = strrchr(*av, '/');
662 	if (p++ == NULL)
663 		p = *av;
664 	if (strcmp(p, "newaliases") == 0)
665 		OpMode = MD_INITALIAS;
666 	else if (strcmp(p, "mailq") == 0)
667 		OpMode = MD_PRINT;
668 	else if (strcmp(p, "smtpd") == 0)
669 		OpMode = MD_DAEMON;
670 	else if (strcmp(p, "hoststat") == 0)
671 		OpMode = MD_HOSTSTAT;
672 	else if (strcmp(p, "purgestat") == 0)
673 		OpMode = MD_PURGESTAT;
674 
675 	optind = 1;
676 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
677 	{
678 		switch (j)
679 		{
680 		  case 'b':	/* operations mode */
681 			switch (j = *optarg)
682 			{
683 			  case MD_DAEMON:
684 			  case MD_FGDAEMON:
685 #if !DAEMON
686 				usrerr("Daemon mode not implemented");
687 				ExitStat = EX_USAGE;
688 				break;
689 #endif /* !DAEMON */
690 			  case MD_SMTP:
691 #if !SMTP
692 				usrerr("I don't speak SMTP");
693 				ExitStat = EX_USAGE;
694 				break;
695 #endif /* !SMTP */
696 
697 			  case MD_INITALIAS:
698 			  case MD_DELIVER:
699 			  case MD_VERIFY:
700 			  case MD_TEST:
701 			  case MD_PRINT:
702 			  case MD_HOSTSTAT:
703 			  case MD_PURGESTAT:
704 			  case MD_ARPAFTP:
705 				OpMode = j;
706 				break;
707 
708 			  case MD_FREEZE:
709 				usrerr("Frozen configurations unsupported");
710 				ExitStat = EX_USAGE;
711 				break;
712 
713 			  default:
714 				usrerr("Invalid operation mode %c", j);
715 				ExitStat = EX_USAGE;
716 				break;
717 			}
718 			break;
719 
720 		  case 'B':	/* body type */
721 			CurEnv->e_bodytype = newstr(optarg);
722 			break;
723 
724 		  case 'C':	/* select configuration file (already done) */
725 			if (RealUid != 0)
726 				warn_C_flag = TRUE;
727 			ConfFile = newstr(optarg);
728 			dp = drop_privileges(TRUE);
729 			setstat(dp);
730 			safecf = FALSE;
731 			break;
732 
733 		  case 'd':	/* debugging -- already done */
734 			break;
735 
736 		  case 'f':	/* from address */
737 		  case 'r':	/* obsolete -f flag */
738 			if (from != NULL)
739 			{
740 				usrerr("More than one \"from\" person");
741 				ExitStat = EX_USAGE;
742 				break;
743 			}
744 			from = newstr(denlstring(optarg, TRUE, TRUE));
745 			if (strcmp(RealUserName, from) != 0)
746 				warn_f_flag = j;
747 			break;
748 
749 		  case 'F':	/* set full name */
750 			FullName = newstr(optarg);
751 			break;
752 
753 		  case 'G':	/* relay (gateway) submission */
754 			/* already set */
755 			break;
756 
757 		  case 'h':	/* hop count */
758 			CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10);
759 			if (*ep)
760 			{
761 				usrerr("Bad hop count (%s)", optarg);
762 				ExitStat = EX_USAGE;
763 			}
764 			break;
765 
766 		  case 'L':	/* program label */
767 			/* already set */
768 			break;
769 
770 		  case 'n':	/* don't alias */
771 			NoAlias = TRUE;
772 			break;
773 
774 		  case 'N':	/* delivery status notifications */
775 			DefaultNotify |= QHASNOTIFY;
776 			define(macid("{dsn_notify}", NULL),
777 			       newstr(optarg), CurEnv);
778 			if (strcasecmp(optarg, "never") == 0)
779 				break;
780 			for (p = optarg; p != NULL; optarg = p)
781 			{
782 				p = strchr(p, ',');
783 				if (p != NULL)
784 					*p++ = '\0';
785 				if (strcasecmp(optarg, "success") == 0)
786 					DefaultNotify |= QPINGONSUCCESS;
787 				else if (strcasecmp(optarg, "failure") == 0)
788 					DefaultNotify |= QPINGONFAILURE;
789 				else if (strcasecmp(optarg, "delay") == 0)
790 					DefaultNotify |= QPINGONDELAY;
791 				else
792 				{
793 					usrerr("Invalid -N argument");
794 					ExitStat = EX_USAGE;
795 				}
796 			}
797 			break;
798 
799 		  case 'o':	/* set option */
800 			setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
801 			break;
802 
803 		  case 'O':	/* set option (long form) */
804 			setoption(' ', optarg, FALSE, TRUE, CurEnv);
805 			break;
806 
807 		  case 'p':	/* set protocol */
808 			p = strchr(optarg, ':');
809 			if (p != NULL)
810 			{
811 				*p++ = '\0';
812 				if (*p != '\0')
813 				{
814 					ep = xalloc(strlen(p) + 1);
815 					cleanstrcpy(ep, p, MAXNAME);
816 					define('s', ep, CurEnv);
817 				}
818 			}
819 			if (*optarg != '\0')
820 			{
821 				ep = xalloc(strlen(optarg) + 1);
822 				cleanstrcpy(ep, optarg, MAXNAME);
823 				define('r', ep, CurEnv);
824 			}
825 			break;
826 
827 		  case 'q':	/* run queue files at intervals */
828 #if QUEUE
829 			/* sanity check */
830 			if (OpMode != MD_DELIVER &&
831 			    OpMode != MD_DAEMON &&
832 			    OpMode != MD_FGDAEMON &&
833 			    OpMode != MD_PRINT &&
834 			    OpMode != MD_QUEUERUN)
835 			{
836 				usrerr("Can not use -q with -b%c", OpMode);
837 				ExitStat = EX_USAGE;
838 				break;
839 			}
840 
841 			/* don't override -bd, -bD or -bp */
842 			if (OpMode == MD_DELIVER)
843 				OpMode = MD_QUEUERUN;
844 
845 			FullName = NULL;
846 
847 			switch (optarg[0])
848 			{
849 			  case 'I':
850 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
851 				new->queue_match = newstr(&optarg[1]);
852 				new->queue_next = QueueLimitId;
853 				QueueLimitId = new;
854 				break;
855 
856 			  case 'R':
857 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
858 				new->queue_match = newstr(&optarg[1]);
859 				new->queue_next = QueueLimitRecipient;
860 				QueueLimitRecipient = new;
861 				break;
862 
863 			  case 'S':
864 				new = (QUEUE_CHAR *) xalloc(sizeof *new);
865 				new->queue_match = newstr(&optarg[1]);
866 				new->queue_next = QueueLimitSender;
867 				QueueLimitSender = new;
868 				break;
869 
870 			  default:
871 				i = Errors;
872 				QueueIntvl = convtime(optarg, 'm');
873 
874 				/* check for bad conversion */
875 				if (i < Errors)
876 					ExitStat = EX_USAGE;
877 				break;
878 			}
879 #else /* QUEUE */
880 			usrerr("I don't know about queues");
881 			ExitStat = EX_USAGE;
882 #endif /* QUEUE */
883 			break;
884 
885 		  case 'R':	/* DSN RET: what to return */
886 			if (bitset(EF_RET_PARAM, CurEnv->e_flags))
887 			{
888 				usrerr("Duplicate -R flag");
889 				ExitStat = EX_USAGE;
890 				break;
891 			}
892 			CurEnv->e_flags |= EF_RET_PARAM;
893 			if (strcasecmp(optarg, "hdrs") == 0)
894 				CurEnv->e_flags |= EF_NO_BODY_RETN;
895 			else if (strcasecmp(optarg, "full") != 0)
896 			{
897 				usrerr("Invalid -R value");
898 				ExitStat = EX_USAGE;
899 			}
900 			define(macid("{dsn_ret}", NULL),
901 			       newstr(optarg), CurEnv);
902 			break;
903 
904 		  case 't':	/* read recipients from message */
905 			GrabTo = TRUE;
906 			break;
907 
908 		  case 'U':	/* initial (user) submission */
909 			/* already set */
910 			break;
911 
912 		  case 'V':	/* DSN ENVID: set "original" envelope id */
913 			if (!xtextok(optarg))
914 			{
915 				usrerr("Invalid syntax in -V flag");
916 				ExitStat = EX_USAGE;
917 			}
918 			else
919 			{
920 				CurEnv->e_envid = newstr(optarg);
921 				define(macid("{dsn_envid}", NULL),
922 				       newstr(optarg), CurEnv);
923 			}
924 			break;
925 
926 		  case 'X':	/* traffic log file */
927 			dp = drop_privileges(TRUE);
928 			setstat(dp);
929 			if (stat(optarg, &traf_st) == 0 &&
930 			    S_ISFIFO(traf_st.st_mode))
931 				TrafficLogFile = fopen(optarg, "w");
932 			else
933 				TrafficLogFile = fopen(optarg, "a");
934 			if (TrafficLogFile == NULL)
935 			{
936 				syserr("cannot open %s", optarg);
937 				ExitStat = EX_CANTCREAT;
938 				break;
939 			}
940 #if HASSETVBUF
941 			(void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
942 #else /* HASSETVBUF */
943 			(void) setlinebuf(TrafficLogFile);
944 #endif /* HASSETVBUF */
945 			break;
946 
947 			/* compatibility flags */
948 		  case 'c':	/* connect to non-local mailers */
949 		  case 'i':	/* don't let dot stop me */
950 		  case 'm':	/* send to me too */
951 		  case 'T':	/* set timeout interval */
952 		  case 'v':	/* give blow-by-blow description */
953 			setoption(j, "T", FALSE, TRUE, CurEnv);
954 			break;
955 
956 		  case 'e':	/* error message disposition */
957 		  case 'M':	/* define macro */
958 			setoption(j, optarg, FALSE, TRUE, CurEnv);
959 			break;
960 
961 		  case 's':	/* save From lines in headers */
962 			setoption('f', "T", FALSE, TRUE, CurEnv);
963 			break;
964 
965 #ifdef DBM
966 		  case 'I':	/* initialize alias DBM file */
967 			OpMode = MD_INITALIAS;
968 			break;
969 #endif /* DBM */
970 
971 #if defined(__osf__) || defined(_AIX3)
972 		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */
973 			break;
974 #endif /* defined(__osf__) || defined(_AIX3) */
975 #if defined(sony_news)
976 		  case 'E':
977 		  case 'J':	/* ignore flags for Japanese code conversion
978 				   implemented on Sony NEWS */
979 			break;
980 #endif /* defined(sony_news) */
981 
982 		  default:
983 			finis(TRUE, EX_USAGE);
984 			break;
985 		}
986 	}
987 	av += optind;
988 
989 	if (bitset(SUBMIT_MTA, SubmitMode) &&
990 	    bitset(SUBMIT_MSA, SubmitMode))
991 	{
992 		/* sanity check */
993 		errno = 0;	/* reset to avoid bogus error messages */
994 		syserr("Cannot use both -G and -U together");
995 	}
996 	else if (bitset(SUBMIT_MTA, SubmitMode))
997 		define(macid("{daemon_flags}", NULL), "CC f", CurEnv);
998 	else if (bitset(SUBMIT_MSA, SubmitMode))
999 	{
1000 		define(macid("{daemon_flags}", NULL), "c u", CurEnv);
1001 
1002 		/* check for wrong OpMode */
1003 		if (OpMode != MD_DELIVER && OpMode != MD_SMTP)
1004 		{
1005 			errno = 0;	/* reset to avoid bogus error msgs */
1006 			syserr("Cannot use -U and -b%c", OpMode);
1007 		}
1008 	}
1009 	else
1010 	{
1011 #if _FFR_DEFAULT_SUBMIT_TO_MSA
1012 		define(macid("{daemon_flags}", NULL), "c u", CurEnv);
1013 #else /* _FFR_DEFAULT_SUBMIT_TO_MSA */
1014 		/* EMPTY */
1015 #endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */
1016 	}
1017 
1018 	/*
1019 	**  Do basic initialization.
1020 	**	Read system control file.
1021 	**	Extract special fields for local use.
1022 	*/
1023 
1024 	/* set up ${opMode} for use in config file */
1025 	{
1026 		char mbuf[2];
1027 
1028 		mbuf[0] = OpMode;
1029 		mbuf[1] = '\0';
1030 		define(MID_OPMODE, newstr(mbuf), CurEnv);
1031 	}
1032 
1033 #if XDEBUG
1034 	checkfd012("before readcf");
1035 #endif /* XDEBUG */
1036 	vendor_pre_defaults(CurEnv);
1037 
1038 	readcf(getcfname(), safecf, CurEnv);
1039 	ConfigFileRead = TRUE;
1040 	vendor_post_defaults(CurEnv);
1041 
1042 	/* Remove the ability for a normal user to send signals */
1043 	if (RealUid != 0 &&
1044 	    RealUid != geteuid())
1045 	{
1046 		uid_t new_uid = geteuid();
1047 
1048 #if HASSETREUID
1049 		/*
1050 		**  Since we can differentiate between uid and euid,
1051 		**  make the uid a different user so the real user
1052 		**  can't send signals.  However, it doesn't need to be
1053 		**  root (euid has root).
1054 		*/
1055 
1056 		if (new_uid == 0)
1057 			new_uid = DefUid;
1058 		if (tTd(47, 5))
1059 			dprintf("Changing real uid to %d\n", (int) new_uid);
1060 		if (setreuid(new_uid, geteuid()) < 0)
1061 		{
1062 			syserr("main: setreuid(%d, %d) failed",
1063 			       (int) new_uid, (int) geteuid());
1064 			finis(FALSE, EX_OSERR);
1065 			/* NOTREACHED */
1066 		}
1067 		if (tTd(47, 10))
1068 			dprintf("Now running as e/ruid %d:%d\n",
1069 				(int) geteuid(), (int) getuid());
1070 #else /* HASSETREUID */
1071 		/*
1072 		**  Have to change both effective and real so need to
1073 		**  change them both to effective to keep privs.
1074 		*/
1075 
1076 		if (tTd(47, 5))
1077 			dprintf("Changing uid to %d\n", (int) new_uid);
1078 		if (setuid(new_uid) < 0)
1079 		{
1080 			syserr("main: setuid(%d) failed", (int) new_uid);
1081 			finis(FALSE, EX_OSERR);
1082 			/* NOTREACHED */
1083 		}
1084 		if (tTd(47, 10))
1085 			dprintf("Now running as e/ruid %d:%d\n",
1086 				(int) geteuid(), (int) getuid());
1087 #endif /* HASSETREUID */
1088 	}
1089 
1090 	/* set up the basic signal handlers */
1091 	if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
1092 		(void) setsignal(SIGINT, intsig);
1093 	(void) setsignal(SIGTERM, intsig);
1094 
1095 	/* Enforce use of local time (null string overrides this) */
1096 	if (TimeZoneSpec == NULL)
1097 		unsetenv("TZ");
1098 	else if (TimeZoneSpec[0] != '\0')
1099 		setuserenv("TZ", TimeZoneSpec);
1100 	else
1101 		setuserenv("TZ", NULL);
1102 	tzset();
1103 
1104 	/* avoid denial-of-service attacks */
1105 	resetlimits();
1106 
1107 	if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
1108 	{
1109 		/* drop privileges -- daemon mode done after socket/bind */
1110 		dp = drop_privileges(FALSE);
1111 		setstat(dp);
1112 	}
1113 
1114 #if NAMED_BIND
1115 	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
1116 	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
1117 #endif /* NAMED_BIND */
1118 
1119 	/*
1120 	**  Find our real host name for future logging.
1121 	*/
1122 
1123 	authinfo = getauthinfo(STDIN_FILENO, &forged);
1124 	define('_', authinfo, CurEnv);
1125 
1126 	/* suppress error printing if errors mailed back or whatever */
1127 	if (CurEnv->e_errormode != EM_PRINT)
1128 		HoldErrs = TRUE;
1129 
1130 	/* set up the $=m class now, after .cf has a chance to redefine $m */
1131 	expand("\201m", jbuf, sizeof jbuf, CurEnv);
1132 	if (jbuf[0] != '\0')
1133 		setclass('m', jbuf);
1134 
1135 	/* probe interfaces and locate any additional names */
1136 	if (!DontProbeInterfaces)
1137 		load_if_names();
1138 
1139 	if (tTd(0, 1))
1140 	{
1141 		dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
1142 		dprintf("\n      (short domain name) $w = ");
1143 		xputs(macvalue('w', CurEnv));
1144 		dprintf("\n  (canonical domain name) $j = ");
1145 		xputs(macvalue('j', CurEnv));
1146 		dprintf("\n         (subdomain name) $m = ");
1147 		xputs(macvalue('m', CurEnv));
1148 		dprintf("\n              (node name) $k = ");
1149 		xputs(macvalue('k', CurEnv));
1150 		dprintf("\n========================================================\n\n");
1151 	}
1152 
1153 	/*
1154 	**  Do more command line checking -- these are things that
1155 	**  have to modify the results of reading the config file.
1156 	*/
1157 
1158 	/* process authorization warnings from command line */
1159 	if (warn_C_flag)
1160 		auth_warning(CurEnv, "Processed by %s with -C %s",
1161 			RealUserName, ConfFile);
1162 	if (Warn_Q_option && !wordinclass(RealUserName, 't'))
1163 		auth_warning(CurEnv, "Processed from queue %s", QueueDir);
1164 
1165 	/* check body type for legality */
1166 	if (CurEnv->e_bodytype == NULL)
1167 		/* EMPTY */
1168 		/* nothing */ ;
1169 	else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
1170 		SevenBitInput = TRUE;
1171 	else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
1172 		SevenBitInput = FALSE;
1173 	else
1174 	{
1175 		usrerr("Illegal body type %s", CurEnv->e_bodytype);
1176 		CurEnv->e_bodytype = NULL;
1177 	}
1178 
1179 	/* tweak default DSN notifications */
1180 	if (DefaultNotify == 0)
1181 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1182 
1183 	/* be sure we don't pick up bogus HOSTALIASES environment variable */
1184 	if (OpMode == MD_QUEUERUN && RealUid != 0)
1185 		(void) unsetenv("HOSTALIASES");
1186 
1187 	/* check for sane configuration level */
1188 	if (ConfigLevel > MAXCONFIGLEVEL)
1189 	{
1190 		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1191 			ConfigLevel, Version, MAXCONFIGLEVEL);
1192 	}
1193 
1194 	/* need MCI cache to have persistence */
1195 	if (HostStatDir != NULL && MaxMciCache == 0)
1196 	{
1197 		HostStatDir = NULL;
1198 		printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1199 	}
1200 
1201 	/* need HostStatusDir in order to have SingleThreadDelivery */
1202 	if (SingleThreadDelivery && HostStatDir == NULL)
1203 	{
1204 		SingleThreadDelivery = FALSE;
1205 		printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1206 	}
1207 
1208 	/* check for permissions */
1209 	if ((OpMode == MD_DAEMON ||
1210 	     OpMode == MD_FGDAEMON ||
1211 	     OpMode == MD_PURGESTAT) &&
1212 	    RealUid != 0 &&
1213 	    RealUid != TrustedUid)
1214 	{
1215 		if (LogLevel > 1)
1216 			sm_syslog(LOG_ALERT, NOQID,
1217 				  "user %d attempted to %s",
1218 				  RealUid,
1219 				  OpMode != MD_PURGESTAT ? "run daemon"
1220 							 : "purge host status");
1221 		usrerr("Permission denied");
1222 		finis(FALSE, EX_USAGE);
1223 	}
1224 	if (OpMode == MD_INITALIAS &&
1225 	    RealUid != 0 &&
1226 	    RealUid != TrustedUid &&
1227 	    !wordinclass(RealUserName, 't'))
1228 	{
1229 		if (LogLevel > 1)
1230 			sm_syslog(LOG_ALERT, NOQID,
1231 				  "user %d attempted to rebuild the alias map",
1232 				  RealUid);
1233 		usrerr("Permission denied");
1234 		finis(FALSE, EX_USAGE);
1235 	}
1236 
1237 	if (MeToo)
1238 		BlankEnvelope.e_flags |= EF_METOO;
1239 
1240 	switch (OpMode)
1241 	{
1242 	  case MD_TEST:
1243 		/* don't have persistent host status in test mode */
1244 		HostStatDir = NULL;
1245 		if (Verbose == 0)
1246 			Verbose = 2;
1247 		CurEnv->e_errormode = EM_PRINT;
1248 		HoldErrs = FALSE;
1249 		break;
1250 
1251 	  case MD_VERIFY:
1252 		CurEnv->e_errormode = EM_PRINT;
1253 		HoldErrs = FALSE;
1254 
1255 		/* arrange to exit cleanly on hangup signal */
1256 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1257 			(void) setsignal(SIGHUP, intsig);
1258 		break;
1259 
1260 	  case MD_FGDAEMON:
1261 		run_in_foreground = TRUE;
1262 		OpMode = MD_DAEMON;
1263 		/* FALLTHROUGH */
1264 
1265 	  case MD_DAEMON:
1266 		vendor_daemon_setup(CurEnv);
1267 
1268 		/* remove things that don't make sense in daemon mode */
1269 		FullName = NULL;
1270 		GrabTo = FALSE;
1271 
1272 		/* arrange to restart on hangup signal */
1273 		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1274 			sm_syslog(LOG_WARNING, NOQID,
1275 				  "daemon invoked without full pathname; kill -1 won't work");
1276 		(void) setsignal(SIGTERM, term_daemon);
1277 		break;
1278 
1279 	  case MD_INITALIAS:
1280 		Verbose = 2;
1281 		CurEnv->e_errormode = EM_PRINT;
1282 		HoldErrs = FALSE;
1283 		/* FALLTHROUGH */
1284 
1285 	  default:
1286 		/* arrange to exit cleanly on hangup signal */
1287 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1288 			(void) setsignal(SIGHUP, intsig);
1289 		break;
1290 	}
1291 
1292 	/* special considerations for FullName */
1293 	if (FullName != NULL)
1294 	{
1295 		char *full = NULL;
1296 
1297 		/* full names can't have newlines */
1298 		if (strchr(FullName, '\n') != NULL)
1299 		{
1300 			full = newstr(denlstring(FullName, TRUE, TRUE));
1301 			FullName = full;
1302 		}
1303 
1304 		/* check for characters that may have to be quoted */
1305 		if (!rfc822_string(FullName))
1306 		{
1307 			/*
1308 			**  Quote a full name with special characters
1309 			**  as a comment so crackaddr() doesn't destroy
1310 			**  the name portion of the address.
1311 			*/
1312 
1313 			FullName = addquotes(FullName);
1314 			if (full != NULL)
1315 				sm_free(full);
1316 		}
1317 	}
1318 
1319 	/* do heuristic mode adjustment */
1320 	if (Verbose)
1321 	{
1322 		/* turn off noconnect option */
1323 		setoption('c', "F", TRUE, FALSE, CurEnv);
1324 
1325 		/* turn on interactive delivery */
1326 		setoption('d', "", TRUE, FALSE, CurEnv);
1327 	}
1328 
1329 #ifdef VENDOR_CODE
1330 	/* check for vendor mismatch */
1331 	if (VendorCode != VENDOR_CODE)
1332 	{
1333 		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1334 			getvendor(VENDOR_CODE), getvendor(VendorCode));
1335 	}
1336 #endif /* VENDOR_CODE */
1337 
1338 	/* check for out of date configuration level */
1339 	if (ConfigLevel < MAXCONFIGLEVEL)
1340 	{
1341 		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1342 			Version, MAXCONFIGLEVEL, ConfigLevel);
1343 	}
1344 
1345 	if (ConfigLevel < 3)
1346 		UseErrorsTo = TRUE;
1347 
1348 	/* set options that were previous macros */
1349 	if (SmtpGreeting == NULL)
1350 	{
1351 		if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
1352 			SmtpGreeting = newstr(p);
1353 		else
1354 			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1355 	}
1356 	if (UnixFromLine == NULL)
1357 	{
1358 		if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
1359 			UnixFromLine = newstr(p);
1360 		else
1361 			UnixFromLine = "From \201g  \201d";
1362 	}
1363 	SmtpError[0] = '\0';
1364 
1365 	/* our name for SMTP codes */
1366 	expand("\201j", jbuf, sizeof jbuf, CurEnv);
1367 	if (jbuf[0] == '\0')
1368 		MyHostName = newstr("localhost");
1369 	else
1370 		MyHostName = jbuf;
1371 	if (strchr(MyHostName, '.') == NULL)
1372 		message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1373 			MyHostName);
1374 
1375 	/* make certain that this name is part of the $=w class */
1376 	setclass('w', MyHostName);
1377 
1378 	/* the indices of built-in mailers */
1379 	st = stab("local", ST_MAILER, ST_FIND);
1380 	if (st != NULL)
1381 		LocalMailer = st->s_mailer;
1382 	else if (OpMode != MD_TEST || !warn_C_flag)
1383 		syserr("No local mailer defined");
1384 
1385 	st = stab("prog", ST_MAILER, ST_FIND);
1386 	if (st == NULL)
1387 		syserr("No prog mailer defined");
1388 	else
1389 	{
1390 		ProgMailer = st->s_mailer;
1391 		clrbitn(M_MUSER, ProgMailer->m_flags);
1392 	}
1393 
1394 	st = stab("*file*", ST_MAILER, ST_FIND);
1395 	if (st == NULL)
1396 		syserr("No *file* mailer defined");
1397 	else
1398 	{
1399 		FileMailer = st->s_mailer;
1400 		clrbitn(M_MUSER, FileMailer->m_flags);
1401 	}
1402 
1403 	st = stab("*include*", ST_MAILER, ST_FIND);
1404 	if (st == NULL)
1405 		syserr("No *include* mailer defined");
1406 	else
1407 		InclMailer = st->s_mailer;
1408 
1409 	if (ConfigLevel < 6)
1410 	{
1411 		/* heuristic tweaking of local mailer for back compat */
1412 		if (LocalMailer != NULL)
1413 		{
1414 			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1415 			setbitn(M_HASPWENT, LocalMailer->m_flags);
1416 			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1417 			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1418 			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1419 			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1420 			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1421 		}
1422 		if (ProgMailer != NULL)
1423 			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1424 		if (FileMailer != NULL)
1425 			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1426 	}
1427 	if (ConfigLevel < 7)
1428 	{
1429 		if (LocalMailer != NULL)
1430 			setbitn(M_VRFY250, LocalMailer->m_flags);
1431 		if (ProgMailer != NULL)
1432 			setbitn(M_VRFY250, ProgMailer->m_flags);
1433 		if (FileMailer != NULL)
1434 			setbitn(M_VRFY250, FileMailer->m_flags);
1435 	}
1436 
1437 	/* MIME Content-Types that cannot be transfer encoded */
1438 	setclass('n', "multipart/signed");
1439 
1440 	/* MIME message/xxx subtypes that can be treated as messages */
1441 	setclass('s', "rfc822");
1442 
1443 	/* MIME Content-Transfer-Encodings that can be encoded */
1444 	setclass('e', "7bit");
1445 	setclass('e', "8bit");
1446 	setclass('e', "binary");
1447 
1448 #ifdef USE_B_CLASS
1449 	/* MIME Content-Types that should be treated as binary */
1450 	setclass('b', "image");
1451 	setclass('b', "audio");
1452 	setclass('b', "video");
1453 	setclass('b', "application/octet-stream");
1454 #endif /* USE_B_CLASS */
1455 
1456 	/* MIME headers which have fields to check for overflow */
1457 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
1458 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
1459 
1460 	/* MIME headers to check for length overflow */
1461 	setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
1462 
1463 	/* MIME headers to check for overflow and rebalance */
1464 	setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
1465 	setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
1466 	setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
1467 	setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
1468 	setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
1469 
1470 	/* Macros to save in the qf file -- don't remove any */
1471 	setclass(macid("{persistentMacros}", NULL), "r");
1472 	setclass(macid("{persistentMacros}", NULL), "s");
1473 	setclass(macid("{persistentMacros}", NULL), "_");
1474 	setclass(macid("{persistentMacros}", NULL), "{if_addr}");
1475 	setclass(macid("{persistentMacros}", NULL), "{daemon_flags}");
1476 	setclass(macid("{persistentMacros}", NULL), "{client_flags}");
1477 
1478 	/* operate in queue directory */
1479 	if (QueueDir == NULL)
1480 	{
1481 		if (OpMode != MD_TEST)
1482 		{
1483 			syserr("QueueDirectory (Q) option must be set");
1484 			ExitStat = EX_CONFIG;
1485 		}
1486 	}
1487 	else
1488 	{
1489 		/*
1490 		**  If multiple queues wildcarded, use one for
1491 		**  the daemon's home. Note that this preconditions
1492 		**  a wildcarded QueueDir to a real pathname.
1493 		*/
1494 
1495 		if (OpMode != MD_TEST)
1496 			multiqueue_cache();
1497 	}
1498 
1499 	/* check host status directory for validity */
1500 	if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
1501 	{
1502 		/* cannot use this value */
1503 		if (tTd(0, 2))
1504 			dprintf("Cannot use HostStatusDirectory = %s: %s\n",
1505 				HostStatDir, errstring(errno));
1506 		HostStatDir = NULL;
1507 	}
1508 
1509 #if QUEUE
1510 	if (OpMode == MD_QUEUERUN && RealUid != 0 &&
1511 	    bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1512 	{
1513 		struct stat stbuf;
1514 
1515 		/* check to see if we own the queue directory */
1516 		if (stat(".", &stbuf) < 0)
1517 			syserr("main: cannot stat %s", QueueDir);
1518 		if (stbuf.st_uid != RealUid)
1519 		{
1520 			/* nope, really a botch */
1521 			usrerr("You do not have permission to process the queue");
1522 			finis(FALSE, EX_NOPERM);
1523 		}
1524 	}
1525 #endif /* QUEUE */
1526 
1527 #if _FFR_MILTER
1528 	/* sanity checks on milter filters */
1529 	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
1530 		milter_parse_list(InputFilterList, InputFilters, MAXFILTERS);
1531 #endif /* _FFR_MILTER */
1532 
1533 
1534 	/* if we've had errors so far, exit now */
1535 	if (ExitStat != EX_OK && OpMode != MD_TEST)
1536 		finis(FALSE, ExitStat);
1537 
1538 #if XDEBUG
1539 	checkfd012("before main() initmaps");
1540 #endif /* XDEBUG */
1541 
1542 	/*
1543 	**  Do operation-mode-dependent initialization.
1544 	*/
1545 
1546 	switch (OpMode)
1547 	{
1548 	  case MD_PRINT:
1549 		/* print the queue */
1550 #if QUEUE
1551 		dropenvelope(CurEnv, TRUE);
1552 		(void) setsignal(SIGPIPE, quiesce);
1553 		printqueue();
1554 		finis(FALSE, EX_OK);
1555 #else /* QUEUE */
1556 		usrerr("No queue to print");
1557 		finis(FALSE, EX_UNAVAILABLE);
1558 #endif /* QUEUE */
1559 		break;
1560 
1561 	  case MD_HOSTSTAT:
1562 		(void) setsignal(SIGPIPE, quiesce);
1563 		(void) mci_traverse_persistent(mci_print_persistent, NULL);
1564 		finis(FALSE, EX_OK);
1565 		break;
1566 
1567 	  case MD_PURGESTAT:
1568 		(void) mci_traverse_persistent(mci_purge_persistent, NULL);
1569 		finis(FALSE, EX_OK);
1570 		break;
1571 
1572 	  case MD_INITALIAS:
1573 		/* initialize maps */
1574 		initmaps();
1575 		finis(FALSE, ExitStat);
1576 		break;
1577 
1578 	  case MD_SMTP:
1579 	  case MD_DAEMON:
1580 		/* reset DSN parameters */
1581 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1582 		define(macid("{dsn_notify}", NULL), NULL, CurEnv);
1583 		CurEnv->e_envid = NULL;
1584 		define(macid("{dsn_envid}", NULL), NULL, CurEnv);
1585 		CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
1586 		define(macid("{dsn_ret}", NULL), NULL, CurEnv);
1587 
1588 		/* don't open maps for daemon -- done below in child */
1589 		break;
1590 	}
1591 
1592 	if (tTd(0, 15))
1593 	{
1594 		/* print configuration table (or at least part of it) */
1595 		if (tTd(0, 90))
1596 			printrules();
1597 		for (i = 0; i < MAXMAILERS; i++)
1598 		{
1599 			if (Mailer[i] != NULL)
1600 				printmailer(Mailer[i]);
1601 		}
1602 	}
1603 
1604 	/*
1605 	**  Switch to the main envelope.
1606 	*/
1607 
1608 	CurEnv = newenvelope(&MainEnvelope, CurEnv);
1609 	MainEnvelope.e_flags = BlankEnvelope.e_flags;
1610 
1611 	/*
1612 	**  If test mode, read addresses from stdin and process.
1613 	*/
1614 
1615 	if (OpMode == MD_TEST)
1616 	{
1617 		char buf[MAXLINE];
1618 
1619 #if _FFR_TESTMODE_DROP_PRIVS
1620 		dp = drop_privileges(TRUE);
1621 		if (dp != EX_OK)
1622 		{
1623 			CurEnv->e_id = NULL;
1624 			finis(TRUE, dp);
1625 		}
1626 #endif /* _FFR_TESTMODE_DROP_PRIVS */
1627 
1628 		if (isatty(fileno(stdin)))
1629 			Verbose = 2;
1630 
1631 		if (Verbose)
1632 		{
1633 			printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1634 			printf("Enter <ruleset> <address>\n");
1635 		}
1636 		if (setjmp(TopFrame) > 0)
1637 			printf("\n");
1638 		(void) setsignal(SIGINT, intindebug);
1639 		for (;;)
1640 		{
1641 			if (Verbose == 2)
1642 				printf("> ");
1643 			(void) fflush(stdout);
1644 			if (fgets(buf, sizeof buf, stdin) == NULL)
1645 				testmodeline("/quit", CurEnv);
1646 			p = strchr(buf, '\n');
1647 			if (p != NULL)
1648 				*p = '\0';
1649 			if (Verbose < 2)
1650 				printf("> %s\n", buf);
1651 			testmodeline(buf, CurEnv);
1652 		}
1653 	}
1654 
1655 #if SMTP
1656 # if STARTTLS
1657 	tls_ok = init_tls_library();
1658 # endif /* STARTTLS */
1659 #endif /* SMTP */
1660 
1661 #if QUEUE
1662 	/*
1663 	**  If collecting stuff from the queue, go start doing that.
1664 	*/
1665 
1666 	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
1667 	{
1668 # if SMTP
1669 #  if STARTTLS
1670 		if (tls_ok
1671 		   )
1672 		{
1673 			/* init TLS for client, ignore result for now */
1674 			(void) initclttls();
1675 		}
1676 #  endif /* STARTTLS */
1677 # endif /* SMTP */
1678 		(void) runqueue(FALSE, Verbose);
1679 		finis(TRUE, ExitStat);
1680 	}
1681 #endif /* QUEUE */
1682 
1683 # if SASL
1684 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1685 	{
1686 		/* give a syserr or just disable AUTH ? */
1687 		if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
1688 			syserr("!sasl_server_init failed! [%s]",
1689 			       sasl_errstring(i, NULL, NULL));
1690 	}
1691 # endif /* SASL */
1692 
1693 	/*
1694 	**  If a daemon, wait for a request.
1695 	**	getrequests will always return in a child.
1696 	**	If we should also be processing the queue, start
1697 	**		doing it in background.
1698 	**	We check for any errors that might have happened
1699 	**		during startup.
1700 	*/
1701 
1702 	if (OpMode == MD_DAEMON || QueueIntvl != 0)
1703 	{
1704 		char dtype[200];
1705 
1706 		if (!run_in_foreground && !tTd(99, 100))
1707 		{
1708 			/* put us in background */
1709 			i = fork();
1710 			if (i < 0)
1711 				syserr("daemon: cannot fork");
1712 			if (i != 0)
1713 				finis(FALSE, EX_OK);
1714 
1715 			/* disconnect from our controlling tty */
1716 			disconnect(2, CurEnv);
1717 		}
1718 
1719 		dtype[0] = '\0';
1720 		if (OpMode == MD_DAEMON)
1721 			(void) strlcat(dtype, "+SMTP", sizeof dtype);
1722 		if (QueueIntvl != 0)
1723 		{
1724 			(void) strlcat(dtype, "+queueing@", sizeof dtype);
1725 			(void) strlcat(dtype, pintvl(QueueIntvl, TRUE),
1726 				       sizeof dtype);
1727 		}
1728 		if (tTd(0, 1))
1729 			(void) strlcat(dtype, "+debugging", sizeof dtype);
1730 
1731 		sm_syslog(LOG_INFO, NOQID,
1732 			  "starting daemon (%s): %s", Version, dtype + 1);
1733 #ifdef XLA
1734 		xla_create_file();
1735 #endif /* XLA */
1736 
1737 		/* save daemon type in a macro for possible PidFile use */
1738 		define(macid("{daemon_info}", NULL),
1739 		       newstr(dtype + 1), &BlankEnvelope);
1740 
1741 		/* save queue interval in a macro for possible PidFile use */
1742 		define(macid("{queue_interval}", NULL),
1743 		       newstr(pintvl(QueueIntvl, TRUE)), CurEnv);
1744 
1745 #if QUEUE
1746 		if (QueueIntvl != 0)
1747 		{
1748 			(void) runqueue(TRUE, FALSE);
1749 			if (OpMode != MD_DAEMON)
1750 			{
1751 				/* write the pid to file */
1752 				log_sendmail_pid(CurEnv);
1753 				(void) setsignal(SIGTERM, term_daemon);
1754 				for (;;)
1755 				{
1756 					(void) pause();
1757 					if (ShutdownRequest != NULL)
1758 						shutdown_daemon();
1759 					else if (DoQueueRun)
1760 						(void) runqueue(TRUE, FALSE);
1761 				}
1762 			}
1763 		}
1764 #endif /* QUEUE */
1765 		dropenvelope(CurEnv, TRUE);
1766 
1767 #if DAEMON
1768 # if STARTTLS
1769 		/* init TLS for server, ignore result for now */
1770 		(void) initsrvtls();
1771 # endif /* STARTTLS */
1772 		p_flags = getrequests(CurEnv);
1773 
1774 		/* drop privileges */
1775 		(void) drop_privileges(FALSE);
1776 
1777 		/* at this point we are in a child: reset state */
1778 		(void) newenvelope(CurEnv, CurEnv);
1779 
1780 		/*
1781 		**  Get authentication data
1782 		*/
1783 
1784 		authinfo = getauthinfo(fileno(InChannel), &forged);
1785 		define('_', authinfo, &BlankEnvelope);
1786 #endif /* DAEMON */
1787 	}
1788 
1789 	if (LogLevel > 9)
1790 	{
1791 		/* log connection information */
1792 		sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo);
1793 	}
1794 
1795 #if SMTP
1796 	/*
1797 	**  If running SMTP protocol, start collecting and executing
1798 	**  commands.  This will never return.
1799 	*/
1800 
1801 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1802 	{
1803 		char pbuf[20];
1804 
1805 		/*
1806 		**  Save some macros for check_* rulesets.
1807 		*/
1808 
1809 		if (forged)
1810 		{
1811 			char ipbuf[103];
1812 
1813 			(void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
1814 					anynet_ntoa(&RealHostAddr));
1815 			define(macid("{client_name}", NULL),
1816 			       newstr(ipbuf), &BlankEnvelope);
1817 			define(macid("{client_resolve}", NULL),
1818 			       "FORGED", &BlankEnvelope);
1819 		}
1820 		else
1821 			define(macid("{client_name}", NULL), RealHostName,
1822 			       &BlankEnvelope);
1823 		define(macid("{client_addr}", NULL),
1824 		       newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
1825 		(void)sm_getla(&BlankEnvelope);
1826 
1827 		switch(RealHostAddr.sa.sa_family)
1828 		{
1829 # if NETINET
1830 		  case AF_INET:
1831 			(void) snprintf(pbuf, sizeof pbuf, "%d",
1832 					RealHostAddr.sin.sin_port);
1833 			break;
1834 # endif /* NETINET */
1835 # if NETINET6
1836 		  case AF_INET6:
1837 			(void) snprintf(pbuf, sizeof pbuf, "%d",
1838 					RealHostAddr.sin6.sin6_port);
1839 			break;
1840 # endif /* NETINET6 */
1841 		  default:
1842 			(void) snprintf(pbuf, sizeof pbuf, "0");
1843 			break;
1844 		}
1845 		define(macid("{client_port}", NULL),
1846 		       newstr(pbuf), &BlankEnvelope);
1847 
1848 		if (OpMode == MD_DAEMON)
1849 		{
1850 			/* validate the connection */
1851 			HoldErrs = TRUE;
1852 			nullserver = validate_connection(&RealHostAddr,
1853 							 RealHostName, CurEnv);
1854 			HoldErrs = FALSE;
1855 		}
1856 		else if (p_flags == NULL)
1857 		{
1858 			p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
1859 			clrbitmap(p_flags);
1860 		}
1861 # if STARTTLS
1862 		if (OpMode == MD_SMTP)
1863 			(void) initsrvtls();
1864 # endif /* STARTTLS */
1865 
1866 
1867 		smtp(nullserver, *p_flags, CurEnv);
1868 	}
1869 #endif /* SMTP */
1870 
1871 	clearenvelope(CurEnv, FALSE);
1872 	if (OpMode == MD_VERIFY)
1873 	{
1874 		set_delivery_mode(SM_VERIFY, CurEnv);
1875 		PostMasterCopy = NULL;
1876 	}
1877 	else
1878 	{
1879 		/* interactive -- all errors are global */
1880 		CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
1881 	}
1882 
1883 	/*
1884 	**  Do basic system initialization and set the sender
1885 	*/
1886 
1887 	initsys(CurEnv);
1888 	define(macid("{ntries}", NULL), "0", CurEnv);
1889 	setsender(from, CurEnv, NULL, '\0', FALSE);
1890 	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
1891 	    (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) ||
1892 	     strcmp(CurEnv->e_from.q_user, RealUserName) != 0))
1893 	{
1894 		auth_warning(CurEnv, "%s set sender to %s using -%c",
1895 			RealUserName, from, warn_f_flag);
1896 #if SASL
1897 		auth = FALSE;
1898 #endif /* SASL */
1899 	}
1900 	if (auth)
1901 	{
1902 		char *fv;
1903 
1904 		/* set the initial sender for AUTH= to $f@$j */
1905 		fv = macvalue('f', CurEnv);
1906 		if (fv == NULL || *fv == '\0')
1907 			CurEnv->e_auth_param = NULL;
1908 		else
1909 		{
1910 			if (strchr(fv, '@') == NULL)
1911 			{
1912 				i = strlen(fv) + strlen(macvalue('j', CurEnv))
1913 				    + 2;
1914 				p = xalloc(i);
1915 				(void) snprintf(p, i, "%s@%s", fv,
1916 						macvalue('j', CurEnv));
1917 			}
1918 			else
1919 				p = newstr(fv);
1920 			CurEnv->e_auth_param = newstr(xtextify(p, "="));
1921 		}
1922 	}
1923 	if (macvalue('s', CurEnv) == NULL)
1924 		define('s', RealHostName, CurEnv);
1925 
1926 	if (*av == NULL && !GrabTo)
1927 	{
1928 		CurEnv->e_to = NULL;
1929 		CurEnv->e_flags |= EF_GLOBALERRS;
1930 		HoldErrs = FALSE;
1931 		SuperSafe = FALSE;
1932 		usrerr("Recipient names must be specified");
1933 
1934 		/* collect body for UUCP return */
1935 		if (OpMode != MD_VERIFY)
1936 			collect(InChannel, FALSE, NULL, CurEnv);
1937 		finis(TRUE, EX_USAGE);
1938 	}
1939 
1940 	/*
1941 	**  Scan argv and deliver the message to everyone.
1942 	*/
1943 
1944 	sendtoargv(av, CurEnv);
1945 
1946 	/* if we have had errors sofar, arrange a meaningful exit stat */
1947 	if (Errors > 0 && ExitStat == EX_OK)
1948 		ExitStat = EX_USAGE;
1949 
1950 #if _FFR_FIX_DASHT
1951 	/*
1952 	**  If using -t, force not sending to argv recipients, even
1953 	**  if they are mentioned in the headers.
1954 	*/
1955 
1956 	if (GrabTo)
1957 	{
1958 		ADDRESS *q;
1959 
1960 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
1961 			q->q_state = QS_REMOVED;
1962 	}
1963 #endif /* _FFR_FIX_DASHT */
1964 
1965 	/*
1966 	**  Read the input mail.
1967 	*/
1968 
1969 	CurEnv->e_to = NULL;
1970 	if (OpMode != MD_VERIFY || GrabTo)
1971 	{
1972 		int savederrors = Errors;
1973 		long savedflags = CurEnv->e_flags & EF_FATALERRS;
1974 
1975 		CurEnv->e_flags |= EF_GLOBALERRS;
1976 		CurEnv->e_flags &= ~EF_FATALERRS;
1977 		Errors = 0;
1978 		buffer_errors();
1979 		collect(InChannel, FALSE, NULL, CurEnv);
1980 
1981 		/* header checks failed */
1982 		if (Errors > 0)
1983 		{
1984 			/* Log who the mail would have gone to */
1985 			if (LogLevel > 8 && CurEnv->e_message != NULL &&
1986 			    !GrabTo)
1987 			{
1988 				ADDRESS *a;
1989 
1990 				for (a = CurEnv->e_sendqueue;
1991 				     a != NULL;
1992 				     a = a->q_next)
1993 				{
1994 					if (!QS_IS_UNDELIVERED(a->q_state))
1995 						continue;
1996 
1997 					CurEnv->e_to = a->q_paddr;
1998 					logdelivery(NULL, NULL, NULL,
1999 						    CurEnv->e_message,
2000 						    NULL, (time_t) 0, CurEnv);
2001 				}
2002 				CurEnv->e_to = NULL;
2003 			}
2004 			flush_errors(TRUE);
2005 			finis(TRUE, ExitStat);
2006 			/* NOTREACHED */
2007 			return -1;
2008 		}
2009 
2010 		/* bail out if message too large */
2011 		if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
2012 		{
2013 			finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR);
2014 			/* NOTREACHED */
2015 			return -1;
2016 		}
2017 		Errors = savederrors;
2018 		CurEnv->e_flags |= savedflags;
2019 	}
2020 	errno = 0;
2021 
2022 	if (tTd(1, 1))
2023 		dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
2024 
2025 	/*
2026 	**  Actually send everything.
2027 	**	If verifying, just ack.
2028 	*/
2029 
2030 	CurEnv->e_from.q_state = QS_SENDER;
2031 	if (tTd(1, 5))
2032 	{
2033 		dprintf("main: QS_SENDER ");
2034 		printaddr(&CurEnv->e_from, FALSE);
2035 	}
2036 	CurEnv->e_to = NULL;
2037 	CurrentLA = sm_getla(CurEnv);
2038 	GrabTo = FALSE;
2039 #if NAMED_BIND
2040 	_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2041 	_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2042 #endif /* NAMED_BIND */
2043 	sendall(CurEnv, SM_DEFAULT);
2044 
2045 	/*
2046 	**  All done.
2047 	**	Don't send return error message if in VERIFY mode.
2048 	*/
2049 
2050 	finis(TRUE, ExitStat);
2051 	/* NOTREACHED */
2052 	return ExitStat;
2053 }
2054 /*
2055 **  QUIESCE -- signal handler for SIGPIPE
2056 **
2057 **	Parameters:
2058 **		sig -- incoming signal.
2059 **
2060 **	Returns:
2061 **		none.
2062 **
2063 **	Side Effects:
2064 **		Sets StopRequest which should cause the mailq/hoststatus
2065 **		display to stop.
2066 **
2067 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2068 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2069 **		DOING.
2070 */
2071 
2072 /* ARGSUSED */
2073 static SIGFUNC_DECL
2074 quiesce(sig)
2075 	int sig;
2076 {
2077 	int save_errno = errno;
2078 
2079 	FIX_SYSV_SIGNAL(sig, quiesce);
2080 	StopRequest = TRUE;
2081 	errno = save_errno;
2082 	return SIGFUNC_RETURN;
2083 }
2084 /*
2085 **  STOP_SENDMAIL -- Stop the running program
2086 **
2087 **	Parameters:
2088 **		none.
2089 **
2090 **	Returns:
2091 **		none.
2092 **
2093 **	Side Effects:
2094 **		exits.
2095 */
2096 
2097 void
2098 stop_sendmail()
2099 {
2100 	/* reset uid for process accounting */
2101 	endpwent();
2102 	(void) setuid(RealUid);
2103 	exit(EX_OK);
2104 }
2105 
2106 /*
2107 **  INTINDEBUG -- signal handler for SIGINT in -bt mode
2108 **
2109 **	Parameters:
2110 **		sig -- incoming signal.
2111 **
2112 **	Returns:
2113 **		none.
2114 **
2115 **	Side Effects:
2116 **		longjmps back to test mode loop.
2117 **
2118 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2119 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2120 **		DOING.
2121 **
2122 **	XXX: More work is needed for this signal handler.
2123 */
2124 
2125 /* ARGSUSED */
2126 static SIGFUNC_DECL
2127 intindebug(sig)
2128 	int sig;
2129 {
2130 	int save_errno = errno;
2131 
2132 	FIX_SYSV_SIGNAL(sig, intindebug);
2133 	errno = save_errno;
2134 	CHECK_CRITICAL(sig);
2135 
2136 	errno = save_errno;
2137 	longjmp(TopFrame, 1);
2138 	return SIGFUNC_RETURN;
2139 }
2140 /*
2141 **  FINIS -- Clean up and exit.
2142 **
2143 **	Parameters:
2144 **		drop -- whether or not to drop CurEnv envelope
2145 **		exitstat -- exit status to use for exit() call
2146 **
2147 **	Returns:
2148 **		never
2149 **
2150 **	Side Effects:
2151 **		exits sendmail
2152 */
2153 
2154 void
2155 finis(drop, exitstat)
2156 	bool drop;
2157 	volatile int exitstat;
2158 {
2159 	/* Still want to process new timeouts added below */
2160 	clear_events();
2161 	(void) releasesignal(SIGALRM);
2162 
2163 	if (tTd(2, 1))
2164 	{
2165 		dprintf("\n====finis: stat %d e_id=%s e_flags=",
2166 			exitstat,
2167 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
2168 		printenvflags(CurEnv);
2169 	}
2170 	if (tTd(2, 9))
2171 		printopenfds(FALSE);
2172 
2173 	/* if we fail in finis(), just exit */
2174 	if (setjmp(TopFrame) != 0)
2175 	{
2176 		/* failed -- just give it up */
2177 		goto forceexit;
2178 	}
2179 
2180 	/* clean up temp files */
2181 	CurEnv->e_to = NULL;
2182 	if (drop)
2183 	{
2184 		if (CurEnv->e_id != NULL)
2185 			dropenvelope(CurEnv, TRUE);
2186 		else
2187 			poststats(StatFile);
2188 	}
2189 
2190 	/* flush any cached connections */
2191 	mci_flush(TRUE, NULL);
2192 
2193 	/* close maps belonging to this pid */
2194 	closemaps();
2195 
2196 #if USERDB
2197 	/* close UserDatabase */
2198 	_udbx_close();
2199 #endif /* USERDB */
2200 
2201 #ifdef XLA
2202 	/* clean up extended load average stuff */
2203 	xla_all_end();
2204 #endif /* XLA */
2205 
2206 	/* and exit */
2207   forceexit:
2208 	if (LogLevel > 78)
2209 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
2210 			  "finis, pid=%d",
2211 			  (int) getpid());
2212 	if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
2213 		exitstat = EX_OK;
2214 
2215 	sync_queue_time();
2216 
2217 	/* reset uid for process accounting */
2218 	endpwent();
2219 	(void) setuid(RealUid);
2220 	exit(exitstat);
2221 }
2222 /*
2223 **  TERM_DEAMON -- SIGTERM handler for the daemon
2224 **
2225 **	Parameters:
2226 **		sig -- signal number.
2227 **
2228 **	Returns:
2229 **		none.
2230 **
2231 **	Side Effects:
2232 **		Sets ShutdownRequest which will hopefully trigger
2233 **		the daemon to exit.
2234 **
2235 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2236 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2237 **		DOING.
2238 */
2239 
2240 /* ARGSUSED */
2241 static SIGFUNC_DECL
2242 term_daemon(sig)
2243 	int sig;
2244 {
2245 	int save_errno = errno;
2246 
2247 	FIX_SYSV_SIGNAL(sig, term_daemon);
2248 	ShutdownRequest = "signal";
2249 	errno = save_errno;
2250 	return SIGFUNC_RETURN;
2251 }
2252 /*
2253 **  SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
2254 **
2255 **	Parameters:
2256 **		none.
2257 **
2258 **	Returns:
2259 **		none.
2260 **
2261 **	Side Effects:
2262 **		closes control socket, exits.
2263 */
2264 
2265 void
2266 shutdown_daemon()
2267 {
2268 	char *reason;
2269 
2270 	allsignals(TRUE);
2271 
2272 	reason = ShutdownRequest;
2273 	ShutdownRequest = NULL;
2274 	PendingSignal = 0;
2275 
2276 	if (LogLevel > 79)
2277 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)",
2278 			  reason == NULL ? "implicit call" : reason);
2279 
2280 	FileName = NULL;
2281 	closecontrolsocket(TRUE);
2282 #ifdef XLA
2283 	xla_all_end();
2284 #endif /* XLA */
2285 
2286 	finis(FALSE, EX_OK);
2287 }
2288 /*
2289 **  INTSIG -- clean up on interrupt
2290 **
2291 **	This just arranges to exit.  It pessimizes in that it
2292 **	may resend a message.
2293 **
2294 **	Parameters:
2295 **		none.
2296 **
2297 **	Returns:
2298 **		none.
2299 **
2300 **	Side Effects:
2301 **		Unlocks the current job.
2302 **
2303 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2304 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2305 **		DOING.
2306 **
2307 **		XXX: More work is needed for this signal handler.
2308 */
2309 
2310 /* ARGSUSED */
2311 SIGFUNC_DECL
2312 intsig(sig)
2313 	int sig;
2314 {
2315 	bool drop = FALSE;
2316 	int save_errno = errno;
2317 
2318 	FIX_SYSV_SIGNAL(sig, intsig);
2319 	errno = save_errno;
2320 	CHECK_CRITICAL(sig);
2321 	allsignals(TRUE);
2322 	if (sig != 0 && LogLevel > 79)
2323 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
2324 	FileName = NULL;
2325 
2326 	/* Clean-up on aborted stdin message submission */
2327 	if (CurEnv->e_id != NULL &&
2328 	    (OpMode == MD_SMTP ||
2329 	     OpMode == MD_DELIVER ||
2330 	     OpMode == MD_ARPAFTP))
2331 	{
2332 		register ADDRESS *q;
2333 
2334 		/* don't return an error indication */
2335 		CurEnv->e_to = NULL;
2336 		CurEnv->e_flags &= ~EF_FATALERRS;
2337 		CurEnv->e_flags |= EF_CLRQUEUE;
2338 
2339 		/*
2340 		**  Spin through the addresses and
2341 		**  mark them dead to prevent bounces
2342 		*/
2343 
2344 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
2345 			q->q_state = QS_DONTSEND;
2346 
2347 		/* and don't try to deliver the partial message either */
2348 		if (InChild)
2349 			ExitStat = EX_QUIT;
2350 
2351 		drop = TRUE;
2352 	}
2353 	else if (OpMode != MD_TEST)
2354 		unlockqueue(CurEnv);
2355 
2356 	finis(drop, EX_OK);
2357 }
2358 /*
2359 **  INITMACROS -- initialize the macro system
2360 **
2361 **	This just involves defining some macros that are actually
2362 **	used internally as metasymbols to be themselves.
2363 **
2364 **	Parameters:
2365 **		none.
2366 **
2367 **	Returns:
2368 **		none.
2369 **
2370 **	Side Effects:
2371 **		initializes several macros to be themselves.
2372 */
2373 
2374 struct metamac	MetaMacros[] =
2375 {
2376 	/* LHS pattern matching characters */
2377 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
2378 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
2379 
2380 	/* these are RHS metasymbols */
2381 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
2382 	{ '>', CALLSUBR },
2383 
2384 	/* the conditional operations */
2385 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
2386 
2387 	/* the hostname lookup characters */
2388 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
2389 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
2390 
2391 	/* miscellaneous control characters */
2392 	{ '&', MACRODEXPAND },
2393 
2394 	{ '\0', '\0' }
2395 };
2396 
2397 #define MACBINDING(name, mid) \
2398 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
2399 		MacroName[mid] = name;
2400 
2401 void
2402 initmacros(e)
2403 	register ENVELOPE *e;
2404 {
2405 	register struct metamac *m;
2406 	register int c;
2407 	char buf[5];
2408 	extern char *MacroName[MAXMACROID + 1];
2409 
2410 	for (m = MetaMacros; m->metaname != '\0'; m++)
2411 	{
2412 		buf[0] = m->metaval;
2413 		buf[1] = '\0';
2414 		define(m->metaname, newstr(buf), e);
2415 	}
2416 	buf[0] = MATCHREPL;
2417 	buf[2] = '\0';
2418 	for (c = '0'; c <= '9'; c++)
2419 	{
2420 		buf[1] = c;
2421 		define(c, newstr(buf), e);
2422 	}
2423 
2424 	/* set defaults for some macros sendmail will use later */
2425 	define('n', "MAILER-DAEMON", e);
2426 
2427 	/* set up external names for some internal macros */
2428 	MACBINDING("opMode", MID_OPMODE);
2429 	/*XXX should probably add equivalents for all short macros here XXX*/
2430 }
2431 /*
2432 **  DISCONNECT -- remove our connection with any foreground process
2433 **
2434 **	Parameters:
2435 **		droplev -- how "deeply" we should drop the line.
2436 **			0 -- ignore signals, mail back errors, make sure
2437 **			     output goes to stdout.
2438 **			1 -- also, make stdout go to /dev/null.
2439 **			2 -- also, disconnect from controlling terminal
2440 **			     (only for daemon mode).
2441 **		e -- the current envelope.
2442 **
2443 **	Returns:
2444 **		none
2445 **
2446 **	Side Effects:
2447 **		Trys to insure that we are immune to vagaries of
2448 **		the controlling tty.
2449 */
2450 
2451 void
2452 disconnect(droplev, e)
2453 	int droplev;
2454 	register ENVELOPE *e;
2455 {
2456 	int fd;
2457 
2458 	if (tTd(52, 1))
2459 		dprintf("disconnect: In %d Out %d, e=%lx\n",
2460 			fileno(InChannel), fileno(OutChannel), (u_long) e);
2461 	if (tTd(52, 100))
2462 	{
2463 		dprintf("don't\n");
2464 		return;
2465 	}
2466 	if (LogLevel > 93)
2467 		sm_syslog(LOG_DEBUG, e->e_id,
2468 			  "disconnect level %d",
2469 			  droplev);
2470 
2471 	/* be sure we don't get nasty signals */
2472 	(void) setsignal(SIGINT, SIG_IGN);
2473 	(void) setsignal(SIGQUIT, SIG_IGN);
2474 
2475 	/* we can't communicate with our caller, so.... */
2476 	HoldErrs = TRUE;
2477 	CurEnv->e_errormode = EM_MAIL;
2478 	Verbose = 0;
2479 	DisConnected = TRUE;
2480 
2481 	/* all input from /dev/null */
2482 	if (InChannel != stdin)
2483 	{
2484 		(void) fclose(InChannel);
2485 		InChannel = stdin;
2486 	}
2487 	if (freopen("/dev/null", "r", stdin) == NULL)
2488 		sm_syslog(LOG_ERR, e->e_id,
2489 			  "disconnect: freopen(\"/dev/null\") failed: %s",
2490 			  errstring(errno));
2491 
2492 	/* output to the transcript */
2493 	if (OutChannel != stdout)
2494 	{
2495 		(void) fclose(OutChannel);
2496 		OutChannel = stdout;
2497 	}
2498 	if (droplev > 0)
2499 	{
2500 		fd = open("/dev/null", O_WRONLY, 0666);
2501 		if (fd == -1)
2502 			sm_syslog(LOG_ERR, e->e_id,
2503 				  "disconnect: open(\"/dev/null\") failed: %s",
2504 				  errstring(errno));
2505 		(void) fflush(stdout);
2506 		(void) dup2(fd, STDOUT_FILENO);
2507 		(void) dup2(fd, STDERR_FILENO);
2508 		(void) close(fd);
2509 	}
2510 
2511 	/* drop our controlling TTY completely if possible */
2512 	if (droplev > 1)
2513 	{
2514 		(void) setsid();
2515 		errno = 0;
2516 	}
2517 
2518 #if XDEBUG
2519 	checkfd012("disconnect");
2520 #endif /* XDEBUG */
2521 
2522 	if (LogLevel > 71)
2523 		sm_syslog(LOG_DEBUG, e->e_id,
2524 			  "in background, pid=%d",
2525 			  (int) getpid());
2526 
2527 	errno = 0;
2528 }
2529 
2530 static void
2531 obsolete(argv)
2532 	char *argv[];
2533 {
2534 	register char *ap;
2535 	register char *op;
2536 
2537 	while ((ap = *++argv) != NULL)
2538 	{
2539 		/* Return if "--" or not an option of any form. */
2540 		if (ap[0] != '-' || ap[1] == '-')
2541 			return;
2542 
2543 		/* skip over options that do have a value */
2544 		op = strchr(OPTIONS, ap[1]);
2545 		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
2546 		    ap[1] != 'd' &&
2547 #if defined(sony_news)
2548 		    ap[1] != 'E' && ap[1] != 'J' &&
2549 #endif /* defined(sony_news) */
2550 		    argv[1] != NULL && argv[1][0] != '-')
2551 		{
2552 			argv++;
2553 			continue;
2554 		}
2555 
2556 		/* If -C doesn't have an argument, use sendmail.cf. */
2557 #define	__DEFPATH	"sendmail.cf"
2558 		if (ap[1] == 'C' && ap[2] == '\0')
2559 		{
2560 			*argv = xalloc(sizeof(__DEFPATH) + 2);
2561 			(void) snprintf(argv[0], sizeof(__DEFPATH) + 2, "-C%s",
2562 					__DEFPATH);
2563 		}
2564 
2565 		/* If -q doesn't have an argument, run it once. */
2566 		if (ap[1] == 'q' && ap[2] == '\0')
2567 			*argv = "-q0";
2568 
2569 		/* if -d doesn't have an argument, use 0-99.1 */
2570 		if (ap[1] == 'd' && ap[2] == '\0')
2571 			*argv = "-d0-99.1";
2572 
2573 #if defined(sony_news)
2574 		/* if -E doesn't have an argument, use -EC */
2575 		if (ap[1] == 'E' && ap[2] == '\0')
2576 			*argv = "-EC";
2577 
2578 		/* if -J doesn't have an argument, use -JJ */
2579 		if (ap[1] == 'J' && ap[2] == '\0')
2580 			*argv = "-JJ";
2581 #endif /* defined(sony_news) */
2582 	}
2583 }
2584 /*
2585 **  AUTH_WARNING -- specify authorization warning
2586 **
2587 **	Parameters:
2588 **		e -- the current envelope.
2589 **		msg -- the text of the message.
2590 **		args -- arguments to the message.
2591 **
2592 **	Returns:
2593 **		none.
2594 */
2595 
2596 void
2597 #ifdef __STDC__
2598 auth_warning(register ENVELOPE *e, const char *msg, ...)
2599 #else /* __STDC__ */
2600 auth_warning(e, msg, va_alist)
2601 	register ENVELOPE *e;
2602 	const char *msg;
2603 	va_dcl
2604 #endif /* __STDC__ */
2605 {
2606 	char buf[MAXLINE];
2607 	VA_LOCAL_DECL
2608 
2609 	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
2610 	{
2611 		register char *p;
2612 		static char hostbuf[48];
2613 
2614 		if (hostbuf[0] == '\0')
2615 		{
2616 			struct hostent *hp;
2617 
2618 			hp = myhostname(hostbuf, sizeof hostbuf);
2619 #if _FFR_FREEHOSTENT && NETINET6
2620 			if (hp != NULL)
2621 			{
2622 				freehostent(hp);
2623 				hp = NULL;
2624 			}
2625 #endif /* _FFR_FREEHOSTENT && NETINET6 */
2626 		}
2627 
2628 		(void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
2629 		p = &buf[strlen(buf)];
2630 		VA_START(msg);
2631 		vsnprintf(p, SPACELEFT(buf, p), msg, ap);
2632 		VA_END;
2633 		addheader("X-Authentication-Warning", buf, 0, &e->e_header);
2634 		if (LogLevel > 3)
2635 			sm_syslog(LOG_INFO, e->e_id,
2636 				  "Authentication-Warning: %.400s",
2637 				  buf);
2638 	}
2639 }
2640 /*
2641 **  GETEXTENV -- get from external environment
2642 **
2643 **	Parameters:
2644 **		envar -- the name of the variable to retrieve
2645 **
2646 **	Returns:
2647 **		The value, if any.
2648 */
2649 
2650 char *
2651 getextenv(envar)
2652 	const char *envar;
2653 {
2654 	char **envp;
2655 	int l;
2656 
2657 	l = strlen(envar);
2658 	for (envp = ExternalEnviron; *envp != NULL; envp++)
2659 	{
2660 		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
2661 			return &(*envp)[l + 1];
2662 	}
2663 	return NULL;
2664 }
2665 /*
2666 **  SETUSERENV -- set an environment in the propogated environment
2667 **
2668 **	Parameters:
2669 **		envar -- the name of the environment variable.
2670 **		value -- the value to which it should be set.  If
2671 **			null, this is extracted from the incoming
2672 **			environment.  If that is not set, the call
2673 **			to setuserenv is ignored.
2674 **
2675 **	Returns:
2676 **		none.
2677 */
2678 
2679 void
2680 setuserenv(envar, value)
2681 	const char *envar;
2682 	const char *value;
2683 {
2684 	int i, l;
2685 	char **evp = UserEnviron;
2686 	char *p;
2687 
2688 	if (value == NULL)
2689 	{
2690 		value = getextenv(envar);
2691 		if (value == NULL)
2692 			return;
2693 	}
2694 
2695 	i = strlen(envar) + 1;
2696 	l = strlen(value) + i + 1;
2697 	p = (char *) xalloc(l);
2698 	(void) snprintf(p, l, "%s=%s", envar, value);
2699 
2700 	while (*evp != NULL && strncmp(*evp, p, i) != 0)
2701 		evp++;
2702 	if (*evp != NULL)
2703 	{
2704 		*evp++ = p;
2705 	}
2706 	else if (evp < &UserEnviron[MAXUSERENVIRON])
2707 	{
2708 		*evp++ = p;
2709 		*evp = NULL;
2710 	}
2711 
2712 	/* make sure it is in our environment as well */
2713 	if (putenv(p) < 0)
2714 		syserr("setuserenv: putenv(%s) failed", p);
2715 }
2716 /*
2717 **  DUMPSTATE -- dump state
2718 **
2719 **	For debugging.
2720 */
2721 
2722 void
2723 dumpstate(when)
2724 	char *when;
2725 {
2726 	register char *j = macvalue('j', CurEnv);
2727 	int rs;
2728 	extern int NextMacroId;
2729 
2730 	sm_syslog(LOG_DEBUG, CurEnv->e_id,
2731 		  "--- dumping state on %s: $j = %s ---",
2732 		  when,
2733 		  j == NULL ? "<NULL>" : j);
2734 	if (j != NULL)
2735 	{
2736 		if (!wordinclass(j, 'w'))
2737 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
2738 				  "*** $j not in $=w ***");
2739 	}
2740 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
2741 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)\n",
2742 		  NextMacroId, MAXMACROID);
2743 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
2744 	printopenfds(TRUE);
2745 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
2746 	mci_dump_all(TRUE);
2747 	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
2748 	if (rs > 0)
2749 	{
2750 		int status;
2751 		register char **pvp;
2752 		char *pv[MAXATOM + 1];
2753 
2754 		pv[0] = NULL;
2755 		status = rewrite(pv, rs, 0, CurEnv);
2756 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
2757 			  "--- ruleset debug_dumpstate returns stat %d, pv: ---",
2758 			  status);
2759 		for (pvp = pv; *pvp != NULL; pvp++)
2760 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
2761 	}
2762 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
2763 }
2764 #ifdef SIGUSR1
2765 /*
2766 **  SIGUSR1 -- Signal a request to dump state.
2767 **
2768 **	Parameters:
2769 **		sig -- calling signal.
2770 **
2771 **	Returns:
2772 **		none.
2773 **
2774 **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2775 **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2776 **		DOING.
2777 **
2778 **		XXX: More work is needed for this signal handler.
2779 */
2780 
2781 /* ARGSUSED */
2782 static SIGFUNC_DECL
2783 sigusr1(sig)
2784 	int sig;
2785 {
2786 	int save_errno = errno;
2787 
2788 	FIX_SYSV_SIGNAL(sig, sigusr1);
2789 	errno = save_errno;
2790 	CHECK_CRITICAL(sig);
2791 	dumpstate("user signal");
2792 	errno = save_errno;
2793 	return SIGFUNC_RETURN;
2794 }
2795 # endif /* SIGUSR1 */
2796 /*
2797 **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
2798 **
2799 **	Parameters:
2800 **		to_real_uid -- if set, drop to the real uid instead
2801 **			of the RunAsUser.
2802 **
2803 **	Returns:
2804 **		EX_OSERR if the setuid failed.
2805 **		EX_OK otherwise.
2806 */
2807 
2808 int
2809 drop_privileges(to_real_uid)
2810 	bool to_real_uid;
2811 {
2812 	int rval = EX_OK;
2813 	GIDSET_T emptygidset[1];
2814 
2815 	if (tTd(47, 1))
2816 		dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
2817 			(int)to_real_uid, (int)RealUid,
2818 			(int)RealGid, (int)RunAsUid, (int)RunAsGid);
2819 
2820 	if (to_real_uid)
2821 	{
2822 		RunAsUserName = RealUserName;
2823 		RunAsUid = RealUid;
2824 		RunAsGid = RealGid;
2825 	}
2826 
2827 	/* make sure no one can grab open descriptors for secret files */
2828 	endpwent();
2829 
2830 	/* reset group permissions; these can be set later */
2831 	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
2832 	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
2833 	{
2834 		syserr("drop_privileges: setgroups(1, %d) failed",
2835 		       (int)emptygidset[0]);
2836 		rval = EX_OSERR;
2837 	}
2838 
2839 	/* reset primary group and user id */
2840 	if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
2841 	{
2842 		syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid);
2843 		rval = EX_OSERR;
2844 	}
2845 	if (to_real_uid || RunAsUid != 0)
2846 	{
2847 		uid_t euid = geteuid();
2848 
2849 		if (setuid(RunAsUid) < 0)
2850 		{
2851 			syserr("drop_privileges: setuid(%d) failed",
2852 			       (int)RunAsUid);
2853 			rval = EX_OSERR;
2854 		}
2855 		else if (RunAsUid != 0 && setuid(0) == 0)
2856 		{
2857 			/*
2858 			**  Believe it or not, the Linux capability model
2859 			**  allows a non-root process to override setuid()
2860 			**  on a process running as root and prevent that
2861 			**  process from dropping privileges.
2862 			*/
2863 
2864 			syserr("drop_privileges: setuid(0) succeeded (when it should not)");
2865 			rval = EX_OSERR;
2866 		}
2867 		else if (RunAsUid != euid && setuid(euid) == 0)
2868 		{
2869 			/*
2870 			**  Some operating systems will keep the saved-uid
2871 			**  if a non-root effective-uid calls setuid(real-uid)
2872 			**  making it possible to set it back again later.
2873 			*/
2874 
2875 			syserr("drop_privileges: Unable to drop non-root set-user-id privileges");
2876 			rval = EX_OSERR;
2877 		}
2878 	}
2879 	if (tTd(47, 5))
2880 	{
2881 		dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
2882 			(int)geteuid(), (int)getuid(),
2883 			(int)getegid(), (int)getgid());
2884 		dprintf("drop_privileges: RunAsUser = %d:%d\n",
2885 			(int)RunAsUid, (int)RunAsGid);
2886 		if (tTd(47, 10))
2887 			dprintf("drop_privileges: rval = %d\n", rval);
2888 	}
2889 	return rval;
2890 }
2891 /*
2892 **  FILL_FD -- make sure a file descriptor has been properly allocated
2893 **
2894 **	Used to make sure that stdin/out/err are allocated on startup
2895 **
2896 **	Parameters:
2897 **		fd -- the file descriptor to be filled.
2898 **		where -- a string used for logging.  If NULL, this is
2899 **			being called on startup, and logging should
2900 **			not be done.
2901 **
2902 **	Returns:
2903 **		none
2904 */
2905 
2906 void
2907 fill_fd(fd, where)
2908 	int fd;
2909 	char *where;
2910 {
2911 	int i;
2912 	struct stat stbuf;
2913 
2914 	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
2915 		return;
2916 
2917 	if (where != NULL)
2918 		syserr("fill_fd: %s: fd %d not open", where, fd);
2919 	else
2920 		MissingFds |= 1 << fd;
2921 	i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
2922 	if (i < 0)
2923 	{
2924 		syserr("!fill_fd: %s: cannot open /dev/null",
2925 			where == NULL ? "startup" : where);
2926 	}
2927 	if (fd != i)
2928 	{
2929 		(void) dup2(i, fd);
2930 		(void) close(i);
2931 	}
2932 }
2933 /*
2934 **  TESTMODELINE -- process a test mode input line
2935 **
2936 **	Parameters:
2937 **		line -- the input line.
2938 **		e -- the current environment.
2939 **	Syntax:
2940 **		#  a comment
2941 **		.X process X as a configuration line
2942 **		=X dump a configuration item (such as mailers)
2943 **		$X dump a macro or class
2944 **		/X try an activity
2945 **		X  normal process through rule set X
2946 */
2947 
2948 static void
2949 testmodeline(line, e)
2950 	char *line;
2951 	ENVELOPE *e;
2952 {
2953 	register char *p;
2954 	char *q;
2955 	auto char *delimptr;
2956 	int mid;
2957 	int i, rs;
2958 	STAB *map;
2959 	char **s;
2960 	struct rewrite *rw;
2961 	ADDRESS a;
2962 	static int tryflags = RF_COPYNONE;
2963 	char exbuf[MAXLINE];
2964 	extern u_char TokTypeNoC[];
2965 
2966 #if _FFR_ADDR_TYPE
2967 	define(macid("{addr_type}", NULL), "e r", e);
2968 #endif /* _FFR_ADDR_TYPE */
2969 
2970 	/* skip leading spaces */
2971 	while (*line == ' ')
2972 		line++;
2973 
2974 	switch (line[0])
2975 	{
2976 	  case '#':
2977 	  case '\0':
2978 		return;
2979 
2980 	  case '?':
2981 		help("-bt", e);
2982 		return;
2983 
2984 	  case '.':		/* config-style settings */
2985 		switch (line[1])
2986 		{
2987 		  case 'D':
2988 			mid = macid(&line[2], &delimptr);
2989 			if (mid == 0)
2990 				return;
2991 			translate_dollars(delimptr);
2992 			define(mid, newstr(delimptr), e);
2993 			break;
2994 
2995 		  case 'C':
2996 			if (line[2] == '\0')	/* not to call syserr() */
2997 				return;
2998 
2999 			mid = macid(&line[2], &delimptr);
3000 			if (mid == 0)
3001 				return;
3002 			translate_dollars(delimptr);
3003 			expand(delimptr, exbuf, sizeof exbuf, e);
3004 			p = exbuf;
3005 			while (*p != '\0')
3006 			{
3007 				register char *wd;
3008 				char delim;
3009 
3010 				while (*p != '\0' && isascii(*p) && isspace(*p))
3011 					p++;
3012 				wd = p;
3013 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3014 					p++;
3015 				delim = *p;
3016 				*p = '\0';
3017 				if (wd[0] != '\0')
3018 					setclass(mid, wd);
3019 				*p = delim;
3020 			}
3021 			break;
3022 
3023 		  case '\0':
3024 			printf("Usage: .[DC]macro value(s)\n");
3025 			break;
3026 
3027 		  default:
3028 			printf("Unknown \".\" command %s\n", line);
3029 			break;
3030 		}
3031 		return;
3032 
3033 	  case '=':		/* config-style settings */
3034 		switch (line[1])
3035 		{
3036 		  case 'S':		/* dump rule set */
3037 			rs = strtorwset(&line[2], NULL, ST_FIND);
3038 			if (rs < 0)
3039 			{
3040 				printf("Undefined ruleset %s\n", &line[2]);
3041 				return;
3042 			}
3043 			rw = RewriteRules[rs];
3044 			if (rw == NULL)
3045 				return;
3046 			do
3047 			{
3048 				(void) putchar('R');
3049 				s = rw->r_lhs;
3050 				while (*s != NULL)
3051 				{
3052 					xputs(*s++);
3053 					(void) putchar(' ');
3054 				}
3055 				(void) putchar('\t');
3056 				(void) putchar('\t');
3057 				s = rw->r_rhs;
3058 				while (*s != NULL)
3059 				{
3060 					xputs(*s++);
3061 					(void) putchar(' ');
3062 				}
3063 				(void) putchar('\n');
3064 			} while ((rw = rw->r_next) != NULL);
3065 			break;
3066 
3067 		  case 'M':
3068 			for (i = 0; i < MAXMAILERS; i++)
3069 			{
3070 				if (Mailer[i] != NULL)
3071 					printmailer(Mailer[i]);
3072 			}
3073 			break;
3074 
3075 		  case '\0':
3076 			printf("Usage: =Sruleset or =M\n");
3077 			break;
3078 
3079 		  default:
3080 			printf("Unknown \"=\" command %s\n", line);
3081 			break;
3082 		}
3083 		return;
3084 
3085 	  case '-':		/* set command-line-like opts */
3086 		switch (line[1])
3087 		{
3088 		  case 'd':
3089 			tTflag(&line[2]);
3090 			break;
3091 
3092 		  case '\0':
3093 			printf("Usage: -d{debug arguments}\n");
3094 			break;
3095 
3096 		  default:
3097 			printf("Unknown \"-\" command %s\n", line);
3098 			break;
3099 		}
3100 		return;
3101 
3102 	  case '$':
3103 		if (line[1] == '=')
3104 		{
3105 			mid = macid(&line[2], NULL);
3106 			if (mid != 0)
3107 				stabapply(dump_class, mid);
3108 			return;
3109 		}
3110 		mid = macid(&line[1], NULL);
3111 		if (mid == 0)
3112 			return;
3113 		p = macvalue(mid, e);
3114 		if (p == NULL)
3115 			printf("Undefined\n");
3116 		else
3117 		{
3118 			xputs(p);
3119 			printf("\n");
3120 		}
3121 		return;
3122 
3123 	  case '/':		/* miscellaneous commands */
3124 		p = &line[strlen(line)];
3125 		while (--p >= line && isascii(*p) && isspace(*p))
3126 			*p = '\0';
3127 		p = strpbrk(line, " \t");
3128 		if (p != NULL)
3129 		{
3130 			while (isascii(*p) && isspace(*p))
3131 				*p++ = '\0';
3132 		}
3133 		else
3134 			p = "";
3135 		if (line[1] == '\0')
3136 		{
3137 			printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
3138 			return;
3139 		}
3140 		if (strcasecmp(&line[1], "quit") == 0)
3141 		{
3142 			CurEnv->e_id = NULL;
3143 			finis(TRUE, ExitStat);
3144 		}
3145 		if (strcasecmp(&line[1], "mx") == 0)
3146 		{
3147 #if NAMED_BIND
3148 			/* look up MX records */
3149 			int nmx;
3150 			auto int rcode;
3151 			char *mxhosts[MAXMXHOSTS + 1];
3152 
3153 			if (*p == '\0')
3154 			{
3155 				printf("Usage: /mx address\n");
3156 				return;
3157 			}
3158 			nmx = getmxrr(p, mxhosts, NULL, FALSE, &rcode);
3159 			printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
3160 			for (i = 0; i < nmx; i++)
3161 				printf("\t%s\n", mxhosts[i]);
3162 #else /* NAMED_BIND */
3163 			printf("No MX code compiled in\n");
3164 #endif /* NAMED_BIND */
3165 		}
3166 		else if (strcasecmp(&line[1], "canon") == 0)
3167 		{
3168 			char host[MAXHOSTNAMELEN];
3169 
3170 			if (*p == '\0')
3171 			{
3172 				printf("Usage: /canon address\n");
3173 				return;
3174 			}
3175 			else if (strlcpy(host, p, sizeof host) >= sizeof host)
3176 			{
3177 				printf("Name too long\n");
3178 				return;
3179 			}
3180 			(void) getcanonname(host, sizeof host, HasWildcardMX);
3181 			printf("getcanonname(%s) returns %s\n", p, host);
3182 		}
3183 		else if (strcasecmp(&line[1], "map") == 0)
3184 		{
3185 			auto int rcode = EX_OK;
3186 			char *av[2];
3187 
3188 			if (*p == '\0')
3189 			{
3190 				printf("Usage: /map mapname key\n");
3191 				return;
3192 			}
3193 			for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
3194 				continue;
3195 			if (*q == '\0')
3196 			{
3197 				printf("No key specified\n");
3198 				return;
3199 			}
3200 			*q++ = '\0';
3201 			map = stab(p, ST_MAP, ST_FIND);
3202 			if (map == NULL)
3203 			{
3204 				printf("Map named \"%s\" not found\n", p);
3205 				return;
3206 			}
3207 			if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
3208 			    !openmap(&(map->s_map)))
3209 			{
3210 				printf("Map named \"%s\" not open\n", p);
3211 				return;
3212 			}
3213 			printf("map_lookup: %s (%s) ", p, q);
3214 			av[0] = q;
3215 			av[1] = NULL;
3216 			p = (*map->s_map.map_class->map_lookup)
3217 					(&map->s_map, q, av, &rcode);
3218 			if (p == NULL)
3219 				printf("no match (%d)\n", rcode);
3220 			else
3221 				printf("returns %s (%d)\n", p, rcode);
3222 		}
3223 		else if (strcasecmp(&line[1], "try") == 0)
3224 		{
3225 			MAILER *m;
3226 			STAB *st;
3227 			auto int rcode = EX_OK;
3228 
3229 			q = strpbrk(p, " \t");
3230 			if (q != NULL)
3231 			{
3232 				while (isascii(*q) && isspace(*q))
3233 					*q++ = '\0';
3234 			}
3235 			if (q == NULL || *q == '\0')
3236 			{
3237 				printf("Usage: /try mailer address\n");
3238 				return;
3239 			}
3240 			st = stab(p, ST_MAILER, ST_FIND);
3241 			if (st == NULL)
3242 			{
3243 				printf("Unknown mailer %s\n", p);
3244 				return;
3245 			}
3246 			m = st->s_mailer;
3247 			printf("Trying %s %s address %s for mailer %s\n",
3248 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
3249 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
3250 				q, p);
3251 			p = remotename(q, m, tryflags, &rcode, CurEnv);
3252 			printf("Rcode = %d, addr = %s\n",
3253 				rcode, p == NULL ? "<NULL>" : p);
3254 			e->e_to = NULL;
3255 		}
3256 		else if (strcasecmp(&line[1], "tryflags") == 0)
3257 		{
3258 			if (*p == '\0')
3259 			{
3260 				printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
3261 				return;
3262 			}
3263 			for (; *p != '\0'; p++)
3264 			{
3265 				switch (*p)
3266 				{
3267 				  case 'H':
3268 				  case 'h':
3269 					tryflags |= RF_HEADERADDR;
3270 					break;
3271 
3272 				  case 'E':
3273 				  case 'e':
3274 					tryflags &= ~RF_HEADERADDR;
3275 					break;
3276 
3277 				  case 'S':
3278 				  case 's':
3279 					tryflags |= RF_SENDERADDR;
3280 					break;
3281 
3282 				  case 'R':
3283 				  case 'r':
3284 					tryflags &= ~RF_SENDERADDR;
3285 					break;
3286 				}
3287 			}
3288 #if _FFR_ADDR_TYPE
3289 			exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
3290 			exbuf[1] = ' ';
3291 			exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
3292 			exbuf[3] = '\0';
3293 			define(macid("{addr_type}", NULL), newstr(exbuf), e);
3294 #endif /* _FFR_ADDR_TYPE */
3295 		}
3296 		else if (strcasecmp(&line[1], "parse") == 0)
3297 		{
3298 			if (*p == '\0')
3299 			{
3300 				printf("Usage: /parse address\n");
3301 				return;
3302 			}
3303 			q = crackaddr(p);
3304 			printf("Cracked address = ");
3305 			xputs(q);
3306 			printf("\nParsing %s %s address\n",
3307 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
3308 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
3309 			if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
3310 				printf("Cannot parse\n");
3311 			else if (a.q_host != NULL && a.q_host[0] != '\0')
3312 				printf("mailer %s, host %s, user %s\n",
3313 					a.q_mailer->m_name, a.q_host, a.q_user);
3314 			else
3315 				printf("mailer %s, user %s\n",
3316 					a.q_mailer->m_name, a.q_user);
3317 			e->e_to = NULL;
3318 		}
3319 		else
3320 		{
3321 			printf("Unknown \"/\" command %s\n", line);
3322 		}
3323 		return;
3324 	}
3325 
3326 	for (p = line; isascii(*p) && isspace(*p); p++)
3327 		continue;
3328 	q = p;
3329 	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3330 		p++;
3331 	if (*p == '\0')
3332 	{
3333 		printf("No address!\n");
3334 		return;
3335 	}
3336 	*p = '\0';
3337 	if (invalidaddr(p + 1, NULL))
3338 		return;
3339 	do
3340 	{
3341 		register char **pvp;
3342 		char pvpbuf[PSBUFSIZE];
3343 
3344 		pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
3345 			      &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL);
3346 		if (pvp == NULL)
3347 			continue;
3348 		p = q;
3349 		while (*p != '\0')
3350 		{
3351 			int status;
3352 
3353 			rs = strtorwset(p, NULL, ST_FIND);
3354 			if (rs < 0)
3355 			{
3356 				printf("Undefined ruleset %s\n", p);
3357 				break;
3358 			}
3359 			status = rewrite(pvp, rs, 0, e);
3360 			if (status != EX_OK)
3361 				printf("== Ruleset %s (%d) status %d\n",
3362 					p, rs, status);
3363 			while (*p != '\0' && *p++ != ',')
3364 				continue;
3365 		}
3366 	} while (*(p = delimptr) != '\0');
3367 }
3368 
3369 static void
3370 dump_class(s, id)
3371 	register STAB *s;
3372 	int id;
3373 {
3374 	if (s->s_type != ST_CLASS)
3375 		return;
3376 	if (bitnset(bitidx(id), s->s_class))
3377 		printf("%s\n", s->s_name);
3378 }
3379