xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67769)
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*67769Seric static char sccsid[] = "@(#)readcf.c	8.38 (Berkeley) 09/08/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;
80*67769Seric 	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];
8710709Seric 	extern char *munchstring();
8853654Seric 	extern void makemapentry();
893308Seric 
9052647Seric 	FileName = cfname;
9152647Seric 	LineNumber = 0;
9252647Seric 
933308Seric 	cf = fopen(cfname, "r");
943308Seric 	if (cf == NULL)
953308Seric 	{
9652647Seric 		syserr("cannot open");
973308Seric 		exit(EX_OSFILE);
983308Seric 	}
993308Seric 
10052647Seric 	if (fstat(fileno(cf), &statb) < 0)
10152647Seric 	{
10252647Seric 		syserr("cannot fstat");
10352647Seric 		exit(EX_OSFILE);
10452647Seric 	}
10552647Seric 
10652647Seric 	if (!S_ISREG(statb.st_mode))
10752647Seric 	{
10852647Seric 		syserr("not a plain file");
10952647Seric 		exit(EX_OSFILE);
11052647Seric 	}
11152647Seric 
11252647Seric 	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
11352647Seric 	{
11453037Seric 		if (OpMode == MD_DAEMON || OpMode == MD_FREEZE)
11553037Seric 			fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
11653037Seric 				FileName);
11753037Seric #ifdef LOG
11853037Seric 		if (LogLevel > 0)
11953037Seric 			syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
12053037Seric 				FileName);
12153037Seric #endif
12252647Seric 	}
12352647Seric 
12459254Seric #ifdef XLA
12559254Seric 	xla_zero();
12659254Seric #endif
12759254Seric 
12857135Seric 	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
1293308Seric 	{
13057135Seric 		if (bp[0] == '#')
13157135Seric 		{
13257135Seric 			if (bp != buf)
13357135Seric 				free(bp);
13452637Seric 			continue;
13557135Seric 		}
13652637Seric 
137*67769Seric 		/* do macro expansion mappings */
13857135Seric 		for (p = bp; *p != '\0'; p++)
13916157Seric 		{
14057135Seric 			if (*p == '#' && p > bp && ConfigLevel >= 3)
14152647Seric 			{
14252647Seric 				/* this is an on-line comment */
14352647Seric 				register char *e;
14452647Seric 
14558050Seric 				switch (*--p & 0377)
14652647Seric 				{
14758050Seric 				  case MACROEXPAND:
14852647Seric 					/* it's from $# -- let it go through */
14952647Seric 					p++;
15052647Seric 					break;
15152647Seric 
15252647Seric 				  case '\\':
15352647Seric 					/* it's backslash escaped */
15452647Seric 					(void) strcpy(p, p + 1);
15552647Seric 					break;
15652647Seric 
15752647Seric 				  default:
15852647Seric 					/* delete preceeding white space */
15958050Seric 					while (isascii(*p) && isspace(*p) && p > bp)
16052647Seric 						p--;
16156795Seric 					if ((e = strchr(++p, '\n')) != NULL)
16252647Seric 						(void) strcpy(p, e);
16352647Seric 					else
16452647Seric 						p[0] = p[1] = '\0';
16552647Seric 					break;
16652647Seric 				}
16752647Seric 				continue;
16852647Seric 			}
16952647Seric 
170*67769Seric 			if (*p != '$' || p[1] == '\0')
17116157Seric 				continue;
17216157Seric 
17316157Seric 			if (p[1] == '$')
17416157Seric 			{
17516157Seric 				/* actual dollar sign.... */
17623111Seric 				(void) strcpy(p, p + 1);
17716157Seric 				continue;
17816157Seric 			}
17916157Seric 
18016157Seric 			/* convert to macro expansion character */
181*67769Seric 			*p++ = MACROEXPAND;
182*67769Seric 
183*67769Seric 			/* convert macro name to code */
184*67769Seric 			*p = macid(p, &ep);
185*67769Seric 			if (ep != p)
186*67769Seric 				strcpy(p + 1, ep);
18716157Seric 		}
18816157Seric 
18916157Seric 		/* interpret this line */
19064718Seric 		errno = 0;
19157135Seric 		switch (bp[0])
1923308Seric 		{
1933308Seric 		  case '\0':
1943308Seric 		  case '#':		/* comment */
1953308Seric 			break;
1963308Seric 
1973308Seric 		  case 'R':		/* rewriting rule */
19857135Seric 			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
1993308Seric 				continue;
2003308Seric 
2013308Seric 			if (*p == '\0')
2025909Seric 			{
20365821Seric 				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
2045909Seric 				break;
2055909Seric 			}
2065909Seric 
2075909Seric 			/* allocate space for the rule header */
2085909Seric 			if (rwp == NULL)
2095909Seric 			{
2105909Seric 				RewriteRules[ruleset] = rwp =
2115909Seric 					(struct rewrite *) xalloc(sizeof *rwp);
2125909Seric 			}
2133308Seric 			else
2143308Seric 			{
2155909Seric 				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
2165909Seric 				rwp = rwp->r_next;
2175909Seric 			}
2185909Seric 			rwp->r_next = NULL;
2193308Seric 
2205909Seric 			/* expand and save the LHS */
2215909Seric 			*p = '\0';
22257135Seric 			expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
22365066Seric 			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
22465066Seric 					     sizeof pvpbuf, NULL);
22557589Seric 			nfuzzy = 0;
2265909Seric 			if (rwp->r_lhs != NULL)
22757589Seric 			{
22857589Seric 				register char **ap;
22957589Seric 
2305909Seric 				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
23157589Seric 
23257589Seric 				/* count the number of fuzzy matches in LHS */
23357589Seric 				for (ap = rwp->r_lhs; *ap != NULL; ap++)
23457589Seric 				{
23558148Seric 					char *botch;
23658148Seric 
23758148Seric 					botch = NULL;
23858050Seric 					switch (**ap & 0377)
23957589Seric 					{
24057589Seric 					  case MATCHZANY:
24157589Seric 					  case MATCHANY:
24257589Seric 					  case MATCHONE:
24357589Seric 					  case MATCHCLASS:
24457589Seric 					  case MATCHNCLASS:
24557589Seric 						nfuzzy++;
24658148Seric 						break;
24758148Seric 
24858148Seric 					  case MATCHREPL:
24958148Seric 						botch = "$0-$9";
25058148Seric 						break;
25158148Seric 
25258148Seric 					  case CANONNET:
25358148Seric 						botch = "$#";
25458148Seric 						break;
25558148Seric 
25658148Seric 					  case CANONUSER:
25758148Seric 						botch = "$:";
25858148Seric 						break;
25958148Seric 
26058148Seric 					  case CALLSUBR:
26158148Seric 						botch = "$>";
26258148Seric 						break;
26358148Seric 
26458148Seric 					  case CONDIF:
26558148Seric 						botch = "$?";
26658148Seric 						break;
26758148Seric 
26858148Seric 					  case CONDELSE:
26958148Seric 						botch = "$|";
27058148Seric 						break;
27158148Seric 
27258148Seric 					  case CONDFI:
27358148Seric 						botch = "$.";
27458148Seric 						break;
27558148Seric 
27658148Seric 					  case HOSTBEGIN:
27758148Seric 						botch = "$[";
27858148Seric 						break;
27958148Seric 
28058148Seric 					  case HOSTEND:
28158148Seric 						botch = "$]";
28258148Seric 						break;
28358148Seric 
28458148Seric 					  case LOOKUPBEGIN:
28558148Seric 						botch = "$(";
28658148Seric 						break;
28758148Seric 
28858148Seric 					  case LOOKUPEND:
28958148Seric 						botch = "$)";
29058148Seric 						break;
29157589Seric 					}
29258148Seric 					if (botch != NULL)
29358148Seric 						syserr("Inappropriate use of %s on LHS",
29458148Seric 							botch);
29557589Seric 				}
29657589Seric 			}
29756678Seric 			else
29856678Seric 				syserr("R line: null LHS");
2995909Seric 
3005909Seric 			/* expand and save the RHS */
3015909Seric 			while (*++p == '\t')
3025909Seric 				continue;
3037231Seric 			q = p;
3047231Seric 			while (*p != '\0' && *p != '\t')
3057231Seric 				p++;
3067231Seric 			*p = '\0';
30755012Seric 			expand(q, exbuf, &exbuf[sizeof exbuf], e);
30865066Seric 			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
30965066Seric 					     sizeof pvpbuf, NULL);
3105909Seric 			if (rwp->r_rhs != NULL)
31157589Seric 			{
31257589Seric 				register char **ap;
31357589Seric 
3145909Seric 				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
31557589Seric 
31657589Seric 				/* check no out-of-bounds replacements */
31757589Seric 				nfuzzy += '0';
31857589Seric 				for (ap = rwp->r_rhs; *ap != NULL; ap++)
31957589Seric 				{
32058148Seric 					char *botch;
32158148Seric 
32258148Seric 					botch = NULL;
32358148Seric 					switch (**ap & 0377)
32457589Seric 					{
32558148Seric 					  case MATCHREPL:
32658148Seric 						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
32758148Seric 						{
32858148Seric 							syserr("replacement $%c out of bounds",
32958148Seric 								(*ap)[1]);
33058148Seric 						}
33158148Seric 						break;
33258148Seric 
33358148Seric 					  case MATCHZANY:
33458148Seric 						botch = "$*";
33558148Seric 						break;
33658148Seric 
33758148Seric 					  case MATCHANY:
33858148Seric 						botch = "$+";
33958148Seric 						break;
34058148Seric 
34158148Seric 					  case MATCHONE:
34258148Seric 						botch = "$-";
34358148Seric 						break;
34458148Seric 
34558148Seric 					  case MATCHCLASS:
34658148Seric 						botch = "$=";
34758148Seric 						break;
34858148Seric 
34958148Seric 					  case MATCHNCLASS:
35058148Seric 						botch = "$~";
35158148Seric 						break;
35257589Seric 					}
35358148Seric 					if (botch != NULL)
35458148Seric 						syserr("Inappropriate use of %s on RHS",
35558148Seric 							botch);
35657589Seric 				}
35757589Seric 			}
35856678Seric 			else
35956678Seric 				syserr("R line: null RHS");
3603308Seric 			break;
3613308Seric 
3624072Seric 		  case 'S':		/* select rewriting set */
36364440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
36464440Seric 				continue;
36564440Seric 			if (!isascii(*p) || !isdigit(*p))
36664440Seric 			{
36764440Seric 				syserr("invalid argument to S line: \"%.20s\"",
36864440Seric 					&bp[1]);
36964440Seric 				break;
37064440Seric 			}
37164440Seric 			ruleset = atoi(p);
3728056Seric 			if (ruleset >= MAXRWSETS || ruleset < 0)
3738056Seric 			{
3749381Seric 				syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
3758056Seric 				ruleset = 0;
3768056Seric 			}
3774072Seric 			rwp = NULL;
3784072Seric 			break;
3794072Seric 
3803308Seric 		  case 'D':		/* macro definition */
381*67769Seric 			mid = macid(&bp[1], &ep);
382*67769Seric 			p = munchstring(ep, NULL);
383*67769Seric 			define(mid, newstr(p), e);
3843308Seric 			break;
3853308Seric 
3863387Seric 		  case 'H':		/* required header line */
38757135Seric 			(void) chompheader(&bp[1], TRUE, e);
3883387Seric 			break;
3893387Seric 
3904061Seric 		  case 'C':		/* word class */
3914432Seric 			/* scan the list of words and set class for all */
392*67769Seric 			mid = macid(&bp[1], &ep);
393*67769Seric 			expand(ep, exbuf, &exbuf[sizeof exbuf], e);
39464121Seric 			for (p = exbuf; *p != '\0'; )
3954061Seric 			{
3964061Seric 				register char *wd;
3974061Seric 				char delim;
3984061Seric 
39958050Seric 				while (*p != '\0' && isascii(*p) && isspace(*p))
4004061Seric 					p++;
4014061Seric 				wd = p;
40258050Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4034061Seric 					p++;
4044061Seric 				delim = *p;
4054061Seric 				*p = '\0';
4064061Seric 				if (wd[0] != '\0')
407*67769Seric 					setclass(mid, wd);
4084061Seric 				*p = delim;
4094061Seric 			}
4104061Seric 			break;
4114061Seric 
41259272Seric 		  case 'F':		/* word class from file */
413*67769Seric 			mid = macid(&bp[1], &ep);
414*67769Seric 			for (p = ep; isascii(*p) && isspace(*p); )
41564133Seric 				p++;
41664133Seric 			if (p[0] == '-' && p[1] == 'o')
41764133Seric 			{
41864133Seric 				optional = TRUE;
41964133Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
42064133Seric 					p++;
42164133Seric 				while (isascii(*p) && isspace(*p))
42267615Seric 					p++;
42364133Seric 			}
42464133Seric 			else
42564133Seric 				optional = FALSE;
42664133Seric 			file = p;
42764133Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
42864133Seric 				p++;
42959272Seric 			if (*p == '\0')
43059272Seric 				p = "%s";
43159272Seric 			else
43259272Seric 			{
43359272Seric 				*p = '\0';
43459272Seric 				while (isascii(*++p) && isspace(*p))
43559272Seric 					continue;
43659272Seric 			}
43764133Seric 			fileclass(bp[1], file, p, safe, optional);
43859272Seric 			break;
43959272Seric 
44059156Seric #ifdef XLA
44159156Seric 		  case 'L':		/* extended load average description */
44259156Seric 			xla_init(&bp[1]);
44359156Seric 			break;
44459156Seric #endif
44559156Seric 
4464096Seric 		  case 'M':		/* define mailer */
44757135Seric 			makemailer(&bp[1]);
4484096Seric 			break;
4494096Seric 
4508252Seric 		  case 'O':		/* set option */
45158734Seric 			setoption(bp[1], &bp[2], safe, FALSE, e);
4528252Seric 			break;
4538252Seric 
4548252Seric 		  case 'P':		/* set precedence */
4558252Seric 			if (NumPriorities >= MAXPRIORITIES)
4568252Seric 			{
4578547Seric 				toomany('P', MAXPRIORITIES);
4588252Seric 				break;
4598252Seric 			}
46057135Seric 			for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
4618252Seric 				continue;
4628252Seric 			if (*p == '\0')
4638252Seric 				goto badline;
4648252Seric 			*p = '\0';
46557135Seric 			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
4668252Seric 			Priorities[NumPriorities].pri_val = atoi(++p);
4678252Seric 			NumPriorities++;
4688252Seric 			break;
4698252Seric 
4708547Seric 		  case 'T':		/* trusted user(s) */
47158161Seric 			/* this option is obsolete, but will be ignored */
4728547Seric 			break;
4738547Seric 
47452645Seric 		  case 'V':		/* configuration syntax version */
47564440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
47664440Seric 				continue;
47764440Seric 			if (!isascii(*p) || !isdigit(*p))
47864440Seric 			{
47964440Seric 				syserr("invalid argument to V line: \"%.20s\"",
48064440Seric 					&bp[1]);
48164440Seric 				break;
48264440Seric 			}
48364718Seric 			ConfigLevel = strtol(p, &ep, 10);
48464279Seric 			if (ConfigLevel >= 5)
48564279Seric 			{
48664279Seric 				/* level 5 configs have short name in $w */
48764279Seric 				p = macvalue('w', e);
48864279Seric 				if (p != NULL && (p = strchr(p, '.')) != NULL)
48964279Seric 					*p = '\0';
49064279Seric 			}
49164718Seric 			if (*ep++ == '/')
49264718Seric 			{
49364718Seric 				/* extract vendor code */
49464718Seric 				for (p = ep; isascii(*p) && isalpha(*p); )
49564718Seric 					p++;
49664718Seric 				*p = '\0';
49764718Seric 
49864718Seric 				if (!setvendor(ep))
49964718Seric 					syserr("invalid V line vendor code: \"%s\"",
50064718Seric 						ep);
50164718Seric 			}
50252645Seric 			break;
50352645Seric 
50453654Seric 		  case 'K':
50557135Seric 			makemapentry(&bp[1]);
50653654Seric 			break;
50753654Seric 
5083308Seric 		  default:
5094061Seric 		  badline:
51057135Seric 			syserr("unknown control line \"%s\"", bp);
5113308Seric 		}
51257135Seric 		if (bp != buf)
51357135Seric 			free(bp);
5143308Seric 	}
51552637Seric 	if (ferror(cf))
51652637Seric 	{
51752647Seric 		syserr("I/O read error", cfname);
51852637Seric 		exit(EX_OSFILE);
51952637Seric 	}
52052637Seric 	fclose(cf);
5219381Seric 	FileName = NULL;
52256836Seric 
52367730Seric 	/* initialize host maps from local service tables */
52467730Seric 	inithostmaps();
52567730Seric 
52657076Seric 	if (stab("host", ST_MAP, ST_FIND) == NULL)
52757076Seric 	{
52857076Seric 		/* user didn't initialize: set up host map */
52957076Seric 		strcpy(buf, "host host");
53066334Seric #if NAMED_BIND
53157076Seric 		if (ConfigLevel >= 2)
53257076Seric 			strcat(buf, " -a.");
53364947Seric #endif
53457076Seric 		makemapentry(buf);
53557076Seric 	}
5364096Seric }
5374096Seric /*
5388547Seric **  TOOMANY -- signal too many of some option
5398547Seric **
5408547Seric **	Parameters:
5418547Seric **		id -- the id of the error line
5428547Seric **		maxcnt -- the maximum possible values
5438547Seric **
5448547Seric **	Returns:
5458547Seric **		none.
5468547Seric **
5478547Seric **	Side Effects:
5488547Seric **		gives a syserr.
5498547Seric */
5508547Seric 
5518547Seric toomany(id, maxcnt)
5528547Seric 	char id;
5538547Seric 	int maxcnt;
5548547Seric {
5559381Seric 	syserr("too many %c lines, %d max", id, maxcnt);
5568547Seric }
5578547Seric /*
5584432Seric **  FILECLASS -- read members of a class from a file
5594432Seric **
5604432Seric **	Parameters:
5614432Seric **		class -- class to define.
5624432Seric **		filename -- name of file to read.
5634432Seric **		fmt -- scanf string to use for match.
56464133Seric **		safe -- if set, this is a safe read.
56564133Seric **		optional -- if set, it is not an error for the file to
56664133Seric **			not exist.
5674432Seric **
5684432Seric **	Returns:
5694432Seric **		none
5704432Seric **
5714432Seric **	Side Effects:
5724432Seric **
5734432Seric **		puts all lines in filename that match a scanf into
5744432Seric **			the named class.
5754432Seric */
5764432Seric 
57764133Seric fileclass(class, filename, fmt, safe, optional)
5784432Seric 	int class;
5794432Seric 	char *filename;
5804432Seric 	char *fmt;
58154973Seric 	bool safe;
58264133Seric 	bool optional;
5834432Seric {
58425808Seric 	FILE *f;
58554973Seric 	struct stat stbuf;
5864432Seric 	char buf[MAXLINE];
5874432Seric 
58866101Seric 	if (tTd(37, 2))
58966101Seric 		printf("fileclass(%s, fmt=%s)\n", filename, fmt);
59066101Seric 
59166031Seric 	if (filename[0] == '|')
59266031Seric 	{
59366031Seric 		syserr("fileclass: pipes (F%c%s) not supported due to security problems",
59466031Seric 			class, filename);
59566031Seric 		return;
59666031Seric 	}
59754973Seric 	if (stat(filename, &stbuf) < 0)
59854973Seric 	{
59966101Seric 		if (tTd(37, 2))
60066101Seric 			printf("  cannot stat (%s)\n", errstring(errno));
60164133Seric 		if (!optional)
60264133Seric 			syserr("fileclass: cannot stat %s", filename);
60354973Seric 		return;
60454973Seric 	}
60554973Seric 	if (!S_ISREG(stbuf.st_mode))
60654973Seric 	{
60754973Seric 		syserr("fileclass: %s not a regular file", filename);
60854973Seric 		return;
60954973Seric 	}
61054973Seric 	if (!safe && access(filename, R_OK) < 0)
61154973Seric 	{
61254973Seric 		syserr("fileclass: access denied on %s", filename);
61354973Seric 		return;
61454973Seric 	}
61554973Seric 	f = fopen(filename, "r");
6164432Seric 	if (f == NULL)
6174432Seric 	{
61854973Seric 		syserr("fileclass: cannot open %s", filename);
6194432Seric 		return;
6204432Seric 	}
6214432Seric 
6224432Seric 	while (fgets(buf, sizeof buf, f) != NULL)
6234432Seric 	{
6244432Seric 		register STAB *s;
62525808Seric 		register char *p;
62625808Seric # ifdef SCANF
6274432Seric 		char wordbuf[MAXNAME+1];
6284432Seric 
6294432Seric 		if (sscanf(buf, fmt, wordbuf) != 1)
6304432Seric 			continue;
63125808Seric 		p = wordbuf;
63256795Seric # else /* SCANF */
63325808Seric 		p = buf;
63456795Seric # endif /* SCANF */
63525808Seric 
63625808Seric 		/*
63725808Seric 		**  Break up the match into words.
63825808Seric 		*/
63925808Seric 
64025808Seric 		while (*p != '\0')
64125808Seric 		{
64225808Seric 			register char *q;
64325808Seric 
64425808Seric 			/* strip leading spaces */
64558050Seric 			while (isascii(*p) && isspace(*p))
64625808Seric 				p++;
64725808Seric 			if (*p == '\0')
64825808Seric 				break;
64925808Seric 
65025808Seric 			/* find the end of the word */
65125808Seric 			q = p;
65258050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
65325808Seric 				p++;
65425808Seric 			if (*p != '\0')
65525808Seric 				*p++ = '\0';
65625808Seric 
65725808Seric 			/* enter the word in the symbol table */
65866101Seric 			setclass(class, q);
65925808Seric 		}
6604432Seric 	}
6614432Seric 
66254973Seric 	(void) fclose(f);
6634432Seric }
6644432Seric /*
6654096Seric **  MAKEMAILER -- define a new mailer.
6664096Seric **
6674096Seric **	Parameters:
66810327Seric **		line -- description of mailer.  This is in labeled
66910327Seric **			fields.  The fields are:
67010327Seric **			   P -- the path to the mailer
67110327Seric **			   F -- the flags associated with the mailer
67210327Seric **			   A -- the argv for this mailer
67310327Seric **			   S -- the sender rewriting set
67410327Seric **			   R -- the recipient rewriting set
67510327Seric **			   E -- the eol string
67610327Seric **			The first word is the canonical name of the mailer.
6774096Seric **
6784096Seric **	Returns:
6794096Seric **		none.
6804096Seric **
6814096Seric **	Side Effects:
6824096Seric **		enters the mailer into the mailer table.
6834096Seric */
6843308Seric 
68521066Seric makemailer(line)
6864096Seric 	char *line;
6874096Seric {
6884096Seric 	register char *p;
6898067Seric 	register struct mailer *m;
6908067Seric 	register STAB *s;
6918067Seric 	int i;
69210327Seric 	char fcode;
69358020Seric 	auto char *endp;
6944096Seric 	extern int NextMailer;
69510327Seric 	extern char **makeargv();
69610327Seric 	extern char *munchstring();
69710701Seric 	extern long atol();
6984096Seric 
69910327Seric 	/* allocate a mailer and set up defaults */
70010327Seric 	m = (struct mailer *) xalloc(sizeof *m);
70110327Seric 	bzero((char *) m, sizeof *m);
70210327Seric 	m->m_eol = "\n";
70367604Seric 	m->m_uid = m->m_gid = 0;
70410327Seric 
70510327Seric 	/* collect the mailer name */
70658050Seric 	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
70710327Seric 		continue;
70810327Seric 	if (*p != '\0')
70910327Seric 		*p++ = '\0';
71010327Seric 	m->m_name = newstr(line);
71110327Seric 
71210327Seric 	/* now scan through and assign info from the fields */
71310327Seric 	while (*p != '\0')
71410327Seric 	{
71558333Seric 		auto char *delimptr;
71658333Seric 
71758050Seric 		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
71810327Seric 			p++;
71910327Seric 
72010327Seric 		/* p now points to field code */
72110327Seric 		fcode = *p;
72210327Seric 		while (*p != '\0' && *p != '=' && *p != ',')
72310327Seric 			p++;
72410327Seric 		if (*p++ != '=')
72510327Seric 		{
72652637Seric 			syserr("mailer %s: `=' expected", m->m_name);
72710327Seric 			return;
72810327Seric 		}
72958050Seric 		while (isascii(*p) && isspace(*p))
73010327Seric 			p++;
73110327Seric 
73210327Seric 		/* p now points to the field body */
73358333Seric 		p = munchstring(p, &delimptr);
73410327Seric 
73510327Seric 		/* install the field into the mailer struct */
73610327Seric 		switch (fcode)
73710327Seric 		{
73810327Seric 		  case 'P':		/* pathname */
73910327Seric 			m->m_mailer = newstr(p);
74010327Seric 			break;
74110327Seric 
74210327Seric 		  case 'F':		/* flags */
74310687Seric 			for (; *p != '\0'; p++)
74458050Seric 				if (!(isascii(*p) && isspace(*p)))
74552637Seric 					setbitn(*p, m->m_flags);
74610327Seric 			break;
74710327Seric 
74810327Seric 		  case 'S':		/* sender rewriting ruleset */
74910327Seric 		  case 'R':		/* recipient rewriting ruleset */
75058020Seric 			i = strtol(p, &endp, 10);
75110327Seric 			if (i < 0 || i >= MAXRWSETS)
75210327Seric 			{
75310327Seric 				syserr("invalid rewrite set, %d max", MAXRWSETS);
75410327Seric 				return;
75510327Seric 			}
75610327Seric 			if (fcode == 'S')
75758020Seric 				m->m_sh_rwset = m->m_se_rwset = i;
75810327Seric 			else
75958020Seric 				m->m_rh_rwset = m->m_re_rwset = i;
76058020Seric 
76158020Seric 			p = endp;
76259985Seric 			if (*p++ == '/')
76358020Seric 			{
76458020Seric 				i = strtol(p, NULL, 10);
76558020Seric 				if (i < 0 || i >= MAXRWSETS)
76658020Seric 				{
76758020Seric 					syserr("invalid rewrite set, %d max",
76858020Seric 						MAXRWSETS);
76958020Seric 					return;
77058020Seric 				}
77158020Seric 				if (fcode == 'S')
77258020Seric 					m->m_sh_rwset = i;
77358020Seric 				else
77458020Seric 					m->m_rh_rwset = i;
77558020Seric 			}
77610327Seric 			break;
77710327Seric 
77810327Seric 		  case 'E':		/* end of line string */
77910327Seric 			m->m_eol = newstr(p);
78010327Seric 			break;
78110327Seric 
78210327Seric 		  case 'A':		/* argument vector */
78310327Seric 			m->m_argv = makeargv(p);
78410327Seric 			break;
78510701Seric 
78610701Seric 		  case 'M':		/* maximum message size */
78710701Seric 			m->m_maxsize = atol(p);
78810701Seric 			break;
78952106Seric 
79052106Seric 		  case 'L':		/* maximum line length */
79152106Seric 			m->m_linelimit = atoi(p);
79252106Seric 			break;
79358935Seric 
79458935Seric 		  case 'D':		/* working directory */
79558935Seric 			m->m_execdir = newstr(p);
79658935Seric 			break;
79767604Seric 
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 */
108467614Seric 	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,
114867707Seric 
114967707Seric 	NULL,			'\0',		FALSE,
115067614Seric };
115167614Seric 
115267614Seric 
115367614Seric 
115458734Seric setoption(opt, val, safe, sticky, e)
115567614Seric 	u_char opt;
11568256Seric 	char *val;
115721755Seric 	bool safe;
11588269Seric 	bool sticky;
115958734Seric 	register ENVELOPE *e;
11608256Seric {
116157207Seric 	register char *p;
116267614Seric 	register struct optioninfo *o;
11638265Seric 	extern bool atobool();
116412633Seric 	extern time_t convtime();
116514879Seric 	extern int QueueLA;
116614879Seric 	extern int RefuseLA;
116764718Seric 	extern bool Warn_Q_option;
11688256Seric 
116967736Seric 	errno = 0;
117067614Seric 	if (opt == ' ')
117167614Seric 	{
117267614Seric 		/* full word options */
117367736Seric 		struct optioninfo *sel;
117467614Seric 
117567614Seric 		p = strchr(val, '=');
117667614Seric 		if (p == NULL)
117767614Seric 			p = &val[strlen(val)];
117867614Seric 		while (*--p == ' ')
117967614Seric 			continue;
118067614Seric 		while (*++p == ' ')
118167614Seric 			*p = '\0';
118267731Seric 		if (p == val)
118367731Seric 		{
118467731Seric 			syserr("readcf: null option name");
118567731Seric 			return;
118667731Seric 		}
118767614Seric 		if (*p == '=')
118867614Seric 			*p++ = '\0';
118967614Seric 		while (*p == ' ')
119067614Seric 			p++;
119167736Seric 		sel = NULL;
119267614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
119367614Seric 		{
119467736Seric 			if (strncasecmp(o->o_name, val, strlen(val)) != 0)
119567736Seric 				continue;
119667736Seric 			if (strlen(o->o_name) == strlen(val))
119767736Seric 			{
119867736Seric 				/* completely specified -- this must be it */
119967736Seric 				sel = NULL;
120067614Seric 				break;
120167736Seric 			}
120267736Seric 			if (sel != NULL)
120367736Seric 				break;
120467736Seric 			sel = o;
120567614Seric 		}
120667736Seric 		if (sel != NULL && o->o_name == NULL)
120767736Seric 			o = sel;
120867736Seric 		else if (o->o_name == NULL)
120967614Seric 			syserr("readcf: unknown option name %s", val);
121067736Seric 		else if (sel != NULL)
121167736Seric 		{
121267736Seric 			syserr("readcf: ambiguous option name %s (matches %s and %s)",
121367736Seric 				val, sel->o_name, o->o_name);
121467736Seric 			return;
121567736Seric 		}
121667736Seric 		if (strlen(val) != strlen(o->o_name))
121767736Seric 		{
121867736Seric 			bool oldVerbose = Verbose;
121967736Seric 
122067736Seric 			Verbose = TRUE;
122167736Seric 			message("Option %s used as abbreviation for %s",
122267736Seric 				val, o->o_name);
122367736Seric 			Verbose = oldVerbose;
122467736Seric 		}
122567614Seric 		opt = o->o_code;
122667614Seric 		val = p;
122767614Seric 	}
122867614Seric 	else
122967614Seric 	{
123067614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
123167614Seric 		{
123267614Seric 			if (o->o_code == opt)
123367614Seric 				break;
123467614Seric 		}
123567614Seric 	}
123667614Seric 
12378256Seric 	if (tTd(37, 1))
123867731Seric 	{
123967731Seric 		printf(isascii(opt) && isprint(opt) ?
124067731Seric 			    "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s",
124167614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
124267614Seric 			opt, val);
124367731Seric 	}
12448256Seric 
12458256Seric 	/*
12468269Seric 	**  See if this option is preset for us.
12478256Seric 	*/
12488256Seric 
124959731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12508269Seric 	{
12519341Seric 		if (tTd(37, 1))
12529341Seric 			printf(" (ignored)\n");
12538269Seric 		return;
12548269Seric 	}
12558269Seric 
125621755Seric 	/*
125721755Seric 	**  Check to see if this option can be specified by this user.
125821755Seric 	*/
125921755Seric 
126063787Seric 	if (!safe && RealUid == 0)
126121755Seric 		safe = TRUE;
126267614Seric 	if (!safe && !o->o_safe)
126321755Seric 	{
126439111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
126521755Seric 		{
126636582Sbostic 			if (tTd(37, 1))
126736582Sbostic 				printf(" (unsafe)");
126863787Seric 			if (RealUid != geteuid())
126936582Sbostic 			{
127051210Seric 				if (tTd(37, 1))
127151210Seric 					printf("(Resetting uid)");
127263787Seric 				(void) setgid(RealGid);
127363787Seric 				(void) setuid(RealUid);
127436582Sbostic 			}
127521755Seric 		}
127621755Seric 	}
127751210Seric 	if (tTd(37, 1))
127817985Seric 		printf("\n");
12798269Seric 
128067614Seric 	switch (opt & 0xff)
12818256Seric 	{
128259709Seric 	  case '7':		/* force seven-bit input */
128367546Seric 		SevenBitInput = atobool(val);
128452106Seric 		break;
128552106Seric 
128667546Seric 	  case '8':		/* handling of 8-bit input */
128767546Seric 		switch (*val)
128867546Seric 		{
128967547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
129067546Seric 			MimeMode = 0;
129167546Seric 			break;
129267546Seric 
129367547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
129467546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
129567546Seric 			break;
129667546Seric 
129767547Seric 		  case 'j':		/* "just send 8" */
129867546Seric 			MimeMode = MM_PASS8BIT;
129967546Seric 			break;
130067546Seric 
130167546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
130267546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
130367546Seric 			break;
130467546Seric 
130567546Seric 		  case 's':		/* strict adherence */
130667546Seric 			MimeMode = MM_CVTMIME;
130767546Seric 			break;
130867546Seric 
130967547Seric 		  case 'a':		/* encode 8 bit if available */
131067546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
131167546Seric 			break;
131267546Seric 
131367547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
131467547Seric 			MimeMode = MM_MIME8BIT;
131567547Seric 			break;
131667547Seric 
131767546Seric 		  default:
131867546Seric 			syserr("Unknown 8-bit mode %c", *val);
131967546Seric 			exit(EX_USAGE);
132067546Seric 		}
132167546Seric 		break;
132267546Seric 
13238256Seric 	  case 'A':		/* set default alias file */
13249381Seric 		if (val[0] == '\0')
132559672Seric 			setalias("aliases");
13269381Seric 		else
132759672Seric 			setalias(val);
13288256Seric 		break;
13298256Seric 
133017474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
133117474Seric 		if (val[0] == '\0')
133264796Seric 			SafeAlias = 5 * 60;		/* five minutes */
133317474Seric 		else
133464796Seric 			SafeAlias = convtime(val, 'm');
133517474Seric 		break;
133617474Seric 
133716843Seric 	  case 'B':		/* substitution for blank character */
133816843Seric 		SpaceSub = val[0];
133916843Seric 		if (SpaceSub == '\0')
134016843Seric 			SpaceSub = ' ';
134116843Seric 		break;
134216843Seric 
134359283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
134459283Seric 		p = strchr(val, '/');
134559283Seric 		if (p != NULL)
134659283Seric 		{
134759283Seric 			*p++ = '\0';
134859283Seric 			MaxMessageSize = atol(p);
134959283Seric 		}
135058082Seric 		MinBlocksFree = atol(val);
135158082Seric 		break;
135258082Seric 
13539284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13549381Seric 		NoConnect = atobool(val);
13559284Seric 		break;
13569284Seric 
135751305Seric 	  case 'C':		/* checkpoint every N addresses */
135851305Seric 		CheckpointInterval = atoi(val);
135924944Seric 		break;
136024944Seric 
13619284Seric 	  case 'd':		/* delivery mode */
13629284Seric 		switch (*val)
13638269Seric 		{
13649284Seric 		  case '\0':
136558734Seric 			e->e_sendmode = SM_DELIVER;
13668269Seric 			break;
13678269Seric 
136810755Seric 		  case SM_QUEUE:	/* queue only */
136910755Seric #ifndef QUEUE
137010755Seric 			syserr("need QUEUE to set -odqueue");
137156795Seric #endif /* QUEUE */
137210755Seric 			/* fall through..... */
137310755Seric 
13749284Seric 		  case SM_DELIVER:	/* do everything */
13759284Seric 		  case SM_FORK:		/* fork after verification */
137658734Seric 			e->e_sendmode = *val;
13778269Seric 			break;
13788269Seric 
13798269Seric 		  default:
13809284Seric 			syserr("Unknown delivery mode %c", *val);
13818269Seric 			exit(EX_USAGE);
13828269Seric 		}
13838269Seric 		break;
13848269Seric 
13859146Seric 	  case 'D':		/* rebuild alias database as needed */
13869381Seric 		AutoRebuild = atobool(val);
13879146Seric 		break;
13889146Seric 
138955372Seric 	  case 'E':		/* error message header/header file */
139055379Seric 		if (*val != '\0')
139155379Seric 			ErrMsgFile = newstr(val);
139255372Seric 		break;
139355372Seric 
13948269Seric 	  case 'e':		/* set error processing mode */
13958269Seric 		switch (*val)
13968269Seric 		{
13979381Seric 		  case EM_QUIET:	/* be silent about it */
13989381Seric 		  case EM_MAIL:		/* mail back */
13999381Seric 		  case EM_BERKNET:	/* do berknet error processing */
14009381Seric 		  case EM_WRITE:	/* write back (or mail) */
14019381Seric 		  case EM_PRINT:	/* print errors normally (default) */
140258734Seric 			e->e_errormode = *val;
14038269Seric 			break;
14048269Seric 		}
14058269Seric 		break;
14068269Seric 
14079049Seric 	  case 'F':		/* file mode */
140817975Seric 		FileMode = atooct(val) & 0777;
14099049Seric 		break;
14109049Seric 
14118269Seric 	  case 'f':		/* save Unix-style From lines on front */
14129381Seric 		SaveFrom = atobool(val);
14138269Seric 		break;
14148269Seric 
141553735Seric 	  case 'G':		/* match recipients against GECOS field */
141653735Seric 		MatchGecos = atobool(val);
141753735Seric 		break;
141853735Seric 
14198256Seric 	  case 'g':		/* default gid */
142064133Seric 		if (isascii(*val) && isdigit(*val))
142164133Seric 			DefGid = atoi(val);
142264133Seric 		else
142364133Seric 		{
142464133Seric 			register struct group *gr;
142564133Seric 
142664133Seric 			DefGid = -1;
142764133Seric 			gr = getgrnam(val);
142864133Seric 			if (gr == NULL)
142964133Seric 				syserr("readcf: option g: unknown group %s", val);
143064133Seric 			else
143164133Seric 				DefGid = gr->gr_gid;
143264133Seric 		}
14338256Seric 		break;
14348256Seric 
14358256Seric 	  case 'H':		/* help file */
14369381Seric 		if (val[0] == '\0')
14378269Seric 			HelpFile = "sendmail.hf";
14389381Seric 		else
14399381Seric 			HelpFile = newstr(val);
14408256Seric 		break;
14418256Seric 
144251305Seric 	  case 'h':		/* maximum hop count */
144351305Seric 		MaxHopCount = atoi(val);
144451305Seric 		break;
144551305Seric 
144635651Seric 	  case 'I':		/* use internet domain name server */
144766334Seric #if NAMED_BIND
144857207Seric 		UseNameServer = TRUE;
144957207Seric 		for (p = val; *p != 0; )
145057207Seric 		{
145157207Seric 			bool clearmode;
145257207Seric 			char *q;
145357207Seric 			struct resolverflags *rfp;
145457207Seric 
145557207Seric 			while (*p == ' ')
145657207Seric 				p++;
145757207Seric 			if (*p == '\0')
145857207Seric 				break;
145957207Seric 			clearmode = FALSE;
146057207Seric 			if (*p == '-')
146157207Seric 				clearmode = TRUE;
146257207Seric 			else if (*p != '+')
146357207Seric 				p--;
146457207Seric 			p++;
146557207Seric 			q = p;
146658050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
146757207Seric 				p++;
146857207Seric 			if (*p != '\0')
146957207Seric 				*p++ = '\0';
147057207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
147157207Seric 			{
147257207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
147357207Seric 					break;
147457207Seric 			}
147564923Seric 			if (rfp->rf_name == NULL)
147664923Seric 				syserr("readcf: I option value %s unrecognized", q);
147764923Seric 			else if (clearmode)
147857207Seric 				_res.options &= ~rfp->rf_bits;
147957207Seric 			else
148057207Seric 				_res.options |= rfp->rf_bits;
148157207Seric 		}
148257207Seric 		if (tTd(8, 2))
148357207Seric 			printf("_res.options = %x\n", _res.options);
148457207Seric #else
148557207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
148657207Seric #endif
148735651Seric 		break;
148835651Seric 
14898269Seric 	  case 'i':		/* ignore dot lines in message */
14909381Seric 		IgnrDot = atobool(val);
14918269Seric 		break;
14928269Seric 
149359730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
149459730Seric 		SendMIMEErrors = atobool(val);
149559730Seric 		break;
149659730Seric 
149757136Seric 	  case 'J':		/* .forward search path */
149857136Seric 		ForwardPath = newstr(val);
149957136Seric 		break;
150057136Seric 
150154967Seric 	  case 'k':		/* connection cache size */
150254967Seric 		MaxMciCache = atoi(val);
150356215Seric 		if (MaxMciCache < 0)
150456215Seric 			MaxMciCache = 0;
150554967Seric 		break;
150654967Seric 
150754967Seric 	  case 'K':		/* connection cache timeout */
150858796Seric 		MciCacheTimeout = convtime(val, 'm');
150954967Seric 		break;
151054967Seric 
151161104Seric 	  case 'l':		/* use Errors-To: header */
151261104Seric 		UseErrorsTo = atobool(val);
151361104Seric 		break;
151461104Seric 
15158256Seric 	  case 'L':		/* log level */
151664140Seric 		if (safe || LogLevel < atoi(val))
151764140Seric 			LogLevel = atoi(val);
15188256Seric 		break;
15198256Seric 
15208269Seric 	  case 'M':		/* define macro */
15219381Seric 		define(val[0], newstr(&val[1]), CurEnv);
152216878Seric 		sticky = FALSE;
15238269Seric 		break;
15248269Seric 
15258269Seric 	  case 'm':		/* send to me too */
15269381Seric 		MeToo = atobool(val);
15278269Seric 		break;
15288269Seric 
152925820Seric 	  case 'n':		/* validate RHS in newaliases */
153025820Seric 		CheckAliases = atobool(val);
153125820Seric 		break;
153225820Seric 
153361104Seric 	    /* 'N' available -- was "net name" */
153461104Seric 
153558851Seric 	  case 'O':		/* daemon options */
153658851Seric 		setdaemonoptions(val);
153758851Seric 		break;
153858851Seric 
15398269Seric 	  case 'o':		/* assume old style headers */
15409381Seric 		if (atobool(val))
15419341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
15429341Seric 		else
15439341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
15448269Seric 		break;
15458269Seric 
154658082Seric 	  case 'p':		/* select privacy level */
154758082Seric 		p = val;
154858082Seric 		for (;;)
154958082Seric 		{
155058082Seric 			register struct prival *pv;
155158082Seric 			extern struct prival PrivacyValues[];
155258082Seric 
155358082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
155458082Seric 				p++;
155558082Seric 			if (*p == '\0')
155658082Seric 				break;
155758082Seric 			val = p;
155858082Seric 			while (isascii(*p) && isalnum(*p))
155958082Seric 				p++;
156058082Seric 			if (*p != '\0')
156158082Seric 				*p++ = '\0';
156258082Seric 
156358082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
156458082Seric 			{
156558082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
156658082Seric 					break;
156758082Seric 			}
156858886Seric 			if (pv->pv_name == NULL)
156958886Seric 				syserr("readcf: Op line: %s unrecognized", val);
157058082Seric 			PrivacyFlags |= pv->pv_flag;
157158082Seric 		}
157258082Seric 		break;
157358082Seric 
157424944Seric 	  case 'P':		/* postmaster copy address for returned mail */
157524944Seric 		PostMasterCopy = newstr(val);
157624944Seric 		break;
157724944Seric 
157824944Seric 	  case 'q':		/* slope of queue only function */
157924944Seric 		QueueFactor = atoi(val);
158024944Seric 		break;
158124944Seric 
15828256Seric 	  case 'Q':		/* queue directory */
15839381Seric 		if (val[0] == '\0')
15848269Seric 			QueueDir = "mqueue";
15859381Seric 		else
15869381Seric 			QueueDir = newstr(val);
158758789Seric 		if (RealUid != 0 && !safe)
158864718Seric 			Warn_Q_option = TRUE;
15898256Seric 		break;
15908256Seric 
159158148Seric 	  case 'R':		/* don't prune routes */
159258148Seric 		DontPruneRoutes = atobool(val);
159358148Seric 		break;
159458148Seric 
15958256Seric 	  case 'r':		/* read timeout */
159658112Seric 		settimeouts(val);
15978256Seric 		break;
15988256Seric 
15998256Seric 	  case 'S':		/* status file */
16009381Seric 		if (val[0] == '\0')
16018269Seric 			StatFile = "sendmail.st";
16029381Seric 		else
16039381Seric 			StatFile = newstr(val);
16048256Seric 		break;
16058256Seric 
16068265Seric 	  case 's':		/* be super safe, even if expensive */
16079381Seric 		SuperSafe = atobool(val);
16088256Seric 		break;
16098256Seric 
16108256Seric 	  case 'T':		/* queue timeout */
161158737Seric 		p = strchr(val, '/');
161258737Seric 		if (p != NULL)
161358737Seric 		{
161458737Seric 			*p++ = '\0';
161567730Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd');
161658737Seric 		}
161767730Seric 		TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h');
161854967Seric 		break;
16198256Seric 
16208265Seric 	  case 't':		/* time zone name */
162152106Seric 		TimeZoneSpec = newstr(val);
16228265Seric 		break;
16238265Seric 
162450556Seric 	  case 'U':		/* location of user database */
162551360Seric 		UdbSpec = newstr(val);
162650556Seric 		break;
162750556Seric 
16288256Seric 	  case 'u':		/* set default uid */
162964133Seric 		if (isascii(*val) && isdigit(*val))
163064133Seric 			DefUid = atoi(val);
163164133Seric 		else
163264133Seric 		{
163364133Seric 			register struct passwd *pw;
163464133Seric 
163564133Seric 			DefUid = -1;
163664133Seric 			pw = getpwnam(val);
163764133Seric 			if (pw == NULL)
163864133Seric 				syserr("readcf: option u: unknown user %s", val);
163964133Seric 			else
164064133Seric 				DefUid = pw->pw_uid;
164164133Seric 		}
164240973Sbostic 		setdefuser();
16438256Seric 		break;
16448256Seric 
164558851Seric 	  case 'V':		/* fallback MX host */
164658851Seric 		FallBackMX = newstr(val);
164758851Seric 		break;
164858851Seric 
16498269Seric 	  case 'v':		/* run in verbose mode */
16509381Seric 		Verbose = atobool(val);
16518256Seric 		break;
16528256Seric 
165363837Seric 	  case 'w':		/* if we are best MX, try host directly */
165463837Seric 		TryNullMXList = atobool(val);
165563837Seric 		break;
165661104Seric 
165761104Seric 	    /* 'W' available -- was wizard password */
165861104Seric 
165914879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
166014879Seric 		QueueLA = atoi(val);
166114879Seric 		break;
166214879Seric 
166314879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
166414879Seric 		RefuseLA = atoi(val);
166514879Seric 		break;
166614879Seric 
166724981Seric 	  case 'y':		/* work recipient factor */
166824981Seric 		WkRecipFact = atoi(val);
166924981Seric 		break;
167024981Seric 
167124981Seric 	  case 'Y':		/* fork jobs during queue runs */
167224952Seric 		ForkQueueRuns = atobool(val);
167324952Seric 		break;
167424952Seric 
167524981Seric 	  case 'z':		/* work message class factor */
167624981Seric 		WkClassFact = atoi(val);
167724981Seric 		break;
167824981Seric 
167924981Seric 	  case 'Z':		/* work time factor */
168024981Seric 		WkTimeFact = atoi(val);
168124981Seric 		break;
168224981Seric 
168367614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
168467614Seric 		BrokenSmtpPeers = atobool(val);
168567614Seric 		break;
168667614Seric 
168767614Seric 	  case O_SQBH:		/* sort work queue by host first */
168867614Seric 		SortQueueByHost = atobool(val);
168967614Seric 		break;
169067614Seric 
169167707Seric 	  case O_DNICE:		/* delivery nice value */
169267707Seric 		DeliveryNiceness = atoi(val);
169367707Seric 		break;
169467707Seric 
169567707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
169667707Seric 		MinQueueAge = convtime(val, 'm');
169767707Seric 		break;
169867707Seric 
169967707Seric 	  case O_MHSA:		/* maximum age of cached host status */
170067707Seric 		MaxHostStatAge = convtime(val, 'm');
170167707Seric 		break;
170267707Seric 
17038256Seric 	  default:
17048256Seric 		break;
17058256Seric 	}
170616878Seric 	if (sticky)
170716878Seric 		setbitn(opt, StickyOpt);
17089188Seric 	return;
17098256Seric }
171010687Seric /*
171110687Seric **  SETCLASS -- set a word into a class
171210687Seric **
171310687Seric **	Parameters:
171410687Seric **		class -- the class to put the word in.
171510687Seric **		word -- the word to enter
171610687Seric **
171710687Seric **	Returns:
171810687Seric **		none.
171910687Seric **
172010687Seric **	Side Effects:
172110687Seric **		puts the word into the symbol table.
172210687Seric */
172310687Seric 
172410687Seric setclass(class, word)
172510687Seric 	int class;
172610687Seric 	char *word;
172710687Seric {
172810687Seric 	register STAB *s;
172910687Seric 
173057943Seric 	if (tTd(37, 8))
173164326Seric 		printf("setclass(%c, %s)\n", class, word);
173210687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
173310687Seric 	setbitn(class, s->s_class);
173410687Seric }
173553654Seric /*
173653654Seric **  MAKEMAPENTRY -- create a map entry
173753654Seric **
173853654Seric **	Parameters:
173953654Seric **		line -- the config file line
174053654Seric **
174153654Seric **	Returns:
174253654Seric **		TRUE if it successfully entered the map entry.
174353654Seric **		FALSE otherwise (usually syntax error).
174453654Seric **
174553654Seric **	Side Effects:
174653654Seric **		Enters the map into the dictionary.
174753654Seric */
174853654Seric 
174953654Seric void
175053654Seric makemapentry(line)
175153654Seric 	char *line;
175253654Seric {
175353654Seric 	register char *p;
175453654Seric 	char *mapname;
175553654Seric 	char *classname;
175664078Seric 	register STAB *s;
175753654Seric 	STAB *class;
175853654Seric 
175958050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
176053654Seric 		continue;
176158050Seric 	if (!(isascii(*p) && isalnum(*p)))
176253654Seric 	{
176353654Seric 		syserr("readcf: config K line: no map name");
176453654Seric 		return;
176553654Seric 	}
176653654Seric 
176753654Seric 	mapname = p;
176858050Seric 	while (isascii(*++p) && isalnum(*p))
176953654Seric 		continue;
177053654Seric 	if (*p != '\0')
177153654Seric 		*p++ = '\0';
177258050Seric 	while (isascii(*p) && isspace(*p))
177353654Seric 		p++;
177458050Seric 	if (!(isascii(*p) && isalnum(*p)))
177553654Seric 	{
177653654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
177753654Seric 		return;
177853654Seric 	}
177953654Seric 	classname = p;
178058050Seric 	while (isascii(*++p) && isalnum(*p))
178153654Seric 		continue;
178253654Seric 	if (*p != '\0')
178353654Seric 		*p++ = '\0';
178458050Seric 	while (isascii(*p) && isspace(*p))
178553654Seric 		p++;
178653654Seric 
178753654Seric 	/* look up the class */
178853654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
178953654Seric 	if (class == NULL)
179053654Seric 	{
179153654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
179253654Seric 		return;
179353654Seric 	}
179453654Seric 
179553654Seric 	/* enter the map */
179664078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
179764078Seric 	s->s_map.map_class = &class->s_mapclass;
179864078Seric 	s->s_map.map_mname = newstr(mapname);
179953654Seric 
180064078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
180164078Seric 		s->s_map.map_mflags |= MF_VALID;
180264078Seric 
180364078Seric 	if (tTd(37, 5))
180464078Seric 	{
180564078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
180664078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
180764078Seric 			s->s_map.map_mflags,
180864078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
180964078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
181064078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
181164078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
181264078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
181364078Seric 	}
181453654Seric }
181558112Seric /*
181658112Seric **  SETTIMEOUTS -- parse and set timeout values
181758112Seric **
181858112Seric **	Parameters:
181958112Seric **		val -- a pointer to the values.  If NULL, do initial
182058112Seric **			settings.
182158112Seric **
182258112Seric **	Returns:
182358112Seric **		none.
182458112Seric **
182558112Seric **	Side Effects:
182658112Seric **		Initializes the TimeOuts structure
182758112Seric */
182858112Seric 
182964255Seric #define SECONDS
183058112Seric #define MINUTES	* 60
183158112Seric #define HOUR	* 3600
183258112Seric 
183358112Seric settimeouts(val)
183458112Seric 	register char *val;
183558112Seric {
183658112Seric 	register char *p;
183758671Seric 	extern time_t convtime();
183858112Seric 
183958112Seric 	if (val == NULL)
184058112Seric 	{
184158112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
184258112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
184358112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
184458112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
184558112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
184658112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
184758112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
184858112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
184958112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
185058112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
185158112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
185264255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
185367711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
185458112Seric 		return;
185558112Seric 	}
185658112Seric 
185758112Seric 	for (;; val = p)
185858112Seric 	{
185958112Seric 		while (isascii(*val) && isspace(*val))
186058112Seric 			val++;
186158112Seric 		if (*val == '\0')
186258112Seric 			break;
186358112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
186458112Seric 			continue;
186558112Seric 		if (*p != '\0')
186658112Seric 			*p++ = '\0';
186758112Seric 
186858112Seric 		if (isascii(*val) && isdigit(*val))
186958112Seric 		{
187058112Seric 			/* old syntax -- set everything */
187158796Seric 			TimeOuts.to_mail = convtime(val, 'm');
187258112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
187358112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
187458112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
187558112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
187658112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
187758112Seric 			continue;
187858112Seric 		}
187958112Seric 		else
188058112Seric 		{
188167711Seric 			register char *q = strchr(val, ':');
188258112Seric 			time_t to;
188358112Seric 
188467711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
188558112Seric 			{
188658112Seric 				/* syntax error */
188758112Seric 				continue;
188858112Seric 			}
188958112Seric 			*q++ = '\0';
189058796Seric 			to = convtime(q, 'm');
189158112Seric 
189258112Seric 			if (strcasecmp(val, "initial") == 0)
189358112Seric 				TimeOuts.to_initial = to;
189458112Seric 			else if (strcasecmp(val, "mail") == 0)
189558112Seric 				TimeOuts.to_mail = to;
189658112Seric 			else if (strcasecmp(val, "rcpt") == 0)
189758112Seric 				TimeOuts.to_rcpt = to;
189858112Seric 			else if (strcasecmp(val, "datainit") == 0)
189958112Seric 				TimeOuts.to_datainit = to;
190058112Seric 			else if (strcasecmp(val, "datablock") == 0)
190158112Seric 				TimeOuts.to_datablock = to;
190258112Seric 			else if (strcasecmp(val, "datafinal") == 0)
190358112Seric 				TimeOuts.to_datafinal = to;
190458112Seric 			else if (strcasecmp(val, "command") == 0)
190558112Seric 				TimeOuts.to_nextcommand = to;
190658112Seric 			else if (strcasecmp(val, "rset") == 0)
190758112Seric 				TimeOuts.to_rset = to;
190858112Seric 			else if (strcasecmp(val, "helo") == 0)
190958112Seric 				TimeOuts.to_helo = to;
191058112Seric 			else if (strcasecmp(val, "quit") == 0)
191158112Seric 				TimeOuts.to_quit = to;
191258112Seric 			else if (strcasecmp(val, "misc") == 0)
191358112Seric 				TimeOuts.to_miscshort = to;
191464255Seric 			else if (strcasecmp(val, "ident") == 0)
191564255Seric 				TimeOuts.to_ident = to;
191667711Seric 			else if (strcasecmp(val, "fileopen") == 0)
191767711Seric 				TimeOuts.to_fileopen = to;
191867711Seric 			else if (strcasecmp(val, "queuewarn") == 0)
191967730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
192067711Seric 			else if (strcasecmp(val, "queuereturn") == 0)
192167730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
192267730Seric 			else if (strcasecmp(val, "queuewarn.normal") == 0)
192367730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
192467730Seric 			else if (strcasecmp(val, "queuereturn.normal") == 0)
192567730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
192667730Seric 			else if (strcasecmp(val, "queuewarn.urgent") == 0)
192767730Seric 				TimeOuts.to_q_warning[TOC_URGENT] = to;
192867730Seric 			else if (strcasecmp(val, "queuereturn.urgent") == 0)
192967730Seric 				TimeOuts.to_q_return[TOC_URGENT] = to;
193067730Seric 			else if (strcasecmp(val, "queuewarn.non-urgent") == 0)
193167730Seric 				TimeOuts.to_q_warning[TOC_NONURGENT] = to;
193267730Seric 			else if (strcasecmp(val, "queuereturn.non-urgent") == 0)
193367730Seric 				TimeOuts.to_q_return[TOC_NONURGENT] = to;
193458112Seric 			else
193558112Seric 				syserr("settimeouts: invalid timeout %s", val);
193658112Seric 		}
193758112Seric 	}
193858112Seric }
1939