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