xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67903)
122709Sdist /*
234921Sbostic  * Copyright (c) 1983 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*67903Seric static char sccsid[] = "@(#)readcf.c	8.46 (Berkeley) 11/12/94";
1133731Sbostic #endif /* not lint */
1222709Sdist 
133313Seric # include "sendmail.h"
1464133Seric # include <pwd.h>
1564133Seric # include <grp.h>
1666334Seric #if NAMED_BIND
1757207Seric # include <resolv.h>
1857207Seric #endif
193308Seric 
203308Seric /*
213308Seric **  READCF -- read control file.
223308Seric **
233308Seric **	This routine reads the control file and builds the internal
243308Seric **	form.
253308Seric **
264432Seric **	The file is formatted as a sequence of lines, each taken
274432Seric **	atomically.  The first character of each line describes how
284432Seric **	the line is to be interpreted.  The lines are:
294432Seric **		Dxval		Define macro x to have value val.
304432Seric **		Cxword		Put word into class x.
314432Seric **		Fxfile [fmt]	Read file for lines to put into
324432Seric **				class x.  Use scanf string 'fmt'
334432Seric **				or "%s" if not present.  Fmt should
344432Seric **				only produce one string-valued result.
354432Seric **		Hname: value	Define header with field-name 'name'
364432Seric **				and value as specified; this will be
374432Seric **				macro expanded immediately before
384432Seric **				use.
394432Seric **		Sn		Use rewriting set n.
404432Seric **		Rlhs rhs	Rewrite addresses that match lhs to
414432Seric **				be rhs.
4224944Seric **		Mn arg=val...	Define mailer.  n is the internal name.
4324944Seric **				Args specify mailer parameters.
448252Seric **		Oxvalue		Set option x to value.
458252Seric **		Pname=value	Set precedence name to value.
4664718Seric **		Vversioncode[/vendorcode]
4764718Seric **				Version level/vendor name of
4864718Seric **				configuration syntax.
4953654Seric **		Kmapname mapclass arguments....
5053654Seric **				Define keyed lookup of a given class.
5153654Seric **				Arguments are class dependent.
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 
6655012Seric readcf(cfname, safe, e)
673308Seric 	char *cfname;
6854973Seric 	bool safe;
6955012Seric 	register ENVELOPE *e;
703308Seric {
713308Seric 	FILE *cf;
728547Seric 	int ruleset = 0;
738547Seric 	char *q;
749350Seric 	struct rewrite *rwp = NULL;
7557135Seric 	char *bp;
7664718Seric 	auto char *ep;
7757589Seric 	int nfuzzy;
7864133Seric 	char *file;
7964133Seric 	bool optional;
8067769Seric 	int mid;
813308Seric 	char buf[MAXLINE];
823308Seric 	register char *p;
833308Seric 	extern char **copyplist();
8452647Seric 	struct stat statb;
855909Seric 	char exbuf[MAXLINE];
8665066Seric 	char pvpbuf[MAXLINE + MAXATOM];
8767826Seric 	static char *null_list[1] = { NULL };
8810709Seric 	extern char *munchstring();
8953654Seric 	extern void makemapentry();
903308Seric 
9152647Seric 	FileName = cfname;
9252647Seric 	LineNumber = 0;
9352647Seric 
943308Seric 	cf = fopen(cfname, "r");
953308Seric 	if (cf == NULL)
963308Seric 	{
9752647Seric 		syserr("cannot open");
983308Seric 		exit(EX_OSFILE);
993308Seric 	}
1003308Seric 
10152647Seric 	if (fstat(fileno(cf), &statb) < 0)
10252647Seric 	{
10352647Seric 		syserr("cannot fstat");
10452647Seric 		exit(EX_OSFILE);
10552647Seric 	}
10652647Seric 
10752647Seric 	if (!S_ISREG(statb.st_mode))
10852647Seric 	{
10952647Seric 		syserr("not a plain file");
11052647Seric 		exit(EX_OSFILE);
11152647Seric 	}
11252647Seric 
11352647Seric 	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
11452647Seric 	{
11553037Seric 		if (OpMode == MD_DAEMON || OpMode == MD_FREEZE)
11653037Seric 			fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
11753037Seric 				FileName);
11853037Seric #ifdef LOG
11953037Seric 		if (LogLevel > 0)
12053037Seric 			syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
12153037Seric 				FileName);
12253037Seric #endif
12352647Seric 	}
12452647Seric 
12559254Seric #ifdef XLA
12659254Seric 	xla_zero();
12759254Seric #endif
12859254Seric 
12957135Seric 	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
1303308Seric 	{
13157135Seric 		if (bp[0] == '#')
13257135Seric 		{
13357135Seric 			if (bp != buf)
13457135Seric 				free(bp);
13552637Seric 			continue;
13657135Seric 		}
13752637Seric 
13867769Seric 		/* do macro expansion mappings */
13957135Seric 		for (p = bp; *p != '\0'; p++)
14016157Seric 		{
14157135Seric 			if (*p == '#' && p > bp && ConfigLevel >= 3)
14252647Seric 			{
14352647Seric 				/* this is an on-line comment */
14452647Seric 				register char *e;
14552647Seric 
14658050Seric 				switch (*--p & 0377)
14752647Seric 				{
14858050Seric 				  case MACROEXPAND:
14952647Seric 					/* it's from $# -- let it go through */
15052647Seric 					p++;
15152647Seric 					break;
15252647Seric 
15352647Seric 				  case '\\':
15452647Seric 					/* it's backslash escaped */
15552647Seric 					(void) strcpy(p, p + 1);
15652647Seric 					break;
15752647Seric 
15852647Seric 				  default:
15952647Seric 					/* delete preceeding white space */
16058050Seric 					while (isascii(*p) && isspace(*p) && p > bp)
16152647Seric 						p--;
16256795Seric 					if ((e = strchr(++p, '\n')) != NULL)
16352647Seric 						(void) strcpy(p, e);
16452647Seric 					else
16552647Seric 						p[0] = p[1] = '\0';
16652647Seric 					break;
16752647Seric 				}
16852647Seric 				continue;
16952647Seric 			}
17052647Seric 
17167769Seric 			if (*p != '$' || p[1] == '\0')
17216157Seric 				continue;
17316157Seric 
17416157Seric 			if (p[1] == '$')
17516157Seric 			{
17616157Seric 				/* actual dollar sign.... */
17723111Seric 				(void) strcpy(p, p + 1);
17816157Seric 				continue;
17916157Seric 			}
18016157Seric 
18116157Seric 			/* convert to macro expansion character */
18267769Seric 			*p++ = MACROEXPAND;
18367769Seric 
18467769Seric 			/* convert macro name to code */
18567769Seric 			*p = macid(p, &ep);
18667769Seric 			if (ep != p)
18767769Seric 				strcpy(p + 1, ep);
18816157Seric 		}
18916157Seric 
19016157Seric 		/* interpret this line */
19164718Seric 		errno = 0;
19257135Seric 		switch (bp[0])
1933308Seric 		{
1943308Seric 		  case '\0':
1953308Seric 		  case '#':		/* comment */
1963308Seric 			break;
1973308Seric 
1983308Seric 		  case 'R':		/* rewriting rule */
19957135Seric 			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
2003308Seric 				continue;
2013308Seric 
2023308Seric 			if (*p == '\0')
2035909Seric 			{
20465821Seric 				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
2055909Seric 				break;
2065909Seric 			}
2075909Seric 
2085909Seric 			/* allocate space for the rule header */
2095909Seric 			if (rwp == NULL)
2105909Seric 			{
2115909Seric 				RewriteRules[ruleset] = rwp =
2125909Seric 					(struct rewrite *) xalloc(sizeof *rwp);
2135909Seric 			}
2143308Seric 			else
2153308Seric 			{
2165909Seric 				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
2175909Seric 				rwp = rwp->r_next;
2185909Seric 			}
2195909Seric 			rwp->r_next = NULL;
2203308Seric 
2215909Seric 			/* expand and save the LHS */
2225909Seric 			*p = '\0';
22357135Seric 			expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
22465066Seric 			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
22565066Seric 					     sizeof pvpbuf, NULL);
22657589Seric 			nfuzzy = 0;
2275909Seric 			if (rwp->r_lhs != NULL)
22857589Seric 			{
22957589Seric 				register char **ap;
23057589Seric 
2315909Seric 				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
23257589Seric 
23357589Seric 				/* count the number of fuzzy matches in LHS */
23457589Seric 				for (ap = rwp->r_lhs; *ap != NULL; ap++)
23557589Seric 				{
23658148Seric 					char *botch;
23758148Seric 
23858148Seric 					botch = NULL;
23958050Seric 					switch (**ap & 0377)
24057589Seric 					{
24157589Seric 					  case MATCHZANY:
24257589Seric 					  case MATCHANY:
24357589Seric 					  case MATCHONE:
24457589Seric 					  case MATCHCLASS:
24557589Seric 					  case MATCHNCLASS:
24657589Seric 						nfuzzy++;
24758148Seric 						break;
24858148Seric 
24958148Seric 					  case MATCHREPL:
25058148Seric 						botch = "$0-$9";
25158148Seric 						break;
25258148Seric 
25358148Seric 					  case CANONNET:
25458148Seric 						botch = "$#";
25558148Seric 						break;
25658148Seric 
25758148Seric 					  case CANONUSER:
25858148Seric 						botch = "$:";
25958148Seric 						break;
26058148Seric 
26158148Seric 					  case CALLSUBR:
26258148Seric 						botch = "$>";
26358148Seric 						break;
26458148Seric 
26558148Seric 					  case CONDIF:
26658148Seric 						botch = "$?";
26758148Seric 						break;
26858148Seric 
26958148Seric 					  case CONDELSE:
27058148Seric 						botch = "$|";
27158148Seric 						break;
27258148Seric 
27358148Seric 					  case CONDFI:
27458148Seric 						botch = "$.";
27558148Seric 						break;
27658148Seric 
27758148Seric 					  case HOSTBEGIN:
27858148Seric 						botch = "$[";
27958148Seric 						break;
28058148Seric 
28158148Seric 					  case HOSTEND:
28258148Seric 						botch = "$]";
28358148Seric 						break;
28458148Seric 
28558148Seric 					  case LOOKUPBEGIN:
28658148Seric 						botch = "$(";
28758148Seric 						break;
28858148Seric 
28958148Seric 					  case LOOKUPEND:
29058148Seric 						botch = "$)";
29158148Seric 						break;
29257589Seric 					}
29358148Seric 					if (botch != NULL)
29458148Seric 						syserr("Inappropriate use of %s on LHS",
29558148Seric 							botch);
29657589Seric 				}
29757589Seric 			}
29856678Seric 			else
29967826Seric 			{
30056678Seric 				syserr("R line: null LHS");
30167826Seric 				rwp->r_lhs = null_list;
30267826Seric 			}
3035909Seric 
3045909Seric 			/* expand and save the RHS */
3055909Seric 			while (*++p == '\t')
3065909Seric 				continue;
3077231Seric 			q = p;
3087231Seric 			while (*p != '\0' && *p != '\t')
3097231Seric 				p++;
3107231Seric 			*p = '\0';
31155012Seric 			expand(q, exbuf, &exbuf[sizeof exbuf], e);
31265066Seric 			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
31365066Seric 					     sizeof pvpbuf, NULL);
3145909Seric 			if (rwp->r_rhs != NULL)
31557589Seric 			{
31657589Seric 				register char **ap;
31757589Seric 
3185909Seric 				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
31957589Seric 
32057589Seric 				/* check no out-of-bounds replacements */
32157589Seric 				nfuzzy += '0';
32257589Seric 				for (ap = rwp->r_rhs; *ap != NULL; ap++)
32357589Seric 				{
32458148Seric 					char *botch;
32558148Seric 
32658148Seric 					botch = NULL;
32758148Seric 					switch (**ap & 0377)
32857589Seric 					{
32958148Seric 					  case MATCHREPL:
33058148Seric 						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
33158148Seric 						{
33258148Seric 							syserr("replacement $%c out of bounds",
33358148Seric 								(*ap)[1]);
33458148Seric 						}
33558148Seric 						break;
33658148Seric 
33758148Seric 					  case MATCHZANY:
33858148Seric 						botch = "$*";
33958148Seric 						break;
34058148Seric 
34158148Seric 					  case MATCHANY:
34258148Seric 						botch = "$+";
34358148Seric 						break;
34458148Seric 
34558148Seric 					  case MATCHONE:
34658148Seric 						botch = "$-";
34758148Seric 						break;
34858148Seric 
34958148Seric 					  case MATCHCLASS:
35058148Seric 						botch = "$=";
35158148Seric 						break;
35258148Seric 
35358148Seric 					  case MATCHNCLASS:
35458148Seric 						botch = "$~";
35558148Seric 						break;
35657589Seric 					}
35758148Seric 					if (botch != NULL)
35858148Seric 						syserr("Inappropriate use of %s on RHS",
35958148Seric 							botch);
36057589Seric 				}
36157589Seric 			}
36256678Seric 			else
36367826Seric 			{
36456678Seric 				syserr("R line: null RHS");
36567826Seric 				rwp->r_rhs = null_list;
36667826Seric 			}
3673308Seric 			break;
3683308Seric 
3694072Seric 		  case 'S':		/* select rewriting set */
37064440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
37164440Seric 				continue;
37264440Seric 			if (!isascii(*p) || !isdigit(*p))
37364440Seric 			{
37464440Seric 				syserr("invalid argument to S line: \"%.20s\"",
37564440Seric 					&bp[1]);
37664440Seric 				break;
37764440Seric 			}
37864440Seric 			ruleset = atoi(p);
3798056Seric 			if (ruleset >= MAXRWSETS || ruleset < 0)
3808056Seric 			{
3819381Seric 				syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
3828056Seric 				ruleset = 0;
3838056Seric 			}
3844072Seric 			rwp = NULL;
3854072Seric 			break;
3864072Seric 
3873308Seric 		  case 'D':		/* macro definition */
38867769Seric 			mid = macid(&bp[1], &ep);
38967769Seric 			p = munchstring(ep, NULL);
39067769Seric 			define(mid, newstr(p), e);
3913308Seric 			break;
3923308Seric 
3933387Seric 		  case 'H':		/* required header line */
39457135Seric 			(void) chompheader(&bp[1], TRUE, e);
3953387Seric 			break;
3963387Seric 
3974061Seric 		  case 'C':		/* word class */
3984432Seric 			/* scan the list of words and set class for all */
39967769Seric 			mid = macid(&bp[1], &ep);
40067769Seric 			expand(ep, exbuf, &exbuf[sizeof exbuf], e);
40164121Seric 			for (p = exbuf; *p != '\0'; )
4024061Seric 			{
4034061Seric 				register char *wd;
4044061Seric 				char delim;
4054061Seric 
40658050Seric 				while (*p != '\0' && isascii(*p) && isspace(*p))
4074061Seric 					p++;
4084061Seric 				wd = p;
40958050Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4104061Seric 					p++;
4114061Seric 				delim = *p;
4124061Seric 				*p = '\0';
4134061Seric 				if (wd[0] != '\0')
41467769Seric 					setclass(mid, wd);
4154061Seric 				*p = delim;
4164061Seric 			}
4174061Seric 			break;
4184061Seric 
41959272Seric 		  case 'F':		/* word class from file */
42067769Seric 			mid = macid(&bp[1], &ep);
42167769Seric 			for (p = ep; isascii(*p) && isspace(*p); )
42264133Seric 				p++;
42364133Seric 			if (p[0] == '-' && p[1] == 'o')
42464133Seric 			{
42564133Seric 				optional = TRUE;
42664133Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
42764133Seric 					p++;
42864133Seric 				while (isascii(*p) && isspace(*p))
42967615Seric 					p++;
43064133Seric 			}
43164133Seric 			else
43264133Seric 				optional = FALSE;
43364133Seric 			file = p;
43464133Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
43564133Seric 				p++;
43659272Seric 			if (*p == '\0')
43759272Seric 				p = "%s";
43859272Seric 			else
43959272Seric 			{
44059272Seric 				*p = '\0';
44159272Seric 				while (isascii(*++p) && isspace(*p))
44259272Seric 					continue;
44359272Seric 			}
44464133Seric 			fileclass(bp[1], file, p, safe, optional);
44559272Seric 			break;
44659272Seric 
44759156Seric #ifdef XLA
44859156Seric 		  case 'L':		/* extended load average description */
44959156Seric 			xla_init(&bp[1]);
45059156Seric 			break;
45159156Seric #endif
45259156Seric 
4534096Seric 		  case 'M':		/* define mailer */
45457135Seric 			makemailer(&bp[1]);
4554096Seric 			break;
4564096Seric 
4578252Seric 		  case 'O':		/* set option */
45858734Seric 			setoption(bp[1], &bp[2], safe, FALSE, e);
4598252Seric 			break;
4608252Seric 
4618252Seric 		  case 'P':		/* set precedence */
4628252Seric 			if (NumPriorities >= MAXPRIORITIES)
4638252Seric 			{
4648547Seric 				toomany('P', MAXPRIORITIES);
4658252Seric 				break;
4668252Seric 			}
46757135Seric 			for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
4688252Seric 				continue;
4698252Seric 			if (*p == '\0')
4708252Seric 				goto badline;
4718252Seric 			*p = '\0';
47257135Seric 			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
4738252Seric 			Priorities[NumPriorities].pri_val = atoi(++p);
4748252Seric 			NumPriorities++;
4758252Seric 			break;
4768252Seric 
4778547Seric 		  case 'T':		/* trusted user(s) */
47858161Seric 			/* this option is obsolete, but will be ignored */
4798547Seric 			break;
4808547Seric 
48152645Seric 		  case 'V':		/* configuration syntax version */
48264440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
48364440Seric 				continue;
48464440Seric 			if (!isascii(*p) || !isdigit(*p))
48564440Seric 			{
48664440Seric 				syserr("invalid argument to V line: \"%.20s\"",
48764440Seric 					&bp[1]);
48864440Seric 				break;
48964440Seric 			}
49064718Seric 			ConfigLevel = strtol(p, &ep, 10);
49164279Seric 			if (ConfigLevel >= 5)
49264279Seric 			{
49364279Seric 				/* level 5 configs have short name in $w */
49464279Seric 				p = macvalue('w', e);
49564279Seric 				if (p != NULL && (p = strchr(p, '.')) != NULL)
49664279Seric 					*p = '\0';
49764279Seric 			}
49864718Seric 			if (*ep++ == '/')
49964718Seric 			{
50064718Seric 				/* extract vendor code */
50164718Seric 				for (p = ep; isascii(*p) && isalpha(*p); )
50264718Seric 					p++;
50364718Seric 				*p = '\0';
50464718Seric 
50564718Seric 				if (!setvendor(ep))
50664718Seric 					syserr("invalid V line vendor code: \"%s\"",
50764718Seric 						ep);
50864718Seric 			}
50952645Seric 			break;
51052645Seric 
51153654Seric 		  case 'K':
51257135Seric 			makemapentry(&bp[1]);
51353654Seric 			break;
51453654Seric 
5153308Seric 		  default:
5164061Seric 		  badline:
51757135Seric 			syserr("unknown control line \"%s\"", bp);
5183308Seric 		}
51957135Seric 		if (bp != buf)
52057135Seric 			free(bp);
5213308Seric 	}
52252637Seric 	if (ferror(cf))
52352637Seric 	{
52452647Seric 		syserr("I/O read error", cfname);
52552637Seric 		exit(EX_OSFILE);
52652637Seric 	}
52752637Seric 	fclose(cf);
5289381Seric 	FileName = NULL;
52956836Seric 
53067730Seric 	/* initialize host maps from local service tables */
53167730Seric 	inithostmaps();
5324096Seric }
5334096Seric /*
5348547Seric **  TOOMANY -- signal too many of some option
5358547Seric **
5368547Seric **	Parameters:
5378547Seric **		id -- the id of the error line
5388547Seric **		maxcnt -- the maximum possible values
5398547Seric **
5408547Seric **	Returns:
5418547Seric **		none.
5428547Seric **
5438547Seric **	Side Effects:
5448547Seric **		gives a syserr.
5458547Seric */
5468547Seric 
5478547Seric toomany(id, maxcnt)
5488547Seric 	char id;
5498547Seric 	int maxcnt;
5508547Seric {
5519381Seric 	syserr("too many %c lines, %d max", id, maxcnt);
5528547Seric }
5538547Seric /*
5544432Seric **  FILECLASS -- read members of a class from a file
5554432Seric **
5564432Seric **	Parameters:
5574432Seric **		class -- class to define.
5584432Seric **		filename -- name of file to read.
5594432Seric **		fmt -- scanf string to use for match.
56064133Seric **		safe -- if set, this is a safe read.
56164133Seric **		optional -- if set, it is not an error for the file to
56264133Seric **			not exist.
5634432Seric **
5644432Seric **	Returns:
5654432Seric **		none
5664432Seric **
5674432Seric **	Side Effects:
5684432Seric **
5694432Seric **		puts all lines in filename that match a scanf into
5704432Seric **			the named class.
5714432Seric */
5724432Seric 
57364133Seric fileclass(class, filename, fmt, safe, optional)
5744432Seric 	int class;
5754432Seric 	char *filename;
5764432Seric 	char *fmt;
57754973Seric 	bool safe;
57864133Seric 	bool optional;
5794432Seric {
58025808Seric 	FILE *f;
58154973Seric 	struct stat stbuf;
5824432Seric 	char buf[MAXLINE];
5834432Seric 
58466101Seric 	if (tTd(37, 2))
58566101Seric 		printf("fileclass(%s, fmt=%s)\n", filename, fmt);
58666101Seric 
58766031Seric 	if (filename[0] == '|')
58866031Seric 	{
58966031Seric 		syserr("fileclass: pipes (F%c%s) not supported due to security problems",
59066031Seric 			class, filename);
59166031Seric 		return;
59266031Seric 	}
59354973Seric 	if (stat(filename, &stbuf) < 0)
59454973Seric 	{
59566101Seric 		if (tTd(37, 2))
59666101Seric 			printf("  cannot stat (%s)\n", errstring(errno));
59764133Seric 		if (!optional)
59864133Seric 			syserr("fileclass: cannot stat %s", filename);
59954973Seric 		return;
60054973Seric 	}
60154973Seric 	if (!S_ISREG(stbuf.st_mode))
60254973Seric 	{
60354973Seric 		syserr("fileclass: %s not a regular file", filename);
60454973Seric 		return;
60554973Seric 	}
60654973Seric 	if (!safe && access(filename, R_OK) < 0)
60754973Seric 	{
60854973Seric 		syserr("fileclass: access denied on %s", filename);
60954973Seric 		return;
61054973Seric 	}
61154973Seric 	f = fopen(filename, "r");
6124432Seric 	if (f == NULL)
6134432Seric 	{
61454973Seric 		syserr("fileclass: cannot open %s", filename);
6154432Seric 		return;
6164432Seric 	}
6174432Seric 
6184432Seric 	while (fgets(buf, sizeof buf, f) != NULL)
6194432Seric 	{
6204432Seric 		register STAB *s;
62125808Seric 		register char *p;
62225808Seric # ifdef SCANF
6234432Seric 		char wordbuf[MAXNAME+1];
6244432Seric 
6254432Seric 		if (sscanf(buf, fmt, wordbuf) != 1)
6264432Seric 			continue;
62725808Seric 		p = wordbuf;
62856795Seric # else /* SCANF */
62925808Seric 		p = buf;
63056795Seric # endif /* SCANF */
63125808Seric 
63225808Seric 		/*
63325808Seric 		**  Break up the match into words.
63425808Seric 		*/
63525808Seric 
63625808Seric 		while (*p != '\0')
63725808Seric 		{
63825808Seric 			register char *q;
63925808Seric 
64025808Seric 			/* strip leading spaces */
64158050Seric 			while (isascii(*p) && isspace(*p))
64225808Seric 				p++;
64325808Seric 			if (*p == '\0')
64425808Seric 				break;
64525808Seric 
64625808Seric 			/* find the end of the word */
64725808Seric 			q = p;
64858050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
64925808Seric 				p++;
65025808Seric 			if (*p != '\0')
65125808Seric 				*p++ = '\0';
65225808Seric 
65325808Seric 			/* enter the word in the symbol table */
65466101Seric 			setclass(class, q);
65525808Seric 		}
6564432Seric 	}
6574432Seric 
65854973Seric 	(void) fclose(f);
6594432Seric }
6604432Seric /*
6614096Seric **  MAKEMAILER -- define a new mailer.
6624096Seric **
6634096Seric **	Parameters:
66410327Seric **		line -- description of mailer.  This is in labeled
66510327Seric **			fields.  The fields are:
66610327Seric **			   P -- the path to the mailer
66710327Seric **			   F -- the flags associated with the mailer
66810327Seric **			   A -- the argv for this mailer
66910327Seric **			   S -- the sender rewriting set
67010327Seric **			   R -- the recipient rewriting set
67110327Seric **			   E -- the eol string
67210327Seric **			The first word is the canonical name of the mailer.
6734096Seric **
6744096Seric **	Returns:
6754096Seric **		none.
6764096Seric **
6774096Seric **	Side Effects:
6784096Seric **		enters the mailer into the mailer table.
6794096Seric */
6803308Seric 
68121066Seric makemailer(line)
6824096Seric 	char *line;
6834096Seric {
6844096Seric 	register char *p;
6858067Seric 	register struct mailer *m;
6868067Seric 	register STAB *s;
6878067Seric 	int i;
68810327Seric 	char fcode;
68958020Seric 	auto char *endp;
6904096Seric 	extern int NextMailer;
69110327Seric 	extern char **makeargv();
69210327Seric 	extern char *munchstring();
69310701Seric 	extern long atol();
6944096Seric 
69510327Seric 	/* allocate a mailer and set up defaults */
69610327Seric 	m = (struct mailer *) xalloc(sizeof *m);
69710327Seric 	bzero((char *) m, sizeof *m);
69810327Seric 	m->m_eol = "\n";
69967604Seric 	m->m_uid = m->m_gid = 0;
70010327Seric 
70110327Seric 	/* collect the mailer name */
70258050Seric 	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
70310327Seric 		continue;
70410327Seric 	if (*p != '\0')
70510327Seric 		*p++ = '\0';
70610327Seric 	m->m_name = newstr(line);
70710327Seric 
70810327Seric 	/* now scan through and assign info from the fields */
70910327Seric 	while (*p != '\0')
71010327Seric 	{
71158333Seric 		auto char *delimptr;
71258333Seric 
71358050Seric 		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
71410327Seric 			p++;
71510327Seric 
71610327Seric 		/* p now points to field code */
71710327Seric 		fcode = *p;
71810327Seric 		while (*p != '\0' && *p != '=' && *p != ',')
71910327Seric 			p++;
72010327Seric 		if (*p++ != '=')
72110327Seric 		{
72252637Seric 			syserr("mailer %s: `=' expected", m->m_name);
72310327Seric 			return;
72410327Seric 		}
72558050Seric 		while (isascii(*p) && isspace(*p))
72610327Seric 			p++;
72710327Seric 
72810327Seric 		/* p now points to the field body */
72958333Seric 		p = munchstring(p, &delimptr);
73010327Seric 
73110327Seric 		/* install the field into the mailer struct */
73210327Seric 		switch (fcode)
73310327Seric 		{
73410327Seric 		  case 'P':		/* pathname */
73510327Seric 			m->m_mailer = newstr(p);
73610327Seric 			break;
73710327Seric 
73810327Seric 		  case 'F':		/* flags */
73910687Seric 			for (; *p != '\0'; p++)
74058050Seric 				if (!(isascii(*p) && isspace(*p)))
74152637Seric 					setbitn(*p, m->m_flags);
74210327Seric 			break;
74310327Seric 
74410327Seric 		  case 'S':		/* sender rewriting ruleset */
74510327Seric 		  case 'R':		/* recipient rewriting ruleset */
74658020Seric 			i = strtol(p, &endp, 10);
74710327Seric 			if (i < 0 || i >= MAXRWSETS)
74810327Seric 			{
74910327Seric 				syserr("invalid rewrite set, %d max", MAXRWSETS);
75010327Seric 				return;
75110327Seric 			}
75210327Seric 			if (fcode == 'S')
75358020Seric 				m->m_sh_rwset = m->m_se_rwset = i;
75410327Seric 			else
75558020Seric 				m->m_rh_rwset = m->m_re_rwset = i;
75658020Seric 
75758020Seric 			p = endp;
75859985Seric 			if (*p++ == '/')
75958020Seric 			{
76058020Seric 				i = strtol(p, NULL, 10);
76158020Seric 				if (i < 0 || i >= MAXRWSETS)
76258020Seric 				{
76358020Seric 					syserr("invalid rewrite set, %d max",
76458020Seric 						MAXRWSETS);
76558020Seric 					return;
76658020Seric 				}
76758020Seric 				if (fcode == 'S')
76858020Seric 					m->m_sh_rwset = i;
76958020Seric 				else
77058020Seric 					m->m_rh_rwset = i;
77158020Seric 			}
77210327Seric 			break;
77310327Seric 
77410327Seric 		  case 'E':		/* end of line string */
77510327Seric 			m->m_eol = newstr(p);
77610327Seric 			break;
77710327Seric 
77810327Seric 		  case 'A':		/* argument vector */
77910327Seric 			m->m_argv = makeargv(p);
78010327Seric 			break;
78110701Seric 
78210701Seric 		  case 'M':		/* maximum message size */
78310701Seric 			m->m_maxsize = atol(p);
78410701Seric 			break;
78552106Seric 
78652106Seric 		  case 'L':		/* maximum line length */
78752106Seric 			m->m_linelimit = atoi(p);
78852106Seric 			break;
78958935Seric 
79058935Seric 		  case 'D':		/* working directory */
79158935Seric 			m->m_execdir = newstr(p);
79258935Seric 			break;
79367604Seric 
79467896Seric 		  case 'C':		/* default charset */
79567896Seric 			m->m_defcharset = newstr(p);
79667896Seric 			break;
79767896Seric 
79867604Seric 		  case 'U':		/* user id */
79967604Seric 			if (isascii(*p) && !isdigit(*p))
80067604Seric 			{
80167604Seric 				char *q = p;
80267604Seric 				struct passwd *pw;
80367604Seric 
80467604Seric 				while (isascii(*p) && isalnum(*p))
80567604Seric 					p++;
80667604Seric 				while (isascii(*p) && isspace(*p))
80767604Seric 					*p++ = '\0';
80867604Seric 				if (*p != '\0')
80967604Seric 					*p++ = '\0';
81067604Seric 				pw = getpwnam(q);
81167604Seric 				if (pw == NULL)
81267604Seric 					syserr("readcf: mailer U= flag: unknown user %s", q);
81367604Seric 				else
81467604Seric 				{
81567604Seric 					m->m_uid = pw->pw_uid;
81667604Seric 					m->m_gid = pw->pw_gid;
81767604Seric 				}
81867604Seric 			}
81967604Seric 			else
82067604Seric 			{
82167604Seric 				auto char *q;
82267604Seric 
82367604Seric 				m->m_uid = strtol(p, &q, 0);
82467604Seric 				p = q;
82567604Seric 			}
82667604Seric 			while (isascii(*p) && isspace(*p))
82767604Seric 				p++;
82867604Seric 			if (*p == '\0')
82967604Seric 				break;
83067604Seric 			if (isascii(*p) && !isdigit(*p))
83167604Seric 			{
83267604Seric 				char *q = p;
83367604Seric 				struct group *gr;
83467604Seric 
83567604Seric 				while (isascii(*p) && isalnum(*p))
83667604Seric 					p++;
83767604Seric 				*p++ = '\0';
83867604Seric 				gr = getgrnam(q);
83967604Seric 				if (gr == NULL)
84067604Seric 					syserr("readcf: mailer U= flag: unknown group %s", q);
84167604Seric 				else
84267604Seric 					m->m_gid = gr->gr_gid;
84367604Seric 			}
84467604Seric 			else
84567604Seric 			{
84667604Seric 				m->m_gid = strtol(p, NULL, 0);
84767604Seric 			}
84867604Seric 			break;
84910327Seric 		}
85010327Seric 
85158333Seric 		p = delimptr;
85210327Seric 	}
85310327Seric 
85452106Seric 	/* do some heuristic cleanup for back compatibility */
85552106Seric 	if (bitnset(M_LIMITS, m->m_flags))
85652106Seric 	{
85752106Seric 		if (m->m_linelimit == 0)
85852106Seric 			m->m_linelimit = SMTPLINELIM;
85955418Seric 		if (ConfigLevel < 2)
86052106Seric 			setbitn(M_7BITS, m->m_flags);
86152106Seric 	}
86252106Seric 
86358321Seric 	/* do some rationality checking */
86458321Seric 	if (m->m_argv == NULL)
86558321Seric 	{
86658321Seric 		syserr("M%s: A= argument required", m->m_name);
86758321Seric 		return;
86858321Seric 	}
86958321Seric 	if (m->m_mailer == NULL)
87058321Seric 	{
87158321Seric 		syserr("M%s: P= argument required", m->m_name);
87258321Seric 		return;
87358321Seric 	}
87458321Seric 
8754096Seric 	if (NextMailer >= MAXMAILERS)
8764096Seric 	{
8779381Seric 		syserr("too many mailers defined (%d max)", MAXMAILERS);
8784096Seric 		return;
8794096Seric 	}
88057402Seric 
88110327Seric 	s = stab(m->m_name, ST_MAILER, ST_ENTER);
88257402Seric 	if (s->s_mailer != NULL)
88357402Seric 	{
88457402Seric 		i = s->s_mailer->m_mno;
88557402Seric 		free(s->s_mailer);
88657402Seric 	}
88757402Seric 	else
88857402Seric 	{
88957402Seric 		i = NextMailer++;
89057402Seric 	}
89157402Seric 	Mailer[i] = s->s_mailer = m;
89257454Seric 	m->m_mno = i;
89310327Seric }
89410327Seric /*
89510327Seric **  MUNCHSTRING -- translate a string into internal form.
89610327Seric **
89710327Seric **	Parameters:
89810327Seric **		p -- the string to munch.
89958333Seric **		delimptr -- if non-NULL, set to the pointer of the
90058333Seric **			field delimiter character.
90110327Seric **
90210327Seric **	Returns:
90310327Seric **		the munched string.
90410327Seric */
9054096Seric 
90610327Seric char *
90758333Seric munchstring(p, delimptr)
90810327Seric 	register char *p;
90958333Seric 	char **delimptr;
91010327Seric {
91110327Seric 	register char *q;
91210327Seric 	bool backslash = FALSE;
91310327Seric 	bool quotemode = FALSE;
91410327Seric 	static char buf[MAXLINE];
9154096Seric 
91610327Seric 	for (q = buf; *p != '\0'; p++)
9174096Seric 	{
91810327Seric 		if (backslash)
91910327Seric 		{
92010327Seric 			/* everything is roughly literal */
92110357Seric 			backslash = FALSE;
92210327Seric 			switch (*p)
92310327Seric 			{
92410327Seric 			  case 'r':		/* carriage return */
92510327Seric 				*q++ = '\r';
92610327Seric 				continue;
92710327Seric 
92810327Seric 			  case 'n':		/* newline */
92910327Seric 				*q++ = '\n';
93010327Seric 				continue;
93110327Seric 
93210327Seric 			  case 'f':		/* form feed */
93310327Seric 				*q++ = '\f';
93410327Seric 				continue;
93510327Seric 
93610327Seric 			  case 'b':		/* backspace */
93710327Seric 				*q++ = '\b';
93810327Seric 				continue;
93910327Seric 			}
94010327Seric 			*q++ = *p;
94110327Seric 		}
94210327Seric 		else
94310327Seric 		{
94410327Seric 			if (*p == '\\')
94510327Seric 				backslash = TRUE;
94610327Seric 			else if (*p == '"')
94710327Seric 				quotemode = !quotemode;
94810327Seric 			else if (quotemode || *p != ',')
94910327Seric 				*q++ = *p;
95010327Seric 			else
95110327Seric 				break;
95210327Seric 		}
9534096Seric 	}
9544096Seric 
95558333Seric 	if (delimptr != NULL)
95658333Seric 		*delimptr = p;
95710327Seric 	*q++ = '\0';
95810327Seric 	return (buf);
95910327Seric }
96010327Seric /*
96110327Seric **  MAKEARGV -- break up a string into words
96210327Seric **
96310327Seric **	Parameters:
96410327Seric **		p -- the string to break up.
96510327Seric **
96610327Seric **	Returns:
96710327Seric **		a char **argv (dynamically allocated)
96810327Seric **
96910327Seric **	Side Effects:
97010327Seric **		munges p.
97110327Seric */
9724096Seric 
97310327Seric char **
97410327Seric makeargv(p)
97510327Seric 	register char *p;
97610327Seric {
97710327Seric 	char *q;
97810327Seric 	int i;
97910327Seric 	char **avp;
98010327Seric 	char *argv[MAXPV + 1];
98110327Seric 
98210327Seric 	/* take apart the words */
98310327Seric 	i = 0;
98410327Seric 	while (*p != '\0' && i < MAXPV)
9854096Seric 	{
98610327Seric 		q = p;
98758050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
98810327Seric 			p++;
98958050Seric 		while (isascii(*p) && isspace(*p))
99010327Seric 			*p++ = '\0';
99110327Seric 		argv[i++] = newstr(q);
9924096Seric 	}
99310327Seric 	argv[i++] = NULL;
9944096Seric 
99510327Seric 	/* now make a copy of the argv */
99610327Seric 	avp = (char **) xalloc(sizeof *avp * i);
99716893Seric 	bcopy((char *) argv, (char *) avp, sizeof *avp * i);
99810327Seric 
99910327Seric 	return (avp);
10003308Seric }
10013308Seric /*
10023308Seric **  PRINTRULES -- print rewrite rules (for debugging)
10033308Seric **
10043308Seric **	Parameters:
10053308Seric **		none.
10063308Seric **
10073308Seric **	Returns:
10083308Seric **		none.
10093308Seric **
10103308Seric **	Side Effects:
10113308Seric **		prints rewrite rules.
10123308Seric */
10133308Seric 
10143308Seric printrules()
10153308Seric {
10163308Seric 	register struct rewrite *rwp;
10174072Seric 	register int ruleset;
10183308Seric 
10194072Seric 	for (ruleset = 0; ruleset < 10; ruleset++)
10203308Seric 	{
10214072Seric 		if (RewriteRules[ruleset] == NULL)
10224072Seric 			continue;
10238067Seric 		printf("\n----Rule Set %d:", ruleset);
10243308Seric 
10254072Seric 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
10263308Seric 		{
10278067Seric 			printf("\nLHS:");
10288067Seric 			printav(rwp->r_lhs);
10298067Seric 			printf("RHS:");
10308067Seric 			printav(rwp->r_rhs);
10313308Seric 		}
10323308Seric 	}
10333308Seric }
10344319Seric 
10354096Seric /*
10368256Seric **  SETOPTION -- set global processing option
10378256Seric **
10388256Seric **	Parameters:
10398256Seric **		opt -- option name.
10408256Seric **		val -- option value (as a text string).
104121755Seric **		safe -- set if this came from a configuration file.
104221755Seric **			Some options (if set from the command line) will
104321755Seric **			reset the user id to avoid security problems.
10448269Seric **		sticky -- if set, don't let other setoptions override
10458269Seric **			this value.
104658734Seric **		e -- the main envelope.
10478256Seric **
10488256Seric **	Returns:
10498256Seric **		none.
10508256Seric **
10518256Seric **	Side Effects:
10528256Seric **		Sets options as implied by the arguments.
10538256Seric */
10548256Seric 
105510687Seric static BITMAP	StickyOpt;		/* set if option is stuck */
10568269Seric 
105757207Seric 
105866334Seric #if NAMED_BIND
105957207Seric 
106057207Seric struct resolverflags
106157207Seric {
106257207Seric 	char	*rf_name;	/* name of the flag */
106357207Seric 	long	rf_bits;	/* bits to set/clear */
106457207Seric } ResolverFlags[] =
106557207Seric {
106657207Seric 	"debug",	RES_DEBUG,
106757207Seric 	"aaonly",	RES_AAONLY,
106857207Seric 	"usevc",	RES_USEVC,
106957207Seric 	"primary",	RES_PRIMARY,
107057207Seric 	"igntc",	RES_IGNTC,
107157207Seric 	"recurse",	RES_RECURSE,
107257207Seric 	"defnames",	RES_DEFNAMES,
107357207Seric 	"stayopen",	RES_STAYOPEN,
107457207Seric 	"dnsrch",	RES_DNSRCH,
107565583Seric 	"true",		0,		/* to avoid error on old syntax */
107657207Seric 	NULL,		0
107757207Seric };
107857207Seric 
107957207Seric #endif
108057207Seric 
108167614Seric struct optioninfo
108267614Seric {
108367614Seric 	char	*o_name;	/* long name of option */
108467787Seric 	u_char	o_code;		/* short name of option */
108567614Seric 	bool	o_safe;		/* safe for random people to use */
108667614Seric } OptionTab[] =
108767614Seric {
108867707Seric 	"SevenBitInput",	'7',		TRUE,
108967707Seric 	"EightBitMode",		'8',		TRUE,
109067707Seric 	"AliasFile",		'A',		FALSE,
109167707Seric 	"AliasWait",		'a',		FALSE,
109267707Seric 	"BlankSub",		'B',		FALSE,
109367707Seric 	"MinFreeBlocks",	'b',		TRUE,
109467707Seric 	"CheckpointInterval",	'C',		TRUE,
109567707Seric 	"HoldExpensive",	'c',		FALSE,
109667707Seric 	"AutoRebuildAliases",	'D',		FALSE,
109767707Seric 	"DeliveryMode",		'd',		TRUE,
109867707Seric 	"ErrorHeader",		'E',		FALSE,
109967707Seric 	"ErrorMode",		'e',		TRUE,
110067707Seric 	"TempFileMode",		'F',		FALSE,
110167707Seric 	"SaveFromLine",		'f',		FALSE,
110267707Seric 	"MatchGECOS",		'G',		FALSE,
110367707Seric 	"HelpFile",		'H',		FALSE,
110467707Seric 	"MaxHopCount",		'h',		FALSE,
110567707Seric 	"NameServerOptions",	'I',		FALSE,
110667707Seric 	"IgnoreDots",		'i',		TRUE,
110767707Seric 	"ForwardPath",		'J',		FALSE,
110867707Seric 	"SendMimeErrors",	'j',		TRUE,
110967707Seric 	"ConnectionCacheSize",	'k',		FALSE,
111067707Seric 	"ConnectionCacheTimeout", 'K',		FALSE,
111167707Seric 	"UseErrorsTo",		'l',		FALSE,
111267707Seric 	"LogLevel",		'L',		FALSE,
111367707Seric 	"MeToo",		'm',		TRUE,
111467707Seric 	"CheckAliases",		'n',		FALSE,
111567707Seric 	"OldStyleHeaders",	'o',		TRUE,
111667707Seric 	"DaemonPortOptions",	'O',		FALSE,
111767707Seric 	"PrivacyOptions",	'p',		TRUE,
111867707Seric 	"PostmasterCopy",	'P',		FALSE,
111967707Seric 	"QueueFactor",		'q',		FALSE,
112067707Seric 	"QueueDirectory",	'Q',		FALSE,
112167707Seric 	"DontPruneRoutes",	'R',		FALSE,
112267711Seric 	"Timeouts",		'r',		TRUE,
112367707Seric 	"StatusFile",		'S',		FALSE,
112467707Seric 	"SuperSafe",		's',		TRUE,
112567707Seric 	"QueueTimeout",		'T',		FALSE,
112667707Seric 	"TimeZoneSpec",		't',		FALSE,
112767707Seric 	"UserDatabaseSpec",	'U',		FALSE,
112867707Seric 	"DefaultUser",		'u',		FALSE,
112967707Seric 	"FallbackMXhost",	'V',		FALSE,
113067707Seric 	"Verbose",		'v',		TRUE,
113167707Seric 	"TryNullMXList",	'w',		TRUE,
113267707Seric 	"QueueLA",		'x',		FALSE,
113367707Seric 	"RefuseLA",		'X',		FALSE,
113467707Seric 	"RecipientFactor",	'y',		FALSE,
113567707Seric 	"ForkQueueRuns",	'Y',		FALSE,
113667707Seric 	"ClassFactor",		'z',		FALSE,
113767707Seric 	"TimeFactor",		'Z',		FALSE,
113867707Seric #define O_BSP		0x80
113967707Seric 	"BrokenSmtpPeers",	O_BSP,		TRUE,
114067707Seric #define O_SQBH		0x81
114167707Seric 	"SortQueueByHost",	O_SQBH,		TRUE,
114267707Seric #define O_DNICE		0x82
114367707Seric 	"DeliveryNiceness",	O_DNICE,	TRUE,
114467707Seric #define O_MQA		0x83
114567707Seric 	"MinQueueAge",		O_MQA,		TRUE,
114667707Seric #define O_MHSA		0x84
114767707Seric 	"MaxHostStatAge",	O_MHSA,		TRUE,
114867813Seric #define O_DEFCHARSET	0x85
114967813Seric 	"DefaultCharSet",	O_DEFCHARSET,	TRUE,
115067848Seric #define O_SSFILE	0x86
115167848Seric 	"ServiceSwitchFile",	O_SSFILE,	FALSE,
115267707Seric 
115367707Seric 	NULL,			'\0',		FALSE,
115467614Seric };
115567614Seric 
115667614Seric 
115767614Seric 
115858734Seric setoption(opt, val, safe, sticky, e)
115967614Seric 	u_char opt;
11608256Seric 	char *val;
116121755Seric 	bool safe;
11628269Seric 	bool sticky;
116358734Seric 	register ENVELOPE *e;
11648256Seric {
116557207Seric 	register char *p;
116667614Seric 	register struct optioninfo *o;
1167*67903Seric 	char *subopt;
11688265Seric 	extern bool atobool();
116912633Seric 	extern time_t convtime();
117014879Seric 	extern int QueueLA;
117114879Seric 	extern int RefuseLA;
117264718Seric 	extern bool Warn_Q_option;
11738256Seric 
117467736Seric 	errno = 0;
117567614Seric 	if (opt == ' ')
117667614Seric 	{
117767614Seric 		/* full word options */
117867736Seric 		struct optioninfo *sel;
117967614Seric 
118067614Seric 		p = strchr(val, '=');
118167614Seric 		if (p == NULL)
118267614Seric 			p = &val[strlen(val)];
118367614Seric 		while (*--p == ' ')
118467614Seric 			continue;
118567614Seric 		while (*++p == ' ')
118667614Seric 			*p = '\0';
118767731Seric 		if (p == val)
118867731Seric 		{
118967731Seric 			syserr("readcf: null option name");
119067731Seric 			return;
119167731Seric 		}
119267614Seric 		if (*p == '=')
119367614Seric 			*p++ = '\0';
119467614Seric 		while (*p == ' ')
119567614Seric 			p++;
1196*67903Seric 		subopt = strchr(val, '.');
1197*67903Seric 		if (subopt != NULL)
1198*67903Seric 			*subopt++ = '\0';
119967736Seric 		sel = NULL;
120067614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
120167614Seric 		{
120267736Seric 			if (strncasecmp(o->o_name, val, strlen(val)) != 0)
120367736Seric 				continue;
120467736Seric 			if (strlen(o->o_name) == strlen(val))
120567736Seric 			{
120667736Seric 				/* completely specified -- this must be it */
120767736Seric 				sel = NULL;
120867614Seric 				break;
120967736Seric 			}
121067736Seric 			if (sel != NULL)
121167736Seric 				break;
121267736Seric 			sel = o;
121367614Seric 		}
121467736Seric 		if (sel != NULL && o->o_name == NULL)
121567736Seric 			o = sel;
121667736Seric 		else if (o->o_name == NULL)
121767787Seric 		{
121867614Seric 			syserr("readcf: unknown option name %s", val);
121967787Seric 			return;
122067787Seric 		}
122167736Seric 		else if (sel != NULL)
122267736Seric 		{
122367736Seric 			syserr("readcf: ambiguous option name %s (matches %s and %s)",
122467736Seric 				val, sel->o_name, o->o_name);
122567736Seric 			return;
122667736Seric 		}
122767736Seric 		if (strlen(val) != strlen(o->o_name))
122867736Seric 		{
122967736Seric 			bool oldVerbose = Verbose;
123067736Seric 
123167736Seric 			Verbose = TRUE;
123267736Seric 			message("Option %s used as abbreviation for %s",
123367736Seric 				val, o->o_name);
123467736Seric 			Verbose = oldVerbose;
123567736Seric 		}
123667614Seric 		opt = o->o_code;
123767614Seric 		val = p;
123867614Seric 	}
123967614Seric 	else
124067614Seric 	{
124167614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
124267614Seric 		{
124367614Seric 			if (o->o_code == opt)
124467614Seric 				break;
124567614Seric 		}
1246*67903Seric 		subopt = NULL;
124767614Seric 	}
124867614Seric 
12498256Seric 	if (tTd(37, 1))
125067731Seric 	{
125167731Seric 		printf(isascii(opt) && isprint(opt) ?
1252*67903Seric 			    "setoption %s (%c).%s=%s" :
1253*67903Seric 			    "setoption %s (0x%x).%s=%s",
125467614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
1255*67903Seric 			opt,
1256*67903Seric 			subopt == NULL ? "" : subopt,
1257*67903Seric 			val);
125867731Seric 	}
12598256Seric 
12608256Seric 	/*
12618269Seric 	**  See if this option is preset for us.
12628256Seric 	*/
12638256Seric 
126459731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12658269Seric 	{
12669341Seric 		if (tTd(37, 1))
12679341Seric 			printf(" (ignored)\n");
12688269Seric 		return;
12698269Seric 	}
12708269Seric 
127121755Seric 	/*
127221755Seric 	**  Check to see if this option can be specified by this user.
127321755Seric 	*/
127421755Seric 
127563787Seric 	if (!safe && RealUid == 0)
127621755Seric 		safe = TRUE;
127767614Seric 	if (!safe && !o->o_safe)
127821755Seric 	{
127939111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
128021755Seric 		{
128136582Sbostic 			if (tTd(37, 1))
128236582Sbostic 				printf(" (unsafe)");
128363787Seric 			if (RealUid != geteuid())
128436582Sbostic 			{
128551210Seric 				if (tTd(37, 1))
128651210Seric 					printf("(Resetting uid)");
128763787Seric 				(void) setgid(RealGid);
128863787Seric 				(void) setuid(RealUid);
128936582Sbostic 			}
129021755Seric 		}
129121755Seric 	}
129251210Seric 	if (tTd(37, 1))
129317985Seric 		printf("\n");
12948269Seric 
129567614Seric 	switch (opt & 0xff)
12968256Seric 	{
129759709Seric 	  case '7':		/* force seven-bit input */
129867546Seric 		SevenBitInput = atobool(val);
129952106Seric 		break;
130052106Seric 
130167546Seric 	  case '8':		/* handling of 8-bit input */
130267546Seric 		switch (*val)
130367546Seric 		{
130467547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
130567546Seric 			MimeMode = 0;
130667546Seric 			break;
130767546Seric 
130867547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
130967546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
131067546Seric 			break;
131167546Seric 
131267547Seric 		  case 'j':		/* "just send 8" */
131367546Seric 			MimeMode = MM_PASS8BIT;
131467546Seric 			break;
131567546Seric 
131667546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
131767546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
131867546Seric 			break;
131967546Seric 
132067546Seric 		  case 's':		/* strict adherence */
132167546Seric 			MimeMode = MM_CVTMIME;
132267546Seric 			break;
132367546Seric 
132467547Seric 		  case 'a':		/* encode 8 bit if available */
132567546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
132667546Seric 			break;
132767546Seric 
132867547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
132967547Seric 			MimeMode = MM_MIME8BIT;
133067547Seric 			break;
133167547Seric 
133267546Seric 		  default:
133367546Seric 			syserr("Unknown 8-bit mode %c", *val);
133467546Seric 			exit(EX_USAGE);
133567546Seric 		}
133667546Seric 		break;
133767546Seric 
13388256Seric 	  case 'A':		/* set default alias file */
13399381Seric 		if (val[0] == '\0')
134059672Seric 			setalias("aliases");
13419381Seric 		else
134259672Seric 			setalias(val);
13438256Seric 		break;
13448256Seric 
134517474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
134617474Seric 		if (val[0] == '\0')
134764796Seric 			SafeAlias = 5 * 60;		/* five minutes */
134817474Seric 		else
134964796Seric 			SafeAlias = convtime(val, 'm');
135017474Seric 		break;
135117474Seric 
135216843Seric 	  case 'B':		/* substitution for blank character */
135316843Seric 		SpaceSub = val[0];
135416843Seric 		if (SpaceSub == '\0')
135516843Seric 			SpaceSub = ' ';
135616843Seric 		break;
135716843Seric 
135859283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
135959283Seric 		p = strchr(val, '/');
136059283Seric 		if (p != NULL)
136159283Seric 		{
136259283Seric 			*p++ = '\0';
136359283Seric 			MaxMessageSize = atol(p);
136459283Seric 		}
136558082Seric 		MinBlocksFree = atol(val);
136658082Seric 		break;
136758082Seric 
13689284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13699381Seric 		NoConnect = atobool(val);
13709284Seric 		break;
13719284Seric 
137251305Seric 	  case 'C':		/* checkpoint every N addresses */
137351305Seric 		CheckpointInterval = atoi(val);
137424944Seric 		break;
137524944Seric 
13769284Seric 	  case 'd':		/* delivery mode */
13779284Seric 		switch (*val)
13788269Seric 		{
13799284Seric 		  case '\0':
138058734Seric 			e->e_sendmode = SM_DELIVER;
13818269Seric 			break;
13828269Seric 
138310755Seric 		  case SM_QUEUE:	/* queue only */
138410755Seric #ifndef QUEUE
138510755Seric 			syserr("need QUEUE to set -odqueue");
138656795Seric #endif /* QUEUE */
138710755Seric 			/* fall through..... */
138810755Seric 
13899284Seric 		  case SM_DELIVER:	/* do everything */
13909284Seric 		  case SM_FORK:		/* fork after verification */
139158734Seric 			e->e_sendmode = *val;
13928269Seric 			break;
13938269Seric 
13948269Seric 		  default:
13959284Seric 			syserr("Unknown delivery mode %c", *val);
13968269Seric 			exit(EX_USAGE);
13978269Seric 		}
13988269Seric 		break;
13998269Seric 
14009146Seric 	  case 'D':		/* rebuild alias database as needed */
14019381Seric 		AutoRebuild = atobool(val);
14029146Seric 		break;
14039146Seric 
140455372Seric 	  case 'E':		/* error message header/header file */
140555379Seric 		if (*val != '\0')
140655379Seric 			ErrMsgFile = newstr(val);
140755372Seric 		break;
140855372Seric 
14098269Seric 	  case 'e':		/* set error processing mode */
14108269Seric 		switch (*val)
14118269Seric 		{
14129381Seric 		  case EM_QUIET:	/* be silent about it */
14139381Seric 		  case EM_MAIL:		/* mail back */
14149381Seric 		  case EM_BERKNET:	/* do berknet error processing */
14159381Seric 		  case EM_WRITE:	/* write back (or mail) */
14169381Seric 		  case EM_PRINT:	/* print errors normally (default) */
141758734Seric 			e->e_errormode = *val;
14188269Seric 			break;
14198269Seric 		}
14208269Seric 		break;
14218269Seric 
14229049Seric 	  case 'F':		/* file mode */
142317975Seric 		FileMode = atooct(val) & 0777;
14249049Seric 		break;
14259049Seric 
14268269Seric 	  case 'f':		/* save Unix-style From lines on front */
14279381Seric 		SaveFrom = atobool(val);
14288269Seric 		break;
14298269Seric 
143053735Seric 	  case 'G':		/* match recipients against GECOS field */
143153735Seric 		MatchGecos = atobool(val);
143253735Seric 		break;
143353735Seric 
14348256Seric 	  case 'g':		/* default gid */
143567823Seric   g_opt:
143664133Seric 		if (isascii(*val) && isdigit(*val))
143764133Seric 			DefGid = atoi(val);
143864133Seric 		else
143964133Seric 		{
144064133Seric 			register struct group *gr;
144164133Seric 
144264133Seric 			DefGid = -1;
144364133Seric 			gr = getgrnam(val);
144464133Seric 			if (gr == NULL)
144567823Seric 				syserr("readcf: option %c: unknown group %s",
144667823Seric 					opt, val);
144764133Seric 			else
144864133Seric 				DefGid = gr->gr_gid;
144964133Seric 		}
14508256Seric 		break;
14518256Seric 
14528256Seric 	  case 'H':		/* help file */
14539381Seric 		if (val[0] == '\0')
14548269Seric 			HelpFile = "sendmail.hf";
14559381Seric 		else
14569381Seric 			HelpFile = newstr(val);
14578256Seric 		break;
14588256Seric 
145951305Seric 	  case 'h':		/* maximum hop count */
146051305Seric 		MaxHopCount = atoi(val);
146151305Seric 		break;
146251305Seric 
146335651Seric 	  case 'I':		/* use internet domain name server */
146466334Seric #if NAMED_BIND
146557207Seric 		UseNameServer = TRUE;
146657207Seric 		for (p = val; *p != 0; )
146757207Seric 		{
146857207Seric 			bool clearmode;
146957207Seric 			char *q;
147057207Seric 			struct resolverflags *rfp;
147157207Seric 
147257207Seric 			while (*p == ' ')
147357207Seric 				p++;
147457207Seric 			if (*p == '\0')
147557207Seric 				break;
147657207Seric 			clearmode = FALSE;
147757207Seric 			if (*p == '-')
147857207Seric 				clearmode = TRUE;
147957207Seric 			else if (*p != '+')
148057207Seric 				p--;
148157207Seric 			p++;
148257207Seric 			q = p;
148358050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
148457207Seric 				p++;
148557207Seric 			if (*p != '\0')
148657207Seric 				*p++ = '\0';
148757207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
148857207Seric 			{
148957207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
149057207Seric 					break;
149157207Seric 			}
149264923Seric 			if (rfp->rf_name == NULL)
149364923Seric 				syserr("readcf: I option value %s unrecognized", q);
149464923Seric 			else if (clearmode)
149557207Seric 				_res.options &= ~rfp->rf_bits;
149657207Seric 			else
149757207Seric 				_res.options |= rfp->rf_bits;
149857207Seric 		}
149957207Seric 		if (tTd(8, 2))
150057207Seric 			printf("_res.options = %x\n", _res.options);
150157207Seric #else
150257207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
150357207Seric #endif
150435651Seric 		break;
150535651Seric 
15068269Seric 	  case 'i':		/* ignore dot lines in message */
15079381Seric 		IgnrDot = atobool(val);
15088269Seric 		break;
15098269Seric 
151059730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
151159730Seric 		SendMIMEErrors = atobool(val);
151259730Seric 		break;
151359730Seric 
151457136Seric 	  case 'J':		/* .forward search path */
151557136Seric 		ForwardPath = newstr(val);
151657136Seric 		break;
151757136Seric 
151854967Seric 	  case 'k':		/* connection cache size */
151954967Seric 		MaxMciCache = atoi(val);
152056215Seric 		if (MaxMciCache < 0)
152156215Seric 			MaxMciCache = 0;
152254967Seric 		break;
152354967Seric 
152454967Seric 	  case 'K':		/* connection cache timeout */
152558796Seric 		MciCacheTimeout = convtime(val, 'm');
152654967Seric 		break;
152754967Seric 
152861104Seric 	  case 'l':		/* use Errors-To: header */
152961104Seric 		UseErrorsTo = atobool(val);
153061104Seric 		break;
153161104Seric 
15328256Seric 	  case 'L':		/* log level */
153364140Seric 		if (safe || LogLevel < atoi(val))
153464140Seric 			LogLevel = atoi(val);
15358256Seric 		break;
15368256Seric 
15378269Seric 	  case 'M':		/* define macro */
15389381Seric 		define(val[0], newstr(&val[1]), CurEnv);
153916878Seric 		sticky = FALSE;
15408269Seric 		break;
15418269Seric 
15428269Seric 	  case 'm':		/* send to me too */
15439381Seric 		MeToo = atobool(val);
15448269Seric 		break;
15458269Seric 
154625820Seric 	  case 'n':		/* validate RHS in newaliases */
154725820Seric 		CheckAliases = atobool(val);
154825820Seric 		break;
154925820Seric 
155061104Seric 	    /* 'N' available -- was "net name" */
155161104Seric 
155258851Seric 	  case 'O':		/* daemon options */
155358851Seric 		setdaemonoptions(val);
155458851Seric 		break;
155558851Seric 
15568269Seric 	  case 'o':		/* assume old style headers */
15579381Seric 		if (atobool(val))
15589341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
15599341Seric 		else
15609341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
15618269Seric 		break;
15628269Seric 
156358082Seric 	  case 'p':		/* select privacy level */
156458082Seric 		p = val;
156558082Seric 		for (;;)
156658082Seric 		{
156758082Seric 			register struct prival *pv;
156858082Seric 			extern struct prival PrivacyValues[];
156958082Seric 
157058082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
157158082Seric 				p++;
157258082Seric 			if (*p == '\0')
157358082Seric 				break;
157458082Seric 			val = p;
157558082Seric 			while (isascii(*p) && isalnum(*p))
157658082Seric 				p++;
157758082Seric 			if (*p != '\0')
157858082Seric 				*p++ = '\0';
157958082Seric 
158058082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
158158082Seric 			{
158258082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
158358082Seric 					break;
158458082Seric 			}
158558886Seric 			if (pv->pv_name == NULL)
158658886Seric 				syserr("readcf: Op line: %s unrecognized", val);
158758082Seric 			PrivacyFlags |= pv->pv_flag;
158858082Seric 		}
158958082Seric 		break;
159058082Seric 
159124944Seric 	  case 'P':		/* postmaster copy address for returned mail */
159224944Seric 		PostMasterCopy = newstr(val);
159324944Seric 		break;
159424944Seric 
159524944Seric 	  case 'q':		/* slope of queue only function */
159624944Seric 		QueueFactor = atoi(val);
159724944Seric 		break;
159824944Seric 
15998256Seric 	  case 'Q':		/* queue directory */
16009381Seric 		if (val[0] == '\0')
16018269Seric 			QueueDir = "mqueue";
16029381Seric 		else
16039381Seric 			QueueDir = newstr(val);
160458789Seric 		if (RealUid != 0 && !safe)
160564718Seric 			Warn_Q_option = TRUE;
16068256Seric 		break;
16078256Seric 
160858148Seric 	  case 'R':		/* don't prune routes */
160958148Seric 		DontPruneRoutes = atobool(val);
161058148Seric 		break;
161158148Seric 
16128256Seric 	  case 'r':		/* read timeout */
1613*67903Seric 		if (subopt == NULL)
1614*67903Seric 			inittimeouts(val);
1615*67903Seric 		else
1616*67903Seric 			settimeout(subopt, val);
16178256Seric 		break;
16188256Seric 
16198256Seric 	  case 'S':		/* status file */
16209381Seric 		if (val[0] == '\0')
16218269Seric 			StatFile = "sendmail.st";
16229381Seric 		else
16239381Seric 			StatFile = newstr(val);
16248256Seric 		break;
16258256Seric 
16268265Seric 	  case 's':		/* be super safe, even if expensive */
16279381Seric 		SuperSafe = atobool(val);
16288256Seric 		break;
16298256Seric 
16308256Seric 	  case 'T':		/* queue timeout */
163158737Seric 		p = strchr(val, '/');
163258737Seric 		if (p != NULL)
163358737Seric 		{
163458737Seric 			*p++ = '\0';
1635*67903Seric 			settimeout("queuewarn", p);
163658737Seric 		}
1637*67903Seric 		settimeout("queuereturn", val);
163854967Seric 		break;
16398256Seric 
16408265Seric 	  case 't':		/* time zone name */
164152106Seric 		TimeZoneSpec = newstr(val);
16428265Seric 		break;
16438265Seric 
164450556Seric 	  case 'U':		/* location of user database */
164551360Seric 		UdbSpec = newstr(val);
164650556Seric 		break;
164750556Seric 
16488256Seric 	  case 'u':		/* set default uid */
164967823Seric 		for (p = val; *p != '\0'; p++)
165067823Seric 		{
165167823Seric 			if (*p == '.' || *p == '/' || *p == ':')
165267823Seric 			{
165367823Seric 				*p++ = '\0';
165467823Seric 				break;
165567823Seric 			}
165667823Seric 		}
165764133Seric 		if (isascii(*val) && isdigit(*val))
165864133Seric 			DefUid = atoi(val);
165964133Seric 		else
166064133Seric 		{
166164133Seric 			register struct passwd *pw;
166264133Seric 
166364133Seric 			DefUid = -1;
166464133Seric 			pw = getpwnam(val);
166564133Seric 			if (pw == NULL)
166664133Seric 				syserr("readcf: option u: unknown user %s", val);
166764133Seric 			else
166867823Seric 			{
166964133Seric 				DefUid = pw->pw_uid;
167067823Seric 				DefGid = pw->pw_gid;
167167823Seric 			}
167264133Seric 		}
167340973Sbostic 		setdefuser();
16748256Seric 
167567823Seric 		/* handle the group if it is there */
167667823Seric 		if (*p == '\0')
167767823Seric 			break;
167867823Seric 		val = p;
167967823Seric 		goto g_opt;
168067823Seric 
168158851Seric 	  case 'V':		/* fallback MX host */
168258851Seric 		FallBackMX = newstr(val);
168358851Seric 		break;
168458851Seric 
16858269Seric 	  case 'v':		/* run in verbose mode */
16869381Seric 		Verbose = atobool(val);
16878256Seric 		break;
16888256Seric 
168963837Seric 	  case 'w':		/* if we are best MX, try host directly */
169063837Seric 		TryNullMXList = atobool(val);
169163837Seric 		break;
169261104Seric 
169361104Seric 	    /* 'W' available -- was wizard password */
169461104Seric 
169514879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
169614879Seric 		QueueLA = atoi(val);
169714879Seric 		break;
169814879Seric 
169914879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
170014879Seric 		RefuseLA = atoi(val);
170114879Seric 		break;
170214879Seric 
170324981Seric 	  case 'y':		/* work recipient factor */
170424981Seric 		WkRecipFact = atoi(val);
170524981Seric 		break;
170624981Seric 
170724981Seric 	  case 'Y':		/* fork jobs during queue runs */
170824952Seric 		ForkQueueRuns = atobool(val);
170924952Seric 		break;
171024952Seric 
171124981Seric 	  case 'z':		/* work message class factor */
171224981Seric 		WkClassFact = atoi(val);
171324981Seric 		break;
171424981Seric 
171524981Seric 	  case 'Z':		/* work time factor */
171624981Seric 		WkTimeFact = atoi(val);
171724981Seric 		break;
171824981Seric 
171967614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
172067614Seric 		BrokenSmtpPeers = atobool(val);
172167614Seric 		break;
172267614Seric 
172367614Seric 	  case O_SQBH:		/* sort work queue by host first */
172467614Seric 		SortQueueByHost = atobool(val);
172567614Seric 		break;
172667614Seric 
172767707Seric 	  case O_DNICE:		/* delivery nice value */
172867707Seric 		DeliveryNiceness = atoi(val);
172967707Seric 		break;
173067707Seric 
173167707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
173267707Seric 		MinQueueAge = convtime(val, 'm');
173367707Seric 		break;
173467707Seric 
173567707Seric 	  case O_MHSA:		/* maximum age of cached host status */
173667707Seric 		MaxHostStatAge = convtime(val, 'm');
173767707Seric 		break;
173867707Seric 
173967813Seric 	  case O_DEFCHARSET:	/* default character set for mimefying */
174067814Seric 		DefaultCharSet = newstr(val);
174167813Seric 		break;
174267813Seric 
174367848Seric 	  case O_SSFILE:	/* service switch file */
174467848Seric 		ServiceSwitchFile = newstr(val);
174567848Seric 		break;
174667848Seric 
17478256Seric 	  default:
17488256Seric 		break;
17498256Seric 	}
175016878Seric 	if (sticky)
175116878Seric 		setbitn(opt, StickyOpt);
17529188Seric 	return;
17538256Seric }
175410687Seric /*
175510687Seric **  SETCLASS -- set a word into a class
175610687Seric **
175710687Seric **	Parameters:
175810687Seric **		class -- the class to put the word in.
175910687Seric **		word -- the word to enter
176010687Seric **
176110687Seric **	Returns:
176210687Seric **		none.
176310687Seric **
176410687Seric **	Side Effects:
176510687Seric **		puts the word into the symbol table.
176610687Seric */
176710687Seric 
176810687Seric setclass(class, word)
176910687Seric 	int class;
177010687Seric 	char *word;
177110687Seric {
177210687Seric 	register STAB *s;
177310687Seric 
177457943Seric 	if (tTd(37, 8))
177564326Seric 		printf("setclass(%c, %s)\n", class, word);
177610687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
177710687Seric 	setbitn(class, s->s_class);
177810687Seric }
177953654Seric /*
178053654Seric **  MAKEMAPENTRY -- create a map entry
178153654Seric **
178253654Seric **	Parameters:
178353654Seric **		line -- the config file line
178453654Seric **
178553654Seric **	Returns:
178653654Seric **		TRUE if it successfully entered the map entry.
178753654Seric **		FALSE otherwise (usually syntax error).
178853654Seric **
178953654Seric **	Side Effects:
179053654Seric **		Enters the map into the dictionary.
179153654Seric */
179253654Seric 
179353654Seric void
179453654Seric makemapentry(line)
179553654Seric 	char *line;
179653654Seric {
179753654Seric 	register char *p;
179853654Seric 	char *mapname;
179953654Seric 	char *classname;
180064078Seric 	register STAB *s;
180153654Seric 	STAB *class;
180253654Seric 
180358050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
180453654Seric 		continue;
180558050Seric 	if (!(isascii(*p) && isalnum(*p)))
180653654Seric 	{
180753654Seric 		syserr("readcf: config K line: no map name");
180853654Seric 		return;
180953654Seric 	}
181053654Seric 
181153654Seric 	mapname = p;
181267848Seric 	while ((isascii(*++p) && isalnum(*p)) || *p == '.')
181353654Seric 		continue;
181453654Seric 	if (*p != '\0')
181553654Seric 		*p++ = '\0';
181658050Seric 	while (isascii(*p) && isspace(*p))
181753654Seric 		p++;
181858050Seric 	if (!(isascii(*p) && isalnum(*p)))
181953654Seric 	{
182053654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
182153654Seric 		return;
182253654Seric 	}
182353654Seric 	classname = p;
182458050Seric 	while (isascii(*++p) && isalnum(*p))
182553654Seric 		continue;
182653654Seric 	if (*p != '\0')
182753654Seric 		*p++ = '\0';
182858050Seric 	while (isascii(*p) && isspace(*p))
182953654Seric 		p++;
183053654Seric 
183153654Seric 	/* look up the class */
183253654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
183353654Seric 	if (class == NULL)
183453654Seric 	{
183553654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
183653654Seric 		return;
183753654Seric 	}
183853654Seric 
183953654Seric 	/* enter the map */
184064078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
184164078Seric 	s->s_map.map_class = &class->s_mapclass;
184264078Seric 	s->s_map.map_mname = newstr(mapname);
184353654Seric 
184464078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
184564078Seric 		s->s_map.map_mflags |= MF_VALID;
184664078Seric 
184764078Seric 	if (tTd(37, 5))
184864078Seric 	{
184964078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
185064078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
185164078Seric 			s->s_map.map_mflags,
185264078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
185364078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
185464078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
185564078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
185664078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
185764078Seric 	}
185853654Seric }
185958112Seric /*
1860*67903Seric **  INITTIMEOUTS -- parse and set timeout values
186158112Seric **
186258112Seric **	Parameters:
186358112Seric **		val -- a pointer to the values.  If NULL, do initial
186458112Seric **			settings.
186558112Seric **
186658112Seric **	Returns:
186758112Seric **		none.
186858112Seric **
186958112Seric **	Side Effects:
187058112Seric **		Initializes the TimeOuts structure
187158112Seric */
187258112Seric 
187364255Seric #define SECONDS
187458112Seric #define MINUTES	* 60
187558112Seric #define HOUR	* 3600
187658112Seric 
1877*67903Seric inittimeouts(val)
187858112Seric 	register char *val;
187958112Seric {
188058112Seric 	register char *p;
188158671Seric 	extern time_t convtime();
188258112Seric 
188358112Seric 	if (val == NULL)
188458112Seric 	{
188558112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
188658112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
188758112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
188858112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
188958112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
189058112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
189158112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
189258112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
189358112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
189458112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
189558112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
189664255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
189767711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
189858112Seric 		return;
189958112Seric 	}
190058112Seric 
190158112Seric 	for (;; val = p)
190258112Seric 	{
190358112Seric 		while (isascii(*val) && isspace(*val))
190458112Seric 			val++;
190558112Seric 		if (*val == '\0')
190658112Seric 			break;
190758112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
190858112Seric 			continue;
190958112Seric 		if (*p != '\0')
191058112Seric 			*p++ = '\0';
191158112Seric 
191258112Seric 		if (isascii(*val) && isdigit(*val))
191358112Seric 		{
191458112Seric 			/* old syntax -- set everything */
191558796Seric 			TimeOuts.to_mail = convtime(val, 'm');
191658112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
191758112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
191858112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
191958112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
192058112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
192158112Seric 			continue;
192258112Seric 		}
192358112Seric 		else
192458112Seric 		{
192567711Seric 			register char *q = strchr(val, ':');
192658112Seric 
192767711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
192858112Seric 			{
192958112Seric 				/* syntax error */
193058112Seric 				continue;
193158112Seric 			}
193258112Seric 			*q++ = '\0';
1933*67903Seric 			settimeout(val, q);
1934*67903Seric 		}
1935*67903Seric 	}
1936*67903Seric }
1937*67903Seric /*
1938*67903Seric **  SETTIMEOUT -- set an individual timeout
1939*67903Seric **
1940*67903Seric **	Parameters:
1941*67903Seric **		name -- the name of the timeout.
1942*67903Seric **		val -- the value of the timeout.
1943*67903Seric **
1944*67903Seric **	Returns:
1945*67903Seric **		none.
1946*67903Seric */
194758112Seric 
1948*67903Seric settimeout(name, val)
1949*67903Seric 	char *name;
1950*67903Seric 	char *val;
1951*67903Seric {
1952*67903Seric 	register char *p;
1953*67903Seric 	time_t to;
1954*67903Seric 	extern time_t convtime();
1955*67903Seric 
1956*67903Seric 	to = convtime(val, 'm');
1957*67903Seric 	p = strchr(name, '.');
1958*67903Seric 	if (p != NULL)
1959*67903Seric 		*p++ = '\0';
1960*67903Seric 
1961*67903Seric 	if (strcasecmp(name, "initial") == 0)
1962*67903Seric 		TimeOuts.to_initial = to;
1963*67903Seric 	else if (strcasecmp(name, "mail") == 0)
1964*67903Seric 		TimeOuts.to_mail = to;
1965*67903Seric 	else if (strcasecmp(name, "rcpt") == 0)
1966*67903Seric 		TimeOuts.to_rcpt = to;
1967*67903Seric 	else if (strcasecmp(name, "datainit") == 0)
1968*67903Seric 		TimeOuts.to_datainit = to;
1969*67903Seric 	else if (strcasecmp(name, "datablock") == 0)
1970*67903Seric 		TimeOuts.to_datablock = to;
1971*67903Seric 	else if (strcasecmp(name, "datafinal") == 0)
1972*67903Seric 		TimeOuts.to_datafinal = to;
1973*67903Seric 	else if (strcasecmp(name, "command") == 0)
1974*67903Seric 		TimeOuts.to_nextcommand = to;
1975*67903Seric 	else if (strcasecmp(name, "rset") == 0)
1976*67903Seric 		TimeOuts.to_rset = to;
1977*67903Seric 	else if (strcasecmp(name, "helo") == 0)
1978*67903Seric 		TimeOuts.to_helo = to;
1979*67903Seric 	else if (strcasecmp(name, "quit") == 0)
1980*67903Seric 		TimeOuts.to_quit = to;
1981*67903Seric 	else if (strcasecmp(name, "misc") == 0)
1982*67903Seric 		TimeOuts.to_miscshort = to;
1983*67903Seric 	else if (strcasecmp(name, "ident") == 0)
1984*67903Seric 		TimeOuts.to_ident = to;
1985*67903Seric 	else if (strcasecmp(name, "fileopen") == 0)
1986*67903Seric 		TimeOuts.to_fileopen = to;
1987*67903Seric 	else if (strcasecmp(name, "queuewarn") == 0)
1988*67903Seric 	{
1989*67903Seric 		to = convtime(val, 'h');
1990*67903Seric 		if (p == NULL || strcmp(p, "*") == NULL)
1991*67903Seric 		{
1992*67903Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = to;
1993*67903Seric 			TimeOuts.to_q_warning[TOC_URGENT] = to;
1994*67903Seric 			TimeOuts.to_q_warning[TOC_NONURGENT] = to;
199558112Seric 		}
1996*67903Seric 		else if (strcasecmp(p, "normal") == 0)
1997*67903Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = to;
1998*67903Seric 		else if (strcasecmp(p, "urgent") == 0)
1999*67903Seric 			TimeOuts.to_q_warning[TOC_URGENT] = to;
2000*67903Seric 		else if (strcasecmp(p, "non-urgent") == 0)
2001*67903Seric 			TimeOuts.to_q_warning[TOC_NONURGENT] = to;
2002*67903Seric 		else
2003*67903Seric 			syserr("settimeout: invalid queuewarn subtimeout %s", p);
200458112Seric 	}
2005*67903Seric 	else if (strcasecmp(name, "queuereturn") == 0)
2006*67903Seric 	{
2007*67903Seric 		to = convtime(val, 'd');
2008*67903Seric 		if (p == NULL || strcmp(p, "*") == 0)
2009*67903Seric 		{
2010*67903Seric 			TimeOuts.to_q_return[TOC_NORMAL] = to;
2011*67903Seric 			TimeOuts.to_q_return[TOC_URGENT] = to;
2012*67903Seric 			TimeOuts.to_q_return[TOC_NONURGENT] = to;
2013*67903Seric 		}
2014*67903Seric 		else if (strcasecmp(p, "normal") == 0)
2015*67903Seric 			TimeOuts.to_q_return[TOC_NORMAL] = to;
2016*67903Seric 		else if (strcasecmp(p, "urgent") == 0)
2017*67903Seric 			TimeOuts.to_q_return[TOC_URGENT] = to;
2018*67903Seric 		else if (strcasecmp(p, "non-urgent") == 0)
2019*67903Seric 			TimeOuts.to_q_return[TOC_NONURGENT] = to;
2020*67903Seric 		else
2021*67903Seric 			syserr("settimeout: invalid queuereturn subtimeout %s", p);
2022*67903Seric 	}
2023*67903Seric 	else
2024*67903Seric 		syserr("settimeout: invalid timeout %s", name);
202558112Seric }
2026