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