ep = sm_malloc_x(strlen(p) + 1); cleanstrcpy(ep, p, MAXNAME);
i = strlen(p) + 1; ep = sm_malloc_x(i); cleanstrcpy(ep, p, i);
static char	*getextenv __P((const char *));static void	sm_printoptions __P((char **));static SIGFUNC_DECL	intindebug __P((int));static SIGFUNC_DECL	sighup __P((int));static SIGFUNC_DECL	sigpipe __P((int));static SIGFUNC_DECL	sigterm __P((int));#ifdef SIGUSR1static SIGFUNC_DECL	sigusr1 __P((int));#endif /* SIGUSR1 *//***  SENDMAIL -- Post mail to a set of destinations.****	This is the basic mail router.  All user mail programs should**	call this routine to actually deliver mail.  Sendmail in**	turn calls a bunch of mail servers that do the real work of**	delivering the mail.****	Sendmail is driven by settings read in from /etc/mail/sendmail.cf**	(read by readcf.c).****	Usage:**		/usr/lib/sendmail [flags] addr ...****		See the associated documentation for details.****	Authors:**		Eric Allman, UCB/INGRES (until 10/81).**			     Britton-Lee, Inc., purveyors of fine**				database computers (11/81 - 10/88).**			     International Computer Science Institute**				(11/88 - 9/89).**			     UCB/Mammoth Project (10/89 - 7/95).**			     InReference, Inc. (8/95 - 1/97).**			     Sendmail, Inc. (1/98 - present).**		The support of my employers is gratefully acknowledged.**			Few of them (Britton-Lee in particular) have had**			anything to gain from my involvement in this project.****		Gregory Neil Shapiro,**			Worcester Polytechnic Institute	(until 3/98).**			Sendmail, Inc. (3/98 - present).****		Claus Assmann,**			Sendmail, Inc. (12/98 - present).*/char		*FullName;	/* sender's full name */ENVELOPE	BlankEnvelope;	/* a "blank" envelope */static ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */ADDRESS		NullAddress =	/* a null address */		{ "", "", NULL, "" };char		*CommandLineArgs;	/* command line args for pid file */bool		Warn_Q_option = false;	/* warn about Q option use */static int	MissingFds = 0;	/* bit map of fds missing on startup */char		*Mbdb = "pw";	/* mailbox database defaults to /etc/passwd */#ifdef NGROUPS_MAXGIDSET_T	InitialGidSet[NGROUPS_MAX];#endif /* NGROUPS_MAX */#define MAXCONFIGLEVEL	10	/* highest config version level known */#if SASLstatic sasl_callback_t srvcallbacks[] ={	{	SASL_CB_VERIFYFILE,	&safesaslfile,	NULL	},	{	SASL_CB_PROXY_POLICY,	&proxy_policy,	NULL	},	{	SASL_CB_LIST_END,	NULL,		NULL	}};#endif /* SASL */unsigned int	SubmitMode;int		SyslogPrefixLen; /* estimated length of syslog prefix */#define PIDLEN		6	/* pid length for computing SyslogPrefixLen */#ifndef SL_FUDGE# define SL_FUDGE	10	/* fudge offset for SyslogPrefixLen */#endif /* ! SL_FUDGE */#define SLDLL		8	/* est. length of default syslog label *//* Some options are dangerous to allow users to use in non-submit mode */#define CHECK_AGAINST_OPMODE(cmd)					\{									\	if (extraprivs &&						\	    OpMode != MD_DELIVER && OpMode != MD_SMTP &&		\	    OpMode != MD_ARPAFTP &&					\	    OpMode != MD_VERIFY && OpMode != MD_TEST)			\	{								\		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\				     "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \		       (cmd));						\		break;							\	}								\	if (extraprivs && queuerun)					\	{								\		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,		\				     "WARNING: Ignoring submission mode -%c option with -q\n", \		       (cmd));						\		break;							\	}								\}intmain(argc, argv, envp)	int argc;	char **argv;	char **envp;{	register char *p;	char **av;	extern char Version[];	char *ep, *from;	STAB *st;	register int i;	int j;	int dp;	int fill_errno;	int qgrp = NOQGRP;		/* queue group to process */	bool safecf = true;	BITMAP256 *p_flags = NULL;	/* daemon flags */	bool warn_C_flag = false;	bool auth = true;		/* whether to set e_auth_param */	char warn_f_flag = '\0';	bool run_in_foreground = false;	/* -bD mode */	bool queuerun = false, debug = false;	struct passwd *pw;	struct hostent *hp;	char *nullserver = NULL;	char *authinfo = NULL;	char *sysloglabel = NULL;	/* label for syslog */	char *conffile = NULL;		/* name of .cf file */	char *queuegroup = NULL;	/* queue group to process */#if _FFR_QUARANTINE	char *quarantining = NULL;	/* quarantine queue items? */#endif /* _FFR_QUARANTINE */	bool extraprivs;	bool forged, negate;	bool queuepersistent = false;	/* queue runner process runs forever */	bool foregroundqueue = false;	/* queue run in foreground */	bool save_val;			/* to save some bool var. */	int cftype;			/* which cf file to use? */	static time_t starttime = 0;	/* when was process started */	struct stat traf_st;		/* for TrafficLog FIFO check */	char buf[MAXLINE];	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */	static char rnamebuf[MAXNAME];	/* holds RealUserName */	char *emptyenviron[1];#if STARTTLS	bool tls_ok;#endif /* STARTTLS */	QUEUE_CHAR *new;	ENVELOPE *e;	extern int DtableSize;	extern int optind;	extern int opterr;	extern char *optarg;	extern char **environ;#if SASL	extern void sm_sasl_init __P((void));#endif /* SASL */#if USE_ENVIRON	envp = environ;#endif /* USE_ENVIRON */	/* turn off profiling */	SM_PROF(0);	/* install default exception handler */	sm_exc_newthread(fatal_error);	/* set the default in/out channel so errors reported to screen */	InChannel = smioin;	OutChannel = smioout;	/*	**  Check to see if we reentered.	**	This would normally happen if e_putheader or e_putbody	**	were NULL when invoked.	*/	if (starttime != 0)	{		syserr("main: reentered!");		abort();	}	starttime = curtime();	/* avoid null pointer dereferences */	TermEscape.te_rv_on = TermEscape.te_rv_off = "";	RealUid = getuid();	RealGid = getgid();	/* Check if sendmail is running with extra privs */	extraprivs = (RealUid != 0 &&		      (geteuid() != getuid() || getegid() != getgid()));	CurrentPid = getpid();	/* get whatever .cf file is right for the opmode */	cftype = SM_GET_RIGHT_CF;	/* in 4.4BSD, the table can be huge; impose a reasonable limit */	DtableSize = getdtsize();	if (DtableSize > 256)		DtableSize = 256;	/*	**  Be sure we have enough file descriptors.	**	But also be sure that 0, 1, & 2 are open.	*/	/* reset errno and fill_errno; the latter is used way down below */	errno = fill_errno = 0;	fill_fd(STDIN_FILENO, NULL);	if (errno != 0)		fill_errno = errno;	fill_fd(STDOUT_FILENO, NULL);	if (errno != 0)		fill_errno = errno;	fill_fd(STDERR_FILENO, NULL);	if (errno != 0)		fill_errno = errno;	i = DtableSize;	while (--i > 0)	{		if (i != STDIN_FILENO && i != STDOUT_FILENO &&		    i != STDERR_FILENO)			(void) close(i);	}	errno = 0;#if LOG# ifndef SM_LOG_STR#  define SM_LOG_STR	"sendmail"# endif /* ! SM_LOG_STR */#  ifdef LOG_MAIL	openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);#  else /* LOG_MAIL */	openlog(SM_LOG_STR, LOG_PID);#  endif /* LOG_MAIL */#endif /* LOG */	/*	**  Seed the random number generator.	**  Used for queue file names, picking a queue directory, and	**  MX randomization.	*/	seed_random();	/* do machine-dependent initializations */	init_md(argc, argv);	SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;	/* reset status from syserr() calls for missing file descriptors */	Errors = 0;	ExitStat = EX_OK;	SubmitMode = SUBMIT_UNKNOWN;#if XDEBUG	checkfd012("after openlog");#endif /* XDEBUG */	tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1");#ifdef NGROUPS_MAX	/* save initial group set for future checks */	i = getgroups(NGROUPS_MAX, InitialGidSet);	if (i <= 0)	{		InitialGidSet[0] = (GID_T) -1;		i = 0;	}	while (i < NGROUPS_MAX)		InitialGidSet[i++] = InitialGidSet[0];#endif /* NGROUPS_MAX */	/* drop group id privileges (RunAsUser not yet set) */	dp = drop_privileges(false);	setstat(dp);#ifdef SIGUSR1	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */	if (!extraprivs)	{		/* arrange to dump state on user-1 signal */		(void) sm_signal(SIGUSR1, sigusr1);	}	else	{		/* ignore user-1 signal */		(void) sm_signal(SIGUSR1, SIG_IGN);	}#endif /* SIGUSR1 */	/* initialize for setproctitle */	initsetproctitle(argc, argv, envp);	/* Handle any non-getoptable constructions. */	obsolete(argv);	/*	**  Do a quick prescan of the argument list.	*/	/* find initial opMode */	OpMode = MD_DELIVER;	av = argv;	p = strrchr(*av, '/');	if (p++ == NULL)		p = *av;	if (strcmp(p, "newaliases") == 0)		OpMode = MD_INITALIAS;	else if (strcmp(p, "mailq") == 0)		OpMode = MD_PRINT;	else if (strcmp(p, "smtpd") == 0)		OpMode = MD_DAEMON;	else if (strcmp(p, "hoststat") == 0)		OpMode = MD_HOSTSTAT;	else if (strcmp(p, "purgestat") == 0)		OpMode = MD_PURGESTAT;#if _FFR_QUARANTINE# if defined(__osf__) || defined(_AIX3)#  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:xQ:"# endif /* defined(__osf__) || defined(_AIX3) */# if defined(sony_news)#  define OPTIONS	"A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"# endif /* defined(sony_news) */# ifndef OPTIONS#  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"# endif /* ! OPTIONS */#else /* _FFR_QUARANTINE */# if defined(__osf__) || defined(_AIX3)#  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:x"# endif /* defined(__osf__) || defined(_AIX3) */# if defined(sony_news)#  define OPTIONS	"A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:"# endif /* defined(sony_news) */# ifndef OPTIONS#  define OPTIONS	"A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:"# endif /* ! OPTIONS */#endif /* _FFR_QUARANTINE */	/* Set to 0 to allow -b; need to check optarg before using it! */	opterr = 0;	while ((j = getopt(argc, argv, OPTIONS)) != -1)	{		switch (j)		{		  case 'b':	/* operations mode */			j = (optarg == NULL) ? ' ' : *optarg;			switch (j)			{			  case MD_DAEMON:			  case MD_FGDAEMON:			  case MD_SMTP:			  case MD_INITALIAS:			  case MD_DELIVER:			  case MD_VERIFY:			  case MD_TEST:			  case MD_PRINT:			  case MD_PRINTNQE:			  case MD_HOSTSTAT:			  case MD_PURGESTAT:			  case MD_ARPAFTP:				OpMode = j;				break;			  case MD_FREEZE:				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,						     "Frozen configurations unsupported\n");				return EX_USAGE;			  default:				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,						     "Invalid operation mode %c\n",						     j);				return EX_USAGE;			}			break;		  case 'd':			debug = true;			tTflag(optarg);			(void) sm_io_setvbuf(smioout, SM_TIME_DEFAULT,					     (char *) NULL, SM_IO_NBF,					     SM_IO_BUFSIZ);			break;		  case 'G':	/* relay (gateway) submission */			SubmitMode = SUBMIT_MTA;			break;		  case 'L':			if (optarg == NULL)			{				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,						     "option requires an argument -- '%c'",						     (char) j);				return EX_USAGE;			}			j = SM_MIN(strlen(optarg), 24) + 1;			sysloglabel = xalloc(j);			(void) sm_strlcpy(sysloglabel, optarg, j);			SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +					  SL_FUDGE + j;			break;#if _FFR_QUARANTINE		  case 'Q':#endif /* _FFR_QUARANTINE */		  case 'q':			/* just check if it is there */			queuerun = true;			break;		}	}	opterr = 1;	/* Don't leak queue information via debug flags */	if (extraprivs && queuerun && debug)	{		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "WARNING: Can not use -d with -q.  Disabling debugging.\n");		sm_debug_setfile(NULL);		(void) memset(tTdvect, '\0', sizeof tTdvect);	}#if LOG	if (sysloglabel != NULL)	{		/* Sanitize the string */		for (p = sysloglabel; *p != '\0'; p++)		{			if (!isascii(*p) || !isprint(*p) || *p == '%')				*p = '*';		}		closelog();#  ifdef LOG_MAIL		openlog(sysloglabel, LOG_PID, LOG_MAIL);#  else /* LOG_MAIL */		openlog(sysloglabel, LOG_PID);#  endif /* LOG_MAIL */	}#endif /* LOG */	/* set up the blank envelope */	BlankEnvelope.e_puthdr = putheader;	BlankEnvelope.e_putbody = putbody;	BlankEnvelope.e_xfp = NULL;	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);	CurEnv = &BlankEnvelope;	STRUCTCOPY(NullAddress, MainEnvelope.e_from);	/*	**  Set default values for variables.	**	These cannot be in initialized data space.	*/	setdefaults(&BlankEnvelope);	initmacros(&BlankEnvelope);	/* reset macro */	set_op_mode(OpMode);	pw = sm_getpwuid(RealUid);	if (pw != NULL)		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);	else		(void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",				   (int) RealUid);	RealUserName = rnamebuf;	if (tTd(0, 101))	{		sm_dprintf("Version %s\n", Version);		finis(false, true, EX_OK);		/* NOTREACHED */	}	/*	**  if running non-set-user-ID binary as non-root, pretend	**  we are the RunAsUid	*/	if (RealUid != 0 && geteuid() == RealUid)	{		if (tTd(47, 1))			sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",				   (int) RealUid);		RunAsUid = RealUid;	}	else if (geteuid() != 0)		RunAsUid = geteuid();	EffGid = getegid();	if (RealUid != 0 && EffGid == RealGid)		RunAsGid = RealGid;	if (tTd(47, 5))	{		sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",			   (int) geteuid(), (int) getuid(),			   (int) getegid(), (int) getgid());		sm_dprintf("main: RunAsUser = %d:%d\n",			   (int) RunAsUid, (int) RunAsGid);	}	/* save command line arguments */	j = 0;	for (av = argv; *av != NULL; )		j += strlen(*av++) + 1;	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));	CommandLineArgs = xalloc(j);	p = CommandLineArgs;	for (av = argv, i = 0; *av != NULL; )	{		int h;		SaveArgv[i++] = newstr(*av);		if (av != argv)			*p++ = ' ';		(void) sm_strlcpy(p, *av++, j);		h = strlen(p);		p += h;		j -= h + 1;	}	SaveArgv[i] = NULL;	if (tTd(0, 1))	{		extern char *CompileOptions[];		sm_dprintf("Version %s\n Compiled with:", Version);		sm_printoptions(CompileOptions);	}	if (tTd(0, 10))	{		extern char *OsCompileOptions[];		sm_dprintf("    OS Defines:");		sm_printoptions(OsCompileOptions);#ifdef _PATH_UNIX		sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);#endif /* _PATH_UNIX */		sm_dprintf("     Conf file:\t%s (default for MSP)\n",			   getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,				     conffile));		sm_dprintf("     Conf file:\t%s (default for MTA)\n",			   getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,				     conffile));		sm_dprintf("      Pid file:\t%s (default)\n", PidFile);	}	if (tTd(0, 12))	{		extern char *SmCompileOptions[];		sm_dprintf(" libsm Defines:");		sm_printoptions(SmCompileOptions);	}	if (tTd(0, 13))	{		extern char *FFRCompileOptions[];		sm_dprintf("   FFR Defines:");		sm_printoptions(FFRCompileOptions);	}	/* clear sendmail's environment */	ExternalEnviron = environ;	emptyenviron[0] = NULL;	environ = emptyenviron;	/*	**  restore any original TZ setting until TimeZoneSpec has been	**  determined - or early log messages may get bogus time stamps	*/	if ((p = getextenv("TZ")) != NULL)	{		char *tz;		int tzlen;		/* XXX check for reasonable length? */		tzlen = strlen(p) + 4;		tz = xalloc(tzlen);		(void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);		/* XXX check return code? */		(void) putenv(tz);	}	/* prime the child environment */	setuserenv("AGENT", "sendmail");	(void) sm_signal(SIGPIPE, SIG_IGN);	OldUmask = umask(022);	FullName = getextenv("NAME");	if (FullName != NULL)		FullName = newstr(FullName);	/*	**  Initialize name server if it is going to be used.	*/#if NAMED_BIND	if (!bitset(RES_INIT, _res.options))		(void) res_init();	if (tTd(8, 8))		_res.options |= RES_DEBUG;	else		_res.options &= ~RES_DEBUG;# ifdef RES_NOALIASES	if (bitset(RES_NOALIASES, _res.options))		ResNoAliases = true;	_res.options |= RES_NOALIASES;# endif /* RES_NOALIASES */	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;#endif /* NAMED_BIND */	errno = 0;	from = NULL;	/* initialize some macros, etc. */	init_vendor_macros(&BlankEnvelope);	/* version */	macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);	/* hostname */	hp = myhostname(jbuf, sizeof jbuf);	if (jbuf[0] != '\0')	{		struct utsname utsname;		if (tTd(0, 4))			sm_dprintf("Canonical name: %s\n", jbuf);		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);		setclass('w', jbuf);		p = strchr(jbuf, '.');		if (p != NULL)		{			if (p[1] != '\0')			{				macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm',					  &p[1]);			}			while (p != NULL && strchr(&p[1], '.') != NULL)			{				*p = '\0';				if (tTd(0, 4))					sm_dprintf("\ta.k.a.: %s\n", jbuf);				setclass('w', jbuf);				*p++ = '.';				p = strchr(p, '.');			}		}		if (uname(&utsname) >= 0)			p = utsname.nodename;		else		{			if (tTd(0, 22))				sm_dprintf("uname failed (%s)\n",					   sm_errstring(errno));			makelower(jbuf);			p = jbuf;		}		if (tTd(0, 4))			sm_dprintf(" UUCP nodename: %s\n", p);		macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);		setclass('k', p);		setclass('w', p);	}	if (hp != NULL)	{		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)		{			if (tTd(0, 4))				sm_dprintf("\ta.k.a.: %s\n", *av);			setclass('w', *av);		}#if NETINET || NETINET6		for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)		{# if NETINET6			char *addr;			char buf6[INET6_ADDRSTRLEN];			struct in6_addr ia6;# endif /* NETINET6 */# if NETINET			struct in_addr ia;# endif /* NETINET */			char ipbuf[103];			ipbuf[0] = '\0';			switch (hp->h_addrtype)			{# if NETINET			  case AF_INET:				if (hp->h_length != INADDRSZ)					break;				memmove(&ia, hp->h_addr_list[i], INADDRSZ);				(void) sm_snprintf(ipbuf, sizeof ipbuf,						   "[%.100s]", inet_ntoa(ia));				break;# endif /* NETINET */# if NETINET6			  case AF_INET6:				if (hp->h_length != IN6ADDRSZ)					break;				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);				addr = anynet_ntop(&ia6, buf6, sizeof buf6);				if (addr != NULL)					(void) sm_snprintf(ipbuf, sizeof ipbuf,							   "[%.100s]", addr);				break;# endif /* NETINET6 */			}			if (ipbuf[0] == '\0')				break;			if (tTd(0, 4))				sm_dprintf("\ta.k.a.: %s\n", ipbuf);			setclass('w', ipbuf);		}#endif /* NETINET || NETINET6 */#if NETINET6		freehostent(hp);		hp = NULL;#endif /* NETINET6 */	}	/* current time */	macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));	/* current load average */	sm_getla();	QueueLimitRecipient = (QUEUE_CHAR *) NULL;	QueueLimitSender = (QUEUE_CHAR *) NULL;	QueueLimitId = (QUEUE_CHAR *) NULL;#if _FFR_QUARANTINE	QueueLimitQuarantine = (QUEUE_CHAR *) NULL;#endif /* _FFR_QUARANTINE */	/*	**  Crack argv.	*/	optind = 1;	while ((j = getopt(argc, argv, OPTIONS)) != -1)	{		switch (j)		{		  case 'b':	/* operations mode */			/* already done */			break;		  case 'A':	/* use Alternate sendmail/submit.cf */			cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF						  : SM_GET_SENDMAIL_CF;			break;		  case 'B':	/* body type */			CHECK_AGAINST_OPMODE(j);			BlankEnvelope.e_bodytype = newstr(optarg);			break;		  case 'C':	/* select configuration file (already done) */			if (RealUid != 0)				warn_C_flag = true;			conffile = newstr(optarg);			dp = drop_privileges(true);			setstat(dp);			safecf = false;			break;		  case 'd':	/* debugging */			/* already done */			break;		  case 'f':	/* from address */		  case 'r':	/* obsolete -f flag */			CHECK_AGAINST_OPMODE(j);			if (from != NULL)			{				usrerr("More than one \"from\" person");				ExitStat = EX_USAGE;				break;			}			if (optarg[0] == '\0')				from = newstr("<>");			else				from = newstr(denlstring(optarg, true, true));			if (strcmp(RealUserName, from) != 0)				warn_f_flag = j;			break;		  case 'F':	/* set full name */			CHECK_AGAINST_OPMODE(j);			FullName = newstr(optarg);			break;		  case 'G':	/* relay (gateway) submission */			/* already set */			CHECK_AGAINST_OPMODE(j);			break;		  case 'h':	/* hop count */			CHECK_AGAINST_OPMODE(j);			BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,								  10);			(void) sm_snprintf(buf, sizeof buf, "%d",					   BlankEnvelope.e_hopcount);			macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);			if (*ep)			{				usrerr("Bad hop count (%s)", optarg);				ExitStat = EX_USAGE;			}			break;		  case 'L':	/* program label */			/* already set */			break;		  case 'n':	/* don't alias */			CHECK_AGAINST_OPMODE(j);			NoAlias = true;			break;		  case 'N':	/* delivery status notifications */			CHECK_AGAINST_OPMODE(j);			DefaultNotify |= QHASNOTIFY;			macdefine(&BlankEnvelope.e_macro, A_TEMP,				macid("{dsn_notify}"), optarg);			if (sm_strcasecmp(optarg, "never") == 0)				break;			for (p = optarg; p != NULL; optarg = p)			{				p = strchr(p, ',');				if (p != NULL)					*p++ = '\0';				if (sm_strcasecmp(optarg, "success") == 0)					DefaultNotify |= QPINGONSUCCESS;				else if (sm_strcasecmp(optarg, "failure") == 0)					DefaultNotify |= QPINGONFAILURE;				else if (sm_strcasecmp(optarg, "delay") == 0)					DefaultNotify |= QPINGONDELAY;				else				{					usrerr("Invalid -N argument");					ExitStat = EX_USAGE;				}			}			break;		  case 'o':	/* set option */			setoption(*optarg, optarg + 1, false, true,				  &BlankEnvelope);			break;		  case 'O':	/* set option (long form) */			setoption(' ', optarg, false, true, &BlankEnvelope);			break;		  case 'p':	/* set protocol */			CHECK_AGAINST_OPMODE(j);			p = strchr(optarg, ':');			if (p != NULL)			{				*p++ = '\0';				if (*p != '\0')				{					ep = sm_malloc_x(strlen(p) + 1);					cleanstrcpy(ep, p, MAXNAME);					macdefine(&BlankEnvelope.e_macro,						  A_HEAP, 's', ep);				}			}			if (*optarg != '\0')			{				ep = sm_malloc_x(strlen(optarg) + 1);				cleanstrcpy(ep, optarg, MAXNAME);				macdefine(&BlankEnvelope.e_macro, A_HEAP,					  'r', ep);			}			break;#if _FFR_QUARANTINE		  case 'Q':	/* change quarantining on queued items */			/* sanity check */			if (OpMode != MD_DELIVER &&			    OpMode != MD_QUEUERUN)			{				usrerr("Can not use -Q with -b%c", OpMode);				ExitStat = EX_USAGE;				break;			}			if (OpMode == MD_DELIVER)				set_op_mode(MD_QUEUERUN);			FullName = NULL;			quarantining = newstr(optarg);			break;#endif /* _FFR_QUARANTINE */		  case 'q':	/* run queue files at intervals */			/* sanity check */			if (OpMode != MD_DELIVER &&			    OpMode != MD_DAEMON &&			    OpMode != MD_FGDAEMON &&			    OpMode != MD_PRINT &&			    OpMode != MD_PRINTNQE &&			    OpMode != MD_QUEUERUN)			{				usrerr("Can not use -q with -b%c", OpMode);				ExitStat = EX_USAGE;				break;			}			/* don't override -bd, -bD or -bp */			if (OpMode == MD_DELIVER)				set_op_mode(MD_QUEUERUN);			FullName = NULL;			negate = optarg[0] == '!';			if (negate)			{				/* negate meaning of pattern match */				optarg++; /* skip '!' for next switch */			}			switch (optarg[0])			{			  case 'G': /* Limit by queue group name */				if (negate)				{					usrerr("Can not use -q!G");					ExitStat = EX_USAGE;					break;				}				if (queuegroup != NULL)				{					usrerr("Can not use multiple -qG options");					ExitStat = EX_USAGE;					break;				}				queuegroup = newstr(&optarg[1]);				break;			  case 'I': /* Limit by ID */				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_negate = negate;				new->queue_next = QueueLimitId;				QueueLimitId = new;				break;			  case 'R': /* Limit by recipient */				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_negate = negate;				new->queue_next = QueueLimitRecipient;				QueueLimitRecipient = new;				break;			  case 'S': /* Limit by sender */				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_negate = negate;				new->queue_next = QueueLimitSender;				QueueLimitSender = new;				break;			  case 'f': /* foreground queue run */				foregroundqueue  = true;				break;#if _FFR_QUARANTINE			  case 'Q': /* Limit by quarantine message */				if (optarg[1] != '\0')				{					new = (QUEUE_CHAR *) xalloc(sizeof *new);					new->queue_match = newstr(&optarg[1]);					new->queue_negate = negate;					new->queue_next = QueueLimitQuarantine;					QueueLimitQuarantine = new;				}				QueueMode = QM_QUARANTINE;				break;			  case 'L': /* act on lost items */				QueueMode = QM_LOST;				break;#endif /* _FFR_QUARANTINE */			  case 'p': /* Persistent queue */				queuepersistent = true;				if (QueueIntvl == 0)					QueueIntvl = 1;				if (optarg[1] == '\0')					break;				++optarg;				/* FALLTHROUGH */			  default:				i = Errors;				QueueIntvl = convtime(optarg, 'm');				if (QueueIntvl < 0)				{					usrerr("Invalid -q value");					ExitStat = EX_USAGE;				}				/* check for bad conversion */				if (i < Errors)					ExitStat = EX_USAGE;				break;			}			break;		  case 'R':	/* DSN RET: what to return */			CHECK_AGAINST_OPMODE(j);			if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))			{				usrerr("Duplicate -R flag");				ExitStat = EX_USAGE;				break;			}			BlankEnvelope.e_flags |= EF_RET_PARAM;			if (sm_strcasecmp(optarg, "hdrs") == 0)				BlankEnvelope.e_flags |= EF_NO_BODY_RETN;			else if (sm_strcasecmp(optarg, "full") != 0)			{				usrerr("Invalid -R value");				ExitStat = EX_USAGE;			}			macdefine(&BlankEnvelope.e_macro, A_TEMP,				  macid("{dsn_ret}"), optarg);			break;		  case 't':	/* read recipients from message */			CHECK_AGAINST_OPMODE(j);			GrabTo = true;			break;		  case 'V':	/* DSN ENVID: set "original" envelope id */			CHECK_AGAINST_OPMODE(j);			if (!xtextok(optarg))			{				usrerr("Invalid syntax in -V flag");				ExitStat = EX_USAGE;			}			else			{				BlankEnvelope.e_envid = newstr(optarg);				macdefine(&BlankEnvelope.e_macro, A_TEMP,					  macid("{dsn_envid}"), optarg);			}			break;		  case 'X':	/* traffic log file */			dp = drop_privileges(true);			setstat(dp);			if (stat(optarg, &traf_st) == 0 &&			    S_ISFIFO(traf_st.st_mode))				TrafficLogFile = sm_io_open(SmFtStdio,							    SM_TIME_DEFAULT,							    optarg,							    SM_IO_WRONLY, NULL);			else				TrafficLogFile = sm_io_open(SmFtStdio,							    SM_TIME_DEFAULT,							    optarg,							    SM_IO_APPEND, NULL);			if (TrafficLogFile == NULL)			{				syserr("cannot open %s", optarg);				ExitStat = EX_CANTCREAT;				break;			}			(void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,					     NULL, SM_IO_LBF, 0);			break;			/* compatibility flags */		  case 'c':	/* connect to non-local mailers */		  case 'i':	/* don't let dot stop me */		  case 'm':	/* send to me too */		  case 'T':	/* set timeout interval */		  case 'v':	/* give blow-by-blow description */			setoption(j, "T", false, true, &BlankEnvelope);			break;		  case 'e':	/* error message disposition */		  case 'M':	/* define macro */			setoption(j, optarg, false, true, &BlankEnvelope);			break;		  case 's':	/* save From lines in headers */			setoption('f', "T", false, true, &BlankEnvelope);			break;#ifdef DBM		  case 'I':	/* initialize alias DBM file */			set_op_mode(MD_INITALIAS);			break;#endif /* DBM */#if defined(__osf__) || defined(_AIX3)		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */			break;#endif /* defined(__osf__) || defined(_AIX3) */#if defined(sony_news)		  case 'E':		  case 'J':	/* ignore flags for Japanese code conversion				   implemented on Sony NEWS */			break;#endif /* defined(sony_news) */		  default:			finis(true, true, EX_USAGE);			/* NOTREACHED */			break;		}	}	/* if we've had errors so far, exit now */	if ((ExitStat != EX_OK && OpMode != MD_TEST) ||	    ExitStat == EX_OSERR)	{		finis(false, true, ExitStat);		/* NOTREACHED */	}	if (bitset(SUBMIT_MTA, SubmitMode))	{		/* If set daemon_flags on command line, don't reset it */		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)			macdefine(&BlankEnvelope.e_macro, A_PERM,				  macid("{daemon_flags}"), "CC f");	}	else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)	{		SubmitMode = SUBMIT_MSA;		/* If set daemon_flags on command line, don't reset it */		if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)			macdefine(&BlankEnvelope.e_macro, A_PERM,				  macid("{daemon_flags}"), "c u");	}	/*	**  Do basic initialization.	**	Read system control file.	**	Extract special fields for local use.	*/#if XDEBUG	checkfd012("before readcf");#endif /* XDEBUG */	vendor_pre_defaults(&BlankEnvelope);	readcf(getcfname(OpMode, SubmitMode, cftype, conffile),			 safecf, &BlankEnvelope);#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)	ConfigFileRead = true;#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */	vendor_post_defaults(&BlankEnvelope);	/* now we can complain about missing fds */	if (MissingFds != 0 && LogLevel > 8)	{		char mbuf[MAXLINE];		mbuf[0] = '\0';		if (bitset(1 << STDIN_FILENO, MissingFds))			(void) sm_strlcat(mbuf, ", stdin", sizeof mbuf);		if (bitset(1 << STDOUT_FILENO, MissingFds))			(void) sm_strlcat(mbuf, ", stdout", sizeof mbuf);		if (bitset(1 << STDERR_FILENO, MissingFds))			(void) sm_strlcat(mbuf, ", stderr", sizeof mbuf);		/* Notice: fill_errno is from high above: fill_fd() */		sm_syslog(LOG_WARNING, NOQID,			  "File descriptors missing on startup: %s; %s",			  &mbuf[2], sm_errstring(fill_errno));	}	/* Remove the ability for a normal user to send signals */	if (RealUid != 0 && RealUid != geteuid())	{		uid_t new_uid = geteuid();#if HASSETREUID		/*		**  Since we can differentiate between uid and euid,		**  make the uid a different user so the real user		**  can't send signals.  However, it doesn't need to be		**  root (euid has root).		*/		if (new_uid == 0)			new_uid = DefUid;		if (tTd(47, 5))			sm_dprintf("Changing real uid to %d\n", (int) new_uid);		if (setreuid(new_uid, geteuid()) < 0)		{			syserr("main: setreuid(%d, %d) failed",			       (int) new_uid, (int) geteuid());			finis(false, true, EX_OSERR);			/* NOTREACHED */		}		if (tTd(47, 10))			sm_dprintf("Now running as e/ruid %d:%d\n",				   (int) geteuid(), (int) getuid());#else /* HASSETREUID */		/*		**  Have to change both effective and real so need to		**  change them both to effective to keep privs.		*/		if (tTd(47, 5))			sm_dprintf("Changing uid to %d\n", (int) new_uid);		if (setuid(new_uid) < 0)		{			syserr("main: setuid(%d) failed", (int) new_uid);			finis(false, true, EX_OSERR);			/* NOTREACHED */		}		if (tTd(47, 10))			sm_dprintf("Now running as e/ruid %d:%d\n",				   (int) geteuid(), (int) getuid());#endif /* HASSETREUID */	}#if NAMED_BIND	if (FallBackMX != NULL)		(void) getfallbackmxrr(FallBackMX);#endif /* NAMED_BIND */	if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER)	{		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "WARNING: SuperSafe=interactive should only be used with\n         DeliveryMode=interactive\n");	}	if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))	{		usrerr("Mail submission program cannot be used as daemon");		finis(false, true, EX_USAGE);	}	if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||	    OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||	    OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)		makeworkgroups();	/* set up the basic signal handlers */	if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)		(void) sm_signal(SIGINT, intsig);	(void) sm_signal(SIGTERM, intsig);	/* Enforce use of local time (null string overrides this) */	if (TimeZoneSpec == NULL)		unsetenv("TZ");	else if (TimeZoneSpec[0] != '\0')		setuserenv("TZ", TimeZoneSpec);	else		setuserenv("TZ", NULL);	tzset();	/* initialize mailbox database */	i = sm_mbdb_initialize(Mbdb);	if (i != EX_OK)	{		usrerr("Can't initialize mailbox database \"%s\": %s",		       Mbdb, sm_strexit(i));		ExitStat = i;	}	/* avoid denial-of-service attacks */	resetlimits();	if (OpMode == MD_TEST)	{		/* can't be done after readcf if RunAs* is used */		dp = drop_privileges(true);		if (dp != EX_OK)		{			finis(false, true, dp);			/* NOTREACHED */		}	}	else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)	{		/* drop privileges -- daemon mode done after socket/bind */		dp = drop_privileges(false);		setstat(dp);		if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))		{			usrerr("Mail submission program must have RunAsUser set to non root user");			finis(false, true, EX_CONFIG);			/* NOTREACHED */		}	}#if NAMED_BIND	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];#endif /* NAMED_BIND */	/*	**  Find our real host name for future logging.	*/	authinfo = getauthinfo(STDIN_FILENO, &forged);	macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);	/* suppress error printing if errors mailed back or whatever */	if (BlankEnvelope.e_errormode != EM_PRINT)		HoldErrs = true;	/* set up the $=m class now, after .cf has a chance to redefine $m */	expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope);	if (jbuf[0] != '\0')		setclass('m', jbuf);	/* probe interfaces and locate any additional names */	if (DontProbeInterfaces != DPI_PROBENONE)		load_if_names();	if (tTd(0, 10))	{		char pidpath[MAXPATHLEN];		/* Now we know which .cf file we use */		sm_dprintf("     Conf file:\t%s (selected)\n",			   getcfname(OpMode, SubmitMode, cftype, conffile));		expand(PidFile, pidpath, sizeof pidpath, &BlankEnvelope);		sm_dprintf("      Pid file:\t%s (selected)\n", pidpath);	}	if (tTd(0, 1))	{		sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");		sm_dprintf("\n      (short domain name) $w = ");		xputs(macvalue('w', &BlankEnvelope));		sm_dprintf("\n  (canonical domain name) $j = ");		xputs(macvalue('j', &BlankEnvelope));		sm_dprintf("\n         (subdomain name) $m = ");		xputs(macvalue('m', &BlankEnvelope));		sm_dprintf("\n              (node name) $k = ");		xputs(macvalue('k', &BlankEnvelope));		sm_dprintf("\n========================================================\n\n");	}	/*	**  Do more command line checking -- these are things that	**  have to modify the results of reading the config file.	*/	/* process authorization warnings from command line */	if (warn_C_flag)		auth_warning(&BlankEnvelope, "Processed by %s with -C %s",			     RealUserName, conffile);	if (Warn_Q_option && !wordinclass(RealUserName, 't'))		auth_warning(&BlankEnvelope, "Processed from queue %s",			     QueueDir);	if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&	    RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)		sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",			  (int) RealUid);	/* check body type for legality */	i = check_bodytype(BlankEnvelope.e_bodytype);	if (i == BODYTYPE_ILLEGAL)	{		usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);		BlankEnvelope.e_bodytype = NULL;	}	else if (i != BODYTYPE_NONE)		SevenBitInput = (i == BODYTYPE_7BIT);	/* tweak default DSN notifications */	if (DefaultNotify == 0)		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;	/* be sure we don't pick up bogus HOSTALIASES environment variable */	if (OpMode == MD_QUEUERUN && RealUid != 0)		(void) unsetenv("HOSTALIASES");	/* check for sane configuration level */	if (ConfigLevel > MAXCONFIGLEVEL)	{		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",		       ConfigLevel, Version, MAXCONFIGLEVEL);	}	/* need MCI cache to have persistence */	if (HostStatDir != NULL && MaxMciCache == 0)	{		HostStatDir = NULL;		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");	}	/* need HostStatusDir in order to have SingleThreadDelivery */	if (SingleThreadDelivery && HostStatDir == NULL)	{		SingleThreadDelivery = false;		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "Warning: HostStatusDirectory required for SingleThreadDelivery\n");	}	/* check for permissions */	if (RealUid != 0 &&	    RealUid != TrustedUid)	{		char *action = NULL;		switch (OpMode)		{		  case MD_QUEUERUN:#if _FFR_QUARANTINE			if (quarantining != NULL)				action = "quarantine jobs";			else#endif /* _FFR_QUARANTINE */			/* Normal users can do a single queue run */			if (QueueIntvl == 0)				break;			/* but not persistent queue runners */			if (action == NULL)				action = "start a queue runner daemon";			/* FALLTHROUGH */		  case MD_PURGESTAT:			if (action == NULL)				action = "purge host status";			/* FALLTHROUGH */		  case MD_DAEMON:		  case MD_FGDAEMON:			if (action == NULL)				action = "run daemon";			if (tTd(65, 1))				sm_dprintf("Deny user %d attempt to %s\n",					   (int) RealUid, action);			if (LogLevel > 1)				sm_syslog(LOG_ALERT, NOQID,					  "user %d attempted to %s",					  (int) RealUid, action);			HoldErrs = false;			usrerr("Permission denied (real uid not trusted)");			finis(false, true, EX_USAGE);			/* NOTREACHED */			break;		  case MD_VERIFY:			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))			{				/*				**  If -bv and RestrictExpand,				**  drop privs to prevent normal				**  users from reading private				**  aliases/forwards/:include:s				*/				if (tTd(65, 1))					sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",						   (int) RealUid);				dp = drop_privileges(true);				/* Fake address safety */				if (tTd(65, 1))					sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");				setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);				if (dp != EX_OK)				{					if (tTd(65, 1))						sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",							   (int) RealUid);					CurEnv->e_id = NULL;					finis(true, true, dp);					/* NOTREACHED */				}			}			break;		  case MD_TEST:		  case MD_PRINT:		  case MD_PRINTNQE:		  case MD_FREEZE:		  case MD_HOSTSTAT:			/* Nothing special to check */			break;		  case MD_INITALIAS:			if (!wordinclass(RealUserName, 't'))			{				if (tTd(65, 1))					sm_dprintf("Deny user %d attempt to rebuild the alias map\n",						   (int) RealUid);				if (LogLevel > 1)					sm_syslog(LOG_ALERT, NOQID,						  "user %d attempted to rebuild the alias map",						  (int) RealUid);				HoldErrs = false;				usrerr("Permission denied (real uid not trusted)");				finis(false, true, EX_USAGE);				/* NOTREACHED */			}			if (UseMSP)			{				HoldErrs = false;				usrerr("User %d cannot rebuild aliases in mail submission program",				       (int) RealUid);				finis(false, true, EX_USAGE);				/* NOTREACHED */			}			/* FALLTHROUGH */		  default:			if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&			    Verbose != 0)			{				/*				**  If -v and RestrictExpand, reset				**  Verbose to prevent normal users				**  from seeing the expansion of				**  aliases/forwards/:include:s				*/				if (tTd(65, 1))					sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",						   (int) RealUid);				Verbose = 0;			}			break;		}	}	if (MeToo)		BlankEnvelope.e_flags |= EF_METOO;	switch (OpMode)	{	  case MD_TEST:		/* don't have persistent host status in test mode */		HostStatDir = NULL;		if (Verbose == 0)			Verbose = 2;		BlankEnvelope.e_errormode = EM_PRINT;		HoldErrs = false;		break;	  case MD_VERIFY:		BlankEnvelope.e_errormode = EM_PRINT;		HoldErrs = false;		/* arrange to exit cleanly on hangup signal */		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)			(void) sm_signal(SIGHUP, intsig);		if (geteuid() != 0)			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,					     "Notice: -bv may give misleading output for non-privileged user\n");		break;	  case MD_FGDAEMON:		run_in_foreground = true;		set_op_mode(MD_DAEMON);		/* FALLTHROUGH */	  case MD_DAEMON:		vendor_daemon_setup(&BlankEnvelope);		/* remove things that don't make sense in daemon mode */		FullName = NULL;		GrabTo = false;		/* arrange to restart on hangup signal */		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')			sm_syslog(LOG_WARNING, NOQID,				  "daemon invoked without full pathname; kill -1 won't work");		break;	  case MD_INITALIAS:		Verbose = 2;		BlankEnvelope.e_errormode = EM_PRINT;		HoldErrs = false;		/* FALLTHROUGH */	  default:		/* arrange to exit cleanly on hangup signal */		if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)			(void) sm_signal(SIGHUP, intsig);		break;	}	/* special considerations for FullName */	if (FullName != NULL)	{		char *full = NULL;		/* full names can't have newlines */		if (strchr(FullName, '\n') != NULL)		{			full = newstr(denlstring(FullName, true, true));			FullName = full;		}		/* check for characters that may have to be quoted */		if (!rfc822_string(FullName))		{			/*			**  Quote a full name with special characters			**  as a comment so crackaddr() doesn't destroy			**  the name portion of the address.			*/			FullName = addquotes(FullName, NULL);			if (full != NULL)				sm_free(full);  /* XXX */		}	}	/* do heuristic mode adjustment */	if (Verbose)	{		/* turn off noconnect option */		setoption('c', "F", true, false, &BlankEnvelope);		/* turn on interactive delivery */		setoption('d', "", true, false, &BlankEnvelope);	}#ifdef VENDOR_CODE	/* check for vendor mismatch */	if (VendorCode != VENDOR_CODE)	{		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",			getvendor(VENDOR_CODE), getvendor(VendorCode));	}#endif /* VENDOR_CODE */	/* check for out of date configuration level */	if (ConfigLevel < MAXCONFIGLEVEL)	{		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",			Version, MAXCONFIGLEVEL, ConfigLevel);	}	if (ConfigLevel < 3)		UseErrorsTo = true;	/* set options that were previous macros */	if (SmtpGreeting == NULL)	{		if (ConfigLevel < 7 &&		    (p = macvalue('e', &BlankEnvelope)) != NULL)			SmtpGreeting = newstr(p);		else			SmtpGreeting = "\201j Sendmail \201v ready at \201b";	}	if (UnixFromLine == NULL)	{		if (ConfigLevel < 7 &&		    (p = macvalue('l', &BlankEnvelope)) != NULL)			UnixFromLine = newstr(p);		else			UnixFromLine = "From \201g  \201d";	}	SmtpError[0] = '\0';	/* our name for SMTP codes */	expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);	if (jbuf[0] == '\0')		PSTRSET(MyHostName, "localhost");	else		PSTRSET(MyHostName, jbuf);	if (strchr(MyHostName, '.') == NULL)		message("WARNING: local host name (%s) is not qualified; fix $j in config file",			MyHostName);	/* make certain that this name is part of the $=w class */	setclass('w', MyHostName);	/* fill in the structure of the *default* queue */	st = stab("mqueue", ST_QUEUE, ST_FIND);	if (st == NULL)		syserr("No default queue (mqueue) defined");	else		set_def_queueval(st->s_quegrp, true);	/* the indices of built-in mailers */	st = stab("local", ST_MAILER, ST_FIND);	if (st != NULL)		LocalMailer = st->s_mailer;	else if (OpMode != MD_TEST || !warn_C_flag)		syserr("No local mailer defined");	st = stab("prog", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No prog mailer defined");	else	{		ProgMailer = st->s_mailer;		clrbitn(M_MUSER, ProgMailer->m_flags);	}	st = stab("*file*", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No *file* mailer defined");	else	{		FileMailer = st->s_mailer;		clrbitn(M_MUSER, FileMailer->m_flags);	}	st = stab("*include*", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No *include* mailer defined");	else		InclMailer = st->s_mailer;	if (ConfigLevel < 6)	{		/* heuristic tweaking of local mailer for back compat */		if (LocalMailer != NULL)		{			setbitn(M_ALIASABLE, LocalMailer->m_flags);			setbitn(M_HASPWENT, LocalMailer->m_flags);			setbitn(M_TRYRULESET5, LocalMailer->m_flags);			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);			setbitn(M_CHECKPROG, LocalMailer->m_flags);			setbitn(M_CHECKFILE, LocalMailer->m_flags);			setbitn(M_CHECKUDB, LocalMailer->m_flags);		}		if (ProgMailer != NULL)			setbitn(M_RUNASRCPT, ProgMailer->m_flags);		if (FileMailer != NULL)			setbitn(M_RUNASRCPT, FileMailer->m_flags);	}	if (ConfigLevel < 7)	{		if (LocalMailer != NULL)			setbitn(M_VRFY250, LocalMailer->m_flags);		if (ProgMailer != NULL)			setbitn(M_VRFY250, ProgMailer->m_flags);		if (FileMailer != NULL)			setbitn(M_VRFY250, FileMailer->m_flags);	}	/* MIME Content-Types that cannot be transfer encoded */	setclass('n', "multipart/signed");	/* MIME message/xxx subtypes that can be treated as messages */	setclass('s', "rfc822");	/* MIME Content-Transfer-Encodings that can be encoded */	setclass('e', "7bit");	setclass('e', "8bit");	setclass('e', "binary");#ifdef USE_B_CLASS	/* MIME Content-Types that should be treated as binary */	setclass('b', "image");	setclass('b', "audio");	setclass('b', "video");	setclass('b', "application/octet-stream");#endif /* USE_B_CLASS */	/* MIME headers which have fields to check for overflow */	setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");	setclass(macid("{checkMIMEFieldHeaders}"), "content-type");	/* MIME headers to check for length overflow */	setclass(macid("{checkMIMETextHeaders}"), "content-description");	/* MIME headers to check for overflow and rebalance */	setclass(macid("{checkMIMEHeaders}"), "content-disposition");	setclass(macid("{checkMIMEHeaders}"), "content-id");	setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");	setclass(macid("{checkMIMEHeaders}"), "content-type");	setclass(macid("{checkMIMEHeaders}"), "mime-version");	/* Macros to save in the queue file -- don't remove any */	setclass(macid("{persistentMacros}"), "r");	setclass(macid("{persistentMacros}"), "s");	setclass(macid("{persistentMacros}"), "_");	setclass(macid("{persistentMacros}"), "{if_addr}");	setclass(macid("{persistentMacros}"), "{daemon_flags}");	/* operate in queue directory */	if (QueueDir == NULL || *QueueDir == '\0')	{		if (OpMode != MD_TEST)		{			syserr("QueueDirectory (Q) option must be set");			ExitStat = EX_CONFIG;		}	}	else	{		if (OpMode != MD_TEST)			setup_queues(OpMode == MD_DAEMON);	}	/* check host status directory for validity */	if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))	{		/* cannot use this value */		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "Warning: Cannot use HostStatusDirectory = %s: %s\n",				     HostStatDir, sm_errstring(errno));		HostStatDir = NULL;	}	if (OpMode == MD_QUEUERUN &&	    RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))	{		struct stat stbuf;		/* check to see if we own the queue directory */		if (stat(".", &stbuf) < 0)			syserr("main: cannot stat %s", QueueDir);		if (stbuf.st_uid != RealUid)		{			/* nope, really a botch */			HoldErrs = false;			usrerr("You do not have permission to process the queue");			finis(false, true, EX_NOPERM);			/* NOTREACHED */		}	}#if MILTER	/* sanity checks on milter filters */	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)	{		milter_config(InputFilterList, InputFilters, MAXFILTERS);# if _FFR_MILTER_PERDAEMON		setup_daemon_milters();# endif /* _FFR_MILTER_PERDAEMON */	}#endif /* MILTER */	/* Convert queuegroup string to qgrp number */	if (queuegroup != NULL)	{		qgrp = name2qid(queuegroup);		if (qgrp == NOQGRP)		{			HoldErrs = false;			usrerr("Queue group %s unknown", queuegroup);			finis(false, true, ExitStat);			/* NOTREACHED */		}	}	/* if we've had errors so far, exit now */	if (ExitStat != EX_OK && OpMode != MD_TEST)	{		finis(false, true, ExitStat);		/* NOTREACHED */	}#if SASL	/* sendmail specific SASL initialization */	sm_sasl_init();#endif /* SASL */#if XDEBUG	checkfd012("before main() initmaps");#endif /* XDEBUG */	/*	**  Do operation-mode-dependent initialization.	*/	switch (OpMode)	{	  case MD_PRINT:		/* print the queue */		HoldErrs = false;		dropenvelope(&BlankEnvelope, true, false);		(void) sm_signal(SIGPIPE, sigpipe);		if (qgrp != NOQGRP)		{			int j;			/* Selecting a particular queue group to run */			for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)			{				if (StopRequest)					stop_sendmail();				(void) print_single_queue(qgrp, j);			}			finis(false, true, EX_OK);			/* NOTREACHED */		}		printqueue();		finis(false, true, EX_OK);		/* NOTREACHED */		break;	  case MD_PRINTNQE:		/* print number of entries in queue */		dropenvelope(&BlankEnvelope, true, false);		(void) sm_signal(SIGPIPE, sigpipe);		printnqe(smioout, NULL);		finis(false, true, EX_OK);		/* NOTREACHED */		break;#if _FFR_QUARANTINE	  case MD_QUEUERUN:		/* only handle quarantining here */		if (quarantining == NULL)			break;		if (QueueMode != QM_QUARANTINE &&		    QueueMode != QM_NORMAL)		{			HoldErrs = false;			usrerr("Can not use -Q with -q%c", QueueMode);			ExitStat = EX_USAGE;			finis(false, true, ExitStat);			/* NOTREACHED */		}		quarantine_queue(quarantining, qgrp);		finis(false, true, EX_OK);		break;#endif /* _FFR_QUARANTINE */	  case MD_HOSTSTAT:		(void) sm_signal(SIGPIPE, sigpipe);		(void) mci_traverse_persistent(mci_print_persistent, NULL);		finis(false, true, EX_OK);		/* NOTREACHED */		break;	  case MD_PURGESTAT:		(void) mci_traverse_persistent(mci_purge_persistent, NULL);		finis(false, true, EX_OK);		/* NOTREACHED */		break;	  case MD_INITALIAS:		/* initialize maps */		initmaps();		finis(false, true, ExitStat);		/* NOTREACHED */		break;	  case MD_SMTP:	  case MD_DAEMON:		/* reset DSN parameters */		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;		macdefine(&BlankEnvelope.e_macro, A_PERM,			  macid("{dsn_notify}"), NULL);		BlankEnvelope.e_envid = NULL;		macdefine(&BlankEnvelope.e_macro, A_PERM,			  macid("{dsn_envid}"), NULL);		BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);		macdefine(&BlankEnvelope.e_macro, A_PERM,			  macid("{dsn_ret}"), NULL);		/* don't open maps for daemon -- done below in child */		break;	}	if (tTd(0, 15))	{		/* print configuration table (or at least part of it) */		if (tTd(0, 90))			printrules();		for (i = 0; i < MAXMAILERS; i++)		{			if (Mailer[i] != NULL)				printmailer(Mailer[i]);		}	}	/*	**  Switch to the main envelope.	*/	CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,			     sm_rpool_new_x(NULL));	MainEnvelope.e_flags = BlankEnvelope.e_flags;	/*	**  If test mode, read addresses from stdin and process.	*/	if (OpMode == MD_TEST)	{		if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))			Verbose = 2;		if (Verbose)		{			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,				     "Enter <ruleset> <address>\n");		}		macdefine(&(MainEnvelope.e_macro), A_PERM,			  macid("{addr_type}"), "e r");		for (;;)		{			SM_TRY			{				(void) sm_signal(SIGINT, intindebug);				(void) sm_releasesignal(SIGINT);				if (Verbose == 2)					(void) sm_io_fprintf(smioout,							     SM_TIME_DEFAULT,							     "> ");				(void) sm_io_flush(smioout, SM_TIME_DEFAULT);				if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,						sizeof buf) == NULL)					testmodeline("/quit", &MainEnvelope);				p = strchr(buf, '\n');				if (p != NULL)					*p = '\0';				if (Verbose < 2)					(void) sm_io_fprintf(smioout,							     SM_TIME_DEFAULT,							     "> %s\n", buf);				testmodeline(buf, &MainEnvelope);			}			SM_EXCEPT(exc, "[!F]*")			{				/*				**  8.10 just prints \n on interrupt.				**  I'm printing the exception here in case				**  sendmail is extended to raise additional				**  exceptions in this context.				*/				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,						     "\n");				sm_exc_print(exc, smioout);			}			SM_END_TRY		}	}#if STARTTLS	tls_ok = true;	if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)	{		/* check whether STARTTLS is turned off for the client */		if (chkclientmodifiers(D_NOTLS))			tls_ok = false;	}	else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||		 OpMode == MD_SMTP)	{		/* check whether STARTTLS is turned off for the server */		if (chkdaemonmodifiers(D_NOTLS))			tls_ok = false;	}	else	/* other modes don't need STARTTLS */		tls_ok = false;	if (tls_ok)	{		/* basic TLS initialization */		tls_ok = init_tls_library();	}	if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))	{		/* disable TLS for client */		setclttls(false);	}#endif /* STARTTLS */	/*	**  If collecting stuff from the queue, go start doing that.	*/	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)	{		pid_t pid = -1;#if STARTTLS		/* init TLS for client, ignore result for now */		(void) initclttls(tls_ok);#endif /* STARTTLS */		/*		**  The parent process of the caller of runqueue() needs		**  to stay around for a possible SIGTERM. The SIGTERM will		**  tell this process that all of the queue runners children		**  need to be sent SIGTERM as well. At the same time, we		**  want to return control to the command line. So we do an		**  extra fork().		*/		if (Verbose || foregroundqueue || (pid = fork()) <= 0)		{			/*			**  If the fork() failed we should still try to do			**  the queue run. If it succeeded then the child			**  is going to start the run and wait for all			**  of the children to finish.			*/			if (pid == 0)			{				/* Reset global flags */				RestartRequest = NULL;				ShutdownRequest = NULL;				PendingSignal = 0;				/* disconnect from terminal */				disconnect(2, CurEnv);			}			CurrentPid = getpid();			if (qgrp != NOQGRP)			{				int rwgflags = RWG_NONE;				/*				**  To run a specific queue group mark it to				**  be run, select the work group it's in and				**  increment the work counter.				*/				for (i = 0; i < NumQueue && Queue[i] != NULL;				     i++)					Queue[i]->qg_nextrun = (time_t) -1;				Queue[qgrp]->qg_nextrun = 0;				if (Verbose)					rwgflags |= RWG_VERBOSE;				if (queuepersistent)					rwgflags |= RWG_PERSISTENT;				rwgflags |= RWG_FORCE;				(void) run_work_group(Queue[qgrp]->qg_wgrp,						      rwgflags);			}			else				(void) runqueue(false, Verbose,						queuepersistent, true);			/* set the title to make it easier to find */			sm_setproctitle(true, CurEnv, "Queue control");			(void) sm_signal(SIGCHLD, SIG_DFL);			while (CurChildren > 0)			{				int status;				pid_t ret;				while ((ret = sm_wait(&status)) <= 0)					continue;				/* Only drop when a child gives status */				if (WIFSTOPPED(status))					continue;				proc_list_drop(ret, status, NULL);			}		}		finis(true, true, ExitStat);		/* NOTREACHED */	}# if SASL	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)	{		/* check whether AUTH is turned off for the server */		if (!chkdaemonmodifiers(D_NOAUTH) &&		    (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)			syserr("!sasl_server_init failed! [%s]",				sasl_errstring(i, NULL, NULL));	}# endif /* SASL */	if (OpMode == MD_SMTP)	{		proc_list_add(CurrentPid, "Sendmail SMTP Agent",			      PROC_DAEMON, 0, -1);		/* clean up background delivery children */		(void) sm_signal(SIGCHLD, reapchild);	}	/*	**  If a daemon, wait for a request.	**	getrequests will always return in a child.	**	If we should also be processing the queue, start	**		doing it in background.	**	We check for any errors that might have happened	**		during startup.	*/	if (OpMode == MD_DAEMON || QueueIntvl > 0)	{		char dtype[200];		if (!run_in_foreground && !tTd(99, 100))		{			/* put us in background */			i = fork();			if (i < 0)				syserr("daemon: cannot fork");			if (i != 0)			{				finis(false, true, EX_OK);				/* NOTREACHED */			}			/*			**  Initialize exception stack and default exception			**  handler for child process.			*/			/* Reset global flags */			RestartRequest = NULL;			RestartWorkGroup = false;			ShutdownRequest = NULL;			PendingSignal = 0;			CurrentPid = getpid();			sm_exc_newthread(fatal_error);			/* disconnect from our controlling tty */			disconnect(2, &MainEnvelope);		}		dtype[0] = '\0';		if (OpMode == MD_DAEMON)		{			(void) sm_strlcat(dtype, "+SMTP", sizeof dtype);			DaemonPid = CurrentPid;		}		if (QueueIntvl > 0)		{			(void) sm_strlcat2(dtype,					   queuepersistent					   ? "+persistent-queueing@"					   : "+queueing@",					   pintvl(QueueIntvl, true),					   sizeof dtype);		}		if (tTd(0, 1))			(void) sm_strlcat(dtype, "+debugging", sizeof dtype);		sm_syslog(LOG_INFO, NOQID,			  "starting daemon (%s): %s", Version, dtype + 1);#if XLA		xla_create_file();#endif /* XLA */		/* save daemon type in a macro for possible PidFile use */		macdefine(&BlankEnvelope.e_macro, A_TEMP,			macid("{daemon_info}"), dtype + 1);		/* save queue interval in a macro for possible PidFile use */		macdefine(&MainEnvelope.e_macro, A_TEMP,			macid("{queue_interval}"), pintvl(QueueIntvl, true));		/* workaround: can't seem to release the signal in the parent */		(void) sm_signal(SIGHUP, sighup);		(void) sm_releasesignal(SIGHUP);		(void) sm_signal(SIGTERM, sigterm);		if (QueueIntvl > 0)		{			(void) runqueue(true, false, queuepersistent, true);			/*			**  If queuepersistent but not in daemon mode then			**  we're going to do the queue runner monitoring here.			**  If in daemon mode then the monitoring will happen			**  elsewhere.			*/			if (OpMode != MD_DAEMON && queuepersistent)			{				/* set the title to make it easier to find */				sm_setproctitle(true, CurEnv, "Queue control");				(void) sm_signal(SIGCHLD, SIG_DFL);				while (CurChildren > 0)				{					int status;					pid_t ret;					int group;					if (ShutdownRequest != NULL)						shutdown_daemon();					else if (RestartRequest != NULL)						restart_daemon();					else if (RestartWorkGroup)						restart_marked_work_groups();					while ((ret = sm_wait(&status)) <= 0)						continue;					if (WIFSTOPPED(status))						continue;					/* Probe only on a child status */					proc_list_drop(ret, status, &group);					if (WIFSIGNALED(status))					{						if (WCOREDUMP(status))						{							sm_syslog(LOG_ERR, NOQID,								  "persistent queue runner=%d core dumped, signal=%d",								  group, WTERMSIG(status));							/* don't restart this one */							mark_work_group_restart(group, -1);							continue;						}						sm_syslog(LOG_ERR, NOQID,							  "persistent queue runner=%d died, signal=%d",							  group, WTERMSIG(status));					}					/*					**  When debugging active, don't					**  restart the persistent queues.					**  But do log this as info.					*/					if (sm_debug_active(&DebugNoPRestart,							    1))					{						sm_syslog(LOG_DEBUG, NOQID,							  "persistent queue runner=%d, exited",							  group);						mark_work_group_restart(group, -1);					}				}				finis(true, true, ExitStat);				/* NOTREACHED */			}			if (OpMode != MD_DAEMON)			{				char qtype[200];				/*				**  Write the pid to file				**  XXX Overwrites sendmail.pid				*/				log_sendmail_pid(&MainEnvelope);				/* set the title to make it easier to find */				qtype[0] = '\0';				(void) sm_strlcpyn(qtype, sizeof qtype, 4,						   "Queue runner@",						   pintvl(QueueIntvl, true),						   " for ",						   QueueDir);				sm_setproctitle(true, CurEnv, qtype);				for (;;)				{					(void) pause();					if (ShutdownRequest != NULL)						shutdown_daemon();					else if (RestartRequest != NULL)						restart_daemon();					else if (RestartWorkGroup)						restart_marked_work_groups();					if (doqueuerun())						(void) runqueue(true, false,								false, false);				}			}		}		dropenvelope(&MainEnvelope, true, false);#if STARTTLS		/* init TLS for server, ignore result for now */		(void) initsrvtls(tls_ok);#endif /* STARTTLS */	nextreq:		p_flags = getrequests(&MainEnvelope);		/* drop privileges */		(void) drop_privileges(false);		/*		**  Get authentication data		**  Set _ macro in BlankEnvelope before calling newenvelope().		*/		authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,						     NULL), &forged);		macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);		/* at this point we are in a child: reset state */		sm_rpool_free(MainEnvelope.e_rpool);		(void) newenvelope(&MainEnvelope, &MainEnvelope,				   sm_rpool_new_x(NULL));	}	if (LogLevel > 9)	{		/* log connection information */		sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo);	}	/*	**  If running SMTP protocol, start collecting and executing	**  commands.  This will never return.	*/	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)	{		char pbuf[20];		/*		**  Save some macros for check_* rulesets.		*/		if (forged)		{			char ipbuf[103];			(void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]",					   anynet_ntoa(&RealHostAddr));			macdefine(&BlankEnvelope.e_macro, A_TEMP,				  macid("{client_name}"), ipbuf);		}		else			macdefine(&BlankEnvelope.e_macro, A_PERM,				  macid("{client_name}"), RealHostName);		macdefine(&BlankEnvelope.e_macro, A_TEMP,			  macid("{client_addr}"), anynet_ntoa(&RealHostAddr));		sm_getla();		switch (RealHostAddr.sa.sa_family)		{#if NETINET		  case AF_INET:			(void) sm_snprintf(pbuf, sizeof pbuf, "%d",					   RealHostAddr.sin.sin_port);			break;#endif /* NETINET */#if NETINET6		  case AF_INET6:			(void) sm_snprintf(pbuf, sizeof pbuf, "%d",					   RealHostAddr.sin6.sin6_port);			break;#endif /* NETINET6 */		  default:			(void) sm_snprintf(pbuf, sizeof pbuf, "0");			break;		}		macdefine(&BlankEnvelope.e_macro, A_TEMP,			macid("{client_port}"), pbuf);		if (OpMode == MD_DAEMON)		{			/* validate the connection */			HoldErrs = true;			nullserver = validate_connection(&RealHostAddr,							 RealHostName,							 &MainEnvelope);			HoldErrs = false;		}		else if (p_flags == NULL)		{			p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);			clrbitmap(p_flags);		}#if STARTTLS		if (OpMode == MD_SMTP)			(void) initsrvtls(tls_ok);#endif /* STARTTLS */		/* turn off profiling */		SM_PROF(1);		smtp(nullserver, *p_flags, &MainEnvelope);		if (tTd(93, 100))		{			/* turn off profiling */			SM_PROF(0);			if (OpMode == MD_DAEMON)				goto nextreq;		}	}	sm_rpool_free(MainEnvelope.e_rpool);	clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));	if (OpMode == MD_VERIFY)	{		set_delivery_mode(SM_VERIFY, &MainEnvelope);		PostMasterCopy = NULL;	}	else	{		/* interactive -- all errors are global */		MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;	}	/*	**  Do basic system initialization and set the sender	*/	initsys(&MainEnvelope);	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");	macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");	setsender(from, &MainEnvelope, NULL, '\0', false);	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&	    (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||	     strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))	{		auth_warning(&MainEnvelope, "%s set sender to %s using -%c",			     RealUserName, from, warn_f_flag);#if SASL		auth = false;#endif /* SASL */	}	if (auth)	{		char *fv;		/* set the initial sender for AUTH= to $f@$j */		fv = macvalue('f', &MainEnvelope);		if (fv == NULL || *fv == '\0')			MainEnvelope.e_auth_param = NULL;		else		{			if (strchr(fv, '@') == NULL)			{				i = strlen(fv) + strlen(macvalue('j',							&MainEnvelope)) + 2;				p = sm_malloc_x(i);				(void) sm_strlcpyn(p, i, 3, fv, "@",						   macvalue('j',							    &MainEnvelope));			}			else				p = sm_strdup_x(fv);			MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,								      xtextify(p, "="));			sm_free(p);  /* XXX */		}	}	if (macvalue('s', &MainEnvelope) == NULL)		macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);	av = argv + optind;	if (*av == NULL && !GrabTo)	{		MainEnvelope.e_to = NULL;		MainEnvelope.e_flags |= EF_GLOBALERRS;		HoldErrs = false;		SuperSafe = SAFE_NO;		usrerr("Recipient names must be specified");		/* collect body for UUCP return */		if (OpMode != MD_VERIFY)			collect(InChannel, false, NULL, &MainEnvelope);		finis(true, true, EX_USAGE);		/* NOTREACHED */	}	/*	**  Scan argv and deliver the message to everyone.	*/	save_val = LogUsrErrs;	LogUsrErrs = true;	sendtoargv(av, &MainEnvelope);	LogUsrErrs = save_val;	/* if we have had errors sofar, arrange a meaningful exit stat */	if (Errors > 0 && ExitStat == EX_OK)		ExitStat = EX_USAGE;#if _FFR_FIX_DASHT	/*	**  If using -t, force not sending to argv recipients, even	**  if they are mentioned in the headers.	*/	if (GrabTo)	{		ADDRESS *q;		for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)			q->q_state = QS_REMOVED;	}#endif /* _FFR_FIX_DASHT */	/*	**  Read the input mail.	*/	MainEnvelope.e_to = NULL;	if (OpMode != MD_VERIFY || GrabTo)	{		int savederrors;		unsigned long savedflags;		/*		**  workaround for compiler warning on Irix:		**  do not initialize variable in the definition, but		**  later on:		**  warning(1548): transfer of control bypasses		**  initialization of:		**  variable "savederrors" (declared at line 2570)		**  variable "savedflags" (declared at line 2571)		**  goto giveup;		*/		savederrors = Errors;		savedflags = MainEnvelope.e_flags & EF_FATALERRS;		MainEnvelope.e_flags |= EF_GLOBALERRS;		MainEnvelope.e_flags &= ~EF_FATALERRS;		Errors = 0;		buffer_errors();		collect(InChannel, false, NULL, &MainEnvelope);		/* header checks failed */		if (Errors > 0)		{  giveup:			if (!GrabTo)			{				/* Log who the mail would have gone to */				logundelrcpts(&MainEnvelope,					      MainEnvelope.e_message,					      8, false);			}			flush_errors(true);			finis(true, true, ExitStat);			/* NOTREACHED */			return -1;		}		/* bail out if message too large */		if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))		{			finis(true, true, ExitStat != EX_OK ? ExitStat							    : EX_DATAERR);			/* NOTREACHED */			return -1;		}		/* set message size */		(void) sm_snprintf(buf, sizeof buf, "%ld",				   MainEnvelope.e_msgsize);		macdefine(&MainEnvelope.e_macro, A_TEMP,			  macid("{msg_size}"), buf);		Errors = savederrors;		MainEnvelope.e_flags |= savedflags;	}	errno = 0;	if (tTd(1, 1))		sm_dprintf("From person = \"%s\"\n",			   MainEnvelope.e_from.q_paddr);#if _FFR_QUARANTINE	/* Check if quarantining stats should be updated */	if (MainEnvelope.e_quarmsg != NULL)		markstats(&MainEnvelope, NULL, STATS_QUARANTINE);#endif /* _FFR_QUARANTINE */	/*	**  Actually send everything.	**	If verifying, just ack.	*/	if (Errors == 0)	{		if (!split_by_recipient(&MainEnvelope) &&		    bitset(EF_FATALERRS, MainEnvelope.e_flags))			goto giveup;	}	/* make sure we deliver at least the first envelope */	i = FastSplit > 0 ? 0 : -1;	for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)	{		ENVELOPE *next;		e->e_from.q_state = QS_SENDER;		if (tTd(1, 5))		{			sm_dprintf("main[%d]: QS_SENDER ", i);			printaddr(&e->e_from, false);		}		e->e_to = NULL;		sm_getla();		GrabTo = false;#if NAMED_BIND		_res.retry = TimeOuts.res_retry[RES_TO_FIRST];		_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];#endif /* NAMED_BIND */		next = e->e_sibling;		e->e_sibling = NULL;		/* after FastSplit envelopes: queue up */		sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);		e->e_sibling = next;	}	/*	**  All done.	**	Don't send return error message if in VERIFY mode.	*/	finis(true, true, ExitStat);	/* NOTREACHED */	return ExitStat;}/***  STOP_SENDMAIL -- Stop the running program****	Parameters:**		none.****	Returns:**		none.****	Side Effects:**		exits.*/voidstop_sendmail(){	/* reset uid for process accounting */	endpwent();	(void) setuid(RealUid);	exit(EX_OK);}/***  FINIS -- Clean up and exit.****	Parameters:**		drop -- whether or not to drop CurEnv envelope**		cleanup -- call exit() or _exit()?**		exitstat -- exit status to use for exit() call****	Returns:**		never****	Side Effects:**		exits sendmail*/voidfinis(drop, cleanup, exitstat)	bool drop;	bool cleanup;	volatile int exitstat;{	/* Still want to process new timeouts added below */	sm_clear_events();	(void) sm_releasesignal(SIGALRM);	if (tTd(2, 1))	{		sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",			   exitstat,			   CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);		printenvflags(CurEnv);	}	if (tTd(2, 9))		printopenfds(false);	SM_TRY		/*		**  Clean up.  This might raise E:mta.quickabort		*/		/* clean up temp files */		CurEnv->e_to = NULL;		if (drop)		{			if (CurEnv->e_id != NULL)			{				dropenvelope(CurEnv, true, false);				sm_rpool_free(CurEnv->e_rpool);				CurEnv->e_rpool = NULL;			}			else				poststats(StatFile);		}		/* flush any cached connections */		mci_flush(true, NULL);		/* close maps belonging to this pid */		closemaps(false);#if USERDB		/* close UserDatabase */		_udbx_close();#endif /* USERDB */#if SASL		stop_sasl_client();#endif /* SASL */#if XLA		/* clean up extended load average stuff */		xla_all_end();#endif /* XLA */	SM_FINALLY		/*		**  And exit.		*/		if (LogLevel > 78)			sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",				  (int) CurrentPid);		if (exitstat == EX_TEMPFAIL ||		    CurEnv->e_errormode == EM_BERKNET)			exitstat = EX_OK;		/* XXX clean up queues and related data structures */		cleanup_queues();#if SM_CONF_SHM		cleanup_shm(DaemonPid == getpid());#endif /* SM_CONF_SHM */		/* reset uid for process accounting */		endpwent();		sm_mbdb_terminate();		(void) setuid(RealUid);#if SM_HEAP_CHECK		/* dump the heap, if we are checking for memory leaks */		if (sm_debug_active(&SmHeapCheck, 2))			sm_heap_report(smioout,				       sm_debug_level(&SmHeapCheck) - 1);#endif /* SM_HEAP_CHECK */		if (sm_debug_active(&SmXtrapReport, 1))			sm_dprintf("xtrap count = %d\n", SmXtrapCount);		if (cleanup)			exit(exitstat);		else			_exit(exitstat);	SM_END_TRY}/***  INTINDEBUG -- signal handler for SIGINT in -bt mode****	Parameters:**		sig -- incoming signal.****	Returns:**		none.****	Side Effects:**		longjmps back to test mode loop.****	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE**		DOING.*//* Type of an exception generated on SIGINT during address test mode.  */static const SM_EXC_TYPE_T EtypeInterrupt ={	SmExcTypeMagic,	"S:mta.interrupt",	"",	sm_etype_printf,	"interrupt",};/* ARGSUSED */static SIGFUNC_DECLintindebug(sig)	int sig;{	int save_errno = errno;	FIX_SYSV_SIGNAL(sig, intindebug);	errno = save_errno;	CHECK_CRITICAL(sig);	errno = save_errno;	sm_exc_raisenew_x(&EtypeInterrupt);	errno = save_errno;	return SIGFUNC_RETURN;}/***  SIGTERM -- SIGTERM handler for the daemon****	Parameters:**		sig -- signal number.****	Returns:**		none.****	Side Effects:**		Sets ShutdownRequest which will hopefully trigger**		the daemon to exit.****	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE**		DOING.*//* ARGSUSED */static SIGFUNC_DECLsigterm(sig)	int sig;{	int save_errno = errno;	FIX_SYSV_SIGNAL(sig, sigterm);	ShutdownRequest = "signal";	errno = save_errno;	return SIGFUNC_RETURN;}/***  SIGHUP -- handle a SIGHUP signal****	Parameters:**		sig -- incoming signal.****	Returns:**		none.****	Side Effects:**		Sets RestartRequest which should cause the daemon**		to restart.****	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE**		DOING.*//* ARGSUSED */static SIGFUNC_DECLsighup(sig)	int sig;{	int save_errno = errno;	FIX_SYSV_SIGNAL(sig, sighup);	RestartRequest = "signal";	errno = save_errno;	return SIGFUNC_RETURN;}/***  SIGPIPE -- signal handler for SIGPIPE****	Parameters:**		sig -- incoming signal.****	Returns:**		none.****	Side Effects:**		Sets StopRequest which should cause the mailq/hoststatus**		display to stop.****	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE**		DOING.*//* ARGSUSED */static SIGFUNC_DECLsigpipe(sig)	int sig;{	int save_errno = errno;	FIX_SYSV_SIGNAL(sig, sigpipe);	StopRequest = true;	errno = save_errno;	return SIGFUNC_RETURN;}/***  INTSIG -- clean up on interrupt****	This just arranges to exit.  It pessimizes in that it**	may resend a message.****	Parameters:**		none.****	Returns:**		none.****	Side Effects:**		Unlocks the current job.****	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE**		DOING.****		XXX: More work is needed for this signal handler.*//* ARGSUSED */SIGFUNC_DECLintsig(sig)	int sig;{	bool drop = false;	int save_errno = errno;	FIX_SYSV_SIGNAL(sig, intsig);	errno = save_errno;	CHECK_CRITICAL(sig);	sm_allsignals(true);	if (sig != 0 && LogLevel > 79)		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");	FileName = NULL;	/* Clean-up on aborted stdin message submission */	if (CurEnv->e_id != NULL &&	    (OpMode == MD_SMTP ||	     OpMode == MD_DELIVER ||	     OpMode == MD_ARPAFTP))	{		register ADDRESS *q;		/* don't return an error indication */		CurEnv->e_to = NULL;		CurEnv->e_flags &= ~EF_FATALERRS;		CurEnv->e_flags |= EF_CLRQUEUE;		/*		**  Spin through the addresses and		**  mark them dead to prevent bounces		*/		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)			q->q_state = QS_DONTSEND;		drop = true;	}	else if (OpMode != MD_TEST)	{		unlockqueue(CurEnv);	}	finis(drop, false, EX_OK);	/* NOTREACHED */}/***  DISCONNECT -- remove our connection with any foreground process****	Parameters:**		droplev -- how "deeply" we should drop the line.**			0 -- ignore signals, mail back errors, make sure**			     output goes to stdout.**			1 -- also, make stdout go to /dev/null.**			2 -- also, disconnect from controlling terminal**			     (only for daemon mode).**		e -- the current envelope.****	Returns:**		none****	Side Effects:**		Trys to insure that we are immune to vagaries of**		the controlling tty.*/voiddisconnect(droplev, e)	int droplev;	register ENVELOPE *e;{	int fd;	if (tTd(52, 1))		sm_dprintf("disconnect: In %d Out %d, e=%p\n",			   sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),			   sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);	if (tTd(52, 100))	{		sm_dprintf("don't\n");		return;	}	if (LogLevel > 93)		sm_syslog(LOG_DEBUG, e->e_id,			  "disconnect level %d",			  droplev);	/* be sure we don't get nasty signals */	(void) sm_signal(SIGINT, SIG_IGN);	(void) sm_signal(SIGQUIT, SIG_IGN);	/* we can't communicate with our caller, so.... */	HoldErrs = true;	CurEnv->e_errormode = EM_MAIL;	Verbose = 0;	DisConnected = true;	/* all input from /dev/null */	if (InChannel != smioin)	{		(void) sm_io_close(InChannel, SM_TIME_DEFAULT);		InChannel = smioin;	}	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,			 SM_IO_RDONLY, NULL, smioin) == NULL)		sm_syslog(LOG_ERR, e->e_id,			  "disconnect: sm_io_reopen(\"%s\") failed: %s",			  SM_PATH_DEVNULL, sm_errstring(errno));	/*	**  output to the transcript	**	We also compare the fd numbers here since OutChannel	**	might be a layer on top of smioout due to encryption	**	(see sfsasl.c).	*/	if (OutChannel != smioout &&	    sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=	    sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))	{		(void) sm_io_close(OutChannel, SM_TIME_DEFAULT);		OutChannel = smioout;#if 0		/*		**  Has smioout been closed? Reopen it.		**	This shouldn't happen anymore, the code is here		**	just as a reminder.		*/		if (smioout->sm_magic == NULL &&		    sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,				 SM_IO_WRONLY, NULL, smioout) == NULL)			sm_syslog(LOG_ERR, e->e_id,				  "disconnect: sm_io_reopen(\"%s\") failed: %s",				  SM_PATH_DEVNULL, sm_errstring(errno));#endif /* 0 */	}	if (droplev > 0)	{		fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);		if (fd == -1)			sm_syslog(LOG_ERR, e->e_id,				  "disconnect: open(\"%s\") failed: %s",				  SM_PATH_DEVNULL, sm_errstring(errno));		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);		(void) dup2(fd, STDOUT_FILENO);		(void) dup2(fd, STDERR_FILENO);		(void) close(fd);	}	/* drop our controlling TTY completely if possible */	if (droplev > 1)	{		(void) setsid();		errno = 0;	}#if XDEBUG	checkfd012("disconnect");#endif /* XDEBUG */	if (LogLevel > 71)		sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",			  (int) CurrentPid);	errno = 0;}static voidobsolete(argv)	char *argv[];{	register char *ap;	register char *op;	while ((ap = *++argv) != NULL)	{		/* Return if "--" or not an option of any form. */		if (ap[0] != '-' || ap[1] == '-')			return;#if _FFR_QUARANTINE		/* Don't allow users to use "-Q." or "-Q ." */		if ((ap[1] == 'Q' && ap[2] == '.') ||		    (ap[1] == 'Q' && argv[1] != NULL &&		     argv[1][0] == '.' && argv[1][1] == '\0'))		{			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,					     "Can not use -Q.\n");			exit(EX_USAGE);		}#endif /* _FFR_QUARANTINE */		/* skip over options that do have a value */		op = strchr(OPTIONS, ap[1]);		if (op != NULL && *++op == ':' && ap[2] == '\0' &&		    ap[1] != 'd' &&#if defined(sony_news)		    ap[1] != 'E' && ap[1] != 'J' &&#endif /* defined(sony_news) */		    argv[1] != NULL && argv[1][0] != '-')		{			argv++;			continue;		}		/* If -C doesn't have an argument, use sendmail.cf. */#define __DEFPATH	"sendmail.cf"		if (ap[1] == 'C' && ap[2] == '\0')		{			*argv = xalloc(sizeof(__DEFPATH) + 2);			(void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,					   "-C", __DEFPATH);		}		/* If -q doesn't have an argument, run it once. */		if (ap[1] == 'q' && ap[2] == '\0')			*argv = "-q0";#if _FFR_QUARANTINE		/* If -Q doesn't have an argument, disable quarantining */		if (ap[1] == 'Q' && ap[2] == '\0')			*argv = "-Q.";#endif /* _FFR_QUARANTINE */		/* if -d doesn't have an argument, use 0-99.1 */		if (ap[1] == 'd' && ap[2] == '\0')			*argv = "-d0-99.1";#if defined(sony_news)		/* if -E doesn't have an argument, use -EC */		if (ap[1] == 'E' && ap[2] == '\0')			*argv = "-EC";		/* if -J doesn't have an argument, use -JJ */		if (ap[1] == 'J' && ap[2] == '\0')			*argv = "-JJ";#endif /* defined(sony_news) */	}}/***  AUTH_WARNING -- specify authorization warning****	Parameters:**		e -- the current envelope.**		msg -- the text of the message.**		args -- arguments to the message.****	Returns:**		none.*/void#ifdef __STDC__auth_warning(register ENVELOPE *e, const char *msg, ...)#else /* __STDC__ */auth_warning(e, msg, va_alist)	register ENVELOPE *e;	const char *msg;	va_dcl#endif /* __STDC__ */{	char buf[MAXLINE];	SM_VA_LOCAL_DECL	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))	{		register char *p;		static char hostbuf[48];		if (hostbuf[0] == '\0')		{			struct hostent *hp;			hp = myhostname(hostbuf, sizeof hostbuf);#if NETINET6			if (hp != NULL)			{				freehostent(hp);				hp = NULL;			}#endif /* NETINET6 */		}		(void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": ");		p = &buf[strlen(buf)];		SM_VA_START(ap, msg);		(void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);		SM_VA_END(ap);		addheader("X-Authentication-Warning", buf, 0, e);		if (LogLevel > 3)			sm_syslog(LOG_INFO, e->e_id,				  "Authentication-Warning: %.400s",				  buf);	}}/***  GETEXTENV -- get from external environment****	Parameters:**		envar -- the name of the variable to retrieve****	Returns:**		The value, if any.*/static char *getextenv(envar)	const char *envar;{	char **envp;	int l;	l = strlen(envar);	for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++)	{		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')			return &(*envp)[l + 1];	}	return NULL;}