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