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