readcf.c revision 82017
138032Speter/*
273188Sgshapiro * Copyright (c) 1998-2001 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
1438032Speter#ifndef lint
1582017Sgshapirostatic char id[] = "@(#)$Id: readcf.c,v 8.382.4.43 2001/08/14 23:08:13 ca Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2164562Sgshapiro#if NETINET || NETINET6
2264562Sgshapiro# include <arpa/inet.h>
2364562Sgshapiro#endif /* NETINET || NETINET6 */
2464562Sgshapiro
2564562Sgshapiro#define SECONDS
2664562Sgshapiro#define MINUTES	* 60
2764562Sgshapiro#define HOUR	* 3600
2864562Sgshapiro#define HOURS	HOUR
2964562Sgshapiro
3064562Sgshapirostatic void	fileclass __P((int, char *, char *, bool, bool));
3164562Sgshapirostatic char	**makeargv __P((char *));
3264562Sgshapirostatic void	settimeout __P((char *, char *, bool));
3364562Sgshapirostatic void	toomany __P((int, int));
3464562Sgshapiro
3538032Speter/*
3638032Speter**  READCF -- read configuration file.
3738032Speter**
3838032Speter**	This routine reads the configuration file and builds the internal
3938032Speter**	form.
4038032Speter**
4138032Speter**	The file is formatted as a sequence of lines, each taken
4238032Speter**	atomically.  The first character of each line describes how
4338032Speter**	the line is to be interpreted.  The lines are:
4438032Speter**		Dxval		Define macro x to have value val.
4538032Speter**		Cxword		Put word into class x.
4638032Speter**		Fxfile [fmt]	Read file for lines to put into
4738032Speter**				class x.  Use scanf string 'fmt'
4838032Speter**				or "%s" if not present.  Fmt should
4938032Speter**				only produce one string-valued result.
5038032Speter**		Hname: value	Define header with field-name 'name'
5138032Speter**				and value as specified; this will be
5238032Speter**				macro expanded immediately before
5338032Speter**				use.
5438032Speter**		Sn		Use rewriting set n.
5538032Speter**		Rlhs rhs	Rewrite addresses that match lhs to
5638032Speter**				be rhs.
5738032Speter**		Mn arg=val...	Define mailer.  n is the internal name.
5838032Speter**				Args specify mailer parameters.
5938032Speter**		Oxvalue		Set option x to value.
6038032Speter**		Pname=value	Set precedence name to value.
6138032Speter**		Vversioncode[/vendorcode]
6238032Speter**				Version level/vendor name of
6338032Speter**				configuration syntax.
6438032Speter**		Kmapname mapclass arguments....
6538032Speter**				Define keyed lookup of a given class.
6638032Speter**				Arguments are class dependent.
6738032Speter**		Eenvar=value	Set the environment value to the given value.
6838032Speter**
6938032Speter**	Parameters:
7038032Speter**		cfname -- configuration file name.
7138032Speter**		safe -- TRUE if this is the system config file;
7238032Speter**			FALSE otherwise.
7338032Speter**		e -- the main envelope.
7438032Speter**
7538032Speter**	Returns:
7638032Speter**		none.
7738032Speter**
7838032Speter**	Side Effects:
7938032Speter**		Builds several internal tables.
8038032Speter*/
8138032Speter
8238032Spetervoid
8338032Speterreadcf(cfname, safe, e)
8438032Speter	char *cfname;
8538032Speter	bool safe;
8638032Speter	register ENVELOPE *e;
8738032Speter{
8838032Speter	FILE *cf;
8964562Sgshapiro	int ruleset = -1;
9038032Speter	char *q;
9138032Speter	struct rewrite *rwp = NULL;
9238032Speter	char *bp;
9338032Speter	auto char *ep;
9438032Speter	int nfuzzy;
9538032Speter	char *file;
9638032Speter	bool optional;
9738032Speter	int mid;
9838032Speter	register char *p;
9964562Sgshapiro	long sff = SFF_OPENASROOT;
10038032Speter	struct stat statb;
10138032Speter	char buf[MAXLINE];
10238032Speter	char exbuf[MAXLINE];
10338032Speter	char pvpbuf[MAXLINE + MAXATOM];
10438032Speter	static char *null_list[1] = { NULL };
10564562Sgshapiro	extern u_char TokTypeNoC[];
10638032Speter
10738032Speter	FileName = cfname;
10838032Speter	LineNumber = 0;
10938032Speter
11038032Speter	if (DontLockReadFiles)
11138032Speter		sff |= SFF_NOLOCK;
11238032Speter	cf = safefopen(cfname, O_RDONLY, 0444, sff);
11338032Speter	if (cf == NULL)
11438032Speter	{
11538032Speter		syserr("cannot open");
11642575Speter		finis(FALSE, EX_OSFILE);
11738032Speter	}
11838032Speter
11938032Speter	if (fstat(fileno(cf), &statb) < 0)
12038032Speter	{
12138032Speter		syserr("cannot fstat");
12242575Speter		finis(FALSE, EX_OSFILE);
12338032Speter	}
12438032Speter
12538032Speter	if (!S_ISREG(statb.st_mode))
12638032Speter	{
12738032Speter		syserr("not a plain file");
12842575Speter		finis(FALSE, EX_OSFILE);
12938032Speter	}
13038032Speter
13138032Speter	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
13238032Speter	{
13338032Speter		if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
13438032Speter			fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
13538032Speter				FileName);
13638032Speter		if (LogLevel > 0)
13738032Speter			sm_syslog(LOG_CRIT, NOQID,
13864562Sgshapiro				  "%s: WARNING: dangerous write permissions",
13964562Sgshapiro				  FileName);
14038032Speter	}
14138032Speter
14238032Speter#ifdef XLA
14338032Speter	xla_zero();
14464562Sgshapiro#endif /* XLA */
14538032Speter
14638032Speter	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
14738032Speter	{
14838032Speter		if (bp[0] == '#')
14938032Speter		{
15038032Speter			if (bp != buf)
15177349Sgshapiro				sm_free(bp);
15238032Speter			continue;
15338032Speter		}
15438032Speter
15538032Speter		/* do macro expansion mappings */
15638032Speter		translate_dollars(bp);
15738032Speter
15838032Speter		/* interpret this line */
15938032Speter		errno = 0;
16038032Speter		switch (bp[0])
16138032Speter		{
16238032Speter		  case '\0':
16338032Speter		  case '#':		/* comment */
16438032Speter			break;
16538032Speter
16638032Speter		  case 'R':		/* rewriting rule */
16764562Sgshapiro			if (ruleset < 0)
16864562Sgshapiro			{
16964562Sgshapiro				syserr("missing valid ruleset for \"%s\"", bp);
17064562Sgshapiro				break;
17164562Sgshapiro			}
17238032Speter			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
17338032Speter				continue;
17438032Speter
17538032Speter			if (*p == '\0')
17638032Speter			{
17738032Speter				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
17838032Speter				break;
17938032Speter			}
18038032Speter
18138032Speter			/* allocate space for the rule header */
18238032Speter			if (rwp == NULL)
18338032Speter			{
18438032Speter				RewriteRules[ruleset] = rwp =
18538032Speter					(struct rewrite *) xalloc(sizeof *rwp);
18638032Speter			}
18738032Speter			else
18838032Speter			{
18938032Speter				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
19038032Speter				rwp = rwp->r_next;
19138032Speter			}
19238032Speter			rwp->r_next = NULL;
19338032Speter
19438032Speter			/* expand and save the LHS */
19538032Speter			*p = '\0';
19638032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
19738032Speter			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
19864562Sgshapiro					     sizeof pvpbuf, NULL,
19964562Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : NULL);
20038032Speter			nfuzzy = 0;
20138032Speter			if (rwp->r_lhs != NULL)
20238032Speter			{
20338032Speter				register char **ap;
20438032Speter
20538032Speter				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
20638032Speter
20738032Speter				/* count the number of fuzzy matches in LHS */
20838032Speter				for (ap = rwp->r_lhs; *ap != NULL; ap++)
20938032Speter				{
21038032Speter					char *botch;
21138032Speter
21238032Speter					botch = NULL;
21338032Speter					switch (**ap & 0377)
21438032Speter					{
21538032Speter					  case MATCHZANY:
21638032Speter					  case MATCHANY:
21738032Speter					  case MATCHONE:
21838032Speter					  case MATCHCLASS:
21938032Speter					  case MATCHNCLASS:
22038032Speter						nfuzzy++;
22138032Speter						break;
22238032Speter
22338032Speter					  case MATCHREPL:
22438032Speter						botch = "$0-$9";
22538032Speter						break;
22638032Speter
22738032Speter					  case CANONUSER:
22838032Speter						botch = "$:";
22938032Speter						break;
23038032Speter
23138032Speter					  case CALLSUBR:
23238032Speter						botch = "$>";
23338032Speter						break;
23438032Speter
23538032Speter					  case CONDIF:
23638032Speter						botch = "$?";
23738032Speter						break;
23838032Speter
23938032Speter					  case CONDFI:
24038032Speter						botch = "$.";
24138032Speter						break;
24238032Speter
24338032Speter					  case HOSTBEGIN:
24438032Speter						botch = "$[";
24538032Speter						break;
24638032Speter
24738032Speter					  case HOSTEND:
24838032Speter						botch = "$]";
24938032Speter						break;
25038032Speter
25138032Speter					  case LOOKUPBEGIN:
25238032Speter						botch = "$(";
25338032Speter						break;
25438032Speter
25538032Speter					  case LOOKUPEND:
25638032Speter						botch = "$)";
25738032Speter						break;
25838032Speter					}
25938032Speter					if (botch != NULL)
26038032Speter						syserr("Inappropriate use of %s on LHS",
26138032Speter							botch);
26238032Speter				}
26364562Sgshapiro				rwp->r_line = LineNumber;
26438032Speter			}
26538032Speter			else
26638032Speter			{
26738032Speter				syserr("R line: null LHS");
26838032Speter				rwp->r_lhs = null_list;
26938032Speter			}
27082017Sgshapiro			if (nfuzzy > MAXMATCH)
27182017Sgshapiro			{
27282017Sgshapiro				syserr("R line: too many wildcards");
27382017Sgshapiro				rwp->r_lhs = null_list;
27482017Sgshapiro			}
27538032Speter
27638032Speter			/* expand and save the RHS */
27738032Speter			while (*++p == '\t')
27838032Speter				continue;
27938032Speter			q = p;
28038032Speter			while (*p != '\0' && *p != '\t')
28138032Speter				p++;
28238032Speter			*p = '\0';
28338032Speter			expand(q, exbuf, sizeof exbuf, e);
28438032Speter			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
28564562Sgshapiro					     sizeof pvpbuf, NULL,
28664562Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : NULL);
28738032Speter			if (rwp->r_rhs != NULL)
28838032Speter			{
28938032Speter				register char **ap;
29038032Speter
29138032Speter				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
29238032Speter
29338032Speter				/* check no out-of-bounds replacements */
29438032Speter				nfuzzy += '0';
29538032Speter				for (ap = rwp->r_rhs; *ap != NULL; ap++)
29638032Speter				{
29738032Speter					char *botch;
29838032Speter
29938032Speter					botch = NULL;
30038032Speter					switch (**ap & 0377)
30138032Speter					{
30238032Speter					  case MATCHREPL:
30338032Speter						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
30438032Speter						{
30538032Speter							syserr("replacement $%c out of bounds",
30638032Speter								(*ap)[1]);
30738032Speter						}
30838032Speter						break;
30938032Speter
31038032Speter					  case MATCHZANY:
31138032Speter						botch = "$*";
31238032Speter						break;
31338032Speter
31438032Speter					  case MATCHANY:
31538032Speter						botch = "$+";
31638032Speter						break;
31738032Speter
31838032Speter					  case MATCHONE:
31938032Speter						botch = "$-";
32038032Speter						break;
32138032Speter
32238032Speter					  case MATCHCLASS:
32338032Speter						botch = "$=";
32438032Speter						break;
32538032Speter
32638032Speter					  case MATCHNCLASS:
32738032Speter						botch = "$~";
32838032Speter						break;
32938032Speter					}
33038032Speter					if (botch != NULL)
33138032Speter						syserr("Inappropriate use of %s on RHS",
33238032Speter							botch);
33338032Speter				}
33438032Speter			}
33538032Speter			else
33638032Speter			{
33738032Speter				syserr("R line: null RHS");
33838032Speter				rwp->r_rhs = null_list;
33938032Speter			}
34038032Speter			break;
34138032Speter
34238032Speter		  case 'S':		/* select rewriting set */
34338032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
34438032Speter			ruleset = strtorwset(exbuf, NULL, ST_ENTER);
34538032Speter			if (ruleset < 0)
34638032Speter				break;
34764562Sgshapiro
34838032Speter			rwp = RewriteRules[ruleset];
34938032Speter			if (rwp != NULL)
35038032Speter			{
35164562Sgshapiro				if (OpMode == MD_TEST)
35238032Speter					printf("WARNING: Ruleset %s has multiple definitions\n",
35364562Sgshapiro					       &bp[1]);
35464562Sgshapiro				if (tTd(37, 1))
35564562Sgshapiro					dprintf("WARNING: Ruleset %s has multiple definitions\n",
35638032Speter						&bp[1]);
35738032Speter				while (rwp->r_next != NULL)
35838032Speter					rwp = rwp->r_next;
35938032Speter			}
36038032Speter			break;
36138032Speter
36238032Speter		  case 'D':		/* macro definition */
36338032Speter			mid = macid(&bp[1], &ep);
36471345Sgshapiro			if (mid == 0)
36571345Sgshapiro				break;
36638032Speter			p = munchstring(ep, NULL, '\0');
36738032Speter			define(mid, newstr(p), e);
36838032Speter			break;
36938032Speter
37038032Speter		  case 'H':		/* required header line */
37164562Sgshapiro			(void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
37238032Speter			break;
37338032Speter
37438032Speter		  case 'C':		/* word class */
37538032Speter		  case 'T':		/* trusted user (set class `t') */
37638032Speter			if (bp[0] == 'C')
37738032Speter			{
37838032Speter				mid = macid(&bp[1], &ep);
37971345Sgshapiro				if (mid == 0)
38071345Sgshapiro					break;
38138032Speter				expand(ep, exbuf, sizeof exbuf, e);
38238032Speter				p = exbuf;
38338032Speter			}
38438032Speter			else
38538032Speter			{
38638032Speter				mid = 't';
38738032Speter				p = &bp[1];
38838032Speter			}
38938032Speter			while (*p != '\0')
39038032Speter			{
39138032Speter				register char *wd;
39238032Speter				char delim;
39338032Speter
39438032Speter				while (*p != '\0' && isascii(*p) && isspace(*p))
39538032Speter					p++;
39638032Speter				wd = p;
39738032Speter				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
39838032Speter					p++;
39938032Speter				delim = *p;
40038032Speter				*p = '\0';
40138032Speter				if (wd[0] != '\0')
40238032Speter					setclass(mid, wd);
40338032Speter				*p = delim;
40438032Speter			}
40538032Speter			break;
40638032Speter
40738032Speter		  case 'F':		/* word class from file */
40838032Speter			mid = macid(&bp[1], &ep);
40971345Sgshapiro			if (mid == 0)
41071345Sgshapiro				break;
41138032Speter			for (p = ep; isascii(*p) && isspace(*p); )
41238032Speter				p++;
41338032Speter			if (p[0] == '-' && p[1] == 'o')
41438032Speter			{
41538032Speter				optional = TRUE;
41638032Speter				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
41738032Speter					p++;
41838032Speter				while (isascii(*p) && isspace(*p))
41938032Speter					p++;
42038032Speter			}
42138032Speter			else
42238032Speter				optional = FALSE;
42364562Sgshapiro
42438032Speter			file = p;
42564562Sgshapiro			q = p;
42664562Sgshapiro			while (*q != '\0' && !(isascii(*q) && isspace(*q)))
42764562Sgshapiro				q++;
42838032Speter			if (*file == '|')
42938032Speter				p = "%s";
43038032Speter			else
43138032Speter			{
43264562Sgshapiro				p = q;
43338032Speter				if (*p == '\0')
43438032Speter					p = "%s";
43538032Speter				else
43638032Speter				{
43738032Speter					*p = '\0';
43838032Speter					while (isascii(*++p) && isspace(*p))
43938032Speter						continue;
44038032Speter				}
44138032Speter			}
44238032Speter			fileclass(mid, file, p, safe, optional);
44338032Speter			break;
44438032Speter
44538032Speter#ifdef XLA
44638032Speter		  case 'L':		/* extended load average description */
44738032Speter			xla_init(&bp[1]);
44838032Speter			break;
44964562Sgshapiro#endif /* XLA */
45038032Speter
45138032Speter#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
45238032Speter		  case 'L':		/* lookup macro */
45338032Speter		  case 'G':		/* lookup class */
45438032Speter			/* reserved for Sun -- NIS+ database lookup */
45538032Speter			if (VendorCode != VENDOR_SUN)
45638032Speter				goto badline;
45738032Speter			sun_lg_config_line(bp, e);
45838032Speter			break;
45964562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
46038032Speter
46138032Speter		  case 'M':		/* define mailer */
46238032Speter			makemailer(&bp[1]);
46338032Speter			break;
46438032Speter
46538032Speter		  case 'O':		/* set option */
46638032Speter			setoption(bp[1], &bp[2], safe, FALSE, e);
46738032Speter			break;
46838032Speter
46938032Speter		  case 'P':		/* set precedence */
47038032Speter			if (NumPriorities >= MAXPRIORITIES)
47138032Speter			{
47238032Speter				toomany('P', MAXPRIORITIES);
47338032Speter				break;
47438032Speter			}
47538032Speter			for (p = &bp[1]; *p != '\0' && *p != '='; p++)
47638032Speter				continue;
47738032Speter			if (*p == '\0')
47838032Speter				goto badline;
47938032Speter			*p = '\0';
48038032Speter			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
48138032Speter			Priorities[NumPriorities].pri_val = atoi(++p);
48238032Speter			NumPriorities++;
48338032Speter			break;
48438032Speter
48538032Speter		  case 'V':		/* configuration syntax version */
48638032Speter			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
48738032Speter				continue;
48838032Speter			if (!isascii(*p) || !isdigit(*p))
48938032Speter			{
49064562Sgshapiro				syserr("invalid argument to V line: \"%.20s\"",
49138032Speter					&bp[1]);
49238032Speter				break;
49338032Speter			}
49438032Speter			ConfigLevel = strtol(p, &ep, 10);
49538032Speter
49638032Speter			/*
49738032Speter			**  Do heuristic tweaking for back compatibility.
49838032Speter			*/
49938032Speter
50038032Speter			if (ConfigLevel >= 5)
50138032Speter			{
50238032Speter				/* level 5 configs have short name in $w */
50338032Speter				p = macvalue('w', e);
50438032Speter				if (p != NULL && (p = strchr(p, '.')) != NULL)
50538032Speter					*p = '\0';
50638032Speter				define('w', macvalue('w', e), e);
50738032Speter			}
50838032Speter			if (ConfigLevel >= 6)
50938032Speter			{
51038032Speter				ColonOkInAddr = FALSE;
51138032Speter			}
51238032Speter
51338032Speter			/*
51438032Speter			**  Look for vendor code.
51538032Speter			*/
51638032Speter
51738032Speter			if (*ep++ == '/')
51838032Speter			{
51938032Speter				/* extract vendor code */
52038032Speter				for (p = ep; isascii(*p) && isalpha(*p); )
52138032Speter					p++;
52238032Speter				*p = '\0';
52338032Speter
52438032Speter				if (!setvendor(ep))
52538032Speter					syserr("invalid V line vendor code: \"%s\"",
52638032Speter						ep);
52738032Speter			}
52838032Speter			break;
52938032Speter
53038032Speter		  case 'K':
53138032Speter			expand(&bp[1], exbuf, sizeof exbuf, e);
53238032Speter			(void) makemapentry(exbuf);
53338032Speter			break;
53438032Speter
53538032Speter		  case 'E':
53638032Speter			p = strchr(bp, '=');
53738032Speter			if (p != NULL)
53838032Speter				*p++ = '\0';
53938032Speter			setuserenv(&bp[1], p);
54038032Speter			break;
54138032Speter
54264562Sgshapiro#if _FFR_MILTER
54364562Sgshapiro		  case 'X':		/* mail filter */
54464562Sgshapiro			milter_setup(&bp[1]);
54564562Sgshapiro			break;
54664562Sgshapiro#endif /* _FFR_MILTER */
54764562Sgshapiro
54838032Speter		  default:
54938032Speter		  badline:
55038032Speter			syserr("unknown configuration line \"%s\"", bp);
55138032Speter		}
55238032Speter		if (bp != buf)
55377349Sgshapiro			sm_free(bp);
55438032Speter	}
55538032Speter	if (ferror(cf))
55638032Speter	{
55738032Speter		syserr("I/O read error");
55842575Speter		finis(FALSE, EX_OSFILE);
55938032Speter	}
56064562Sgshapiro	(void) fclose(cf);
56138032Speter	FileName = NULL;
56238032Speter
56338032Speter	/* initialize host maps from local service tables */
56438032Speter	inithostmaps();
56538032Speter
56664562Sgshapiro	/* initialize daemon (if not defined yet) */
56764562Sgshapiro	initdaemon();
56864562Sgshapiro
56938032Speter	/* determine if we need to do special name-server frotz */
57038032Speter	{
57138032Speter		int nmaps;
57238032Speter		char *maptype[MAXMAPSTACK];
57338032Speter		short mapreturn[MAXMAPACTIONS];
57438032Speter
57538032Speter		nmaps = switch_map_find("hosts", maptype, mapreturn);
57638032Speter		UseNameServer = FALSE;
57738032Speter		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
57838032Speter		{
57938032Speter			register int mapno;
58038032Speter
58138032Speter			for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
58238032Speter			{
58338032Speter				if (strcmp(maptype[mapno], "dns") == 0)
58438032Speter					UseNameServer = TRUE;
58538032Speter			}
58638032Speter		}
58738032Speter
58838032Speter#ifdef HESIOD
58938032Speter		nmaps = switch_map_find("passwd", maptype, mapreturn);
59038032Speter		UseHesiod = FALSE;
59138032Speter		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
59238032Speter		{
59338032Speter			register int mapno;
59438032Speter
59538032Speter			for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
59638032Speter			{
59738032Speter				if (strcmp(maptype[mapno], "hesiod") == 0)
59838032Speter					UseHesiod = TRUE;
59938032Speter			}
60038032Speter		}
60164562Sgshapiro#endif /* HESIOD */
60238032Speter	}
60338032Speter}
60438032Speter/*
60538032Speter**  TRANSLATE_DOLLARS -- convert $x into internal form
60638032Speter**
60738032Speter**	Actually does all appropriate pre-processing of a config line
60838032Speter**	to turn it into internal form.
60938032Speter**
61038032Speter**	Parameters:
61138032Speter**		bp -- the buffer to translate.
61238032Speter**
61338032Speter**	Returns:
61438032Speter**		None.  The buffer is translated in place.  Since the
61538032Speter**		translations always make the buffer shorter, this is
61638032Speter**		safe without a size parameter.
61738032Speter*/
61838032Speter
61938032Spetervoid
62038032Spetertranslate_dollars(bp)
62138032Speter	char *bp;
62238032Speter{
62338032Speter	register char *p;
62438032Speter	auto char *ep;
62538032Speter
62638032Speter	for (p = bp; *p != '\0'; p++)
62738032Speter	{
62838032Speter		if (*p == '#' && p > bp && ConfigLevel >= 3)
62938032Speter		{
63038032Speter			/* this is an on-line comment */
63138032Speter			register char *e;
63238032Speter
63338032Speter			switch (*--p & 0377)
63438032Speter			{
63538032Speter			  case MACROEXPAND:
63638032Speter				/* it's from $# -- let it go through */
63738032Speter				p++;
63838032Speter				break;
63938032Speter
64038032Speter			  case '\\':
64138032Speter				/* it's backslash escaped */
64264562Sgshapiro				(void) strlcpy(p, p + 1, strlen(p));
64338032Speter				break;
64438032Speter
64538032Speter			  default:
64664562Sgshapiro				/* delete leading white space */
64738032Speter				while (isascii(*p) && isspace(*p) &&
64838032Speter				       *p != '\n' && p > bp)
64938032Speter					p--;
65038032Speter				if ((e = strchr(++p, '\n')) != NULL)
65164562Sgshapiro					(void) strlcpy(p, e, strlen(p));
65238032Speter				else
65338032Speter					*p-- = '\0';
65438032Speter				break;
65538032Speter			}
65638032Speter			continue;
65738032Speter		}
65838032Speter
65938032Speter		if (*p != '$' || p[1] == '\0')
66038032Speter			continue;
66138032Speter
66238032Speter		if (p[1] == '$')
66338032Speter		{
66438032Speter			/* actual dollar sign.... */
66564562Sgshapiro			(void) strlcpy(p, p + 1, strlen(p));
66638032Speter			continue;
66738032Speter		}
66838032Speter
66938032Speter		/* convert to macro expansion character */
67038032Speter		*p++ = MACROEXPAND;
67138032Speter
67238032Speter		/* special handling for $=, $~, $&, and $? */
67338032Speter		if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
67438032Speter			p++;
67538032Speter
67638032Speter		/* convert macro name to code */
67738032Speter		*p = macid(p, &ep);
67864562Sgshapiro		if (ep != p + 1)
67964562Sgshapiro			(void) strlcpy(p + 1, ep, strlen(p + 1));
68038032Speter	}
68138032Speter
68238032Speter	/* strip trailing white space from the line */
68338032Speter	while (--p > bp && isascii(*p) && isspace(*p))
68438032Speter		*p = '\0';
68538032Speter}
68638032Speter/*
68738032Speter**  TOOMANY -- signal too many of some option
68838032Speter**
68938032Speter**	Parameters:
69038032Speter**		id -- the id of the error line
69138032Speter**		maxcnt -- the maximum possible values
69238032Speter**
69338032Speter**	Returns:
69438032Speter**		none.
69538032Speter**
69638032Speter**	Side Effects:
69738032Speter**		gives a syserr.
69838032Speter*/
69938032Speter
70064562Sgshapirostatic void
70138032Spetertoomany(id, maxcnt)
70238032Speter	int id;
70338032Speter	int maxcnt;
70438032Speter{
70538032Speter	syserr("too many %c lines, %d max", id, maxcnt);
70638032Speter}
70738032Speter/*
70838032Speter**  FILECLASS -- read members of a class from a file
70938032Speter**
71038032Speter**	Parameters:
71138032Speter**		class -- class to define.
71238032Speter**		filename -- name of file to read.
71338032Speter**		fmt -- scanf string to use for match.
71438032Speter**		safe -- if set, this is a safe read.
71538032Speter**		optional -- if set, it is not an error for the file to
71638032Speter**			not exist.
71738032Speter**
71838032Speter**	Returns:
71938032Speter**		none
72038032Speter**
72138032Speter**	Side Effects:
72238032Speter**
72338032Speter**		puts all lines in filename that match a scanf into
72438032Speter**			the named class.
72538032Speter*/
72638032Speter
72764562Sgshapirostatic void
72838032Speterfileclass(class, filename, fmt, safe, optional)
72938032Speter	int class;
73038032Speter	char *filename;
73138032Speter	char *fmt;
73238032Speter	bool safe;
73338032Speter	bool optional;
73438032Speter{
73538032Speter	FILE *f;
73664562Sgshapiro	long sff;
73738032Speter	pid_t pid;
73838032Speter	register char *p;
73938032Speter	char buf[MAXLINE];
74038032Speter
74138032Speter	if (tTd(37, 2))
74264562Sgshapiro		dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
74338032Speter
74438032Speter	if (filename[0] == '|')
74538032Speter	{
74638032Speter		auto int fd;
74738032Speter		int i;
74838032Speter		char *argv[MAXPV + 1];
74938032Speter
75038032Speter		i = 0;
75138032Speter		for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
75238032Speter		{
75338032Speter			if (i >= MAXPV)
75438032Speter				break;
75538032Speter			argv[i++] = p;
75638032Speter		}
75738032Speter		argv[i] = NULL;
75838032Speter		pid = prog_open(argv, &fd, CurEnv);
75938032Speter		if (pid < 0)
76038032Speter			f = NULL;
76138032Speter		else
76238032Speter			f = fdopen(fd, "r");
76338032Speter	}
76438032Speter	else
76538032Speter	{
76638032Speter		pid = -1;
76738032Speter		sff = SFF_REGONLY;
76864562Sgshapiro		if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
76938032Speter			sff |= SFF_SAFEDIRPATH;
77064562Sgshapiro		if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
77164562Sgshapiro			     DontBlameSendmail))
77238032Speter			sff |= SFF_NOWLINK;
77338032Speter		if (safe)
77438032Speter			sff |= SFF_OPENASROOT;
77538032Speter		if (DontLockReadFiles)
77638032Speter			sff |= SFF_NOLOCK;
77738032Speter		f = safefopen(filename, O_RDONLY, 0, sff);
77838032Speter	}
77938032Speter	if (f == NULL)
78038032Speter	{
78138032Speter		if (!optional)
78264562Sgshapiro			syserr("fileclass: cannot open '%s'", filename);
78338032Speter		return;
78438032Speter	}
78538032Speter
78638032Speter	while (fgets(buf, sizeof buf, f) != NULL)
78738032Speter	{
78864562Sgshapiro#if SCANF
78938032Speter		char wordbuf[MAXLINE + 1];
79064562Sgshapiro#endif /* SCANF */
79138032Speter
79238032Speter		if (buf[0] == '#')
79338032Speter			continue;
79464562Sgshapiro#if SCANF
79538032Speter		if (sscanf(buf, fmt, wordbuf) != 1)
79638032Speter			continue;
79738032Speter		p = wordbuf;
79864562Sgshapiro#else /* SCANF */
79938032Speter		p = buf;
80064562Sgshapiro#endif /* SCANF */
80138032Speter
80238032Speter		/*
80338032Speter		**  Break up the match into words.
80438032Speter		*/
80538032Speter
80638032Speter		while (*p != '\0')
80738032Speter		{
80838032Speter			register char *q;
80938032Speter
81038032Speter			/* strip leading spaces */
81138032Speter			while (isascii(*p) && isspace(*p))
81238032Speter				p++;
81338032Speter			if (*p == '\0')
81438032Speter				break;
81538032Speter
81638032Speter			/* find the end of the word */
81738032Speter			q = p;
81838032Speter			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
81938032Speter				p++;
82038032Speter			if (*p != '\0')
82138032Speter				*p++ = '\0';
82238032Speter
82338032Speter			/* enter the word in the symbol table */
82438032Speter			setclass(class, q);
82538032Speter		}
82638032Speter	}
82738032Speter
82838032Speter	(void) fclose(f);
82938032Speter	if (pid > 0)
83038032Speter		(void) waitfor(pid);
83138032Speter}
83238032Speter/*
83338032Speter**  MAKEMAILER -- define a new mailer.
83438032Speter**
83538032Speter**	Parameters:
83638032Speter**		line -- description of mailer.  This is in labeled
83738032Speter**			fields.  The fields are:
83838032Speter**			   A -- the argv for this mailer
83938032Speter**			   C -- the character set for MIME conversions
84038032Speter**			   D -- the directory to run in
84138032Speter**			   E -- the eol string
84238032Speter**			   F -- the flags associated with the mailer
84338032Speter**			   L -- the maximum line length
84438032Speter**			   M -- the maximum message size
84538032Speter**			   N -- the niceness at which to run
84638032Speter**			   P -- the path to the mailer
84738032Speter**			   R -- the recipient rewriting set
84838032Speter**			   S -- the sender rewriting set
84938032Speter**			   T -- the mailer type (for DSNs)
85038032Speter**			   U -- the uid to run as
85164562Sgshapiro**			   W -- the time to wait at the end
85273188Sgshapiro**			   m -- maximum messages per connection
85373188Sgshapiro**			   / -- new root directory
85438032Speter**			The first word is the canonical name of the mailer.
85538032Speter**
85638032Speter**	Returns:
85738032Speter**		none.
85838032Speter**
85938032Speter**	Side Effects:
86038032Speter**		enters the mailer into the mailer table.
86138032Speter*/
86238032Speter
86338032Spetervoid
86438032Spetermakemailer(line)
86538032Speter	char *line;
86638032Speter{
86738032Speter	register char *p;
86838032Speter	register struct mailer *m;
86938032Speter	register STAB *s;
87038032Speter	int i;
87138032Speter	char fcode;
87238032Speter	auto char *endp;
87338032Speter	extern int NextMailer;
87438032Speter
87538032Speter	/* allocate a mailer and set up defaults */
87638032Speter	m = (struct mailer *) xalloc(sizeof *m);
87764562Sgshapiro	memset((char *) m, '\0', sizeof *m);
87838032Speter
87938032Speter	/* collect the mailer name */
88038032Speter	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
88138032Speter		continue;
88238032Speter	if (*p != '\0')
88338032Speter		*p++ = '\0';
88438032Speter	if (line[0] == '\0')
88571345Sgshapiro	{
88638032Speter		syserr("name required for mailer");
88771345Sgshapiro		return;
88871345Sgshapiro	}
88938032Speter	m->m_name = newstr(line);
89038032Speter
89138032Speter	/* now scan through and assign info from the fields */
89238032Speter	while (*p != '\0')
89338032Speter	{
89438032Speter		auto char *delimptr;
89538032Speter
89638032Speter		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
89738032Speter			p++;
89838032Speter
89938032Speter		/* p now points to field code */
90038032Speter		fcode = *p;
90138032Speter		while (*p != '\0' && *p != '=' && *p != ',')
90238032Speter			p++;
90338032Speter		if (*p++ != '=')
90438032Speter		{
90538032Speter			syserr("mailer %s: `=' expected", m->m_name);
90638032Speter			return;
90738032Speter		}
90838032Speter		while (isascii(*p) && isspace(*p))
90938032Speter			p++;
91038032Speter
91138032Speter		/* p now points to the field body */
91238032Speter		p = munchstring(p, &delimptr, ',');
91338032Speter
91438032Speter		/* install the field into the mailer struct */
91538032Speter		switch (fcode)
91638032Speter		{
91738032Speter		  case 'P':		/* pathname */
91838032Speter			if (*p == '\0')
91938032Speter				syserr("mailer %s: empty path name", m->m_name);
92071345Sgshapiro			else
92171345Sgshapiro				m->m_mailer = newstr(p);
92238032Speter			break;
92338032Speter
92438032Speter		  case 'F':		/* flags */
92538032Speter			for (; *p != '\0'; p++)
92638032Speter				if (!(isascii(*p) && isspace(*p)))
92771345Sgshapiro					setbitn(bitidx(*p), m->m_flags);
92838032Speter			break;
92938032Speter
93038032Speter		  case 'S':		/* sender rewriting ruleset */
93138032Speter		  case 'R':		/* recipient rewriting ruleset */
93238032Speter			i = strtorwset(p, &endp, ST_ENTER);
93338032Speter			if (i < 0)
93438032Speter				return;
93538032Speter			if (fcode == 'S')
93638032Speter				m->m_sh_rwset = m->m_se_rwset = i;
93738032Speter			else
93838032Speter				m->m_rh_rwset = m->m_re_rwset = i;
93938032Speter
94038032Speter			p = endp;
94138032Speter			if (*p++ == '/')
94238032Speter			{
94338032Speter				i = strtorwset(p, NULL, ST_ENTER);
94438032Speter				if (i < 0)
94538032Speter					return;
94638032Speter				if (fcode == 'S')
94738032Speter					m->m_sh_rwset = i;
94838032Speter				else
94938032Speter					m->m_rh_rwset = i;
95038032Speter			}
95138032Speter			break;
95238032Speter
95338032Speter		  case 'E':		/* end of line string */
95438032Speter			if (*p == '\0')
95538032Speter				syserr("mailer %s: null end-of-line string",
95638032Speter					m->m_name);
95771345Sgshapiro			else
95871345Sgshapiro				m->m_eol = newstr(p);
95938032Speter			break;
96038032Speter
96138032Speter		  case 'A':		/* argument vector */
96238032Speter			if (*p == '\0')
96338032Speter				syserr("mailer %s: null argument vector",
96438032Speter					m->m_name);
96571345Sgshapiro			else
96671345Sgshapiro				m->m_argv = makeargv(p);
96738032Speter			break;
96838032Speter
96938032Speter		  case 'M':		/* maximum message size */
97038032Speter			m->m_maxsize = atol(p);
97138032Speter			break;
97238032Speter
97364562Sgshapiro		  case 'm':		/* maximum messages per connection */
97464562Sgshapiro			m->m_maxdeliveries = atoi(p);
97564562Sgshapiro			break;
97664562Sgshapiro
97764562Sgshapiro#if _FFR_DYNAMIC_TOBUF
97864562Sgshapiro		  case 'r':		/* max recipient per envelope */
97964562Sgshapiro			m->m_maxrcpt = atoi(p);
98064562Sgshapiro			break;
98164562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */
98264562Sgshapiro
98338032Speter		  case 'L':		/* maximum line length */
98438032Speter			m->m_linelimit = atoi(p);
98538032Speter			if (m->m_linelimit < 0)
98638032Speter				m->m_linelimit = 0;
98738032Speter			break;
98838032Speter
98938032Speter		  case 'N':		/* run niceness */
99038032Speter			m->m_nice = atoi(p);
99138032Speter			break;
99238032Speter
99338032Speter		  case 'D':		/* working directory */
99438032Speter			if (*p == '\0')
99538032Speter				syserr("mailer %s: null working directory",
99638032Speter					m->m_name);
99771345Sgshapiro			else
99871345Sgshapiro				m->m_execdir = newstr(p);
99938032Speter			break;
100038032Speter
100138032Speter		  case 'C':		/* default charset */
100238032Speter			if (*p == '\0')
100338032Speter				syserr("mailer %s: null charset", m->m_name);
100471345Sgshapiro			else
100571345Sgshapiro				m->m_defcharset = newstr(p);
100638032Speter			break;
100738032Speter
100838032Speter		  case 'T':		/* MTA-Name/Address/Diagnostic types */
100938032Speter			/* extract MTA name type; default to "dns" */
101038032Speter			m->m_mtatype = newstr(p);
101138032Speter			p = strchr(m->m_mtatype, '/');
101238032Speter			if (p != NULL)
101338032Speter			{
101438032Speter				*p++ = '\0';
101538032Speter				if (*p == '\0')
101638032Speter					p = NULL;
101738032Speter			}
101838032Speter			if (*m->m_mtatype == '\0')
101938032Speter				m->m_mtatype = "dns";
102038032Speter
102138032Speter			/* extract address type; default to "rfc822" */
102238032Speter			m->m_addrtype = p;
102338032Speter			if (p != NULL)
102438032Speter				p = strchr(p, '/');
102538032Speter			if (p != NULL)
102638032Speter			{
102738032Speter				*p++ = '\0';
102838032Speter				if (*p == '\0')
102938032Speter					p = NULL;
103038032Speter			}
103138032Speter			if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
103238032Speter				m->m_addrtype = "rfc822";
103338032Speter
103438032Speter			/* extract diagnostic type; default to "smtp" */
103538032Speter			m->m_diagtype = p;
103638032Speter			if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
103738032Speter				m->m_diagtype = "smtp";
103838032Speter			break;
103938032Speter
104038032Speter		  case 'U':		/* user id */
104138032Speter			if (isascii(*p) && !isdigit(*p))
104238032Speter			{
104338032Speter				char *q = p;
104438032Speter				struct passwd *pw;
104538032Speter
104638032Speter				while (*p != '\0' && isascii(*p) &&
104738032Speter				       (isalnum(*p) || strchr("-_", *p) != NULL))
104838032Speter					p++;
104938032Speter				while (isascii(*p) && isspace(*p))
105038032Speter					*p++ = '\0';
105138032Speter				if (*p != '\0')
105238032Speter					*p++ = '\0';
105338032Speter				if (*q == '\0')
105471345Sgshapiro				{
105538032Speter					syserr("mailer %s: null user name",
105638032Speter						m->m_name);
105771345Sgshapiro					break;
105871345Sgshapiro				}
105938032Speter				pw = sm_getpwnam(q);
106038032Speter				if (pw == NULL)
106171345Sgshapiro				{
106238032Speter					syserr("readcf: mailer U= flag: unknown user %s", q);
106371345Sgshapiro					break;
106471345Sgshapiro				}
106538032Speter				else
106638032Speter				{
106738032Speter					m->m_uid = pw->pw_uid;
106838032Speter					m->m_gid = pw->pw_gid;
106938032Speter				}
107038032Speter			}
107138032Speter			else
107238032Speter			{
107338032Speter				auto char *q;
107438032Speter
107538032Speter				m->m_uid = strtol(p, &q, 0);
107638032Speter				p = q;
107738032Speter				while (isascii(*p) && isspace(*p))
107838032Speter					p++;
107938032Speter				if (*p != '\0')
108038032Speter					p++;
108138032Speter			}
108238032Speter			while (isascii(*p) && isspace(*p))
108338032Speter				p++;
108438032Speter			if (*p == '\0')
108538032Speter				break;
108638032Speter			if (isascii(*p) && !isdigit(*p))
108738032Speter			{
108838032Speter				char *q = p;
108938032Speter				struct group *gr;
109038032Speter
109138032Speter				while (isascii(*p) && isalnum(*p))
109238032Speter					p++;
109338032Speter				*p++ = '\0';
109438032Speter				if (*q == '\0')
109571345Sgshapiro				{
109638032Speter					syserr("mailer %s: null group name",
109738032Speter						m->m_name);
109871345Sgshapiro					break;
109971345Sgshapiro				}
110038032Speter				gr = getgrnam(q);
110138032Speter				if (gr == NULL)
110271345Sgshapiro				{
110338032Speter					syserr("readcf: mailer U= flag: unknown group %s", q);
110471345Sgshapiro					break;
110571345Sgshapiro				}
110638032Speter				else
110738032Speter					m->m_gid = gr->gr_gid;
110838032Speter			}
110938032Speter			else
111038032Speter			{
111138032Speter				m->m_gid = strtol(p, NULL, 0);
111238032Speter			}
111338032Speter			break;
111464562Sgshapiro
111564562Sgshapiro		  case 'W':		/* wait timeout */
111664562Sgshapiro			m->m_wait = convtime(p, 's');
111764562Sgshapiro			break;
111864562Sgshapiro
111964562Sgshapiro		  case '/':		/* new root directory */
112064562Sgshapiro			if (*p == '\0')
112164562Sgshapiro				syserr("mailer %s: null root directory",
112264562Sgshapiro					m->m_name);
112364562Sgshapiro			else
112464562Sgshapiro				m->m_rootdir = newstr(p);
112564562Sgshapiro			break;
112664562Sgshapiro
112764562Sgshapiro		  default:
112864562Sgshapiro			syserr("M%s: unknown mailer equate %c=",
112964562Sgshapiro			       m->m_name, fcode);
113064562Sgshapiro			break;
113138032Speter		}
113238032Speter
113338032Speter		p = delimptr;
113438032Speter	}
113538032Speter
113638032Speter	/* do some rationality checking */
113738032Speter	if (m->m_argv == NULL)
113838032Speter	{
113938032Speter		syserr("M%s: A= argument required", m->m_name);
114038032Speter		return;
114138032Speter	}
114238032Speter	if (m->m_mailer == NULL)
114338032Speter	{
114438032Speter		syserr("M%s: P= argument required", m->m_name);
114538032Speter		return;
114638032Speter	}
114738032Speter
114838032Speter	if (NextMailer >= MAXMAILERS)
114938032Speter	{
115038032Speter		syserr("too many mailers defined (%d max)", MAXMAILERS);
115138032Speter		return;
115238032Speter	}
115338032Speter
115464562Sgshapiro#if _FFR_DYNAMIC_TOBUF
115564562Sgshapiro	if (m->m_maxrcpt <= 0)
115664562Sgshapiro		m->m_maxrcpt = DEFAULT_MAX_RCPT;
115764562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */
115864562Sgshapiro
115938032Speter	/* do some heuristic cleanup for back compatibility */
116038032Speter	if (bitnset(M_LIMITS, m->m_flags))
116138032Speter	{
116238032Speter		if (m->m_linelimit == 0)
116338032Speter			m->m_linelimit = SMTPLINELIM;
116438032Speter		if (ConfigLevel < 2)
116538032Speter			setbitn(M_7BITS, m->m_flags);
116638032Speter	}
116738032Speter
116864562Sgshapiro	if (strcmp(m->m_mailer, "[TCP]") == 0)
116938032Speter	{
117066494Sgshapiro#if _FFR_REMOVE_TCP_MAILER_PATH
117164562Sgshapiro		syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n",
117264562Sgshapiro		       m->m_name);
117371345Sgshapiro		return;
117466494Sgshapiro#else /* _FFR_REMOVE_TCP_MAILER_PATH */
117564562Sgshapiro		printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n",
117664562Sgshapiro		       m->m_name);
117766494Sgshapiro#endif /* _FFR_REMOVE_TCP_MAILER_PATH */
117838032Speter	}
117938032Speter
118066494Sgshapiro	if (strcmp(m->m_mailer, "[IPC]") == 0
118164562Sgshapiro#if !_FFR_REMOVE_TCP_MAILER_PATH
118266494Sgshapiro	    || strcmp(m->m_mailer, "[TCP]") == 0
118364562Sgshapiro#endif /* !_FFR_REMOVE_TCP_MAILER_PATH */
118464562Sgshapiro	    )
118538032Speter	{
118664562Sgshapiro		/* Use the second argument for host or path to socket */
118764562Sgshapiro		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
118864562Sgshapiro		    m->m_argv[1][0] == '\0')
118964562Sgshapiro		{
119064562Sgshapiro			syserr("M%s: too few parameters for %s mailer",
119164562Sgshapiro			       m->m_name, m->m_mailer);
119271345Sgshapiro			return;
119364562Sgshapiro		}
119466494Sgshapiro		if (strcmp(m->m_argv[0], "TCP") != 0
119564562Sgshapiro#if NETUNIX
119666494Sgshapiro		    && strcmp(m->m_argv[0], "FILE") != 0
119764562Sgshapiro#endif /* NETUNIX */
119864562Sgshapiro#if !_FFR_DEPRECATE_IPC_MAILER_ARG
119966494Sgshapiro		    && strcmp(m->m_argv[0], "IPC") != 0
120064562Sgshapiro#endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */
120164562Sgshapiro		    )
120264562Sgshapiro		{
120364562Sgshapiro			printf("M%s: Warning: first argument in %s mailer must be %s\n",
120464562Sgshapiro			       m->m_name, m->m_mailer,
120564562Sgshapiro#if NETUNIX
120664562Sgshapiro			       "TCP or FILE"
120764562Sgshapiro#else /* NETUNIX */
120864562Sgshapiro			       "TCP"
120964562Sgshapiro#endif /* NETUNIX */
121064562Sgshapiro			       );
121164562Sgshapiro		}
121264562Sgshapiro
121364562Sgshapiro	}
121464562Sgshapiro	else if (strcmp(m->m_mailer, "[FILE]") == 0)
121564562Sgshapiro	{
121638032Speter		/* Use the second argument for filename */
121738032Speter		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
121838032Speter		    m->m_argv[2] != NULL)
121938032Speter		{
122038032Speter			syserr("M%s: too %s parameters for [FILE] mailer",
122138032Speter			       m->m_name,
122238032Speter			       (m->m_argv[0] == NULL ||
122338032Speter				m->m_argv[1] == NULL) ? "few" : "many");
122471345Sgshapiro			return;
122538032Speter		}
122638032Speter		else if (strcmp(m->m_argv[0], "FILE") != 0)
122738032Speter		{
122838032Speter			syserr("M%s: first argument in [FILE] mailer must be FILE",
122938032Speter			       m->m_name);
123071345Sgshapiro			return;
123138032Speter		}
123238032Speter	}
123338032Speter
123464562Sgshapiro	if (strcmp(m->m_mailer, "[IPC]") == 0 ||
123564562Sgshapiro	    strcmp(m->m_mailer, "[TCP]") == 0)
123664562Sgshapiro	{
123764562Sgshapiro		if (m->m_mtatype == NULL)
123864562Sgshapiro			m->m_mtatype = "dns";
123964562Sgshapiro		if (m->m_addrtype == NULL)
124064562Sgshapiro			m->m_addrtype = "rfc822";
124164562Sgshapiro		if (m->m_diagtype == NULL)
124264562Sgshapiro		{
124364562Sgshapiro			if (m->m_argv[0] != NULL &&
124464562Sgshapiro			    strcmp(m->m_argv[0], "FILE") == 0)
124564562Sgshapiro				m->m_diagtype = "x-unix";
124664562Sgshapiro			else
124764562Sgshapiro				m->m_diagtype = "smtp";
124864562Sgshapiro		}
124964562Sgshapiro	}
125064562Sgshapiro
125138032Speter	if (m->m_eol == NULL)
125238032Speter	{
125338032Speter		char **pp;
125438032Speter
125538032Speter		/* default for SMTP is \r\n; use \n for local delivery */
125638032Speter		for (pp = m->m_argv; *pp != NULL; pp++)
125738032Speter		{
125838032Speter			for (p = *pp; *p != '\0'; )
125938032Speter			{
126038032Speter				if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
126138032Speter					break;
126238032Speter			}
126338032Speter			if (*p != '\0')
126438032Speter				break;
126538032Speter		}
126638032Speter		if (*pp == NULL)
126738032Speter			m->m_eol = "\r\n";
126838032Speter		else
126938032Speter			m->m_eol = "\n";
127038032Speter	}
127138032Speter
127238032Speter	/* enter the mailer into the symbol table */
127338032Speter	s = stab(m->m_name, ST_MAILER, ST_ENTER);
127438032Speter	if (s->s_mailer != NULL)
127538032Speter	{
127638032Speter		i = s->s_mailer->m_mno;
127777349Sgshapiro		sm_free(s->s_mailer);
127838032Speter	}
127938032Speter	else
128038032Speter	{
128138032Speter		i = NextMailer++;
128238032Speter	}
128338032Speter	Mailer[i] = s->s_mailer = m;
128438032Speter	m->m_mno = i;
128538032Speter}
128638032Speter/*
128738032Speter**  MUNCHSTRING -- translate a string into internal form.
128838032Speter**
128938032Speter**	Parameters:
129038032Speter**		p -- the string to munch.
129138032Speter**		delimptr -- if non-NULL, set to the pointer of the
129238032Speter**			field delimiter character.
129338032Speter**		delim -- the delimiter for the field.
129438032Speter**
129538032Speter**	Returns:
129638032Speter**		the munched string.
129764562Sgshapiro**
129864562Sgshapiro**	Side Effects:
129964562Sgshapiro**		the munched string is a local static buffer.
130064562Sgshapiro**		it must be copied before the function is called again.
130138032Speter*/
130238032Speter
130338032Speterchar *
130438032Spetermunchstring(p, delimptr, delim)
130538032Speter	register char *p;
130638032Speter	char **delimptr;
130738032Speter	int delim;
130838032Speter{
130938032Speter	register char *q;
131038032Speter	bool backslash = FALSE;
131138032Speter	bool quotemode = FALSE;
131238032Speter	static char buf[MAXLINE];
131338032Speter
131438032Speter	for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
131538032Speter	{
131638032Speter		if (backslash)
131738032Speter		{
131838032Speter			/* everything is roughly literal */
131938032Speter			backslash = FALSE;
132038032Speter			switch (*p)
132138032Speter			{
132238032Speter			  case 'r':		/* carriage return */
132338032Speter				*q++ = '\r';
132438032Speter				continue;
132538032Speter
132638032Speter			  case 'n':		/* newline */
132738032Speter				*q++ = '\n';
132838032Speter				continue;
132938032Speter
133038032Speter			  case 'f':		/* form feed */
133138032Speter				*q++ = '\f';
133238032Speter				continue;
133338032Speter
133438032Speter			  case 'b':		/* backspace */
133538032Speter				*q++ = '\b';
133638032Speter				continue;
133738032Speter			}
133838032Speter			*q++ = *p;
133938032Speter		}
134038032Speter		else
134138032Speter		{
134238032Speter			if (*p == '\\')
134338032Speter				backslash = TRUE;
134438032Speter			else if (*p == '"')
134538032Speter				quotemode = !quotemode;
134638032Speter			else if (quotemode || *p != delim)
134738032Speter				*q++ = *p;
134838032Speter			else
134938032Speter				break;
135038032Speter		}
135138032Speter	}
135238032Speter
135338032Speter	if (delimptr != NULL)
135438032Speter		*delimptr = p;
135538032Speter	*q++ = '\0';
135664562Sgshapiro	return buf;
135738032Speter}
135838032Speter/*
135938032Speter**  MAKEARGV -- break up a string into words
136038032Speter**
136138032Speter**	Parameters:
136238032Speter**		p -- the string to break up.
136338032Speter**
136438032Speter**	Returns:
136538032Speter**		a char **argv (dynamically allocated)
136638032Speter**
136738032Speter**	Side Effects:
136838032Speter**		munges p.
136938032Speter*/
137038032Speter
137164562Sgshapirostatic char **
137238032Spetermakeargv(p)
137338032Speter	register char *p;
137438032Speter{
137538032Speter	char *q;
137638032Speter	int i;
137738032Speter	char **avp;
137838032Speter	char *argv[MAXPV + 1];
137938032Speter
138038032Speter	/* take apart the words */
138138032Speter	i = 0;
138238032Speter	while (*p != '\0' && i < MAXPV)
138338032Speter	{
138438032Speter		q = p;
138538032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
138638032Speter			p++;
138738032Speter		while (isascii(*p) && isspace(*p))
138838032Speter			*p++ = '\0';
138938032Speter		argv[i++] = newstr(q);
139038032Speter	}
139138032Speter	argv[i++] = NULL;
139238032Speter
139338032Speter	/* now make a copy of the argv */
139438032Speter	avp = (char **) xalloc(sizeof *avp * i);
139564562Sgshapiro	memmove((char *) avp, (char *) argv, sizeof *avp * i);
139638032Speter
139764562Sgshapiro	return avp;
139838032Speter}
139938032Speter/*
140038032Speter**  PRINTRULES -- print rewrite rules (for debugging)
140138032Speter**
140238032Speter**	Parameters:
140338032Speter**		none.
140438032Speter**
140538032Speter**	Returns:
140638032Speter**		none.
140738032Speter**
140838032Speter**	Side Effects:
140938032Speter**		prints rewrite rules.
141038032Speter*/
141138032Speter
141238032Spetervoid
141338032Speterprintrules()
141438032Speter{
141538032Speter	register struct rewrite *rwp;
141638032Speter	register int ruleset;
141738032Speter
141838032Speter	for (ruleset = 0; ruleset < 10; ruleset++)
141938032Speter	{
142038032Speter		if (RewriteRules[ruleset] == NULL)
142138032Speter			continue;
142238032Speter		printf("\n----Rule Set %d:", ruleset);
142338032Speter
142438032Speter		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
142538032Speter		{
142638032Speter			printf("\nLHS:");
142738032Speter			printav(rwp->r_lhs);
142838032Speter			printf("RHS:");
142938032Speter			printav(rwp->r_rhs);
143038032Speter		}
143138032Speter	}
143238032Speter}
143338032Speter/*
143438032Speter**  PRINTMAILER -- print mailer structure (for debugging)
143538032Speter**
143638032Speter**	Parameters:
143738032Speter**		m -- the mailer to print
143838032Speter**
143938032Speter**	Returns:
144038032Speter**		none.
144138032Speter*/
144238032Speter
144338032Spetervoid
144438032Speterprintmailer(m)
144538032Speter	register MAILER *m;
144638032Speter{
144738032Speter	int j;
144838032Speter
144964562Sgshapiro	printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer);
145064562Sgshapiro	if (RuleSetNames[m->m_se_rwset] == NULL)
145164562Sgshapiro		printf("%d/", m->m_se_rwset);
145264562Sgshapiro	else
145364562Sgshapiro		printf("%s/", RuleSetNames[m->m_se_rwset]);
145464562Sgshapiro	if (RuleSetNames[m->m_sh_rwset] == NULL)
145564562Sgshapiro		printf("%d R=", m->m_sh_rwset);
145664562Sgshapiro	else
145764562Sgshapiro		printf("%s R=", RuleSetNames[m->m_sh_rwset]);
145864562Sgshapiro	if (RuleSetNames[m->m_re_rwset] == NULL)
145964562Sgshapiro		printf("%d/", m->m_re_rwset);
146064562Sgshapiro	else
146164562Sgshapiro		printf("%s/", RuleSetNames[m->m_re_rwset]);
146264562Sgshapiro	if (RuleSetNames[m->m_rh_rwset] == NULL)
146364562Sgshapiro		printf("%d ", m->m_rh_rwset);
146464562Sgshapiro	else
146564562Sgshapiro		printf("%s ", RuleSetNames[m->m_rh_rwset]);
146664562Sgshapiro	printf("M=%ld U=%d:%d F=", m->m_maxsize,
146764562Sgshapiro	       (int) m->m_uid, (int) m->m_gid);
146838032Speter	for (j = '\0'; j <= '\177'; j++)
146938032Speter		if (bitnset(j, m->m_flags))
147038032Speter			(void) putchar(j);
147138032Speter	printf(" L=%d E=", m->m_linelimit);
147238032Speter	xputs(m->m_eol);
147338032Speter	if (m->m_defcharset != NULL)
147438032Speter		printf(" C=%s", m->m_defcharset);
147538032Speter	printf(" T=%s/%s/%s",
147638032Speter		m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
147738032Speter		m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
147838032Speter		m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
147964562Sgshapiro#if _FFR_DYNAMIC_TOBUF
148064562Sgshapiro	printf(" r=%d", m->m_maxrcpt);
148164562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */
148238032Speter	if (m->m_argv != NULL)
148338032Speter	{
148438032Speter		char **a = m->m_argv;
148538032Speter
148638032Speter		printf(" A=");
148738032Speter		while (*a != NULL)
148838032Speter		{
148938032Speter			if (a != m->m_argv)
149038032Speter				printf(" ");
149138032Speter			xputs(*a++);
149238032Speter		}
149338032Speter	}
149438032Speter	printf("\n");
149538032Speter}
149638032Speter/*
149738032Speter**  SETOPTION -- set global processing option
149838032Speter**
149938032Speter**	Parameters:
150038032Speter**		opt -- option name.
150138032Speter**		val -- option value (as a text string).
150238032Speter**		safe -- set if this came from a configuration file.
150338032Speter**			Some options (if set from the command line) will
150438032Speter**			reset the user id to avoid security problems.
150538032Speter**		sticky -- if set, don't let other setoptions override
150638032Speter**			this value.
150738032Speter**		e -- the main envelope.
150838032Speter**
150938032Speter**	Returns:
151038032Speter**		none.
151138032Speter**
151238032Speter**	Side Effects:
151338032Speter**		Sets options as implied by the arguments.
151438032Speter*/
151538032Speter
151664562Sgshapirostatic BITMAP256	StickyOpt;		/* set if option is stuck */
151738032Speter
151838032Speter#if NAMED_BIND
151938032Speter
152064562Sgshapirostatic struct resolverflags
152138032Speter{
152238032Speter	char	*rf_name;	/* name of the flag */
152338032Speter	long	rf_bits;	/* bits to set/clear */
152438032Speter} ResolverFlags[] =
152538032Speter{
152638032Speter	{ "debug",	RES_DEBUG	},
152738032Speter	{ "aaonly",	RES_AAONLY	},
152838032Speter	{ "usevc",	RES_USEVC	},
152938032Speter	{ "primary",	RES_PRIMARY	},
153038032Speter	{ "igntc",	RES_IGNTC	},
153138032Speter	{ "recurse",	RES_RECURSE	},
153238032Speter	{ "defnames",	RES_DEFNAMES	},
153338032Speter	{ "stayopen",	RES_STAYOPEN	},
153438032Speter	{ "dnsrch",	RES_DNSRCH	},
153538032Speter	{ "true",	0		},	/* avoid error on old syntax */
153638032Speter	{ NULL,		0		}
153738032Speter};
153838032Speter
153964562Sgshapiro#endif /* NAMED_BIND */
154038032Speter
154164562Sgshapiro#define OI_NONE		0	/* no special treatment */
154264562Sgshapiro#define OI_SAFE		0x0001	/* safe for random people to use */
154364562Sgshapiro#define OI_SUBOPT	0x0002	/* option has suboptions */
154464562Sgshapiro
154564562Sgshapirostatic struct optioninfo
154638032Speter{
154738032Speter	char	*o_name;	/* long name of option */
154838032Speter	u_char	o_code;		/* short name of option */
154964562Sgshapiro	u_short	o_flags;	/* option flags */
155038032Speter} OptionTab[] =
155138032Speter{
155264562Sgshapiro#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
155364562Sgshapiro	{ "RemoteMode",			'>',		OI_NONE	},
155464562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */
155564562Sgshapiro	{ "SevenBitInput",		'7',		OI_SAFE	},
155664562Sgshapiro	{ "EightBitMode",		'8',		OI_SAFE	},
155764562Sgshapiro	{ "AliasFile",			'A',		OI_NONE	},
155864562Sgshapiro	{ "AliasWait",			'a',		OI_NONE	},
155964562Sgshapiro	{ "BlankSub",			'B',		OI_NONE	},
156064562Sgshapiro	{ "MinFreeBlocks",		'b',		OI_SAFE	},
156164562Sgshapiro	{ "CheckpointInterval",		'C',		OI_SAFE	},
156264562Sgshapiro	{ "HoldExpensive",		'c',		OI_NONE	},
156364562Sgshapiro#if !_FFR_REMOVE_AUTOREBUILD
156464562Sgshapiro	{ "AutoRebuildAliases",		'D',		OI_NONE	},
156564562Sgshapiro#endif /* !_FFR_REMOVE_AUTOREBUILD */
156664562Sgshapiro	{ "DeliveryMode",		'd',		OI_SAFE	},
156764562Sgshapiro	{ "ErrorHeader",		'E',		OI_NONE	},
156864562Sgshapiro	{ "ErrorMode",			'e',		OI_SAFE	},
156964562Sgshapiro	{ "TempFileMode",		'F',		OI_NONE	},
157064562Sgshapiro	{ "SaveFromLine",		'f',		OI_NONE	},
157164562Sgshapiro	{ "MatchGECOS",			'G',		OI_NONE	},
157264562Sgshapiro	{ "HelpFile",			'H',		OI_NONE	},
157364562Sgshapiro	{ "MaxHopCount",		'h',		OI_NONE	},
157464562Sgshapiro	{ "ResolverOptions",		'I',		OI_NONE	},
157564562Sgshapiro	{ "IgnoreDots",			'i',		OI_SAFE	},
157664562Sgshapiro	{ "ForwardPath",		'J',		OI_NONE	},
157764562Sgshapiro	{ "SendMimeErrors",		'j',		OI_SAFE	},
157864562Sgshapiro	{ "ConnectionCacheSize",	'k',		OI_NONE	},
157964562Sgshapiro	{ "ConnectionCacheTimeout",	'K',		OI_NONE	},
158064562Sgshapiro	{ "UseErrorsTo",		'l',		OI_NONE	},
158164562Sgshapiro	{ "LogLevel",			'L',		OI_SAFE	},
158264562Sgshapiro	{ "MeToo",			'm',		OI_SAFE	},
158364562Sgshapiro	{ "CheckAliases",		'n',		OI_NONE	},
158464562Sgshapiro	{ "OldStyleHeaders",		'o',		OI_SAFE	},
158564562Sgshapiro	{ "DaemonPortOptions",		'O',		OI_NONE	},
158664562Sgshapiro	{ "PrivacyOptions",		'p',		OI_SAFE	},
158764562Sgshapiro	{ "PostmasterCopy",		'P',		OI_NONE	},
158864562Sgshapiro	{ "QueueFactor",		'q',		OI_NONE	},
158964562Sgshapiro	{ "QueueDirectory",		'Q',		OI_NONE	},
159064562Sgshapiro	{ "DontPruneRoutes",		'R',		OI_NONE	},
159164562Sgshapiro	{ "Timeout",			'r',		OI_SUBOPT },
159264562Sgshapiro	{ "StatusFile",			'S',		OI_NONE	},
159364562Sgshapiro	{ "SuperSafe",			's',		OI_SAFE	},
159464562Sgshapiro	{ "QueueTimeout",		'T',		OI_NONE	},
159564562Sgshapiro	{ "TimeZoneSpec",		't',		OI_NONE	},
159664562Sgshapiro	{ "UserDatabaseSpec",		'U',		OI_NONE	},
159764562Sgshapiro	{ "DefaultUser",		'u',		OI_NONE	},
159864562Sgshapiro	{ "FallbackMXhost",		'V',		OI_NONE	},
159964562Sgshapiro	{ "Verbose",			'v',		OI_SAFE	},
160064562Sgshapiro	{ "TryNullMXList",		'w',		OI_NONE	},
160164562Sgshapiro	{ "QueueLA",			'x',		OI_NONE	},
160264562Sgshapiro	{ "RefuseLA",			'X',		OI_NONE	},
160364562Sgshapiro	{ "RecipientFactor",		'y',		OI_NONE	},
160464562Sgshapiro	{ "ForkEachJob",		'Y',		OI_NONE	},
160564562Sgshapiro	{ "ClassFactor",		'z',		OI_NONE	},
160664562Sgshapiro	{ "RetryFactor",		'Z',		OI_NONE	},
160738032Speter#define O_QUEUESORTORD	0x81
160864562Sgshapiro	{ "QueueSortOrder",		O_QUEUESORTORD,	OI_SAFE	},
160938032Speter#define O_HOSTSFILE	0x82
161064562Sgshapiro	{ "HostsFile",			O_HOSTSFILE,	OI_NONE	},
161138032Speter#define O_MQA		0x83
161264562Sgshapiro	{ "MinQueueAge",		O_MQA,		OI_SAFE	},
161338032Speter#define O_DEFCHARSET	0x85
161464562Sgshapiro	{ "DefaultCharSet",		O_DEFCHARSET,	OI_SAFE	},
161538032Speter#define O_SSFILE	0x86
161664562Sgshapiro	{ "ServiceSwitchFile",		O_SSFILE,	OI_NONE	},
161738032Speter#define O_DIALDELAY	0x87
161864562Sgshapiro	{ "DialDelay",			O_DIALDELAY,	OI_SAFE	},
161938032Speter#define O_NORCPTACTION	0x88
162064562Sgshapiro	{ "NoRecipientAction",		O_NORCPTACTION,	OI_SAFE	},
162138032Speter#define O_SAFEFILEENV	0x89
162264562Sgshapiro	{ "SafeFileEnvironment",	O_SAFEFILEENV,	OI_NONE	},
162338032Speter#define O_MAXMSGSIZE	0x8a
162464562Sgshapiro	{ "MaxMessageSize",		O_MAXMSGSIZE,	OI_NONE	},
162538032Speter#define O_COLONOKINADDR	0x8b
162664562Sgshapiro	{ "ColonOkInAddr",		O_COLONOKINADDR, OI_SAFE },
162738032Speter#define O_MAXQUEUERUN	0x8c
162864562Sgshapiro	{ "MaxQueueRunSize",		O_MAXQUEUERUN,	OI_SAFE	},
162938032Speter#define O_MAXCHILDREN	0x8d
163064562Sgshapiro	{ "MaxDaemonChildren",		O_MAXCHILDREN,	OI_NONE	},
163138032Speter#define O_KEEPCNAMES	0x8e
163264562Sgshapiro	{ "DontExpandCnames",		O_KEEPCNAMES,	OI_NONE	},
163338032Speter#define O_MUSTQUOTE	0x8f
163464562Sgshapiro	{ "MustQuoteChars",		O_MUSTQUOTE,	OI_NONE	},
163538032Speter#define O_SMTPGREETING	0x90
163664562Sgshapiro	{ "SmtpGreetingMessage",	O_SMTPGREETING,	OI_NONE	},
163738032Speter#define O_UNIXFROM	0x91
163864562Sgshapiro	{ "UnixFromLine",		O_UNIXFROM,	OI_NONE	},
163938032Speter#define O_OPCHARS	0x92
164064562Sgshapiro	{ "OperatorChars",		O_OPCHARS,	OI_NONE	},
164138032Speter#define O_DONTINITGRPS	0x93
164264562Sgshapiro	{ "DontInitGroups",		O_DONTINITGRPS,	OI_NONE	},
164338032Speter#define O_SLFH		0x94
164464562Sgshapiro	{ "SingleLineFromHeader",	O_SLFH,		OI_SAFE	},
164538032Speter#define O_ABH		0x95
164664562Sgshapiro	{ "AllowBogusHELO",		O_ABH,		OI_SAFE	},
164738032Speter#define O_CONNTHROT	0x97
164864562Sgshapiro	{ "ConnectionRateThrottle",	O_CONNTHROT,	OI_NONE	},
164938032Speter#define O_UGW		0x99
165064562Sgshapiro	{ "UnsafeGroupWrites",		O_UGW,		OI_NONE	},
165138032Speter#define O_DBLBOUNCE	0x9a
165264562Sgshapiro	{ "DoubleBounceAddress",	O_DBLBOUNCE,	OI_NONE	},
165338032Speter#define O_HSDIR		0x9b
165464562Sgshapiro	{ "HostStatusDirectory",	O_HSDIR,	OI_NONE	},
165538032Speter#define O_SINGTHREAD	0x9c
165664562Sgshapiro	{ "SingleThreadDelivery",	O_SINGTHREAD,	OI_NONE	},
165738032Speter#define O_RUNASUSER	0x9d
165864562Sgshapiro	{ "RunAsUser",			O_RUNASUSER,	OI_NONE	},
165938032Speter#define O_DSN_RRT	0x9e
166064562Sgshapiro	{ "RrtImpliesDsn",		O_DSN_RRT,	OI_NONE	},
166138032Speter#define O_PIDFILE	0x9f
166264562Sgshapiro	{ "PidFile",			O_PIDFILE,	OI_NONE	},
166338032Speter#define O_DONTBLAMESENDMAIL	0xa0
166464562Sgshapiro	{ "DontBlameSendmail",		O_DONTBLAMESENDMAIL,	OI_NONE	},
166538032Speter#define O_DPI		0xa1
166664562Sgshapiro	{ "DontProbeInterfaces",	O_DPI,		OI_NONE	},
166738032Speter#define O_MAXRCPT	0xa2
166864562Sgshapiro	{ "MaxRecipientsPerMessage",	O_MAXRCPT,	OI_SAFE	},
166938032Speter#define O_DEADLETTER	0xa3
167064562Sgshapiro	{ "DeadLetterDrop",		O_DEADLETTER,	OI_NONE	},
167138032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
167264562Sgshapiro# define O_DONTLOCK	0xa4
167364562Sgshapiro	{ "DontLockFilesForRead",	O_DONTLOCK,	OI_NONE	},
167464562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
167538032Speter#define O_MAXALIASRCSN	0xa5
167664562Sgshapiro	{ "MaxAliasRecursion",		O_MAXALIASRCSN,	OI_NONE	},
167738032Speter#define O_CNCTONLYTO	0xa6
167864562Sgshapiro	{ "ConnectOnlyTo",		O_CNCTONLYTO,	OI_NONE	},
167942575Speter#define O_TRUSTUSER	0xa7
168064562Sgshapiro	{ "TrustedUser",		O_TRUSTUSER,	OI_NONE	},
168142575Speter#define O_MAXMIMEHDRLEN	0xa8
168264562Sgshapiro	{ "MaxMimeHeaderLength",	O_MAXMIMEHDRLEN,	OI_NONE	},
168342575Speter#define O_CONTROLSOCKET	0xa9
168464562Sgshapiro	{ "ControlSocketName",		O_CONTROLSOCKET,	OI_NONE	},
168543730Speter#define O_MAXHDRSLEN	0xaa
168664562Sgshapiro	{ "MaxHeadersLength",		O_MAXHDRSLEN,	OI_NONE	},
168764562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
168864562Sgshapiro# define O_MAXFORWARD	0xab
168964562Sgshapiro	{ "MaxForwardEntries",		O_MAXFORWARD,	OI_NONE	},
169064562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */
169164562Sgshapiro#define O_PROCTITLEPREFIX	0xac
169264562Sgshapiro	{ "ProcessTitlePrefix",		O_PROCTITLEPREFIX,	OI_NONE	},
169364562Sgshapiro#define O_SASLINFO	0xad
169464562Sgshapiro#if _FFR_ALLOW_SASLINFO
169564562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_SAFE	},
169664562Sgshapiro#else /* _FFR_ALLOW_SASLINFO */
169764562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_NONE	},
169864562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */
169964562Sgshapiro#define O_SASLMECH	0xae
170064562Sgshapiro	{ "AuthMechanisms",		O_SASLMECH,	OI_NONE	},
170164562Sgshapiro#define O_CLIENTPORT	0xaf
170264562Sgshapiro	{ "ClientPortOptions",		O_CLIENTPORT,	OI_NONE	},
170364562Sgshapiro#define O_DF_BUFSIZE	0xb0
170464562Sgshapiro	{ "DataFileBufferSize",		O_DF_BUFSIZE,	OI_NONE	},
170564562Sgshapiro#define O_XF_BUFSIZE	0xb1
170664562Sgshapiro	{ "XscriptFileBufferSize",	O_XF_BUFSIZE,	OI_NONE	},
170764562Sgshapiro# define O_LDAPDEFAULTSPEC	0xb2
170864562Sgshapiro	{ "LDAPDefaultSpec",		O_LDAPDEFAULTSPEC,	OI_NONE	},
170964562Sgshapiro#if _FFR_QUEUEDELAY
171064562Sgshapiro#define O_QUEUEDELAY	0xb3
171164562Sgshapiro	{ "QueueDelay",			O_QUEUEDELAY,	OI_NONE	},
171264562Sgshapiro#endif /* _FFR_QUEUEDELAY */
171364562Sgshapiro# define O_SRVCERTFILE	0xb4
171464562Sgshapiro	{ "ServerCertFile",		O_SRVCERTFILE,	OI_NONE	},
171564562Sgshapiro# define O_SRVKEYFILE	0xb5
171664562Sgshapiro	{ "Serverkeyfile",		O_SRVKEYFILE,	OI_NONE	},
171764562Sgshapiro# define O_CLTCERTFILE	0xb6
171864562Sgshapiro	{ "ClientCertFile",		O_CLTCERTFILE,	OI_NONE	},
171964562Sgshapiro# define O_CLTKEYFILE	0xb7
172064562Sgshapiro	{ "Clientkeyfile",		O_CLTKEYFILE,	OI_NONE	},
172164562Sgshapiro# define O_CACERTFILE	0xb8
172264562Sgshapiro	{ "CACERTFile",			O_CACERTFILE,	OI_NONE	},
172364562Sgshapiro# define O_CACERTPATH	0xb9
172464562Sgshapiro	{ "CACERTPath",			O_CACERTPATH,	OI_NONE	},
172564562Sgshapiro# define O_DHPARAMS	0xba
172664562Sgshapiro	{ "DHParameters",		O_DHPARAMS,	OI_NONE	},
172764562Sgshapiro#if _FFR_MILTER
172864562Sgshapiro#define O_INPUTMILTER	0xbb
172964562Sgshapiro	{ "InputMailFilters",		O_INPUTMILTER,	OI_NONE	},
173064562Sgshapiro#define O_MILTER	0xbc
173164562Sgshapiro	{ "Milter",			O_MILTER,	OI_SUBOPT	},
173264562Sgshapiro#endif /* _FFR_MILTER */
173364562Sgshapiro#define O_SASLOPTS	0xbd
173464562Sgshapiro	{ "AuthOptions",		O_SASLOPTS,	OI_NONE	},
173564562Sgshapiro#if _FFR_QUEUE_FILE_MODE
173664562Sgshapiro#define O_QUEUE_FILE_MODE	0xbe
173764562Sgshapiro	{ "QueueFileMode",		O_QUEUE_FILE_MODE, OI_NONE	},
173864562Sgshapiro#endif /* _FFR_QUEUE_FILE_MODE */
173964562Sgshapiro# if _FFR_TLS_1
174064562Sgshapiro# define O_DHPARAMS5	0xbf
174164562Sgshapiro	{ "DHParameters512",		O_DHPARAMS5,	OI_NONE	},
174264562Sgshapiro# define O_CIPHERLIST	0xc0
174364562Sgshapiro	{ "CipherList",			O_CIPHERLIST,	OI_NONE	},
174464562Sgshapiro# endif /* _FFR_TLS_1 */
174564562Sgshapiro# define O_RANDFILE	0xc1
174664562Sgshapiro	{ "RandFile",			O_RANDFILE,	OI_NONE	},
174764562Sgshapiro	{ NULL,				'\0',		OI_NONE	}
174838032Speter};
174938032Speter
175038032Spetervoid
175138032Spetersetoption(opt, val, safe, sticky, e)
175238032Speter	int opt;
175338032Speter	char *val;
175438032Speter	bool safe;
175538032Speter	bool sticky;
175638032Speter	register ENVELOPE *e;
175738032Speter{
175838032Speter	register char *p;
175938032Speter	register struct optioninfo *o;
176038032Speter	char *subopt;
176138032Speter	int mid;
176238032Speter	bool can_setuid = RunAsUid == 0;
176338032Speter	auto char *ep;
176438032Speter	char buf[50];
176538032Speter	extern bool Warn_Q_option;
176664562Sgshapiro#if _FFR_ALLOW_SASLINFO
176764562Sgshapiro	extern int SubmitMode;
176864562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */
176938032Speter
177038032Speter	errno = 0;
177138032Speter	if (opt == ' ')
177238032Speter	{
177338032Speter		/* full word options */
177438032Speter		struct optioninfo *sel;
177538032Speter
177638032Speter		p = strchr(val, '=');
177738032Speter		if (p == NULL)
177838032Speter			p = &val[strlen(val)];
177938032Speter		while (*--p == ' ')
178038032Speter			continue;
178138032Speter		while (*++p == ' ')
178238032Speter			*p = '\0';
178338032Speter		if (p == val)
178438032Speter		{
178538032Speter			syserr("readcf: null option name");
178638032Speter			return;
178738032Speter		}
178838032Speter		if (*p == '=')
178938032Speter			*p++ = '\0';
179038032Speter		while (*p == ' ')
179138032Speter			p++;
179238032Speter		subopt = strchr(val, '.');
179338032Speter		if (subopt != NULL)
179438032Speter			*subopt++ = '\0';
179538032Speter		sel = NULL;
179638032Speter		for (o = OptionTab; o->o_name != NULL; o++)
179738032Speter		{
179838032Speter			if (strncasecmp(o->o_name, val, strlen(val)) != 0)
179938032Speter				continue;
180038032Speter			if (strlen(o->o_name) == strlen(val))
180138032Speter			{
180238032Speter				/* completely specified -- this must be it */
180338032Speter				sel = NULL;
180438032Speter				break;
180538032Speter			}
180638032Speter			if (sel != NULL)
180738032Speter				break;
180838032Speter			sel = o;
180938032Speter		}
181038032Speter		if (sel != NULL && o->o_name == NULL)
181138032Speter			o = sel;
181238032Speter		else if (o->o_name == NULL)
181338032Speter		{
181438032Speter			syserr("readcf: unknown option name %s", val);
181538032Speter			return;
181638032Speter		}
181738032Speter		else if (sel != NULL)
181838032Speter		{
181938032Speter			syserr("readcf: ambiguous option name %s (matches %s and %s)",
182038032Speter				val, sel->o_name, o->o_name);
182138032Speter			return;
182238032Speter		}
182338032Speter		if (strlen(val) != strlen(o->o_name))
182438032Speter		{
182538032Speter			int oldVerbose = Verbose;
182638032Speter
182738032Speter			Verbose = 1;
182838032Speter			message("Option %s used as abbreviation for %s",
182938032Speter				val, o->o_name);
183038032Speter			Verbose = oldVerbose;
183138032Speter		}
183238032Speter		opt = o->o_code;
183338032Speter		val = p;
183438032Speter	}
183538032Speter	else
183638032Speter	{
183738032Speter		for (o = OptionTab; o->o_name != NULL; o++)
183838032Speter		{
183938032Speter			if (o->o_code == opt)
184038032Speter				break;
184138032Speter		}
184238032Speter		subopt = NULL;
184338032Speter	}
184438032Speter
184564562Sgshapiro	if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
184664562Sgshapiro	{
184764562Sgshapiro		if (tTd(37, 1))
184864562Sgshapiro			dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
184964562Sgshapiro				o->o_name == NULL ? "<unknown>" : o->o_name,
185064562Sgshapiro				subopt);
185164562Sgshapiro		subopt = NULL;
185264562Sgshapiro	}
185364562Sgshapiro
185438032Speter	if (tTd(37, 1))
185538032Speter	{
185664562Sgshapiro		dprintf(isascii(opt) && isprint(opt) ?
185764562Sgshapiro			"setoption %s (%c)%s%s=" :
185864562Sgshapiro			"setoption %s (0x%x)%s%s=",
185938032Speter			o->o_name == NULL ? "<unknown>" : o->o_name,
186038032Speter			opt,
186164562Sgshapiro			subopt == NULL ? "" : ".",
186238032Speter			subopt == NULL ? "" : subopt);
186338032Speter		xputs(val);
186438032Speter	}
186538032Speter
186638032Speter	/*
186738032Speter	**  See if this option is preset for us.
186838032Speter	*/
186938032Speter
187038032Speter	if (!sticky && bitnset(opt, StickyOpt))
187138032Speter	{
187238032Speter		if (tTd(37, 1))
187364562Sgshapiro			dprintf(" (ignored)\n");
187438032Speter		return;
187538032Speter	}
187638032Speter
187738032Speter	/*
187838032Speter	**  Check to see if this option can be specified by this user.
187938032Speter	*/
188038032Speter
188138032Speter	if (!safe && RealUid == 0)
188238032Speter		safe = TRUE;
188364562Sgshapiro	if (!safe && !bitset(OI_SAFE, o->o_flags))
188438032Speter	{
188538032Speter		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
188638032Speter		{
188764562Sgshapiro			int dp;
188864562Sgshapiro
188938032Speter			if (tTd(37, 1))
189064562Sgshapiro				dprintf(" (unsafe)");
189164562Sgshapiro			dp = drop_privileges(TRUE);
189264562Sgshapiro			setstat(dp);
189338032Speter		}
189438032Speter	}
189538032Speter	if (tTd(37, 1))
189664562Sgshapiro		dprintf("\n");
189738032Speter
189838032Speter	switch (opt & 0xff)
189938032Speter	{
190038032Speter	  case '7':		/* force seven-bit input */
190138032Speter		SevenBitInput = atobool(val);
190238032Speter		break;
190338032Speter
190477349Sgshapiro	  case '8':		/* handling of 8-bit input */
190538032Speter#if MIME8TO7
190638032Speter		switch (*val)
190738032Speter		{
190838032Speter		  case 'm':		/* convert 8-bit, convert MIME */
190938032Speter			MimeMode = MM_CVTMIME|MM_MIME8BIT;
191038032Speter			break;
191138032Speter
191238032Speter		  case 'p':		/* pass 8 bit, convert MIME */
191338032Speter			MimeMode = MM_CVTMIME|MM_PASS8BIT;
191438032Speter			break;
191538032Speter
191638032Speter		  case 's':		/* strict adherence */
191738032Speter			MimeMode = MM_CVTMIME;
191838032Speter			break;
191938032Speter
192064562Sgshapiro# if 0
192138032Speter		  case 'r':		/* reject 8-bit, don't convert MIME */
192238032Speter			MimeMode = 0;
192338032Speter			break;
192438032Speter
192538032Speter		  case 'j':		/* "just send 8" */
192638032Speter			MimeMode = MM_PASS8BIT;
192738032Speter			break;
192838032Speter
192938032Speter		  case 'a':		/* encode 8 bit if available */
193038032Speter			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
193138032Speter			break;
193238032Speter
193338032Speter		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
193438032Speter			MimeMode = MM_MIME8BIT;
193538032Speter			break;
193664562Sgshapiro# endif /* 0 */
193738032Speter
193838032Speter		  default:
193938032Speter			syserr("Unknown 8-bit mode %c", *val);
194042575Speter			finis(FALSE, EX_USAGE);
194138032Speter		}
194277349Sgshapiro#else /* MIME8TO7 */
194377349Sgshapiro		printf("Warning: Option EightBitMode requires MIME8TO7 support\n");
194477349Sgshapiro#endif /* MIME8TO7 */
194538032Speter		break;
194638032Speter
194738032Speter	  case 'A':		/* set default alias file */
194838032Speter		if (val[0] == '\0')
194938032Speter			setalias("aliases");
195038032Speter		else
195138032Speter			setalias(val);
195238032Speter		break;
195338032Speter
195438032Speter	  case 'a':		/* look N minutes for "@:@" in alias file */
195538032Speter		if (val[0] == '\0')
195638032Speter			SafeAlias = 5 * 60;		/* five minutes */
195738032Speter		else
195838032Speter			SafeAlias = convtime(val, 'm');
195938032Speter		break;
196038032Speter
196138032Speter	  case 'B':		/* substitution for blank character */
196238032Speter		SpaceSub = val[0];
196338032Speter		if (SpaceSub == '\0')
196438032Speter			SpaceSub = ' ';
196538032Speter		break;
196638032Speter
196738032Speter	  case 'b':		/* min blocks free on queue fs/max msg size */
196838032Speter		p = strchr(val, '/');
196938032Speter		if (p != NULL)
197038032Speter		{
197138032Speter			*p++ = '\0';
197238032Speter			MaxMessageSize = atol(p);
197338032Speter		}
197438032Speter		MinBlocksFree = atol(val);
197538032Speter		break;
197638032Speter
197738032Speter	  case 'c':		/* don't connect to "expensive" mailers */
197838032Speter		NoConnect = atobool(val);
197938032Speter		break;
198038032Speter
198138032Speter	  case 'C':		/* checkpoint every N addresses */
198238032Speter		CheckpointInterval = atoi(val);
198338032Speter		break;
198438032Speter
198538032Speter	  case 'd':		/* delivery mode */
198638032Speter		switch (*val)
198738032Speter		{
198838032Speter		  case '\0':
198964562Sgshapiro			set_delivery_mode(SM_DELIVER, e);
199038032Speter			break;
199138032Speter
199238032Speter		  case SM_QUEUE:	/* queue only */
199338032Speter		  case SM_DEFER:	/* queue only and defer map lookups */
199438032Speter#if !QUEUE
199538032Speter			syserr("need QUEUE to set -odqueue or -oddefer");
199671345Sgshapiro			break;
199764562Sgshapiro#endif /* !QUEUE */
199864562Sgshapiro			/* FALLTHROUGH */
199938032Speter
200038032Speter		  case SM_DELIVER:	/* do everything */
200138032Speter		  case SM_FORK:		/* fork after verification */
200264562Sgshapiro			set_delivery_mode(*val, e);
200338032Speter			break;
200438032Speter
200538032Speter		  default:
200638032Speter			syserr("Unknown delivery mode %c", *val);
200742575Speter			finis(FALSE, EX_USAGE);
200838032Speter		}
200938032Speter		break;
201038032Speter
201164562Sgshapiro#if !_FFR_REMOVE_AUTOREBUILD
201238032Speter	  case 'D':		/* rebuild alias database as needed */
201338032Speter		AutoRebuild = atobool(val);
201438032Speter		break;
201564562Sgshapiro#endif /* !_FFR_REMOVE_AUTOREBUILD */
201638032Speter
201738032Speter	  case 'E':		/* error message header/header file */
201838032Speter		if (*val != '\0')
201938032Speter			ErrMsgFile = newstr(val);
202038032Speter		break;
202138032Speter
202238032Speter	  case 'e':		/* set error processing mode */
202338032Speter		switch (*val)
202438032Speter		{
202538032Speter		  case EM_QUIET:	/* be silent about it */
202638032Speter		  case EM_MAIL:		/* mail back */
202738032Speter		  case EM_BERKNET:	/* do berknet error processing */
202838032Speter		  case EM_WRITE:	/* write back (or mail) */
202938032Speter		  case EM_PRINT:	/* print errors normally (default) */
203038032Speter			e->e_errormode = *val;
203138032Speter			break;
203238032Speter		}
203338032Speter		break;
203438032Speter
203538032Speter	  case 'F':		/* file mode */
203638032Speter		FileMode = atooct(val) & 0777;
203738032Speter		break;
203838032Speter
203938032Speter	  case 'f':		/* save Unix-style From lines on front */
204038032Speter		SaveFrom = atobool(val);
204138032Speter		break;
204238032Speter
204338032Speter	  case 'G':		/* match recipients against GECOS field */
204438032Speter		MatchGecos = atobool(val);
204538032Speter		break;
204638032Speter
204738032Speter	  case 'g':		/* default gid */
204838032Speter  g_opt:
204938032Speter		if (isascii(*val) && isdigit(*val))
205038032Speter			DefGid = atoi(val);
205138032Speter		else
205238032Speter		{
205338032Speter			register struct group *gr;
205438032Speter
205538032Speter			DefGid = -1;
205638032Speter			gr = getgrnam(val);
205738032Speter			if (gr == NULL)
205838032Speter				syserr("readcf: option %c: unknown group %s",
205938032Speter					opt, val);
206038032Speter			else
206138032Speter				DefGid = gr->gr_gid;
206238032Speter		}
206338032Speter		break;
206438032Speter
206538032Speter	  case 'H':		/* help file */
206638032Speter		if (val[0] == '\0')
206764562Sgshapiro			HelpFile = "helpfile";
206838032Speter		else
206973188Sgshapiro		{
207038032Speter			HelpFile = newstr(val);
207173188Sgshapiro		}
207238032Speter		break;
207338032Speter
207438032Speter	  case 'h':		/* maximum hop count */
207538032Speter		MaxHopCount = atoi(val);
207638032Speter		break;
207738032Speter
207838032Speter	  case 'I':		/* use internet domain name server */
207938032Speter#if NAMED_BIND
208038032Speter		for (p = val; *p != 0; )
208138032Speter		{
208238032Speter			bool clearmode;
208338032Speter			char *q;
208438032Speter			struct resolverflags *rfp;
208538032Speter
208638032Speter			while (*p == ' ')
208738032Speter				p++;
208838032Speter			if (*p == '\0')
208938032Speter				break;
209038032Speter			clearmode = FALSE;
209138032Speter			if (*p == '-')
209238032Speter				clearmode = TRUE;
209338032Speter			else if (*p != '+')
209438032Speter				p--;
209538032Speter			p++;
209638032Speter			q = p;
209738032Speter			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
209838032Speter				p++;
209938032Speter			if (*p != '\0')
210038032Speter				*p++ = '\0';
210138032Speter			if (strcasecmp(q, "HasWildcardMX") == 0)
210238032Speter			{
210338032Speter				HasWildcardMX = !clearmode;
210438032Speter				continue;
210538032Speter			}
210673188Sgshapiro#if _FFR_WORKAROUND_BROKEN_NAMESERVERS
210773188Sgshapiro			if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
210873188Sgshapiro			{
210973188Sgshapiro				WorkAroundBrokenAAAA = !clearmode;
211073188Sgshapiro				continue;
211173188Sgshapiro			}
211273188Sgshapiro#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */
211338032Speter			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
211438032Speter			{
211538032Speter				if (strcasecmp(q, rfp->rf_name) == 0)
211638032Speter					break;
211738032Speter			}
211838032Speter			if (rfp->rf_name == NULL)
211938032Speter				syserr("readcf: I option value %s unrecognized", q);
212038032Speter			else if (clearmode)
212138032Speter				_res.options &= ~rfp->rf_bits;
212238032Speter			else
212338032Speter				_res.options |= rfp->rf_bits;
212438032Speter		}
212538032Speter		if (tTd(8, 2))
212664562Sgshapiro			dprintf("_res.options = %x, HasWildcardMX = %d\n",
212738032Speter				(u_int) _res.options, HasWildcardMX);
212864562Sgshapiro#else /* NAMED_BIND */
212938032Speter		usrerr("name server (I option) specified but BIND not compiled in");
213064562Sgshapiro#endif /* NAMED_BIND */
213138032Speter		break;
213238032Speter
213338032Speter	  case 'i':		/* ignore dot lines in message */
213438032Speter		IgnrDot = atobool(val);
213538032Speter		break;
213638032Speter
213738032Speter	  case 'j':		/* send errors in MIME (RFC 1341) format */
213838032Speter		SendMIMEErrors = atobool(val);
213938032Speter		break;
214038032Speter
214138032Speter	  case 'J':		/* .forward search path */
214238032Speter		ForwardPath = newstr(val);
214338032Speter		break;
214438032Speter
214538032Speter	  case 'k':		/* connection cache size */
214638032Speter		MaxMciCache = atoi(val);
214738032Speter		if (MaxMciCache < 0)
214838032Speter			MaxMciCache = 0;
214938032Speter		break;
215038032Speter
215138032Speter	  case 'K':		/* connection cache timeout */
215238032Speter		MciCacheTimeout = convtime(val, 'm');
215338032Speter		break;
215438032Speter
215538032Speter	  case 'l':		/* use Errors-To: header */
215638032Speter		UseErrorsTo = atobool(val);
215738032Speter		break;
215838032Speter
215938032Speter	  case 'L':		/* log level */
216038032Speter		if (safe || LogLevel < atoi(val))
216138032Speter			LogLevel = atoi(val);
216238032Speter		break;
216338032Speter
216438032Speter	  case 'M':		/* define macro */
216571345Sgshapiro		sticky = FALSE;
216638032Speter		mid = macid(val, &ep);
216771345Sgshapiro		if (mid == 0)
216871345Sgshapiro			break;
216938032Speter		p = newstr(ep);
217038032Speter		if (!safe)
217138032Speter			cleanstrcpy(p, p, MAXNAME);
217238032Speter		define(mid, p, CurEnv);
217338032Speter		break;
217438032Speter
217538032Speter	  case 'm':		/* send to me too */
217638032Speter		MeToo = atobool(val);
217738032Speter		break;
217838032Speter
217938032Speter	  case 'n':		/* validate RHS in newaliases */
218038032Speter		CheckAliases = atobool(val);
218138032Speter		break;
218238032Speter
218338032Speter	    /* 'N' available -- was "net name" */
218438032Speter
218538032Speter	  case 'O':		/* daemon options */
218638032Speter#if DAEMON
218764562Sgshapiro		if (!setdaemonoptions(val))
218864562Sgshapiro			syserr("too many daemons defined (%d max)", MAXDAEMONS);
218964562Sgshapiro#else /* DAEMON */
219038032Speter		syserr("DaemonPortOptions (O option) set but DAEMON not compiled in");
219164562Sgshapiro#endif /* DAEMON */
219238032Speter		break;
219338032Speter
219438032Speter	  case 'o':		/* assume old style headers */
219538032Speter		if (atobool(val))
219638032Speter			CurEnv->e_flags |= EF_OLDSTYLE;
219738032Speter		else
219838032Speter			CurEnv->e_flags &= ~EF_OLDSTYLE;
219938032Speter		break;
220038032Speter
220138032Speter	  case 'p':		/* select privacy level */
220238032Speter		p = val;
220338032Speter		for (;;)
220438032Speter		{
220538032Speter			register struct prival *pv;
220638032Speter			extern struct prival PrivacyValues[];
220738032Speter
220838032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
220938032Speter				p++;
221038032Speter			if (*p == '\0')
221138032Speter				break;
221238032Speter			val = p;
221338032Speter			while (isascii(*p) && isalnum(*p))
221438032Speter				p++;
221538032Speter			if (*p != '\0')
221638032Speter				*p++ = '\0';
221738032Speter
221838032Speter			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
221938032Speter			{
222038032Speter				if (strcasecmp(val, pv->pv_name) == 0)
222138032Speter					break;
222238032Speter			}
222338032Speter			if (pv->pv_name == NULL)
222438032Speter				syserr("readcf: Op line: %s unrecognized", val);
222571345Sgshapiro			else
222671345Sgshapiro				PrivacyFlags |= pv->pv_flag;
222738032Speter		}
222838032Speter		sticky = FALSE;
222938032Speter		break;
223038032Speter
223138032Speter	  case 'P':		/* postmaster copy address for returned mail */
223238032Speter		PostMasterCopy = newstr(val);
223338032Speter		break;
223438032Speter
223538032Speter	  case 'q':		/* slope of queue only function */
223638032Speter		QueueFactor = atoi(val);
223738032Speter		break;
223838032Speter
223938032Speter	  case 'Q':		/* queue directory */
224038032Speter		if (val[0] == '\0')
224166494Sgshapiro		{
224238032Speter			QueueDir = "mqueue";
224366494Sgshapiro		}
224438032Speter		else
224566494Sgshapiro		{
224638032Speter			QueueDir = newstr(val);
224766494Sgshapiro		}
224838032Speter		if (RealUid != 0 && !safe)
224938032Speter			Warn_Q_option = TRUE;
225038032Speter		break;
225138032Speter
225238032Speter	  case 'R':		/* don't prune routes */
225338032Speter		DontPruneRoutes = atobool(val);
225438032Speter		break;
225538032Speter
225638032Speter	  case 'r':		/* read timeout */
225738032Speter		if (subopt == NULL)
225864562Sgshapiro			inittimeouts(val, sticky);
225938032Speter		else
226064562Sgshapiro			settimeout(subopt, val, sticky);
226138032Speter		break;
226238032Speter
226338032Speter	  case 'S':		/* status file */
226438032Speter		if (val[0] == '\0')
226564562Sgshapiro			StatFile = "statistics";
226638032Speter		else
226773188Sgshapiro		{
226838032Speter			StatFile = newstr(val);
226973188Sgshapiro		}
227038032Speter		break;
227138032Speter
227238032Speter	  case 's':		/* be super safe, even if expensive */
227338032Speter		SuperSafe = atobool(val);
227438032Speter		break;
227538032Speter
227638032Speter	  case 'T':		/* queue timeout */
227738032Speter		p = strchr(val, '/');
227838032Speter		if (p != NULL)
227938032Speter		{
228038032Speter			*p++ = '\0';
228164562Sgshapiro			settimeout("queuewarn", p, sticky);
228238032Speter		}
228364562Sgshapiro		settimeout("queuereturn", val, sticky);
228438032Speter		break;
228538032Speter
228638032Speter	  case 't':		/* time zone name */
228738032Speter		TimeZoneSpec = newstr(val);
228838032Speter		break;
228938032Speter
229038032Speter	  case 'U':		/* location of user database */
229138032Speter		UdbSpec = newstr(val);
229238032Speter		break;
229338032Speter
229438032Speter	  case 'u':		/* set default uid */
229538032Speter		for (p = val; *p != '\0'; p++)
229638032Speter		{
229738032Speter			if (*p == '.' || *p == '/' || *p == ':')
229838032Speter			{
229938032Speter				*p++ = '\0';
230038032Speter				break;
230138032Speter			}
230238032Speter		}
230338032Speter		if (isascii(*val) && isdigit(*val))
230438032Speter		{
230538032Speter			DefUid = atoi(val);
230638032Speter			setdefuser();
230738032Speter		}
230838032Speter		else
230938032Speter		{
231038032Speter			register struct passwd *pw;
231138032Speter
231238032Speter			DefUid = -1;
231338032Speter			pw = sm_getpwnam(val);
231438032Speter			if (pw == NULL)
231571345Sgshapiro			{
231638032Speter				syserr("readcf: option u: unknown user %s", val);
231771345Sgshapiro				break;
231871345Sgshapiro			}
231938032Speter			else
232038032Speter			{
232138032Speter				DefUid = pw->pw_uid;
232238032Speter				DefGid = pw->pw_gid;
232338032Speter				DefUser = newstr(pw->pw_name);
232438032Speter			}
232538032Speter		}
232638032Speter
232738032Speter#ifdef UID_MAX
232838032Speter		if (DefUid > UID_MAX)
232938032Speter		{
233038032Speter			syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
233171345Sgshapiro				(long) DefUid, (long) UID_MAX);
233271345Sgshapiro			break;
233338032Speter		}
233464562Sgshapiro#endif /* UID_MAX */
233538032Speter
233638032Speter		/* handle the group if it is there */
233738032Speter		if (*p == '\0')
233838032Speter			break;
233938032Speter		val = p;
234038032Speter		goto g_opt;
234138032Speter
234238032Speter	  case 'V':		/* fallback MX host */
234338032Speter		if (val[0] != '\0')
234438032Speter			FallBackMX = newstr(val);
234538032Speter		break;
234638032Speter
234738032Speter	  case 'v':		/* run in verbose mode */
234838032Speter		Verbose = atobool(val) ? 1 : 0;
234938032Speter		break;
235038032Speter
235138032Speter	  case 'w':		/* if we are best MX, try host directly */
235238032Speter		TryNullMXList = atobool(val);
235338032Speter		break;
235438032Speter
235538032Speter	    /* 'W' available -- was wizard password */
235638032Speter
235738032Speter	  case 'x':		/* load avg at which to auto-queue msgs */
235838032Speter		QueueLA = atoi(val);
235938032Speter		break;
236038032Speter
236138032Speter	  case 'X':		/* load avg at which to auto-reject connections */
236238032Speter		RefuseLA = atoi(val);
236338032Speter		break;
236438032Speter
236538032Speter	  case 'y':		/* work recipient factor */
236638032Speter		WkRecipFact = atoi(val);
236738032Speter		break;
236838032Speter
236938032Speter	  case 'Y':		/* fork jobs during queue runs */
237038032Speter		ForkQueueRuns = atobool(val);
237138032Speter		break;
237238032Speter
237338032Speter	  case 'z':		/* work message class factor */
237438032Speter		WkClassFact = atoi(val);
237538032Speter		break;
237638032Speter
237738032Speter	  case 'Z':		/* work time factor */
237838032Speter		WkTimeFact = atoi(val);
237938032Speter		break;
238038032Speter
238164562Sgshapiro
238238032Speter	  case O_QUEUESORTORD:	/* queue sorting order */
238338032Speter		switch (*val)
238438032Speter		{
238538032Speter		  case 'h':	/* Host first */
238638032Speter		  case 'H':
238764562Sgshapiro			QueueSortOrder = QSO_BYHOST;
238838032Speter			break;
238938032Speter
239038032Speter		  case 'p':	/* Priority order */
239138032Speter		  case 'P':
239264562Sgshapiro			QueueSortOrder = QSO_BYPRIORITY;
239338032Speter			break;
239438032Speter
239538032Speter		  case 't':	/* Submission time */
239638032Speter		  case 'T':
239764562Sgshapiro			QueueSortOrder = QSO_BYTIME;
239838032Speter			break;
239938032Speter
240064562Sgshapiro		  case 'f':	/* File Name */
240164562Sgshapiro		  case 'F':
240264562Sgshapiro			QueueSortOrder = QSO_BYFILENAME;
240364562Sgshapiro			break;
240464562Sgshapiro
240538032Speter		  default:
240638032Speter			syserr("Invalid queue sort order \"%s\"", val);
240738032Speter		}
240838032Speter		break;
240938032Speter
241064562Sgshapiro#if _FFR_QUEUEDELAY
241164562Sgshapiro	  case O_QUEUEDELAY:	/* queue delay algorithm */
241264562Sgshapiro		switch (*val)
241364562Sgshapiro		{
241464562Sgshapiro		  case 'e':	/* exponential */
241564562Sgshapiro		  case 'E':
241664562Sgshapiro			QueueAlg = QD_EXP;
241764562Sgshapiro			QueueInitDelay = 10 MINUTES;
241864562Sgshapiro			QueueMaxDelay = 2 HOURS;
241964562Sgshapiro			p = strchr(val, '/');
242064562Sgshapiro			if (p != NULL)
242164562Sgshapiro			{
242264562Sgshapiro				char *q;
242364562Sgshapiro
242464562Sgshapiro				*p++ = '\0';
242564562Sgshapiro				q = strchr(p, '/');
242664562Sgshapiro				if (q != NULL)
242764562Sgshapiro					*q++ = '\0';
242864562Sgshapiro				QueueInitDelay = convtime(p, 's');
242964562Sgshapiro				if (q != NULL)
243064562Sgshapiro				{
243164562Sgshapiro					QueueMaxDelay = convtime(q, 's');
243264562Sgshapiro				}
243364562Sgshapiro			}
243464562Sgshapiro			break;
243564562Sgshapiro
243664562Sgshapiro		  case 'l':	/* linear */
243764562Sgshapiro		  case 'L':
243864562Sgshapiro			QueueAlg = QD_LINEAR;
243964562Sgshapiro			break;
244064562Sgshapiro
244164562Sgshapiro		  default:
244264562Sgshapiro			syserr("Invalid queue delay algorithm \"%s\"", val);
244364562Sgshapiro		}
244464562Sgshapiro		break;
244564562Sgshapiro#endif /* _FFR_QUEUEDELAY */
244664562Sgshapiro
244738032Speter	  case O_HOSTSFILE:	/* pathname of /etc/hosts file */
244838032Speter		HostsFile = newstr(val);
244938032Speter		break;
245038032Speter
245138032Speter	  case O_MQA:		/* minimum queue age between deliveries */
245238032Speter		MinQueueAge = convtime(val, 'm');
245338032Speter		break;
245438032Speter
245538032Speter	  case O_DEFCHARSET:	/* default character set for mimefying */
245638032Speter		DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
245738032Speter		break;
245838032Speter
245938032Speter	  case O_SSFILE:	/* service switch file */
246038032Speter		ServiceSwitchFile = newstr(val);
246138032Speter		break;
246238032Speter
246338032Speter	  case O_DIALDELAY:	/* delay for dial-on-demand operation */
246438032Speter		DialDelay = convtime(val, 's');
246538032Speter		break;
246638032Speter
246738032Speter	  case O_NORCPTACTION:	/* what to do if no recipient */
246838032Speter		if (strcasecmp(val, "none") == 0)
246938032Speter			NoRecipientAction = NRA_NO_ACTION;
247038032Speter		else if (strcasecmp(val, "add-to") == 0)
247138032Speter			NoRecipientAction = NRA_ADD_TO;
247238032Speter		else if (strcasecmp(val, "add-apparently-to") == 0)
247338032Speter			NoRecipientAction = NRA_ADD_APPARENTLY_TO;
247438032Speter		else if (strcasecmp(val, "add-bcc") == 0)
247538032Speter			NoRecipientAction = NRA_ADD_BCC;
247638032Speter		else if (strcasecmp(val, "add-to-undisclosed") == 0)
247738032Speter			NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
247838032Speter		else
247938032Speter			syserr("Invalid NoRecipientAction: %s", val);
248038032Speter		break;
248138032Speter
248238032Speter	  case O_SAFEFILEENV:	/* chroot() environ for writing to files */
248338032Speter		SafeFileEnv = newstr(val);
248438032Speter		break;
248538032Speter
248638032Speter	  case O_MAXMSGSIZE:	/* maximum message size */
248738032Speter		MaxMessageSize = atol(val);
248838032Speter		break;
248938032Speter
249038032Speter	  case O_COLONOKINADDR:	/* old style handling of colon addresses */
249138032Speter		ColonOkInAddr = atobool(val);
249238032Speter		break;
249338032Speter
249438032Speter	  case O_MAXQUEUERUN:	/* max # of jobs in a single queue run */
249538032Speter		MaxQueueRun = atol(val);
249638032Speter		break;
249738032Speter
249838032Speter	  case O_MAXCHILDREN:	/* max # of children of daemon */
249938032Speter		MaxChildren = atoi(val);
250038032Speter		break;
250138032Speter
250264562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
250364562Sgshapiro	  case O_MAXFORWARD:	/* max # of forward entries */
250464562Sgshapiro		MaxForwardEntries = atoi(val);
250564562Sgshapiro		break;
250664562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */
250764562Sgshapiro
250838032Speter	  case O_KEEPCNAMES:	/* don't expand CNAME records */
250938032Speter		DontExpandCnames = atobool(val);
251038032Speter		break;
251138032Speter
251238032Speter	  case O_MUSTQUOTE:	/* must quote these characters in phrases */
251364562Sgshapiro		(void) strlcpy(buf, "@,;:\\()[]", sizeof buf);
251438032Speter		if (strlen(val) < (SIZE_T) sizeof buf - 10)
251564562Sgshapiro			(void) strlcat(buf, val, sizeof buf);
251664562Sgshapiro		else
251764562Sgshapiro			printf("Warning: MustQuoteChars too long, ignored.\n");
251838032Speter		MustQuoteChars = newstr(buf);
251938032Speter		break;
252038032Speter
252138032Speter	  case O_SMTPGREETING:	/* SMTP greeting message (old $e macro) */
252238032Speter		SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
252338032Speter		break;
252438032Speter
252538032Speter	  case O_UNIXFROM:	/* UNIX From_ line (old $l macro) */
252638032Speter		UnixFromLine = newstr(munchstring(val, NULL, '\0'));
252738032Speter		break;
252838032Speter
252938032Speter	  case O_OPCHARS:	/* operator characters (old $o macro) */
253064562Sgshapiro		if (OperatorChars != NULL)
253164562Sgshapiro			printf("Warning: OperatorChars is being redefined.\n         It should only be set before ruleset definitions.\n");
253238032Speter		OperatorChars = newstr(munchstring(val, NULL, '\0'));
253338032Speter		break;
253438032Speter
253538032Speter	  case O_DONTINITGRPS:	/* don't call initgroups(3) */
253638032Speter		DontInitGroups = atobool(val);
253738032Speter		break;
253838032Speter
253938032Speter	  case O_SLFH:		/* make sure from fits on one line */
254038032Speter		SingleLineFromHeader = atobool(val);
254138032Speter		break;
254238032Speter
254338032Speter	  case O_ABH:		/* allow HELO commands with syntax errors */
254438032Speter		AllowBogusHELO = atobool(val);
254538032Speter		break;
254638032Speter
254738032Speter	  case O_CONNTHROT:	/* connection rate throttle */
254838032Speter		ConnRateThrottle = atoi(val);
254938032Speter		break;
255038032Speter
255138032Speter	  case O_UGW:		/* group writable files are unsafe */
255238032Speter		if (!atobool(val))
255364562Sgshapiro		{
255464562Sgshapiro			setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
255564562Sgshapiro				DontBlameSendmail);
255664562Sgshapiro			setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
255764562Sgshapiro				DontBlameSendmail);
255864562Sgshapiro		}
255938032Speter		break;
256038032Speter
256138032Speter	  case O_DBLBOUNCE:	/* address to which to send double bounces */
256238032Speter		if (val[0] != '\0')
256338032Speter			DoubleBounceAddr = newstr(val);
256438032Speter		else
256538032Speter			syserr("readcf: option DoubleBounceAddress: value required");
256638032Speter		break;
256738032Speter
256838032Speter	  case O_HSDIR:		/* persistent host status directory */
256938032Speter		if (val[0] != '\0')
257073188Sgshapiro		{
257138032Speter			HostStatDir = newstr(val);
257273188Sgshapiro		}
257338032Speter		break;
257438032Speter
257538032Speter	  case O_SINGTHREAD:	/* single thread deliveries (requires hsdir) */
257638032Speter		SingleThreadDelivery = atobool(val);
257738032Speter		break;
257838032Speter
257938032Speter	  case O_RUNASUSER:	/* run bulk of code as this user */
258038032Speter		for (p = val; *p != '\0'; p++)
258138032Speter		{
258238032Speter			if (*p == '.' || *p == '/' || *p == ':')
258338032Speter			{
258438032Speter				*p++ = '\0';
258538032Speter				break;
258638032Speter			}
258738032Speter		}
258838032Speter		if (isascii(*val) && isdigit(*val))
258938032Speter		{
259038032Speter			if (can_setuid)
259138032Speter				RunAsUid = atoi(val);
259238032Speter		}
259338032Speter		else
259438032Speter		{
259538032Speter			register struct passwd *pw;
259638032Speter
259738032Speter			pw = sm_getpwnam(val);
259838032Speter			if (pw == NULL)
259971345Sgshapiro			{
260038032Speter				syserr("readcf: option RunAsUser: unknown user %s", val);
260171345Sgshapiro				break;
260271345Sgshapiro			}
260338032Speter			else if (can_setuid)
260438032Speter			{
260538032Speter				if (*p == '\0')
260638032Speter					RunAsUserName = newstr(val);
260738032Speter				RunAsUid = pw->pw_uid;
260838032Speter				RunAsGid = pw->pw_gid;
260938032Speter			}
261038032Speter		}
261138032Speter#ifdef UID_MAX
261238032Speter		if (RunAsUid > UID_MAX)
261338032Speter		{
261438032Speter			syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
261571345Sgshapiro				(long) RunAsUid, (long) UID_MAX);
261671345Sgshapiro			break;
261738032Speter		}
261864562Sgshapiro#endif /* UID_MAX */
261938032Speter		if (*p != '\0')
262038032Speter		{
262138032Speter			if (isascii(*p) && isdigit(*p))
262238032Speter			{
262338032Speter				if (can_setuid)
262438032Speter					RunAsGid = atoi(p);
262538032Speter			}
262638032Speter			else
262738032Speter			{
262838032Speter				register struct group *gr;
262964562Sgshapiro
263038032Speter				gr = getgrnam(p);
263138032Speter				if (gr == NULL)
263238032Speter					syserr("readcf: option RunAsUser: unknown group %s",
263338032Speter						p);
263438032Speter				else if (can_setuid)
263538032Speter					RunAsGid = gr->gr_gid;
263638032Speter			}
263738032Speter		}
263838032Speter		if (tTd(47, 5))
263964562Sgshapiro			dprintf("readcf: RunAsUser = %d:%d\n",
264064562Sgshapiro				(int)RunAsUid, (int)RunAsGid);
264138032Speter		break;
264238032Speter
264338032Speter	  case O_DSN_RRT:
264438032Speter		RrtImpliesDsn = atobool(val);
264538032Speter		break;
264638032Speter
264738032Speter	  case O_PIDFILE:
264864562Sgshapiro		if (PidFile != NULL)
264977349Sgshapiro			sm_free(PidFile);
265038032Speter		PidFile = newstr(val);
265138032Speter		break;
265238032Speter
265338032Speter	case O_DONTBLAMESENDMAIL:
265438032Speter		p = val;
265538032Speter		for (;;)
265638032Speter		{
265738032Speter			register struct dbsval *dbs;
265838032Speter			extern struct dbsval DontBlameSendmailValues[];
265938032Speter
266038032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
266138032Speter				p++;
266238032Speter			if (*p == '\0')
266338032Speter				break;
266438032Speter			val = p;
266538032Speter			while (isascii(*p) && isalnum(*p))
266638032Speter				p++;
266738032Speter			if (*p != '\0')
266838032Speter				*p++ = '\0';
266938032Speter
267038032Speter			for (dbs = DontBlameSendmailValues;
267138032Speter			     dbs->dbs_name != NULL; dbs++)
267238032Speter			{
267338032Speter				if (strcasecmp(val, dbs->dbs_name) == 0)
267438032Speter					break;
267538032Speter			}
267638032Speter			if (dbs->dbs_name == NULL)
267738032Speter				syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
267838032Speter			else if (dbs->dbs_flag == DBS_SAFE)
267964562Sgshapiro				clrbitmap(DontBlameSendmail);
268038032Speter			else
268164562Sgshapiro				setbitn(dbs->dbs_flag, DontBlameSendmail);
268238032Speter		}
268338032Speter		sticky = FALSE;
268438032Speter		break;
268538032Speter
268638032Speter	  case O_DPI:
268738032Speter		DontProbeInterfaces = atobool(val);
268838032Speter		break;
268938032Speter
269038032Speter	  case O_MAXRCPT:
269138032Speter		MaxRcptPerMsg = atoi(val);
269238032Speter		break;
269338032Speter
269438032Speter	  case O_DEADLETTER:
269538032Speter		if (DeadLetterDrop != NULL)
269677349Sgshapiro			sm_free(DeadLetterDrop);
269738032Speter		DeadLetterDrop = newstr(val);
269838032Speter		break;
269938032Speter
270038032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
270138032Speter	  case O_DONTLOCK:
270238032Speter		DontLockReadFiles = atobool(val);
270338032Speter		break;
270464562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
270538032Speter
270638032Speter	  case O_MAXALIASRCSN:
270738032Speter		MaxAliasRecursion = atoi(val);
270838032Speter		break;
270938032Speter
271038032Speter	  case O_CNCTONLYTO:
271138032Speter		/* XXX should probably use gethostbyname */
271264562Sgshapiro#if NETINET || NETINET6
271364562Sgshapiro# if NETINET6
271464562Sgshapiro		if (inet_addr(val) == INADDR_NONE)
271564562Sgshapiro		{
271664562Sgshapiro			ConnectOnlyTo.sa.sa_family = AF_INET6;
271764562Sgshapiro			if (inet_pton(AF_INET6, val,
271864562Sgshapiro				      &ConnectOnlyTo.sin6.sin6_addr) != 1)
271964562Sgshapiro				syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
272064562Sgshapiro				       val);
272164562Sgshapiro		}
272264562Sgshapiro		else
272364562Sgshapiro# endif /* NETINET6 */
272464562Sgshapiro		{
272564562Sgshapiro			ConnectOnlyTo.sa.sa_family = AF_INET;
272664562Sgshapiro			ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
272764562Sgshapiro		}
272864562Sgshapiro#endif /* NETINET || NETINET6 */
272938032Speter		break;
273038032Speter
273142575Speter	  case O_TRUSTUSER:
273264562Sgshapiro#if HASFCHOWN
273338032Speter		if (isascii(*val) && isdigit(*val))
273442575Speter			TrustedUid = atoi(val);
273538032Speter		else
273638032Speter		{
273738032Speter			register struct passwd *pw;
273838032Speter
273942575Speter			TrustedUid = 0;
274038032Speter			pw = sm_getpwnam(val);
274138032Speter			if (pw == NULL)
274271345Sgshapiro			{
274342575Speter				syserr("readcf: option TrustedUser: unknown user %s", val);
274471345Sgshapiro				break;
274571345Sgshapiro			}
274638032Speter			else
274742575Speter				TrustedUid = pw->pw_uid;
274838032Speter		}
274938032Speter
275064562Sgshapiro# ifdef UID_MAX
275142575Speter		if (TrustedUid > UID_MAX)
275238032Speter		{
275342575Speter			syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
275471345Sgshapiro				(long) TrustedUid, (long) UID_MAX);
275542575Speter			TrustedUid = 0;
275638032Speter		}
275764562Sgshapiro# endif /* UID_MAX */
275864562Sgshapiro#else /* HASFCHOWN */
275964562Sgshapiro		syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()");
276064562Sgshapiro#endif /* HASFCHOWN */
276138032Speter		break;
276238032Speter
276342575Speter	  case O_MAXMIMEHDRLEN:
276442575Speter		p = strchr(val, '/');
276542575Speter		if (p != NULL)
276642575Speter			*p++ = '\0';
276742575Speter		MaxMimeHeaderLength = atoi(val);
276842575Speter		if (p != NULL && *p != '\0')
276942575Speter			MaxMimeFieldLength = atoi(p);
277042575Speter		else
277142575Speter			MaxMimeFieldLength = MaxMimeHeaderLength / 2;
277242575Speter
277342575Speter		if (MaxMimeHeaderLength < 0)
277442575Speter			MaxMimeHeaderLength = 0;
277542575Speter		else if (MaxMimeHeaderLength < 128)
277642575Speter			printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
277742575Speter
277842575Speter		if (MaxMimeFieldLength < 0)
277942575Speter			MaxMimeFieldLength = 0;
278042575Speter		else if (MaxMimeFieldLength < 40)
278142575Speter			printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
278242575Speter		break;
278342575Speter
278442575Speter	  case O_CONTROLSOCKET:
278542575Speter		if (ControlSocketName != NULL)
278677349Sgshapiro			sm_free(ControlSocketName);
278742575Speter		ControlSocketName = newstr(val);
278842575Speter		break;
278942575Speter
279043730Speter	  case O_MAXHDRSLEN:
279143730Speter		MaxHeadersLength = atoi(val);
279243148Speter
279343730Speter		if (MaxHeadersLength > 0 &&
279443730Speter		    MaxHeadersLength < (MAXHDRSLEN / 2))
279564562Sgshapiro			printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", (MAXHDRSLEN / 2));
279643148Speter		break;
279743148Speter
279864562Sgshapiro	  case O_PROCTITLEPREFIX:
279964562Sgshapiro		if (ProcTitlePrefix != NULL)
280077349Sgshapiro			sm_free(ProcTitlePrefix);
280164562Sgshapiro		ProcTitlePrefix = newstr(val);
280264562Sgshapiro		break;
280364562Sgshapiro
280464562Sgshapiro#if SASL
280564562Sgshapiro	  case O_SASLINFO:
280664562Sgshapiro#if _FFR_ALLOW_SASLINFO
280764562Sgshapiro		/*
280864562Sgshapiro		**  Allow users to select their own authinfo file.
280964562Sgshapiro		**  However, this is not a "perfect" solution.
281064562Sgshapiro		**  If mail is queued, the authentication info
281164562Sgshapiro		**  will not be used in subsequent delivery attempts.
281264562Sgshapiro		**  If we really want to support this, then it has
281364562Sgshapiro		**  to be stored in the queue file.
281464562Sgshapiro		*/
281564562Sgshapiro		if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
281664562Sgshapiro		    RunAsUid != RealUid)
281764562Sgshapiro		{
281864562Sgshapiro			errno = 0;
281964562Sgshapiro			syserr("Error: %s only allowed with -U\n",
282064562Sgshapiro				o->o_name == NULL ? "<unknown>" : o->o_name);
282164562Sgshapiro			ExitStat = EX_USAGE;
282264562Sgshapiro			break;
282364562Sgshapiro		}
282464562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */
282564562Sgshapiro		if (SASLInfo != NULL)
282677349Sgshapiro			sm_free(SASLInfo);
282764562Sgshapiro		SASLInfo = newstr(val);
282864562Sgshapiro		break;
282964562Sgshapiro
283064562Sgshapiro	  case O_SASLMECH:
283164562Sgshapiro		if (AuthMechanisms != NULL)
283277349Sgshapiro			sm_free(AuthMechanisms);
283364562Sgshapiro		if (*val != '\0')
283464562Sgshapiro			AuthMechanisms = newstr(val);
283564562Sgshapiro		else
283664562Sgshapiro			AuthMechanisms = NULL;
283764562Sgshapiro		break;
283864562Sgshapiro
283964562Sgshapiro	  case O_SASLOPTS:
284064562Sgshapiro		while (val != NULL && *val != '\0')
284164562Sgshapiro		{
284264562Sgshapiro			switch(*val)
284364562Sgshapiro			{
284464562Sgshapiro			  case 'A':
284564562Sgshapiro				SASLOpts |= SASL_AUTH_AUTH;
284664562Sgshapiro				break;
284764562Sgshapiro# if _FFR_SASL_OPTS
284864562Sgshapiro			  case 'a':
284964562Sgshapiro				SASLOpts |= SASL_SEC_NOACTIVE;
285064562Sgshapiro				break;
285164562Sgshapiro			  case 'c':
285264562Sgshapiro				SASLOpts |= SASL_SEC_PASS_CREDENTIALS;
285364562Sgshapiro				break;
285464562Sgshapiro			  case 'd':
285564562Sgshapiro				SASLOpts |= SASL_SEC_NODICTIONARY;
285664562Sgshapiro				break;
285764562Sgshapiro			  case 'f':
285864562Sgshapiro				SASLOpts |= SASL_SEC_FORWARD_SECRECY;
285964562Sgshapiro				break;
286064562Sgshapiro			  case 'p':
286164562Sgshapiro				SASLOpts |= SASL_SEC_NOPLAINTEXT;
286264562Sgshapiro				break;
286364562Sgshapiro			  case 'y':
286464562Sgshapiro				SASLOpts |= SASL_SEC_NOANONYMOUS;
286564562Sgshapiro				break;
286664562Sgshapiro# endif /* _FFR_SASL_OPTS */
286764562Sgshapiro			  default:
286864562Sgshapiro				printf("Warning: Option: %s unknown parameter '%c'\n",
286964562Sgshapiro					o->o_name == NULL ? "<unknown>"
287064562Sgshapiro							  : o->o_name,
287164562Sgshapiro					(isascii(*val) && isprint(*val)) ? *val
287264562Sgshapiro									 : '?');
287364562Sgshapiro				break;
287464562Sgshapiro			}
287564562Sgshapiro			++val;
287664562Sgshapiro			val = strpbrk(val, ", \t");
287764562Sgshapiro			if (val != NULL)
287864562Sgshapiro				++val;
287964562Sgshapiro		}
288064562Sgshapiro		break;
288164562Sgshapiro
288264562Sgshapiro#else /* SASL */
288364562Sgshapiro	  case O_SASLINFO:
288464562Sgshapiro	  case O_SASLMECH:
288564562Sgshapiro	  case O_SASLOPTS:
288664562Sgshapiro		printf("Warning: Option: %s requires SASL support (-DSASL)\n",
288764562Sgshapiro			o->o_name == NULL ? "<unknown>" : o->o_name);
288864562Sgshapiro		break;
288964562Sgshapiro#endif /* SASL */
289064562Sgshapiro
289164562Sgshapiro#if STARTTLS
289264562Sgshapiro	  case O_SRVCERTFILE:
289364562Sgshapiro		if (SrvCERTfile != NULL)
289477349Sgshapiro			sm_free(SrvCERTfile);
289564562Sgshapiro		SrvCERTfile = newstr(val);
289664562Sgshapiro		break;
289764562Sgshapiro
289864562Sgshapiro	  case O_SRVKEYFILE:
289964562Sgshapiro		if (Srvkeyfile != NULL)
290077349Sgshapiro			sm_free(Srvkeyfile);
290164562Sgshapiro		Srvkeyfile = newstr(val);
290264562Sgshapiro		break;
290364562Sgshapiro
290464562Sgshapiro	  case O_CLTCERTFILE:
290564562Sgshapiro		if (CltCERTfile != NULL)
290677349Sgshapiro			sm_free(CltCERTfile);
290764562Sgshapiro		CltCERTfile = newstr(val);
290864562Sgshapiro		break;
290964562Sgshapiro
291064562Sgshapiro	  case O_CLTKEYFILE:
291164562Sgshapiro		if (Cltkeyfile != NULL)
291277349Sgshapiro			sm_free(Cltkeyfile);
291364562Sgshapiro		Cltkeyfile = newstr(val);
291464562Sgshapiro		break;
291564562Sgshapiro
291664562Sgshapiro	  case O_CACERTFILE:
291764562Sgshapiro		if (CACERTfile != NULL)
291877349Sgshapiro			sm_free(CACERTfile);
291964562Sgshapiro		CACERTfile = newstr(val);
292064562Sgshapiro		break;
292164562Sgshapiro
292264562Sgshapiro	  case O_CACERTPATH:
292364562Sgshapiro		if (CACERTpath != NULL)
292477349Sgshapiro			sm_free(CACERTpath);
292564562Sgshapiro		CACERTpath = newstr(val);
292664562Sgshapiro		break;
292764562Sgshapiro
292864562Sgshapiro	  case O_DHPARAMS:
292964562Sgshapiro		if (DHParams != NULL)
293077349Sgshapiro			sm_free(DHParams);
293164562Sgshapiro		DHParams = newstr(val);
293264562Sgshapiro		break;
293364562Sgshapiro
293464562Sgshapiro#  if _FFR_TLS_1
293564562Sgshapiro	  case O_DHPARAMS5:
293664562Sgshapiro		if (DHParams5 != NULL)
293777349Sgshapiro			sm_free(DHParams5);
293864562Sgshapiro		DHParams5 = newstr(val);
293964562Sgshapiro		break;
294064562Sgshapiro
294164562Sgshapiro	  case O_CIPHERLIST:
294264562Sgshapiro		if (CipherList != NULL)
294377349Sgshapiro			sm_free(CipherList);
294464562Sgshapiro		CipherList = newstr(val);
294564562Sgshapiro		break;
294664562Sgshapiro#  endif /* _FFR_TLS_1 */
294764562Sgshapiro
294864562Sgshapiro	  case O_RANDFILE:
294964562Sgshapiro		if (RandFile != NULL)
295077349Sgshapiro			sm_free(RandFile);
295164562Sgshapiro		RandFile= newstr(val);
295264562Sgshapiro		break;
295364562Sgshapiro
295464562Sgshapiro# else /* STARTTLS */
295564562Sgshapiro	  case O_SRVCERTFILE:
295664562Sgshapiro	  case O_SRVKEYFILE:
295764562Sgshapiro	  case O_CLTCERTFILE:
295864562Sgshapiro	  case O_CLTKEYFILE:
295964562Sgshapiro	  case O_CACERTFILE:
296064562Sgshapiro	  case O_CACERTPATH:
296164562Sgshapiro	  case O_DHPARAMS:
296264562Sgshapiro#  if _FFR_TLS_1
296364562Sgshapiro	  case O_DHPARAMS5:
296464562Sgshapiro	  case O_CIPHERLIST:
296564562Sgshapiro#  endif /* _FFR_TLS_1 */
296664562Sgshapiro	  case O_RANDFILE:
296764562Sgshapiro		printf("Warning: Option: %s requires TLS support\n",
296864562Sgshapiro			o->o_name == NULL ? "<unknown>" : o->o_name);
296964562Sgshapiro		break;
297064562Sgshapiro
297164562Sgshapiro# endif /* STARTTLS */
297264562Sgshapiro
297364562Sgshapiro	  case O_CLIENTPORT:
297464562Sgshapiro#if DAEMON
297564562Sgshapiro		setclientoptions(val);
297664562Sgshapiro#else /* DAEMON */
297764562Sgshapiro		syserr("ClientPortOptions (O option) set but DAEMON not compiled in");
297864562Sgshapiro#endif /* DAEMON */
297964562Sgshapiro		break;
298064562Sgshapiro
298164562Sgshapiro	  case O_DF_BUFSIZE:
298264562Sgshapiro		DataFileBufferSize = atoi(val);
298364562Sgshapiro		break;
298464562Sgshapiro
298564562Sgshapiro	  case O_XF_BUFSIZE:
298664562Sgshapiro		XscriptFileBufferSize = atoi(val);
298764562Sgshapiro		break;
298864562Sgshapiro
298964562Sgshapiro	  case O_LDAPDEFAULTSPEC:
299064562Sgshapiro#ifdef LDAPMAP
299164562Sgshapiro		ldapmap_set_defaults(val);
299264562Sgshapiro#else /* LDAPMAP */
299364562Sgshapiro		printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
299464562Sgshapiro			o->o_name == NULL ? "<unknown>" : o->o_name);
299564562Sgshapiro#endif /* LDAPMAP */
299664562Sgshapiro		break;
299764562Sgshapiro
299864562Sgshapiro#if _FFR_MILTER
299964562Sgshapiro	  case O_INPUTMILTER:
300064562Sgshapiro		InputFilterList = newstr(val);
300164562Sgshapiro		break;
300264562Sgshapiro
300364562Sgshapiro	  case O_MILTER:
300464562Sgshapiro		milter_set_option(subopt, val, sticky);
300564562Sgshapiro		break;
300664562Sgshapiro#endif /* _FFR_MILTER */
300764562Sgshapiro
300864562Sgshapiro#if _FFR_QUEUE_FILE_MODE
300964562Sgshapiro	  case O_QUEUE_FILE_MODE:	/* queue file mode */
301064562Sgshapiro		QueueFileMode = atooct(val) & 0777;
301164562Sgshapiro		break;
301264562Sgshapiro#endif /* _FFR_QUEUE_FILE_MODE */
301364562Sgshapiro
301438032Speter	  default:
301538032Speter		if (tTd(37, 1))
301638032Speter		{
301738032Speter			if (isascii(opt) && isprint(opt))
301864562Sgshapiro				dprintf("Warning: option %c unknown\n", opt);
301938032Speter			else
302064562Sgshapiro				dprintf("Warning: option 0x%x unknown\n", opt);
302138032Speter		}
302238032Speter		break;
302338032Speter	}
302464562Sgshapiro
302564562Sgshapiro	/*
302664562Sgshapiro	**  Options with suboptions are responsible for taking care
302764562Sgshapiro	**  of sticky-ness (e.g., that a command line setting is kept
302864562Sgshapiro	**  when reading in the sendmail.cf file).  This has to be done
302964562Sgshapiro	**  when the suboptions are parsed since each suboption must be
303064562Sgshapiro	**  sticky, not the root option.
303164562Sgshapiro	*/
303264562Sgshapiro
303364562Sgshapiro	if (sticky && !bitset(OI_SUBOPT, o->o_flags))
303438032Speter		setbitn(opt, StickyOpt);
303538032Speter}
303638032Speter/*
303738032Speter**  SETCLASS -- set a string into a class
303838032Speter**
303938032Speter**	Parameters:
304038032Speter**		class -- the class to put the string in.
304138032Speter**		str -- the string to enter
304238032Speter**
304338032Speter**	Returns:
304438032Speter**		none.
304538032Speter**
304638032Speter**	Side Effects:
304738032Speter**		puts the word into the symbol table.
304838032Speter*/
304938032Speter
305038032Spetervoid
305138032Spetersetclass(class, str)
305238032Speter	int class;
305338032Speter	char *str;
305438032Speter{
305538032Speter	register STAB *s;
305638032Speter
305764562Sgshapiro	if ((*str & 0377) == MATCHCLASS)
305864562Sgshapiro	{
305964562Sgshapiro		int mid;
306064562Sgshapiro
306164562Sgshapiro		str++;
306264562Sgshapiro		mid = macid(str, NULL);
306371345Sgshapiro		if (mid == 0)
306464562Sgshapiro			return;
306564562Sgshapiro
306664562Sgshapiro		if (tTd(37, 8))
306764562Sgshapiro			dprintf("setclass(%s, $=%s)\n",
306864562Sgshapiro				macname(class), macname(mid));
306964562Sgshapiro		copy_class(mid, class);
307064562Sgshapiro	}
307164562Sgshapiro	else
307264562Sgshapiro	{
307364562Sgshapiro		if (tTd(37, 8))
307464562Sgshapiro			dprintf("setclass(%s, %s)\n", macname(class), str);
307564562Sgshapiro
307664562Sgshapiro		s = stab(str, ST_CLASS, ST_ENTER);
307771345Sgshapiro		setbitn(bitidx(class), s->s_class);
307864562Sgshapiro	}
307938032Speter}
308038032Speter/*
308138032Speter**  MAKEMAPENTRY -- create a map entry
308238032Speter**
308338032Speter**	Parameters:
308438032Speter**		line -- the config file line
308538032Speter**
308638032Speter**	Returns:
308738032Speter**		A pointer to the map that has been created.
308838032Speter**		NULL if there was a syntax error.
308938032Speter**
309038032Speter**	Side Effects:
309138032Speter**		Enters the map into the dictionary.
309238032Speter*/
309338032Speter
309438032SpeterMAP *
309538032Spetermakemapentry(line)
309638032Speter	char *line;
309738032Speter{
309838032Speter	register char *p;
309938032Speter	char *mapname;
310038032Speter	char *classname;
310138032Speter	register STAB *s;
310238032Speter	STAB *class;
310338032Speter
310438032Speter	for (p = line; isascii(*p) && isspace(*p); p++)
310538032Speter		continue;
310638032Speter	if (!(isascii(*p) && isalnum(*p)))
310738032Speter	{
310838032Speter		syserr("readcf: config K line: no map name");
310938032Speter		return NULL;
311038032Speter	}
311138032Speter
311238032Speter	mapname = p;
311338032Speter	while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
311438032Speter		continue;
311538032Speter	if (*p != '\0')
311638032Speter		*p++ = '\0';
311738032Speter	while (isascii(*p) && isspace(*p))
311838032Speter		p++;
311938032Speter	if (!(isascii(*p) && isalnum(*p)))
312038032Speter	{
312138032Speter		syserr("readcf: config K line, map %s: no map class", mapname);
312238032Speter		return NULL;
312338032Speter	}
312438032Speter	classname = p;
312538032Speter	while (isascii(*++p) && isalnum(*p))
312638032Speter		continue;
312738032Speter	if (*p != '\0')
312838032Speter		*p++ = '\0';
312938032Speter	while (isascii(*p) && isspace(*p))
313038032Speter		p++;
313138032Speter
313238032Speter	/* look up the class */
313338032Speter	class = stab(classname, ST_MAPCLASS, ST_FIND);
313438032Speter	if (class == NULL)
313538032Speter	{
313638032Speter		syserr("readcf: map %s: class %s not available", mapname, classname);
313738032Speter		return NULL;
313838032Speter	}
313938032Speter
314038032Speter	/* enter the map */
314138032Speter	s = stab(mapname, ST_MAP, ST_ENTER);
314238032Speter	s->s_map.map_class = &class->s_mapclass;
314338032Speter	s->s_map.map_mname = newstr(mapname);
314438032Speter
314538032Speter	if (class->s_mapclass.map_parse(&s->s_map, p))
314638032Speter		s->s_map.map_mflags |= MF_VALID;
314738032Speter
314838032Speter	if (tTd(37, 5))
314938032Speter	{
315064562Sgshapiro		dprintf("map %s, class %s, flags %lx, file %s,\n",
315138032Speter			s->s_map.map_mname, s->s_map.map_class->map_cname,
315238032Speter			s->s_map.map_mflags,
315338032Speter			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
315464562Sgshapiro		dprintf("\tapp %s, domain %s, rebuild %s\n",
315538032Speter			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
315638032Speter			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
315738032Speter			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
315838032Speter	}
315938032Speter
316038032Speter	return &s->s_map;
316138032Speter}
316238032Speter/*
316338032Speter**  STRTORWSET -- convert string to rewriting set number
316438032Speter**
316538032Speter**	Parameters:
316638032Speter**		p -- the pointer to the string to decode.
316738032Speter**		endp -- if set, store the trailing delimiter here.
316838032Speter**		stabmode -- ST_ENTER to create this entry, ST_FIND if
316938032Speter**			it must already exist.
317038032Speter**
317138032Speter**	Returns:
317238032Speter**		The appropriate ruleset number.
317338032Speter**		-1 if it is not valid (error already printed)
317438032Speter*/
317538032Speter
317638032Speterint
317738032Speterstrtorwset(p, endp, stabmode)
317838032Speter	char *p;
317938032Speter	char **endp;
318038032Speter	int stabmode;
318138032Speter{
318238032Speter	int ruleset;
318338032Speter	static int nextruleset = MAXRWSETS;
318438032Speter
318538032Speter	while (isascii(*p) && isspace(*p))
318638032Speter		p++;
318738032Speter	if (!isascii(*p))
318838032Speter	{
318938032Speter		syserr("invalid ruleset name: \"%.20s\"", p);
319038032Speter		return -1;
319138032Speter	}
319238032Speter	if (isdigit(*p))
319338032Speter	{
319438032Speter		ruleset = strtol(p, endp, 10);
319538032Speter		if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
319638032Speter		{
319738032Speter			syserr("bad ruleset %d (%d max)",
319838032Speter				ruleset, MAXRWSETS / 2);
319938032Speter			ruleset = -1;
320038032Speter		}
320138032Speter	}
320238032Speter	else
320338032Speter	{
320438032Speter		STAB *s;
320538032Speter		char delim;
320664562Sgshapiro		char *q = NULL;
320738032Speter
320838032Speter		q = p;
320938032Speter		while (*p != '\0' && isascii(*p) &&
321038032Speter		       (isalnum(*p) || *p == '_'))
321138032Speter			p++;
321238032Speter		if (q == p || !(isascii(*q) && isalpha(*q)))
321338032Speter		{
321438032Speter			/* no valid characters */
321538032Speter			syserr("invalid ruleset name: \"%.20s\"", q);
321638032Speter			return -1;
321738032Speter		}
321838032Speter		while (isascii(*p) && isspace(*p))
321938032Speter			*p++ = '\0';
322038032Speter		delim = *p;
322138032Speter		if (delim != '\0')
322238032Speter			*p = '\0';
322338032Speter		s = stab(q, ST_RULESET, stabmode);
322438032Speter		if (delim != '\0')
322538032Speter			*p = delim;
322638032Speter
322738032Speter		if (s == NULL)
322838032Speter			return -1;
322938032Speter
323038032Speter		if (stabmode == ST_ENTER && delim == '=')
323138032Speter		{
323238032Speter			while (isascii(*++p) && isspace(*p))
323338032Speter				continue;
323438032Speter			if (!(isascii(*p) && isdigit(*p)))
323538032Speter			{
323638032Speter				syserr("bad ruleset definition \"%s\" (number required after `=')", q);
323738032Speter				ruleset = -1;
323838032Speter			}
323938032Speter			else
324038032Speter			{
324138032Speter				ruleset = strtol(p, endp, 10);
324238032Speter				if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
324338032Speter				{
324438032Speter					syserr("bad ruleset number %d in \"%s\" (%d max)",
324538032Speter						ruleset, q, MAXRWSETS / 2);
324638032Speter					ruleset = -1;
324738032Speter				}
324838032Speter			}
324938032Speter		}
325038032Speter		else
325138032Speter		{
325238032Speter			if (endp != NULL)
325338032Speter				*endp = p;
325464562Sgshapiro			if (s->s_ruleset >= 0)
325538032Speter				ruleset = s->s_ruleset;
325638032Speter			else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
325738032Speter			{
325838032Speter				syserr("%s: too many named rulesets (%d max)",
325938032Speter					q, MAXRWSETS / 2);
326038032Speter				ruleset = -1;
326138032Speter			}
326238032Speter		}
326364562Sgshapiro		if (s->s_ruleset >= 0 &&
326464562Sgshapiro		    ruleset >= 0 &&
326564562Sgshapiro		    ruleset != s->s_ruleset)
326638032Speter		{
326738032Speter			syserr("%s: ruleset changed value (old %d, new %d)",
326838032Speter				q, s->s_ruleset, ruleset);
326938032Speter			ruleset = s->s_ruleset;
327038032Speter		}
327164562Sgshapiro		else if (ruleset >= 0)
327238032Speter		{
327338032Speter			s->s_ruleset = ruleset;
327438032Speter		}
327571345Sgshapiro		if (stabmode == ST_ENTER && ruleset >= 0)
327664562Sgshapiro		{
327764562Sgshapiro			char *h = NULL;
327864562Sgshapiro
327964562Sgshapiro			if (RuleSetNames[ruleset] != NULL)
328077349Sgshapiro				sm_free(RuleSetNames[ruleset]);
328164562Sgshapiro			if (delim != '\0' && (h = strchr(q, delim)) != NULL)
328264562Sgshapiro				*h = '\0';
328364562Sgshapiro			RuleSetNames[ruleset] = newstr(q);
328464562Sgshapiro			if (delim == '/' && h != NULL)
328564562Sgshapiro				*h = delim;	/* put back delim */
328664562Sgshapiro		}
328738032Speter	}
328838032Speter	return ruleset;
328938032Speter}
329038032Speter/*
329164562Sgshapiro**  SETTIMEOUT -- set an individual timeout
329264562Sgshapiro**
329364562Sgshapiro**	Parameters:
329464562Sgshapiro**		name -- the name of the timeout.
329564562Sgshapiro**		val -- the value of the timeout.
329664562Sgshapiro**		sticky -- if set, don't let other setoptions override
329764562Sgshapiro**			this value.
329864562Sgshapiro**
329964562Sgshapiro**	Returns:
330064562Sgshapiro**		none.
330164562Sgshapiro*/
330264562Sgshapiro
330364562Sgshapiro/* set if Timeout sub-option is stuck */
330464562Sgshapirostatic BITMAP256	StickyTimeoutOpt;
330564562Sgshapiro
330664562Sgshapirostatic struct timeoutinfo
330764562Sgshapiro{
330864562Sgshapiro	char	*to_name;	/* long name of timeout */
330964562Sgshapiro	u_char	to_code;	/* code for option */
331064562Sgshapiro} TimeOutTab[] =
331164562Sgshapiro{
331264562Sgshapiro#define TO_INITIAL			0x01
331364562Sgshapiro	{ "initial",			TO_INITIAL			},
331464562Sgshapiro#define TO_MAIL				0x02
331564562Sgshapiro	{ "mail",			TO_MAIL				},
331664562Sgshapiro#define TO_RCPT				0x03
331764562Sgshapiro	{ "rcpt",			TO_RCPT				},
331864562Sgshapiro#define TO_DATAINIT			0x04
331964562Sgshapiro	{ "datainit",			TO_DATAINIT			},
332064562Sgshapiro#define TO_DATABLOCK			0x05
332164562Sgshapiro	{ "datablock",			TO_DATABLOCK			},
332264562Sgshapiro#define TO_DATAFINAL			0x06
332364562Sgshapiro	{ "datafinal",			TO_DATAFINAL			},
332464562Sgshapiro#define TO_COMMAND			0x07
332564562Sgshapiro	{ "command",			TO_COMMAND			},
332664562Sgshapiro#define TO_RSET				0x08
332764562Sgshapiro	{ "rset",			TO_RSET				},
332864562Sgshapiro#define TO_HELO				0x09
332964562Sgshapiro	{ "helo",			TO_HELO				},
333064562Sgshapiro#define TO_QUIT				0x0A
333164562Sgshapiro	{ "quit",			TO_QUIT				},
333264562Sgshapiro#define TO_MISC				0x0B
333364562Sgshapiro	{ "misc",			TO_MISC				},
333464562Sgshapiro#define TO_IDENT			0x0C
333564562Sgshapiro	{ "ident",			TO_IDENT			},
333664562Sgshapiro#define TO_FILEOPEN			0x0D
333764562Sgshapiro	{ "fileopen",			TO_FILEOPEN			},
333864562Sgshapiro#define TO_CONNECT			0x0E
333964562Sgshapiro	{ "connect",			TO_CONNECT			},
334064562Sgshapiro#define TO_ICONNECT			0x0F
334164562Sgshapiro	{ "iconnect",			TO_ICONNECT			},
334264562Sgshapiro#define TO_QUEUEWARN			0x10
334364562Sgshapiro	{ "queuewarn",			TO_QUEUEWARN			},
334464562Sgshapiro	{ "queuewarn.*",		TO_QUEUEWARN			},
334564562Sgshapiro#define TO_QUEUEWARN_NORMAL		0x11
334664562Sgshapiro	{ "queuewarn.normal",		TO_QUEUEWARN_NORMAL		},
334764562Sgshapiro#define TO_QUEUEWARN_URGENT		0x12
334864562Sgshapiro	{ "queuewarn.urgent",		TO_QUEUEWARN_URGENT		},
334964562Sgshapiro#define TO_QUEUEWARN_NON_URGENT		0x13
335064562Sgshapiro	{ "queuewarn.non-urgent",	TO_QUEUEWARN_NON_URGENT		},
335164562Sgshapiro#define TO_QUEUERETURN			0x14
335264562Sgshapiro	{ "queuereturn",		TO_QUEUERETURN			},
335364562Sgshapiro	{ "queuereturn.*",		TO_QUEUERETURN			},
335464562Sgshapiro#define TO_QUEUERETURN_NORMAL		0x15
335564562Sgshapiro	{ "queuereturn.normal",		TO_QUEUERETURN_NORMAL		},
335664562Sgshapiro#define TO_QUEUERETURN_URGENT		0x16
335764562Sgshapiro	{ "queuereturn.urgent",		TO_QUEUERETURN_URGENT		},
335864562Sgshapiro#define TO_QUEUERETURN_NON_URGENT	0x17
335964562Sgshapiro	{ "queuereturn.non-urgent",	TO_QUEUERETURN_NON_URGENT	},
336064562Sgshapiro#define TO_HOSTSTATUS			0x18
336164562Sgshapiro	{ "hoststatus",			TO_HOSTSTATUS			},
336264562Sgshapiro#define TO_RESOLVER_RETRANS		0x19
336364562Sgshapiro	{ "resolver.retrans",		TO_RESOLVER_RETRANS		},
336464562Sgshapiro#define TO_RESOLVER_RETRANS_NORMAL	0x1A
336564562Sgshapiro	{ "resolver.retrans.normal",	TO_RESOLVER_RETRANS_NORMAL	},
336664562Sgshapiro#define TO_RESOLVER_RETRANS_FIRST	0x1B
336764562Sgshapiro	{ "resolver.retrans.first",	TO_RESOLVER_RETRANS_FIRST	},
336864562Sgshapiro#define TO_RESOLVER_RETRY		0x1C
336964562Sgshapiro	{ "resolver.retry",		TO_RESOLVER_RETRY		},
337064562Sgshapiro#define TO_RESOLVER_RETRY_NORMAL	0x1D
337164562Sgshapiro	{ "resolver.retry.normal",	TO_RESOLVER_RETRY_NORMAL	},
337264562Sgshapiro#define TO_RESOLVER_RETRY_FIRST		0x1E
337364562Sgshapiro	{ "resolver.retry.first",	TO_RESOLVER_RETRY_FIRST		},
337464562Sgshapiro#define TO_CONTROL			0x1F
337564562Sgshapiro	{ "control",			TO_CONTROL			},
337664562Sgshapiro	{ NULL,				0				},
337764562Sgshapiro};
337864562Sgshapiro
337964562Sgshapiro
338064562Sgshapirostatic void
338164562Sgshapirosettimeout(name, val, sticky)
338264562Sgshapiro	char *name;
338364562Sgshapiro	char *val;
338464562Sgshapiro	bool sticky;
338564562Sgshapiro{
338664562Sgshapiro	register struct timeoutinfo *to;
338764562Sgshapiro	int i;
338880785Sgshapiro	int addopts;
338964562Sgshapiro	time_t toval;
339064562Sgshapiro
339164562Sgshapiro	if (tTd(37, 2))
339264562Sgshapiro		dprintf("settimeout(%s = %s)", name, val);
339364562Sgshapiro
339464562Sgshapiro	for (to = TimeOutTab; to->to_name != NULL; to++)
339564562Sgshapiro	{
339664562Sgshapiro		if (strcasecmp(to->to_name, name) == 0)
339764562Sgshapiro			break;
339864562Sgshapiro	}
339964562Sgshapiro
340064562Sgshapiro	if (to->to_name == NULL)
340171345Sgshapiro	{
340271345Sgshapiro		errno = 0; /* avoid bogus error text */
340364562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
340471345Sgshapiro		return;
340571345Sgshapiro	}
340664562Sgshapiro
340764562Sgshapiro	/*
340864562Sgshapiro	**  See if this option is preset for us.
340964562Sgshapiro	*/
341064562Sgshapiro
341164562Sgshapiro	if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
341264562Sgshapiro	{
341364562Sgshapiro		if (tTd(37, 2))
341464562Sgshapiro			dprintf(" (ignored)\n");
341564562Sgshapiro		return;
341664562Sgshapiro	}
341764562Sgshapiro
341864562Sgshapiro	if (tTd(37, 2))
341964562Sgshapiro		dprintf("\n");
342064562Sgshapiro
342164562Sgshapiro	toval = convtime(val, 'm');
342280785Sgshapiro	addopts = 0;
342364562Sgshapiro
342464562Sgshapiro	switch (to->to_code)
342564562Sgshapiro	{
342664562Sgshapiro	  case TO_INITIAL:
342764562Sgshapiro		TimeOuts.to_initial = toval;
342864562Sgshapiro		break;
342964562Sgshapiro
343064562Sgshapiro	  case TO_MAIL:
343164562Sgshapiro		TimeOuts.to_mail = toval;
343264562Sgshapiro		break;
343364562Sgshapiro
343464562Sgshapiro	  case TO_RCPT:
343564562Sgshapiro		TimeOuts.to_rcpt = toval;
343664562Sgshapiro		break;
343764562Sgshapiro
343864562Sgshapiro	  case TO_DATAINIT:
343964562Sgshapiro		TimeOuts.to_datainit = toval;
344064562Sgshapiro		break;
344164562Sgshapiro
344264562Sgshapiro	  case TO_DATABLOCK:
344364562Sgshapiro		TimeOuts.to_datablock = toval;
344464562Sgshapiro		break;
344564562Sgshapiro
344664562Sgshapiro	  case TO_DATAFINAL:
344764562Sgshapiro		TimeOuts.to_datafinal = toval;
344864562Sgshapiro		break;
344964562Sgshapiro
345064562Sgshapiro	  case TO_COMMAND:
345164562Sgshapiro		TimeOuts.to_nextcommand = toval;
345264562Sgshapiro		break;
345364562Sgshapiro
345464562Sgshapiro	  case TO_RSET:
345564562Sgshapiro		TimeOuts.to_rset = toval;
345664562Sgshapiro		break;
345764562Sgshapiro
345864562Sgshapiro	  case TO_HELO:
345964562Sgshapiro		TimeOuts.to_helo = toval;
346064562Sgshapiro		break;
346164562Sgshapiro
346264562Sgshapiro	  case TO_QUIT:
346364562Sgshapiro		TimeOuts.to_quit = toval;
346464562Sgshapiro		break;
346564562Sgshapiro
346664562Sgshapiro	  case TO_MISC:
346764562Sgshapiro		TimeOuts.to_miscshort = toval;
346864562Sgshapiro		break;
346964562Sgshapiro
347064562Sgshapiro	  case TO_IDENT:
347164562Sgshapiro		TimeOuts.to_ident = toval;
347264562Sgshapiro		break;
347364562Sgshapiro
347464562Sgshapiro	  case TO_FILEOPEN:
347564562Sgshapiro		TimeOuts.to_fileopen = toval;
347664562Sgshapiro		break;
347764562Sgshapiro
347864562Sgshapiro	  case TO_CONNECT:
347964562Sgshapiro		TimeOuts.to_connect = toval;
348064562Sgshapiro		break;
348164562Sgshapiro
348264562Sgshapiro	  case TO_ICONNECT:
348364562Sgshapiro		TimeOuts.to_iconnect = toval;
348464562Sgshapiro		break;
348564562Sgshapiro
348664562Sgshapiro	  case TO_QUEUEWARN:
348764562Sgshapiro		toval = convtime(val, 'h');
348864562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
348964562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
349064562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
349180785Sgshapiro		addopts = 2;
349264562Sgshapiro		break;
349364562Sgshapiro
349464562Sgshapiro	  case TO_QUEUEWARN_NORMAL:
349564562Sgshapiro		toval = convtime(val, 'h');
349664562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
349764562Sgshapiro		break;
349864562Sgshapiro
349964562Sgshapiro	  case TO_QUEUEWARN_URGENT:
350064562Sgshapiro		toval = convtime(val, 'h');
350164562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
350264562Sgshapiro		break;
350364562Sgshapiro
350464562Sgshapiro	  case TO_QUEUEWARN_NON_URGENT:
350564562Sgshapiro		toval = convtime(val, 'h');
350664562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
350764562Sgshapiro		break;
350864562Sgshapiro
350964562Sgshapiro	  case TO_QUEUERETURN:
351064562Sgshapiro		toval = convtime(val, 'd');
351164562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
351264562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
351364562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
351480785Sgshapiro		addopts = 2;
351564562Sgshapiro		break;
351664562Sgshapiro
351764562Sgshapiro	  case TO_QUEUERETURN_NORMAL:
351864562Sgshapiro		toval = convtime(val, 'd');
351964562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
352064562Sgshapiro		break;
352164562Sgshapiro
352264562Sgshapiro	  case TO_QUEUERETURN_URGENT:
352364562Sgshapiro		toval = convtime(val, 'd');
352464562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
352564562Sgshapiro		break;
352664562Sgshapiro
352764562Sgshapiro	  case TO_QUEUERETURN_NON_URGENT:
352864562Sgshapiro		toval = convtime(val, 'd');
352964562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
353064562Sgshapiro		break;
353164562Sgshapiro
353264562Sgshapiro
353364562Sgshapiro	  case TO_HOSTSTATUS:
353464562Sgshapiro		MciInfoTimeout = toval;
353564562Sgshapiro		break;
353664562Sgshapiro
353764562Sgshapiro	  case TO_RESOLVER_RETRANS:
353864562Sgshapiro		toval = convtime(val, 's');
353964562Sgshapiro		TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
354064562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = toval;
354164562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
354280785Sgshapiro		addopts = 2;
354364562Sgshapiro		break;
354464562Sgshapiro
354564562Sgshapiro	  case TO_RESOLVER_RETRY:
354664562Sgshapiro		i = atoi(val);
354764562Sgshapiro		TimeOuts.res_retry[RES_TO_DEFAULT] = i;
354864562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = i;
354964562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = i;
355080785Sgshapiro		addopts = 2;
355164562Sgshapiro		break;
355264562Sgshapiro
355364562Sgshapiro	  case TO_RESOLVER_RETRANS_NORMAL:
355464562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
355564562Sgshapiro		break;
355664562Sgshapiro
355764562Sgshapiro	  case TO_RESOLVER_RETRY_NORMAL:
355864562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
355964562Sgshapiro		break;
356064562Sgshapiro
356164562Sgshapiro	  case TO_RESOLVER_RETRANS_FIRST:
356264562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
356364562Sgshapiro		break;
356464562Sgshapiro
356564562Sgshapiro	  case TO_RESOLVER_RETRY_FIRST:
356664562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
356764562Sgshapiro		break;
356864562Sgshapiro
356964562Sgshapiro	  case TO_CONTROL:
357064562Sgshapiro		TimeOuts.to_control = toval;
357164562Sgshapiro		break;
357264562Sgshapiro
357364562Sgshapiro	  default:
357464562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
357564562Sgshapiro		break;
357664562Sgshapiro	}
357764562Sgshapiro
357864562Sgshapiro	if (sticky)
357980785Sgshapiro	{
358080785Sgshapiro		for (i = 0; i <= addopts; i++)
358180785Sgshapiro			setbitn(to->to_code + i, StickyTimeoutOpt);
358280785Sgshapiro	}
358364562Sgshapiro}
358464562Sgshapiro/*
358538032Speter**  INITTIMEOUTS -- parse and set timeout values
358638032Speter**
358738032Speter**	Parameters:
358838032Speter**		val -- a pointer to the values.  If NULL, do initial
358938032Speter**			settings.
359064562Sgshapiro**		sticky -- if set, don't let other setoptions override
359164562Sgshapiro**			this suboption value.
359238032Speter**
359338032Speter**	Returns:
359438032Speter**		none.
359538032Speter**
359638032Speter**	Side Effects:
359738032Speter**		Initializes the TimeOuts structure
359838032Speter*/
359938032Speter
360038032Spetervoid
360164562Sgshapiroinittimeouts(val, sticky)
360238032Speter	register char *val;
360364562Sgshapiro	bool sticky;
360438032Speter{
360538032Speter	register char *p;
360638032Speter
360738032Speter	if (tTd(37, 2))
360864562Sgshapiro		dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
360938032Speter	if (val == NULL)
361038032Speter	{
361138032Speter		TimeOuts.to_connect = (time_t) 0 SECONDS;
361238032Speter		TimeOuts.to_initial = (time_t) 5 MINUTES;
361338032Speter		TimeOuts.to_helo = (time_t) 5 MINUTES;
361438032Speter		TimeOuts.to_mail = (time_t) 10 MINUTES;
361538032Speter		TimeOuts.to_rcpt = (time_t) 1 HOUR;
361638032Speter		TimeOuts.to_datainit = (time_t) 5 MINUTES;
361738032Speter		TimeOuts.to_datablock = (time_t) 1 HOUR;
361838032Speter		TimeOuts.to_datafinal = (time_t) 1 HOUR;
361938032Speter		TimeOuts.to_rset = (time_t) 5 MINUTES;
362038032Speter		TimeOuts.to_quit = (time_t) 2 MINUTES;
362138032Speter		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
362238032Speter		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
362338032Speter#if IDENTPROTO
362464562Sgshapiro		TimeOuts.to_ident = (time_t) 5 SECONDS;
362564562Sgshapiro#else /* IDENTPROTO */
362638032Speter		TimeOuts.to_ident = (time_t) 0 SECONDS;
362764562Sgshapiro#endif /* IDENTPROTO */
362838032Speter		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
362964562Sgshapiro		TimeOuts.to_control = (time_t) 2 MINUTES;
363038032Speter		if (tTd(37, 5))
363138032Speter		{
363264562Sgshapiro			dprintf("Timeouts:\n");
363364562Sgshapiro			dprintf("  connect = %ld\n", (long)TimeOuts.to_connect);
363464562Sgshapiro			dprintf("  initial = %ld\n", (long)TimeOuts.to_initial);
363564562Sgshapiro			dprintf("  helo = %ld\n", (long)TimeOuts.to_helo);
363664562Sgshapiro			dprintf("  mail = %ld\n", (long)TimeOuts.to_mail);
363764562Sgshapiro			dprintf("  rcpt = %ld\n", (long)TimeOuts.to_rcpt);
363864562Sgshapiro			dprintf("  datainit = %ld\n", (long)TimeOuts.to_datainit);
363964562Sgshapiro			dprintf("  datablock = %ld\n", (long)TimeOuts.to_datablock);
364064562Sgshapiro			dprintf("  datafinal = %ld\n", (long)TimeOuts.to_datafinal);
364164562Sgshapiro			dprintf("  rset = %ld\n", (long)TimeOuts.to_rset);
364264562Sgshapiro			dprintf("  quit = %ld\n", (long)TimeOuts.to_quit);
364364562Sgshapiro			dprintf("  nextcommand = %ld\n", (long)TimeOuts.to_nextcommand);
364464562Sgshapiro			dprintf("  miscshort = %ld\n", (long)TimeOuts.to_miscshort);
364564562Sgshapiro			dprintf("  ident = %ld\n", (long)TimeOuts.to_ident);
364664562Sgshapiro			dprintf("  fileopen = %ld\n", (long)TimeOuts.to_fileopen);
364764562Sgshapiro			dprintf("  control = %ld\n", (long)TimeOuts.to_control);
364838032Speter		}
364938032Speter		return;
365038032Speter	}
365138032Speter
365238032Speter	for (;; val = p)
365338032Speter	{
365438032Speter		while (isascii(*val) && isspace(*val))
365538032Speter			val++;
365638032Speter		if (*val == '\0')
365738032Speter			break;
365838032Speter		for (p = val; *p != '\0' && *p != ','; p++)
365938032Speter			continue;
366038032Speter		if (*p != '\0')
366138032Speter			*p++ = '\0';
366238032Speter
366338032Speter		if (isascii(*val) && isdigit(*val))
366438032Speter		{
366538032Speter			/* old syntax -- set everything */
366638032Speter			TimeOuts.to_mail = convtime(val, 'm');
366738032Speter			TimeOuts.to_rcpt = TimeOuts.to_mail;
366838032Speter			TimeOuts.to_datainit = TimeOuts.to_mail;
366938032Speter			TimeOuts.to_datablock = TimeOuts.to_mail;
367038032Speter			TimeOuts.to_datafinal = TimeOuts.to_mail;
367138032Speter			TimeOuts.to_nextcommand = TimeOuts.to_mail;
367264562Sgshapiro			if (sticky)
367364562Sgshapiro			{
367464562Sgshapiro				setbitn(TO_MAIL, StickyTimeoutOpt);
367564562Sgshapiro				setbitn(TO_RCPT, StickyTimeoutOpt);
367664562Sgshapiro				setbitn(TO_DATAINIT, StickyTimeoutOpt);
367764562Sgshapiro				setbitn(TO_DATABLOCK, StickyTimeoutOpt);
367864562Sgshapiro				setbitn(TO_DATAFINAL, StickyTimeoutOpt);
367964562Sgshapiro				setbitn(TO_COMMAND, StickyTimeoutOpt);
368064562Sgshapiro			}
368138032Speter			continue;
368238032Speter		}
368338032Speter		else
368438032Speter		{
368538032Speter			register char *q = strchr(val, ':');
368638032Speter
368738032Speter			if (q == NULL && (q = strchr(val, '=')) == NULL)
368838032Speter			{
368938032Speter				/* syntax error */
369038032Speter				continue;
369138032Speter			}
369238032Speter			*q++ = '\0';
369364562Sgshapiro			settimeout(val, q, sticky);
369438032Speter		}
369538032Speter	}
369638032Speter}
3697