xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67736)
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*67736Seric static char sccsid[] = "@(#)readcf.c	8.37 (Berkeley) 08/23/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;
803308Seric 	char buf[MAXLINE];
813308Seric 	register char *p;
823308Seric 	extern char **copyplist();
8352647Seric 	struct stat statb;
845909Seric 	char exbuf[MAXLINE];
8565066Seric 	char pvpbuf[MAXLINE + MAXATOM];
8610709Seric 	extern char *munchstring();
8753654Seric 	extern void makemapentry();
883308Seric 
8952647Seric 	FileName = cfname;
9052647Seric 	LineNumber = 0;
9152647Seric 
923308Seric 	cf = fopen(cfname, "r");
933308Seric 	if (cf == NULL)
943308Seric 	{
9552647Seric 		syserr("cannot open");
963308Seric 		exit(EX_OSFILE);
973308Seric 	}
983308Seric 
9952647Seric 	if (fstat(fileno(cf), &statb) < 0)
10052647Seric 	{
10152647Seric 		syserr("cannot fstat");
10252647Seric 		exit(EX_OSFILE);
10352647Seric 	}
10452647Seric 
10552647Seric 	if (!S_ISREG(statb.st_mode))
10652647Seric 	{
10752647Seric 		syserr("not a plain file");
10852647Seric 		exit(EX_OSFILE);
10952647Seric 	}
11052647Seric 
11152647Seric 	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
11252647Seric 	{
11353037Seric 		if (OpMode == MD_DAEMON || OpMode == MD_FREEZE)
11453037Seric 			fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
11553037Seric 				FileName);
11653037Seric #ifdef LOG
11753037Seric 		if (LogLevel > 0)
11853037Seric 			syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
11953037Seric 				FileName);
12053037Seric #endif
12152647Seric 	}
12252647Seric 
12359254Seric #ifdef XLA
12459254Seric 	xla_zero();
12559254Seric #endif
12659254Seric 
12757135Seric 	while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
1283308Seric 	{
12957135Seric 		if (bp[0] == '#')
13057135Seric 		{
13157135Seric 			if (bp != buf)
13257135Seric 				free(bp);
13352637Seric 			continue;
13457135Seric 		}
13552637Seric 
13658050Seric 		/* map $ into \201 for macro expansion */
13757135Seric 		for (p = bp; *p != '\0'; p++)
13816157Seric 		{
13957135Seric 			if (*p == '#' && p > bp && ConfigLevel >= 3)
14052647Seric 			{
14152647Seric 				/* this is an on-line comment */
14252647Seric 				register char *e;
14352647Seric 
14458050Seric 				switch (*--p & 0377)
14552647Seric 				{
14658050Seric 				  case MACROEXPAND:
14752647Seric 					/* it's from $# -- let it go through */
14852647Seric 					p++;
14952647Seric 					break;
15052647Seric 
15152647Seric 				  case '\\':
15252647Seric 					/* it's backslash escaped */
15352647Seric 					(void) strcpy(p, p + 1);
15452647Seric 					break;
15552647Seric 
15652647Seric 				  default:
15752647Seric 					/* delete preceeding white space */
15858050Seric 					while (isascii(*p) && isspace(*p) && p > bp)
15952647Seric 						p--;
16056795Seric 					if ((e = strchr(++p, '\n')) != NULL)
16152647Seric 						(void) strcpy(p, e);
16252647Seric 					else
16352647Seric 						p[0] = p[1] = '\0';
16452647Seric 					break;
16552647Seric 				}
16652647Seric 				continue;
16752647Seric 			}
16852647Seric 
16916157Seric 			if (*p != '$')
17016157Seric 				continue;
17116157Seric 
17216157Seric 			if (p[1] == '$')
17316157Seric 			{
17416157Seric 				/* actual dollar sign.... */
17523111Seric 				(void) strcpy(p, p + 1);
17616157Seric 				continue;
17716157Seric 			}
17816157Seric 
17916157Seric 			/* convert to macro expansion character */
18058050Seric 			*p = MACROEXPAND;
18116157Seric 		}
18216157Seric 
18316157Seric 		/* interpret this line */
18464718Seric 		errno = 0;
18557135Seric 		switch (bp[0])
1863308Seric 		{
1873308Seric 		  case '\0':
1883308Seric 		  case '#':		/* comment */
1893308Seric 			break;
1903308Seric 
1913308Seric 		  case 'R':		/* rewriting rule */
19257135Seric 			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
1933308Seric 				continue;
1943308Seric 
1953308Seric 			if (*p == '\0')
1965909Seric 			{
19765821Seric 				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
1985909Seric 				break;
1995909Seric 			}
2005909Seric 
2015909Seric 			/* allocate space for the rule header */
2025909Seric 			if (rwp == NULL)
2035909Seric 			{
2045909Seric 				RewriteRules[ruleset] = rwp =
2055909Seric 					(struct rewrite *) xalloc(sizeof *rwp);
2065909Seric 			}
2073308Seric 			else
2083308Seric 			{
2095909Seric 				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
2105909Seric 				rwp = rwp->r_next;
2115909Seric 			}
2125909Seric 			rwp->r_next = NULL;
2133308Seric 
2145909Seric 			/* expand and save the LHS */
2155909Seric 			*p = '\0';
21657135Seric 			expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
21765066Seric 			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
21865066Seric 					     sizeof pvpbuf, NULL);
21957589Seric 			nfuzzy = 0;
2205909Seric 			if (rwp->r_lhs != NULL)
22157589Seric 			{
22257589Seric 				register char **ap;
22357589Seric 
2245909Seric 				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
22557589Seric 
22657589Seric 				/* count the number of fuzzy matches in LHS */
22757589Seric 				for (ap = rwp->r_lhs; *ap != NULL; ap++)
22857589Seric 				{
22958148Seric 					char *botch;
23058148Seric 
23158148Seric 					botch = NULL;
23258050Seric 					switch (**ap & 0377)
23357589Seric 					{
23457589Seric 					  case MATCHZANY:
23557589Seric 					  case MATCHANY:
23657589Seric 					  case MATCHONE:
23757589Seric 					  case MATCHCLASS:
23857589Seric 					  case MATCHNCLASS:
23957589Seric 						nfuzzy++;
24058148Seric 						break;
24158148Seric 
24258148Seric 					  case MATCHREPL:
24358148Seric 						botch = "$0-$9";
24458148Seric 						break;
24558148Seric 
24658148Seric 					  case CANONNET:
24758148Seric 						botch = "$#";
24858148Seric 						break;
24958148Seric 
25058148Seric 					  case CANONUSER:
25158148Seric 						botch = "$:";
25258148Seric 						break;
25358148Seric 
25458148Seric 					  case CALLSUBR:
25558148Seric 						botch = "$>";
25658148Seric 						break;
25758148Seric 
25858148Seric 					  case CONDIF:
25958148Seric 						botch = "$?";
26058148Seric 						break;
26158148Seric 
26258148Seric 					  case CONDELSE:
26358148Seric 						botch = "$|";
26458148Seric 						break;
26558148Seric 
26658148Seric 					  case CONDFI:
26758148Seric 						botch = "$.";
26858148Seric 						break;
26958148Seric 
27058148Seric 					  case HOSTBEGIN:
27158148Seric 						botch = "$[";
27258148Seric 						break;
27358148Seric 
27458148Seric 					  case HOSTEND:
27558148Seric 						botch = "$]";
27658148Seric 						break;
27758148Seric 
27858148Seric 					  case LOOKUPBEGIN:
27958148Seric 						botch = "$(";
28058148Seric 						break;
28158148Seric 
28258148Seric 					  case LOOKUPEND:
28358148Seric 						botch = "$)";
28458148Seric 						break;
28557589Seric 					}
28658148Seric 					if (botch != NULL)
28758148Seric 						syserr("Inappropriate use of %s on LHS",
28858148Seric 							botch);
28957589Seric 				}
29057589Seric 			}
29156678Seric 			else
29256678Seric 				syserr("R line: null LHS");
2935909Seric 
2945909Seric 			/* expand and save the RHS */
2955909Seric 			while (*++p == '\t')
2965909Seric 				continue;
2977231Seric 			q = p;
2987231Seric 			while (*p != '\0' && *p != '\t')
2997231Seric 				p++;
3007231Seric 			*p = '\0';
30155012Seric 			expand(q, exbuf, &exbuf[sizeof exbuf], e);
30265066Seric 			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
30365066Seric 					     sizeof pvpbuf, NULL);
3045909Seric 			if (rwp->r_rhs != NULL)
30557589Seric 			{
30657589Seric 				register char **ap;
30757589Seric 
3085909Seric 				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
30957589Seric 
31057589Seric 				/* check no out-of-bounds replacements */
31157589Seric 				nfuzzy += '0';
31257589Seric 				for (ap = rwp->r_rhs; *ap != NULL; ap++)
31357589Seric 				{
31458148Seric 					char *botch;
31558148Seric 
31658148Seric 					botch = NULL;
31758148Seric 					switch (**ap & 0377)
31857589Seric 					{
31958148Seric 					  case MATCHREPL:
32058148Seric 						if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
32158148Seric 						{
32258148Seric 							syserr("replacement $%c out of bounds",
32358148Seric 								(*ap)[1]);
32458148Seric 						}
32558148Seric 						break;
32658148Seric 
32758148Seric 					  case MATCHZANY:
32858148Seric 						botch = "$*";
32958148Seric 						break;
33058148Seric 
33158148Seric 					  case MATCHANY:
33258148Seric 						botch = "$+";
33358148Seric 						break;
33458148Seric 
33558148Seric 					  case MATCHONE:
33658148Seric 						botch = "$-";
33758148Seric 						break;
33858148Seric 
33958148Seric 					  case MATCHCLASS:
34058148Seric 						botch = "$=";
34158148Seric 						break;
34258148Seric 
34358148Seric 					  case MATCHNCLASS:
34458148Seric 						botch = "$~";
34558148Seric 						break;
34657589Seric 					}
34758148Seric 					if (botch != NULL)
34858148Seric 						syserr("Inappropriate use of %s on RHS",
34958148Seric 							botch);
35057589Seric 				}
35157589Seric 			}
35256678Seric 			else
35356678Seric 				syserr("R line: null RHS");
3543308Seric 			break;
3553308Seric 
3564072Seric 		  case 'S':		/* select rewriting set */
35764440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
35864440Seric 				continue;
35964440Seric 			if (!isascii(*p) || !isdigit(*p))
36064440Seric 			{
36164440Seric 				syserr("invalid argument to S line: \"%.20s\"",
36264440Seric 					&bp[1]);
36364440Seric 				break;
36464440Seric 			}
36564440Seric 			ruleset = atoi(p);
3668056Seric 			if (ruleset >= MAXRWSETS || ruleset < 0)
3678056Seric 			{
3689381Seric 				syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
3698056Seric 				ruleset = 0;
3708056Seric 			}
3714072Seric 			rwp = NULL;
3724072Seric 			break;
3734072Seric 
3743308Seric 		  case 'D':		/* macro definition */
37564086Seric 			p = munchstring(&bp[2], NULL);
37664086Seric 			define(bp[1], newstr(p), e);
3773308Seric 			break;
3783308Seric 
3793387Seric 		  case 'H':		/* required header line */
38057135Seric 			(void) chompheader(&bp[1], TRUE, e);
3813387Seric 			break;
3823387Seric 
3834061Seric 		  case 'C':		/* word class */
3844432Seric 			/* scan the list of words and set class for all */
38564121Seric 			expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e);
38664121Seric 			for (p = exbuf; *p != '\0'; )
3874061Seric 			{
3884061Seric 				register char *wd;
3894061Seric 				char delim;
3904061Seric 
39158050Seric 				while (*p != '\0' && isascii(*p) && isspace(*p))
3924061Seric 					p++;
3934061Seric 				wd = p;
39458050Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3954061Seric 					p++;
3964061Seric 				delim = *p;
3974061Seric 				*p = '\0';
3984061Seric 				if (wd[0] != '\0')
39957135Seric 					setclass(bp[1], wd);
4004061Seric 				*p = delim;
4014061Seric 			}
4024061Seric 			break;
4034061Seric 
40459272Seric 		  case 'F':		/* word class from file */
40564133Seric 			for (p = &bp[2]; isascii(*p) && isspace(*p); )
40664133Seric 				p++;
40764133Seric 			if (p[0] == '-' && p[1] == 'o')
40864133Seric 			{
40964133Seric 				optional = TRUE;
41064133Seric 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
41164133Seric 					p++;
41264133Seric 				while (isascii(*p) && isspace(*p))
41367615Seric 					p++;
41464133Seric 			}
41564133Seric 			else
41664133Seric 				optional = FALSE;
41764133Seric 			file = p;
41864133Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
41964133Seric 				p++;
42059272Seric 			if (*p == '\0')
42159272Seric 				p = "%s";
42259272Seric 			else
42359272Seric 			{
42459272Seric 				*p = '\0';
42559272Seric 				while (isascii(*++p) && isspace(*p))
42659272Seric 					continue;
42759272Seric 			}
42864133Seric 			fileclass(bp[1], file, p, safe, optional);
42959272Seric 			break;
43059272Seric 
43159156Seric #ifdef XLA
43259156Seric 		  case 'L':		/* extended load average description */
43359156Seric 			xla_init(&bp[1]);
43459156Seric 			break;
43559156Seric #endif
43659156Seric 
4374096Seric 		  case 'M':		/* define mailer */
43857135Seric 			makemailer(&bp[1]);
4394096Seric 			break;
4404096Seric 
4418252Seric 		  case 'O':		/* set option */
44258734Seric 			setoption(bp[1], &bp[2], safe, FALSE, e);
4438252Seric 			break;
4448252Seric 
4458252Seric 		  case 'P':		/* set precedence */
4468252Seric 			if (NumPriorities >= MAXPRIORITIES)
4478252Seric 			{
4488547Seric 				toomany('P', MAXPRIORITIES);
4498252Seric 				break;
4508252Seric 			}
45157135Seric 			for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
4528252Seric 				continue;
4538252Seric 			if (*p == '\0')
4548252Seric 				goto badline;
4558252Seric 			*p = '\0';
45657135Seric 			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
4578252Seric 			Priorities[NumPriorities].pri_val = atoi(++p);
4588252Seric 			NumPriorities++;
4598252Seric 			break;
4608252Seric 
4618547Seric 		  case 'T':		/* trusted user(s) */
46258161Seric 			/* this option is obsolete, but will be ignored */
4638547Seric 			break;
4648547Seric 
46552645Seric 		  case 'V':		/* configuration syntax version */
46664440Seric 			for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
46764440Seric 				continue;
46864440Seric 			if (!isascii(*p) || !isdigit(*p))
46964440Seric 			{
47064440Seric 				syserr("invalid argument to V line: \"%.20s\"",
47164440Seric 					&bp[1]);
47264440Seric 				break;
47364440Seric 			}
47464718Seric 			ConfigLevel = strtol(p, &ep, 10);
47564279Seric 			if (ConfigLevel >= 5)
47664279Seric 			{
47764279Seric 				/* level 5 configs have short name in $w */
47864279Seric 				p = macvalue('w', e);
47964279Seric 				if (p != NULL && (p = strchr(p, '.')) != NULL)
48064279Seric 					*p = '\0';
48164279Seric 			}
48264718Seric 			if (*ep++ == '/')
48364718Seric 			{
48464718Seric 				/* extract vendor code */
48564718Seric 				for (p = ep; isascii(*p) && isalpha(*p); )
48664718Seric 					p++;
48764718Seric 				*p = '\0';
48864718Seric 
48964718Seric 				if (!setvendor(ep))
49064718Seric 					syserr("invalid V line vendor code: \"%s\"",
49164718Seric 						ep);
49264718Seric 			}
49352645Seric 			break;
49452645Seric 
49553654Seric 		  case 'K':
49657135Seric 			makemapentry(&bp[1]);
49753654Seric 			break;
49853654Seric 
4993308Seric 		  default:
5004061Seric 		  badline:
50157135Seric 			syserr("unknown control line \"%s\"", bp);
5023308Seric 		}
50357135Seric 		if (bp != buf)
50457135Seric 			free(bp);
5053308Seric 	}
50652637Seric 	if (ferror(cf))
50752637Seric 	{
50852647Seric 		syserr("I/O read error", cfname);
50952637Seric 		exit(EX_OSFILE);
51052637Seric 	}
51152637Seric 	fclose(cf);
5129381Seric 	FileName = NULL;
51356836Seric 
51467730Seric 	/* initialize host maps from local service tables */
51567730Seric 	inithostmaps();
51667730Seric 
51757076Seric 	if (stab("host", ST_MAP, ST_FIND) == NULL)
51857076Seric 	{
51957076Seric 		/* user didn't initialize: set up host map */
52057076Seric 		strcpy(buf, "host host");
52166334Seric #if NAMED_BIND
52257076Seric 		if (ConfigLevel >= 2)
52357076Seric 			strcat(buf, " -a.");
52464947Seric #endif
52557076Seric 		makemapentry(buf);
52657076Seric 	}
5274096Seric }
5284096Seric /*
5298547Seric **  TOOMANY -- signal too many of some option
5308547Seric **
5318547Seric **	Parameters:
5328547Seric **		id -- the id of the error line
5338547Seric **		maxcnt -- the maximum possible values
5348547Seric **
5358547Seric **	Returns:
5368547Seric **		none.
5378547Seric **
5388547Seric **	Side Effects:
5398547Seric **		gives a syserr.
5408547Seric */
5418547Seric 
5428547Seric toomany(id, maxcnt)
5438547Seric 	char id;
5448547Seric 	int maxcnt;
5458547Seric {
5469381Seric 	syserr("too many %c lines, %d max", id, maxcnt);
5478547Seric }
5488547Seric /*
5494432Seric **  FILECLASS -- read members of a class from a file
5504432Seric **
5514432Seric **	Parameters:
5524432Seric **		class -- class to define.
5534432Seric **		filename -- name of file to read.
5544432Seric **		fmt -- scanf string to use for match.
55564133Seric **		safe -- if set, this is a safe read.
55664133Seric **		optional -- if set, it is not an error for the file to
55764133Seric **			not exist.
5584432Seric **
5594432Seric **	Returns:
5604432Seric **		none
5614432Seric **
5624432Seric **	Side Effects:
5634432Seric **
5644432Seric **		puts all lines in filename that match a scanf into
5654432Seric **			the named class.
5664432Seric */
5674432Seric 
56864133Seric fileclass(class, filename, fmt, safe, optional)
5694432Seric 	int class;
5704432Seric 	char *filename;
5714432Seric 	char *fmt;
57254973Seric 	bool safe;
57364133Seric 	bool optional;
5744432Seric {
57525808Seric 	FILE *f;
57654973Seric 	struct stat stbuf;
5774432Seric 	char buf[MAXLINE];
5784432Seric 
57966101Seric 	if (tTd(37, 2))
58066101Seric 		printf("fileclass(%s, fmt=%s)\n", filename, fmt);
58166101Seric 
58266031Seric 	if (filename[0] == '|')
58366031Seric 	{
58466031Seric 		syserr("fileclass: pipes (F%c%s) not supported due to security problems",
58566031Seric 			class, filename);
58666031Seric 		return;
58766031Seric 	}
58854973Seric 	if (stat(filename, &stbuf) < 0)
58954973Seric 	{
59066101Seric 		if (tTd(37, 2))
59166101Seric 			printf("  cannot stat (%s)\n", errstring(errno));
59264133Seric 		if (!optional)
59364133Seric 			syserr("fileclass: cannot stat %s", filename);
59454973Seric 		return;
59554973Seric 	}
59654973Seric 	if (!S_ISREG(stbuf.st_mode))
59754973Seric 	{
59854973Seric 		syserr("fileclass: %s not a regular file", filename);
59954973Seric 		return;
60054973Seric 	}
60154973Seric 	if (!safe && access(filename, R_OK) < 0)
60254973Seric 	{
60354973Seric 		syserr("fileclass: access denied on %s", filename);
60454973Seric 		return;
60554973Seric 	}
60654973Seric 	f = fopen(filename, "r");
6074432Seric 	if (f == NULL)
6084432Seric 	{
60954973Seric 		syserr("fileclass: cannot open %s", filename);
6104432Seric 		return;
6114432Seric 	}
6124432Seric 
6134432Seric 	while (fgets(buf, sizeof buf, f) != NULL)
6144432Seric 	{
6154432Seric 		register STAB *s;
61625808Seric 		register char *p;
61725808Seric # ifdef SCANF
6184432Seric 		char wordbuf[MAXNAME+1];
6194432Seric 
6204432Seric 		if (sscanf(buf, fmt, wordbuf) != 1)
6214432Seric 			continue;
62225808Seric 		p = wordbuf;
62356795Seric # else /* SCANF */
62425808Seric 		p = buf;
62556795Seric # endif /* SCANF */
62625808Seric 
62725808Seric 		/*
62825808Seric 		**  Break up the match into words.
62925808Seric 		*/
63025808Seric 
63125808Seric 		while (*p != '\0')
63225808Seric 		{
63325808Seric 			register char *q;
63425808Seric 
63525808Seric 			/* strip leading spaces */
63658050Seric 			while (isascii(*p) && isspace(*p))
63725808Seric 				p++;
63825808Seric 			if (*p == '\0')
63925808Seric 				break;
64025808Seric 
64125808Seric 			/* find the end of the word */
64225808Seric 			q = p;
64358050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
64425808Seric 				p++;
64525808Seric 			if (*p != '\0')
64625808Seric 				*p++ = '\0';
64725808Seric 
64825808Seric 			/* enter the word in the symbol table */
64966101Seric 			setclass(class, q);
65025808Seric 		}
6514432Seric 	}
6524432Seric 
65354973Seric 	(void) fclose(f);
6544432Seric }
6554432Seric /*
6564096Seric **  MAKEMAILER -- define a new mailer.
6574096Seric **
6584096Seric **	Parameters:
65910327Seric **		line -- description of mailer.  This is in labeled
66010327Seric **			fields.  The fields are:
66110327Seric **			   P -- the path to the mailer
66210327Seric **			   F -- the flags associated with the mailer
66310327Seric **			   A -- the argv for this mailer
66410327Seric **			   S -- the sender rewriting set
66510327Seric **			   R -- the recipient rewriting set
66610327Seric **			   E -- the eol string
66710327Seric **			The first word is the canonical name of the mailer.
6684096Seric **
6694096Seric **	Returns:
6704096Seric **		none.
6714096Seric **
6724096Seric **	Side Effects:
6734096Seric **		enters the mailer into the mailer table.
6744096Seric */
6753308Seric 
67621066Seric makemailer(line)
6774096Seric 	char *line;
6784096Seric {
6794096Seric 	register char *p;
6808067Seric 	register struct mailer *m;
6818067Seric 	register STAB *s;
6828067Seric 	int i;
68310327Seric 	char fcode;
68458020Seric 	auto char *endp;
6854096Seric 	extern int NextMailer;
68610327Seric 	extern char **makeargv();
68710327Seric 	extern char *munchstring();
68810701Seric 	extern long atol();
6894096Seric 
69010327Seric 	/* allocate a mailer and set up defaults */
69110327Seric 	m = (struct mailer *) xalloc(sizeof *m);
69210327Seric 	bzero((char *) m, sizeof *m);
69310327Seric 	m->m_eol = "\n";
69467604Seric 	m->m_uid = m->m_gid = 0;
69510327Seric 
69610327Seric 	/* collect the mailer name */
69758050Seric 	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
69810327Seric 		continue;
69910327Seric 	if (*p != '\0')
70010327Seric 		*p++ = '\0';
70110327Seric 	m->m_name = newstr(line);
70210327Seric 
70310327Seric 	/* now scan through and assign info from the fields */
70410327Seric 	while (*p != '\0')
70510327Seric 	{
70658333Seric 		auto char *delimptr;
70758333Seric 
70858050Seric 		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
70910327Seric 			p++;
71010327Seric 
71110327Seric 		/* p now points to field code */
71210327Seric 		fcode = *p;
71310327Seric 		while (*p != '\0' && *p != '=' && *p != ',')
71410327Seric 			p++;
71510327Seric 		if (*p++ != '=')
71610327Seric 		{
71752637Seric 			syserr("mailer %s: `=' expected", m->m_name);
71810327Seric 			return;
71910327Seric 		}
72058050Seric 		while (isascii(*p) && isspace(*p))
72110327Seric 			p++;
72210327Seric 
72310327Seric 		/* p now points to the field body */
72458333Seric 		p = munchstring(p, &delimptr);
72510327Seric 
72610327Seric 		/* install the field into the mailer struct */
72710327Seric 		switch (fcode)
72810327Seric 		{
72910327Seric 		  case 'P':		/* pathname */
73010327Seric 			m->m_mailer = newstr(p);
73110327Seric 			break;
73210327Seric 
73310327Seric 		  case 'F':		/* flags */
73410687Seric 			for (; *p != '\0'; p++)
73558050Seric 				if (!(isascii(*p) && isspace(*p)))
73652637Seric 					setbitn(*p, m->m_flags);
73710327Seric 			break;
73810327Seric 
73910327Seric 		  case 'S':		/* sender rewriting ruleset */
74010327Seric 		  case 'R':		/* recipient rewriting ruleset */
74158020Seric 			i = strtol(p, &endp, 10);
74210327Seric 			if (i < 0 || i >= MAXRWSETS)
74310327Seric 			{
74410327Seric 				syserr("invalid rewrite set, %d max", MAXRWSETS);
74510327Seric 				return;
74610327Seric 			}
74710327Seric 			if (fcode == 'S')
74858020Seric 				m->m_sh_rwset = m->m_se_rwset = i;
74910327Seric 			else
75058020Seric 				m->m_rh_rwset = m->m_re_rwset = i;
75158020Seric 
75258020Seric 			p = endp;
75359985Seric 			if (*p++ == '/')
75458020Seric 			{
75558020Seric 				i = strtol(p, NULL, 10);
75658020Seric 				if (i < 0 || i >= MAXRWSETS)
75758020Seric 				{
75858020Seric 					syserr("invalid rewrite set, %d max",
75958020Seric 						MAXRWSETS);
76058020Seric 					return;
76158020Seric 				}
76258020Seric 				if (fcode == 'S')
76358020Seric 					m->m_sh_rwset = i;
76458020Seric 				else
76558020Seric 					m->m_rh_rwset = i;
76658020Seric 			}
76710327Seric 			break;
76810327Seric 
76910327Seric 		  case 'E':		/* end of line string */
77010327Seric 			m->m_eol = newstr(p);
77110327Seric 			break;
77210327Seric 
77310327Seric 		  case 'A':		/* argument vector */
77410327Seric 			m->m_argv = makeargv(p);
77510327Seric 			break;
77610701Seric 
77710701Seric 		  case 'M':		/* maximum message size */
77810701Seric 			m->m_maxsize = atol(p);
77910701Seric 			break;
78052106Seric 
78152106Seric 		  case 'L':		/* maximum line length */
78252106Seric 			m->m_linelimit = atoi(p);
78352106Seric 			break;
78458935Seric 
78558935Seric 		  case 'D':		/* working directory */
78658935Seric 			m->m_execdir = newstr(p);
78758935Seric 			break;
78867604Seric 
78967604Seric 		  case 'U':		/* user id */
79067604Seric 			if (isascii(*p) && !isdigit(*p))
79167604Seric 			{
79267604Seric 				char *q = p;
79367604Seric 				struct passwd *pw;
79467604Seric 
79567604Seric 				while (isascii(*p) && isalnum(*p))
79667604Seric 					p++;
79767604Seric 				while (isascii(*p) && isspace(*p))
79867604Seric 					*p++ = '\0';
79967604Seric 				if (*p != '\0')
80067604Seric 					*p++ = '\0';
80167604Seric 				pw = getpwnam(q);
80267604Seric 				if (pw == NULL)
80367604Seric 					syserr("readcf: mailer U= flag: unknown user %s", q);
80467604Seric 				else
80567604Seric 				{
80667604Seric 					m->m_uid = pw->pw_uid;
80767604Seric 					m->m_gid = pw->pw_gid;
80867604Seric 				}
80967604Seric 			}
81067604Seric 			else
81167604Seric 			{
81267604Seric 				auto char *q;
81367604Seric 
81467604Seric 				m->m_uid = strtol(p, &q, 0);
81567604Seric 				p = q;
81667604Seric 			}
81767604Seric 			while (isascii(*p) && isspace(*p))
81867604Seric 				p++;
81967604Seric 			if (*p == '\0')
82067604Seric 				break;
82167604Seric 			if (isascii(*p) && !isdigit(*p))
82267604Seric 			{
82367604Seric 				char *q = p;
82467604Seric 				struct group *gr;
82567604Seric 
82667604Seric 				while (isascii(*p) && isalnum(*p))
82767604Seric 					p++;
82867604Seric 				*p++ = '\0';
82967604Seric 				gr = getgrnam(q);
83067604Seric 				if (gr == NULL)
83167604Seric 					syserr("readcf: mailer U= flag: unknown group %s", q);
83267604Seric 				else
83367604Seric 					m->m_gid = gr->gr_gid;
83467604Seric 			}
83567604Seric 			else
83667604Seric 			{
83767604Seric 				m->m_gid = strtol(p, NULL, 0);
83867604Seric 			}
83967604Seric 			break;
84010327Seric 		}
84110327Seric 
84258333Seric 		p = delimptr;
84310327Seric 	}
84410327Seric 
84552106Seric 	/* do some heuristic cleanup for back compatibility */
84652106Seric 	if (bitnset(M_LIMITS, m->m_flags))
84752106Seric 	{
84852106Seric 		if (m->m_linelimit == 0)
84952106Seric 			m->m_linelimit = SMTPLINELIM;
85055418Seric 		if (ConfigLevel < 2)
85152106Seric 			setbitn(M_7BITS, m->m_flags);
85252106Seric 	}
85352106Seric 
85458321Seric 	/* do some rationality checking */
85558321Seric 	if (m->m_argv == NULL)
85658321Seric 	{
85758321Seric 		syserr("M%s: A= argument required", m->m_name);
85858321Seric 		return;
85958321Seric 	}
86058321Seric 	if (m->m_mailer == NULL)
86158321Seric 	{
86258321Seric 		syserr("M%s: P= argument required", m->m_name);
86358321Seric 		return;
86458321Seric 	}
86558321Seric 
8664096Seric 	if (NextMailer >= MAXMAILERS)
8674096Seric 	{
8689381Seric 		syserr("too many mailers defined (%d max)", MAXMAILERS);
8694096Seric 		return;
8704096Seric 	}
87157402Seric 
87210327Seric 	s = stab(m->m_name, ST_MAILER, ST_ENTER);
87357402Seric 	if (s->s_mailer != NULL)
87457402Seric 	{
87557402Seric 		i = s->s_mailer->m_mno;
87657402Seric 		free(s->s_mailer);
87757402Seric 	}
87857402Seric 	else
87957402Seric 	{
88057402Seric 		i = NextMailer++;
88157402Seric 	}
88257402Seric 	Mailer[i] = s->s_mailer = m;
88357454Seric 	m->m_mno = i;
88410327Seric }
88510327Seric /*
88610327Seric **  MUNCHSTRING -- translate a string into internal form.
88710327Seric **
88810327Seric **	Parameters:
88910327Seric **		p -- the string to munch.
89058333Seric **		delimptr -- if non-NULL, set to the pointer of the
89158333Seric **			field delimiter character.
89210327Seric **
89310327Seric **	Returns:
89410327Seric **		the munched string.
89510327Seric */
8964096Seric 
89710327Seric char *
89858333Seric munchstring(p, delimptr)
89910327Seric 	register char *p;
90058333Seric 	char **delimptr;
90110327Seric {
90210327Seric 	register char *q;
90310327Seric 	bool backslash = FALSE;
90410327Seric 	bool quotemode = FALSE;
90510327Seric 	static char buf[MAXLINE];
9064096Seric 
90710327Seric 	for (q = buf; *p != '\0'; p++)
9084096Seric 	{
90910327Seric 		if (backslash)
91010327Seric 		{
91110327Seric 			/* everything is roughly literal */
91210357Seric 			backslash = FALSE;
91310327Seric 			switch (*p)
91410327Seric 			{
91510327Seric 			  case 'r':		/* carriage return */
91610327Seric 				*q++ = '\r';
91710327Seric 				continue;
91810327Seric 
91910327Seric 			  case 'n':		/* newline */
92010327Seric 				*q++ = '\n';
92110327Seric 				continue;
92210327Seric 
92310327Seric 			  case 'f':		/* form feed */
92410327Seric 				*q++ = '\f';
92510327Seric 				continue;
92610327Seric 
92710327Seric 			  case 'b':		/* backspace */
92810327Seric 				*q++ = '\b';
92910327Seric 				continue;
93010327Seric 			}
93110327Seric 			*q++ = *p;
93210327Seric 		}
93310327Seric 		else
93410327Seric 		{
93510327Seric 			if (*p == '\\')
93610327Seric 				backslash = TRUE;
93710327Seric 			else if (*p == '"')
93810327Seric 				quotemode = !quotemode;
93910327Seric 			else if (quotemode || *p != ',')
94010327Seric 				*q++ = *p;
94110327Seric 			else
94210327Seric 				break;
94310327Seric 		}
9444096Seric 	}
9454096Seric 
94658333Seric 	if (delimptr != NULL)
94758333Seric 		*delimptr = p;
94810327Seric 	*q++ = '\0';
94910327Seric 	return (buf);
95010327Seric }
95110327Seric /*
95210327Seric **  MAKEARGV -- break up a string into words
95310327Seric **
95410327Seric **	Parameters:
95510327Seric **		p -- the string to break up.
95610327Seric **
95710327Seric **	Returns:
95810327Seric **		a char **argv (dynamically allocated)
95910327Seric **
96010327Seric **	Side Effects:
96110327Seric **		munges p.
96210327Seric */
9634096Seric 
96410327Seric char **
96510327Seric makeargv(p)
96610327Seric 	register char *p;
96710327Seric {
96810327Seric 	char *q;
96910327Seric 	int i;
97010327Seric 	char **avp;
97110327Seric 	char *argv[MAXPV + 1];
97210327Seric 
97310327Seric 	/* take apart the words */
97410327Seric 	i = 0;
97510327Seric 	while (*p != '\0' && i < MAXPV)
9764096Seric 	{
97710327Seric 		q = p;
97858050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
97910327Seric 			p++;
98058050Seric 		while (isascii(*p) && isspace(*p))
98110327Seric 			*p++ = '\0';
98210327Seric 		argv[i++] = newstr(q);
9834096Seric 	}
98410327Seric 	argv[i++] = NULL;
9854096Seric 
98610327Seric 	/* now make a copy of the argv */
98710327Seric 	avp = (char **) xalloc(sizeof *avp * i);
98816893Seric 	bcopy((char *) argv, (char *) avp, sizeof *avp * i);
98910327Seric 
99010327Seric 	return (avp);
9913308Seric }
9923308Seric /*
9933308Seric **  PRINTRULES -- print rewrite rules (for debugging)
9943308Seric **
9953308Seric **	Parameters:
9963308Seric **		none.
9973308Seric **
9983308Seric **	Returns:
9993308Seric **		none.
10003308Seric **
10013308Seric **	Side Effects:
10023308Seric **		prints rewrite rules.
10033308Seric */
10043308Seric 
10053308Seric printrules()
10063308Seric {
10073308Seric 	register struct rewrite *rwp;
10084072Seric 	register int ruleset;
10093308Seric 
10104072Seric 	for (ruleset = 0; ruleset < 10; ruleset++)
10113308Seric 	{
10124072Seric 		if (RewriteRules[ruleset] == NULL)
10134072Seric 			continue;
10148067Seric 		printf("\n----Rule Set %d:", ruleset);
10153308Seric 
10164072Seric 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
10173308Seric 		{
10188067Seric 			printf("\nLHS:");
10198067Seric 			printav(rwp->r_lhs);
10208067Seric 			printf("RHS:");
10218067Seric 			printav(rwp->r_rhs);
10223308Seric 		}
10233308Seric 	}
10243308Seric }
10254319Seric 
10264096Seric /*
10278256Seric **  SETOPTION -- set global processing option
10288256Seric **
10298256Seric **	Parameters:
10308256Seric **		opt -- option name.
10318256Seric **		val -- option value (as a text string).
103221755Seric **		safe -- set if this came from a configuration file.
103321755Seric **			Some options (if set from the command line) will
103421755Seric **			reset the user id to avoid security problems.
10358269Seric **		sticky -- if set, don't let other setoptions override
10368269Seric **			this value.
103758734Seric **		e -- the main envelope.
10388256Seric **
10398256Seric **	Returns:
10408256Seric **		none.
10418256Seric **
10428256Seric **	Side Effects:
10438256Seric **		Sets options as implied by the arguments.
10448256Seric */
10458256Seric 
104610687Seric static BITMAP	StickyOpt;		/* set if option is stuck */
10478269Seric 
104857207Seric 
104966334Seric #if NAMED_BIND
105057207Seric 
105157207Seric struct resolverflags
105257207Seric {
105357207Seric 	char	*rf_name;	/* name of the flag */
105457207Seric 	long	rf_bits;	/* bits to set/clear */
105557207Seric } ResolverFlags[] =
105657207Seric {
105757207Seric 	"debug",	RES_DEBUG,
105857207Seric 	"aaonly",	RES_AAONLY,
105957207Seric 	"usevc",	RES_USEVC,
106057207Seric 	"primary",	RES_PRIMARY,
106157207Seric 	"igntc",	RES_IGNTC,
106257207Seric 	"recurse",	RES_RECURSE,
106357207Seric 	"defnames",	RES_DEFNAMES,
106457207Seric 	"stayopen",	RES_STAYOPEN,
106557207Seric 	"dnsrch",	RES_DNSRCH,
106665583Seric 	"true",		0,		/* to avoid error on old syntax */
106757207Seric 	NULL,		0
106857207Seric };
106957207Seric 
107057207Seric #endif
107157207Seric 
107267614Seric struct optioninfo
107367614Seric {
107467614Seric 	char	*o_name;	/* long name of option */
107567614Seric 	char	o_code;		/* short name of option */
107667614Seric 	bool	o_safe;		/* safe for random people to use */
107767614Seric } OptionTab[] =
107867614Seric {
107967707Seric 	"SevenBitInput",	'7',		TRUE,
108067707Seric 	"EightBitMode",		'8',		TRUE,
108167707Seric 	"AliasFile",		'A',		FALSE,
108267707Seric 	"AliasWait",		'a',		FALSE,
108367707Seric 	"BlankSub",		'B',		FALSE,
108467707Seric 	"MinFreeBlocks",	'b',		TRUE,
108567707Seric 	"CheckpointInterval",	'C',		TRUE,
108667707Seric 	"HoldExpensive",	'c',		FALSE,
108767707Seric 	"AutoRebuildAliases",	'D',		FALSE,
108867707Seric 	"DeliveryMode",		'd',		TRUE,
108967707Seric 	"ErrorHeader",		'E',		FALSE,
109067707Seric 	"ErrorMode",		'e',		TRUE,
109167707Seric 	"TempFileMode",		'F',		FALSE,
109267707Seric 	"SaveFromLine",		'f',		FALSE,
109367707Seric 	"MatchGECOS",		'G',		FALSE,
109467707Seric 	"HelpFile",		'H',		FALSE,
109567707Seric 	"MaxHopCount",		'h',		FALSE,
109667707Seric 	"NameServerOptions",	'I',		FALSE,
109767707Seric 	"IgnoreDots",		'i',		TRUE,
109867707Seric 	"ForwardPath",		'J',		FALSE,
109967707Seric 	"SendMimeErrors",	'j',		TRUE,
110067707Seric 	"ConnectionCacheSize",	'k',		FALSE,
110167707Seric 	"ConnectionCacheTimeout", 'K',		FALSE,
110267707Seric 	"UseErrorsTo",		'l',		FALSE,
110367707Seric 	"LogLevel",		'L',		FALSE,
110467707Seric 	"MeToo",		'm',		TRUE,
110567707Seric 	"CheckAliases",		'n',		FALSE,
110667707Seric 	"OldStyleHeaders",	'o',		TRUE,
110767707Seric 	"DaemonPortOptions",	'O',		FALSE,
110867707Seric 	"PrivacyOptions",	'p',		TRUE,
110967707Seric 	"PostmasterCopy",	'P',		FALSE,
111067707Seric 	"QueueFactor",		'q',		FALSE,
111167707Seric 	"QueueDirectory",	'Q',		FALSE,
111267707Seric 	"DontPruneRoutes",	'R',		FALSE,
111367711Seric 	"Timeouts",		'r',		TRUE,
111467707Seric 	"StatusFile",		'S',		FALSE,
111567707Seric 	"SuperSafe",		's',		TRUE,
111667707Seric 	"QueueTimeout",		'T',		FALSE,
111767707Seric 	"TimeZoneSpec",		't',		FALSE,
111867707Seric 	"UserDatabaseSpec",	'U',		FALSE,
111967707Seric 	"DefaultUser",		'u',		FALSE,
112067707Seric 	"FallbackMXhost",	'V',		FALSE,
112167707Seric 	"Verbose",		'v',		TRUE,
112267707Seric 	"TryNullMXList",	'w',		TRUE,
112367707Seric 	"QueueLA",		'x',		FALSE,
112467707Seric 	"RefuseLA",		'X',		FALSE,
112567707Seric 	"RecipientFactor",	'y',		FALSE,
112667707Seric 	"ForkQueueRuns",	'Y',		FALSE,
112767707Seric 	"ClassFactor",		'z',		FALSE,
112867707Seric 	"TimeFactor",		'Z',		FALSE,
112967707Seric #define O_BSP		0x80
113067707Seric 	"BrokenSmtpPeers",	O_BSP,		TRUE,
113167707Seric #define O_SQBH		0x81
113267707Seric 	"SortQueueByHost",	O_SQBH,		TRUE,
113367707Seric #define O_DNICE		0x82
113467707Seric 	"DeliveryNiceness",	O_DNICE,	TRUE,
113567707Seric #define O_MQA		0x83
113667707Seric 	"MinQueueAge",		O_MQA,		TRUE,
113767707Seric #define O_MHSA		0x84
113867707Seric 	"MaxHostStatAge",	O_MHSA,		TRUE,
113967707Seric 
114067707Seric 	NULL,			'\0',		FALSE,
114167614Seric };
114267614Seric 
114367614Seric 
114467614Seric 
114558734Seric setoption(opt, val, safe, sticky, e)
114667614Seric 	u_char opt;
11478256Seric 	char *val;
114821755Seric 	bool safe;
11498269Seric 	bool sticky;
115058734Seric 	register ENVELOPE *e;
11518256Seric {
115257207Seric 	register char *p;
115367614Seric 	register struct optioninfo *o;
11548265Seric 	extern bool atobool();
115512633Seric 	extern time_t convtime();
115614879Seric 	extern int QueueLA;
115714879Seric 	extern int RefuseLA;
115864718Seric 	extern bool Warn_Q_option;
11598256Seric 
1160*67736Seric 	errno = 0;
116167614Seric 	if (opt == ' ')
116267614Seric 	{
116367614Seric 		/* full word options */
1164*67736Seric 		struct optioninfo *sel;
116567614Seric 
116667614Seric 		p = strchr(val, '=');
116767614Seric 		if (p == NULL)
116867614Seric 			p = &val[strlen(val)];
116967614Seric 		while (*--p == ' ')
117067614Seric 			continue;
117167614Seric 		while (*++p == ' ')
117267614Seric 			*p = '\0';
117367731Seric 		if (p == val)
117467731Seric 		{
117567731Seric 			syserr("readcf: null option name");
117667731Seric 			return;
117767731Seric 		}
117867614Seric 		if (*p == '=')
117967614Seric 			*p++ = '\0';
118067614Seric 		while (*p == ' ')
118167614Seric 			p++;
1182*67736Seric 		sel = NULL;
118367614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
118467614Seric 		{
1185*67736Seric 			if (strncasecmp(o->o_name, val, strlen(val)) != 0)
1186*67736Seric 				continue;
1187*67736Seric 			if (strlen(o->o_name) == strlen(val))
1188*67736Seric 			{
1189*67736Seric 				/* completely specified -- this must be it */
1190*67736Seric 				sel = NULL;
119167614Seric 				break;
1192*67736Seric 			}
1193*67736Seric 			if (sel != NULL)
1194*67736Seric 				break;
1195*67736Seric 			sel = o;
119667614Seric 		}
1197*67736Seric 		if (sel != NULL && o->o_name == NULL)
1198*67736Seric 			o = sel;
1199*67736Seric 		else if (o->o_name == NULL)
120067614Seric 			syserr("readcf: unknown option name %s", val);
1201*67736Seric 		else if (sel != NULL)
1202*67736Seric 		{
1203*67736Seric 			syserr("readcf: ambiguous option name %s (matches %s and %s)",
1204*67736Seric 				val, sel->o_name, o->o_name);
1205*67736Seric 			return;
1206*67736Seric 		}
1207*67736Seric 		if (strlen(val) != strlen(o->o_name))
1208*67736Seric 		{
1209*67736Seric 			bool oldVerbose = Verbose;
1210*67736Seric 
1211*67736Seric 			Verbose = TRUE;
1212*67736Seric 			message("Option %s used as abbreviation for %s",
1213*67736Seric 				val, o->o_name);
1214*67736Seric 			Verbose = oldVerbose;
1215*67736Seric 		}
121667614Seric 		opt = o->o_code;
121767614Seric 		val = p;
121867614Seric 	}
121967614Seric 	else
122067614Seric 	{
122167614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
122267614Seric 		{
122367614Seric 			if (o->o_code == opt)
122467614Seric 				break;
122567614Seric 		}
122667614Seric 	}
122767614Seric 
12288256Seric 	if (tTd(37, 1))
122967731Seric 	{
123067731Seric 		printf(isascii(opt) && isprint(opt) ?
123167731Seric 			    "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s",
123267614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
123367614Seric 			opt, val);
123467731Seric 	}
12358256Seric 
12368256Seric 	/*
12378269Seric 	**  See if this option is preset for us.
12388256Seric 	*/
12398256Seric 
124059731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12418269Seric 	{
12429341Seric 		if (tTd(37, 1))
12439341Seric 			printf(" (ignored)\n");
12448269Seric 		return;
12458269Seric 	}
12468269Seric 
124721755Seric 	/*
124821755Seric 	**  Check to see if this option can be specified by this user.
124921755Seric 	*/
125021755Seric 
125163787Seric 	if (!safe && RealUid == 0)
125221755Seric 		safe = TRUE;
125367614Seric 	if (!safe && !o->o_safe)
125421755Seric 	{
125539111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
125621755Seric 		{
125736582Sbostic 			if (tTd(37, 1))
125836582Sbostic 				printf(" (unsafe)");
125963787Seric 			if (RealUid != geteuid())
126036582Sbostic 			{
126151210Seric 				if (tTd(37, 1))
126251210Seric 					printf("(Resetting uid)");
126363787Seric 				(void) setgid(RealGid);
126463787Seric 				(void) setuid(RealUid);
126536582Sbostic 			}
126621755Seric 		}
126721755Seric 	}
126851210Seric 	if (tTd(37, 1))
126917985Seric 		printf("\n");
12708269Seric 
127167614Seric 	switch (opt & 0xff)
12728256Seric 	{
127359709Seric 	  case '7':		/* force seven-bit input */
127467546Seric 		SevenBitInput = atobool(val);
127552106Seric 		break;
127652106Seric 
127767546Seric 	  case '8':		/* handling of 8-bit input */
127867546Seric 		switch (*val)
127967546Seric 		{
128067547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
128167546Seric 			MimeMode = 0;
128267546Seric 			break;
128367546Seric 
128467547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
128567546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
128667546Seric 			break;
128767546Seric 
128867547Seric 		  case 'j':		/* "just send 8" */
128967546Seric 			MimeMode = MM_PASS8BIT;
129067546Seric 			break;
129167546Seric 
129267546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
129367546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
129467546Seric 			break;
129567546Seric 
129667546Seric 		  case 's':		/* strict adherence */
129767546Seric 			MimeMode = MM_CVTMIME;
129867546Seric 			break;
129967546Seric 
130067547Seric 		  case 'a':		/* encode 8 bit if available */
130167546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
130267546Seric 			break;
130367546Seric 
130467547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
130567547Seric 			MimeMode = MM_MIME8BIT;
130667547Seric 			break;
130767547Seric 
130867546Seric 		  default:
130967546Seric 			syserr("Unknown 8-bit mode %c", *val);
131067546Seric 			exit(EX_USAGE);
131167546Seric 		}
131267546Seric 		break;
131367546Seric 
13148256Seric 	  case 'A':		/* set default alias file */
13159381Seric 		if (val[0] == '\0')
131659672Seric 			setalias("aliases");
13179381Seric 		else
131859672Seric 			setalias(val);
13198256Seric 		break;
13208256Seric 
132117474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
132217474Seric 		if (val[0] == '\0')
132364796Seric 			SafeAlias = 5 * 60;		/* five minutes */
132417474Seric 		else
132564796Seric 			SafeAlias = convtime(val, 'm');
132617474Seric 		break;
132717474Seric 
132816843Seric 	  case 'B':		/* substitution for blank character */
132916843Seric 		SpaceSub = val[0];
133016843Seric 		if (SpaceSub == '\0')
133116843Seric 			SpaceSub = ' ';
133216843Seric 		break;
133316843Seric 
133459283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
133559283Seric 		p = strchr(val, '/');
133659283Seric 		if (p != NULL)
133759283Seric 		{
133859283Seric 			*p++ = '\0';
133959283Seric 			MaxMessageSize = atol(p);
134059283Seric 		}
134158082Seric 		MinBlocksFree = atol(val);
134258082Seric 		break;
134358082Seric 
13449284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13459381Seric 		NoConnect = atobool(val);
13469284Seric 		break;
13479284Seric 
134851305Seric 	  case 'C':		/* checkpoint every N addresses */
134951305Seric 		CheckpointInterval = atoi(val);
135024944Seric 		break;
135124944Seric 
13529284Seric 	  case 'd':		/* delivery mode */
13539284Seric 		switch (*val)
13548269Seric 		{
13559284Seric 		  case '\0':
135658734Seric 			e->e_sendmode = SM_DELIVER;
13578269Seric 			break;
13588269Seric 
135910755Seric 		  case SM_QUEUE:	/* queue only */
136010755Seric #ifndef QUEUE
136110755Seric 			syserr("need QUEUE to set -odqueue");
136256795Seric #endif /* QUEUE */
136310755Seric 			/* fall through..... */
136410755Seric 
13659284Seric 		  case SM_DELIVER:	/* do everything */
13669284Seric 		  case SM_FORK:		/* fork after verification */
136758734Seric 			e->e_sendmode = *val;
13688269Seric 			break;
13698269Seric 
13708269Seric 		  default:
13719284Seric 			syserr("Unknown delivery mode %c", *val);
13728269Seric 			exit(EX_USAGE);
13738269Seric 		}
13748269Seric 		break;
13758269Seric 
13769146Seric 	  case 'D':		/* rebuild alias database as needed */
13779381Seric 		AutoRebuild = atobool(val);
13789146Seric 		break;
13799146Seric 
138055372Seric 	  case 'E':		/* error message header/header file */
138155379Seric 		if (*val != '\0')
138255379Seric 			ErrMsgFile = newstr(val);
138355372Seric 		break;
138455372Seric 
13858269Seric 	  case 'e':		/* set error processing mode */
13868269Seric 		switch (*val)
13878269Seric 		{
13889381Seric 		  case EM_QUIET:	/* be silent about it */
13899381Seric 		  case EM_MAIL:		/* mail back */
13909381Seric 		  case EM_BERKNET:	/* do berknet error processing */
13919381Seric 		  case EM_WRITE:	/* write back (or mail) */
13929381Seric 		  case EM_PRINT:	/* print errors normally (default) */
139358734Seric 			e->e_errormode = *val;
13948269Seric 			break;
13958269Seric 		}
13968269Seric 		break;
13978269Seric 
13989049Seric 	  case 'F':		/* file mode */
139917975Seric 		FileMode = atooct(val) & 0777;
14009049Seric 		break;
14019049Seric 
14028269Seric 	  case 'f':		/* save Unix-style From lines on front */
14039381Seric 		SaveFrom = atobool(val);
14048269Seric 		break;
14058269Seric 
140653735Seric 	  case 'G':		/* match recipients against GECOS field */
140753735Seric 		MatchGecos = atobool(val);
140853735Seric 		break;
140953735Seric 
14108256Seric 	  case 'g':		/* default gid */
141164133Seric 		if (isascii(*val) && isdigit(*val))
141264133Seric 			DefGid = atoi(val);
141364133Seric 		else
141464133Seric 		{
141564133Seric 			register struct group *gr;
141664133Seric 
141764133Seric 			DefGid = -1;
141864133Seric 			gr = getgrnam(val);
141964133Seric 			if (gr == NULL)
142064133Seric 				syserr("readcf: option g: unknown group %s", val);
142164133Seric 			else
142264133Seric 				DefGid = gr->gr_gid;
142364133Seric 		}
14248256Seric 		break;
14258256Seric 
14268256Seric 	  case 'H':		/* help file */
14279381Seric 		if (val[0] == '\0')
14288269Seric 			HelpFile = "sendmail.hf";
14299381Seric 		else
14309381Seric 			HelpFile = newstr(val);
14318256Seric 		break;
14328256Seric 
143351305Seric 	  case 'h':		/* maximum hop count */
143451305Seric 		MaxHopCount = atoi(val);
143551305Seric 		break;
143651305Seric 
143735651Seric 	  case 'I':		/* use internet domain name server */
143866334Seric #if NAMED_BIND
143957207Seric 		UseNameServer = TRUE;
144057207Seric 		for (p = val; *p != 0; )
144157207Seric 		{
144257207Seric 			bool clearmode;
144357207Seric 			char *q;
144457207Seric 			struct resolverflags *rfp;
144557207Seric 
144657207Seric 			while (*p == ' ')
144757207Seric 				p++;
144857207Seric 			if (*p == '\0')
144957207Seric 				break;
145057207Seric 			clearmode = FALSE;
145157207Seric 			if (*p == '-')
145257207Seric 				clearmode = TRUE;
145357207Seric 			else if (*p != '+')
145457207Seric 				p--;
145557207Seric 			p++;
145657207Seric 			q = p;
145758050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
145857207Seric 				p++;
145957207Seric 			if (*p != '\0')
146057207Seric 				*p++ = '\0';
146157207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
146257207Seric 			{
146357207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
146457207Seric 					break;
146557207Seric 			}
146664923Seric 			if (rfp->rf_name == NULL)
146764923Seric 				syserr("readcf: I option value %s unrecognized", q);
146864923Seric 			else if (clearmode)
146957207Seric 				_res.options &= ~rfp->rf_bits;
147057207Seric 			else
147157207Seric 				_res.options |= rfp->rf_bits;
147257207Seric 		}
147357207Seric 		if (tTd(8, 2))
147457207Seric 			printf("_res.options = %x\n", _res.options);
147557207Seric #else
147657207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
147757207Seric #endif
147835651Seric 		break;
147935651Seric 
14808269Seric 	  case 'i':		/* ignore dot lines in message */
14819381Seric 		IgnrDot = atobool(val);
14828269Seric 		break;
14838269Seric 
148459730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
148559730Seric 		SendMIMEErrors = atobool(val);
148659730Seric 		break;
148759730Seric 
148857136Seric 	  case 'J':		/* .forward search path */
148957136Seric 		ForwardPath = newstr(val);
149057136Seric 		break;
149157136Seric 
149254967Seric 	  case 'k':		/* connection cache size */
149354967Seric 		MaxMciCache = atoi(val);
149456215Seric 		if (MaxMciCache < 0)
149556215Seric 			MaxMciCache = 0;
149654967Seric 		break;
149754967Seric 
149854967Seric 	  case 'K':		/* connection cache timeout */
149958796Seric 		MciCacheTimeout = convtime(val, 'm');
150054967Seric 		break;
150154967Seric 
150261104Seric 	  case 'l':		/* use Errors-To: header */
150361104Seric 		UseErrorsTo = atobool(val);
150461104Seric 		break;
150561104Seric 
15068256Seric 	  case 'L':		/* log level */
150764140Seric 		if (safe || LogLevel < atoi(val))
150864140Seric 			LogLevel = atoi(val);
15098256Seric 		break;
15108256Seric 
15118269Seric 	  case 'M':		/* define macro */
15129381Seric 		define(val[0], newstr(&val[1]), CurEnv);
151316878Seric 		sticky = FALSE;
15148269Seric 		break;
15158269Seric 
15168269Seric 	  case 'm':		/* send to me too */
15179381Seric 		MeToo = atobool(val);
15188269Seric 		break;
15198269Seric 
152025820Seric 	  case 'n':		/* validate RHS in newaliases */
152125820Seric 		CheckAliases = atobool(val);
152225820Seric 		break;
152325820Seric 
152461104Seric 	    /* 'N' available -- was "net name" */
152561104Seric 
152658851Seric 	  case 'O':		/* daemon options */
152758851Seric 		setdaemonoptions(val);
152858851Seric 		break;
152958851Seric 
15308269Seric 	  case 'o':		/* assume old style headers */
15319381Seric 		if (atobool(val))
15329341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
15339341Seric 		else
15349341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
15358269Seric 		break;
15368269Seric 
153758082Seric 	  case 'p':		/* select privacy level */
153858082Seric 		p = val;
153958082Seric 		for (;;)
154058082Seric 		{
154158082Seric 			register struct prival *pv;
154258082Seric 			extern struct prival PrivacyValues[];
154358082Seric 
154458082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
154558082Seric 				p++;
154658082Seric 			if (*p == '\0')
154758082Seric 				break;
154858082Seric 			val = p;
154958082Seric 			while (isascii(*p) && isalnum(*p))
155058082Seric 				p++;
155158082Seric 			if (*p != '\0')
155258082Seric 				*p++ = '\0';
155358082Seric 
155458082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
155558082Seric 			{
155658082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
155758082Seric 					break;
155858082Seric 			}
155958886Seric 			if (pv->pv_name == NULL)
156058886Seric 				syserr("readcf: Op line: %s unrecognized", val);
156158082Seric 			PrivacyFlags |= pv->pv_flag;
156258082Seric 		}
156358082Seric 		break;
156458082Seric 
156524944Seric 	  case 'P':		/* postmaster copy address for returned mail */
156624944Seric 		PostMasterCopy = newstr(val);
156724944Seric 		break;
156824944Seric 
156924944Seric 	  case 'q':		/* slope of queue only function */
157024944Seric 		QueueFactor = atoi(val);
157124944Seric 		break;
157224944Seric 
15738256Seric 	  case 'Q':		/* queue directory */
15749381Seric 		if (val[0] == '\0')
15758269Seric 			QueueDir = "mqueue";
15769381Seric 		else
15779381Seric 			QueueDir = newstr(val);
157858789Seric 		if (RealUid != 0 && !safe)
157964718Seric 			Warn_Q_option = TRUE;
15808256Seric 		break;
15818256Seric 
158258148Seric 	  case 'R':		/* don't prune routes */
158358148Seric 		DontPruneRoutes = atobool(val);
158458148Seric 		break;
158558148Seric 
15868256Seric 	  case 'r':		/* read timeout */
158758112Seric 		settimeouts(val);
15888256Seric 		break;
15898256Seric 
15908256Seric 	  case 'S':		/* status file */
15919381Seric 		if (val[0] == '\0')
15928269Seric 			StatFile = "sendmail.st";
15939381Seric 		else
15949381Seric 			StatFile = newstr(val);
15958256Seric 		break;
15968256Seric 
15978265Seric 	  case 's':		/* be super safe, even if expensive */
15989381Seric 		SuperSafe = atobool(val);
15998256Seric 		break;
16008256Seric 
16018256Seric 	  case 'T':		/* queue timeout */
160258737Seric 		p = strchr(val, '/');
160358737Seric 		if (p != NULL)
160458737Seric 		{
160558737Seric 			*p++ = '\0';
160667730Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd');
160758737Seric 		}
160867730Seric 		TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h');
160954967Seric 		break;
16108256Seric 
16118265Seric 	  case 't':		/* time zone name */
161252106Seric 		TimeZoneSpec = newstr(val);
16138265Seric 		break;
16148265Seric 
161550556Seric 	  case 'U':		/* location of user database */
161651360Seric 		UdbSpec = newstr(val);
161750556Seric 		break;
161850556Seric 
16198256Seric 	  case 'u':		/* set default uid */
162064133Seric 		if (isascii(*val) && isdigit(*val))
162164133Seric 			DefUid = atoi(val);
162264133Seric 		else
162364133Seric 		{
162464133Seric 			register struct passwd *pw;
162564133Seric 
162664133Seric 			DefUid = -1;
162764133Seric 			pw = getpwnam(val);
162864133Seric 			if (pw == NULL)
162964133Seric 				syserr("readcf: option u: unknown user %s", val);
163064133Seric 			else
163164133Seric 				DefUid = pw->pw_uid;
163264133Seric 		}
163340973Sbostic 		setdefuser();
16348256Seric 		break;
16358256Seric 
163658851Seric 	  case 'V':		/* fallback MX host */
163758851Seric 		FallBackMX = newstr(val);
163858851Seric 		break;
163958851Seric 
16408269Seric 	  case 'v':		/* run in verbose mode */
16419381Seric 		Verbose = atobool(val);
16428256Seric 		break;
16438256Seric 
164463837Seric 	  case 'w':		/* if we are best MX, try host directly */
164563837Seric 		TryNullMXList = atobool(val);
164663837Seric 		break;
164761104Seric 
164861104Seric 	    /* 'W' available -- was wizard password */
164961104Seric 
165014879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
165114879Seric 		QueueLA = atoi(val);
165214879Seric 		break;
165314879Seric 
165414879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
165514879Seric 		RefuseLA = atoi(val);
165614879Seric 		break;
165714879Seric 
165824981Seric 	  case 'y':		/* work recipient factor */
165924981Seric 		WkRecipFact = atoi(val);
166024981Seric 		break;
166124981Seric 
166224981Seric 	  case 'Y':		/* fork jobs during queue runs */
166324952Seric 		ForkQueueRuns = atobool(val);
166424952Seric 		break;
166524952Seric 
166624981Seric 	  case 'z':		/* work message class factor */
166724981Seric 		WkClassFact = atoi(val);
166824981Seric 		break;
166924981Seric 
167024981Seric 	  case 'Z':		/* work time factor */
167124981Seric 		WkTimeFact = atoi(val);
167224981Seric 		break;
167324981Seric 
167467614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
167567614Seric 		BrokenSmtpPeers = atobool(val);
167667614Seric 		break;
167767614Seric 
167867614Seric 	  case O_SQBH:		/* sort work queue by host first */
167967614Seric 		SortQueueByHost = atobool(val);
168067614Seric 		break;
168167614Seric 
168267707Seric 	  case O_DNICE:		/* delivery nice value */
168367707Seric 		DeliveryNiceness = atoi(val);
168467707Seric 		break;
168567707Seric 
168667707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
168767707Seric 		MinQueueAge = convtime(val, 'm');
168867707Seric 		break;
168967707Seric 
169067707Seric 	  case O_MHSA:		/* maximum age of cached host status */
169167707Seric 		MaxHostStatAge = convtime(val, 'm');
169267707Seric 		break;
169367707Seric 
16948256Seric 	  default:
16958256Seric 		break;
16968256Seric 	}
169716878Seric 	if (sticky)
169816878Seric 		setbitn(opt, StickyOpt);
16999188Seric 	return;
17008256Seric }
170110687Seric /*
170210687Seric **  SETCLASS -- set a word into a class
170310687Seric **
170410687Seric **	Parameters:
170510687Seric **		class -- the class to put the word in.
170610687Seric **		word -- the word to enter
170710687Seric **
170810687Seric **	Returns:
170910687Seric **		none.
171010687Seric **
171110687Seric **	Side Effects:
171210687Seric **		puts the word into the symbol table.
171310687Seric */
171410687Seric 
171510687Seric setclass(class, word)
171610687Seric 	int class;
171710687Seric 	char *word;
171810687Seric {
171910687Seric 	register STAB *s;
172010687Seric 
172157943Seric 	if (tTd(37, 8))
172264326Seric 		printf("setclass(%c, %s)\n", class, word);
172310687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
172410687Seric 	setbitn(class, s->s_class);
172510687Seric }
172653654Seric /*
172753654Seric **  MAKEMAPENTRY -- create a map entry
172853654Seric **
172953654Seric **	Parameters:
173053654Seric **		line -- the config file line
173153654Seric **
173253654Seric **	Returns:
173353654Seric **		TRUE if it successfully entered the map entry.
173453654Seric **		FALSE otherwise (usually syntax error).
173553654Seric **
173653654Seric **	Side Effects:
173753654Seric **		Enters the map into the dictionary.
173853654Seric */
173953654Seric 
174053654Seric void
174153654Seric makemapentry(line)
174253654Seric 	char *line;
174353654Seric {
174453654Seric 	register char *p;
174553654Seric 	char *mapname;
174653654Seric 	char *classname;
174764078Seric 	register STAB *s;
174853654Seric 	STAB *class;
174953654Seric 
175058050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
175153654Seric 		continue;
175258050Seric 	if (!(isascii(*p) && isalnum(*p)))
175353654Seric 	{
175453654Seric 		syserr("readcf: config K line: no map name");
175553654Seric 		return;
175653654Seric 	}
175753654Seric 
175853654Seric 	mapname = p;
175958050Seric 	while (isascii(*++p) && isalnum(*p))
176053654Seric 		continue;
176153654Seric 	if (*p != '\0')
176253654Seric 		*p++ = '\0';
176358050Seric 	while (isascii(*p) && isspace(*p))
176453654Seric 		p++;
176558050Seric 	if (!(isascii(*p) && isalnum(*p)))
176653654Seric 	{
176753654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
176853654Seric 		return;
176953654Seric 	}
177053654Seric 	classname = p;
177158050Seric 	while (isascii(*++p) && isalnum(*p))
177253654Seric 		continue;
177353654Seric 	if (*p != '\0')
177453654Seric 		*p++ = '\0';
177558050Seric 	while (isascii(*p) && isspace(*p))
177653654Seric 		p++;
177753654Seric 
177853654Seric 	/* look up the class */
177953654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
178053654Seric 	if (class == NULL)
178153654Seric 	{
178253654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
178353654Seric 		return;
178453654Seric 	}
178553654Seric 
178653654Seric 	/* enter the map */
178764078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
178864078Seric 	s->s_map.map_class = &class->s_mapclass;
178964078Seric 	s->s_map.map_mname = newstr(mapname);
179053654Seric 
179164078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
179264078Seric 		s->s_map.map_mflags |= MF_VALID;
179364078Seric 
179464078Seric 	if (tTd(37, 5))
179564078Seric 	{
179664078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
179764078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
179864078Seric 			s->s_map.map_mflags,
179964078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
180064078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
180164078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
180264078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
180364078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
180464078Seric 	}
180553654Seric }
180658112Seric /*
180758112Seric **  SETTIMEOUTS -- parse and set timeout values
180858112Seric **
180958112Seric **	Parameters:
181058112Seric **		val -- a pointer to the values.  If NULL, do initial
181158112Seric **			settings.
181258112Seric **
181358112Seric **	Returns:
181458112Seric **		none.
181558112Seric **
181658112Seric **	Side Effects:
181758112Seric **		Initializes the TimeOuts structure
181858112Seric */
181958112Seric 
182064255Seric #define SECONDS
182158112Seric #define MINUTES	* 60
182258112Seric #define HOUR	* 3600
182358112Seric 
182458112Seric settimeouts(val)
182558112Seric 	register char *val;
182658112Seric {
182758112Seric 	register char *p;
182858671Seric 	extern time_t convtime();
182958112Seric 
183058112Seric 	if (val == NULL)
183158112Seric 	{
183258112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
183358112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
183458112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
183558112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
183658112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
183758112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
183858112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
183958112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
184058112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
184158112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
184258112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
184364255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
184467711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
184558112Seric 		return;
184658112Seric 	}
184758112Seric 
184858112Seric 	for (;; val = p)
184958112Seric 	{
185058112Seric 		while (isascii(*val) && isspace(*val))
185158112Seric 			val++;
185258112Seric 		if (*val == '\0')
185358112Seric 			break;
185458112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
185558112Seric 			continue;
185658112Seric 		if (*p != '\0')
185758112Seric 			*p++ = '\0';
185858112Seric 
185958112Seric 		if (isascii(*val) && isdigit(*val))
186058112Seric 		{
186158112Seric 			/* old syntax -- set everything */
186258796Seric 			TimeOuts.to_mail = convtime(val, 'm');
186358112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
186458112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
186558112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
186658112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
186758112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
186858112Seric 			continue;
186958112Seric 		}
187058112Seric 		else
187158112Seric 		{
187267711Seric 			register char *q = strchr(val, ':');
187358112Seric 			time_t to;
187458112Seric 
187567711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
187658112Seric 			{
187758112Seric 				/* syntax error */
187858112Seric 				continue;
187958112Seric 			}
188058112Seric 			*q++ = '\0';
188158796Seric 			to = convtime(q, 'm');
188258112Seric 
188358112Seric 			if (strcasecmp(val, "initial") == 0)
188458112Seric 				TimeOuts.to_initial = to;
188558112Seric 			else if (strcasecmp(val, "mail") == 0)
188658112Seric 				TimeOuts.to_mail = to;
188758112Seric 			else if (strcasecmp(val, "rcpt") == 0)
188858112Seric 				TimeOuts.to_rcpt = to;
188958112Seric 			else if (strcasecmp(val, "datainit") == 0)
189058112Seric 				TimeOuts.to_datainit = to;
189158112Seric 			else if (strcasecmp(val, "datablock") == 0)
189258112Seric 				TimeOuts.to_datablock = to;
189358112Seric 			else if (strcasecmp(val, "datafinal") == 0)
189458112Seric 				TimeOuts.to_datafinal = to;
189558112Seric 			else if (strcasecmp(val, "command") == 0)
189658112Seric 				TimeOuts.to_nextcommand = to;
189758112Seric 			else if (strcasecmp(val, "rset") == 0)
189858112Seric 				TimeOuts.to_rset = to;
189958112Seric 			else if (strcasecmp(val, "helo") == 0)
190058112Seric 				TimeOuts.to_helo = to;
190158112Seric 			else if (strcasecmp(val, "quit") == 0)
190258112Seric 				TimeOuts.to_quit = to;
190358112Seric 			else if (strcasecmp(val, "misc") == 0)
190458112Seric 				TimeOuts.to_miscshort = to;
190564255Seric 			else if (strcasecmp(val, "ident") == 0)
190664255Seric 				TimeOuts.to_ident = to;
190767711Seric 			else if (strcasecmp(val, "fileopen") == 0)
190867711Seric 				TimeOuts.to_fileopen = to;
190967711Seric 			else if (strcasecmp(val, "queuewarn") == 0)
191067730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
191167711Seric 			else if (strcasecmp(val, "queuereturn") == 0)
191267730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
191367730Seric 			else if (strcasecmp(val, "queuewarn.normal") == 0)
191467730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
191567730Seric 			else if (strcasecmp(val, "queuereturn.normal") == 0)
191667730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
191767730Seric 			else if (strcasecmp(val, "queuewarn.urgent") == 0)
191867730Seric 				TimeOuts.to_q_warning[TOC_URGENT] = to;
191967730Seric 			else if (strcasecmp(val, "queuereturn.urgent") == 0)
192067730Seric 				TimeOuts.to_q_return[TOC_URGENT] = to;
192167730Seric 			else if (strcasecmp(val, "queuewarn.non-urgent") == 0)
192267730Seric 				TimeOuts.to_q_warning[TOC_NONURGENT] = to;
192367730Seric 			else if (strcasecmp(val, "queuereturn.non-urgent") == 0)
192467730Seric 				TimeOuts.to_q_return[TOC_NONURGENT] = to;
192558112Seric 			else
192658112Seric 				syserr("settimeouts: invalid timeout %s", val);
192758112Seric 		}
192858112Seric 	}
192958112Seric }
1930