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