readcf.c revision 98841
138032Speter/*
294334Sgshapiro * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
1698841SgshapiroSM_RCSID("@(#)$Id: readcf.c,v 8.607 2002/06/14 16:57:32 ca Exp $")
1764562Sgshapiro
1864562Sgshapiro#if NETINET || NETINET6
1964562Sgshapiro# include <arpa/inet.h>
2064562Sgshapiro#endif /* NETINET || NETINET6 */
2164562Sgshapiro
2264562Sgshapiro#define SECONDS
2364562Sgshapiro#define MINUTES	* 60
2464562Sgshapiro#define HOUR	* 3600
2564562Sgshapiro#define HOURS	HOUR
2664562Sgshapiro
2794334Sgshapirostatic void	fileclass __P((int, char *, char *, bool, bool, bool));
2864562Sgshapirostatic char	**makeargv __P((char *));
2964562Sgshapirostatic void	settimeout __P((char *, char *, bool));
3064562Sgshapirostatic void	toomany __P((int, int));
3190792Sgshapirostatic char	*extrquotstr __P((char *, char **, char *, bool *));
3264562Sgshapiro
3338032Speter/*
3438032Speter**  READCF -- read configuration file.
3538032Speter**
3638032Speter**	This routine reads the configuration file and builds the internal
3738032Speter**	form.
3838032Speter**
3938032Speter**	The file is formatted as a sequence of lines, each taken
4038032Speter**	atomically.  The first character of each line describes how
4138032Speter**	the line is to be interpreted.  The lines are:
4238032Speter**		Dxval		Define macro x to have value val.
4338032Speter**		Cxword		Put word into class x.
4438032Speter**		Fxfile [fmt]	Read file for lines to put into
4538032Speter**				class x.  Use scanf string 'fmt'
4638032Speter**				or "%s" if not present.  Fmt should
4738032Speter**				only produce one string-valued result.
4838032Speter**		Hname: value	Define header with field-name 'name'
4938032Speter**				and value as specified; this will be
5038032Speter**				macro expanded immediately before
5138032Speter**				use.
5238032Speter**		Sn		Use rewriting set n.
5338032Speter**		Rlhs rhs	Rewrite addresses that match lhs to
5438032Speter**				be rhs.
5538032Speter**		Mn arg=val...	Define mailer.  n is the internal name.
5638032Speter**				Args specify mailer parameters.
5738032Speter**		Oxvalue		Set option x to value.
5890792Sgshapiro**		O option value	Set option (long name) to value.
5938032Speter**		Pname=value	Set precedence name to value.
6090792Sgshapiro**		Qn arg=val...	Define queue groups.  n is the internal name.
6190792Sgshapiro**				Args specify queue parameters.
6238032Speter**		Vversioncode[/vendorcode]
6338032Speter**				Version level/vendor name of
6438032Speter**				configuration syntax.
6538032Speter**		Kmapname mapclass arguments....
6638032Speter**				Define keyed lookup of a given class.
6738032Speter**				Arguments are class dependent.
6838032Speter**		Eenvar=value	Set the environment value to the given value.
6938032Speter**
7038032Speter**	Parameters:
7138032Speter**		cfname -- configuration file name.
7290792Sgshapiro**		safe -- true if this is the system config file;
7390792Sgshapiro**			false otherwise.
7438032Speter**		e -- the main envelope.
7538032Speter**
7638032Speter**	Returns:
7738032Speter**		none.
7838032Speter**
7938032Speter**	Side Effects:
8038032Speter**		Builds several internal tables.
8138032Speter*/
8238032Speter
8338032Spetervoid
8438032Speterreadcf(cfname, safe, e)
8538032Speter	char *cfname;
8638032Speter	bool safe;
8738032Speter	register ENVELOPE *e;
8838032Speter{
8990792Sgshapiro	SM_FILE_T *cf;
9064562Sgshapiro	int ruleset = -1;
9138032Speter	char *q;
9238032Speter	struct rewrite *rwp = NULL;
9338032Speter	char *bp;
9438032Speter	auto char *ep;
9538032Speter	int nfuzzy;
9638032Speter	char *file;
9738032Speter	bool optional;
9890792Sgshapiro	bool ok;
9994334Sgshapiro	bool ismap;
10038032Speter	int mid;
10138032Speter	register char *p;
10264562Sgshapiro	long sff = SFF_OPENASROOT;
10338032Speter	struct stat statb;
10438032Speter	char buf[MAXLINE];
10538032Speter	char exbuf[MAXLINE];
10638032Speter	char pvpbuf[MAXLINE + MAXATOM];
10738032Speter	static char *null_list[1] = { NULL };
10890792Sgshapiro	extern unsigned char TokTypeNoC[];
10938032Speter
11038032Speter	FileName = cfname;
11138032Speter	LineNumber = 0;
11238032Speter
11338032Speter	if (DontLockReadFiles)
11438032Speter		sff |= SFF_NOLOCK;
11538032Speter	cf = safefopen(cfname, O_RDONLY, 0444, sff);
11638032Speter	if (cf == NULL)
11738032Speter	{
11838032Speter		syserr("cannot open");
11990792Sgshapiro		finis(false, true, EX_OSFILE);
12038032Speter	}
12138032Speter
12290792Sgshapiro	if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0)
12338032Speter	{
12438032Speter		syserr("cannot fstat");
12590792Sgshapiro		finis(false, true, EX_OSFILE);
12638032Speter	}
12738032Speter
12838032Speter	if (!S_ISREG(statb.st_mode))
12938032Speter	{
13038032Speter		syserr("not a plain file");
13190792Sgshapiro		finis(false, true, EX_OSFILE);
13238032Speter	}
13338032Speter
13438032Speter	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
13538032Speter	{
13638032Speter		if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
13790792Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
13890792Sgshapiro					     "%s: WARNING: dangerous write permissions\n",
13990792Sgshapiro					     FileName);
14038032Speter		if (LogLevel > 0)
14138032Speter			sm_syslog(LOG_CRIT, NOQID,
14264562Sgshapiro				  "%s: WARNING: dangerous write permissions",
14364562Sgshapiro				  FileName);
14438032Speter	}
14538032Speter
14690792Sgshapiro#if XLA
14738032Speter	xla_zero();
14864562Sgshapiro#endif /* XLA */
14938032Speter
15038032Speter	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
15138032Speter	{
15238032Speter		if (bp[0] == '#')
15338032Speter		{
15438032Speter			if (bp != buf)
15590792Sgshapiro				sm_free(bp); /* XXX */
15638032Speter			continue;
15738032Speter		}
15838032Speter
15938032Speter		/* do macro expansion mappings */
16038032Speter		translate_dollars(bp);
16138032Speter
16238032Speter		/* interpret this line */
16338032Speter		errno = 0;
16438032Speter		switch (bp[0])
16538032Speter		{
16638032Speter		  case '\0':
16738032Speter		  case '#':		/* comment */
16838032Speter			break;
16938032Speter
17038032Speter		  case 'R':		/* rewriting rule */
17164562Sgshapiro			if (ruleset < 0)
17264562Sgshapiro			{
17364562Sgshapiro				syserr("missing valid ruleset for \"%s\"", bp);
17464562Sgshapiro				break;
17564562Sgshapiro			}
17638032Speter			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
17738032Speter				continue;
17838032Speter
17938032Speter			if (*p == '\0')
18038032Speter			{
18138032Speter				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
18238032Speter				break;
18338032Speter			}
18438032Speter
18538032Speter			/* allocate space for the rule header */
18638032Speter			if (rwp == NULL)
18738032Speter			{
18838032Speter				RewriteRules[ruleset] = rwp =
18938032Speter					(struct rewrite *) xalloc(sizeof *rwp);
19038032Speter			}
19138032Speter			else
19238032Speter			{
19338032Speter				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
19438032Speter				rwp = rwp->r_next;
19538032Speter			}
19638032Speter			rwp->r_next = NULL;
19738032Speter
19838032Speter			/* expand and save the LHS */
19938032Speter			*p = '\0';
20038032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
20138032Speter			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
20264562Sgshapiro					     sizeof pvpbuf, NULL,
20364562Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : NULL);
20438032Speter			nfuzzy = 0;
20538032Speter			if (rwp->r_lhs != NULL)
20638032Speter			{
20738032Speter				register char **ap;
20838032Speter
20990792Sgshapiro				rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL);
21038032Speter
21138032Speter				/* count the number of fuzzy matches in LHS */
21238032Speter				for (ap = rwp->r_lhs; *ap != NULL; ap++)
21338032Speter				{
21438032Speter					char *botch;
21538032Speter
21638032Speter					botch = NULL;
21738032Speter					switch (**ap & 0377)
21838032Speter					{
21938032Speter					  case MATCHZANY:
22038032Speter					  case MATCHANY:
22138032Speter					  case MATCHONE:
22238032Speter					  case MATCHCLASS:
22338032Speter					  case MATCHNCLASS:
22438032Speter						nfuzzy++;
22538032Speter						break;
22638032Speter
22738032Speter					  case MATCHREPL:
22838032Speter						botch = "$0-$9";
22938032Speter						break;
23038032Speter
23138032Speter					  case CANONUSER:
23238032Speter						botch = "$:";
23338032Speter						break;
23438032Speter
23538032Speter					  case CALLSUBR:
23638032Speter						botch = "$>";
23738032Speter						break;
23838032Speter
23938032Speter					  case CONDIF:
24038032Speter						botch = "$?";
24138032Speter						break;
24238032Speter
24338032Speter					  case CONDFI:
24438032Speter						botch = "$.";
24538032Speter						break;
24638032Speter
24738032Speter					  case HOSTBEGIN:
24838032Speter						botch = "$[";
24938032Speter						break;
25038032Speter
25138032Speter					  case HOSTEND:
25238032Speter						botch = "$]";
25338032Speter						break;
25438032Speter
25538032Speter					  case LOOKUPBEGIN:
25638032Speter						botch = "$(";
25738032Speter						break;
25838032Speter
25938032Speter					  case LOOKUPEND:
26038032Speter						botch = "$)";
26138032Speter						break;
26238032Speter					}
26338032Speter					if (botch != NULL)
26438032Speter						syserr("Inappropriate use of %s on LHS",
26538032Speter							botch);
26638032Speter				}
26764562Sgshapiro				rwp->r_line = LineNumber;
26838032Speter			}
26938032Speter			else
27038032Speter			{
27138032Speter				syserr("R line: null LHS");
27238032Speter				rwp->r_lhs = null_list;
27338032Speter			}
27482017Sgshapiro			if (nfuzzy > MAXMATCH)
27582017Sgshapiro			{
27682017Sgshapiro				syserr("R line: too many wildcards");
27782017Sgshapiro				rwp->r_lhs = null_list;
27882017Sgshapiro			}
27938032Speter
28038032Speter			/* expand and save the RHS */
28138032Speter			while (*++p == '\t')
28238032Speter				continue;
28338032Speter			q = p;
28438032Speter			while (*p != '\0' && *p != '\t')
28538032Speter				p++;
28638032Speter			*p = '\0';
28738032Speter			expand(q, exbuf, sizeof exbuf, e);
28838032Speter			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
28964562Sgshapiro					     sizeof pvpbuf, NULL,
29064562Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : NULL);
29138032Speter			if (rwp->r_rhs != NULL)
29238032Speter			{
29338032Speter				register char **ap;
29438032Speter
29590792Sgshapiro				rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
29638032Speter
29738032Speter				/* check no out-of-bounds replacements */
29838032Speter				nfuzzy += '0';
29938032Speter				for (ap = rwp->r_rhs; *ap != NULL; ap++)
30038032Speter				{
30138032Speter					char *botch;
30238032Speter
30338032Speter					botch = NULL;
30438032Speter					switch (**ap & 0377)
30538032Speter					{
30638032Speter					  case MATCHREPL:
30738032Speter						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
30838032Speter						{
30938032Speter							syserr("replacement $%c out of bounds",
31038032Speter								(*ap)[1]);
31138032Speter						}
31238032Speter						break;
31338032Speter
31438032Speter					  case MATCHZANY:
31538032Speter						botch = "$*";
31638032Speter						break;
31738032Speter
31838032Speter					  case MATCHANY:
31938032Speter						botch = "$+";
32038032Speter						break;
32138032Speter
32238032Speter					  case MATCHONE:
32338032Speter						botch = "$-";
32438032Speter						break;
32538032Speter
32638032Speter					  case MATCHCLASS:
32738032Speter						botch = "$=";
32838032Speter						break;
32938032Speter
33038032Speter					  case MATCHNCLASS:
33138032Speter						botch = "$~";
33238032Speter						break;
33390792Sgshapiro
33490792Sgshapiro#if 0
33590792Sgshapiro/*
33690792Sgshapiro**  This doesn't work yet as there are maps defined *after* the cf
33790792Sgshapiro**  is read such as host, user, and alias.  So for now, it's removed.
33890792Sgshapiro**  When it comes back, the RELEASE_NOTES entry will be:
33990792Sgshapiro**	Emit warnings for unknown maps when reading the .cf file.  Based on
34090792Sgshapiro**		patch from Robert Harker of Harker Systems.
34190792Sgshapiro*/
34290792Sgshapiro
34390792Sgshapiro					  case LOOKUPBEGIN:
34490792Sgshapiro						/*
34590792Sgshapiro						**  Got a database lookup,
34690792Sgshapiro						**  check if map is defined.
34790792Sgshapiro						*/
34890792Sgshapiro
34990792Sgshapiro						ep = *(ap + 1);
35090792Sgshapiro						if ((*ep & 0377) != MACRODEXPAND &&
35190792Sgshapiro						    stab(ep, ST_MAP,
35290792Sgshapiro							 ST_FIND) == NULL)
35390792Sgshapiro						{
35490792Sgshapiro							(void) sm_io_fprintf(smioout,
35590792Sgshapiro									     SM_TIME_DEFAULT,
35690792Sgshapiro									     "Warning: %s: line %d: map %s not found\n",
35790792Sgshapiro									     FileName,
35890792Sgshapiro									     LineNumber,
35990792Sgshapiro									     ep);
36090792Sgshapiro						}
36190792Sgshapiro						break;
36290792Sgshapiro#endif /* 0 */
36338032Speter					}
36438032Speter					if (botch != NULL)
36538032Speter						syserr("Inappropriate use of %s on RHS",
36638032Speter							botch);
36738032Speter				}
36838032Speter			}
36938032Speter			else
37038032Speter			{
37138032Speter				syserr("R line: null RHS");
37238032Speter				rwp->r_rhs = null_list;
37338032Speter			}
37438032Speter			break;
37538032Speter
37638032Speter		  case 'S':		/* select rewriting set */
37738032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
37838032Speter			ruleset = strtorwset(exbuf, NULL, ST_ENTER);
37938032Speter			if (ruleset < 0)
38038032Speter				break;
38164562Sgshapiro
38238032Speter			rwp = RewriteRules[ruleset];
38338032Speter			if (rwp != NULL)
38438032Speter			{
38564562Sgshapiro				if (OpMode == MD_TEST)
38690792Sgshapiro					(void) sm_io_fprintf(smioout,
38790792Sgshapiro							     SM_TIME_DEFAULT,
38890792Sgshapiro							     "WARNING: Ruleset %s has multiple definitions\n",
38990792Sgshapiro							    &bp[1]);
39064562Sgshapiro				if (tTd(37, 1))
39190792Sgshapiro					sm_dprintf("WARNING: Ruleset %s has multiple definitions\n",
39290792Sgshapiro						   &bp[1]);
39338032Speter				while (rwp->r_next != NULL)
39438032Speter					rwp = rwp->r_next;
39538032Speter			}
39638032Speter			break;
39738032Speter
39838032Speter		  case 'D':		/* macro definition */
39990792Sgshapiro			mid = macid_parse(&bp[1], &ep);
40071345Sgshapiro			if (mid == 0)
40171345Sgshapiro				break;
40238032Speter			p = munchstring(ep, NULL, '\0');
40390792Sgshapiro			macdefine(&e->e_macro, A_TEMP, mid, p);
40438032Speter			break;
40538032Speter
40638032Speter		  case 'H':		/* required header line */
40764562Sgshapiro			(void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
40838032Speter			break;
40938032Speter
41038032Speter		  case 'C':		/* word class */
41138032Speter		  case 'T':		/* trusted user (set class `t') */
41238032Speter			if (bp[0] == 'C')
41338032Speter			{
41490792Sgshapiro				mid = macid_parse(&bp[1], &ep);
41571345Sgshapiro				if (mid == 0)
41671345Sgshapiro					break;
41738032Speter				expand(ep, exbuf, sizeof exbuf, e);
41838032Speter				p = exbuf;
41938032Speter			}
42038032Speter			else
42138032Speter			{
42238032Speter				mid = 't';
42338032Speter				p = &bp[1];
42438032Speter			}
42538032Speter			while (*p != '\0')
42638032Speter			{
42738032Speter				register char *wd;
42838032Speter				char delim;
42938032Speter
43038032Speter				while (*p != '\0' && isascii(*p) && isspace(*p))
43138032Speter					p++;
43238032Speter				wd = p;
43338032Speter				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
43438032Speter					p++;
43538032Speter				delim = *p;
43638032Speter				*p = '\0';
43738032Speter				if (wd[0] != '\0')
43838032Speter					setclass(mid, wd);
43938032Speter				*p = delim;
44038032Speter			}
44138032Speter			break;
44238032Speter
44338032Speter		  case 'F':		/* word class from file */
44490792Sgshapiro			mid = macid_parse(&bp[1], &ep);
44571345Sgshapiro			if (mid == 0)
44671345Sgshapiro				break;
44738032Speter			for (p = ep; isascii(*p) && isspace(*p); )
44838032Speter				p++;
44938032Speter			if (p[0] == '-' && p[1] == 'o')
45038032Speter			{
45190792Sgshapiro				optional = true;
45290792Sgshapiro				while (*p != '\0' &&
45390792Sgshapiro				       !(isascii(*p) && isspace(*p)))
45438032Speter					p++;
45538032Speter				while (isascii(*p) && isspace(*p))
45638032Speter					p++;
45790792Sgshapiro				file = p;
45838032Speter			}
45938032Speter			else
46090792Sgshapiro				optional = false;
46164562Sgshapiro
46294334Sgshapiro			/* check if [key]@map:spec */
46394334Sgshapiro			ismap = false;
46494334Sgshapiro			if (!SM_IS_DIR_DELIM(*p) &&
46594334Sgshapiro			    *p != '|' &&
46694334Sgshapiro			    (q = strchr(p, '@')) != NULL)
46790792Sgshapiro			{
46894334Sgshapiro				q++;
46994334Sgshapiro
47094334Sgshapiro				/* look for @LDAP or @map: in string */
47194334Sgshapiro				if (strcmp(q, "LDAP") == 0 ||
47294334Sgshapiro				    (*q != ':' &&
47394334Sgshapiro				     strchr(q, ':') != NULL))
47494334Sgshapiro					ismap = true;
47594334Sgshapiro			}
47694334Sgshapiro
47794334Sgshapiro			if (ismap)
47894334Sgshapiro			{
47990792Sgshapiro				/* use entire spec */
48090792Sgshapiro				file = p;
48190792Sgshapiro			}
48290792Sgshapiro			else
48390792Sgshapiro			{
48490792Sgshapiro				file = extrquotstr(p, &q, " ", &ok);
48590792Sgshapiro				if (!ok)
48690792Sgshapiro				{
48790792Sgshapiro					syserr("illegal filename '%s'", p);
48890792Sgshapiro					break;
48990792Sgshapiro				}
49090792Sgshapiro			}
49190792Sgshapiro
49294334Sgshapiro			if (*file == '|' || ismap)
49338032Speter				p = "%s";
49438032Speter			else
49538032Speter			{
49664562Sgshapiro				p = q;
49738032Speter				if (*p == '\0')
49838032Speter					p = "%s";
49938032Speter				else
50038032Speter				{
50138032Speter					*p = '\0';
50238032Speter					while (isascii(*++p) && isspace(*p))
50338032Speter						continue;
50438032Speter				}
50538032Speter			}
50694334Sgshapiro			fileclass(mid, file, p, ismap, safe, optional);
50738032Speter			break;
50838032Speter
50990792Sgshapiro#if XLA
51038032Speter		  case 'L':		/* extended load average description */
51138032Speter			xla_init(&bp[1]);
51238032Speter			break;
51364562Sgshapiro#endif /* XLA */
51438032Speter
51538032Speter#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
51638032Speter		  case 'L':		/* lookup macro */
51738032Speter		  case 'G':		/* lookup class */
51838032Speter			/* reserved for Sun -- NIS+ database lookup */
51938032Speter			if (VendorCode != VENDOR_SUN)
52038032Speter				goto badline;
52138032Speter			sun_lg_config_line(bp, e);
52238032Speter			break;
52364562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
52438032Speter
52538032Speter		  case 'M':		/* define mailer */
52638032Speter			makemailer(&bp[1]);
52738032Speter			break;
52838032Speter
52938032Speter		  case 'O':		/* set option */
53090792Sgshapiro			setoption(bp[1], &bp[2], safe, false, e);
53138032Speter			break;
53238032Speter
53338032Speter		  case 'P':		/* set precedence */
53438032Speter			if (NumPriorities >= MAXPRIORITIES)
53538032Speter			{
53638032Speter				toomany('P', MAXPRIORITIES);
53738032Speter				break;
53838032Speter			}
53938032Speter			for (p = &bp[1]; *p != '\0' && *p != '='; p++)
54038032Speter				continue;
54138032Speter			if (*p == '\0')
54238032Speter				goto badline;
54338032Speter			*p = '\0';
54438032Speter			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
54538032Speter			Priorities[NumPriorities].pri_val = atoi(++p);
54638032Speter			NumPriorities++;
54738032Speter			break;
54838032Speter
54990792Sgshapiro		  case 'Q':		/* define queue */
55090792Sgshapiro			makequeue(&bp[1], true);
55190792Sgshapiro			break;
55290792Sgshapiro
55338032Speter		  case 'V':		/* configuration syntax version */
55438032Speter			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
55538032Speter				continue;
55638032Speter			if (!isascii(*p) || !isdigit(*p))
55738032Speter			{
55864562Sgshapiro				syserr("invalid argument to V line: \"%.20s\"",
55938032Speter					&bp[1]);
56038032Speter				break;
56138032Speter			}
56238032Speter			ConfigLevel = strtol(p, &ep, 10);
56338032Speter
56438032Speter			/*
56538032Speter			**  Do heuristic tweaking for back compatibility.
56638032Speter			*/
56738032Speter
56838032Speter			if (ConfigLevel >= 5)
56938032Speter			{
57038032Speter				/* level 5 configs have short name in $w */
57138032Speter				p = macvalue('w', e);
57238032Speter				if (p != NULL && (p = strchr(p, '.')) != NULL)
57390792Sgshapiro				{
57438032Speter					*p = '\0';
57590792Sgshapiro					macdefine(&e->e_macro, A_TEMP, 'w',
57690792Sgshapiro						  macvalue('w', e));
57790792Sgshapiro				}
57838032Speter			}
57938032Speter			if (ConfigLevel >= 6)
58038032Speter			{
58190792Sgshapiro				ColonOkInAddr = false;
58238032Speter			}
58338032Speter
58438032Speter			/*
58538032Speter			**  Look for vendor code.
58638032Speter			*/
58738032Speter
58838032Speter			if (*ep++ == '/')
58938032Speter			{
59038032Speter				/* extract vendor code */
59138032Speter				for (p = ep; isascii(*p) && isalpha(*p); )
59238032Speter					p++;
59338032Speter				*p = '\0';
59438032Speter
59538032Speter				if (!setvendor(ep))
59638032Speter					syserr("invalid V line vendor code: \"%s\"",
59738032Speter						ep);
59838032Speter			}
59938032Speter			break;
60038032Speter
60138032Speter		  case 'K':
60238032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
60338032Speter			(void) makemapentry(exbuf);
60438032Speter			break;
60538032Speter
60638032Speter		  case 'E':
60738032Speter			p = strchr(bp, '=');
60838032Speter			if (p != NULL)
60938032Speter				*p++ = '\0';
61038032Speter			setuserenv(&bp[1], p);
61138032Speter			break;
61238032Speter
61364562Sgshapiro		  case 'X':		/* mail filter */
61490792Sgshapiro#if MILTER
61564562Sgshapiro			milter_setup(&bp[1]);
61690792Sgshapiro#else /* MILTER */
61790792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
61890792Sgshapiro					     "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n");
61990792Sgshapiro#endif /* MILTER */
62064562Sgshapiro			break;
62164562Sgshapiro
62238032Speter		  default:
62338032Speter		  badline:
62438032Speter			syserr("unknown configuration line \"%s\"", bp);
62538032Speter		}
62638032Speter		if (bp != buf)
62790792Sgshapiro			sm_free(bp); /* XXX */
62838032Speter	}
62990792Sgshapiro	if (sm_io_error(cf))
63038032Speter	{
63138032Speter		syserr("I/O read error");
63290792Sgshapiro		finis(false, true, EX_OSFILE);
63338032Speter	}
63490792Sgshapiro	(void) sm_io_close(cf, SM_TIME_DEFAULT);
63538032Speter	FileName = NULL;
63638032Speter
63738032Speter	/* initialize host maps from local service tables */
63838032Speter	inithostmaps();
63938032Speter
64064562Sgshapiro	/* initialize daemon (if not defined yet) */
64164562Sgshapiro	initdaemon();
64264562Sgshapiro
64338032Speter	/* determine if we need to do special name-server frotz */
64438032Speter	{
64538032Speter		int nmaps;
64638032Speter		char *maptype[MAXMAPSTACK];
64738032Speter		short mapreturn[MAXMAPACTIONS];
64838032Speter
64938032Speter		nmaps = switch_map_find("hosts", maptype, mapreturn);
65090792Sgshapiro		UseNameServer = false;
65138032Speter		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
65238032Speter		{
65338032Speter			register int mapno;
65438032Speter
65590792Sgshapiro			for (mapno = 0; mapno < nmaps && !UseNameServer;
65690792Sgshapiro			     mapno++)
65738032Speter			{
65838032Speter				if (strcmp(maptype[mapno], "dns") == 0)
65990792Sgshapiro					UseNameServer = true;
66038032Speter			}
66138032Speter		}
66238032Speter	}
66338032Speter}
66490792Sgshapiro/*
66538032Speter**  TRANSLATE_DOLLARS -- convert $x into internal form
66638032Speter**
66738032Speter**	Actually does all appropriate pre-processing of a config line
66838032Speter**	to turn it into internal form.
66938032Speter**
67038032Speter**	Parameters:
67138032Speter**		bp -- the buffer to translate.
67238032Speter**
67338032Speter**	Returns:
67438032Speter**		None.  The buffer is translated in place.  Since the
67538032Speter**		translations always make the buffer shorter, this is
67638032Speter**		safe without a size parameter.
67738032Speter*/
67838032Speter
67938032Spetervoid
68038032Spetertranslate_dollars(bp)
68138032Speter	char *bp;
68238032Speter{
68338032Speter	register char *p;
68438032Speter	auto char *ep;
68538032Speter
68638032Speter	for (p = bp; *p != '\0'; p++)
68738032Speter	{
68838032Speter		if (*p == '#' && p > bp && ConfigLevel >= 3)
68938032Speter		{
69038032Speter			register char *e;
69138032Speter
69238032Speter			switch (*--p & 0377)
69338032Speter			{
69438032Speter			  case MACROEXPAND:
69538032Speter				/* it's from $# -- let it go through */
69638032Speter				p++;
69738032Speter				break;
69838032Speter
69938032Speter			  case '\\':
70038032Speter				/* it's backslash escaped */
70190792Sgshapiro				(void) sm_strlcpy(p, p + 1, strlen(p));
70238032Speter				break;
70338032Speter
70438032Speter			  default:
70564562Sgshapiro				/* delete leading white space */
70638032Speter				while (isascii(*p) && isspace(*p) &&
70738032Speter				       *p != '\n' && p > bp)
70838032Speter					p--;
70938032Speter				if ((e = strchr(++p, '\n')) != NULL)
71090792Sgshapiro					(void) sm_strlcpy(p, e, strlen(p));
71138032Speter				else
71238032Speter					*p-- = '\0';
71338032Speter				break;
71438032Speter			}
71538032Speter			continue;
71638032Speter		}
71738032Speter
71838032Speter		if (*p != '$' || p[1] == '\0')
71938032Speter			continue;
72038032Speter
72138032Speter		if (p[1] == '$')
72238032Speter		{
72338032Speter			/* actual dollar sign.... */
72490792Sgshapiro			(void) sm_strlcpy(p, p + 1, strlen(p));
72538032Speter			continue;
72638032Speter		}
72738032Speter
72838032Speter		/* convert to macro expansion character */
72938032Speter		*p++ = MACROEXPAND;
73038032Speter
73138032Speter		/* special handling for $=, $~, $&, and $? */
73238032Speter		if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
73338032Speter			p++;
73438032Speter
73538032Speter		/* convert macro name to code */
73690792Sgshapiro		*p = macid_parse(p, &ep);
73764562Sgshapiro		if (ep != p + 1)
73890792Sgshapiro			(void) sm_strlcpy(p + 1, ep, strlen(p + 1));
73938032Speter	}
74038032Speter
74138032Speter	/* strip trailing white space from the line */
74238032Speter	while (--p > bp && isascii(*p) && isspace(*p))
74338032Speter		*p = '\0';
74438032Speter}
74590792Sgshapiro/*
74638032Speter**  TOOMANY -- signal too many of some option
74738032Speter**
74838032Speter**	Parameters:
74938032Speter**		id -- the id of the error line
75038032Speter**		maxcnt -- the maximum possible values
75138032Speter**
75238032Speter**	Returns:
75338032Speter**		none.
75438032Speter**
75538032Speter**	Side Effects:
75638032Speter**		gives a syserr.
75738032Speter*/
75838032Speter
75964562Sgshapirostatic void
76038032Spetertoomany(id, maxcnt)
76138032Speter	int id;
76238032Speter	int maxcnt;
76338032Speter{
76438032Speter	syserr("too many %c lines, %d max", id, maxcnt);
76538032Speter}
76690792Sgshapiro/*
76738032Speter**  FILECLASS -- read members of a class from a file
76838032Speter**
76938032Speter**	Parameters:
77038032Speter**		class -- class to define.
77138032Speter**		filename -- name of file to read.
77238032Speter**		fmt -- scanf string to use for match.
77394334Sgshapiro**		ismap -- if set, this is a map lookup.
77438032Speter**		safe -- if set, this is a safe read.
77538032Speter**		optional -- if set, it is not an error for the file to
77638032Speter**			not exist.
77738032Speter**
77838032Speter**	Returns:
77938032Speter**		none
78038032Speter**
78138032Speter**	Side Effects:
78238032Speter**		puts all lines in filename that match a scanf into
78338032Speter**			the named class.
78438032Speter*/
78538032Speter
78690792Sgshapiro/*
78790792Sgshapiro**  Break up the match into words and add to class.
78890792Sgshapiro*/
78990792Sgshapiro
79064562Sgshapirostatic void
79190792Sgshapiroparse_class_words(class, line)
79290792Sgshapiro	int class;
79390792Sgshapiro	char *line;
79490792Sgshapiro{
79590792Sgshapiro	while (line != NULL && *line != '\0')
79690792Sgshapiro	{
79790792Sgshapiro		register char *q;
79890792Sgshapiro
79990792Sgshapiro		/* strip leading spaces */
80090792Sgshapiro		while (isascii(*line) && isspace(*line))
80190792Sgshapiro			line++;
80290792Sgshapiro		if (*line == '\0')
80390792Sgshapiro			break;
80490792Sgshapiro
80590792Sgshapiro		/* find the end of the word */
80690792Sgshapiro		q = line;
80790792Sgshapiro		while (*line != '\0' && !(isascii(*line) && isspace(*line)))
80890792Sgshapiro			line++;
80990792Sgshapiro		if (*line != '\0')
81090792Sgshapiro			*line++ = '\0';
81190792Sgshapiro
81290792Sgshapiro		/* enter the word in the symbol table */
81390792Sgshapiro		setclass(class, q);
81490792Sgshapiro	}
81590792Sgshapiro}
81690792Sgshapiro
81790792Sgshapirostatic void
81894334Sgshapirofileclass(class, filename, fmt, ismap, safe, optional)
81938032Speter	int class;
82038032Speter	char *filename;
82138032Speter	char *fmt;
82294334Sgshapiro	bool ismap;
82338032Speter	bool safe;
82438032Speter	bool optional;
82538032Speter{
82690792Sgshapiro	SM_FILE_T *f;
82764562Sgshapiro	long sff;
82838032Speter	pid_t pid;
82938032Speter	register char *p;
83038032Speter	char buf[MAXLINE];
83138032Speter
83238032Speter	if (tTd(37, 2))
83390792Sgshapiro		sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
83438032Speter
83590792Sgshapiro	if (*filename == '\0')
83638032Speter	{
83790792Sgshapiro		syserr("fileclass: missing file name");
83890792Sgshapiro		return;
83990792Sgshapiro	}
84094334Sgshapiro	else if (ismap)
84190792Sgshapiro	{
84290792Sgshapiro		int status = 0;
84390792Sgshapiro		char *key;
84490792Sgshapiro		char *mn;
84590792Sgshapiro		char *cl, *spec;
84690792Sgshapiro		STAB *mapclass;
84790792Sgshapiro		MAP map;
84890792Sgshapiro
84990792Sgshapiro		mn = newstr(macname(class));
85090792Sgshapiro
85190792Sgshapiro		key = filename;
85290792Sgshapiro
85394334Sgshapiro		/* skip past key */
85494334Sgshapiro		if ((p = strchr(filename, '@')) == NULL)
85594334Sgshapiro		{
85694334Sgshapiro			/* should not happen */
85794334Sgshapiro			syserr("fileclass: bogus map specification");
85894334Sgshapiro			sm_free(mn);
85994334Sgshapiro			return;
86094334Sgshapiro		}
86194334Sgshapiro
86290792Sgshapiro		/* skip past '@' */
86390792Sgshapiro		*p++ = '\0';
86490792Sgshapiro		cl = p;
86590792Sgshapiro
86690792Sgshapiro		if (strcmp(cl, "LDAP") == 0)
86790792Sgshapiro		{
86890792Sgshapiro			int n;
86990792Sgshapiro			char *lc;
87090792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
87190792Sgshapiro			char lcbuf[MAXLINE];
87290792Sgshapiro
87390792Sgshapiro			/* Get $j */
87490792Sgshapiro			expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
87590792Sgshapiro			if (jbuf[0] == '\0')
87690792Sgshapiro			{
87790792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
87890792Sgshapiro						  sizeof jbuf);
87990792Sgshapiro			}
88090792Sgshapiro
88190792Sgshapiro			/* impose the default schema */
88290792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
88390792Sgshapiro			if (lc == NULL)
88490792Sgshapiro				lc = "";
88590792Sgshapiro			else
88690792Sgshapiro			{
88790792Sgshapiro				expand(lc, lcbuf, sizeof lcbuf, CurEnv);
88890792Sgshapiro				lc = lcbuf;
88990792Sgshapiro			}
89090792Sgshapiro
89190792Sgshapiro			cl = "ldap";
89290792Sgshapiro			n = sm_snprintf(buf, sizeof buf,
89390792Sgshapiro					"-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue",
89490792Sgshapiro					mn, lc, jbuf);
89590792Sgshapiro			if (n >= sizeof buf)
89690792Sgshapiro			{
89790792Sgshapiro				syserr("fileclass: F{%s}: Default LDAP string too long",
89890792Sgshapiro				       mn);
89990792Sgshapiro				sm_free(mn);
90090792Sgshapiro				return;
90190792Sgshapiro			}
90290792Sgshapiro			spec = buf;
90390792Sgshapiro		}
90490792Sgshapiro		else
90590792Sgshapiro		{
90690792Sgshapiro			if ((spec = strchr(cl, ':')) == NULL)
90790792Sgshapiro			{
90890792Sgshapiro				syserr("fileclass: F{%s}: missing map class",
90990792Sgshapiro				       mn);
91090792Sgshapiro				sm_free(mn);
91190792Sgshapiro				return;
91290792Sgshapiro			}
91390792Sgshapiro			*spec++ ='\0';
91490792Sgshapiro		}
91590792Sgshapiro
91690792Sgshapiro		/* set up map structure */
91790792Sgshapiro		mapclass = stab(cl, ST_MAPCLASS, ST_FIND);
91890792Sgshapiro		if (mapclass == NULL)
91990792Sgshapiro		{
92090792Sgshapiro			syserr("fileclass: F{%s}: class %s not available",
92190792Sgshapiro			       mn, cl);
92290792Sgshapiro			sm_free(mn);
92390792Sgshapiro			return;
92490792Sgshapiro		}
92590792Sgshapiro		memset(&map, '\0', sizeof map);
92690792Sgshapiro		map.map_class = &mapclass->s_mapclass;
92790792Sgshapiro		map.map_mname = mn;
92890792Sgshapiro		map.map_mflags |= MF_FILECLASS;
92990792Sgshapiro
93094334Sgshapiro		if (tTd(37, 5))
93194334Sgshapiro			sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
93294334Sgshapiro				   mn, cl, key, spec);
93394334Sgshapiro
93494334Sgshapiro
93590792Sgshapiro		/* parse map spec */
93690792Sgshapiro		if (!map.map_class->map_parse(&map, spec))
93790792Sgshapiro		{
93890792Sgshapiro			/* map_parse() showed the error already */
93990792Sgshapiro			sm_free(mn);
94090792Sgshapiro			return;
94190792Sgshapiro		}
94290792Sgshapiro		map.map_mflags |= MF_VALID;
94390792Sgshapiro
94490792Sgshapiro		/* open map */
94590792Sgshapiro		if (map.map_class->map_open(&map, O_RDONLY))
94690792Sgshapiro		{
94790792Sgshapiro			map.map_mflags |= MF_OPEN;
94890792Sgshapiro			map.map_pid = getpid();
94990792Sgshapiro		}
95090792Sgshapiro		else
95190792Sgshapiro		{
95290792Sgshapiro			if (!optional &&
95390792Sgshapiro			    !bitset(MF_OPTIONAL, map.map_mflags))
95490792Sgshapiro				syserr("fileclass: F{%s}: map open failed",
95590792Sgshapiro				       mn);
95690792Sgshapiro			sm_free(mn);
95790792Sgshapiro			return;
95890792Sgshapiro		}
95990792Sgshapiro
96090792Sgshapiro		/* lookup */
96190792Sgshapiro		p = (*map.map_class->map_lookup)(&map, key, NULL, &status);
96290792Sgshapiro		if (status != EX_OK && status != EX_NOTFOUND)
96390792Sgshapiro		{
96490792Sgshapiro			if (!optional)
96590792Sgshapiro				syserr("fileclass: F{%s}: map lookup failed",
96690792Sgshapiro				       mn);
96790792Sgshapiro			p = NULL;
96890792Sgshapiro		}
96990792Sgshapiro
97090792Sgshapiro		/* use the results */
97190792Sgshapiro		if (p != NULL)
97290792Sgshapiro			parse_class_words(class, p);
97390792Sgshapiro
97490792Sgshapiro		/* close map */
97590792Sgshapiro		map.map_mflags |= MF_CLOSING;
97690792Sgshapiro		map.map_class->map_close(&map);
97790792Sgshapiro		map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
97890792Sgshapiro		sm_free(mn);
97990792Sgshapiro		return;
98090792Sgshapiro	}
98190792Sgshapiro	else if (filename[0] == '|')
98290792Sgshapiro	{
98338032Speter		auto int fd;
98438032Speter		int i;
98538032Speter		char *argv[MAXPV + 1];
98638032Speter
98738032Speter		i = 0;
98890792Sgshapiro		for (p = strtok(&filename[1], " \t");
98990792Sgshapiro		     p != NULL && i < MAXPV;
99090792Sgshapiro		     p = strtok(NULL, " \t"))
99138032Speter			argv[i++] = p;
99238032Speter		argv[i] = NULL;
99338032Speter		pid = prog_open(argv, &fd, CurEnv);
99438032Speter		if (pid < 0)
99538032Speter			f = NULL;
99638032Speter		else
99790792Sgshapiro			f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
99890792Sgshapiro				       (void *) &fd, SM_IO_RDONLY, NULL);
99938032Speter	}
100038032Speter	else
100138032Speter	{
100238032Speter		pid = -1;
100338032Speter		sff = SFF_REGONLY;
100464562Sgshapiro		if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
100538032Speter			sff |= SFF_SAFEDIRPATH;
100664562Sgshapiro		if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
100764562Sgshapiro			     DontBlameSendmail))
100838032Speter			sff |= SFF_NOWLINK;
100938032Speter		if (safe)
101038032Speter			sff |= SFF_OPENASROOT;
101190792Sgshapiro		else if (RealUid == 0)
101290792Sgshapiro			sff |= SFF_ROOTOK;
101338032Speter		if (DontLockReadFiles)
101438032Speter			sff |= SFF_NOLOCK;
101538032Speter		f = safefopen(filename, O_RDONLY, 0, sff);
101638032Speter	}
101738032Speter	if (f == NULL)
101838032Speter	{
101938032Speter		if (!optional)
102064562Sgshapiro			syserr("fileclass: cannot open '%s'", filename);
102138032Speter		return;
102238032Speter	}
102338032Speter
102490792Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
102538032Speter	{
102664562Sgshapiro#if SCANF
102738032Speter		char wordbuf[MAXLINE + 1];
102864562Sgshapiro#endif /* SCANF */
102938032Speter
103038032Speter		if (buf[0] == '#')
103138032Speter			continue;
103264562Sgshapiro#if SCANF
103390792Sgshapiro		if (sm_io_sscanf(buf, fmt, wordbuf) != 1)
103438032Speter			continue;
103538032Speter		p = wordbuf;
103664562Sgshapiro#else /* SCANF */
103738032Speter		p = buf;
103864562Sgshapiro#endif /* SCANF */
103938032Speter
104090792Sgshapiro		parse_class_words(class, p);
104190792Sgshapiro
104238032Speter		/*
104390792Sgshapiro		**  If anything else is added here,
104490792Sgshapiro		**  check if the '@' map case above
104590792Sgshapiro		**  needs the code as well.
104638032Speter		*/
104738032Speter	}
104838032Speter
104990792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
105038032Speter	if (pid > 0)
105138032Speter		(void) waitfor(pid);
105238032Speter}
105390792Sgshapiro/*
105438032Speter**  MAKEMAILER -- define a new mailer.
105538032Speter**
105638032Speter**	Parameters:
105738032Speter**		line -- description of mailer.  This is in labeled
105838032Speter**			fields.  The fields are:
105938032Speter**			   A -- the argv for this mailer
106038032Speter**			   C -- the character set for MIME conversions
106138032Speter**			   D -- the directory to run in
106238032Speter**			   E -- the eol string
106338032Speter**			   F -- the flags associated with the mailer
106438032Speter**			   L -- the maximum line length
106538032Speter**			   M -- the maximum message size
106638032Speter**			   N -- the niceness at which to run
106738032Speter**			   P -- the path to the mailer
106890792Sgshapiro**			   Q -- the queue group for the mailer
106938032Speter**			   R -- the recipient rewriting set
107038032Speter**			   S -- the sender rewriting set
107138032Speter**			   T -- the mailer type (for DSNs)
107238032Speter**			   U -- the uid to run as
107364562Sgshapiro**			   W -- the time to wait at the end
107473188Sgshapiro**			   m -- maximum messages per connection
107590792Sgshapiro**			   r -- maximum number of recipients per message
107673188Sgshapiro**			   / -- new root directory
107738032Speter**			The first word is the canonical name of the mailer.
107838032Speter**
107938032Speter**	Returns:
108038032Speter**		none.
108138032Speter**
108238032Speter**	Side Effects:
108338032Speter**		enters the mailer into the mailer table.
108438032Speter*/
108538032Speter
108638032Spetervoid
108738032Spetermakemailer(line)
108838032Speter	char *line;
108938032Speter{
109038032Speter	register char *p;
109138032Speter	register struct mailer *m;
109238032Speter	register STAB *s;
109338032Speter	int i;
109438032Speter	char fcode;
109538032Speter	auto char *endp;
109690792Sgshapiro	static int nextmailer = 0;	/* "free" index into Mailer struct */
109738032Speter
109838032Speter	/* allocate a mailer and set up defaults */
109938032Speter	m = (struct mailer *) xalloc(sizeof *m);
110064562Sgshapiro	memset((char *) m, '\0', sizeof *m);
110190792Sgshapiro	errno = 0; /* avoid bogus error text */
110238032Speter
110338032Speter	/* collect the mailer name */
110490792Sgshapiro	for (p = line;
110590792Sgshapiro	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
110690792Sgshapiro	     p++)
110738032Speter		continue;
110838032Speter	if (*p != '\0')
110938032Speter		*p++ = '\0';
111038032Speter	if (line[0] == '\0')
111171345Sgshapiro	{
111238032Speter		syserr("name required for mailer");
111371345Sgshapiro		return;
111471345Sgshapiro	}
111538032Speter	m->m_name = newstr(line);
111694334Sgshapiro	m->m_qgrp = NOQGRP;
111738032Speter
111838032Speter	/* now scan through and assign info from the fields */
111938032Speter	while (*p != '\0')
112038032Speter	{
112138032Speter		auto char *delimptr;
112238032Speter
112390792Sgshapiro		while (*p != '\0' &&
112490792Sgshapiro		       (*p == ',' || (isascii(*p) && isspace(*p))))
112538032Speter			p++;
112638032Speter
112738032Speter		/* p now points to field code */
112838032Speter		fcode = *p;
112938032Speter		while (*p != '\0' && *p != '=' && *p != ',')
113038032Speter			p++;
113138032Speter		if (*p++ != '=')
113238032Speter		{
113338032Speter			syserr("mailer %s: `=' expected", m->m_name);
113438032Speter			return;
113538032Speter		}
113638032Speter		while (isascii(*p) && isspace(*p))
113738032Speter			p++;
113838032Speter
113938032Speter		/* p now points to the field body */
114038032Speter		p = munchstring(p, &delimptr, ',');
114138032Speter
114238032Speter		/* install the field into the mailer struct */
114338032Speter		switch (fcode)
114438032Speter		{
114538032Speter		  case 'P':		/* pathname */
114690792Sgshapiro			if (*p != '\0')	/* error is issued below */
114771345Sgshapiro				m->m_mailer = newstr(p);
114838032Speter			break;
114938032Speter
115038032Speter		  case 'F':		/* flags */
115138032Speter			for (; *p != '\0'; p++)
115290792Sgshapiro			{
115338032Speter				if (!(isascii(*p) && isspace(*p)))
115490792Sgshapiro				{
115590792Sgshapiro#if _FFR_DEPRECATE_MAILER_FLAG_I
115690792Sgshapiro					if (*p == M_INTERNAL)
115790792Sgshapiro						sm_syslog(LOG_WARNING, NOQID,
115890792Sgshapiro							  "WARNING: mailer=%s, flag=%c deprecated",
115990792Sgshapiro							  m->m_name, *p);
116090792Sgshapiro#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
116171345Sgshapiro					setbitn(bitidx(*p), m->m_flags);
116290792Sgshapiro				}
116390792Sgshapiro			}
116438032Speter			break;
116538032Speter
116638032Speter		  case 'S':		/* sender rewriting ruleset */
116738032Speter		  case 'R':		/* recipient rewriting ruleset */
116838032Speter			i = strtorwset(p, &endp, ST_ENTER);
116938032Speter			if (i < 0)
117038032Speter				return;
117138032Speter			if (fcode == 'S')
117238032Speter				m->m_sh_rwset = m->m_se_rwset = i;
117338032Speter			else
117438032Speter				m->m_rh_rwset = m->m_re_rwset = i;
117538032Speter
117638032Speter			p = endp;
117738032Speter			if (*p++ == '/')
117838032Speter			{
117938032Speter				i = strtorwset(p, NULL, ST_ENTER);
118038032Speter				if (i < 0)
118138032Speter					return;
118238032Speter				if (fcode == 'S')
118338032Speter					m->m_sh_rwset = i;
118438032Speter				else
118538032Speter					m->m_rh_rwset = i;
118638032Speter			}
118738032Speter			break;
118838032Speter
118938032Speter		  case 'E':		/* end of line string */
119038032Speter			if (*p == '\0')
119138032Speter				syserr("mailer %s: null end-of-line string",
119238032Speter					m->m_name);
119371345Sgshapiro			else
119471345Sgshapiro				m->m_eol = newstr(p);
119538032Speter			break;
119638032Speter
119738032Speter		  case 'A':		/* argument vector */
119890792Sgshapiro			if (*p != '\0')	/* error is issued below */
119971345Sgshapiro				m->m_argv = makeargv(p);
120038032Speter			break;
120138032Speter
120238032Speter		  case 'M':		/* maximum message size */
120338032Speter			m->m_maxsize = atol(p);
120438032Speter			break;
120538032Speter
120664562Sgshapiro		  case 'm':		/* maximum messages per connection */
120764562Sgshapiro			m->m_maxdeliveries = atoi(p);
120864562Sgshapiro			break;
120964562Sgshapiro
121064562Sgshapiro		  case 'r':		/* max recipient per envelope */
121164562Sgshapiro			m->m_maxrcpt = atoi(p);
121264562Sgshapiro			break;
121364562Sgshapiro
121438032Speter		  case 'L':		/* maximum line length */
121538032Speter			m->m_linelimit = atoi(p);
121638032Speter			if (m->m_linelimit < 0)
121738032Speter				m->m_linelimit = 0;
121838032Speter			break;
121938032Speter
122038032Speter		  case 'N':		/* run niceness */
122138032Speter			m->m_nice = atoi(p);
122238032Speter			break;
122338032Speter
122438032Speter		  case 'D':		/* working directory */
122538032Speter			if (*p == '\0')
122638032Speter				syserr("mailer %s: null working directory",
122738032Speter					m->m_name);
122871345Sgshapiro			else
122971345Sgshapiro				m->m_execdir = newstr(p);
123038032Speter			break;
123138032Speter
123238032Speter		  case 'C':		/* default charset */
123338032Speter			if (*p == '\0')
123438032Speter				syserr("mailer %s: null charset", m->m_name);
123571345Sgshapiro			else
123671345Sgshapiro				m->m_defcharset = newstr(p);
123738032Speter			break;
123838032Speter
123990792Sgshapiro		  case 'Q':		/* queue for this mailer */
124090792Sgshapiro			if (*p == '\0')
124190792Sgshapiro			{
124290792Sgshapiro				syserr("mailer %s: null queue", m->m_name);
124390792Sgshapiro				break;
124490792Sgshapiro			}
124590792Sgshapiro			s = stab(p, ST_QUEUE, ST_FIND);
124690792Sgshapiro			if (s == NULL)
124790792Sgshapiro				syserr("mailer %s: unknown queue %s",
124890792Sgshapiro					m->m_name, p);
124990792Sgshapiro			else
125090792Sgshapiro				m->m_qgrp = s->s_quegrp->qg_index;
125190792Sgshapiro			break;
125290792Sgshapiro
125338032Speter		  case 'T':		/* MTA-Name/Address/Diagnostic types */
125438032Speter			/* extract MTA name type; default to "dns" */
125538032Speter			m->m_mtatype = newstr(p);
125638032Speter			p = strchr(m->m_mtatype, '/');
125738032Speter			if (p != NULL)
125838032Speter			{
125938032Speter				*p++ = '\0';
126038032Speter				if (*p == '\0')
126138032Speter					p = NULL;
126238032Speter			}
126338032Speter			if (*m->m_mtatype == '\0')
126438032Speter				m->m_mtatype = "dns";
126538032Speter
126638032Speter			/* extract address type; default to "rfc822" */
126738032Speter			m->m_addrtype = p;
126838032Speter			if (p != NULL)
126938032Speter				p = strchr(p, '/');
127038032Speter			if (p != NULL)
127138032Speter			{
127238032Speter				*p++ = '\0';
127338032Speter				if (*p == '\0')
127438032Speter					p = NULL;
127538032Speter			}
127638032Speter			if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
127738032Speter				m->m_addrtype = "rfc822";
127838032Speter
127938032Speter			/* extract diagnostic type; default to "smtp" */
128038032Speter			m->m_diagtype = p;
128138032Speter			if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
128238032Speter				m->m_diagtype = "smtp";
128338032Speter			break;
128438032Speter
128538032Speter		  case 'U':		/* user id */
128638032Speter			if (isascii(*p) && !isdigit(*p))
128738032Speter			{
128838032Speter				char *q = p;
128938032Speter				struct passwd *pw;
129038032Speter
129138032Speter				while (*p != '\0' && isascii(*p) &&
129238032Speter				       (isalnum(*p) || strchr("-_", *p) != NULL))
129338032Speter					p++;
129438032Speter				while (isascii(*p) && isspace(*p))
129538032Speter					*p++ = '\0';
129638032Speter				if (*p != '\0')
129738032Speter					*p++ = '\0';
129838032Speter				if (*q == '\0')
129971345Sgshapiro				{
130038032Speter					syserr("mailer %s: null user name",
130138032Speter						m->m_name);
130271345Sgshapiro					break;
130371345Sgshapiro				}
130438032Speter				pw = sm_getpwnam(q);
130538032Speter				if (pw == NULL)
130671345Sgshapiro				{
130738032Speter					syserr("readcf: mailer U= flag: unknown user %s", q);
130871345Sgshapiro					break;
130971345Sgshapiro				}
131038032Speter				else
131138032Speter				{
131238032Speter					m->m_uid = pw->pw_uid;
131338032Speter					m->m_gid = pw->pw_gid;
131438032Speter				}
131538032Speter			}
131638032Speter			else
131738032Speter			{
131838032Speter				auto char *q;
131938032Speter
132038032Speter				m->m_uid = strtol(p, &q, 0);
132138032Speter				p = q;
132238032Speter				while (isascii(*p) && isspace(*p))
132338032Speter					p++;
132438032Speter				if (*p != '\0')
132538032Speter					p++;
132638032Speter			}
132738032Speter			while (isascii(*p) && isspace(*p))
132838032Speter				p++;
132938032Speter			if (*p == '\0')
133038032Speter				break;
133138032Speter			if (isascii(*p) && !isdigit(*p))
133238032Speter			{
133338032Speter				char *q = p;
133438032Speter				struct group *gr;
133538032Speter
133638032Speter				while (isascii(*p) && isalnum(*p))
133738032Speter					p++;
133838032Speter				*p++ = '\0';
133938032Speter				if (*q == '\0')
134071345Sgshapiro				{
134138032Speter					syserr("mailer %s: null group name",
134238032Speter						m->m_name);
134371345Sgshapiro					break;
134471345Sgshapiro				}
134538032Speter				gr = getgrnam(q);
134638032Speter				if (gr == NULL)
134771345Sgshapiro				{
134838032Speter					syserr("readcf: mailer U= flag: unknown group %s", q);
134971345Sgshapiro					break;
135071345Sgshapiro				}
135138032Speter				else
135238032Speter					m->m_gid = gr->gr_gid;
135338032Speter			}
135438032Speter			else
135538032Speter			{
135638032Speter				m->m_gid = strtol(p, NULL, 0);
135738032Speter			}
135838032Speter			break;
135964562Sgshapiro
136064562Sgshapiro		  case 'W':		/* wait timeout */
136164562Sgshapiro			m->m_wait = convtime(p, 's');
136264562Sgshapiro			break;
136364562Sgshapiro
136464562Sgshapiro		  case '/':		/* new root directory */
136564562Sgshapiro			if (*p == '\0')
136664562Sgshapiro				syserr("mailer %s: null root directory",
136764562Sgshapiro					m->m_name);
136864562Sgshapiro			else
136964562Sgshapiro				m->m_rootdir = newstr(p);
137064562Sgshapiro			break;
137164562Sgshapiro
137264562Sgshapiro		  default:
137364562Sgshapiro			syserr("M%s: unknown mailer equate %c=",
137464562Sgshapiro			       m->m_name, fcode);
137564562Sgshapiro			break;
137638032Speter		}
137738032Speter
137838032Speter		p = delimptr;
137938032Speter	}
138038032Speter
138190792Sgshapiro#if !HASRRESVPORT
138290792Sgshapiro	if (bitnset(M_SECURE_PORT, m->m_flags))
138390792Sgshapiro	{
138490792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
138590792Sgshapiro				     "M%s: Warning: F=%c set on system that doesn't support rresvport()\n",
138690792Sgshapiro				     m->m_name, M_SECURE_PORT);
138790792Sgshapiro	}
138890792Sgshapiro#endif /* !HASRRESVPORT */
138990792Sgshapiro
139090792Sgshapiro#if !HASNICE
139190792Sgshapiro	if (m->m_nice != 0)
139290792Sgshapiro	{
139390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
139490792Sgshapiro				     "M%s: Warning: N= set on system that doesn't support nice()\n",
139590792Sgshapiro				     m->m_name);
139690792Sgshapiro	}
139790792Sgshapiro#endif /* !HASNICE */
139890792Sgshapiro
139938032Speter	/* do some rationality checking */
140038032Speter	if (m->m_argv == NULL)
140138032Speter	{
140238032Speter		syserr("M%s: A= argument required", m->m_name);
140338032Speter		return;
140438032Speter	}
140538032Speter	if (m->m_mailer == NULL)
140638032Speter	{
140738032Speter		syserr("M%s: P= argument required", m->m_name);
140838032Speter		return;
140938032Speter	}
141038032Speter
141190792Sgshapiro	if (nextmailer >= MAXMAILERS)
141238032Speter	{
141338032Speter		syserr("too many mailers defined (%d max)", MAXMAILERS);
141438032Speter		return;
141538032Speter	}
141638032Speter
141764562Sgshapiro	if (m->m_maxrcpt <= 0)
141864562Sgshapiro		m->m_maxrcpt = DEFAULT_MAX_RCPT;
141964562Sgshapiro
142038032Speter	/* do some heuristic cleanup for back compatibility */
142138032Speter	if (bitnset(M_LIMITS, m->m_flags))
142238032Speter	{
142338032Speter		if (m->m_linelimit == 0)
142438032Speter			m->m_linelimit = SMTPLINELIM;
142538032Speter		if (ConfigLevel < 2)
142638032Speter			setbitn(M_7BITS, m->m_flags);
142738032Speter	}
142838032Speter
142964562Sgshapiro	if (strcmp(m->m_mailer, "[TCP]") == 0)
143038032Speter	{
143190792Sgshapiro		syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name);
143271345Sgshapiro		return;
143338032Speter	}
143438032Speter
143590792Sgshapiro	if (strcmp(m->m_mailer, "[IPC]") == 0)
143638032Speter	{
143764562Sgshapiro		/* Use the second argument for host or path to socket */
143864562Sgshapiro		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
143964562Sgshapiro		    m->m_argv[1][0] == '\0')
144064562Sgshapiro		{
144164562Sgshapiro			syserr("M%s: too few parameters for %s mailer",
144264562Sgshapiro			       m->m_name, m->m_mailer);
144371345Sgshapiro			return;
144464562Sgshapiro		}
144566494Sgshapiro		if (strcmp(m->m_argv[0], "TCP") != 0
144664562Sgshapiro#if NETUNIX
144766494Sgshapiro		    && strcmp(m->m_argv[0], "FILE") != 0
144864562Sgshapiro#endif /* NETUNIX */
144964562Sgshapiro		    )
145064562Sgshapiro		{
145190792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
145290792Sgshapiro					     "M%s: Warning: first argument in %s mailer must be %s\n",
145390792Sgshapiro					     m->m_name, m->m_mailer,
145464562Sgshapiro#if NETUNIX
145590792Sgshapiro					     "TCP or FILE"
145664562Sgshapiro#else /* NETUNIX */
145790792Sgshapiro					     "TCP"
145864562Sgshapiro#endif /* NETUNIX */
145990792Sgshapiro				     );
146064562Sgshapiro		}
146190792Sgshapiro		if (m->m_mtatype == NULL)
146290792Sgshapiro			m->m_mtatype = "dns";
146390792Sgshapiro		if (m->m_addrtype == NULL)
146490792Sgshapiro			m->m_addrtype = "rfc822";
146590792Sgshapiro		if (m->m_diagtype == NULL)
146690792Sgshapiro		{
146790792Sgshapiro			if (m->m_argv[0] != NULL &&
146890792Sgshapiro			    strcmp(m->m_argv[0], "FILE") == 0)
146990792Sgshapiro				m->m_diagtype = "x-unix";
147090792Sgshapiro			else
147190792Sgshapiro				m->m_diagtype = "smtp";
147290792Sgshapiro		}
147364562Sgshapiro	}
147464562Sgshapiro	else if (strcmp(m->m_mailer, "[FILE]") == 0)
147564562Sgshapiro	{
147638032Speter		/* Use the second argument for filename */
147738032Speter		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
147838032Speter		    m->m_argv[2] != NULL)
147938032Speter		{
148038032Speter			syserr("M%s: too %s parameters for [FILE] mailer",
148138032Speter			       m->m_name,
148238032Speter			       (m->m_argv[0] == NULL ||
148338032Speter				m->m_argv[1] == NULL) ? "few" : "many");
148471345Sgshapiro			return;
148538032Speter		}
148638032Speter		else if (strcmp(m->m_argv[0], "FILE") != 0)
148738032Speter		{
148838032Speter			syserr("M%s: first argument in [FILE] mailer must be FILE",
148938032Speter			       m->m_name);
149071345Sgshapiro			return;
149138032Speter		}
149238032Speter	}
149338032Speter
149438032Speter	if (m->m_eol == NULL)
149538032Speter	{
149638032Speter		char **pp;
149738032Speter
149838032Speter		/* default for SMTP is \r\n; use \n for local delivery */
149938032Speter		for (pp = m->m_argv; *pp != NULL; pp++)
150038032Speter		{
150138032Speter			for (p = *pp; *p != '\0'; )
150238032Speter			{
150338032Speter				if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
150438032Speter					break;
150538032Speter			}
150638032Speter			if (*p != '\0')
150738032Speter				break;
150838032Speter		}
150938032Speter		if (*pp == NULL)
151038032Speter			m->m_eol = "\r\n";
151138032Speter		else
151238032Speter			m->m_eol = "\n";
151338032Speter	}
151438032Speter
151538032Speter	/* enter the mailer into the symbol table */
151638032Speter	s = stab(m->m_name, ST_MAILER, ST_ENTER);
151738032Speter	if (s->s_mailer != NULL)
151838032Speter	{
151938032Speter		i = s->s_mailer->m_mno;
152090792Sgshapiro		sm_free(s->s_mailer); /* XXX */
152138032Speter	}
152238032Speter	else
152338032Speter	{
152490792Sgshapiro		i = nextmailer++;
152538032Speter	}
152638032Speter	Mailer[i] = s->s_mailer = m;
152738032Speter	m->m_mno = i;
152838032Speter}
152990792Sgshapiro/*
153038032Speter**  MUNCHSTRING -- translate a string into internal form.
153138032Speter**
153238032Speter**	Parameters:
153338032Speter**		p -- the string to munch.
153438032Speter**		delimptr -- if non-NULL, set to the pointer of the
153538032Speter**			field delimiter character.
153638032Speter**		delim -- the delimiter for the field.
153738032Speter**
153838032Speter**	Returns:
153938032Speter**		the munched string.
154064562Sgshapiro**
154164562Sgshapiro**	Side Effects:
154264562Sgshapiro**		the munched string is a local static buffer.
154364562Sgshapiro**		it must be copied before the function is called again.
154438032Speter*/
154538032Speter
154638032Speterchar *
154738032Spetermunchstring(p, delimptr, delim)
154838032Speter	register char *p;
154938032Speter	char **delimptr;
155038032Speter	int delim;
155138032Speter{
155238032Speter	register char *q;
155390792Sgshapiro	bool backslash = false;
155490792Sgshapiro	bool quotemode = false;
155538032Speter	static char buf[MAXLINE];
155638032Speter
155738032Speter	for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
155838032Speter	{
155938032Speter		if (backslash)
156038032Speter		{
156138032Speter			/* everything is roughly literal */
156290792Sgshapiro			backslash = false;
156338032Speter			switch (*p)
156438032Speter			{
156538032Speter			  case 'r':		/* carriage return */
156638032Speter				*q++ = '\r';
156738032Speter				continue;
156838032Speter
156938032Speter			  case 'n':		/* newline */
157038032Speter				*q++ = '\n';
157138032Speter				continue;
157238032Speter
157338032Speter			  case 'f':		/* form feed */
157438032Speter				*q++ = '\f';
157538032Speter				continue;
157638032Speter
157738032Speter			  case 'b':		/* backspace */
157838032Speter				*q++ = '\b';
157938032Speter				continue;
158038032Speter			}
158138032Speter			*q++ = *p;
158238032Speter		}
158338032Speter		else
158438032Speter		{
158538032Speter			if (*p == '\\')
158690792Sgshapiro				backslash = true;
158738032Speter			else if (*p == '"')
158838032Speter				quotemode = !quotemode;
158938032Speter			else if (quotemode || *p != delim)
159038032Speter				*q++ = *p;
159138032Speter			else
159238032Speter				break;
159338032Speter		}
159438032Speter	}
159538032Speter
159638032Speter	if (delimptr != NULL)
159738032Speter		*delimptr = p;
159838032Speter	*q++ = '\0';
159964562Sgshapiro	return buf;
160038032Speter}
160190792Sgshapiro/*
160290792Sgshapiro**  EXTRQUOTSTR -- extract a (quoted) string.
160390792Sgshapiro**
160490792Sgshapiro**	This routine deals with quoted (") strings and escaped
160590792Sgshapiro**	spaces (\\ ).
160690792Sgshapiro**
160790792Sgshapiro**	Parameters:
160890792Sgshapiro**		p -- source string.
160990792Sgshapiro**		delimptr -- if non-NULL, set to the pointer of the
161090792Sgshapiro**			field delimiter character.
161190792Sgshapiro**		delimbuf -- delimiters for the field.
161290792Sgshapiro**		st -- if non-NULL, store the return value (whether the
161390792Sgshapiro**			string was correctly quoted) here.
161490792Sgshapiro**
161590792Sgshapiro**	Returns:
161690792Sgshapiro**		the extracted string.
161790792Sgshapiro**
161890792Sgshapiro**	Side Effects:
161990792Sgshapiro**		the returned string is a local static buffer.
162090792Sgshapiro**		it must be copied before the function is called again.
162190792Sgshapiro*/
162290792Sgshapiro
162390792Sgshapirostatic char *
162490792Sgshapiroextrquotstr(p, delimptr, delimbuf, st)
162590792Sgshapiro	register char *p;
162690792Sgshapiro	char **delimptr;
162790792Sgshapiro	char *delimbuf;
162890792Sgshapiro	bool *st;
162990792Sgshapiro{
163090792Sgshapiro	register char *q;
163190792Sgshapiro	bool backslash = false;
163290792Sgshapiro	bool quotemode = false;
163390792Sgshapiro	static char buf[MAXLINE];
163490792Sgshapiro
163590792Sgshapiro	for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
163690792Sgshapiro	{
163790792Sgshapiro		if (backslash)
163890792Sgshapiro		{
163990792Sgshapiro			backslash = false;
164090792Sgshapiro			if (*p != ' ')
164190792Sgshapiro				*q++ = '\\';
164290792Sgshapiro		}
164390792Sgshapiro		if (*p == '\\')
164490792Sgshapiro			backslash = true;
164590792Sgshapiro		else if (*p == '"')
164690792Sgshapiro			quotemode = !quotemode;
164790792Sgshapiro		else if (quotemode ||
164890792Sgshapiro			 strchr(delimbuf, (int) *p) == NULL)
164990792Sgshapiro			*q++ = *p;
165090792Sgshapiro		else
165190792Sgshapiro			break;
165290792Sgshapiro	}
165390792Sgshapiro
165490792Sgshapiro	if (delimptr != NULL)
165590792Sgshapiro		*delimptr = p;
165690792Sgshapiro	*q++ = '\0';
165790792Sgshapiro	if (st != NULL)
165890792Sgshapiro		*st = !(quotemode || backslash);
165990792Sgshapiro	return buf;
166090792Sgshapiro}
166190792Sgshapiro/*
166238032Speter**  MAKEARGV -- break up a string into words
166338032Speter**
166438032Speter**	Parameters:
166538032Speter**		p -- the string to break up.
166638032Speter**
166738032Speter**	Returns:
166838032Speter**		a char **argv (dynamically allocated)
166938032Speter**
167038032Speter**	Side Effects:
167138032Speter**		munges p.
167238032Speter*/
167338032Speter
167464562Sgshapirostatic char **
167538032Spetermakeargv(p)
167638032Speter	register char *p;
167738032Speter{
167838032Speter	char *q;
167938032Speter	int i;
168038032Speter	char **avp;
168138032Speter	char *argv[MAXPV + 1];
168238032Speter
168338032Speter	/* take apart the words */
168438032Speter	i = 0;
168538032Speter	while (*p != '\0' && i < MAXPV)
168638032Speter	{
168738032Speter		q = p;
168838032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
168938032Speter			p++;
169038032Speter		while (isascii(*p) && isspace(*p))
169138032Speter			*p++ = '\0';
169238032Speter		argv[i++] = newstr(q);
169338032Speter	}
169438032Speter	argv[i++] = NULL;
169538032Speter
169638032Speter	/* now make a copy of the argv */
169738032Speter	avp = (char **) xalloc(sizeof *avp * i);
169864562Sgshapiro	memmove((char *) avp, (char *) argv, sizeof *avp * i);
169938032Speter
170064562Sgshapiro	return avp;
170138032Speter}
170290792Sgshapiro/*
170338032Speter**  PRINTRULES -- print rewrite rules (for debugging)
170438032Speter**
170538032Speter**	Parameters:
170638032Speter**		none.
170738032Speter**
170838032Speter**	Returns:
170938032Speter**		none.
171038032Speter**
171138032Speter**	Side Effects:
171238032Speter**		prints rewrite rules.
171338032Speter*/
171438032Speter
171538032Spetervoid
171638032Speterprintrules()
171738032Speter{
171838032Speter	register struct rewrite *rwp;
171938032Speter	register int ruleset;
172038032Speter
172138032Speter	for (ruleset = 0; ruleset < 10; ruleset++)
172238032Speter	{
172338032Speter		if (RewriteRules[ruleset] == NULL)
172438032Speter			continue;
172590792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
172690792Sgshapiro				     "\n----Rule Set %d:", ruleset);
172738032Speter
172838032Speter		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
172938032Speter		{
173090792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
173190792Sgshapiro					     "\nLHS:");
173238032Speter			printav(rwp->r_lhs);
173390792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
173490792Sgshapiro					     "RHS:");
173538032Speter			printav(rwp->r_rhs);
173638032Speter		}
173738032Speter	}
173838032Speter}
173990792Sgshapiro/*
174038032Speter**  PRINTMAILER -- print mailer structure (for debugging)
174138032Speter**
174238032Speter**	Parameters:
174338032Speter**		m -- the mailer to print
174438032Speter**
174538032Speter**	Returns:
174638032Speter**		none.
174738032Speter*/
174838032Speter
174938032Spetervoid
175038032Speterprintmailer(m)
175138032Speter	register MAILER *m;
175238032Speter{
175338032Speter	int j;
175438032Speter
175590792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
175690792Sgshapiro			     "mailer %d (%s): P=%s S=", m->m_mno, m->m_name,
175790792Sgshapiro			     m->m_mailer);
175864562Sgshapiro	if (RuleSetNames[m->m_se_rwset] == NULL)
175990792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/",
176090792Sgshapiro				     m->m_se_rwset);
176164562Sgshapiro	else
176290792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/",
176390792Sgshapiro				     RuleSetNames[m->m_se_rwset]);
176464562Sgshapiro	if (RuleSetNames[m->m_sh_rwset] == NULL)
176590792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d R=",
176690792Sgshapiro				     m->m_sh_rwset);
176764562Sgshapiro	else
176890792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s R=",
176990792Sgshapiro				     RuleSetNames[m->m_sh_rwset]);
177064562Sgshapiro	if (RuleSetNames[m->m_re_rwset] == NULL)
177190792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/",
177290792Sgshapiro				     m->m_re_rwset);
177364562Sgshapiro	else
177490792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/",
177590792Sgshapiro				     RuleSetNames[m->m_re_rwset]);
177664562Sgshapiro	if (RuleSetNames[m->m_rh_rwset] == NULL)
177790792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d ",
177890792Sgshapiro				     m->m_rh_rwset);
177964562Sgshapiro	else
178090792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s ",
178190792Sgshapiro				     RuleSetNames[m->m_rh_rwset]);
178290792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=",
178390792Sgshapiro			     m->m_maxsize, (int) m->m_uid, (int) m->m_gid);
178438032Speter	for (j = '\0'; j <= '\177'; j++)
178538032Speter		if (bitnset(j, m->m_flags))
178690792Sgshapiro			(void) sm_io_putc(smioout, SM_TIME_DEFAULT, j);
178790792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " L=%d E=",
178890792Sgshapiro			     m->m_linelimit);
178938032Speter	xputs(m->m_eol);
179038032Speter	if (m->m_defcharset != NULL)
179190792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " C=%s",
179290792Sgshapiro				     m->m_defcharset);
179390792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " T=%s/%s/%s",
179490792Sgshapiro			     m->m_mtatype == NULL
179590792Sgshapiro				? "<undefined>" : m->m_mtatype,
179690792Sgshapiro			     m->m_addrtype == NULL
179790792Sgshapiro				? "<undefined>" : m->m_addrtype,
179890792Sgshapiro			     m->m_diagtype == NULL
179990792Sgshapiro				? "<undefined>" : m->m_diagtype);
180090792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt);
180138032Speter	if (m->m_argv != NULL)
180238032Speter	{
180338032Speter		char **a = m->m_argv;
180438032Speter
180590792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " A=");
180638032Speter		while (*a != NULL)
180738032Speter		{
180838032Speter			if (a != m->m_argv)
180990792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
181090792Sgshapiro						     " ");
181138032Speter			xputs(*a++);
181238032Speter		}
181338032Speter	}
181490792Sgshapiro	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
181538032Speter}
181690792Sgshapiro/*
181738032Speter**  SETOPTION -- set global processing option
181838032Speter**
181938032Speter**	Parameters:
182038032Speter**		opt -- option name.
182138032Speter**		val -- option value (as a text string).
182238032Speter**		safe -- set if this came from a configuration file.
182338032Speter**			Some options (if set from the command line) will
182438032Speter**			reset the user id to avoid security problems.
182538032Speter**		sticky -- if set, don't let other setoptions override
182638032Speter**			this value.
182738032Speter**		e -- the main envelope.
182838032Speter**
182938032Speter**	Returns:
183038032Speter**		none.
183138032Speter**
183238032Speter**	Side Effects:
183338032Speter**		Sets options as implied by the arguments.
183438032Speter*/
183538032Speter
183664562Sgshapirostatic BITMAP256	StickyOpt;		/* set if option is stuck */
183738032Speter
183838032Speter#if NAMED_BIND
183938032Speter
184064562Sgshapirostatic struct resolverflags
184138032Speter{
184238032Speter	char	*rf_name;	/* name of the flag */
184338032Speter	long	rf_bits;	/* bits to set/clear */
184438032Speter} ResolverFlags[] =
184538032Speter{
184638032Speter	{ "debug",	RES_DEBUG	},
184738032Speter	{ "aaonly",	RES_AAONLY	},
184838032Speter	{ "usevc",	RES_USEVC	},
184938032Speter	{ "primary",	RES_PRIMARY	},
185038032Speter	{ "igntc",	RES_IGNTC	},
185138032Speter	{ "recurse",	RES_RECURSE	},
185238032Speter	{ "defnames",	RES_DEFNAMES	},
185338032Speter	{ "stayopen",	RES_STAYOPEN	},
185438032Speter	{ "dnsrch",	RES_DNSRCH	},
185590792Sgshapiro# ifdef RES_USE_INET6
185690792Sgshapiro	{ "use_inet6",	RES_USE_INET6	},
185790792Sgshapiro# endif /* RES_USE_INET6 */
185838032Speter	{ "true",	0		},	/* avoid error on old syntax */
185938032Speter	{ NULL,		0		}
186038032Speter};
186138032Speter
186264562Sgshapiro#endif /* NAMED_BIND */
186338032Speter
186464562Sgshapiro#define OI_NONE		0	/* no special treatment */
186564562Sgshapiro#define OI_SAFE		0x0001	/* safe for random people to use */
186664562Sgshapiro#define OI_SUBOPT	0x0002	/* option has suboptions */
186764562Sgshapiro
186864562Sgshapirostatic struct optioninfo
186938032Speter{
187090792Sgshapiro	char		*o_name;	/* long name of option */
187190792Sgshapiro	unsigned char	o_code;		/* short name of option */
187290792Sgshapiro	unsigned short	o_flags;	/* option flags */
187338032Speter} OptionTab[] =
187438032Speter{
187564562Sgshapiro#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
187664562Sgshapiro	{ "RemoteMode",			'>',		OI_NONE	},
187764562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */
187864562Sgshapiro	{ "SevenBitInput",		'7',		OI_SAFE	},
187964562Sgshapiro	{ "EightBitMode",		'8',		OI_SAFE	},
188064562Sgshapiro	{ "AliasFile",			'A',		OI_NONE	},
188164562Sgshapiro	{ "AliasWait",			'a',		OI_NONE	},
188264562Sgshapiro	{ "BlankSub",			'B',		OI_NONE	},
188364562Sgshapiro	{ "MinFreeBlocks",		'b',		OI_SAFE	},
188464562Sgshapiro	{ "CheckpointInterval",		'C',		OI_SAFE	},
188564562Sgshapiro	{ "HoldExpensive",		'c',		OI_NONE	},
188664562Sgshapiro	{ "DeliveryMode",		'd',		OI_SAFE	},
188764562Sgshapiro	{ "ErrorHeader",		'E',		OI_NONE	},
188864562Sgshapiro	{ "ErrorMode",			'e',		OI_SAFE	},
188964562Sgshapiro	{ "TempFileMode",		'F',		OI_NONE	},
189064562Sgshapiro	{ "SaveFromLine",		'f',		OI_NONE	},
189164562Sgshapiro	{ "MatchGECOS",			'G',		OI_NONE	},
189290792Sgshapiro
189390792Sgshapiro	/* no long name, just here to avoid problems in setoption */
189490792Sgshapiro	{ "",				'g',		OI_NONE	},
189564562Sgshapiro	{ "HelpFile",			'H',		OI_NONE	},
189664562Sgshapiro	{ "MaxHopCount",		'h',		OI_NONE	},
189764562Sgshapiro	{ "ResolverOptions",		'I',		OI_NONE	},
189864562Sgshapiro	{ "IgnoreDots",			'i',		OI_SAFE	},
189964562Sgshapiro	{ "ForwardPath",		'J',		OI_NONE	},
190064562Sgshapiro	{ "SendMimeErrors",		'j',		OI_SAFE	},
190164562Sgshapiro	{ "ConnectionCacheSize",	'k',		OI_NONE	},
190264562Sgshapiro	{ "ConnectionCacheTimeout",	'K',		OI_NONE	},
190364562Sgshapiro	{ "UseErrorsTo",		'l',		OI_NONE	},
190464562Sgshapiro	{ "LogLevel",			'L',		OI_SAFE	},
190564562Sgshapiro	{ "MeToo",			'm',		OI_SAFE	},
190690792Sgshapiro
190790792Sgshapiro	/* no long name, just here to avoid problems in setoption */
190890792Sgshapiro	{ "",				'M',		OI_NONE	},
190964562Sgshapiro	{ "CheckAliases",		'n',		OI_NONE	},
191064562Sgshapiro	{ "OldStyleHeaders",		'o',		OI_SAFE	},
191164562Sgshapiro	{ "DaemonPortOptions",		'O',		OI_NONE	},
191264562Sgshapiro	{ "PrivacyOptions",		'p',		OI_SAFE	},
191364562Sgshapiro	{ "PostmasterCopy",		'P',		OI_NONE	},
191464562Sgshapiro	{ "QueueFactor",		'q',		OI_NONE	},
191564562Sgshapiro	{ "QueueDirectory",		'Q',		OI_NONE	},
191664562Sgshapiro	{ "DontPruneRoutes",		'R',		OI_NONE	},
191764562Sgshapiro	{ "Timeout",			'r',		OI_SUBOPT },
191864562Sgshapiro	{ "StatusFile",			'S',		OI_NONE	},
191964562Sgshapiro	{ "SuperSafe",			's',		OI_SAFE	},
192064562Sgshapiro	{ "QueueTimeout",		'T',		OI_NONE	},
192164562Sgshapiro	{ "TimeZoneSpec",		't',		OI_NONE	},
192264562Sgshapiro	{ "UserDatabaseSpec",		'U',		OI_NONE	},
192364562Sgshapiro	{ "DefaultUser",		'u',		OI_NONE	},
192464562Sgshapiro	{ "FallbackMXhost",		'V',		OI_NONE	},
192564562Sgshapiro	{ "Verbose",			'v',		OI_SAFE	},
192664562Sgshapiro	{ "TryNullMXList",		'w',		OI_NONE	},
192764562Sgshapiro	{ "QueueLA",			'x',		OI_NONE	},
192864562Sgshapiro	{ "RefuseLA",			'X',		OI_NONE	},
192964562Sgshapiro	{ "RecipientFactor",		'y',		OI_NONE	},
193064562Sgshapiro	{ "ForkEachJob",		'Y',		OI_NONE	},
193164562Sgshapiro	{ "ClassFactor",		'z',		OI_NONE	},
193264562Sgshapiro	{ "RetryFactor",		'Z',		OI_NONE	},
193338032Speter#define O_QUEUESORTORD	0x81
193464562Sgshapiro	{ "QueueSortOrder",		O_QUEUESORTORD,	OI_SAFE	},
193538032Speter#define O_HOSTSFILE	0x82
193664562Sgshapiro	{ "HostsFile",			O_HOSTSFILE,	OI_NONE	},
193738032Speter#define O_MQA		0x83
193864562Sgshapiro	{ "MinQueueAge",		O_MQA,		OI_SAFE	},
193938032Speter#define O_DEFCHARSET	0x85
194064562Sgshapiro	{ "DefaultCharSet",		O_DEFCHARSET,	OI_SAFE	},
194138032Speter#define O_SSFILE	0x86
194264562Sgshapiro	{ "ServiceSwitchFile",		O_SSFILE,	OI_NONE	},
194338032Speter#define O_DIALDELAY	0x87
194464562Sgshapiro	{ "DialDelay",			O_DIALDELAY,	OI_SAFE	},
194538032Speter#define O_NORCPTACTION	0x88
194664562Sgshapiro	{ "NoRecipientAction",		O_NORCPTACTION,	OI_SAFE	},
194738032Speter#define O_SAFEFILEENV	0x89
194864562Sgshapiro	{ "SafeFileEnvironment",	O_SAFEFILEENV,	OI_NONE	},
194938032Speter#define O_MAXMSGSIZE	0x8a
195064562Sgshapiro	{ "MaxMessageSize",		O_MAXMSGSIZE,	OI_NONE	},
195138032Speter#define O_COLONOKINADDR	0x8b
195264562Sgshapiro	{ "ColonOkInAddr",		O_COLONOKINADDR, OI_SAFE },
195338032Speter#define O_MAXQUEUERUN	0x8c
195464562Sgshapiro	{ "MaxQueueRunSize",		O_MAXQUEUERUN,	OI_SAFE	},
195538032Speter#define O_MAXCHILDREN	0x8d
195664562Sgshapiro	{ "MaxDaemonChildren",		O_MAXCHILDREN,	OI_NONE	},
195738032Speter#define O_KEEPCNAMES	0x8e
195864562Sgshapiro	{ "DontExpandCnames",		O_KEEPCNAMES,	OI_NONE	},
195938032Speter#define O_MUSTQUOTE	0x8f
196064562Sgshapiro	{ "MustQuoteChars",		O_MUSTQUOTE,	OI_NONE	},
196138032Speter#define O_SMTPGREETING	0x90
196264562Sgshapiro	{ "SmtpGreetingMessage",	O_SMTPGREETING,	OI_NONE	},
196338032Speter#define O_UNIXFROM	0x91
196464562Sgshapiro	{ "UnixFromLine",		O_UNIXFROM,	OI_NONE	},
196538032Speter#define O_OPCHARS	0x92
196664562Sgshapiro	{ "OperatorChars",		O_OPCHARS,	OI_NONE	},
196738032Speter#define O_DONTINITGRPS	0x93
196864562Sgshapiro	{ "DontInitGroups",		O_DONTINITGRPS,	OI_NONE	},
196938032Speter#define O_SLFH		0x94
197064562Sgshapiro	{ "SingleLineFromHeader",	O_SLFH,		OI_SAFE	},
197138032Speter#define O_ABH		0x95
197264562Sgshapiro	{ "AllowBogusHELO",		O_ABH,		OI_SAFE	},
197338032Speter#define O_CONNTHROT	0x97
197464562Sgshapiro	{ "ConnectionRateThrottle",	O_CONNTHROT,	OI_NONE	},
197538032Speter#define O_UGW		0x99
197664562Sgshapiro	{ "UnsafeGroupWrites",		O_UGW,		OI_NONE	},
197738032Speter#define O_DBLBOUNCE	0x9a
197864562Sgshapiro	{ "DoubleBounceAddress",	O_DBLBOUNCE,	OI_NONE	},
197938032Speter#define O_HSDIR		0x9b
198064562Sgshapiro	{ "HostStatusDirectory",	O_HSDIR,	OI_NONE	},
198138032Speter#define O_SINGTHREAD	0x9c
198264562Sgshapiro	{ "SingleThreadDelivery",	O_SINGTHREAD,	OI_NONE	},
198338032Speter#define O_RUNASUSER	0x9d
198464562Sgshapiro	{ "RunAsUser",			O_RUNASUSER,	OI_NONE	},
198538032Speter#define O_DSN_RRT	0x9e
198664562Sgshapiro	{ "RrtImpliesDsn",		O_DSN_RRT,	OI_NONE	},
198738032Speter#define O_PIDFILE	0x9f
198864562Sgshapiro	{ "PidFile",			O_PIDFILE,	OI_NONE	},
198938032Speter#define O_DONTBLAMESENDMAIL	0xa0
199064562Sgshapiro	{ "DontBlameSendmail",		O_DONTBLAMESENDMAIL,	OI_NONE	},
199138032Speter#define O_DPI		0xa1
199264562Sgshapiro	{ "DontProbeInterfaces",	O_DPI,		OI_NONE	},
199338032Speter#define O_MAXRCPT	0xa2
199464562Sgshapiro	{ "MaxRecipientsPerMessage",	O_MAXRCPT,	OI_SAFE	},
199538032Speter#define O_DEADLETTER	0xa3
199664562Sgshapiro	{ "DeadLetterDrop",		O_DEADLETTER,	OI_NONE	},
199738032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
199864562Sgshapiro# define O_DONTLOCK	0xa4
199964562Sgshapiro	{ "DontLockFilesForRead",	O_DONTLOCK,	OI_NONE	},
200064562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
200138032Speter#define O_MAXALIASRCSN	0xa5
200264562Sgshapiro	{ "MaxAliasRecursion",		O_MAXALIASRCSN,	OI_NONE	},
200338032Speter#define O_CNCTONLYTO	0xa6
200464562Sgshapiro	{ "ConnectOnlyTo",		O_CNCTONLYTO,	OI_NONE	},
200542575Speter#define O_TRUSTUSER	0xa7
200664562Sgshapiro	{ "TrustedUser",		O_TRUSTUSER,	OI_NONE	},
200742575Speter#define O_MAXMIMEHDRLEN	0xa8
200864562Sgshapiro	{ "MaxMimeHeaderLength",	O_MAXMIMEHDRLEN,	OI_NONE	},
200942575Speter#define O_CONTROLSOCKET	0xa9
201064562Sgshapiro	{ "ControlSocketName",		O_CONTROLSOCKET,	OI_NONE	},
201143730Speter#define O_MAXHDRSLEN	0xaa
201264562Sgshapiro	{ "MaxHeadersLength",		O_MAXHDRSLEN,	OI_NONE	},
201364562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
201464562Sgshapiro# define O_MAXFORWARD	0xab
201564562Sgshapiro	{ "MaxForwardEntries",		O_MAXFORWARD,	OI_NONE	},
201664562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */
201764562Sgshapiro#define O_PROCTITLEPREFIX	0xac
201864562Sgshapiro	{ "ProcessTitlePrefix",		O_PROCTITLEPREFIX,	OI_NONE	},
201964562Sgshapiro#define O_SASLINFO	0xad
202064562Sgshapiro#if _FFR_ALLOW_SASLINFO
202164562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_SAFE	},
202264562Sgshapiro#else /* _FFR_ALLOW_SASLINFO */
202364562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_NONE	},
202464562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */
202564562Sgshapiro#define O_SASLMECH	0xae
202664562Sgshapiro	{ "AuthMechanisms",		O_SASLMECH,	OI_NONE	},
202764562Sgshapiro#define O_CLIENTPORT	0xaf
202864562Sgshapiro	{ "ClientPortOptions",		O_CLIENTPORT,	OI_NONE	},
202964562Sgshapiro#define O_DF_BUFSIZE	0xb0
203064562Sgshapiro	{ "DataFileBufferSize",		O_DF_BUFSIZE,	OI_NONE	},
203164562Sgshapiro#define O_XF_BUFSIZE	0xb1
203264562Sgshapiro	{ "XscriptFileBufferSize",	O_XF_BUFSIZE,	OI_NONE	},
203390792Sgshapiro#define O_LDAPDEFAULTSPEC	0xb2
203464562Sgshapiro	{ "LDAPDefaultSpec",		O_LDAPDEFAULTSPEC,	OI_NONE	},
203564562Sgshapiro#if _FFR_QUEUEDELAY
203690792Sgshapiro# define O_QUEUEDELAY	0xb3
203764562Sgshapiro	{ "QueueDelay",			O_QUEUEDELAY,	OI_NONE	},
203864562Sgshapiro#endif /* _FFR_QUEUEDELAY */
203990792Sgshapiro#define O_SRVCERTFILE	0xb4
204064562Sgshapiro	{ "ServerCertFile",		O_SRVCERTFILE,	OI_NONE	},
204190792Sgshapiro#define O_SRVKEYFILE	0xb5
204264562Sgshapiro	{ "Serverkeyfile",		O_SRVKEYFILE,	OI_NONE	},
204390792Sgshapiro#define O_CLTCERTFILE	0xb6
204464562Sgshapiro	{ "ClientCertFile",		O_CLTCERTFILE,	OI_NONE	},
204590792Sgshapiro#define O_CLTKEYFILE	0xb7
204664562Sgshapiro	{ "Clientkeyfile",		O_CLTKEYFILE,	OI_NONE	},
204790792Sgshapiro#define O_CACERTFILE	0xb8
204864562Sgshapiro	{ "CACERTFile",			O_CACERTFILE,	OI_NONE	},
204990792Sgshapiro#define O_CACERTPATH	0xb9
205064562Sgshapiro	{ "CACERTPath",			O_CACERTPATH,	OI_NONE	},
205190792Sgshapiro#define O_DHPARAMS	0xba
205264562Sgshapiro	{ "DHParameters",		O_DHPARAMS,	OI_NONE	},
205364562Sgshapiro#define O_INPUTMILTER	0xbb
205464562Sgshapiro	{ "InputMailFilters",		O_INPUTMILTER,	OI_NONE	},
205564562Sgshapiro#define O_MILTER	0xbc
205664562Sgshapiro	{ "Milter",			O_MILTER,	OI_SUBOPT	},
205764562Sgshapiro#define O_SASLOPTS	0xbd
205864562Sgshapiro	{ "AuthOptions",		O_SASLOPTS,	OI_NONE	},
205964562Sgshapiro#define O_QUEUE_FILE_MODE	0xbe
206064562Sgshapiro	{ "QueueFileMode",		O_QUEUE_FILE_MODE, OI_NONE	},
206190792Sgshapiro#if _FFR_TLS_1
206264562Sgshapiro# define O_DHPARAMS5	0xbf
206364562Sgshapiro	{ "DHParameters512",		O_DHPARAMS5,	OI_NONE	},
206464562Sgshapiro# define O_CIPHERLIST	0xc0
206564562Sgshapiro	{ "CipherList",			O_CIPHERLIST,	OI_NONE	},
206690792Sgshapiro#endif /* _FFR_TLS_1 */
206790792Sgshapiro#define O_RANDFILE	0xc1
206864562Sgshapiro	{ "RandFile",			O_RANDFILE,	OI_NONE	},
206990792Sgshapiro#define O_TLS_SRV_OPTS	0xc2
207090792Sgshapiro	{ "TLSSrvOptions",		O_TLS_SRV_OPTS,	OI_NONE	},
207190792Sgshapiro#define O_RCPTTHROT	0xc3
207290792Sgshapiro	{ "BadRcptThrottle",		O_RCPTTHROT,	OI_SAFE	},
207390792Sgshapiro#define O_DLVR_MIN	0xc4
207490792Sgshapiro	{ "DeliverByMin",		O_DLVR_MIN,	OI_NONE	},
207590792Sgshapiro#define O_MAXQUEUECHILDREN	0xc5
207690792Sgshapiro	{ "MaxQueueChildren",		O_MAXQUEUECHILDREN,	OI_NONE	},
207790792Sgshapiro#define O_MAXRUNNERSPERQUEUE	0xc6
207890792Sgshapiro	{ "MaxRunnersPerQueue",		O_MAXRUNNERSPERQUEUE,	OI_NONE },
207990792Sgshapiro#define O_DIRECTSUBMODIFIERS	0xc7
208090792Sgshapiro	{ "DirectSubmissionModifiers",	O_DIRECTSUBMODIFIERS,	OI_NONE },
208190792Sgshapiro#define O_NICEQUEUERUN	0xc8
208290792Sgshapiro	{ "NiceQueueRun",		O_NICEQUEUERUN,	OI_NONE	},
208390792Sgshapiro#define O_SHMKEY	0xc9
208490792Sgshapiro	{ "SharedMemoryKey",		O_SHMKEY,	OI_NONE	},
208590792Sgshapiro#define O_SASLBITS	0xca
208690792Sgshapiro	{ "AuthMaxBits",		O_SASLBITS,	OI_NONE	},
208790792Sgshapiro#define O_MBDB		0xcb
208890792Sgshapiro	{ "MailboxDatabase",		O_MBDB,		OI_NONE	},
208990792Sgshapiro#define O_MSQ		0xcc
209090792Sgshapiro	{ "UseMSP",	O_MSQ,		OI_NONE	},
209190792Sgshapiro#define O_DELAY_LA	0xcd
209290792Sgshapiro	{ "DelayLA",	O_DELAY_LA,	OI_NONE	},
209390792Sgshapiro#define O_FASTSPLIT	0xce
209490792Sgshapiro	{ "FastSplit",	O_FASTSPLIT,	OI_NONE	},
209590792Sgshapiro#if _FFR_SOFT_BOUNCE
209690792Sgshapiro# define O_SOFTBOUNCE	0xcf
209790792Sgshapiro	{ "SoftBounce",	O_SOFTBOUNCE,	OI_NONE	},
209890792Sgshapiro#endif /* _FFR_SOFT_BOUNCE */
209994334Sgshapiro#if _FFR_SELECT_SHM
210094334Sgshapiro# define O_SHMKEYFILE	0xd0
210194334Sgshapiro	{ "SharedMemoryKeyFile",	O_SHMKEYFILE,	OI_NONE	},
210294334Sgshapiro#endif /* _FFR_SELECT_SHM */
210364562Sgshapiro	{ NULL,				'\0',		OI_NONE	}
210438032Speter};
210538032Speter
210690792Sgshapiro# define CANONIFY(val)
210790792Sgshapiro
210890792Sgshapiro# define SET_OPT_DEFAULT(opt, val)	opt = val
210990792Sgshapiro
211090792Sgshapiro/* set a string option by expanding the value and assigning it */
211190792Sgshapiro/* WARNING this belongs ONLY into a case statement! */
211290792Sgshapiro#define SET_STRING_EXP(str)	\
211390792Sgshapiro		expand(val, exbuf, sizeof exbuf, e);	\
211490792Sgshapiro		newval = sm_pstrdup_x(exbuf);		\
211590792Sgshapiro		if (str != NULL)	\
211690792Sgshapiro			sm_free(str);	\
211790792Sgshapiro		CANONIFY(newval);	\
211890792Sgshapiro		str = newval;		\
211990792Sgshapiro		break
212090792Sgshapiro
212190792Sgshapiro#define OPTNAME	o->o_name == NULL ? "<unknown>" : o->o_name
212290792Sgshapiro
212338032Spetervoid
212438032Spetersetoption(opt, val, safe, sticky, e)
212538032Speter	int opt;
212638032Speter	char *val;
212738032Speter	bool safe;
212838032Speter	bool sticky;
212938032Speter	register ENVELOPE *e;
213038032Speter{
213138032Speter	register char *p;
213238032Speter	register struct optioninfo *o;
213338032Speter	char *subopt;
213438032Speter	int mid;
213538032Speter	bool can_setuid = RunAsUid == 0;
213638032Speter	auto char *ep;
213738032Speter	char buf[50];
213838032Speter	extern bool Warn_Q_option;
213964562Sgshapiro#if _FFR_ALLOW_SASLINFO
214090792Sgshapiro	extern unsigned int SubmitMode;
214164562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */
214290792Sgshapiro#if STARTTLS
214390792Sgshapiro	char *newval;
214490792Sgshapiro	char exbuf[MAXLINE];
214590792Sgshapiro#endif /* STARTTLS */
214638032Speter
214738032Speter	errno = 0;
214838032Speter	if (opt == ' ')
214938032Speter	{
215038032Speter		/* full word options */
215138032Speter		struct optioninfo *sel;
215238032Speter
215338032Speter		p = strchr(val, '=');
215438032Speter		if (p == NULL)
215538032Speter			p = &val[strlen(val)];
215638032Speter		while (*--p == ' ')
215738032Speter			continue;
215838032Speter		while (*++p == ' ')
215938032Speter			*p = '\0';
216038032Speter		if (p == val)
216138032Speter		{
216238032Speter			syserr("readcf: null option name");
216338032Speter			return;
216438032Speter		}
216538032Speter		if (*p == '=')
216638032Speter			*p++ = '\0';
216738032Speter		while (*p == ' ')
216838032Speter			p++;
216938032Speter		subopt = strchr(val, '.');
217038032Speter		if (subopt != NULL)
217138032Speter			*subopt++ = '\0';
217238032Speter		sel = NULL;
217338032Speter		for (o = OptionTab; o->o_name != NULL; o++)
217438032Speter		{
217590792Sgshapiro			if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0)
217638032Speter				continue;
217738032Speter			if (strlen(o->o_name) == strlen(val))
217838032Speter			{
217938032Speter				/* completely specified -- this must be it */
218038032Speter				sel = NULL;
218138032Speter				break;
218238032Speter			}
218338032Speter			if (sel != NULL)
218438032Speter				break;
218538032Speter			sel = o;
218638032Speter		}
218738032Speter		if (sel != NULL && o->o_name == NULL)
218838032Speter			o = sel;
218938032Speter		else if (o->o_name == NULL)
219038032Speter		{
219138032Speter			syserr("readcf: unknown option name %s", val);
219238032Speter			return;
219338032Speter		}
219438032Speter		else if (sel != NULL)
219538032Speter		{
219638032Speter			syserr("readcf: ambiguous option name %s (matches %s and %s)",
219738032Speter				val, sel->o_name, o->o_name);
219838032Speter			return;
219938032Speter		}
220038032Speter		if (strlen(val) != strlen(o->o_name))
220138032Speter		{
220238032Speter			int oldVerbose = Verbose;
220338032Speter
220438032Speter			Verbose = 1;
220538032Speter			message("Option %s used as abbreviation for %s",
220638032Speter				val, o->o_name);
220738032Speter			Verbose = oldVerbose;
220838032Speter		}
220938032Speter		opt = o->o_code;
221038032Speter		val = p;
221138032Speter	}
221238032Speter	else
221338032Speter	{
221438032Speter		for (o = OptionTab; o->o_name != NULL; o++)
221538032Speter		{
221638032Speter			if (o->o_code == opt)
221738032Speter				break;
221838032Speter		}
221990792Sgshapiro		if (o->o_name == NULL)
222090792Sgshapiro		{
222190792Sgshapiro			syserr("readcf: unknown option name 0x%x", opt & 0xff);
222290792Sgshapiro			return;
222390792Sgshapiro		}
222438032Speter		subopt = NULL;
222538032Speter	}
222638032Speter
222764562Sgshapiro	if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
222864562Sgshapiro	{
222964562Sgshapiro		if (tTd(37, 1))
223090792Sgshapiro			sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
223190792Sgshapiro				   OPTNAME, subopt);
223264562Sgshapiro		subopt = NULL;
223364562Sgshapiro	}
223464562Sgshapiro
223538032Speter	if (tTd(37, 1))
223638032Speter	{
223790792Sgshapiro		sm_dprintf(isascii(opt) && isprint(opt) ?
223890792Sgshapiro			   "setoption %s (%c)%s%s=" :
223990792Sgshapiro			   "setoption %s (0x%x)%s%s=",
224090792Sgshapiro			   OPTNAME, opt, subopt == NULL ? "" : ".",
224190792Sgshapiro			   subopt == NULL ? "" : subopt);
224238032Speter		xputs(val);
224338032Speter	}
224438032Speter
224538032Speter	/*
224638032Speter	**  See if this option is preset for us.
224738032Speter	*/
224838032Speter
224938032Speter	if (!sticky && bitnset(opt, StickyOpt))
225038032Speter	{
225138032Speter		if (tTd(37, 1))
225290792Sgshapiro			sm_dprintf(" (ignored)\n");
225338032Speter		return;
225438032Speter	}
225538032Speter
225638032Speter	/*
225738032Speter	**  Check to see if this option can be specified by this user.
225838032Speter	*/
225938032Speter
226038032Speter	if (!safe && RealUid == 0)
226190792Sgshapiro		safe = true;
226264562Sgshapiro	if (!safe && !bitset(OI_SAFE, o->o_flags))
226338032Speter	{
226438032Speter		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
226538032Speter		{
226664562Sgshapiro			int dp;
226764562Sgshapiro
226838032Speter			if (tTd(37, 1))
226990792Sgshapiro				sm_dprintf(" (unsafe)");
227090792Sgshapiro			dp = drop_privileges(true);
227164562Sgshapiro			setstat(dp);
227238032Speter		}
227338032Speter	}
227438032Speter	if (tTd(37, 1))
227590792Sgshapiro		sm_dprintf("\n");
227638032Speter
227738032Speter	switch (opt & 0xff)
227838032Speter	{
227938032Speter	  case '7':		/* force seven-bit input */
228038032Speter		SevenBitInput = atobool(val);
228138032Speter		break;
228238032Speter
228377349Sgshapiro	  case '8':		/* handling of 8-bit input */
228438032Speter#if MIME8TO7
228538032Speter		switch (*val)
228638032Speter		{
228790792Sgshapiro		  case 'p':		/* pass 8 bit, convert MIME */
228890792Sgshapiro			MimeMode = MM_CVTMIME|MM_PASS8BIT;
228990792Sgshapiro			break;
229090792Sgshapiro
229138032Speter		  case 'm':		/* convert 8-bit, convert MIME */
229238032Speter			MimeMode = MM_CVTMIME|MM_MIME8BIT;
229338032Speter			break;
229438032Speter
229538032Speter		  case 's':		/* strict adherence */
229638032Speter			MimeMode = MM_CVTMIME;
229738032Speter			break;
229838032Speter
229964562Sgshapiro# if 0
230038032Speter		  case 'r':		/* reject 8-bit, don't convert MIME */
230138032Speter			MimeMode = 0;
230238032Speter			break;
230338032Speter
230438032Speter		  case 'j':		/* "just send 8" */
230538032Speter			MimeMode = MM_PASS8BIT;
230638032Speter			break;
230738032Speter
230838032Speter		  case 'a':		/* encode 8 bit if available */
230938032Speter			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
231038032Speter			break;
231138032Speter
231238032Speter		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
231338032Speter			MimeMode = MM_MIME8BIT;
231438032Speter			break;
231564562Sgshapiro# endif /* 0 */
231638032Speter
231738032Speter		  default:
231838032Speter			syserr("Unknown 8-bit mode %c", *val);
231990792Sgshapiro			finis(false, true, EX_USAGE);
232038032Speter		}
232177349Sgshapiro#else /* MIME8TO7 */
232290792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
232390792Sgshapiro				     "Warning: Option: %s requires MIME8TO7 support\n",
232490792Sgshapiro				     OPTNAME);
232577349Sgshapiro#endif /* MIME8TO7 */
232638032Speter		break;
232738032Speter
232838032Speter	  case 'A':		/* set default alias file */
232938032Speter		if (val[0] == '\0')
233090792Sgshapiro		{
233190792Sgshapiro			char *al;
233290792Sgshapiro
233390792Sgshapiro			SET_OPT_DEFAULT(al, "aliases");
233490792Sgshapiro			setalias(al);
233590792Sgshapiro		}
233638032Speter		else
233738032Speter			setalias(val);
233838032Speter		break;
233938032Speter
234038032Speter	  case 'a':		/* look N minutes for "@:@" in alias file */
234138032Speter		if (val[0] == '\0')
234290792Sgshapiro			SafeAlias = 5 MINUTES;
234338032Speter		else
234438032Speter			SafeAlias = convtime(val, 'm');
234538032Speter		break;
234638032Speter
234738032Speter	  case 'B':		/* substitution for blank character */
234838032Speter		SpaceSub = val[0];
234938032Speter		if (SpaceSub == '\0')
235038032Speter			SpaceSub = ' ';
235138032Speter		break;
235238032Speter
235338032Speter	  case 'b':		/* min blocks free on queue fs/max msg size */
235438032Speter		p = strchr(val, '/');
235538032Speter		if (p != NULL)
235638032Speter		{
235738032Speter			*p++ = '\0';
235838032Speter			MaxMessageSize = atol(p);
235938032Speter		}
236038032Speter		MinBlocksFree = atol(val);
236138032Speter		break;
236238032Speter
236338032Speter	  case 'c':		/* don't connect to "expensive" mailers */
236438032Speter		NoConnect = atobool(val);
236538032Speter		break;
236638032Speter
236738032Speter	  case 'C':		/* checkpoint every N addresses */
236838032Speter		CheckpointInterval = atoi(val);
236938032Speter		break;
237038032Speter
237138032Speter	  case 'd':		/* delivery mode */
237238032Speter		switch (*val)
237338032Speter		{
237438032Speter		  case '\0':
237564562Sgshapiro			set_delivery_mode(SM_DELIVER, e);
237638032Speter			break;
237738032Speter
237838032Speter		  case SM_QUEUE:	/* queue only */
237938032Speter		  case SM_DEFER:	/* queue only and defer map lookups */
238038032Speter		  case SM_DELIVER:	/* do everything */
238138032Speter		  case SM_FORK:		/* fork after verification */
238264562Sgshapiro			set_delivery_mode(*val, e);
238338032Speter			break;
238438032Speter
238538032Speter		  default:
238638032Speter			syserr("Unknown delivery mode %c", *val);
238790792Sgshapiro			finis(false, true, EX_USAGE);
238838032Speter		}
238938032Speter		break;
239038032Speter
239138032Speter	  case 'E':		/* error message header/header file */
239238032Speter		if (*val != '\0')
239338032Speter			ErrMsgFile = newstr(val);
239438032Speter		break;
239538032Speter
239638032Speter	  case 'e':		/* set error processing mode */
239738032Speter		switch (*val)
239838032Speter		{
239938032Speter		  case EM_QUIET:	/* be silent about it */
240038032Speter		  case EM_MAIL:		/* mail back */
240138032Speter		  case EM_BERKNET:	/* do berknet error processing */
240238032Speter		  case EM_WRITE:	/* write back (or mail) */
240338032Speter		  case EM_PRINT:	/* print errors normally (default) */
240438032Speter			e->e_errormode = *val;
240538032Speter			break;
240638032Speter		}
240738032Speter		break;
240838032Speter
240938032Speter	  case 'F':		/* file mode */
241038032Speter		FileMode = atooct(val) & 0777;
241138032Speter		break;
241238032Speter
241338032Speter	  case 'f':		/* save Unix-style From lines on front */
241438032Speter		SaveFrom = atobool(val);
241538032Speter		break;
241638032Speter
241738032Speter	  case 'G':		/* match recipients against GECOS field */
241838032Speter		MatchGecos = atobool(val);
241938032Speter		break;
242038032Speter
242138032Speter	  case 'g':		/* default gid */
242238032Speter  g_opt:
242338032Speter		if (isascii(*val) && isdigit(*val))
242438032Speter			DefGid = atoi(val);
242538032Speter		else
242638032Speter		{
242738032Speter			register struct group *gr;
242838032Speter
242938032Speter			DefGid = -1;
243038032Speter			gr = getgrnam(val);
243138032Speter			if (gr == NULL)
243238032Speter				syserr("readcf: option %c: unknown group %s",
243338032Speter					opt, val);
243438032Speter			else
243538032Speter				DefGid = gr->gr_gid;
243638032Speter		}
243738032Speter		break;
243838032Speter
243938032Speter	  case 'H':		/* help file */
244038032Speter		if (val[0] == '\0')
244190792Sgshapiro		{
244290792Sgshapiro			SET_OPT_DEFAULT(HelpFile, "helpfile");
244390792Sgshapiro		}
244438032Speter		else
244573188Sgshapiro		{
244690792Sgshapiro			CANONIFY(val);
244738032Speter			HelpFile = newstr(val);
244873188Sgshapiro		}
244938032Speter		break;
245038032Speter
245138032Speter	  case 'h':		/* maximum hop count */
245238032Speter		MaxHopCount = atoi(val);
245338032Speter		break;
245438032Speter
245538032Speter	  case 'I':		/* use internet domain name server */
245638032Speter#if NAMED_BIND
245738032Speter		for (p = val; *p != 0; )
245838032Speter		{
245938032Speter			bool clearmode;
246038032Speter			char *q;
246138032Speter			struct resolverflags *rfp;
246238032Speter
246338032Speter			while (*p == ' ')
246438032Speter				p++;
246538032Speter			if (*p == '\0')
246638032Speter				break;
246790792Sgshapiro			clearmode = false;
246838032Speter			if (*p == '-')
246990792Sgshapiro				clearmode = true;
247038032Speter			else if (*p != '+')
247138032Speter				p--;
247238032Speter			p++;
247338032Speter			q = p;
247438032Speter			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
247538032Speter				p++;
247638032Speter			if (*p != '\0')
247738032Speter				*p++ = '\0';
247890792Sgshapiro			if (sm_strcasecmp(q, "HasWildcardMX") == 0)
247938032Speter			{
248038032Speter				HasWildcardMX = !clearmode;
248138032Speter				continue;
248238032Speter			}
248373188Sgshapiro			if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
248473188Sgshapiro			{
248573188Sgshapiro				WorkAroundBrokenAAAA = !clearmode;
248673188Sgshapiro				continue;
248773188Sgshapiro			}
248838032Speter			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
248938032Speter			{
249090792Sgshapiro				if (sm_strcasecmp(q, rfp->rf_name) == 0)
249138032Speter					break;
249238032Speter			}
249338032Speter			if (rfp->rf_name == NULL)
249438032Speter				syserr("readcf: I option value %s unrecognized", q);
249538032Speter			else if (clearmode)
249638032Speter				_res.options &= ~rfp->rf_bits;
249738032Speter			else
249838032Speter				_res.options |= rfp->rf_bits;
249938032Speter		}
250038032Speter		if (tTd(8, 2))
250190792Sgshapiro			sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
250290792Sgshapiro				   (unsigned int) _res.options, HasWildcardMX);
250364562Sgshapiro#else /* NAMED_BIND */
250438032Speter		usrerr("name server (I option) specified but BIND not compiled in");
250564562Sgshapiro#endif /* NAMED_BIND */
250638032Speter		break;
250738032Speter
250838032Speter	  case 'i':		/* ignore dot lines in message */
250938032Speter		IgnrDot = atobool(val);
251038032Speter		break;
251138032Speter
251238032Speter	  case 'j':		/* send errors in MIME (RFC 1341) format */
251338032Speter		SendMIMEErrors = atobool(val);
251438032Speter		break;
251538032Speter
251638032Speter	  case 'J':		/* .forward search path */
251790792Sgshapiro		CANONIFY(val);
251838032Speter		ForwardPath = newstr(val);
251938032Speter		break;
252038032Speter
252138032Speter	  case 'k':		/* connection cache size */
252238032Speter		MaxMciCache = atoi(val);
252338032Speter		if (MaxMciCache < 0)
252438032Speter			MaxMciCache = 0;
252538032Speter		break;
252638032Speter
252738032Speter	  case 'K':		/* connection cache timeout */
252838032Speter		MciCacheTimeout = convtime(val, 'm');
252938032Speter		break;
253038032Speter
253138032Speter	  case 'l':		/* use Errors-To: header */
253238032Speter		UseErrorsTo = atobool(val);
253338032Speter		break;
253438032Speter
253538032Speter	  case 'L':		/* log level */
253638032Speter		if (safe || LogLevel < atoi(val))
253738032Speter			LogLevel = atoi(val);
253838032Speter		break;
253938032Speter
254038032Speter	  case 'M':		/* define macro */
254190792Sgshapiro		sticky = false;
254290792Sgshapiro		mid = macid_parse(val, &ep);
254371345Sgshapiro		if (mid == 0)
254471345Sgshapiro			break;
254538032Speter		p = newstr(ep);
254638032Speter		if (!safe)
254738032Speter			cleanstrcpy(p, p, MAXNAME);
254890792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, p);
254938032Speter		break;
255038032Speter
255138032Speter	  case 'm':		/* send to me too */
255238032Speter		MeToo = atobool(val);
255338032Speter		break;
255438032Speter
255538032Speter	  case 'n':		/* validate RHS in newaliases */
255638032Speter		CheckAliases = atobool(val);
255738032Speter		break;
255838032Speter
255938032Speter	    /* 'N' available -- was "net name" */
256038032Speter
256138032Speter	  case 'O':		/* daemon options */
256264562Sgshapiro		if (!setdaemonoptions(val))
256364562Sgshapiro			syserr("too many daemons defined (%d max)", MAXDAEMONS);
256438032Speter		break;
256538032Speter
256638032Speter	  case 'o':		/* assume old style headers */
256738032Speter		if (atobool(val))
256838032Speter			CurEnv->e_flags |= EF_OLDSTYLE;
256938032Speter		else
257038032Speter			CurEnv->e_flags &= ~EF_OLDSTYLE;
257138032Speter		break;
257238032Speter
257338032Speter	  case 'p':		/* select privacy level */
257438032Speter		p = val;
257538032Speter		for (;;)
257638032Speter		{
257738032Speter			register struct prival *pv;
257838032Speter			extern struct prival PrivacyValues[];
257938032Speter
258038032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
258138032Speter				p++;
258238032Speter			if (*p == '\0')
258338032Speter				break;
258438032Speter			val = p;
258538032Speter			while (isascii(*p) && isalnum(*p))
258638032Speter				p++;
258738032Speter			if (*p != '\0')
258838032Speter				*p++ = '\0';
258938032Speter
259038032Speter			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
259138032Speter			{
259290792Sgshapiro				if (sm_strcasecmp(val, pv->pv_name) == 0)
259338032Speter					break;
259438032Speter			}
259538032Speter			if (pv->pv_name == NULL)
259638032Speter				syserr("readcf: Op line: %s unrecognized", val);
259771345Sgshapiro			else
259871345Sgshapiro				PrivacyFlags |= pv->pv_flag;
259938032Speter		}
260090792Sgshapiro		sticky = false;
260138032Speter		break;
260238032Speter
260338032Speter	  case 'P':		/* postmaster copy address for returned mail */
260438032Speter		PostMasterCopy = newstr(val);
260538032Speter		break;
260638032Speter
260738032Speter	  case 'q':		/* slope of queue only function */
260838032Speter		QueueFactor = atoi(val);
260938032Speter		break;
261038032Speter
261138032Speter	  case 'Q':		/* queue directory */
261238032Speter		if (val[0] == '\0')
261366494Sgshapiro		{
261438032Speter			QueueDir = "mqueue";
261566494Sgshapiro		}
261638032Speter		else
261766494Sgshapiro		{
261838032Speter			QueueDir = newstr(val);
261966494Sgshapiro		}
262038032Speter		if (RealUid != 0 && !safe)
262190792Sgshapiro			Warn_Q_option = true;
262238032Speter		break;
262338032Speter
262438032Speter	  case 'R':		/* don't prune routes */
262538032Speter		DontPruneRoutes = atobool(val);
262638032Speter		break;
262738032Speter
262838032Speter	  case 'r':		/* read timeout */
262938032Speter		if (subopt == NULL)
263064562Sgshapiro			inittimeouts(val, sticky);
263138032Speter		else
263264562Sgshapiro			settimeout(subopt, val, sticky);
263338032Speter		break;
263438032Speter
263538032Speter	  case 'S':		/* status file */
263638032Speter		if (val[0] == '\0')
263790792Sgshapiro		{
263890792Sgshapiro			SET_OPT_DEFAULT(StatFile, "statistics");
263990792Sgshapiro		}
264038032Speter		else
264173188Sgshapiro		{
264290792Sgshapiro			CANONIFY(val);
264338032Speter			StatFile = newstr(val);
264473188Sgshapiro		}
264538032Speter		break;
264638032Speter
264738032Speter	  case 's':		/* be super safe, even if expensive */
264890792Sgshapiro		if (tolower(*val) == 'i')
264990792Sgshapiro			SuperSafe = SAFE_INTERACTIVE;
265090792Sgshapiro		else
265190792Sgshapiro			SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO;
265238032Speter		break;
265338032Speter
265438032Speter	  case 'T':		/* queue timeout */
265538032Speter		p = strchr(val, '/');
265638032Speter		if (p != NULL)
265738032Speter		{
265838032Speter			*p++ = '\0';
265964562Sgshapiro			settimeout("queuewarn", p, sticky);
266038032Speter		}
266164562Sgshapiro		settimeout("queuereturn", val, sticky);
266238032Speter		break;
266338032Speter
266438032Speter	  case 't':		/* time zone name */
266538032Speter		TimeZoneSpec = newstr(val);
266638032Speter		break;
266738032Speter
266838032Speter	  case 'U':		/* location of user database */
266938032Speter		UdbSpec = newstr(val);
267038032Speter		break;
267138032Speter
267238032Speter	  case 'u':		/* set default uid */
267338032Speter		for (p = val; *p != '\0'; p++)
267438032Speter		{
267594334Sgshapiro# if _FFR_DOTTED_USERNAMES
267690792Sgshapiro			if (*p == '/' || *p == ':')
267794334Sgshapiro# else /* _FFR_DOTTED_USERNAMES */
267838032Speter			if (*p == '.' || *p == '/' || *p == ':')
267994334Sgshapiro# endif /* _FFR_DOTTED_USERNAMES */
268038032Speter			{
268138032Speter				*p++ = '\0';
268238032Speter				break;
268338032Speter			}
268438032Speter		}
268538032Speter		if (isascii(*val) && isdigit(*val))
268638032Speter		{
268738032Speter			DefUid = atoi(val);
268838032Speter			setdefuser();
268938032Speter		}
269038032Speter		else
269138032Speter		{
269238032Speter			register struct passwd *pw;
269338032Speter
269438032Speter			DefUid = -1;
269538032Speter			pw = sm_getpwnam(val);
269638032Speter			if (pw == NULL)
269771345Sgshapiro			{
269838032Speter				syserr("readcf: option u: unknown user %s", val);
269971345Sgshapiro				break;
270071345Sgshapiro			}
270138032Speter			else
270238032Speter			{
270338032Speter				DefUid = pw->pw_uid;
270438032Speter				DefGid = pw->pw_gid;
270538032Speter				DefUser = newstr(pw->pw_name);
270638032Speter			}
270738032Speter		}
270838032Speter
270990792Sgshapiro# ifdef UID_MAX
271038032Speter		if (DefUid > UID_MAX)
271138032Speter		{
271238032Speter			syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
271390792Sgshapiro				(long)DefUid, (long)UID_MAX);
271471345Sgshapiro			break;
271538032Speter		}
271690792Sgshapiro# endif /* UID_MAX */
271738032Speter
271838032Speter		/* handle the group if it is there */
271938032Speter		if (*p == '\0')
272038032Speter			break;
272138032Speter		val = p;
272238032Speter		goto g_opt;
272338032Speter
272438032Speter	  case 'V':		/* fallback MX host */
272538032Speter		if (val[0] != '\0')
272638032Speter			FallBackMX = newstr(val);
272738032Speter		break;
272838032Speter
272938032Speter	  case 'v':		/* run in verbose mode */
273038032Speter		Verbose = atobool(val) ? 1 : 0;
273138032Speter		break;
273238032Speter
273338032Speter	  case 'w':		/* if we are best MX, try host directly */
273438032Speter		TryNullMXList = atobool(val);
273538032Speter		break;
273638032Speter
273738032Speter	    /* 'W' available -- was wizard password */
273838032Speter
273938032Speter	  case 'x':		/* load avg at which to auto-queue msgs */
274038032Speter		QueueLA = atoi(val);
274138032Speter		break;
274238032Speter
274390792Sgshapiro	  case 'X':	/* load avg at which to auto-reject connections */
274438032Speter		RefuseLA = atoi(val);
274538032Speter		break;
274638032Speter
274790792Sgshapiro	  case O_DELAY_LA:	/* load avg at which to delay connections */
274890792Sgshapiro		DelayLA = atoi(val);
274990792Sgshapiro		break;
275090792Sgshapiro
275138032Speter	  case 'y':		/* work recipient factor */
275238032Speter		WkRecipFact = atoi(val);
275338032Speter		break;
275438032Speter
275538032Speter	  case 'Y':		/* fork jobs during queue runs */
275638032Speter		ForkQueueRuns = atobool(val);
275738032Speter		break;
275838032Speter
275938032Speter	  case 'z':		/* work message class factor */
276038032Speter		WkClassFact = atoi(val);
276138032Speter		break;
276238032Speter
276338032Speter	  case 'Z':		/* work time factor */
276438032Speter		WkTimeFact = atoi(val);
276538032Speter		break;
276638032Speter
276764562Sgshapiro
276894334Sgshapiro#if _FFR_QUEUE_GROUP_SORTORDER
276994334Sgshapiro	/* coordinate this with makequeue() */
277094334Sgshapiro#endif /* _FFR_QUEUE_GROUP_SORTORDER */
277138032Speter	  case O_QUEUESORTORD:	/* queue sorting order */
277238032Speter		switch (*val)
277338032Speter		{
277490792Sgshapiro		  case 'f':	/* File Name */
277590792Sgshapiro		  case 'F':
277690792Sgshapiro			QueueSortOrder = QSO_BYFILENAME;
277790792Sgshapiro			break;
277890792Sgshapiro
277938032Speter		  case 'h':	/* Host first */
278038032Speter		  case 'H':
278164562Sgshapiro			QueueSortOrder = QSO_BYHOST;
278238032Speter			break;
278338032Speter
278490792Sgshapiro		  case 'm':	/* Modification time */
278590792Sgshapiro		  case 'M':
278690792Sgshapiro			QueueSortOrder = QSO_BYMODTIME;
278790792Sgshapiro			break;
278890792Sgshapiro
278938032Speter		  case 'p':	/* Priority order */
279038032Speter		  case 'P':
279164562Sgshapiro			QueueSortOrder = QSO_BYPRIORITY;
279238032Speter			break;
279338032Speter
279438032Speter		  case 't':	/* Submission time */
279538032Speter		  case 'T':
279664562Sgshapiro			QueueSortOrder = QSO_BYTIME;
279738032Speter			break;
279838032Speter
279990792Sgshapiro		  case 'r':	/* Random */
280090792Sgshapiro		  case 'R':
280190792Sgshapiro			QueueSortOrder = QSO_RANDOM;
280264562Sgshapiro			break;
280364562Sgshapiro
280490792Sgshapiro#if _FFR_RHS
280590792Sgshapiro		  case 's':	/* Shuffled host name */
280690792Sgshapiro		  case 'S':
280790792Sgshapiro			QueueSortOrder = QSO_BYSHUFFLE;
280890792Sgshapiro			break;
280990792Sgshapiro#endif /* _FFR_RHS */
281090792Sgshapiro
281138032Speter		  default:
281238032Speter			syserr("Invalid queue sort order \"%s\"", val);
281338032Speter		}
281438032Speter		break;
281538032Speter
281664562Sgshapiro#if _FFR_QUEUEDELAY
281764562Sgshapiro	  case O_QUEUEDELAY:	/* queue delay algorithm */
281864562Sgshapiro		switch (*val)
281964562Sgshapiro		{
282064562Sgshapiro		  case 'e':	/* exponential */
282164562Sgshapiro		  case 'E':
282264562Sgshapiro			QueueAlg = QD_EXP;
282364562Sgshapiro			QueueInitDelay = 10 MINUTES;
282464562Sgshapiro			QueueMaxDelay = 2 HOURS;
282564562Sgshapiro			p = strchr(val, '/');
282664562Sgshapiro			if (p != NULL)
282764562Sgshapiro			{
282864562Sgshapiro				char *q;
282964562Sgshapiro
283064562Sgshapiro				*p++ = '\0';
283164562Sgshapiro				q = strchr(p, '/');
283264562Sgshapiro				if (q != NULL)
283364562Sgshapiro					*q++ = '\0';
283464562Sgshapiro				QueueInitDelay = convtime(p, 's');
283564562Sgshapiro				if (q != NULL)
283664562Sgshapiro				{
283764562Sgshapiro					QueueMaxDelay = convtime(q, 's');
283864562Sgshapiro				}
283964562Sgshapiro			}
284064562Sgshapiro			break;
284164562Sgshapiro
284264562Sgshapiro		  case 'l':	/* linear */
284364562Sgshapiro		  case 'L':
284464562Sgshapiro			QueueAlg = QD_LINEAR;
284564562Sgshapiro			break;
284664562Sgshapiro
284764562Sgshapiro		  default:
284864562Sgshapiro			syserr("Invalid queue delay algorithm \"%s\"", val);
284964562Sgshapiro		}
285064562Sgshapiro		break;
285164562Sgshapiro#endif /* _FFR_QUEUEDELAY */
285264562Sgshapiro
285338032Speter	  case O_HOSTSFILE:	/* pathname of /etc/hosts file */
285490792Sgshapiro		CANONIFY(val);
285538032Speter		HostsFile = newstr(val);
285638032Speter		break;
285738032Speter
285838032Speter	  case O_MQA:		/* minimum queue age between deliveries */
285938032Speter		MinQueueAge = convtime(val, 'm');
286038032Speter		break;
286138032Speter
286238032Speter	  case O_DEFCHARSET:	/* default character set for mimefying */
286390792Sgshapiro		DefaultCharSet = newstr(denlstring(val, true, true));
286438032Speter		break;
286538032Speter
286638032Speter	  case O_SSFILE:	/* service switch file */
286790792Sgshapiro		CANONIFY(val);
286838032Speter		ServiceSwitchFile = newstr(val);
286938032Speter		break;
287038032Speter
287138032Speter	  case O_DIALDELAY:	/* delay for dial-on-demand operation */
287238032Speter		DialDelay = convtime(val, 's');
287338032Speter		break;
287438032Speter
287538032Speter	  case O_NORCPTACTION:	/* what to do if no recipient */
287690792Sgshapiro		if (sm_strcasecmp(val, "none") == 0)
287738032Speter			NoRecipientAction = NRA_NO_ACTION;
287890792Sgshapiro		else if (sm_strcasecmp(val, "add-to") == 0)
287938032Speter			NoRecipientAction = NRA_ADD_TO;
288090792Sgshapiro		else if (sm_strcasecmp(val, "add-apparently-to") == 0)
288138032Speter			NoRecipientAction = NRA_ADD_APPARENTLY_TO;
288290792Sgshapiro		else if (sm_strcasecmp(val, "add-bcc") == 0)
288338032Speter			NoRecipientAction = NRA_ADD_BCC;
288490792Sgshapiro		else if (sm_strcasecmp(val, "add-to-undisclosed") == 0)
288538032Speter			NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
288638032Speter		else
288738032Speter			syserr("Invalid NoRecipientAction: %s", val);
288838032Speter		break;
288938032Speter
289038032Speter	  case O_SAFEFILEENV:	/* chroot() environ for writing to files */
289194334Sgshapiro		if (*val == '\0')
289294334Sgshapiro			break;
289394334Sgshapiro
289494334Sgshapiro		/* strip trailing slashes */
289594334Sgshapiro		p = val + strlen(val) - 1;
289694334Sgshapiro		while (p >= val && *p == '/')
289794334Sgshapiro			*p-- = '\0';
289894334Sgshapiro
289994334Sgshapiro		if (*val == '\0')
290094334Sgshapiro			break;
290194334Sgshapiro
290238032Speter		SafeFileEnv = newstr(val);
290338032Speter		break;
290438032Speter
290538032Speter	  case O_MAXMSGSIZE:	/* maximum message size */
290638032Speter		MaxMessageSize = atol(val);
290738032Speter		break;
290838032Speter
290938032Speter	  case O_COLONOKINADDR:	/* old style handling of colon addresses */
291038032Speter		ColonOkInAddr = atobool(val);
291138032Speter		break;
291238032Speter
291338032Speter	  case O_MAXQUEUERUN:	/* max # of jobs in a single queue run */
291490792Sgshapiro		MaxQueueRun = atoi(val);
291538032Speter		break;
291638032Speter
291738032Speter	  case O_MAXCHILDREN:	/* max # of children of daemon */
291838032Speter		MaxChildren = atoi(val);
291938032Speter		break;
292038032Speter
292190792Sgshapiro	  case O_MAXQUEUECHILDREN: /* max # of children of daemon */
292290792Sgshapiro		MaxQueueChildren = atoi(val);
292390792Sgshapiro		break;
292490792Sgshapiro
292590792Sgshapiro	  case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */
292690792Sgshapiro		MaxRunnersPerQueue = atoi(val);
292790792Sgshapiro		break;
292890792Sgshapiro
292990792Sgshapiro	  case O_NICEQUEUERUN:		/* nice queue runs */
293090792Sgshapiro#if !HASNICE
293190792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
293290792Sgshapiro				     "Warning: NiceQueueRun set on system that doesn't support nice()\n");
293390792Sgshapiro#endif /* !HASNICE */
293490792Sgshapiro
293590792Sgshapiro		/* XXX do we want to check the range? > 0 ? */
293690792Sgshapiro		NiceQueueRun = atoi(val);
293790792Sgshapiro		break;
293890792Sgshapiro
293994334Sgshapiro	  case O_SHMKEY:		/* shared memory key */
294090792Sgshapiro#if SM_CONF_SHM
294190792Sgshapiro		ShmKey = atol(val);
294290792Sgshapiro#else /* SM_CONF_SHM */
294390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
294490792Sgshapiro				     "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
294590792Sgshapiro				     OPTNAME);
294690792Sgshapiro#endif /* SM_CONF_SHM */
294790792Sgshapiro		break;
294890792Sgshapiro
294994334Sgshapiro#if _FFR_SELECT_SHM
295094334Sgshapiro	  case O_SHMKEYFILE:		/* shared memory key file */
295194334Sgshapiro# if SM_CONF_SHM
295298841Sgshapiro		SET_STRING_EXP(ShmKeyFile);
295394334Sgshapiro# else /* SM_CONF_SHM */
295494334Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
295594334Sgshapiro				     "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
295694334Sgshapiro				     OPTNAME);
295798841Sgshapiro		break;
295894334Sgshapiro# endif /* SM_CONF_SHM */
295994334Sgshapiro#endif /* _FFR_SELECT_SHM */
296094334Sgshapiro
296164562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
296264562Sgshapiro	  case O_MAXFORWARD:	/* max # of forward entries */
296364562Sgshapiro		MaxForwardEntries = atoi(val);
296464562Sgshapiro		break;
296564562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */
296664562Sgshapiro
296738032Speter	  case O_KEEPCNAMES:	/* don't expand CNAME records */
296838032Speter		DontExpandCnames = atobool(val);
296938032Speter		break;
297038032Speter
297138032Speter	  case O_MUSTQUOTE:	/* must quote these characters in phrases */
297290792Sgshapiro		(void) sm_strlcpy(buf, "@,;:\\()[]", sizeof buf);
297390792Sgshapiro		if (strlen(val) < sizeof buf - 10)
297490792Sgshapiro			(void) sm_strlcat(buf, val, sizeof buf);
297564562Sgshapiro		else
297690792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
297790792Sgshapiro					     "Warning: MustQuoteChars too long, ignored.\n");
297838032Speter		MustQuoteChars = newstr(buf);
297938032Speter		break;
298038032Speter
298138032Speter	  case O_SMTPGREETING:	/* SMTP greeting message (old $e macro) */
298238032Speter		SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
298338032Speter		break;
298438032Speter
298538032Speter	  case O_UNIXFROM:	/* UNIX From_ line (old $l macro) */
298638032Speter		UnixFromLine = newstr(munchstring(val, NULL, '\0'));
298738032Speter		break;
298838032Speter
298938032Speter	  case O_OPCHARS:	/* operator characters (old $o macro) */
299064562Sgshapiro		if (OperatorChars != NULL)
299190792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
299290792Sgshapiro					     "Warning: OperatorChars is being redefined.\n         It should only be set before ruleset definitions.\n");
299338032Speter		OperatorChars = newstr(munchstring(val, NULL, '\0'));
299438032Speter		break;
299538032Speter
299638032Speter	  case O_DONTINITGRPS:	/* don't call initgroups(3) */
299738032Speter		DontInitGroups = atobool(val);
299838032Speter		break;
299938032Speter
300038032Speter	  case O_SLFH:		/* make sure from fits on one line */
300138032Speter		SingleLineFromHeader = atobool(val);
300238032Speter		break;
300338032Speter
300438032Speter	  case O_ABH:		/* allow HELO commands with syntax errors */
300538032Speter		AllowBogusHELO = atobool(val);
300638032Speter		break;
300738032Speter
300838032Speter	  case O_CONNTHROT:	/* connection rate throttle */
300938032Speter		ConnRateThrottle = atoi(val);
301038032Speter		break;
301138032Speter
301238032Speter	  case O_UGW:		/* group writable files are unsafe */
301338032Speter		if (!atobool(val))
301464562Sgshapiro		{
301564562Sgshapiro			setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
301664562Sgshapiro				DontBlameSendmail);
301764562Sgshapiro			setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
301864562Sgshapiro				DontBlameSendmail);
301964562Sgshapiro		}
302038032Speter		break;
302138032Speter
302238032Speter	  case O_DBLBOUNCE:	/* address to which to send double bounces */
302390792Sgshapiro		DoubleBounceAddr = newstr(val);
302438032Speter		break;
302538032Speter
302638032Speter	  case O_HSDIR:		/* persistent host status directory */
302738032Speter		if (val[0] != '\0')
302873188Sgshapiro		{
302990792Sgshapiro			CANONIFY(val);
303038032Speter			HostStatDir = newstr(val);
303173188Sgshapiro		}
303238032Speter		break;
303338032Speter
303438032Speter	  case O_SINGTHREAD:	/* single thread deliveries (requires hsdir) */
303538032Speter		SingleThreadDelivery = atobool(val);
303638032Speter		break;
303738032Speter
303838032Speter	  case O_RUNASUSER:	/* run bulk of code as this user */
303938032Speter		for (p = val; *p != '\0'; p++)
304038032Speter		{
304194334Sgshapiro# if _FFR_DOTTED_USERNAMES
304290792Sgshapiro			if (*p == '/' || *p == ':')
304394334Sgshapiro# else /* _FFR_DOTTED_USERNAMES */
304438032Speter			if (*p == '.' || *p == '/' || *p == ':')
304594334Sgshapiro# endif /* _FFR_DOTTED_USERNAMES */
304638032Speter			{
304738032Speter				*p++ = '\0';
304838032Speter				break;
304938032Speter			}
305038032Speter		}
305138032Speter		if (isascii(*val) && isdigit(*val))
305238032Speter		{
305338032Speter			if (can_setuid)
305438032Speter				RunAsUid = atoi(val);
305538032Speter		}
305638032Speter		else
305738032Speter		{
305838032Speter			register struct passwd *pw;
305938032Speter
306038032Speter			pw = sm_getpwnam(val);
306138032Speter			if (pw == NULL)
306271345Sgshapiro			{
306338032Speter				syserr("readcf: option RunAsUser: unknown user %s", val);
306471345Sgshapiro				break;
306571345Sgshapiro			}
306638032Speter			else if (can_setuid)
306738032Speter			{
306838032Speter				if (*p == '\0')
306938032Speter					RunAsUserName = newstr(val);
307038032Speter				RunAsUid = pw->pw_uid;
307138032Speter				RunAsGid = pw->pw_gid;
307238032Speter			}
307390792Sgshapiro			else if (EffGid == pw->pw_gid)
307490792Sgshapiro				RunAsGid = pw->pw_gid;
307590792Sgshapiro			else if (UseMSP && *p == '\0')
307690792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
307790792Sgshapiro						     "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
307890792Sgshapiro						     (int) EffGid,
307990792Sgshapiro						     (int) pw->pw_gid);
308038032Speter		}
308190792Sgshapiro# ifdef UID_MAX
308238032Speter		if (RunAsUid > UID_MAX)
308338032Speter		{
308438032Speter			syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
308571345Sgshapiro				(long) RunAsUid, (long) UID_MAX);
308671345Sgshapiro			break;
308738032Speter		}
308890792Sgshapiro# endif /* UID_MAX */
308938032Speter		if (*p != '\0')
309038032Speter		{
309138032Speter			if (isascii(*p) && isdigit(*p))
309238032Speter			{
309390792Sgshapiro				gid_t runasgid;
309490792Sgshapiro
309590792Sgshapiro				runasgid = (gid_t) atoi(p);
309690792Sgshapiro				if (can_setuid || EffGid == runasgid)
309790792Sgshapiro					RunAsGid = runasgid;
309890792Sgshapiro				else if (UseMSP)
309990792Sgshapiro					(void) sm_io_fprintf(smioout,
310090792Sgshapiro							     SM_TIME_DEFAULT,
310190792Sgshapiro							     "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
310290792Sgshapiro							     (int) EffGid,
310390792Sgshapiro							     (int) runasgid);
310438032Speter			}
310538032Speter			else
310638032Speter			{
310738032Speter				register struct group *gr;
310864562Sgshapiro
310938032Speter				gr = getgrnam(p);
311038032Speter				if (gr == NULL)
311138032Speter					syserr("readcf: option RunAsUser: unknown group %s",
311238032Speter						p);
311390792Sgshapiro				else if (can_setuid || EffGid == gr->gr_gid)
311438032Speter					RunAsGid = gr->gr_gid;
311590792Sgshapiro				else if (UseMSP)
311690792Sgshapiro					(void) sm_io_fprintf(smioout,
311790792Sgshapiro							     SM_TIME_DEFAULT,
311890792Sgshapiro							     "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
311990792Sgshapiro							     (int) EffGid,
312090792Sgshapiro							     (int) gr->gr_gid);
312138032Speter			}
312238032Speter		}
312338032Speter		if (tTd(47, 5))
312490792Sgshapiro			sm_dprintf("readcf: RunAsUser = %d:%d\n",
312590792Sgshapiro				   (int) RunAsUid, (int) RunAsGid);
312638032Speter		break;
312738032Speter
312838032Speter	  case O_DSN_RRT:
312938032Speter		RrtImpliesDsn = atobool(val);
313038032Speter		break;
313138032Speter
313238032Speter	  case O_PIDFILE:
313390792Sgshapiro		PSTRSET(PidFile, val);
313438032Speter		break;
313538032Speter
313690792Sgshapiro	  case O_DONTBLAMESENDMAIL:
313738032Speter		p = val;
313838032Speter		for (;;)
313938032Speter		{
314038032Speter			register struct dbsval *dbs;
314138032Speter			extern struct dbsval DontBlameSendmailValues[];
314238032Speter
314338032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
314438032Speter				p++;
314538032Speter			if (*p == '\0')
314638032Speter				break;
314738032Speter			val = p;
314838032Speter			while (isascii(*p) && isalnum(*p))
314938032Speter				p++;
315038032Speter			if (*p != '\0')
315138032Speter				*p++ = '\0';
315238032Speter
315338032Speter			for (dbs = DontBlameSendmailValues;
315438032Speter			     dbs->dbs_name != NULL; dbs++)
315538032Speter			{
315690792Sgshapiro				if (sm_strcasecmp(val, dbs->dbs_name) == 0)
315738032Speter					break;
315838032Speter			}
315938032Speter			if (dbs->dbs_name == NULL)
316038032Speter				syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
316138032Speter			else if (dbs->dbs_flag == DBS_SAFE)
316264562Sgshapiro				clrbitmap(DontBlameSendmail);
316338032Speter			else
316464562Sgshapiro				setbitn(dbs->dbs_flag, DontBlameSendmail);
316538032Speter		}
316690792Sgshapiro		sticky = false;
316738032Speter		break;
316838032Speter
316938032Speter	  case O_DPI:
317090792Sgshapiro		if (sm_strcasecmp(val, "loopback") == 0)
317190792Sgshapiro			DontProbeInterfaces = DPI_SKIPLOOPBACK;
317290792Sgshapiro		else if (atobool(val))
317390792Sgshapiro			DontProbeInterfaces = DPI_PROBENONE;
317490792Sgshapiro		else
317590792Sgshapiro			DontProbeInterfaces = DPI_PROBEALL;
317638032Speter		break;
317738032Speter
317838032Speter	  case O_MAXRCPT:
317938032Speter		MaxRcptPerMsg = atoi(val);
318038032Speter		break;
318138032Speter
318290792Sgshapiro	  case O_RCPTTHROT:
318390792Sgshapiro		BadRcptThrottle = atoi(val);
318490792Sgshapiro		break;
318590792Sgshapiro
318638032Speter	  case O_DEADLETTER:
318790792Sgshapiro		CANONIFY(val);
318890792Sgshapiro		PSTRSET(DeadLetterDrop, val);
318938032Speter		break;
319038032Speter
319138032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
319238032Speter	  case O_DONTLOCK:
319338032Speter		DontLockReadFiles = atobool(val);
319438032Speter		break;
319564562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
319638032Speter
319738032Speter	  case O_MAXALIASRCSN:
319838032Speter		MaxAliasRecursion = atoi(val);
319938032Speter		break;
320038032Speter
320138032Speter	  case O_CNCTONLYTO:
320238032Speter		/* XXX should probably use gethostbyname */
320364562Sgshapiro#if NETINET || NETINET6
320490792Sgshapiro		ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
320564562Sgshapiro# if NETINET6
320690792Sgshapiro		if (anynet_pton(AF_INET6, val,
320790792Sgshapiro				&ConnectOnlyTo.sin6.sin6_addr) != 1)
320864562Sgshapiro			ConnectOnlyTo.sa.sa_family = AF_INET6;
320964562Sgshapiro		else
321064562Sgshapiro# endif /* NETINET6 */
321190792Sgshapiro# if NETINET
321264562Sgshapiro		{
321364562Sgshapiro			ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
321490792Sgshapiro			if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
321590792Sgshapiro				ConnectOnlyTo.sa.sa_family = AF_INET;
321664562Sgshapiro		}
321790792Sgshapiro
321890792Sgshapiro# endif /* NETINET */
321990792Sgshapiro		if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC)
322090792Sgshapiro		{
322190792Sgshapiro			syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
322290792Sgshapiro			       val);
322390792Sgshapiro			break;
322490792Sgshapiro		}
322564562Sgshapiro#endif /* NETINET || NETINET6 */
322638032Speter		break;
322738032Speter
322842575Speter	  case O_TRUSTUSER:
322990792Sgshapiro# if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING)
323090792Sgshapiro		if (!UseMSP)
323190792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
323290792Sgshapiro					     "readcf: option TrustedUser may cause problems on systems\n        which do not support fchown() if UseMSP is not set.\n");
323390792Sgshapiro# endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */
323438032Speter		if (isascii(*val) && isdigit(*val))
323542575Speter			TrustedUid = atoi(val);
323638032Speter		else
323738032Speter		{
323838032Speter			register struct passwd *pw;
323938032Speter
324042575Speter			TrustedUid = 0;
324138032Speter			pw = sm_getpwnam(val);
324238032Speter			if (pw == NULL)
324371345Sgshapiro			{
324442575Speter				syserr("readcf: option TrustedUser: unknown user %s", val);
324571345Sgshapiro				break;
324671345Sgshapiro			}
324738032Speter			else
324842575Speter				TrustedUid = pw->pw_uid;
324938032Speter		}
325038032Speter
325164562Sgshapiro# ifdef UID_MAX
325242575Speter		if (TrustedUid > UID_MAX)
325338032Speter		{
325442575Speter			syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
325571345Sgshapiro				(long) TrustedUid, (long) UID_MAX);
325642575Speter			TrustedUid = 0;
325738032Speter		}
325864562Sgshapiro# endif /* UID_MAX */
325938032Speter		break;
326038032Speter
326142575Speter	  case O_MAXMIMEHDRLEN:
326242575Speter		p = strchr(val, '/');
326342575Speter		if (p != NULL)
326442575Speter			*p++ = '\0';
326542575Speter		MaxMimeHeaderLength = atoi(val);
326642575Speter		if (p != NULL && *p != '\0')
326742575Speter			MaxMimeFieldLength = atoi(p);
326842575Speter		else
326942575Speter			MaxMimeFieldLength = MaxMimeHeaderLength / 2;
327042575Speter
327142575Speter		if (MaxMimeHeaderLength < 0)
327242575Speter			MaxMimeHeaderLength = 0;
327342575Speter		else if (MaxMimeHeaderLength < 128)
327490792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
327590792Sgshapiro					     "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
327642575Speter
327742575Speter		if (MaxMimeFieldLength < 0)
327842575Speter			MaxMimeFieldLength = 0;
327942575Speter		else if (MaxMimeFieldLength < 40)
328090792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
328190792Sgshapiro					     "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
328242575Speter		break;
328342575Speter
328442575Speter	  case O_CONTROLSOCKET:
328590792Sgshapiro		PSTRSET(ControlSocketName, val);
328642575Speter		break;
328742575Speter
328843730Speter	  case O_MAXHDRSLEN:
328943730Speter		MaxHeadersLength = atoi(val);
329043148Speter
329143730Speter		if (MaxHeadersLength > 0 &&
329243730Speter		    MaxHeadersLength < (MAXHDRSLEN / 2))
329390792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
329490792Sgshapiro					     "Warning: MaxHeadersLength: headers length limit set lower than %d\n",
329590792Sgshapiro					     (MAXHDRSLEN / 2));
329643148Speter		break;
329743148Speter
329864562Sgshapiro	  case O_PROCTITLEPREFIX:
329990792Sgshapiro		PSTRSET(ProcTitlePrefix, val);
330064562Sgshapiro		break;
330164562Sgshapiro
330264562Sgshapiro#if SASL
330364562Sgshapiro	  case O_SASLINFO:
330490792Sgshapiro# if _FFR_ALLOW_SASLINFO
330564562Sgshapiro		/*
330690792Sgshapiro		**  Allow users to select their own authinfo file
330790792Sgshapiro		**  under certain circumstances, otherwise just ignore
330890792Sgshapiro		**  the option.  If the option isn't ignored, several
330990792Sgshapiro		**  commands don't work very well, e.g., mailq.
331064562Sgshapiro		**  However, this is not a "perfect" solution.
331164562Sgshapiro		**  If mail is queued, the authentication info
331264562Sgshapiro		**  will not be used in subsequent delivery attempts.
331364562Sgshapiro		**  If we really want to support this, then it has
331464562Sgshapiro		**  to be stored in the queue file.
331564562Sgshapiro		*/
331664562Sgshapiro		if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
331764562Sgshapiro		    RunAsUid != RealUid)
331864562Sgshapiro			break;
331990792Sgshapiro# endif /* _FFR_ALLOW_SASLINFO */
332090792Sgshapiro		PSTRSET(SASLInfo, val);
332164562Sgshapiro		break;
332264562Sgshapiro
332364562Sgshapiro	  case O_SASLMECH:
332464562Sgshapiro		if (AuthMechanisms != NULL)
332590792Sgshapiro			sm_free(AuthMechanisms); /* XXX */
332664562Sgshapiro		if (*val != '\0')
332764562Sgshapiro			AuthMechanisms = newstr(val);
332864562Sgshapiro		else
332964562Sgshapiro			AuthMechanisms = NULL;
333064562Sgshapiro		break;
333164562Sgshapiro
333264562Sgshapiro	  case O_SASLOPTS:
333364562Sgshapiro		while (val != NULL && *val != '\0')
333464562Sgshapiro		{
333590792Sgshapiro			switch (*val)
333664562Sgshapiro			{
333764562Sgshapiro			  case 'A':
333864562Sgshapiro				SASLOpts |= SASL_AUTH_AUTH;
333964562Sgshapiro				break;
334064562Sgshapiro			  case 'a':
334164562Sgshapiro				SASLOpts |= SASL_SEC_NOACTIVE;
334264562Sgshapiro				break;
334364562Sgshapiro			  case 'c':
334464562Sgshapiro				SASLOpts |= SASL_SEC_PASS_CREDENTIALS;
334564562Sgshapiro				break;
334664562Sgshapiro			  case 'd':
334764562Sgshapiro				SASLOpts |= SASL_SEC_NODICTIONARY;
334864562Sgshapiro				break;
334964562Sgshapiro			  case 'f':
335064562Sgshapiro				SASLOpts |= SASL_SEC_FORWARD_SECRECY;
335164562Sgshapiro				break;
335298121Sgshapiro# if _FFR_SASL_OPT_M
335398121Sgshapiro/* to be activated in 8.13 */
335498121Sgshapiro#  if SASL >= 20101
335598121Sgshapiro			  case 'm':
335698121Sgshapiro				SASLOpts |= SASL_SEC_MUTUAL_AUTH;
335798121Sgshapiro				break;
335898121Sgshapiro#  endif /* SASL >= 20101 */
335998121Sgshapiro# endif /* _FFR_SASL_OPT_M */
336064562Sgshapiro			  case 'p':
336164562Sgshapiro				SASLOpts |= SASL_SEC_NOPLAINTEXT;
336264562Sgshapiro				break;
336364562Sgshapiro			  case 'y':
336464562Sgshapiro				SASLOpts |= SASL_SEC_NOANONYMOUS;
336564562Sgshapiro				break;
336690792Sgshapiro			  case ' ':	/* ignore */
336790792Sgshapiro			  case '\t':	/* ignore */
336890792Sgshapiro			  case ',':	/* ignore */
336990792Sgshapiro				break;
337064562Sgshapiro			  default:
337190792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
337290792Sgshapiro						     "Warning: Option: %s unknown parameter '%c'\n",
337390792Sgshapiro						     OPTNAME,
337490792Sgshapiro						     (isascii(*val) &&
337590792Sgshapiro							isprint(*val))
337690792Sgshapiro							? *val : '?');
337764562Sgshapiro				break;
337864562Sgshapiro			}
337964562Sgshapiro			++val;
338064562Sgshapiro			val = strpbrk(val, ", \t");
338164562Sgshapiro			if (val != NULL)
338264562Sgshapiro				++val;
338364562Sgshapiro		}
338464562Sgshapiro		break;
338590792Sgshapiro	  case O_SASLBITS:
338690792Sgshapiro		MaxSLBits = atoi(val);
338790792Sgshapiro		break;
338864562Sgshapiro
338964562Sgshapiro#else /* SASL */
339064562Sgshapiro	  case O_SASLINFO:
339164562Sgshapiro	  case O_SASLMECH:
339264562Sgshapiro	  case O_SASLOPTS:
339390792Sgshapiro	  case O_SASLBITS:
339490792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
339590792Sgshapiro				     "Warning: Option: %s requires SASL support (-DSASL)\n",
339690792Sgshapiro				     OPTNAME);
339764562Sgshapiro		break;
339864562Sgshapiro#endif /* SASL */
339964562Sgshapiro
340064562Sgshapiro#if STARTTLS
340164562Sgshapiro	  case O_SRVCERTFILE:
340290792Sgshapiro		SET_STRING_EXP(SrvCERTfile);
340364562Sgshapiro	  case O_SRVKEYFILE:
340490792Sgshapiro		SET_STRING_EXP(Srvkeyfile);
340564562Sgshapiro	  case O_CLTCERTFILE:
340690792Sgshapiro		SET_STRING_EXP(CltCERTfile);
340764562Sgshapiro	  case O_CLTKEYFILE:
340890792Sgshapiro		SET_STRING_EXP(Cltkeyfile);
340964562Sgshapiro	  case O_CACERTFILE:
341090792Sgshapiro		SET_STRING_EXP(CACERTfile);
341164562Sgshapiro	  case O_CACERTPATH:
341290792Sgshapiro		SET_STRING_EXP(CACERTpath);
341364562Sgshapiro	  case O_DHPARAMS:
341490792Sgshapiro		SET_STRING_EXP(DHParams);
341590792Sgshapiro# if _FFR_TLS_1
341664562Sgshapiro	  case O_DHPARAMS5:
341790792Sgshapiro		SET_STRING_EXP(DHParams5);
341890792Sgshapiro	  case O_CIPHERLIST:
341990792Sgshapiro		SET_STRING_EXP(CipherList);
342090792Sgshapiro# endif /* _FFR_TLS_1 */
342164562Sgshapiro
342290792Sgshapiro	/*
342390792Sgshapiro	**  XXX How about options per daemon/client instead of globally?
342490792Sgshapiro	**  This doesn't work well for some options, e.g., no server cert,
342590792Sgshapiro	**  but fine for others.
342690792Sgshapiro	**
342790792Sgshapiro	**  XXX Some people may want different certs per server.
342890792Sgshapiro	**
342990792Sgshapiro	**  See also srvfeatures()
343090792Sgshapiro	*/
343190792Sgshapiro
343290792Sgshapiro	  case O_TLS_SRV_OPTS:
343390792Sgshapiro		while (val != NULL && *val != '\0')
343490792Sgshapiro		{
343590792Sgshapiro			switch (*val)
343690792Sgshapiro			{
343790792Sgshapiro			  case 'V':
343890792Sgshapiro				TLS_Srv_Opts |= TLS_I_NO_VRFY;
343990792Sgshapiro				break;
344090792Sgshapiro# if _FFR_TLS_1
344190792Sgshapiro			/*
344290792Sgshapiro			**  Server without a cert? That works only if
344390792Sgshapiro			**  AnonDH is enabled as cipher, which is not in the
344490792Sgshapiro			**  default list. Hence the CipherList option must
344590792Sgshapiro			**  be available. Moreover: which clients support this
344690792Sgshapiro			**  besides sendmail with this setting?
344790792Sgshapiro			*/
344890792Sgshapiro
344990792Sgshapiro			  case 'C':
345090792Sgshapiro				TLS_Srv_Opts &= ~TLS_I_SRV_CERT;
345190792Sgshapiro				break;
345290792Sgshapiro# endif /* _FFR_TLS_1 */
345390792Sgshapiro			  case ' ':	/* ignore */
345490792Sgshapiro			  case '\t':	/* ignore */
345590792Sgshapiro			  case ',':	/* ignore */
345690792Sgshapiro				break;
345790792Sgshapiro			  default:
345890792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
345990792Sgshapiro						     "Warning: Option: %s unknown parameter '%c'\n",
346090792Sgshapiro						     OPTNAME,
346190792Sgshapiro						     (isascii(*val) &&
346290792Sgshapiro							isprint(*val))
346390792Sgshapiro							? *val : '?');
346490792Sgshapiro				break;
346590792Sgshapiro			}
346690792Sgshapiro			++val;
346790792Sgshapiro			val = strpbrk(val, ", \t");
346890792Sgshapiro			if (val != NULL)
346990792Sgshapiro				++val;
347090792Sgshapiro		}
347164562Sgshapiro		break;
347264562Sgshapiro
347364562Sgshapiro	  case O_RANDFILE:
347490792Sgshapiro		PSTRSET(RandFile, val);
347564562Sgshapiro		break;
347664562Sgshapiro
347790792Sgshapiro#else /* STARTTLS */
347864562Sgshapiro	  case O_SRVCERTFILE:
347964562Sgshapiro	  case O_SRVKEYFILE:
348064562Sgshapiro	  case O_CLTCERTFILE:
348164562Sgshapiro	  case O_CLTKEYFILE:
348264562Sgshapiro	  case O_CACERTFILE:
348364562Sgshapiro	  case O_CACERTPATH:
348464562Sgshapiro	  case O_DHPARAMS:
348590792Sgshapiro# if _FFR_TLS_1
348664562Sgshapiro	  case O_DHPARAMS5:
348764562Sgshapiro	  case O_CIPHERLIST:
348890792Sgshapiro# endif /* _FFR_TLS_1 */
348964562Sgshapiro	  case O_RANDFILE:
349090792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
349190792Sgshapiro				     "Warning: Option: %s requires TLS support\n",
349290792Sgshapiro				     OPTNAME);
349364562Sgshapiro		break;
349464562Sgshapiro
349590792Sgshapiro#endif /* STARTTLS */
349664562Sgshapiro
349764562Sgshapiro	  case O_CLIENTPORT:
349864562Sgshapiro		setclientoptions(val);
349964562Sgshapiro		break;
350064562Sgshapiro
350164562Sgshapiro	  case O_DF_BUFSIZE:
350264562Sgshapiro		DataFileBufferSize = atoi(val);
350364562Sgshapiro		break;
350464562Sgshapiro
350564562Sgshapiro	  case O_XF_BUFSIZE:
350664562Sgshapiro		XscriptFileBufferSize = atoi(val);
350764562Sgshapiro		break;
350864562Sgshapiro
350964562Sgshapiro	  case O_LDAPDEFAULTSPEC:
351090792Sgshapiro#if LDAPMAP
351164562Sgshapiro		ldapmap_set_defaults(val);
351264562Sgshapiro#else /* LDAPMAP */
351390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
351490792Sgshapiro				     "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
351590792Sgshapiro				     OPTNAME);
351664562Sgshapiro#endif /* LDAPMAP */
351764562Sgshapiro		break;
351864562Sgshapiro
351964562Sgshapiro	  case O_INPUTMILTER:
352090792Sgshapiro#if MILTER
352164562Sgshapiro		InputFilterList = newstr(val);
352290792Sgshapiro#else /* MILTER */
352390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
352490792Sgshapiro				     "Warning: Option: %s requires Milter support (-DMILTER)\n",
352590792Sgshapiro				     OPTNAME);
352690792Sgshapiro#endif /* MILTER */
352764562Sgshapiro		break;
352864562Sgshapiro
352964562Sgshapiro	  case O_MILTER:
353090792Sgshapiro#if MILTER
353164562Sgshapiro		milter_set_option(subopt, val, sticky);
353290792Sgshapiro#else /* MILTER */
353390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
353490792Sgshapiro				     "Warning: Option: %s requires Milter support (-DMILTER)\n",
353590792Sgshapiro				     OPTNAME);
353690792Sgshapiro#endif /* MILTER */
353764562Sgshapiro		break;
353864562Sgshapiro
353964562Sgshapiro	  case O_QUEUE_FILE_MODE:	/* queue file mode */
354064562Sgshapiro		QueueFileMode = atooct(val) & 0777;
354164562Sgshapiro		break;
354264562Sgshapiro
354390792Sgshapiro	  case O_DLVR_MIN:	/* deliver by minimum time */
354490792Sgshapiro		DeliverByMin = convtime(val, 's');
354590792Sgshapiro		break;
354690792Sgshapiro
354790792Sgshapiro	  /* modifiers {daemon_flags} for direct submissions */
354890792Sgshapiro	  case O_DIRECTSUBMODIFIERS:
354990792Sgshapiro		{
355090792Sgshapiro			BITMAP256 m;	/* ignored */
355190792Sgshapiro			extern ENVELOPE BlankEnvelope;
355290792Sgshapiro
355390792Sgshapiro			macdefine(&BlankEnvelope.e_macro, A_PERM,
355490792Sgshapiro				  macid("{daemon_flags}"),
355590792Sgshapiro				  getmodifiers(val, m));
355690792Sgshapiro		}
355790792Sgshapiro		break;
355890792Sgshapiro
355990792Sgshapiro	  case O_FASTSPLIT:
356090792Sgshapiro		FastSplit = atoi(val);
356190792Sgshapiro		break;
356290792Sgshapiro
356390792Sgshapiro	  case O_MBDB:
356490792Sgshapiro		Mbdb = newstr(val);
356590792Sgshapiro		break;
356690792Sgshapiro
356790792Sgshapiro	  case O_MSQ:
356890792Sgshapiro		UseMSP = atobool(val);
356990792Sgshapiro		break;
357090792Sgshapiro
357190792Sgshapiro#if _FFR_SOFT_BOUNCE
357290792Sgshapiro	  case O_SOFTBOUNCE:
357390792Sgshapiro		SoftBounce = atobool(val);
357490792Sgshapiro		break;
357590792Sgshapiro#endif /* _FFR_SOFT_BOUNCE */
357690792Sgshapiro
357738032Speter	  default:
357838032Speter		if (tTd(37, 1))
357938032Speter		{
358038032Speter			if (isascii(opt) && isprint(opt))
358190792Sgshapiro				sm_dprintf("Warning: option %c unknown\n", opt);
358238032Speter			else
358390792Sgshapiro				sm_dprintf("Warning: option 0x%x unknown\n", opt);
358438032Speter		}
358538032Speter		break;
358638032Speter	}
358764562Sgshapiro
358864562Sgshapiro	/*
358964562Sgshapiro	**  Options with suboptions are responsible for taking care
359064562Sgshapiro	**  of sticky-ness (e.g., that a command line setting is kept
359164562Sgshapiro	**  when reading in the sendmail.cf file).  This has to be done
359264562Sgshapiro	**  when the suboptions are parsed since each suboption must be
359364562Sgshapiro	**  sticky, not the root option.
359464562Sgshapiro	*/
359564562Sgshapiro
359664562Sgshapiro	if (sticky && !bitset(OI_SUBOPT, o->o_flags))
359738032Speter		setbitn(opt, StickyOpt);
359838032Speter}
359990792Sgshapiro/*
360038032Speter**  SETCLASS -- set a string into a class
360138032Speter**
360238032Speter**	Parameters:
360338032Speter**		class -- the class to put the string in.
360438032Speter**		str -- the string to enter
360538032Speter**
360638032Speter**	Returns:
360738032Speter**		none.
360838032Speter**
360938032Speter**	Side Effects:
361038032Speter**		puts the word into the symbol table.
361138032Speter*/
361238032Speter
361338032Spetervoid
361438032Spetersetclass(class, str)
361538032Speter	int class;
361638032Speter	char *str;
361738032Speter{
361838032Speter	register STAB *s;
361938032Speter
362064562Sgshapiro	if ((*str & 0377) == MATCHCLASS)
362164562Sgshapiro	{
362264562Sgshapiro		int mid;
362364562Sgshapiro
362464562Sgshapiro		str++;
362590792Sgshapiro		mid = macid(str);
362671345Sgshapiro		if (mid == 0)
362764562Sgshapiro			return;
362864562Sgshapiro
362964562Sgshapiro		if (tTd(37, 8))
363090792Sgshapiro			sm_dprintf("setclass(%s, $=%s)\n",
363190792Sgshapiro				   macname(class), macname(mid));
363264562Sgshapiro		copy_class(mid, class);
363364562Sgshapiro	}
363464562Sgshapiro	else
363564562Sgshapiro	{
363664562Sgshapiro		if (tTd(37, 8))
363790792Sgshapiro			sm_dprintf("setclass(%s, %s)\n", macname(class), str);
363864562Sgshapiro
363964562Sgshapiro		s = stab(str, ST_CLASS, ST_ENTER);
364071345Sgshapiro		setbitn(bitidx(class), s->s_class);
364164562Sgshapiro	}
364238032Speter}
364390792Sgshapiro/*
364438032Speter**  MAKEMAPENTRY -- create a map entry
364538032Speter**
364638032Speter**	Parameters:
364738032Speter**		line -- the config file line
364838032Speter**
364938032Speter**	Returns:
365038032Speter**		A pointer to the map that has been created.
365138032Speter**		NULL if there was a syntax error.
365238032Speter**
365338032Speter**	Side Effects:
365438032Speter**		Enters the map into the dictionary.
365538032Speter*/
365638032Speter
365738032SpeterMAP *
365838032Spetermakemapentry(line)
365938032Speter	char *line;
366038032Speter{
366138032Speter	register char *p;
366238032Speter	char *mapname;
366338032Speter	char *classname;
366438032Speter	register STAB *s;
366538032Speter	STAB *class;
366638032Speter
366738032Speter	for (p = line; isascii(*p) && isspace(*p); p++)
366838032Speter		continue;
366938032Speter	if (!(isascii(*p) && isalnum(*p)))
367038032Speter	{
367138032Speter		syserr("readcf: config K line: no map name");
367238032Speter		return NULL;
367338032Speter	}
367438032Speter
367538032Speter	mapname = p;
367638032Speter	while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
367738032Speter		continue;
367838032Speter	if (*p != '\0')
367938032Speter		*p++ = '\0';
368038032Speter	while (isascii(*p) && isspace(*p))
368138032Speter		p++;
368238032Speter	if (!(isascii(*p) && isalnum(*p)))
368338032Speter	{
368438032Speter		syserr("readcf: config K line, map %s: no map class", mapname);
368538032Speter		return NULL;
368638032Speter	}
368738032Speter	classname = p;
368838032Speter	while (isascii(*++p) && isalnum(*p))
368938032Speter		continue;
369038032Speter	if (*p != '\0')
369138032Speter		*p++ = '\0';
369238032Speter	while (isascii(*p) && isspace(*p))
369338032Speter		p++;
369438032Speter
369538032Speter	/* look up the class */
369638032Speter	class = stab(classname, ST_MAPCLASS, ST_FIND);
369738032Speter	if (class == NULL)
369838032Speter	{
369990792Sgshapiro		syserr("readcf: map %s: class %s not available", mapname,
370090792Sgshapiro			classname);
370138032Speter		return NULL;
370238032Speter	}
370338032Speter
370438032Speter	/* enter the map */
370538032Speter	s = stab(mapname, ST_MAP, ST_ENTER);
370638032Speter	s->s_map.map_class = &class->s_mapclass;
370738032Speter	s->s_map.map_mname = newstr(mapname);
370838032Speter
370938032Speter	if (class->s_mapclass.map_parse(&s->s_map, p))
371038032Speter		s->s_map.map_mflags |= MF_VALID;
371138032Speter
371238032Speter	if (tTd(37, 5))
371338032Speter	{
371490792Sgshapiro		sm_dprintf("map %s, class %s, flags %lx, file %s,\n",
371590792Sgshapiro			   s->s_map.map_mname, s->s_map.map_class->map_cname,
371690792Sgshapiro			   s->s_map.map_mflags, s->s_map.map_file);
371790792Sgshapiro		sm_dprintf("\tapp %s, domain %s, rebuild %s\n",
371890792Sgshapiro			   s->s_map.map_app, s->s_map.map_domain,
371990792Sgshapiro			   s->s_map.map_rebuild);
372038032Speter	}
372138032Speter	return &s->s_map;
372238032Speter}
372390792Sgshapiro/*
372438032Speter**  STRTORWSET -- convert string to rewriting set number
372538032Speter**
372638032Speter**	Parameters:
372738032Speter**		p -- the pointer to the string to decode.
372838032Speter**		endp -- if set, store the trailing delimiter here.
372938032Speter**		stabmode -- ST_ENTER to create this entry, ST_FIND if
373038032Speter**			it must already exist.
373138032Speter**
373238032Speter**	Returns:
373338032Speter**		The appropriate ruleset number.
373438032Speter**		-1 if it is not valid (error already printed)
373538032Speter*/
373638032Speter
373738032Speterint
373838032Speterstrtorwset(p, endp, stabmode)
373938032Speter	char *p;
374038032Speter	char **endp;
374138032Speter	int stabmode;
374238032Speter{
374338032Speter	int ruleset;
374438032Speter	static int nextruleset = MAXRWSETS;
374538032Speter
374638032Speter	while (isascii(*p) && isspace(*p))
374738032Speter		p++;
374838032Speter	if (!isascii(*p))
374938032Speter	{
375038032Speter		syserr("invalid ruleset name: \"%.20s\"", p);
375138032Speter		return -1;
375238032Speter	}
375338032Speter	if (isdigit(*p))
375438032Speter	{
375538032Speter		ruleset = strtol(p, endp, 10);
375638032Speter		if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
375738032Speter		{
375838032Speter			syserr("bad ruleset %d (%d max)",
375938032Speter				ruleset, MAXRWSETS / 2);
376038032Speter			ruleset = -1;
376138032Speter		}
376238032Speter	}
376338032Speter	else
376438032Speter	{
376538032Speter		STAB *s;
376638032Speter		char delim;
376764562Sgshapiro		char *q = NULL;
376838032Speter
376938032Speter		q = p;
377038032Speter		while (*p != '\0' && isascii(*p) &&
377138032Speter		       (isalnum(*p) || *p == '_'))
377238032Speter			p++;
377338032Speter		if (q == p || !(isascii(*q) && isalpha(*q)))
377438032Speter		{
377538032Speter			/* no valid characters */
377638032Speter			syserr("invalid ruleset name: \"%.20s\"", q);
377738032Speter			return -1;
377838032Speter		}
377938032Speter		while (isascii(*p) && isspace(*p))
378038032Speter			*p++ = '\0';
378138032Speter		delim = *p;
378238032Speter		if (delim != '\0')
378338032Speter			*p = '\0';
378438032Speter		s = stab(q, ST_RULESET, stabmode);
378538032Speter		if (delim != '\0')
378638032Speter			*p = delim;
378738032Speter
378838032Speter		if (s == NULL)
378938032Speter			return -1;
379038032Speter
379138032Speter		if (stabmode == ST_ENTER && delim == '=')
379238032Speter		{
379338032Speter			while (isascii(*++p) && isspace(*p))
379438032Speter				continue;
379538032Speter			if (!(isascii(*p) && isdigit(*p)))
379638032Speter			{
379738032Speter				syserr("bad ruleset definition \"%s\" (number required after `=')", q);
379838032Speter				ruleset = -1;
379938032Speter			}
380038032Speter			else
380138032Speter			{
380238032Speter				ruleset = strtol(p, endp, 10);
380338032Speter				if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
380438032Speter				{
380538032Speter					syserr("bad ruleset number %d in \"%s\" (%d max)",
380638032Speter						ruleset, q, MAXRWSETS / 2);
380738032Speter					ruleset = -1;
380838032Speter				}
380938032Speter			}
381038032Speter		}
381138032Speter		else
381238032Speter		{
381338032Speter			if (endp != NULL)
381438032Speter				*endp = p;
381564562Sgshapiro			if (s->s_ruleset >= 0)
381638032Speter				ruleset = s->s_ruleset;
381738032Speter			else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
381838032Speter			{
381938032Speter				syserr("%s: too many named rulesets (%d max)",
382038032Speter					q, MAXRWSETS / 2);
382138032Speter				ruleset = -1;
382238032Speter			}
382338032Speter		}
382464562Sgshapiro		if (s->s_ruleset >= 0 &&
382564562Sgshapiro		    ruleset >= 0 &&
382664562Sgshapiro		    ruleset != s->s_ruleset)
382738032Speter		{
382838032Speter			syserr("%s: ruleset changed value (old %d, new %d)",
382938032Speter				q, s->s_ruleset, ruleset);
383038032Speter			ruleset = s->s_ruleset;
383138032Speter		}
383264562Sgshapiro		else if (ruleset >= 0)
383338032Speter		{
383438032Speter			s->s_ruleset = ruleset;
383538032Speter		}
383671345Sgshapiro		if (stabmode == ST_ENTER && ruleset >= 0)
383764562Sgshapiro		{
383864562Sgshapiro			char *h = NULL;
383964562Sgshapiro
384064562Sgshapiro			if (RuleSetNames[ruleset] != NULL)
384190792Sgshapiro				sm_free(RuleSetNames[ruleset]); /* XXX */
384264562Sgshapiro			if (delim != '\0' && (h = strchr(q, delim)) != NULL)
384364562Sgshapiro				*h = '\0';
384464562Sgshapiro			RuleSetNames[ruleset] = newstr(q);
384564562Sgshapiro			if (delim == '/' && h != NULL)
384664562Sgshapiro				*h = delim;	/* put back delim */
384764562Sgshapiro		}
384838032Speter	}
384938032Speter	return ruleset;
385038032Speter}
385190792Sgshapiro/*
385264562Sgshapiro**  SETTIMEOUT -- set an individual timeout
385364562Sgshapiro**
385464562Sgshapiro**	Parameters:
385564562Sgshapiro**		name -- the name of the timeout.
385664562Sgshapiro**		val -- the value of the timeout.
385764562Sgshapiro**		sticky -- if set, don't let other setoptions override
385864562Sgshapiro**			this value.
385964562Sgshapiro**
386064562Sgshapiro**	Returns:
386164562Sgshapiro**		none.
386264562Sgshapiro*/
386364562Sgshapiro
386464562Sgshapiro/* set if Timeout sub-option is stuck */
386564562Sgshapirostatic BITMAP256	StickyTimeoutOpt;
386664562Sgshapiro
386764562Sgshapirostatic struct timeoutinfo
386864562Sgshapiro{
386990792Sgshapiro	char		*to_name;	/* long name of timeout */
387090792Sgshapiro	unsigned char	to_code;	/* code for option */
387164562Sgshapiro} TimeOutTab[] =
387264562Sgshapiro{
387364562Sgshapiro#define TO_INITIAL			0x01
387464562Sgshapiro	{ "initial",			TO_INITIAL			},
387564562Sgshapiro#define TO_MAIL				0x02
387664562Sgshapiro	{ "mail",			TO_MAIL				},
387764562Sgshapiro#define TO_RCPT				0x03
387864562Sgshapiro	{ "rcpt",			TO_RCPT				},
387964562Sgshapiro#define TO_DATAINIT			0x04
388064562Sgshapiro	{ "datainit",			TO_DATAINIT			},
388164562Sgshapiro#define TO_DATABLOCK			0x05
388264562Sgshapiro	{ "datablock",			TO_DATABLOCK			},
388364562Sgshapiro#define TO_DATAFINAL			0x06
388464562Sgshapiro	{ "datafinal",			TO_DATAFINAL			},
388564562Sgshapiro#define TO_COMMAND			0x07
388664562Sgshapiro	{ "command",			TO_COMMAND			},
388764562Sgshapiro#define TO_RSET				0x08
388864562Sgshapiro	{ "rset",			TO_RSET				},
388964562Sgshapiro#define TO_HELO				0x09
389064562Sgshapiro	{ "helo",			TO_HELO				},
389164562Sgshapiro#define TO_QUIT				0x0A
389264562Sgshapiro	{ "quit",			TO_QUIT				},
389364562Sgshapiro#define TO_MISC				0x0B
389464562Sgshapiro	{ "misc",			TO_MISC				},
389564562Sgshapiro#define TO_IDENT			0x0C
389664562Sgshapiro	{ "ident",			TO_IDENT			},
389764562Sgshapiro#define TO_FILEOPEN			0x0D
389864562Sgshapiro	{ "fileopen",			TO_FILEOPEN			},
389964562Sgshapiro#define TO_CONNECT			0x0E
390064562Sgshapiro	{ "connect",			TO_CONNECT			},
390164562Sgshapiro#define TO_ICONNECT			0x0F
390264562Sgshapiro	{ "iconnect",			TO_ICONNECT			},
390364562Sgshapiro#define TO_QUEUEWARN			0x10
390464562Sgshapiro	{ "queuewarn",			TO_QUEUEWARN			},
390564562Sgshapiro	{ "queuewarn.*",		TO_QUEUEWARN			},
390664562Sgshapiro#define TO_QUEUEWARN_NORMAL		0x11
390764562Sgshapiro	{ "queuewarn.normal",		TO_QUEUEWARN_NORMAL		},
390864562Sgshapiro#define TO_QUEUEWARN_URGENT		0x12
390964562Sgshapiro	{ "queuewarn.urgent",		TO_QUEUEWARN_URGENT		},
391064562Sgshapiro#define TO_QUEUEWARN_NON_URGENT		0x13
391164562Sgshapiro	{ "queuewarn.non-urgent",	TO_QUEUEWARN_NON_URGENT		},
391264562Sgshapiro#define TO_QUEUERETURN			0x14
391364562Sgshapiro	{ "queuereturn",		TO_QUEUERETURN			},
391464562Sgshapiro	{ "queuereturn.*",		TO_QUEUERETURN			},
391564562Sgshapiro#define TO_QUEUERETURN_NORMAL		0x15
391664562Sgshapiro	{ "queuereturn.normal",		TO_QUEUERETURN_NORMAL		},
391764562Sgshapiro#define TO_QUEUERETURN_URGENT		0x16
391864562Sgshapiro	{ "queuereturn.urgent",		TO_QUEUERETURN_URGENT		},
391964562Sgshapiro#define TO_QUEUERETURN_NON_URGENT	0x17
392064562Sgshapiro	{ "queuereturn.non-urgent",	TO_QUEUERETURN_NON_URGENT	},
392164562Sgshapiro#define TO_HOSTSTATUS			0x18
392264562Sgshapiro	{ "hoststatus",			TO_HOSTSTATUS			},
392364562Sgshapiro#define TO_RESOLVER_RETRANS		0x19
392464562Sgshapiro	{ "resolver.retrans",		TO_RESOLVER_RETRANS		},
392564562Sgshapiro#define TO_RESOLVER_RETRANS_NORMAL	0x1A
392664562Sgshapiro	{ "resolver.retrans.normal",	TO_RESOLVER_RETRANS_NORMAL	},
392764562Sgshapiro#define TO_RESOLVER_RETRANS_FIRST	0x1B
392864562Sgshapiro	{ "resolver.retrans.first",	TO_RESOLVER_RETRANS_FIRST	},
392964562Sgshapiro#define TO_RESOLVER_RETRY		0x1C
393064562Sgshapiro	{ "resolver.retry",		TO_RESOLVER_RETRY		},
393164562Sgshapiro#define TO_RESOLVER_RETRY_NORMAL	0x1D
393264562Sgshapiro	{ "resolver.retry.normal",	TO_RESOLVER_RETRY_NORMAL	},
393364562Sgshapiro#define TO_RESOLVER_RETRY_FIRST		0x1E
393464562Sgshapiro	{ "resolver.retry.first",	TO_RESOLVER_RETRY_FIRST		},
393564562Sgshapiro#define TO_CONTROL			0x1F
393664562Sgshapiro	{ "control",			TO_CONTROL			},
393790792Sgshapiro#define TO_LHLO				0x20
393890792Sgshapiro	{ "lhlo",			TO_LHLO				},
393990792Sgshapiro#define TO_AUTH				0x21
394090792Sgshapiro	{ "auth",			TO_AUTH				},
394190792Sgshapiro#define TO_STARTTLS			0x22
394290792Sgshapiro	{ "starttls",			TO_STARTTLS			},
394390792Sgshapiro#define TO_ACONNECT			0x23
394490792Sgshapiro	{ "aconnect",			TO_ACONNECT			},
394564562Sgshapiro	{ NULL,				0				},
394664562Sgshapiro};
394764562Sgshapiro
394864562Sgshapiro
394964562Sgshapirostatic void
395064562Sgshapirosettimeout(name, val, sticky)
395164562Sgshapiro	char *name;
395264562Sgshapiro	char *val;
395364562Sgshapiro	bool sticky;
395464562Sgshapiro{
395564562Sgshapiro	register struct timeoutinfo *to;
395690792Sgshapiro	int i, addopts;
395764562Sgshapiro	time_t toval;
395864562Sgshapiro
395964562Sgshapiro	if (tTd(37, 2))
396090792Sgshapiro		sm_dprintf("settimeout(%s = %s)", name, val);
396164562Sgshapiro
396264562Sgshapiro	for (to = TimeOutTab; to->to_name != NULL; to++)
396364562Sgshapiro	{
396490792Sgshapiro		if (sm_strcasecmp(to->to_name, name) == 0)
396564562Sgshapiro			break;
396664562Sgshapiro	}
396764562Sgshapiro
396864562Sgshapiro	if (to->to_name == NULL)
396971345Sgshapiro	{
397071345Sgshapiro		errno = 0; /* avoid bogus error text */
397164562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
397271345Sgshapiro		return;
397371345Sgshapiro	}
397464562Sgshapiro
397564562Sgshapiro	/*
397664562Sgshapiro	**  See if this option is preset for us.
397764562Sgshapiro	*/
397864562Sgshapiro
397964562Sgshapiro	if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
398064562Sgshapiro	{
398164562Sgshapiro		if (tTd(37, 2))
398290792Sgshapiro			sm_dprintf(" (ignored)\n");
398364562Sgshapiro		return;
398464562Sgshapiro	}
398564562Sgshapiro
398664562Sgshapiro	if (tTd(37, 2))
398790792Sgshapiro		sm_dprintf("\n");
398864562Sgshapiro
398964562Sgshapiro	toval = convtime(val, 'm');
399080785Sgshapiro	addopts = 0;
399164562Sgshapiro
399264562Sgshapiro	switch (to->to_code)
399364562Sgshapiro	{
399464562Sgshapiro	  case TO_INITIAL:
399564562Sgshapiro		TimeOuts.to_initial = toval;
399664562Sgshapiro		break;
399764562Sgshapiro
399864562Sgshapiro	  case TO_MAIL:
399964562Sgshapiro		TimeOuts.to_mail = toval;
400064562Sgshapiro		break;
400164562Sgshapiro
400264562Sgshapiro	  case TO_RCPT:
400364562Sgshapiro		TimeOuts.to_rcpt = toval;
400464562Sgshapiro		break;
400564562Sgshapiro
400664562Sgshapiro	  case TO_DATAINIT:
400764562Sgshapiro		TimeOuts.to_datainit = toval;
400864562Sgshapiro		break;
400964562Sgshapiro
401064562Sgshapiro	  case TO_DATABLOCK:
401164562Sgshapiro		TimeOuts.to_datablock = toval;
401264562Sgshapiro		break;
401364562Sgshapiro
401464562Sgshapiro	  case TO_DATAFINAL:
401564562Sgshapiro		TimeOuts.to_datafinal = toval;
401664562Sgshapiro		break;
401764562Sgshapiro
401864562Sgshapiro	  case TO_COMMAND:
401964562Sgshapiro		TimeOuts.to_nextcommand = toval;
402064562Sgshapiro		break;
402164562Sgshapiro
402264562Sgshapiro	  case TO_RSET:
402364562Sgshapiro		TimeOuts.to_rset = toval;
402464562Sgshapiro		break;
402564562Sgshapiro
402664562Sgshapiro	  case TO_HELO:
402764562Sgshapiro		TimeOuts.to_helo = toval;
402864562Sgshapiro		break;
402964562Sgshapiro
403064562Sgshapiro	  case TO_QUIT:
403164562Sgshapiro		TimeOuts.to_quit = toval;
403264562Sgshapiro		break;
403364562Sgshapiro
403464562Sgshapiro	  case TO_MISC:
403564562Sgshapiro		TimeOuts.to_miscshort = toval;
403664562Sgshapiro		break;
403764562Sgshapiro
403864562Sgshapiro	  case TO_IDENT:
403964562Sgshapiro		TimeOuts.to_ident = toval;
404064562Sgshapiro		break;
404164562Sgshapiro
404264562Sgshapiro	  case TO_FILEOPEN:
404364562Sgshapiro		TimeOuts.to_fileopen = toval;
404464562Sgshapiro		break;
404564562Sgshapiro
404664562Sgshapiro	  case TO_CONNECT:
404764562Sgshapiro		TimeOuts.to_connect = toval;
404864562Sgshapiro		break;
404964562Sgshapiro
405064562Sgshapiro	  case TO_ICONNECT:
405164562Sgshapiro		TimeOuts.to_iconnect = toval;
405264562Sgshapiro		break;
405364562Sgshapiro
405490792Sgshapiro	  case TO_ACONNECT:
405590792Sgshapiro		TimeOuts.to_aconnect = toval;
405690792Sgshapiro		break;
405790792Sgshapiro
405864562Sgshapiro	  case TO_QUEUEWARN:
405964562Sgshapiro		toval = convtime(val, 'h');
406064562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
406164562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
406264562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
406380785Sgshapiro		addopts = 2;
406464562Sgshapiro		break;
406564562Sgshapiro
406664562Sgshapiro	  case TO_QUEUEWARN_NORMAL:
406764562Sgshapiro		toval = convtime(val, 'h');
406864562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
406964562Sgshapiro		break;
407064562Sgshapiro
407164562Sgshapiro	  case TO_QUEUEWARN_URGENT:
407264562Sgshapiro		toval = convtime(val, 'h');
407364562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
407464562Sgshapiro		break;
407564562Sgshapiro
407664562Sgshapiro	  case TO_QUEUEWARN_NON_URGENT:
407764562Sgshapiro		toval = convtime(val, 'h');
407864562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
407964562Sgshapiro		break;
408064562Sgshapiro
408164562Sgshapiro	  case TO_QUEUERETURN:
408264562Sgshapiro		toval = convtime(val, 'd');
408364562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
408464562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
408564562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
408680785Sgshapiro		addopts = 2;
408764562Sgshapiro		break;
408864562Sgshapiro
408964562Sgshapiro	  case TO_QUEUERETURN_NORMAL:
409064562Sgshapiro		toval = convtime(val, 'd');
409164562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
409264562Sgshapiro		break;
409364562Sgshapiro
409464562Sgshapiro	  case TO_QUEUERETURN_URGENT:
409564562Sgshapiro		toval = convtime(val, 'd');
409664562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
409764562Sgshapiro		break;
409864562Sgshapiro
409964562Sgshapiro	  case TO_QUEUERETURN_NON_URGENT:
410064562Sgshapiro		toval = convtime(val, 'd');
410164562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
410264562Sgshapiro		break;
410364562Sgshapiro
410464562Sgshapiro
410564562Sgshapiro	  case TO_HOSTSTATUS:
410664562Sgshapiro		MciInfoTimeout = toval;
410764562Sgshapiro		break;
410864562Sgshapiro
410964562Sgshapiro	  case TO_RESOLVER_RETRANS:
411064562Sgshapiro		toval = convtime(val, 's');
411164562Sgshapiro		TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
411264562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = toval;
411364562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
411480785Sgshapiro		addopts = 2;
411564562Sgshapiro		break;
411664562Sgshapiro
411764562Sgshapiro	  case TO_RESOLVER_RETRY:
411864562Sgshapiro		i = atoi(val);
411964562Sgshapiro		TimeOuts.res_retry[RES_TO_DEFAULT] = i;
412064562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = i;
412164562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = i;
412280785Sgshapiro		addopts = 2;
412364562Sgshapiro		break;
412464562Sgshapiro
412564562Sgshapiro	  case TO_RESOLVER_RETRANS_NORMAL:
412664562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
412764562Sgshapiro		break;
412864562Sgshapiro
412964562Sgshapiro	  case TO_RESOLVER_RETRY_NORMAL:
413064562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
413164562Sgshapiro		break;
413264562Sgshapiro
413364562Sgshapiro	  case TO_RESOLVER_RETRANS_FIRST:
413464562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
413564562Sgshapiro		break;
413664562Sgshapiro
413764562Sgshapiro	  case TO_RESOLVER_RETRY_FIRST:
413864562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
413964562Sgshapiro		break;
414064562Sgshapiro
414164562Sgshapiro	  case TO_CONTROL:
414264562Sgshapiro		TimeOuts.to_control = toval;
414364562Sgshapiro		break;
414464562Sgshapiro
414590792Sgshapiro	  case TO_LHLO:
414690792Sgshapiro		TimeOuts.to_lhlo = toval;
414790792Sgshapiro		break;
414890792Sgshapiro
414990792Sgshapiro#if SASL
415090792Sgshapiro	  case TO_AUTH:
415190792Sgshapiro		TimeOuts.to_auth = toval;
415290792Sgshapiro		break;
415390792Sgshapiro#endif /* SASL */
415490792Sgshapiro
415590792Sgshapiro#if STARTTLS
415690792Sgshapiro	  case TO_STARTTLS:
415790792Sgshapiro		TimeOuts.to_starttls = toval;
415890792Sgshapiro		break;
415990792Sgshapiro#endif /* STARTTLS */
416090792Sgshapiro
416164562Sgshapiro	  default:
416264562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
416364562Sgshapiro		break;
416464562Sgshapiro	}
416564562Sgshapiro
416664562Sgshapiro	if (sticky)
416780785Sgshapiro	{
416880785Sgshapiro		for (i = 0; i <= addopts; i++)
416980785Sgshapiro			setbitn(to->to_code + i, StickyTimeoutOpt);
417080785Sgshapiro	}
417164562Sgshapiro}
417290792Sgshapiro/*
417338032Speter**  INITTIMEOUTS -- parse and set timeout values
417438032Speter**
417538032Speter**	Parameters:
417638032Speter**		val -- a pointer to the values.  If NULL, do initial
417738032Speter**			settings.
417864562Sgshapiro**		sticky -- if set, don't let other setoptions override
417964562Sgshapiro**			this suboption value.
418038032Speter**
418138032Speter**	Returns:
418238032Speter**		none.
418338032Speter**
418438032Speter**	Side Effects:
418538032Speter**		Initializes the TimeOuts structure
418638032Speter*/
418738032Speter
418838032Spetervoid
418964562Sgshapiroinittimeouts(val, sticky)
419038032Speter	register char *val;
419164562Sgshapiro	bool sticky;
419238032Speter{
419338032Speter	register char *p;
419438032Speter
419538032Speter	if (tTd(37, 2))
419690792Sgshapiro		sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
419738032Speter	if (val == NULL)
419838032Speter	{
419938032Speter		TimeOuts.to_connect = (time_t) 0 SECONDS;
420090792Sgshapiro		TimeOuts.to_aconnect = (time_t) 0 SECONDS;
420194334Sgshapiro		TimeOuts.to_iconnect = (time_t) 0 SECONDS;
420238032Speter		TimeOuts.to_initial = (time_t) 5 MINUTES;
420338032Speter		TimeOuts.to_helo = (time_t) 5 MINUTES;
420438032Speter		TimeOuts.to_mail = (time_t) 10 MINUTES;
420538032Speter		TimeOuts.to_rcpt = (time_t) 1 HOUR;
420638032Speter		TimeOuts.to_datainit = (time_t) 5 MINUTES;
420738032Speter		TimeOuts.to_datablock = (time_t) 1 HOUR;
420838032Speter		TimeOuts.to_datafinal = (time_t) 1 HOUR;
420938032Speter		TimeOuts.to_rset = (time_t) 5 MINUTES;
421038032Speter		TimeOuts.to_quit = (time_t) 2 MINUTES;
421138032Speter		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
421238032Speter		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
421338032Speter#if IDENTPROTO
421464562Sgshapiro		TimeOuts.to_ident = (time_t) 5 SECONDS;
421564562Sgshapiro#else /* IDENTPROTO */
421638032Speter		TimeOuts.to_ident = (time_t) 0 SECONDS;
421764562Sgshapiro#endif /* IDENTPROTO */
421838032Speter		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
421964562Sgshapiro		TimeOuts.to_control = (time_t) 2 MINUTES;
422090792Sgshapiro		TimeOuts.to_lhlo = (time_t) 2 MINUTES;
422190792Sgshapiro#if SASL
422290792Sgshapiro		TimeOuts.to_auth = (time_t) 10 MINUTES;
422390792Sgshapiro#endif /* SASL */
422490792Sgshapiro#if STARTTLS
422590792Sgshapiro		TimeOuts.to_starttls = (time_t) 1 HOUR;
422690792Sgshapiro#endif /* STARTTLS */
422738032Speter		if (tTd(37, 5))
422838032Speter		{
422990792Sgshapiro			sm_dprintf("Timeouts:\n");
423090792Sgshapiro			sm_dprintf("  connect = %ld\n",
423190792Sgshapiro				   (long) TimeOuts.to_connect);
423290792Sgshapiro			sm_dprintf("  aconnect = %ld\n",
423390792Sgshapiro				   (long) TimeOuts.to_aconnect);
423490792Sgshapiro			sm_dprintf("  initial = %ld\n",
423590792Sgshapiro				   (long) TimeOuts.to_initial);
423690792Sgshapiro			sm_dprintf("  helo = %ld\n", (long) TimeOuts.to_helo);
423790792Sgshapiro			sm_dprintf("  mail = %ld\n", (long) TimeOuts.to_mail);
423890792Sgshapiro			sm_dprintf("  rcpt = %ld\n", (long) TimeOuts.to_rcpt);
423990792Sgshapiro			sm_dprintf("  datainit = %ld\n",
424090792Sgshapiro				   (long) TimeOuts.to_datainit);
424190792Sgshapiro			sm_dprintf("  datablock = %ld\n",
424290792Sgshapiro				   (long) TimeOuts.to_datablock);
424390792Sgshapiro			sm_dprintf("  datafinal = %ld\n",
424490792Sgshapiro				   (long) TimeOuts.to_datafinal);
424590792Sgshapiro			sm_dprintf("  rset = %ld\n", (long) TimeOuts.to_rset);
424690792Sgshapiro			sm_dprintf("  quit = %ld\n", (long) TimeOuts.to_quit);
424790792Sgshapiro			sm_dprintf("  nextcommand = %ld\n",
424890792Sgshapiro				   (long) TimeOuts.to_nextcommand);
424990792Sgshapiro			sm_dprintf("  miscshort = %ld\n",
425090792Sgshapiro				   (long) TimeOuts.to_miscshort);
425190792Sgshapiro			sm_dprintf("  ident = %ld\n", (long) TimeOuts.to_ident);
425290792Sgshapiro			sm_dprintf("  fileopen = %ld\n",
425390792Sgshapiro				   (long) TimeOuts.to_fileopen);
425490792Sgshapiro			sm_dprintf("  lhlo = %ld\n",
425590792Sgshapiro				   (long) TimeOuts.to_lhlo);
425690792Sgshapiro			sm_dprintf("  control = %ld\n",
425790792Sgshapiro				   (long) TimeOuts.to_control);
425838032Speter		}
425938032Speter		return;
426038032Speter	}
426138032Speter
426238032Speter	for (;; val = p)
426338032Speter	{
426438032Speter		while (isascii(*val) && isspace(*val))
426538032Speter			val++;
426638032Speter		if (*val == '\0')
426738032Speter			break;
426838032Speter		for (p = val; *p != '\0' && *p != ','; p++)
426938032Speter			continue;
427038032Speter		if (*p != '\0')
427138032Speter			*p++ = '\0';
427238032Speter
427338032Speter		if (isascii(*val) && isdigit(*val))
427438032Speter		{
427538032Speter			/* old syntax -- set everything */
427638032Speter			TimeOuts.to_mail = convtime(val, 'm');
427738032Speter			TimeOuts.to_rcpt = TimeOuts.to_mail;
427838032Speter			TimeOuts.to_datainit = TimeOuts.to_mail;
427938032Speter			TimeOuts.to_datablock = TimeOuts.to_mail;
428038032Speter			TimeOuts.to_datafinal = TimeOuts.to_mail;
428138032Speter			TimeOuts.to_nextcommand = TimeOuts.to_mail;
428264562Sgshapiro			if (sticky)
428364562Sgshapiro			{
428464562Sgshapiro				setbitn(TO_MAIL, StickyTimeoutOpt);
428564562Sgshapiro				setbitn(TO_RCPT, StickyTimeoutOpt);
428664562Sgshapiro				setbitn(TO_DATAINIT, StickyTimeoutOpt);
428764562Sgshapiro				setbitn(TO_DATABLOCK, StickyTimeoutOpt);
428864562Sgshapiro				setbitn(TO_DATAFINAL, StickyTimeoutOpt);
428964562Sgshapiro				setbitn(TO_COMMAND, StickyTimeoutOpt);
429064562Sgshapiro			}
429138032Speter			continue;
429238032Speter		}
429338032Speter		else
429438032Speter		{
429538032Speter			register char *q = strchr(val, ':');
429638032Speter
429738032Speter			if (q == NULL && (q = strchr(val, '=')) == NULL)
429838032Speter			{
429938032Speter				/* syntax error */
430038032Speter				continue;
430138032Speter			}
430238032Speter			*q++ = '\0';
430364562Sgshapiro			settimeout(val, q, sticky);
430438032Speter		}
430538032Speter	}
430638032Speter}
4307