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