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