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