xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 69748)
122709Sdist /*
268839Seric  * Copyright (c) 1983, 1995 Eric P. Allman
362530Sbostic  * Copyright (c) 1988, 1993
462530Sbostic  *	The Regents of the University of California.  All rights reserved.
533731Sbostic  *
642829Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822709Sdist 
922709Sdist #ifndef lint
10*69748Seric static char sccsid[] = "@(#)readcf.c	8.95 (Berkeley) 05/28/95";
1133731Sbostic #endif /* not lint */
1222709Sdist 
133313Seric # include "sendmail.h"
1464133Seric # include <grp.h>
1566334Seric #if NAMED_BIND
1657207Seric # include <resolv.h>
1757207Seric #endif
183308Seric 
193308Seric /*
203308Seric **  READCF -- read control file.
213308Seric **
223308Seric **	This routine reads the control file and builds the internal
233308Seric **	form.
243308Seric **
254432Seric **	The file is formatted as a sequence of lines, each taken
264432Seric **	atomically.  The first character of each line describes how
274432Seric **	the line is to be interpreted.  The lines are:
284432Seric **		Dxval		Define macro x to have value val.
294432Seric **		Cxword		Put word into class x.
304432Seric **		Fxfile [fmt]	Read file for lines to put into
314432Seric **				class x.  Use scanf string 'fmt'
324432Seric **				or "%s" if not present.  Fmt should
334432Seric **				only produce one string-valued result.
344432Seric **		Hname: value	Define header with field-name 'name'
354432Seric **				and value as specified; this will be
364432Seric **				macro expanded immediately before
374432Seric **				use.
384432Seric **		Sn		Use rewriting set n.
394432Seric **		Rlhs rhs	Rewrite addresses that match lhs to
404432Seric **				be rhs.
4124944Seric **		Mn arg=val...	Define mailer.  n is the internal name.
4224944Seric **				Args specify mailer parameters.
438252Seric **		Oxvalue		Set option x to value.
448252Seric **		Pname=value	Set precedence name to value.
4564718Seric **		Vversioncode[/vendorcode]
4664718Seric **				Version level/vendor name of
4764718Seric **				configuration syntax.
4853654Seric **		Kmapname mapclass arguments....
4953654Seric **				Define keyed lookup of a given class.
5053654Seric **				Arguments are class dependent.
5169476Seric **		Eenvar=value	Set the environment value to the given value.
524432Seric **
533308Seric **	Parameters:
543308Seric **		cfname -- control file name.
5554973Seric **		safe -- TRUE if this is the system config file;
5654973Seric **			FALSE otherwise.
5755012Seric **		e -- the main envelope.
583308Seric **
593308Seric **	Returns:
603308Seric **		none.
613308Seric **
623308Seric **	Side Effects:
633308Seric **		Builds several internal tables.
643308Seric */
653308Seric 
66*69748Seric void
6755012Seric readcf(cfname, safe, e)
683308Seric 	char *cfname;
6954973Seric 	bool safe;
7055012Seric 	register ENVELOPE *e;
713308Seric {
723308Seric 	FILE *cf;
738547Seric 	int ruleset = 0;
7468481Seric 	int nextruleset = MAXRWSETS;
758547Seric 	char *q;
769350Seric 	struct rewrite *rwp = NULL;
7757135Seric 	char *bp;
7864718Seric 	auto char *ep;
7957589Seric 	int nfuzzy;
8064133Seric 	char *file;
8164133Seric 	bool optional;
8268481Seric 	int mid;
833308Seric 	char buf[MAXLINE];
843308Seric 	register char *p;
853308Seric 	extern char **copyplist();
8652647Seric 	struct stat statb;
875909Seric 	char exbuf[MAXLINE];
8865066Seric 	char pvpbuf[MAXLINE + MAXATOM];
8968481Seric 	static char *null_list[1] = { NULL };
90*69748Seric 	extern char *munchstring __P((char *, char **));
91*69748Seric 	extern void fileclass __P((int, char *, char *, bool, bool));
92*69748Seric 	extern void toomany __P((int, int));
933308Seric 
9452647Seric 	FileName = cfname;
9552647Seric 	LineNumber = 0;
9652647Seric 
973308Seric 	cf = fopen(cfname, "r");
983308Seric 	if (cf == NULL)
993308Seric 	{
10052647Seric 		syserr("cannot open");
1013308Seric 		exit(EX_OSFILE);
1023308Seric 	}
1033308Seric 
10452647Seric 	if (fstat(fileno(cf), &statb) < 0)
10552647Seric 	{
10652647Seric 		syserr("cannot fstat");
10752647Seric 		exit(EX_OSFILE);
10852647Seric 	}
10952647Seric 
11052647Seric 	if (!S_ISREG(statb.st_mode))
11152647Seric 	{
11252647Seric 		syserr("not a plain file");
11352647Seric 		exit(EX_OSFILE);
11452647Seric 	}
11552647Seric 
11652647Seric 	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
11752647Seric 	{
11869686Seric 		if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
11953037Seric 			fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
12053037Seric 				FileName);
12153037Seric #ifdef LOG
12253037Seric 		if (LogLevel > 0)
12353037Seric 			syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
12453037Seric 				FileName);
12553037Seric #endif
12652647Seric 	}
12752647Seric 
12859254Seric #ifdef XLA
12959254Seric 	xla_zero();
13059254Seric #endif
13159254Seric 
13257135Seric 	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
1333308Seric 	{
13457135Seric 		if (bp[0] == '#')
13557135Seric 		{
13657135Seric 			if (bp != buf)
13757135Seric 				free(bp);
13852637Seric 			continue;
13957135Seric 		}
14052637Seric 
14168481Seric 		/* do macro expansion mappings */
14257135Seric 		for (p = bp; *p != '\0'; p++)
14316157Seric 		{
14457135Seric 			if (*p == '#' && p > bp && ConfigLevel >= 3)
14552647Seric 			{
14652647Seric 				/* this is an on-line comment */
14752647Seric 				register char *e;
14852647Seric 
14958050Seric 				switch (*--p & 0377)
15052647Seric 				{
15158050Seric 				  case MACROEXPAND:
15252647Seric 					/* it's from $# -- let it go through */
15352647Seric 					p++;
15452647Seric 					break;
15552647Seric 
15652647Seric 				  case '\\':
15752647Seric 					/* it's backslash escaped */
15852647Seric 					(void) strcpy(p, p + 1);
15952647Seric 					break;
16052647Seric 
16152647Seric 				  default:
16252647Seric 					/* delete preceeding white space */
16358050Seric 					while (isascii(*p) && isspace(*p) && p > bp)
16452647Seric 						p--;
16556795Seric 					if ((e = strchr(++p, '\n')) != NULL)
16652647Seric 						(void) strcpy(p, e);
16752647Seric 					else
16852647Seric 						p[0] = p[1] = '\0';
16952647Seric 					break;
17052647Seric 				}
17152647Seric 				continue;
17252647Seric 			}
17352647Seric 
17468481Seric 			if (*p != '$' || p[1] == '\0')
17516157Seric 				continue;
17616157Seric 
17716157Seric 			if (p[1] == '$')
17816157Seric 			{
17916157Seric 				/* actual dollar sign.... */
18023111Seric 				(void) strcpy(p, p + 1);
18116157Seric 				continue;
18216157Seric 			}
18316157Seric 
18416157Seric 			/* convert to macro expansion character */
18568481Seric 			*p++ = MACROEXPAND;
18668481Seric 
18768481Seric 			/* convert macro name to code */
18868481Seric 			*p = macid(p, &ep);
18968481Seric 			if (ep != p)
19068481Seric 				strcpy(p + 1, ep);
19116157Seric 		}
19216157Seric 
19316157Seric 		/* interpret this line */
19464718Seric 		errno = 0;
19557135Seric 		switch (bp[0])
1963308Seric 		{
1973308Seric 		  case '\0':
1983308Seric 		  case '#':		/* comment */
1993308Seric 			break;
2003308Seric 
2013308Seric 		  case 'R':		/* rewriting rule */
20257135Seric 			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
2033308Seric 				continue;
2043308Seric 
2053308Seric 			if (*p == '\0')
2065909Seric 			{
20765821Seric 				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
2085909Seric 				break;
2095909Seric 			}
2105909Seric 
2115909Seric 			/* allocate space for the rule header */
2125909Seric 			if (rwp == NULL)
2135909Seric 			{
2145909Seric 				RewriteRules[ruleset] = rwp =
2155909Seric 					(struct rewrite *) xalloc(sizeof *rwp);
2165909Seric 			}
2173308Seric 			else
2183308Seric 			{
2195909Seric 				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
2205909Seric 				rwp = rwp->r_next;
2215909Seric 			}
2225909Seric 			rwp->r_next = NULL;
2233308Seric 
2245909Seric 			/* expand and save the LHS */
2255909Seric 			*p = '\0';
22668529Seric 			expand(&bp[1], exbuf, sizeof exbuf, e);
22765066Seric 			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
22868711Seric 					     sizeof pvpbuf, NULL, NULL);
22957589Seric 			nfuzzy = 0;
2305909Seric 			if (rwp->r_lhs != NULL)
23157589Seric 			{
23257589Seric 				register char **ap;
23357589Seric 
2345909Seric 				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
23557589Seric 
23657589Seric 				/* count the number of fuzzy matches in LHS */
23757589Seric 				for (ap = rwp->r_lhs; *ap != NULL; ap++)
23857589Seric 				{
23958148Seric 					char *botch;
24058148Seric 
24158148Seric 					botch = NULL;
24258050Seric 					switch (**ap & 0377)
24357589Seric 					{
24457589Seric 					  case MATCHZANY:
24557589Seric 					  case MATCHANY:
24657589Seric 					  case MATCHONE:
24757589Seric 					  case MATCHCLASS:
24857589Seric 					  case MATCHNCLASS:
24957589Seric 						nfuzzy++;
25058148Seric 						break;
25158148Seric 
25258148Seric 					  case MATCHREPL:
25358148Seric 						botch = "$0-$9";
25458148Seric 						break;
25558148Seric 
25658148Seric 					  case CANONNET:
25758148Seric 						botch = "$#";
25858148Seric 						break;
25958148Seric 
26058148Seric 					  case CANONUSER:
26158148Seric 						botch = "$:";
26258148Seric 						break;
26358148Seric 
26458148Seric 					  case CALLSUBR:
26558148Seric 						botch = "$>";
26658148Seric 						break;
26758148Seric 
26858148Seric 					  case CONDIF:
26958148Seric 						botch = "$?";
27058148Seric 						break;
27158148Seric 
27258148Seric 					  case CONDELSE:
27358148Seric 						botch = "$|";
27458148Seric 						break;
27558148Seric 
27658148Seric 					  case CONDFI:
27758148Seric 						botch = "$.";
27858148Seric 						break;
27958148Seric 
28058148Seric 					  case HOSTBEGIN:
28158148Seric 						botch = "$[";
28258148Seric 						break;
28358148Seric 
28458148Seric 					  case HOSTEND:
28558148Seric 						botch = "$]";
28658148Seric 						break;
28758148Seric 
28858148Seric 					  case LOOKUPBEGIN:
28958148Seric 						botch = "$(";
29058148Seric 						break;
29158148Seric 
29258148Seric 					  case LOOKUPEND:
29358148Seric 						botch = "$)";
29458148Seric 						break;
29557589Seric 					}
29658148Seric 					if (botch != NULL)
29758148Seric 						syserr("Inappropriate use of %s on LHS",
29858148Seric 							botch);
29957589Seric 				}
30057589Seric 			}
30156678Seric 			else
30268481Seric 			{
30356678Seric 				syserr("R line: null LHS");
30468481Seric 				rwp->r_lhs = null_list;
30568481Seric 			}
3065909Seric 
3075909Seric 			/* expand and save the RHS */
3085909Seric 			while (*++p == '\t')
3095909Seric 				continue;
3107231Seric 			q = p;
3117231Seric 			while (*p != '\0' && *p != '\t')
3127231Seric 				p++;
3137231Seric 			*p = '\0';
31468529Seric 			expand(q, exbuf, sizeof exbuf, e);
31565066Seric 			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
31668711Seric 					     sizeof pvpbuf, NULL, NULL);
3175909Seric 			if (rwp->r_rhs != NULL)
31857589Seric 			{
31957589Seric 				register char **ap;
32057589Seric 
3215909Seric 				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
32257589Seric 
32357589Seric 				/* check no out-of-bounds replacements */
32457589Seric 				nfuzzy += '0';
32557589Seric 				for (ap = rwp->r_rhs; *ap != NULL; ap++)
32657589Seric 				{
32758148Seric 					char *botch;
32858148Seric 
32958148Seric 					botch = NULL;
33058148Seric 					switch (**ap & 0377)
33157589Seric 					{
33258148Seric 					  case MATCHREPL:
33358148Seric 						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
33458148Seric 						{
33558148Seric 							syserr("replacement $%c out of bounds",
33658148Seric 								(*ap)[1]);
33758148Seric 						}
33858148Seric 						break;
33958148Seric 
34058148Seric 					  case MATCHZANY:
34158148Seric 						botch = "$*";
34258148Seric 						break;
34358148Seric 
34458148Seric 					  case MATCHANY:
34558148Seric 						botch = "$+";
34658148Seric 						break;
34758148Seric 
34858148Seric 					  case MATCHONE:
34958148Seric 						botch = "$-";
35058148Seric 						break;
35158148Seric 
35258148Seric 					  case MATCHCLASS:
35358148Seric 						botch = "$=";
35458148Seric 						break;
35558148Seric 
35658148Seric 					  case MATCHNCLASS:
35758148Seric 						botch = "$~";
35858148Seric 						break;
35957589Seric 					}
36058148Seric 					if (botch != NULL)
36158148Seric 						syserr("Inappropriate use of %s on RHS",
36258148Seric 							botch);
36357589Seric 				}
36457589Seric 			}
36556678Seric 			else
36668481Seric 			{
36756678Seric 				syserr("R line: null RHS");
36868481Seric 				rwp->r_rhs = null_list;
36968481Seric 			}
3703308Seric 			break;
3713308Seric 
3724072Seric 		  case 'S':		/* select rewriting set */
37364440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
37464440Seric 				continue;
37568481Seric 			if (!isascii(*p))
37664440Seric 			{
37764440Seric 				syserr("invalid argument to S line: \"%.20s\"",
37864440Seric 					&bp[1]);
37964440Seric 				break;
38064440Seric 			}
38168481Seric 			if (isdigit(*p))
3828056Seric 			{
38368481Seric 				ruleset = atoi(p);
38468481Seric 				if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
38568481Seric 				{
38668481Seric 					syserr("bad ruleset %d (%d max)",
38768481Seric 						ruleset, MAXRWSETS / 2);
38868481Seric 					ruleset = 0;
38968481Seric 				}
3908056Seric 			}
39168481Seric 			else
39268481Seric 			{
39368481Seric 				STAB *s;
39468481Seric 				char delim;
39568481Seric 
39668481Seric 				q = p;
39768481Seric 				while (*p != '\0' && isascii(*p) &&
39868481Seric 				       (isalnum(*p) || strchr("-_$", *p) != NULL))
39968481Seric 					p++;
40068481Seric 				while (isascii(*p) && isspace(*p))
40168481Seric 					*p++ = '\0';
40268481Seric 				delim = *p;
40368481Seric 				if (delim != '\0')
40468481Seric 					*p++ = '\0';
40568481Seric 				s = stab(q, ST_RULESET, ST_ENTER);
40668481Seric 				if (s->s_ruleset != 0)
40768481Seric 					ruleset = s->s_ruleset;
40868481Seric 				else if (delim == '=')
40968481Seric 				{
41068481Seric 					ruleset = atoi(p);
41168481Seric 					if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
41268481Seric 					{
41368481Seric 						syserr("bad ruleset %s = %d (%d max)",
41468481Seric 							q, ruleset, MAXRWSETS / 2);
41568481Seric 						ruleset = 0;
41668481Seric 					}
41768481Seric 				}
41868481Seric 				else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
41968481Seric 				{
42068481Seric 					syserr("%s: too many named rulesets (%d max)",
42168481Seric 						q, MAXRWSETS / 2);
42268481Seric 					ruleset = 0;
42368481Seric 				}
42468481Seric 				s->s_ruleset = ruleset;
42568481Seric 			}
4264072Seric 			rwp = NULL;
4274072Seric 			break;
4284072Seric 
4293308Seric 		  case 'D':		/* macro definition */
43068481Seric 			mid = macid(&bp[1], &ep);
43168481Seric 			p = munchstring(ep, NULL);
43268481Seric 			define(mid, newstr(p), e);
4333308Seric 			break;
4343308Seric 
4353387Seric 		  case 'H':		/* required header line */
43668717Seric 			(void) chompheader(&bp[1], TRUE, NULL, e);
4373387Seric 			break;
4383387Seric 
4394061Seric 		  case 'C':		/* word class */
44068481Seric 		  case 'T':		/* trusted user (set class `t') */
44168481Seric 			if (bp[0] == 'C')
4424061Seric 			{
44368481Seric 				mid = macid(&bp[1], &ep);
44468529Seric 				expand(ep, exbuf, sizeof exbuf, e);
44568481Seric 				p = exbuf;
44668481Seric 			}
44768481Seric 			else
44868481Seric 			{
44968481Seric 				mid = 't';
45068481Seric 				p = &bp[1];
45168481Seric 			}
45268481Seric 			while (*p != '\0')
45368481Seric 			{
4544061Seric 				register char *wd;
4554061Seric 				char delim;
4564061Seric 
45758050Seric 				while (*p != '\0' && isascii(*p) && isspace(*p))
4584061Seric 					p++;
4594061Seric 				wd = p;
46058050Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4614061Seric 					p++;
4624061Seric 				delim = *p;
4634061Seric 				*p = '\0';
4644061Seric 				if (wd[0] != '\0')
46568481Seric 					setclass(mid, wd);
4664061Seric 				*p = delim;
4674061Seric 			}
4684061Seric 			break;
4694061Seric 
47059272Seric 		  case 'F':		/* word class from file */
47168481Seric 			mid = macid(&bp[1], &ep);
47268481Seric 			for (p = ep; isascii(*p) && isspace(*p); )
47364133Seric 				p++;
47464133Seric 			if (p[0] == '-' && p[1] == 'o')
47564133Seric 			{
47664133Seric 				optional = TRUE;
47764133Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
47864133Seric 					p++;
47964133Seric 				while (isascii(*p) && isspace(*p))
48068481Seric 					p++;
48164133Seric 			}
48264133Seric 			else
48364133Seric 				optional = FALSE;
48464133Seric 			file = p;
48564133Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
48664133Seric 				p++;
48759272Seric 			if (*p == '\0')
48859272Seric 				p = "%s";
48959272Seric 			else
49059272Seric 			{
49159272Seric 				*p = '\0';
49259272Seric 				while (isascii(*++p) && isspace(*p))
49359272Seric 					continue;
49459272Seric 			}
49564133Seric 			fileclass(bp[1], file, p, safe, optional);
49659272Seric 			break;
49759272Seric 
49859156Seric #ifdef XLA
49959156Seric 		  case 'L':		/* extended load average description */
50059156Seric 			xla_init(&bp[1]);
50159156Seric 			break;
50259156Seric #endif
50359156Seric 
5044096Seric 		  case 'M':		/* define mailer */
50557135Seric 			makemailer(&bp[1]);
5064096Seric 			break;
5074096Seric 
5088252Seric 		  case 'O':		/* set option */
50958734Seric 			setoption(bp[1], &bp[2], safe, FALSE, e);
5108252Seric 			break;
5118252Seric 
5128252Seric 		  case 'P':		/* set precedence */
5138252Seric 			if (NumPriorities >= MAXPRIORITIES)
5148252Seric 			{
5158547Seric 				toomany('P', MAXPRIORITIES);
5168252Seric 				break;
5178252Seric 			}
51857135Seric 			for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
5198252Seric 				continue;
5208252Seric 			if (*p == '\0')
5218252Seric 				goto badline;
5228252Seric 			*p = '\0';
52357135Seric 			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
5248252Seric 			Priorities[NumPriorities].pri_val = atoi(++p);
5258252Seric 			NumPriorities++;
5268252Seric 			break;
5278252Seric 
52852645Seric 		  case 'V':		/* configuration syntax version */
52964440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
53064440Seric 				continue;
53164440Seric 			if (!isascii(*p) || !isdigit(*p))
53264440Seric 			{
53364440Seric 				syserr("invalid argument to V line: \"%.20s\"",
53464440Seric 					&bp[1]);
53564440Seric 				break;
53664440Seric 			}
53764718Seric 			ConfigLevel = strtol(p, &ep, 10);
53868805Seric 
53968805Seric 			/*
54068805Seric 			**  Do heuristic tweaking for back compatibility.
54168805Seric 			*/
54268805Seric 
54364279Seric 			if (ConfigLevel >= 5)
54464279Seric 			{
54564279Seric 				/* level 5 configs have short name in $w */
54664279Seric 				p = macvalue('w', e);
54764279Seric 				if (p != NULL && (p = strchr(p, '.')) != NULL)
54864279Seric 					*p = '\0';
54964279Seric 			}
55068805Seric 			if (ConfigLevel >= 6)
55168805Seric 			{
55268805Seric 				ColonOkInAddr = FALSE;
55368805Seric 			}
55468805Seric 
55568805Seric 			/*
55668805Seric 			**  Look for vendor code.
55768805Seric 			*/
55868805Seric 
55964718Seric 			if (*ep++ == '/')
56064718Seric 			{
56164718Seric 				/* extract vendor code */
56264718Seric 				for (p = ep; isascii(*p) && isalpha(*p); )
56364718Seric 					p++;
56464718Seric 				*p = '\0';
56564718Seric 
56664718Seric 				if (!setvendor(ep))
56764718Seric 					syserr("invalid V line vendor code: \"%s\"",
56864718Seric 						ep);
56964718Seric 			}
57052645Seric 			break;
57152645Seric 
57253654Seric 		  case 'K':
57357135Seric 			makemapentry(&bp[1]);
57453654Seric 			break;
57553654Seric 
57669476Seric 		  case 'E':
57769476Seric 			p = strchr(bp, '=');
57869476Seric 			if (p != NULL)
57969476Seric 				*p++ = '\0';
58069476Seric 			setuserenv(&bp[1], p);
58169476Seric 			break;
58269476Seric 
5833308Seric 		  default:
5844061Seric 		  badline:
58557135Seric 			syserr("unknown control line \"%s\"", bp);
5863308Seric 		}
58757135Seric 		if (bp != buf)
58857135Seric 			free(bp);
5893308Seric 	}
59052637Seric 	if (ferror(cf))
59152637Seric 	{
59252647Seric 		syserr("I/O read error", cfname);
59352637Seric 		exit(EX_OSFILE);
59452637Seric 	}
59552637Seric 	fclose(cf);
5969381Seric 	FileName = NULL;
59756836Seric 
59868481Seric 	/* initialize host maps from local service tables */
59968481Seric 	inithostmaps();
60068481Seric 
60168481Seric 	/* determine if we need to do special name-server frotz */
60267905Seric 	{
60368481Seric 		int nmaps;
60468481Seric 		char *maptype[MAXMAPSTACK];
60568481Seric 		short mapreturn[MAXMAPACTIONS];
60668481Seric 
60768481Seric 		nmaps = switch_map_find("hosts", maptype, mapreturn);
60868481Seric 		UseNameServer = FALSE;
60968481Seric 		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
61068481Seric 		{
61168481Seric 			register int mapno;
61268481Seric 
61368481Seric 			for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
61468481Seric 			{
61568481Seric 				if (strcmp(maptype[mapno], "dns") == 0)
61668481Seric 					UseNameServer = TRUE;
61768481Seric 			}
61868481Seric 		}
61968481Seric 
62068481Seric #ifdef HESIOD
62168481Seric 		nmaps = switch_map_find("passwd", maptype, mapreturn);
62268481Seric 		UseHesiod = FALSE;
62368481Seric 		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
62468481Seric 		{
62568481Seric 			register int mapno;
62668481Seric 
62768481Seric 			for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
62868481Seric 			{
62968481Seric 				if (strcmp(maptype[mapno], "hesiod") == 0)
63068481Seric 					UseHesiod = TRUE;
63168481Seric 			}
63268481Seric 		}
63368204Seric #endif
63467905Seric 	}
6354096Seric }
6364096Seric /*
6378547Seric **  TOOMANY -- signal too many of some option
6388547Seric **
6398547Seric **	Parameters:
6408547Seric **		id -- the id of the error line
6418547Seric **		maxcnt -- the maximum possible values
6428547Seric **
6438547Seric **	Returns:
6448547Seric **		none.
6458547Seric **
6468547Seric **	Side Effects:
6478547Seric **		gives a syserr.
6488547Seric */
6498547Seric 
650*69748Seric void
6518547Seric toomany(id, maxcnt)
652*69748Seric 	int id;
6538547Seric 	int maxcnt;
6548547Seric {
6559381Seric 	syserr("too many %c lines, %d max", id, maxcnt);
6568547Seric }
6578547Seric /*
6584432Seric **  FILECLASS -- read members of a class from a file
6594432Seric **
6604432Seric **	Parameters:
6614432Seric **		class -- class to define.
6624432Seric **		filename -- name of file to read.
6634432Seric **		fmt -- scanf string to use for match.
66464133Seric **		safe -- if set, this is a safe read.
66564133Seric **		optional -- if set, it is not an error for the file to
66664133Seric **			not exist.
6674432Seric **
6684432Seric **	Returns:
6694432Seric **		none
6704432Seric **
6714432Seric **	Side Effects:
6724432Seric **
6734432Seric **		puts all lines in filename that match a scanf into
6744432Seric **			the named class.
6754432Seric */
6764432Seric 
677*69748Seric void
67864133Seric fileclass(class, filename, fmt, safe, optional)
6794432Seric 	int class;
6804432Seric 	char *filename;
6814432Seric 	char *fmt;
68254973Seric 	bool safe;
68364133Seric 	bool optional;
6844432Seric {
68525808Seric 	FILE *f;
68668513Seric 	int sff;
68769453Seric 	int pid;
68869453Seric 	register char *p;
6894432Seric 	char buf[MAXLINE];
6904432Seric 
69166101Seric 	if (tTd(37, 2))
69266101Seric 		printf("fileclass(%s, fmt=%s)\n", filename, fmt);
69366101Seric 
69466031Seric 	if (filename[0] == '|')
69566031Seric 	{
69669453Seric 		auto int fd;
69769453Seric 		int i;
69869453Seric 		char *argv[MAXPV + 1];
69969453Seric 
70069453Seric 		i = 0;
70169453Seric 		for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
70269453Seric 		{
70369453Seric 			if (i >= MAXPV)
70469453Seric 				break;
70569453Seric 			argv[i++] = p;
70669453Seric 		}
70769453Seric 		argv[i] = NULL;
70869453Seric 		pid = prog_open(argv, &fd, CurEnv);
70969453Seric 		if (pid < 0)
71069453Seric 			f = NULL;
71169453Seric 		else
71269453Seric 			f = fdopen(fd, "r");
71366031Seric 	}
71469453Seric 	else
71569453Seric 	{
71669453Seric 		pid = -1;
71769453Seric 		sff = SFF_REGONLY;
71869453Seric 		if (safe)
71969453Seric 			sff |= SFF_OPENASROOT;
72069453Seric 		f = safefopen(filename, O_RDONLY, 0, sff);
72169453Seric 	}
72268602Seric 	if (f == NULL)
72354973Seric 	{
72468602Seric 		if (!optional)
72568602Seric 			syserr("fileclass: cannot open %s", filename);
7264432Seric 		return;
7274432Seric 	}
7284432Seric 
7294432Seric 	while (fgets(buf, sizeof buf, f) != NULL)
7304432Seric 	{
73125808Seric 		register char *p;
73225808Seric # ifdef SCANF
7334432Seric 		char wordbuf[MAXNAME+1];
7344432Seric 
7354432Seric 		if (sscanf(buf, fmt, wordbuf) != 1)
7364432Seric 			continue;
73725808Seric 		p = wordbuf;
73856795Seric # else /* SCANF */
73925808Seric 		p = buf;
74056795Seric # endif /* SCANF */
74125808Seric 
74225808Seric 		/*
74325808Seric 		**  Break up the match into words.
74425808Seric 		*/
74525808Seric 
74625808Seric 		while (*p != '\0')
74725808Seric 		{
74825808Seric 			register char *q;
74925808Seric 
75025808Seric 			/* strip leading spaces */
75158050Seric 			while (isascii(*p) && isspace(*p))
75225808Seric 				p++;
75325808Seric 			if (*p == '\0')
75425808Seric 				break;
75525808Seric 
75625808Seric 			/* find the end of the word */
75725808Seric 			q = p;
75858050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
75925808Seric 				p++;
76025808Seric 			if (*p != '\0')
76125808Seric 				*p++ = '\0';
76225808Seric 
76325808Seric 			/* enter the word in the symbol table */
76466101Seric 			setclass(class, q);
76525808Seric 		}
7664432Seric 	}
7674432Seric 
76854973Seric 	(void) fclose(f);
76969453Seric 	if (pid > 0)
77069453Seric 		(void) waitfor(pid);
7714432Seric }
7724432Seric /*
7734096Seric **  MAKEMAILER -- define a new mailer.
7744096Seric **
7754096Seric **	Parameters:
77610327Seric **		line -- description of mailer.  This is in labeled
77710327Seric **			fields.  The fields are:
77868481Seric **			   A -- the argv for this mailer
77968481Seric **			   C -- the character set for MIME conversions
78068481Seric **			   D -- the directory to run in
78168481Seric **			   E -- the eol string
78268481Seric **			   F -- the flags associated with the mailer
78368481Seric **			   L -- the maximum line length
78468481Seric **			   M -- the maximum message size
78568816Seric **			   N -- the niceness at which to run
78668479Seric **			   P -- the path to the mailer
78768481Seric **			   R -- the recipient rewriting set
78868479Seric **			   S -- the sender rewriting set
78968481Seric **			   T -- the mailer type (for DSNs)
79068481Seric **			   U -- the uid to run as
79110327Seric **			The first word is the canonical name of the mailer.
7924096Seric **
7934096Seric **	Returns:
7944096Seric **		none.
7954096Seric **
7964096Seric **	Side Effects:
7974096Seric **		enters the mailer into the mailer table.
7984096Seric */
7993308Seric 
800*69748Seric void
80121066Seric makemailer(line)
8024096Seric 	char *line;
8034096Seric {
8044096Seric 	register char *p;
8058067Seric 	register struct mailer *m;
8068067Seric 	register STAB *s;
8078067Seric 	int i;
80810327Seric 	char fcode;
80958020Seric 	auto char *endp;
8104096Seric 	extern int NextMailer;
81110327Seric 	extern char **makeargv();
81210327Seric 	extern char *munchstring();
8134096Seric 
81410327Seric 	/* allocate a mailer and set up defaults */
81510327Seric 	m = (struct mailer *) xalloc(sizeof *m);
81610327Seric 	bzero((char *) m, sizeof *m);
81710327Seric 	m->m_eol = "\n";
81868481Seric 	m->m_uid = m->m_gid = 0;
81910327Seric 
82010327Seric 	/* collect the mailer name */
82158050Seric 	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
82210327Seric 		continue;
82310327Seric 	if (*p != '\0')
82410327Seric 		*p++ = '\0';
82510327Seric 	m->m_name = newstr(line);
82610327Seric 
82710327Seric 	/* now scan through and assign info from the fields */
82810327Seric 	while (*p != '\0')
82910327Seric 	{
83058333Seric 		auto char *delimptr;
83158333Seric 
83258050Seric 		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
83310327Seric 			p++;
83410327Seric 
83510327Seric 		/* p now points to field code */
83610327Seric 		fcode = *p;
83710327Seric 		while (*p != '\0' && *p != '=' && *p != ',')
83810327Seric 			p++;
83910327Seric 		if (*p++ != '=')
84010327Seric 		{
84152637Seric 			syserr("mailer %s: `=' expected", m->m_name);
84210327Seric 			return;
84310327Seric 		}
84458050Seric 		while (isascii(*p) && isspace(*p))
84510327Seric 			p++;
84610327Seric 
84710327Seric 		/* p now points to the field body */
84858333Seric 		p = munchstring(p, &delimptr);
84910327Seric 
85010327Seric 		/* install the field into the mailer struct */
85110327Seric 		switch (fcode)
85210327Seric 		{
85310327Seric 		  case 'P':		/* pathname */
85410327Seric 			m->m_mailer = newstr(p);
85510327Seric 			break;
85610327Seric 
85710327Seric 		  case 'F':		/* flags */
85810687Seric 			for (; *p != '\0'; p++)
85958050Seric 				if (!(isascii(*p) && isspace(*p)))
86052637Seric 					setbitn(*p, m->m_flags);
86110327Seric 			break;
86210327Seric 
86310327Seric 		  case 'S':		/* sender rewriting ruleset */
86410327Seric 		  case 'R':		/* recipient rewriting ruleset */
86558020Seric 			i = strtol(p, &endp, 10);
86610327Seric 			if (i < 0 || i >= MAXRWSETS)
86710327Seric 			{
86810327Seric 				syserr("invalid rewrite set, %d max", MAXRWSETS);
86910327Seric 				return;
87010327Seric 			}
87110327Seric 			if (fcode == 'S')
87258020Seric 				m->m_sh_rwset = m->m_se_rwset = i;
87310327Seric 			else
87458020Seric 				m->m_rh_rwset = m->m_re_rwset = i;
87558020Seric 
87658020Seric 			p = endp;
87759985Seric 			if (*p++ == '/')
87858020Seric 			{
87958020Seric 				i = strtol(p, NULL, 10);
88058020Seric 				if (i < 0 || i >= MAXRWSETS)
88158020Seric 				{
88258020Seric 					syserr("invalid rewrite set, %d max",
88358020Seric 						MAXRWSETS);
88458020Seric 					return;
88558020Seric 				}
88658020Seric 				if (fcode == 'S')
88758020Seric 					m->m_sh_rwset = i;
88858020Seric 				else
88958020Seric 					m->m_rh_rwset = i;
89058020Seric 			}
89110327Seric 			break;
89210327Seric 
89310327Seric 		  case 'E':		/* end of line string */
89410327Seric 			m->m_eol = newstr(p);
89510327Seric 			break;
89610327Seric 
89710327Seric 		  case 'A':		/* argument vector */
89810327Seric 			m->m_argv = makeargv(p);
89910327Seric 			break;
90010701Seric 
90110701Seric 		  case 'M':		/* maximum message size */
90210701Seric 			m->m_maxsize = atol(p);
90310701Seric 			break;
90452106Seric 
90552106Seric 		  case 'L':		/* maximum line length */
90652106Seric 			m->m_linelimit = atoi(p);
90752106Seric 			break;
90858935Seric 
90968816Seric 		  case 'N':		/* run niceness */
91068816Seric 			m->m_nice = atoi(p);
91168816Seric 			break;
91268816Seric 
91358935Seric 		  case 'D':		/* working directory */
91458935Seric 			m->m_execdir = newstr(p);
91558935Seric 			break;
91668481Seric 
91768481Seric 		  case 'C':		/* default charset */
91868481Seric 			m->m_defcharset = newstr(p);
91968481Seric 			break;
92068481Seric 
92169720Seric 		  case 'T':		/* MTA-Name/Address/Diagnostic types */
92268481Seric 			m->m_mtatype = newstr(p);
92368481Seric 			p = strchr(m->m_mtatype, '/');
92468481Seric 			if (p != NULL)
92568481Seric 			{
92668481Seric 				*p++ = '\0';
92768481Seric 				if (*p == '\0')
92868481Seric 					p = NULL;
92968481Seric 			}
93068481Seric 			if (p == NULL)
93168481Seric 				m->m_addrtype = m->m_mtatype;
93268481Seric 			else
93368481Seric 			{
93468481Seric 				m->m_addrtype = p;
93568481Seric 				p = strchr(p, '/');
93668481Seric 			}
93768481Seric 			if (p != NULL)
93868481Seric 			{
93968481Seric 				*p++ = '\0';
94068481Seric 				if (*p == '\0')
94168481Seric 					p = NULL;
94268481Seric 			}
94368481Seric 			if (p == NULL)
94468481Seric 				m->m_diagtype = m->m_mtatype;
94568481Seric 			else
94668481Seric 				m->m_diagtype = p;
94768481Seric 			break;
94868481Seric 
94968481Seric 		  case 'U':		/* user id */
95068481Seric 			if (isascii(*p) && !isdigit(*p))
95168481Seric 			{
95268481Seric 				char *q = p;
95368481Seric 				struct passwd *pw;
95468481Seric 
95568481Seric 				while (isascii(*p) && isalnum(*p))
95668481Seric 					p++;
95768481Seric 				while (isascii(*p) && isspace(*p))
95868481Seric 					*p++ = '\0';
95968481Seric 				if (*p != '\0')
96068481Seric 					*p++ = '\0';
96168693Seric 				pw = sm_getpwnam(q);
96268481Seric 				if (pw == NULL)
96368481Seric 					syserr("readcf: mailer U= flag: unknown user %s", q);
96468481Seric 				else
96568481Seric 				{
96668481Seric 					m->m_uid = pw->pw_uid;
96768481Seric 					m->m_gid = pw->pw_gid;
96868481Seric 				}
96968481Seric 			}
97068481Seric 			else
97168481Seric 			{
97268481Seric 				auto char *q;
97368481Seric 
97468481Seric 				m->m_uid = strtol(p, &q, 0);
97568481Seric 				p = q;
97668481Seric 			}
97768481Seric 			while (isascii(*p) && isspace(*p))
97868481Seric 				p++;
97968481Seric 			if (*p == '\0')
98068481Seric 				break;
98168481Seric 			if (isascii(*p) && !isdigit(*p))
98268481Seric 			{
98368481Seric 				char *q = p;
98468481Seric 				struct group *gr;
98568481Seric 
98668481Seric 				while (isascii(*p) && isalnum(*p))
98768481Seric 					p++;
98868481Seric 				*p++ = '\0';
98968481Seric 				gr = getgrnam(q);
99068481Seric 				if (gr == NULL)
99168481Seric 					syserr("readcf: mailer U= flag: unknown group %s", q);
99268481Seric 				else
99368481Seric 					m->m_gid = gr->gr_gid;
99468481Seric 			}
99568481Seric 			else
99668481Seric 			{
99768481Seric 				m->m_gid = strtol(p, NULL, 0);
99868481Seric 			}
99968481Seric 			break;
100010327Seric 		}
100110327Seric 
100258333Seric 		p = delimptr;
100310327Seric 	}
100410327Seric 
100558321Seric 	/* do some rationality checking */
100658321Seric 	if (m->m_argv == NULL)
100758321Seric 	{
100858321Seric 		syserr("M%s: A= argument required", m->m_name);
100958321Seric 		return;
101058321Seric 	}
101158321Seric 	if (m->m_mailer == NULL)
101258321Seric 	{
101358321Seric 		syserr("M%s: P= argument required", m->m_name);
101458321Seric 		return;
101558321Seric 	}
101658321Seric 
10174096Seric 	if (NextMailer >= MAXMAILERS)
10184096Seric 	{
10199381Seric 		syserr("too many mailers defined (%d max)", MAXMAILERS);
10204096Seric 		return;
10214096Seric 	}
102257402Seric 
102368481Seric 	/* do some heuristic cleanup for back compatibility */
102468481Seric 	if (bitnset(M_LIMITS, m->m_flags))
102568481Seric 	{
102668481Seric 		if (m->m_linelimit == 0)
102768481Seric 			m->m_linelimit = SMTPLINELIM;
102868481Seric 		if (ConfigLevel < 2)
102968481Seric 			setbitn(M_7BITS, m->m_flags);
103068481Seric 	}
103168481Seric 
103268481Seric 	if (ConfigLevel < 6 &&
103368481Seric 	    (strcmp(m->m_mailer, "[IPC]") == 0 ||
103468481Seric 	     strcmp(m->m_mailer, "[TCP]") == 0))
103568481Seric 	{
103668481Seric 		if (m->m_mtatype == NULL)
103768481Seric 			m->m_mtatype = "dns";
103868481Seric 		if (m->m_addrtype == NULL)
103968481Seric 			m->m_addrtype = "rfc822";
104068481Seric 		if (m->m_diagtype == NULL)
104168481Seric 			m->m_diagtype = "smtp";
104268481Seric 	}
104368481Seric 
104468481Seric 	/* enter the mailer into the symbol table */
104510327Seric 	s = stab(m->m_name, ST_MAILER, ST_ENTER);
104657402Seric 	if (s->s_mailer != NULL)
104757402Seric 	{
104857402Seric 		i = s->s_mailer->m_mno;
104957402Seric 		free(s->s_mailer);
105057402Seric 	}
105157402Seric 	else
105257402Seric 	{
105357402Seric 		i = NextMailer++;
105457402Seric 	}
105557402Seric 	Mailer[i] = s->s_mailer = m;
105657454Seric 	m->m_mno = i;
105710327Seric }
105810327Seric /*
105910327Seric **  MUNCHSTRING -- translate a string into internal form.
106010327Seric **
106110327Seric **	Parameters:
106210327Seric **		p -- the string to munch.
106358333Seric **		delimptr -- if non-NULL, set to the pointer of the
106458333Seric **			field delimiter character.
106510327Seric **
106610327Seric **	Returns:
106710327Seric **		the munched string.
106810327Seric */
10694096Seric 
107010327Seric char *
107158333Seric munchstring(p, delimptr)
107210327Seric 	register char *p;
107358333Seric 	char **delimptr;
107410327Seric {
107510327Seric 	register char *q;
107610327Seric 	bool backslash = FALSE;
107710327Seric 	bool quotemode = FALSE;
107810327Seric 	static char buf[MAXLINE];
10794096Seric 
108010327Seric 	for (q = buf; *p != '\0'; p++)
10814096Seric 	{
108210327Seric 		if (backslash)
108310327Seric 		{
108410327Seric 			/* everything is roughly literal */
108510357Seric 			backslash = FALSE;
108610327Seric 			switch (*p)
108710327Seric 			{
108810327Seric 			  case 'r':		/* carriage return */
108910327Seric 				*q++ = '\r';
109010327Seric 				continue;
109110327Seric 
109210327Seric 			  case 'n':		/* newline */
109310327Seric 				*q++ = '\n';
109410327Seric 				continue;
109510327Seric 
109610327Seric 			  case 'f':		/* form feed */
109710327Seric 				*q++ = '\f';
109810327Seric 				continue;
109910327Seric 
110010327Seric 			  case 'b':		/* backspace */
110110327Seric 				*q++ = '\b';
110210327Seric 				continue;
110310327Seric 			}
110410327Seric 			*q++ = *p;
110510327Seric 		}
110610327Seric 		else
110710327Seric 		{
110810327Seric 			if (*p == '\\')
110910327Seric 				backslash = TRUE;
111010327Seric 			else if (*p == '"')
111110327Seric 				quotemode = !quotemode;
111210327Seric 			else if (quotemode || *p != ',')
111310327Seric 				*q++ = *p;
111410327Seric 			else
111510327Seric 				break;
111610327Seric 		}
11174096Seric 	}
11184096Seric 
111958333Seric 	if (delimptr != NULL)
112058333Seric 		*delimptr = p;
112110327Seric 	*q++ = '\0';
112210327Seric 	return (buf);
112310327Seric }
112410327Seric /*
112510327Seric **  MAKEARGV -- break up a string into words
112610327Seric **
112710327Seric **	Parameters:
112810327Seric **		p -- the string to break up.
112910327Seric **
113010327Seric **	Returns:
113110327Seric **		a char **argv (dynamically allocated)
113210327Seric **
113310327Seric **	Side Effects:
113410327Seric **		munges p.
113510327Seric */
11364096Seric 
113710327Seric char **
113810327Seric makeargv(p)
113910327Seric 	register char *p;
114010327Seric {
114110327Seric 	char *q;
114210327Seric 	int i;
114310327Seric 	char **avp;
114410327Seric 	char *argv[MAXPV + 1];
114510327Seric 
114610327Seric 	/* take apart the words */
114710327Seric 	i = 0;
114810327Seric 	while (*p != '\0' && i < MAXPV)
11494096Seric 	{
115010327Seric 		q = p;
115158050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
115210327Seric 			p++;
115358050Seric 		while (isascii(*p) && isspace(*p))
115410327Seric 			*p++ = '\0';
115510327Seric 		argv[i++] = newstr(q);
11564096Seric 	}
115710327Seric 	argv[i++] = NULL;
11584096Seric 
115910327Seric 	/* now make a copy of the argv */
116010327Seric 	avp = (char **) xalloc(sizeof *avp * i);
116116893Seric 	bcopy((char *) argv, (char *) avp, sizeof *avp * i);
116210327Seric 
116310327Seric 	return (avp);
11643308Seric }
11653308Seric /*
11663308Seric **  PRINTRULES -- print rewrite rules (for debugging)
11673308Seric **
11683308Seric **	Parameters:
11693308Seric **		none.
11703308Seric **
11713308Seric **	Returns:
11723308Seric **		none.
11733308Seric **
11743308Seric **	Side Effects:
11753308Seric **		prints rewrite rules.
11763308Seric */
11773308Seric 
1178*69748Seric void
11793308Seric printrules()
11803308Seric {
11813308Seric 	register struct rewrite *rwp;
11824072Seric 	register int ruleset;
11833308Seric 
11844072Seric 	for (ruleset = 0; ruleset < 10; ruleset++)
11853308Seric 	{
11864072Seric 		if (RewriteRules[ruleset] == NULL)
11874072Seric 			continue;
11888067Seric 		printf("\n----Rule Set %d:", ruleset);
11893308Seric 
11904072Seric 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
11913308Seric 		{
11928067Seric 			printf("\nLHS:");
11938067Seric 			printav(rwp->r_lhs);
11948067Seric 			printf("RHS:");
11958067Seric 			printav(rwp->r_rhs);
11963308Seric 		}
11973308Seric 	}
11983308Seric }
119968481Seric /*
120068481Seric **  PRINTMAILER -- print mailer structure (for debugging)
120168481Seric **
120268481Seric **	Parameters:
120368481Seric **		m -- the mailer to print
120468481Seric **
120568481Seric **	Returns:
120668481Seric **		none.
120768481Seric */
12084319Seric 
1209*69748Seric void
121068481Seric printmailer(m)
121168481Seric 	register MAILER *m;
121268481Seric {
121368481Seric 	int j;
121468481Seric 
121568481Seric 	printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=",
121668481Seric 		m->m_mno, m->m_name,
121768481Seric 		m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
121868481Seric 		m->m_re_rwset, m->m_rh_rwset, m->m_maxsize,
121968481Seric 		m->m_uid, m->m_gid);
122068481Seric 	for (j = '\0'; j <= '\177'; j++)
122168481Seric 		if (bitnset(j, m->m_flags))
122268481Seric 			(void) putchar(j);
122368481Seric 	printf(" L=%d E=", m->m_linelimit);
122468481Seric 	xputs(m->m_eol);
122568481Seric 	if (m->m_defcharset != NULL)
122668481Seric 		printf(" C=%s", m->m_defcharset);
122768481Seric 	printf(" T=%s/%s/%s",
122868481Seric 		m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
122968481Seric 		m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
123068481Seric 		m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
123168481Seric 	if (m->m_argv != NULL)
123268481Seric 	{
123368481Seric 		char **a = m->m_argv;
123468481Seric 
123568481Seric 		printf(" A=");
123668481Seric 		while (*a != NULL)
123768481Seric 		{
123868481Seric 			if (a != m->m_argv)
123968481Seric 				printf(" ");
124068481Seric 			xputs(*a++);
124168481Seric 		}
124268481Seric 	}
124368481Seric 	printf("\n");
124468481Seric }
12454096Seric /*
12468256Seric **  SETOPTION -- set global processing option
12478256Seric **
12488256Seric **	Parameters:
12498256Seric **		opt -- option name.
12508256Seric **		val -- option value (as a text string).
125121755Seric **		safe -- set if this came from a configuration file.
125221755Seric **			Some options (if set from the command line) will
125321755Seric **			reset the user id to avoid security problems.
12548269Seric **		sticky -- if set, don't let other setoptions override
12558269Seric **			this value.
125658734Seric **		e -- the main envelope.
12578256Seric **
12588256Seric **	Returns:
12598256Seric **		none.
12608256Seric **
12618256Seric **	Side Effects:
12628256Seric **		Sets options as implied by the arguments.
12638256Seric */
12648256Seric 
126510687Seric static BITMAP	StickyOpt;		/* set if option is stuck */
1266*69748Seric extern void	settimeout __P((char *, char *));
12678269Seric 
126857207Seric 
126966334Seric #if NAMED_BIND
127057207Seric 
127157207Seric struct resolverflags
127257207Seric {
127357207Seric 	char	*rf_name;	/* name of the flag */
127457207Seric 	long	rf_bits;	/* bits to set/clear */
127557207Seric } ResolverFlags[] =
127657207Seric {
127757207Seric 	"debug",	RES_DEBUG,
127857207Seric 	"aaonly",	RES_AAONLY,
127957207Seric 	"usevc",	RES_USEVC,
128057207Seric 	"primary",	RES_PRIMARY,
128157207Seric 	"igntc",	RES_IGNTC,
128257207Seric 	"recurse",	RES_RECURSE,
128357207Seric 	"defnames",	RES_DEFNAMES,
128457207Seric 	"stayopen",	RES_STAYOPEN,
128557207Seric 	"dnsrch",	RES_DNSRCH,
128665583Seric 	"true",		0,		/* to avoid error on old syntax */
128757207Seric 	NULL,		0
128857207Seric };
128957207Seric 
129057207Seric #endif
129157207Seric 
129268481Seric struct optioninfo
129368481Seric {
129468481Seric 	char	*o_name;	/* long name of option */
129568481Seric 	u_char	o_code;		/* short name of option */
129668481Seric 	bool	o_safe;		/* safe for random people to use */
129768481Seric } OptionTab[] =
129868481Seric {
129968481Seric 	"SevenBitInput",	'7',		TRUE,
130069480Seric #if MIME8TO7
130168481Seric 	"EightBitMode",		'8',		TRUE,
130269480Seric #endif
130368481Seric 	"AliasFile",		'A',		FALSE,
130468481Seric 	"AliasWait",		'a',		FALSE,
130568481Seric 	"BlankSub",		'B',		FALSE,
130668481Seric 	"MinFreeBlocks",	'b',		TRUE,
130768481Seric 	"CheckpointInterval",	'C',		TRUE,
130868481Seric 	"HoldExpensive",	'c',		FALSE,
130968481Seric 	"AutoRebuildAliases",	'D',		FALSE,
131068481Seric 	"DeliveryMode",		'd',		TRUE,
131168481Seric 	"ErrorHeader",		'E',		FALSE,
131268481Seric 	"ErrorMode",		'e',		TRUE,
131368481Seric 	"TempFileMode",		'F',		FALSE,
131468481Seric 	"SaveFromLine",		'f',		FALSE,
131568481Seric 	"MatchGECOS",		'G',		FALSE,
131668481Seric 	"HelpFile",		'H',		FALSE,
131768481Seric 	"MaxHopCount",		'h',		FALSE,
131868569Seric 	"ResolverOptions",	'I',		FALSE,
131968481Seric 	"IgnoreDots",		'i',		TRUE,
132068481Seric 	"ForwardPath",		'J',		FALSE,
132168481Seric 	"SendMimeErrors",	'j',		TRUE,
132268481Seric 	"ConnectionCacheSize",	'k',		FALSE,
132368481Seric 	"ConnectionCacheTimeout", 'K',		FALSE,
132468481Seric 	"UseErrorsTo",		'l',		FALSE,
132568481Seric 	"LogLevel",		'L',		FALSE,
132668481Seric 	"MeToo",		'm',		TRUE,
132768481Seric 	"CheckAliases",		'n',		FALSE,
132868481Seric 	"OldStyleHeaders",	'o',		TRUE,
132968481Seric 	"DaemonPortOptions",	'O',		FALSE,
133068481Seric 	"PrivacyOptions",	'p',		TRUE,
133168481Seric 	"PostmasterCopy",	'P',		FALSE,
133268481Seric 	"QueueFactor",		'q',		FALSE,
133368481Seric 	"QueueDirectory",	'Q',		FALSE,
133468481Seric 	"DontPruneRoutes",	'R',		FALSE,
133568481Seric 	"Timeout",		'r',		TRUE,
133668481Seric 	"StatusFile",		'S',		FALSE,
133768481Seric 	"SuperSafe",		's',		TRUE,
133868481Seric 	"QueueTimeout",		'T',		FALSE,
133968481Seric 	"TimeZoneSpec",		't',		FALSE,
134068481Seric 	"UserDatabaseSpec",	'U',		FALSE,
134168481Seric 	"DefaultUser",		'u',		FALSE,
134268481Seric 	"FallbackMXhost",	'V',		FALSE,
134368481Seric 	"Verbose",		'v',		TRUE,
134468481Seric 	"TryNullMXList",	'w',		TRUE,
134568481Seric 	"QueueLA",		'x',		FALSE,
134668481Seric 	"RefuseLA",		'X',		FALSE,
134768481Seric 	"RecipientFactor",	'y',		FALSE,
134868569Seric 	"ForkEachJob",		'Y',		FALSE,
134968481Seric 	"ClassFactor",		'z',		FALSE,
135068569Seric 	"RetryFactor",		'Z',		FALSE,
135168481Seric #define O_QUEUESORTORD	0x81
135268481Seric 	"QueueSortOrder",	O_QUEUESORTORD,	TRUE,
135369401Seric #define O_HOSTSFILE	0x82
135469401Seric 	"HostsFile",		O_HOSTSFILE,	FALSE,
135568481Seric #define O_MQA		0x83
135668481Seric 	"MinQueueAge",		O_MQA,		TRUE,
135768481Seric #define O_MHSA		0x84
135868481Seric /*
135968481Seric 	"MaxHostStatAge",	O_MHSA,		TRUE,
136068481Seric */
136168481Seric #define O_DEFCHARSET	0x85
136268481Seric 	"DefaultCharSet",	O_DEFCHARSET,	TRUE,
136368481Seric #define O_SSFILE	0x86
136468481Seric 	"ServiceSwitchFile",	O_SSFILE,	FALSE,
136568481Seric #define O_DIALDELAY	0x87
136668481Seric 	"DialDelay",		O_DIALDELAY,	TRUE,
136768481Seric #define O_NORCPTACTION	0x88
136868481Seric 	"NoRecipientAction",	O_NORCPTACTION,	TRUE,
136968490Seric #define O_SAFEFILEENV	0x89
137068490Seric 	"SafeFileEnvironment",	O_SAFEFILEENV,	FALSE,
137168569Seric #define O_MAXMSGSIZE	0x8a
137268569Seric 	"MaxMessageSize",	O_MAXMSGSIZE,	FALSE,
137368756Seric #define O_COLONOKINADDR	0x8b
137468756Seric 	"ColonOkInAddr",	O_COLONOKINADDR, TRUE,
137569724Seric #define O_MAXQUEUERUN	0x8c
137669724Seric 	"MaxQueueRunSize",	O_MAXQUEUERUN,	TRUE,
137768481Seric 
137868481Seric 	NULL,			'\0',		FALSE,
137968481Seric };
138068481Seric 
138168481Seric 
138268481Seric 
1383*69748Seric void
138458734Seric setoption(opt, val, safe, sticky, e)
1385*69748Seric 	int opt;
13868256Seric 	char *val;
138721755Seric 	bool safe;
13888269Seric 	bool sticky;
138958734Seric 	register ENVELOPE *e;
13908256Seric {
139157207Seric 	register char *p;
139268481Seric 	register struct optioninfo *o;
139368481Seric 	char *subopt;
13948265Seric 	extern bool atobool();
139512633Seric 	extern time_t convtime();
139614879Seric 	extern int QueueLA;
139714879Seric 	extern int RefuseLA;
139864718Seric 	extern bool Warn_Q_option;
13998256Seric 
140068481Seric 	errno = 0;
140168481Seric 	if (opt == ' ')
140268481Seric 	{
140368481Seric 		/* full word options */
140468481Seric 		struct optioninfo *sel;
140568481Seric 
140668481Seric 		p = strchr(val, '=');
140768481Seric 		if (p == NULL)
140868481Seric 			p = &val[strlen(val)];
140968481Seric 		while (*--p == ' ')
141068481Seric 			continue;
141168481Seric 		while (*++p == ' ')
141268481Seric 			*p = '\0';
141368481Seric 		if (p == val)
141468481Seric 		{
141568481Seric 			syserr("readcf: null option name");
141668481Seric 			return;
141768481Seric 		}
141868481Seric 		if (*p == '=')
141968481Seric 			*p++ = '\0';
142068481Seric 		while (*p == ' ')
142168481Seric 			p++;
142268481Seric 		subopt = strchr(val, '.');
142368481Seric 		if (subopt != NULL)
142468481Seric 			*subopt++ = '\0';
142568481Seric 		sel = NULL;
142668481Seric 		for (o = OptionTab; o->o_name != NULL; o++)
142768481Seric 		{
142868481Seric 			if (strncasecmp(o->o_name, val, strlen(val)) != 0)
142968481Seric 				continue;
143068481Seric 			if (strlen(o->o_name) == strlen(val))
143168481Seric 			{
143268481Seric 				/* completely specified -- this must be it */
143368481Seric 				sel = NULL;
143468481Seric 				break;
143568481Seric 			}
143668481Seric 			if (sel != NULL)
143768481Seric 				break;
143868481Seric 			sel = o;
143968481Seric 		}
144068481Seric 		if (sel != NULL && o->o_name == NULL)
144168481Seric 			o = sel;
144268481Seric 		else if (o->o_name == NULL)
144368481Seric 		{
144468481Seric 			syserr("readcf: unknown option name %s", val);
144568481Seric 			return;
144668481Seric 		}
144768481Seric 		else if (sel != NULL)
144868481Seric 		{
144968481Seric 			syserr("readcf: ambiguous option name %s (matches %s and %s)",
145068481Seric 				val, sel->o_name, o->o_name);
145168481Seric 			return;
145268481Seric 		}
145368481Seric 		if (strlen(val) != strlen(o->o_name))
145468481Seric 		{
145568481Seric 			bool oldVerbose = Verbose;
145668481Seric 
145768481Seric 			Verbose = TRUE;
145868481Seric 			message("Option %s used as abbreviation for %s",
145968481Seric 				val, o->o_name);
146068481Seric 			Verbose = oldVerbose;
146168481Seric 		}
146268481Seric 		opt = o->o_code;
146368481Seric 		val = p;
146468481Seric 	}
146568481Seric 	else
146668481Seric 	{
146768481Seric 		for (o = OptionTab; o->o_name != NULL; o++)
146868481Seric 		{
146968481Seric 			if (o->o_code == opt)
147068481Seric 				break;
147168481Seric 		}
147268481Seric 		subopt = NULL;
147368481Seric 	}
147468481Seric 
14758256Seric 	if (tTd(37, 1))
147668481Seric 	{
147768481Seric 		printf(isascii(opt) && isprint(opt) ?
147868481Seric 			    "setoption %s (%c).%s=%s" :
147968481Seric 			    "setoption %s (0x%x).%s=%s",
148068481Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
148168481Seric 			opt,
148268481Seric 			subopt == NULL ? "" : subopt,
148368481Seric 			val);
148468481Seric 	}
14858256Seric 
14868256Seric 	/*
14878269Seric 	**  See if this option is preset for us.
14888256Seric 	*/
14898256Seric 
149059731Seric 	if (!sticky && bitnset(opt, StickyOpt))
14918269Seric 	{
14929341Seric 		if (tTd(37, 1))
14939341Seric 			printf(" (ignored)\n");
14948269Seric 		return;
14958269Seric 	}
14968269Seric 
149721755Seric 	/*
149821755Seric 	**  Check to see if this option can be specified by this user.
149921755Seric 	*/
150021755Seric 
150163787Seric 	if (!safe && RealUid == 0)
150221755Seric 		safe = TRUE;
150368481Seric 	if (!safe && !o->o_safe)
150421755Seric 	{
150539111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
150621755Seric 		{
150736582Sbostic 			if (tTd(37, 1))
150836582Sbostic 				printf(" (unsafe)");
150963787Seric 			if (RealUid != geteuid())
151036582Sbostic 			{
151151210Seric 				if (tTd(37, 1))
151251210Seric 					printf("(Resetting uid)");
151363787Seric 				(void) setgid(RealGid);
151463787Seric 				(void) setuid(RealUid);
151536582Sbostic 			}
151621755Seric 		}
151721755Seric 	}
151851210Seric 	if (tTd(37, 1))
151917985Seric 		printf("\n");
15208269Seric 
152168481Seric 	switch (opt & 0xff)
15228256Seric 	{
152359709Seric 	  case '7':		/* force seven-bit input */
152468481Seric 		SevenBitInput = atobool(val);
152552106Seric 		break;
152652106Seric 
152769480Seric #if MIME8TO7
152868481Seric 	  case '8':		/* handling of 8-bit input */
152968481Seric 		switch (*val)
153068481Seric 		{
153168481Seric 		  case 'm':		/* convert 8-bit, convert MIME */
153268481Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
153368481Seric 			break;
153468481Seric 
153568481Seric 		  case 'p':		/* pass 8 bit, convert MIME */
153668856Seric 			MimeMode = MM_CVTMIME|MM_PASS8BIT;
153768481Seric 			break;
153868481Seric 
153968481Seric 		  case 's':		/* strict adherence */
154068481Seric 			MimeMode = MM_CVTMIME;
154168481Seric 			break;
154268481Seric 
154368856Seric #if 0
154468856Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
154568856Seric 			MimeMode = 0;
154668856Seric 			break;
154768856Seric 
154868856Seric 		  case 'j':		/* "just send 8" */
154968856Seric 			MimeMode = MM_PASS8BIT;
155068856Seric 			break;
155168856Seric 
155268481Seric 		  case 'a':		/* encode 8 bit if available */
155368481Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
155468481Seric 			break;
155568481Seric 
155668481Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
155768481Seric 			MimeMode = MM_MIME8BIT;
155868481Seric 			break;
155968856Seric #endif
156068481Seric 
156168481Seric 		  default:
156268481Seric 			syserr("Unknown 8-bit mode %c", *val);
156368481Seric 			exit(EX_USAGE);
156468481Seric 		}
156568481Seric 		break;
156669480Seric #endif
156768481Seric 
15688256Seric 	  case 'A':		/* set default alias file */
15699381Seric 		if (val[0] == '\0')
157059672Seric 			setalias("aliases");
15719381Seric 		else
157259672Seric 			setalias(val);
15738256Seric 		break;
15748256Seric 
157517474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
157617474Seric 		if (val[0] == '\0')
157764796Seric 			SafeAlias = 5 * 60;		/* five minutes */
157817474Seric 		else
157964796Seric 			SafeAlias = convtime(val, 'm');
158017474Seric 		break;
158117474Seric 
158216843Seric 	  case 'B':		/* substitution for blank character */
158316843Seric 		SpaceSub = val[0];
158416843Seric 		if (SpaceSub == '\0')
158516843Seric 			SpaceSub = ' ';
158616843Seric 		break;
158716843Seric 
158859283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
158959283Seric 		p = strchr(val, '/');
159059283Seric 		if (p != NULL)
159159283Seric 		{
159259283Seric 			*p++ = '\0';
159359283Seric 			MaxMessageSize = atol(p);
159459283Seric 		}
159558082Seric 		MinBlocksFree = atol(val);
159658082Seric 		break;
159758082Seric 
15989284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
15999381Seric 		NoConnect = atobool(val);
16009284Seric 		break;
16019284Seric 
160251305Seric 	  case 'C':		/* checkpoint every N addresses */
160351305Seric 		CheckpointInterval = atoi(val);
160424944Seric 		break;
160524944Seric 
16069284Seric 	  case 'd':		/* delivery mode */
16079284Seric 		switch (*val)
16088269Seric 		{
16099284Seric 		  case '\0':
161058734Seric 			e->e_sendmode = SM_DELIVER;
16118269Seric 			break;
16128269Seric 
161310755Seric 		  case SM_QUEUE:	/* queue only */
161410755Seric #ifndef QUEUE
161510755Seric 			syserr("need QUEUE to set -odqueue");
161656795Seric #endif /* QUEUE */
161710755Seric 			/* fall through..... */
161810755Seric 
16199284Seric 		  case SM_DELIVER:	/* do everything */
16209284Seric 		  case SM_FORK:		/* fork after verification */
162158734Seric 			e->e_sendmode = *val;
16228269Seric 			break;
16238269Seric 
16248269Seric 		  default:
16259284Seric 			syserr("Unknown delivery mode %c", *val);
16268269Seric 			exit(EX_USAGE);
16278269Seric 		}
16288269Seric 		break;
16298269Seric 
16309146Seric 	  case 'D':		/* rebuild alias database as needed */
16319381Seric 		AutoRebuild = atobool(val);
16329146Seric 		break;
16339146Seric 
163455372Seric 	  case 'E':		/* error message header/header file */
163555379Seric 		if (*val != '\0')
163655379Seric 			ErrMsgFile = newstr(val);
163755372Seric 		break;
163855372Seric 
16398269Seric 	  case 'e':		/* set error processing mode */
16408269Seric 		switch (*val)
16418269Seric 		{
16429381Seric 		  case EM_QUIET:	/* be silent about it */
16439381Seric 		  case EM_MAIL:		/* mail back */
16449381Seric 		  case EM_BERKNET:	/* do berknet error processing */
16459381Seric 		  case EM_WRITE:	/* write back (or mail) */
16469381Seric 		  case EM_PRINT:	/* print errors normally (default) */
164758734Seric 			e->e_errormode = *val;
16488269Seric 			break;
16498269Seric 		}
16508269Seric 		break;
16518269Seric 
16529049Seric 	  case 'F':		/* file mode */
165317975Seric 		FileMode = atooct(val) & 0777;
16549049Seric 		break;
16559049Seric 
16568269Seric 	  case 'f':		/* save Unix-style From lines on front */
16579381Seric 		SaveFrom = atobool(val);
16588269Seric 		break;
16598269Seric 
166053735Seric 	  case 'G':		/* match recipients against GECOS field */
166153735Seric 		MatchGecos = atobool(val);
166253735Seric 		break;
166353735Seric 
16648256Seric 	  case 'g':		/* default gid */
166568481Seric   g_opt:
166664133Seric 		if (isascii(*val) && isdigit(*val))
166764133Seric 			DefGid = atoi(val);
166864133Seric 		else
166964133Seric 		{
167064133Seric 			register struct group *gr;
167164133Seric 
167264133Seric 			DefGid = -1;
167364133Seric 			gr = getgrnam(val);
167464133Seric 			if (gr == NULL)
167568481Seric 				syserr("readcf: option %c: unknown group %s",
167668481Seric 					opt, val);
167764133Seric 			else
167864133Seric 				DefGid = gr->gr_gid;
167964133Seric 		}
16808256Seric 		break;
16818256Seric 
16828256Seric 	  case 'H':		/* help file */
16839381Seric 		if (val[0] == '\0')
16848269Seric 			HelpFile = "sendmail.hf";
16859381Seric 		else
16869381Seric 			HelpFile = newstr(val);
16878256Seric 		break;
16888256Seric 
168951305Seric 	  case 'h':		/* maximum hop count */
169051305Seric 		MaxHopCount = atoi(val);
169151305Seric 		break;
169251305Seric 
169335651Seric 	  case 'I':		/* use internet domain name server */
169466334Seric #if NAMED_BIND
169557207Seric 		for (p = val; *p != 0; )
169657207Seric 		{
169757207Seric 			bool clearmode;
169857207Seric 			char *q;
169957207Seric 			struct resolverflags *rfp;
170057207Seric 
170157207Seric 			while (*p == ' ')
170257207Seric 				p++;
170357207Seric 			if (*p == '\0')
170457207Seric 				break;
170557207Seric 			clearmode = FALSE;
170657207Seric 			if (*p == '-')
170757207Seric 				clearmode = TRUE;
170857207Seric 			else if (*p != '+')
170957207Seric 				p--;
171057207Seric 			p++;
171157207Seric 			q = p;
171258050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
171357207Seric 				p++;
171457207Seric 			if (*p != '\0')
171557207Seric 				*p++ = '\0';
171668759Seric 			if (strcasecmp(q, "HasWildcardMX") == 0)
171768759Seric 			{
171868759Seric 				NoMXforCanon = !clearmode;
171968759Seric 				continue;
172068759Seric 			}
172157207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
172257207Seric 			{
172357207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
172457207Seric 					break;
172557207Seric 			}
172664923Seric 			if (rfp->rf_name == NULL)
172764923Seric 				syserr("readcf: I option value %s unrecognized", q);
172864923Seric 			else if (clearmode)
172957207Seric 				_res.options &= ~rfp->rf_bits;
173057207Seric 			else
173157207Seric 				_res.options |= rfp->rf_bits;
173257207Seric 		}
173357207Seric 		if (tTd(8, 2))
173468759Seric 			printf("_res.options = %x, HasWildcardMX = %d\n",
173568759Seric 				_res.options, !NoMXforCanon);
173657207Seric #else
173757207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
173857207Seric #endif
173935651Seric 		break;
174035651Seric 
17418269Seric 	  case 'i':		/* ignore dot lines in message */
17429381Seric 		IgnrDot = atobool(val);
17438269Seric 		break;
17448269Seric 
174559730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
174659730Seric 		SendMIMEErrors = atobool(val);
174759730Seric 		break;
174859730Seric 
174957136Seric 	  case 'J':		/* .forward search path */
175057136Seric 		ForwardPath = newstr(val);
175157136Seric 		break;
175257136Seric 
175354967Seric 	  case 'k':		/* connection cache size */
175454967Seric 		MaxMciCache = atoi(val);
175556215Seric 		if (MaxMciCache < 0)
175656215Seric 			MaxMciCache = 0;
175754967Seric 		break;
175854967Seric 
175954967Seric 	  case 'K':		/* connection cache timeout */
176058796Seric 		MciCacheTimeout = convtime(val, 'm');
176154967Seric 		break;
176254967Seric 
176361104Seric 	  case 'l':		/* use Errors-To: header */
176461104Seric 		UseErrorsTo = atobool(val);
176561104Seric 		break;
176661104Seric 
17678256Seric 	  case 'L':		/* log level */
176864140Seric 		if (safe || LogLevel < atoi(val))
176964140Seric 			LogLevel = atoi(val);
17708256Seric 		break;
17718256Seric 
17728269Seric 	  case 'M':		/* define macro */
177368267Seric 		p = newstr(&val[1]);
177468267Seric 		if (!safe)
177568267Seric 			cleanstrcpy(p, p, MAXNAME);
177668267Seric 		define(val[0], p, CurEnv);
177716878Seric 		sticky = FALSE;
17788269Seric 		break;
17798269Seric 
17808269Seric 	  case 'm':		/* send to me too */
17819381Seric 		MeToo = atobool(val);
17828269Seric 		break;
17838269Seric 
178425820Seric 	  case 'n':		/* validate RHS in newaliases */
178525820Seric 		CheckAliases = atobool(val);
178625820Seric 		break;
178725820Seric 
178861104Seric 	    /* 'N' available -- was "net name" */
178961104Seric 
179058851Seric 	  case 'O':		/* daemon options */
179158851Seric 		setdaemonoptions(val);
179258851Seric 		break;
179358851Seric 
17948269Seric 	  case 'o':		/* assume old style headers */
17959381Seric 		if (atobool(val))
17969341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
17979341Seric 		else
17989341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
17998269Seric 		break;
18008269Seric 
180158082Seric 	  case 'p':		/* select privacy level */
180258082Seric 		p = val;
180358082Seric 		for (;;)
180458082Seric 		{
180558082Seric 			register struct prival *pv;
180658082Seric 			extern struct prival PrivacyValues[];
180758082Seric 
180858082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
180958082Seric 				p++;
181058082Seric 			if (*p == '\0')
181158082Seric 				break;
181258082Seric 			val = p;
181358082Seric 			while (isascii(*p) && isalnum(*p))
181458082Seric 				p++;
181558082Seric 			if (*p != '\0')
181658082Seric 				*p++ = '\0';
181758082Seric 
181858082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
181958082Seric 			{
182058082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
182158082Seric 					break;
182258082Seric 			}
182358886Seric 			if (pv->pv_name == NULL)
182458886Seric 				syserr("readcf: Op line: %s unrecognized", val);
182558082Seric 			PrivacyFlags |= pv->pv_flag;
182658082Seric 		}
182768479Seric 		sticky = FALSE;
182858082Seric 		break;
182958082Seric 
183024944Seric 	  case 'P':		/* postmaster copy address for returned mail */
183124944Seric 		PostMasterCopy = newstr(val);
183224944Seric 		break;
183324944Seric 
183424944Seric 	  case 'q':		/* slope of queue only function */
183524944Seric 		QueueFactor = atoi(val);
183624944Seric 		break;
183724944Seric 
18388256Seric 	  case 'Q':		/* queue directory */
18399381Seric 		if (val[0] == '\0')
18408269Seric 			QueueDir = "mqueue";
18419381Seric 		else
18429381Seric 			QueueDir = newstr(val);
184358789Seric 		if (RealUid != 0 && !safe)
184464718Seric 			Warn_Q_option = TRUE;
18458256Seric 		break;
18468256Seric 
184758148Seric 	  case 'R':		/* don't prune routes */
184858148Seric 		DontPruneRoutes = atobool(val);
184958148Seric 		break;
185058148Seric 
18518256Seric 	  case 'r':		/* read timeout */
185268481Seric 		if (subopt == NULL)
185368481Seric 			inittimeouts(val);
185468481Seric 		else
185568481Seric 			settimeout(subopt, val);
18568256Seric 		break;
18578256Seric 
18588256Seric 	  case 'S':		/* status file */
18599381Seric 		if (val[0] == '\0')
18608269Seric 			StatFile = "sendmail.st";
18619381Seric 		else
18629381Seric 			StatFile = newstr(val);
18638256Seric 		break;
18648256Seric 
18658265Seric 	  case 's':		/* be super safe, even if expensive */
18669381Seric 		SuperSafe = atobool(val);
18678256Seric 		break;
18688256Seric 
18698256Seric 	  case 'T':		/* queue timeout */
187058737Seric 		p = strchr(val, '/');
187158737Seric 		if (p != NULL)
187258737Seric 		{
187358737Seric 			*p++ = '\0';
187468481Seric 			settimeout("queuewarn", p);
187558737Seric 		}
187668481Seric 		settimeout("queuereturn", val);
187754967Seric 		break;
18788256Seric 
18798265Seric 	  case 't':		/* time zone name */
188052106Seric 		TimeZoneSpec = newstr(val);
18818265Seric 		break;
18828265Seric 
188350556Seric 	  case 'U':		/* location of user database */
188451360Seric 		UdbSpec = newstr(val);
188550556Seric 		break;
188650556Seric 
18878256Seric 	  case 'u':		/* set default uid */
188868481Seric 		for (p = val; *p != '\0'; p++)
188968481Seric 		{
189068481Seric 			if (*p == '.' || *p == '/' || *p == ':')
189168481Seric 			{
189268481Seric 				*p++ = '\0';
189368481Seric 				break;
189468481Seric 			}
189568481Seric 		}
189664133Seric 		if (isascii(*val) && isdigit(*val))
189764133Seric 			DefUid = atoi(val);
189864133Seric 		else
189964133Seric 		{
190064133Seric 			register struct passwd *pw;
190164133Seric 
190264133Seric 			DefUid = -1;
190368693Seric 			pw = sm_getpwnam(val);
190464133Seric 			if (pw == NULL)
190564133Seric 				syserr("readcf: option u: unknown user %s", val);
190664133Seric 			else
190768481Seric 			{
190864133Seric 				DefUid = pw->pw_uid;
190968481Seric 				DefGid = pw->pw_gid;
191068481Seric 			}
191164133Seric 		}
191240973Sbostic 		setdefuser();
19138256Seric 
191468481Seric 		/* handle the group if it is there */
191568481Seric 		if (*p == '\0')
191668481Seric 			break;
191768481Seric 		val = p;
191868481Seric 		goto g_opt;
191968481Seric 
192058851Seric 	  case 'V':		/* fallback MX host */
192158851Seric 		FallBackMX = newstr(val);
192258851Seric 		break;
192358851Seric 
19248269Seric 	  case 'v':		/* run in verbose mode */
19259381Seric 		Verbose = atobool(val);
19268256Seric 		break;
19278256Seric 
192863837Seric 	  case 'w':		/* if we are best MX, try host directly */
192963837Seric 		TryNullMXList = atobool(val);
193063837Seric 		break;
193161104Seric 
193261104Seric 	    /* 'W' available -- was wizard password */
193361104Seric 
193414879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
193514879Seric 		QueueLA = atoi(val);
193614879Seric 		break;
193714879Seric 
193814879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
193914879Seric 		RefuseLA = atoi(val);
194014879Seric 		break;
194114879Seric 
194224981Seric 	  case 'y':		/* work recipient factor */
194324981Seric 		WkRecipFact = atoi(val);
194424981Seric 		break;
194524981Seric 
194624981Seric 	  case 'Y':		/* fork jobs during queue runs */
194724952Seric 		ForkQueueRuns = atobool(val);
194824952Seric 		break;
194924952Seric 
195024981Seric 	  case 'z':		/* work message class factor */
195124981Seric 		WkClassFact = atoi(val);
195224981Seric 		break;
195324981Seric 
195424981Seric 	  case 'Z':		/* work time factor */
195524981Seric 		WkTimeFact = atoi(val);
195624981Seric 		break;
195724981Seric 
195868481Seric 	  case O_QUEUESORTORD:	/* queue sorting order */
195968481Seric 		switch (*val)
196068481Seric 		{
196168481Seric 		  case 'h':	/* Host first */
196268481Seric 		  case 'H':
196368481Seric 			QueueSortOrder = QS_BYHOST;
196468481Seric 			break;
196568481Seric 
196668481Seric 		  case 'p':	/* Priority order */
196768481Seric 		  case 'P':
196868481Seric 			QueueSortOrder = QS_BYPRIORITY;
196968481Seric 			break;
197068481Seric 
197168481Seric 		  default:
197268481Seric 			syserr("Invalid queue sort order \"%s\"", val);
197368481Seric 		}
197468481Seric 		break;
197568481Seric 
197669401Seric 	  case O_HOSTSFILE:	/* pathname of /etc/hosts file */
197769401Seric 		HostsFile = newstr(val);
197869401Seric 		break;
197969401Seric 
198068481Seric 	  case O_MQA:		/* minimum queue age between deliveries */
198168481Seric 		MinQueueAge = convtime(val, 'm');
198268481Seric 		break;
198368481Seric 
198468481Seric 	  case O_MHSA:		/* maximum age of cached host status */
198568481Seric 		MaxHostStatAge = convtime(val, 'm');
198668481Seric 		break;
198768481Seric 
198868481Seric 	  case O_DEFCHARSET:	/* default character set for mimefying */
198968481Seric 		DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
199068481Seric 		break;
199168481Seric 
199268481Seric 	  case O_SSFILE:	/* service switch file */
199368481Seric 		ServiceSwitchFile = newstr(val);
199468481Seric 		break;
199568481Seric 
199668481Seric 	  case O_DIALDELAY:	/* delay for dial-on-demand operation */
199768481Seric 		DialDelay = convtime(val, 's');
199868481Seric 		break;
199968481Seric 
200068481Seric 	  case O_NORCPTACTION:	/* what to do if no recipient */
200168481Seric 		if (strcasecmp(val, "none") == 0)
200268481Seric 			NoRecipientAction = NRA_NO_ACTION;
200368481Seric 		else if (strcasecmp(val, "add-to") == 0)
200468481Seric 			NoRecipientAction = NRA_ADD_TO;
200568481Seric 		else if (strcasecmp(val, "add-apparently-to") == 0)
200668481Seric 			NoRecipientAction = NRA_ADD_APPARENTLY_TO;
200768481Seric 		else if (strcasecmp(val, "add-bcc") == 0)
200868481Seric 			NoRecipientAction = NRA_ADD_BCC;
200968481Seric 		else if (strcasecmp(val, "add-to-undisclosed") == 0)
201068481Seric 			NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
201168481Seric 		else
201268481Seric 			syserr("Invalid NoRecipientAction: %s", val);
201368481Seric 
201468490Seric 	  case O_SAFEFILEENV:	/* chroot() environ for writing to files */
201568490Seric 		SafeFileEnv = newstr(val);
201668490Seric 		break;
201768490Seric 
201868569Seric 	  case O_MAXMSGSIZE:	/* maximum message size */
2019*69748Seric 		MaxMessageSize = atol(val);
202068569Seric 		break;
202168569Seric 
202268756Seric 	  case O_COLONOKINADDR:	/* old style handling of colon addresses */
2023*69748Seric 		ColonOkInAddr = atobool(val);
202468756Seric 		break;
202568756Seric 
202669724Seric 	  case O_MAXQUEUERUN:	/* max # of jobs in a single queue run */
2027*69748Seric 		MaxQueueRun = atol(val);
202869724Seric 		break;
202969724Seric 
20308256Seric 	  default:
203168481Seric 		if (tTd(37, 1))
203268481Seric 		{
203368481Seric 			if (isascii(opt) && isprint(opt))
203468481Seric 				printf("Warning: option %c unknown\n", opt);
203568481Seric 			else
203668481Seric 				printf("Warning: option 0x%x unknown\n", opt);
203768481Seric 		}
20388256Seric 		break;
20398256Seric 	}
204016878Seric 	if (sticky)
204116878Seric 		setbitn(opt, StickyOpt);
20428256Seric }
204310687Seric /*
204468481Seric **  SETCLASS -- set a string into a class
204510687Seric **
204610687Seric **	Parameters:
204768481Seric **		class -- the class to put the string in.
204868481Seric **		str -- the string to enter
204910687Seric **
205010687Seric **	Returns:
205110687Seric **		none.
205210687Seric **
205310687Seric **	Side Effects:
205410687Seric **		puts the word into the symbol table.
205510687Seric */
205610687Seric 
2057*69748Seric void
205868481Seric setclass(class, str)
205910687Seric 	int class;
206068481Seric 	char *str;
206110687Seric {
206210687Seric 	register STAB *s;
206310687Seric 
206457943Seric 	if (tTd(37, 8))
206568481Seric 		printf("setclass(%c, %s)\n", class, str);
206668481Seric 	s = stab(str, ST_CLASS, ST_ENTER);
206710687Seric 	setbitn(class, s->s_class);
206810687Seric }
206953654Seric /*
207053654Seric **  MAKEMAPENTRY -- create a map entry
207153654Seric **
207253654Seric **	Parameters:
207353654Seric **		line -- the config file line
207453654Seric **
207553654Seric **	Returns:
207653654Seric **		TRUE if it successfully entered the map entry.
207753654Seric **		FALSE otherwise (usually syntax error).
207853654Seric **
207953654Seric **	Side Effects:
208053654Seric **		Enters the map into the dictionary.
208153654Seric */
208253654Seric 
208353654Seric void
208453654Seric makemapentry(line)
208553654Seric 	char *line;
208653654Seric {
208753654Seric 	register char *p;
208853654Seric 	char *mapname;
208953654Seric 	char *classname;
209064078Seric 	register STAB *s;
209153654Seric 	STAB *class;
209253654Seric 
209358050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
209453654Seric 		continue;
209558050Seric 	if (!(isascii(*p) && isalnum(*p)))
209653654Seric 	{
209753654Seric 		syserr("readcf: config K line: no map name");
209853654Seric 		return;
209953654Seric 	}
210053654Seric 
210153654Seric 	mapname = p;
210268481Seric 	while ((isascii(*++p) && isalnum(*p)) || *p == '.')
210353654Seric 		continue;
210453654Seric 	if (*p != '\0')
210553654Seric 		*p++ = '\0';
210658050Seric 	while (isascii(*p) && isspace(*p))
210753654Seric 		p++;
210858050Seric 	if (!(isascii(*p) && isalnum(*p)))
210953654Seric 	{
211053654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
211153654Seric 		return;
211253654Seric 	}
211353654Seric 	classname = p;
211458050Seric 	while (isascii(*++p) && isalnum(*p))
211553654Seric 		continue;
211653654Seric 	if (*p != '\0')
211753654Seric 		*p++ = '\0';
211858050Seric 	while (isascii(*p) && isspace(*p))
211953654Seric 		p++;
212053654Seric 
212153654Seric 	/* look up the class */
212253654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
212353654Seric 	if (class == NULL)
212453654Seric 	{
212553654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
212653654Seric 		return;
212753654Seric 	}
212853654Seric 
212953654Seric 	/* enter the map */
213064078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
213164078Seric 	s->s_map.map_class = &class->s_mapclass;
213264078Seric 	s->s_map.map_mname = newstr(mapname);
213353654Seric 
213464078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
213564078Seric 		s->s_map.map_mflags |= MF_VALID;
213664078Seric 
213764078Seric 	if (tTd(37, 5))
213864078Seric 	{
213964078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
214064078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
214164078Seric 			s->s_map.map_mflags,
214264078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
214364078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
214464078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
214564078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
214664078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
214764078Seric 	}
214853654Seric }
214958112Seric /*
215068481Seric **  INITTIMEOUTS -- parse and set timeout values
215158112Seric **
215258112Seric **	Parameters:
215358112Seric **		val -- a pointer to the values.  If NULL, do initial
215458112Seric **			settings.
215558112Seric **
215658112Seric **	Returns:
215758112Seric **		none.
215858112Seric **
215958112Seric **	Side Effects:
216058112Seric **		Initializes the TimeOuts structure
216158112Seric */
216258112Seric 
216364255Seric #define SECONDS
216458112Seric #define MINUTES	* 60
216558112Seric #define HOUR	* 3600
216658112Seric 
2167*69748Seric void
216868481Seric inittimeouts(val)
216958112Seric 	register char *val;
217058112Seric {
217158112Seric 	register char *p;
217258671Seric 	extern time_t convtime();
217358112Seric 
217458112Seric 	if (val == NULL)
217558112Seric 	{
217658112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
217758112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
217858112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
217958112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
218058112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
218158112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
218258112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
218358112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
218458112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
218558112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
218658112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
218768481Seric #if IDENTPROTO
218864255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
218968481Seric #else
219068481Seric 		TimeOuts.to_ident = (time_t) 0 SECONDS;
219168481Seric #endif
219268481Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
219358112Seric 		return;
219458112Seric 	}
219558112Seric 
219658112Seric 	for (;; val = p)
219758112Seric 	{
219858112Seric 		while (isascii(*val) && isspace(*val))
219958112Seric 			val++;
220058112Seric 		if (*val == '\0')
220158112Seric 			break;
220258112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
220358112Seric 			continue;
220458112Seric 		if (*p != '\0')
220558112Seric 			*p++ = '\0';
220658112Seric 
220758112Seric 		if (isascii(*val) && isdigit(*val))
220858112Seric 		{
220958112Seric 			/* old syntax -- set everything */
221058796Seric 			TimeOuts.to_mail = convtime(val, 'm');
221158112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
221258112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
221358112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
221458112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
221558112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
221658112Seric 			continue;
221758112Seric 		}
221858112Seric 		else
221958112Seric 		{
222068481Seric 			register char *q = strchr(val, ':');
222158112Seric 
222268481Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
222358112Seric 			{
222458112Seric 				/* syntax error */
222558112Seric 				continue;
222658112Seric 			}
222758112Seric 			*q++ = '\0';
222868481Seric 			settimeout(val, q);
222968481Seric 		}
223068481Seric 	}
223168481Seric }
223268481Seric /*
223368481Seric **  SETTIMEOUT -- set an individual timeout
223468481Seric **
223568481Seric **	Parameters:
223668481Seric **		name -- the name of the timeout.
223768481Seric **		val -- the value of the timeout.
223868481Seric **
223968481Seric **	Returns:
224068481Seric **		none.
224168481Seric */
224258112Seric 
2243*69748Seric void
224468481Seric settimeout(name, val)
224568481Seric 	char *name;
224668481Seric 	char *val;
224768481Seric {
224868481Seric 	register char *p;
224968481Seric 	time_t to;
225068481Seric 	extern time_t convtime();
225168481Seric 
225268481Seric 	to = convtime(val, 'm');
225368481Seric 	p = strchr(name, '.');
225468481Seric 	if (p != NULL)
225568481Seric 		*p++ = '\0';
225668481Seric 
225768481Seric 	if (strcasecmp(name, "initial") == 0)
225868481Seric 		TimeOuts.to_initial = to;
225968481Seric 	else if (strcasecmp(name, "mail") == 0)
226068481Seric 		TimeOuts.to_mail = to;
226168481Seric 	else if (strcasecmp(name, "rcpt") == 0)
226268481Seric 		TimeOuts.to_rcpt = to;
226368481Seric 	else if (strcasecmp(name, "datainit") == 0)
226468481Seric 		TimeOuts.to_datainit = to;
226568481Seric 	else if (strcasecmp(name, "datablock") == 0)
226668481Seric 		TimeOuts.to_datablock = to;
226768481Seric 	else if (strcasecmp(name, "datafinal") == 0)
226868481Seric 		TimeOuts.to_datafinal = to;
226968481Seric 	else if (strcasecmp(name, "command") == 0)
227068481Seric 		TimeOuts.to_nextcommand = to;
227168481Seric 	else if (strcasecmp(name, "rset") == 0)
227268481Seric 		TimeOuts.to_rset = to;
227368481Seric 	else if (strcasecmp(name, "helo") == 0)
227468481Seric 		TimeOuts.to_helo = to;
227568481Seric 	else if (strcasecmp(name, "quit") == 0)
227668481Seric 		TimeOuts.to_quit = to;
227768481Seric 	else if (strcasecmp(name, "misc") == 0)
227868481Seric 		TimeOuts.to_miscshort = to;
227968481Seric 	else if (strcasecmp(name, "ident") == 0)
228068481Seric 		TimeOuts.to_ident = to;
228168481Seric 	else if (strcasecmp(name, "fileopen") == 0)
228268481Seric 		TimeOuts.to_fileopen = to;
228368481Seric 	else if (strcasecmp(name, "queuewarn") == 0)
228468481Seric 	{
228568481Seric 		to = convtime(val, 'h');
228668481Seric 		if (p == NULL || strcmp(p, "*") == 0)
228768481Seric 		{
228868481Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = to;
228968481Seric 			TimeOuts.to_q_warning[TOC_URGENT] = to;
229068481Seric 			TimeOuts.to_q_warning[TOC_NONURGENT] = to;
229158112Seric 		}
229268481Seric 		else if (strcasecmp(p, "normal") == 0)
229368481Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = to;
229468481Seric 		else if (strcasecmp(p, "urgent") == 0)
229568481Seric 			TimeOuts.to_q_warning[TOC_URGENT] = to;
229668481Seric 		else if (strcasecmp(p, "non-urgent") == 0)
229768481Seric 			TimeOuts.to_q_warning[TOC_NONURGENT] = to;
229868481Seric 		else
229968481Seric 			syserr("settimeout: invalid queuewarn subtimeout %s", p);
230058112Seric 	}
230168481Seric 	else if (strcasecmp(name, "queuereturn") == 0)
230268481Seric 	{
230368481Seric 		to = convtime(val, 'd');
230468481Seric 		if (p == NULL || strcmp(p, "*") == 0)
230568481Seric 		{
230668481Seric 			TimeOuts.to_q_return[TOC_NORMAL] = to;
230768481Seric 			TimeOuts.to_q_return[TOC_URGENT] = to;
230868481Seric 			TimeOuts.to_q_return[TOC_NONURGENT] = to;
230968481Seric 		}
231068481Seric 		else if (strcasecmp(p, "normal") == 0)
231168481Seric 			TimeOuts.to_q_return[TOC_NORMAL] = to;
231268481Seric 		else if (strcasecmp(p, "urgent") == 0)
231368481Seric 			TimeOuts.to_q_return[TOC_URGENT] = to;
231468481Seric 		else if (strcasecmp(p, "non-urgent") == 0)
231568481Seric 			TimeOuts.to_q_return[TOC_NONURGENT] = to;
231668481Seric 		else
231768481Seric 			syserr("settimeout: invalid queuereturn subtimeout %s", p);
231868481Seric 	}
231968481Seric 	else
232068481Seric 		syserr("settimeout: invalid timeout %s", name);
232158112Seric }
2322