xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67731)
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*67731Seric static char sccsid[] = "@(#)readcf.c	8.36 (Berkeley) 08/22/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 
116067614Seric 	if (opt == ' ')
116167614Seric 	{
116267614Seric 		/* full word options */
116367614Seric 
116467614Seric 		p = strchr(val, '=');
116567614Seric 		if (p == NULL)
116667614Seric 			p = &val[strlen(val)];
116767614Seric 		while (*--p == ' ')
116867614Seric 			continue;
116967614Seric 		while (*++p == ' ')
117067614Seric 			*p = '\0';
1171*67731Seric 		if (p == val)
1172*67731Seric 		{
1173*67731Seric 			syserr("readcf: null option name");
1174*67731Seric 			return;
1175*67731Seric 		}
117667614Seric 		if (*p == '=')
117767614Seric 			*p++ = '\0';
117867614Seric 		while (*p == ' ')
117967614Seric 			p++;
118067614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
118167614Seric 		{
118267614Seric 			if (strcasecmp(o->o_name, val) == 0)
118367614Seric 				break;
118467614Seric 		}
118567614Seric 		if (o->o_name == NULL)
118667614Seric 			syserr("readcf: unknown option name %s", val);
118767614Seric 		opt = o->o_code;
118867614Seric 		val = p;
118967614Seric 	}
119067614Seric 	else
119167614Seric 	{
119267614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
119367614Seric 		{
119467614Seric 			if (o->o_code == opt)
119567614Seric 				break;
119667614Seric 		}
119767614Seric 	}
119867614Seric 
11998256Seric 	if (tTd(37, 1))
1200*67731Seric 	{
1201*67731Seric 		printf(isascii(opt) && isprint(opt) ?
1202*67731Seric 			    "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s",
120367614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
120467614Seric 			opt, val);
1205*67731Seric 	}
12068256Seric 
12078256Seric 	/*
12088269Seric 	**  See if this option is preset for us.
12098256Seric 	*/
12108256Seric 
121159731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12128269Seric 	{
12139341Seric 		if (tTd(37, 1))
12149341Seric 			printf(" (ignored)\n");
12158269Seric 		return;
12168269Seric 	}
12178269Seric 
121821755Seric 	/*
121921755Seric 	**  Check to see if this option can be specified by this user.
122021755Seric 	*/
122121755Seric 
122263787Seric 	if (!safe && RealUid == 0)
122321755Seric 		safe = TRUE;
122467614Seric 	if (!safe && !o->o_safe)
122521755Seric 	{
122639111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
122721755Seric 		{
122836582Sbostic 			if (tTd(37, 1))
122936582Sbostic 				printf(" (unsafe)");
123063787Seric 			if (RealUid != geteuid())
123136582Sbostic 			{
123251210Seric 				if (tTd(37, 1))
123351210Seric 					printf("(Resetting uid)");
123463787Seric 				(void) setgid(RealGid);
123563787Seric 				(void) setuid(RealUid);
123636582Sbostic 			}
123721755Seric 		}
123821755Seric 	}
123951210Seric 	if (tTd(37, 1))
124017985Seric 		printf("\n");
12418269Seric 
124267614Seric 	switch (opt & 0xff)
12438256Seric 	{
124459709Seric 	  case '7':		/* force seven-bit input */
124567546Seric 		SevenBitInput = atobool(val);
124652106Seric 		break;
124752106Seric 
124867546Seric 	  case '8':		/* handling of 8-bit input */
124967546Seric 		switch (*val)
125067546Seric 		{
125167547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
125267546Seric 			MimeMode = 0;
125367546Seric 			break;
125467546Seric 
125567547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
125667546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
125767546Seric 			break;
125867546Seric 
125967547Seric 		  case 'j':		/* "just send 8" */
126067546Seric 			MimeMode = MM_PASS8BIT;
126167546Seric 			break;
126267546Seric 
126367546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
126467546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
126567546Seric 			break;
126667546Seric 
126767546Seric 		  case 's':		/* strict adherence */
126867546Seric 			MimeMode = MM_CVTMIME;
126967546Seric 			break;
127067546Seric 
127167547Seric 		  case 'a':		/* encode 8 bit if available */
127267546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
127367546Seric 			break;
127467546Seric 
127567547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
127667547Seric 			MimeMode = MM_MIME8BIT;
127767547Seric 			break;
127867547Seric 
127967546Seric 		  default:
128067546Seric 			syserr("Unknown 8-bit mode %c", *val);
128167546Seric 			exit(EX_USAGE);
128267546Seric 		}
128367546Seric 		break;
128467546Seric 
12858256Seric 	  case 'A':		/* set default alias file */
12869381Seric 		if (val[0] == '\0')
128759672Seric 			setalias("aliases");
12889381Seric 		else
128959672Seric 			setalias(val);
12908256Seric 		break;
12918256Seric 
129217474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
129317474Seric 		if (val[0] == '\0')
129464796Seric 			SafeAlias = 5 * 60;		/* five minutes */
129517474Seric 		else
129664796Seric 			SafeAlias = convtime(val, 'm');
129717474Seric 		break;
129817474Seric 
129916843Seric 	  case 'B':		/* substitution for blank character */
130016843Seric 		SpaceSub = val[0];
130116843Seric 		if (SpaceSub == '\0')
130216843Seric 			SpaceSub = ' ';
130316843Seric 		break;
130416843Seric 
130559283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
130659283Seric 		p = strchr(val, '/');
130759283Seric 		if (p != NULL)
130859283Seric 		{
130959283Seric 			*p++ = '\0';
131059283Seric 			MaxMessageSize = atol(p);
131159283Seric 		}
131258082Seric 		MinBlocksFree = atol(val);
131358082Seric 		break;
131458082Seric 
13159284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13169381Seric 		NoConnect = atobool(val);
13179284Seric 		break;
13189284Seric 
131951305Seric 	  case 'C':		/* checkpoint every N addresses */
132051305Seric 		CheckpointInterval = atoi(val);
132124944Seric 		break;
132224944Seric 
13239284Seric 	  case 'd':		/* delivery mode */
13249284Seric 		switch (*val)
13258269Seric 		{
13269284Seric 		  case '\0':
132758734Seric 			e->e_sendmode = SM_DELIVER;
13288269Seric 			break;
13298269Seric 
133010755Seric 		  case SM_QUEUE:	/* queue only */
133110755Seric #ifndef QUEUE
133210755Seric 			syserr("need QUEUE to set -odqueue");
133356795Seric #endif /* QUEUE */
133410755Seric 			/* fall through..... */
133510755Seric 
13369284Seric 		  case SM_DELIVER:	/* do everything */
13379284Seric 		  case SM_FORK:		/* fork after verification */
133858734Seric 			e->e_sendmode = *val;
13398269Seric 			break;
13408269Seric 
13418269Seric 		  default:
13429284Seric 			syserr("Unknown delivery mode %c", *val);
13438269Seric 			exit(EX_USAGE);
13448269Seric 		}
13458269Seric 		break;
13468269Seric 
13479146Seric 	  case 'D':		/* rebuild alias database as needed */
13489381Seric 		AutoRebuild = atobool(val);
13499146Seric 		break;
13509146Seric 
135155372Seric 	  case 'E':		/* error message header/header file */
135255379Seric 		if (*val != '\0')
135355379Seric 			ErrMsgFile = newstr(val);
135455372Seric 		break;
135555372Seric 
13568269Seric 	  case 'e':		/* set error processing mode */
13578269Seric 		switch (*val)
13588269Seric 		{
13599381Seric 		  case EM_QUIET:	/* be silent about it */
13609381Seric 		  case EM_MAIL:		/* mail back */
13619381Seric 		  case EM_BERKNET:	/* do berknet error processing */
13629381Seric 		  case EM_WRITE:	/* write back (or mail) */
13639381Seric 		  case EM_PRINT:	/* print errors normally (default) */
136458734Seric 			e->e_errormode = *val;
13658269Seric 			break;
13668269Seric 		}
13678269Seric 		break;
13688269Seric 
13699049Seric 	  case 'F':		/* file mode */
137017975Seric 		FileMode = atooct(val) & 0777;
13719049Seric 		break;
13729049Seric 
13738269Seric 	  case 'f':		/* save Unix-style From lines on front */
13749381Seric 		SaveFrom = atobool(val);
13758269Seric 		break;
13768269Seric 
137753735Seric 	  case 'G':		/* match recipients against GECOS field */
137853735Seric 		MatchGecos = atobool(val);
137953735Seric 		break;
138053735Seric 
13818256Seric 	  case 'g':		/* default gid */
138264133Seric 		if (isascii(*val) && isdigit(*val))
138364133Seric 			DefGid = atoi(val);
138464133Seric 		else
138564133Seric 		{
138664133Seric 			register struct group *gr;
138764133Seric 
138864133Seric 			DefGid = -1;
138964133Seric 			gr = getgrnam(val);
139064133Seric 			if (gr == NULL)
139164133Seric 				syserr("readcf: option g: unknown group %s", val);
139264133Seric 			else
139364133Seric 				DefGid = gr->gr_gid;
139464133Seric 		}
13958256Seric 		break;
13968256Seric 
13978256Seric 	  case 'H':		/* help file */
13989381Seric 		if (val[0] == '\0')
13998269Seric 			HelpFile = "sendmail.hf";
14009381Seric 		else
14019381Seric 			HelpFile = newstr(val);
14028256Seric 		break;
14038256Seric 
140451305Seric 	  case 'h':		/* maximum hop count */
140551305Seric 		MaxHopCount = atoi(val);
140651305Seric 		break;
140751305Seric 
140835651Seric 	  case 'I':		/* use internet domain name server */
140966334Seric #if NAMED_BIND
141057207Seric 		UseNameServer = TRUE;
141157207Seric 		for (p = val; *p != 0; )
141257207Seric 		{
141357207Seric 			bool clearmode;
141457207Seric 			char *q;
141557207Seric 			struct resolverflags *rfp;
141657207Seric 
141757207Seric 			while (*p == ' ')
141857207Seric 				p++;
141957207Seric 			if (*p == '\0')
142057207Seric 				break;
142157207Seric 			clearmode = FALSE;
142257207Seric 			if (*p == '-')
142357207Seric 				clearmode = TRUE;
142457207Seric 			else if (*p != '+')
142557207Seric 				p--;
142657207Seric 			p++;
142757207Seric 			q = p;
142858050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
142957207Seric 				p++;
143057207Seric 			if (*p != '\0')
143157207Seric 				*p++ = '\0';
143257207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
143357207Seric 			{
143457207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
143557207Seric 					break;
143657207Seric 			}
143764923Seric 			if (rfp->rf_name == NULL)
143864923Seric 				syserr("readcf: I option value %s unrecognized", q);
143964923Seric 			else if (clearmode)
144057207Seric 				_res.options &= ~rfp->rf_bits;
144157207Seric 			else
144257207Seric 				_res.options |= rfp->rf_bits;
144357207Seric 		}
144457207Seric 		if (tTd(8, 2))
144557207Seric 			printf("_res.options = %x\n", _res.options);
144657207Seric #else
144757207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
144857207Seric #endif
144935651Seric 		break;
145035651Seric 
14518269Seric 	  case 'i':		/* ignore dot lines in message */
14529381Seric 		IgnrDot = atobool(val);
14538269Seric 		break;
14548269Seric 
145559730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
145659730Seric 		SendMIMEErrors = atobool(val);
145759730Seric 		break;
145859730Seric 
145957136Seric 	  case 'J':		/* .forward search path */
146057136Seric 		ForwardPath = newstr(val);
146157136Seric 		break;
146257136Seric 
146354967Seric 	  case 'k':		/* connection cache size */
146454967Seric 		MaxMciCache = atoi(val);
146556215Seric 		if (MaxMciCache < 0)
146656215Seric 			MaxMciCache = 0;
146754967Seric 		break;
146854967Seric 
146954967Seric 	  case 'K':		/* connection cache timeout */
147058796Seric 		MciCacheTimeout = convtime(val, 'm');
147154967Seric 		break;
147254967Seric 
147361104Seric 	  case 'l':		/* use Errors-To: header */
147461104Seric 		UseErrorsTo = atobool(val);
147561104Seric 		break;
147661104Seric 
14778256Seric 	  case 'L':		/* log level */
147864140Seric 		if (safe || LogLevel < atoi(val))
147964140Seric 			LogLevel = atoi(val);
14808256Seric 		break;
14818256Seric 
14828269Seric 	  case 'M':		/* define macro */
14839381Seric 		define(val[0], newstr(&val[1]), CurEnv);
148416878Seric 		sticky = FALSE;
14858269Seric 		break;
14868269Seric 
14878269Seric 	  case 'm':		/* send to me too */
14889381Seric 		MeToo = atobool(val);
14898269Seric 		break;
14908269Seric 
149125820Seric 	  case 'n':		/* validate RHS in newaliases */
149225820Seric 		CheckAliases = atobool(val);
149325820Seric 		break;
149425820Seric 
149561104Seric 	    /* 'N' available -- was "net name" */
149661104Seric 
149758851Seric 	  case 'O':		/* daemon options */
149858851Seric 		setdaemonoptions(val);
149958851Seric 		break;
150058851Seric 
15018269Seric 	  case 'o':		/* assume old style headers */
15029381Seric 		if (atobool(val))
15039341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
15049341Seric 		else
15059341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
15068269Seric 		break;
15078269Seric 
150858082Seric 	  case 'p':		/* select privacy level */
150958082Seric 		p = val;
151058082Seric 		for (;;)
151158082Seric 		{
151258082Seric 			register struct prival *pv;
151358082Seric 			extern struct prival PrivacyValues[];
151458082Seric 
151558082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
151658082Seric 				p++;
151758082Seric 			if (*p == '\0')
151858082Seric 				break;
151958082Seric 			val = p;
152058082Seric 			while (isascii(*p) && isalnum(*p))
152158082Seric 				p++;
152258082Seric 			if (*p != '\0')
152358082Seric 				*p++ = '\0';
152458082Seric 
152558082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
152658082Seric 			{
152758082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
152858082Seric 					break;
152958082Seric 			}
153058886Seric 			if (pv->pv_name == NULL)
153158886Seric 				syserr("readcf: Op line: %s unrecognized", val);
153258082Seric 			PrivacyFlags |= pv->pv_flag;
153358082Seric 		}
153458082Seric 		break;
153558082Seric 
153624944Seric 	  case 'P':		/* postmaster copy address for returned mail */
153724944Seric 		PostMasterCopy = newstr(val);
153824944Seric 		break;
153924944Seric 
154024944Seric 	  case 'q':		/* slope of queue only function */
154124944Seric 		QueueFactor = atoi(val);
154224944Seric 		break;
154324944Seric 
15448256Seric 	  case 'Q':		/* queue directory */
15459381Seric 		if (val[0] == '\0')
15468269Seric 			QueueDir = "mqueue";
15479381Seric 		else
15489381Seric 			QueueDir = newstr(val);
154958789Seric 		if (RealUid != 0 && !safe)
155064718Seric 			Warn_Q_option = TRUE;
15518256Seric 		break;
15528256Seric 
155358148Seric 	  case 'R':		/* don't prune routes */
155458148Seric 		DontPruneRoutes = atobool(val);
155558148Seric 		break;
155658148Seric 
15578256Seric 	  case 'r':		/* read timeout */
155858112Seric 		settimeouts(val);
15598256Seric 		break;
15608256Seric 
15618256Seric 	  case 'S':		/* status file */
15629381Seric 		if (val[0] == '\0')
15638269Seric 			StatFile = "sendmail.st";
15649381Seric 		else
15659381Seric 			StatFile = newstr(val);
15668256Seric 		break;
15678256Seric 
15688265Seric 	  case 's':		/* be super safe, even if expensive */
15699381Seric 		SuperSafe = atobool(val);
15708256Seric 		break;
15718256Seric 
15728256Seric 	  case 'T':		/* queue timeout */
157358737Seric 		p = strchr(val, '/');
157458737Seric 		if (p != NULL)
157558737Seric 		{
157658737Seric 			*p++ = '\0';
157767730Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd');
157858737Seric 		}
157967730Seric 		TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h');
158054967Seric 		break;
15818256Seric 
15828265Seric 	  case 't':		/* time zone name */
158352106Seric 		TimeZoneSpec = newstr(val);
15848265Seric 		break;
15858265Seric 
158650556Seric 	  case 'U':		/* location of user database */
158751360Seric 		UdbSpec = newstr(val);
158850556Seric 		break;
158950556Seric 
15908256Seric 	  case 'u':		/* set default uid */
159164133Seric 		if (isascii(*val) && isdigit(*val))
159264133Seric 			DefUid = atoi(val);
159364133Seric 		else
159464133Seric 		{
159564133Seric 			register struct passwd *pw;
159664133Seric 
159764133Seric 			DefUid = -1;
159864133Seric 			pw = getpwnam(val);
159964133Seric 			if (pw == NULL)
160064133Seric 				syserr("readcf: option u: unknown user %s", val);
160164133Seric 			else
160264133Seric 				DefUid = pw->pw_uid;
160364133Seric 		}
160440973Sbostic 		setdefuser();
16058256Seric 		break;
16068256Seric 
160758851Seric 	  case 'V':		/* fallback MX host */
160858851Seric 		FallBackMX = newstr(val);
160958851Seric 		break;
161058851Seric 
16118269Seric 	  case 'v':		/* run in verbose mode */
16129381Seric 		Verbose = atobool(val);
16138256Seric 		break;
16148256Seric 
161563837Seric 	  case 'w':		/* if we are best MX, try host directly */
161663837Seric 		TryNullMXList = atobool(val);
161763837Seric 		break;
161861104Seric 
161961104Seric 	    /* 'W' available -- was wizard password */
162061104Seric 
162114879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
162214879Seric 		QueueLA = atoi(val);
162314879Seric 		break;
162414879Seric 
162514879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
162614879Seric 		RefuseLA = atoi(val);
162714879Seric 		break;
162814879Seric 
162924981Seric 	  case 'y':		/* work recipient factor */
163024981Seric 		WkRecipFact = atoi(val);
163124981Seric 		break;
163224981Seric 
163324981Seric 	  case 'Y':		/* fork jobs during queue runs */
163424952Seric 		ForkQueueRuns = atobool(val);
163524952Seric 		break;
163624952Seric 
163724981Seric 	  case 'z':		/* work message class factor */
163824981Seric 		WkClassFact = atoi(val);
163924981Seric 		break;
164024981Seric 
164124981Seric 	  case 'Z':		/* work time factor */
164224981Seric 		WkTimeFact = atoi(val);
164324981Seric 		break;
164424981Seric 
164567614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
164667614Seric 		BrokenSmtpPeers = atobool(val);
164767614Seric 		break;
164867614Seric 
164967614Seric 	  case O_SQBH:		/* sort work queue by host first */
165067614Seric 		SortQueueByHost = atobool(val);
165167614Seric 		break;
165267614Seric 
165367707Seric 	  case O_DNICE:		/* delivery nice value */
165467707Seric 		DeliveryNiceness = atoi(val);
165567707Seric 		break;
165667707Seric 
165767707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
165867707Seric 		MinQueueAge = convtime(val, 'm');
165967707Seric 		break;
166067707Seric 
166167707Seric 	  case O_MHSA:		/* maximum age of cached host status */
166267707Seric 		MaxHostStatAge = convtime(val, 'm');
166367707Seric 		break;
166467707Seric 
16658256Seric 	  default:
16668256Seric 		break;
16678256Seric 	}
166816878Seric 	if (sticky)
166916878Seric 		setbitn(opt, StickyOpt);
16709188Seric 	return;
16718256Seric }
167210687Seric /*
167310687Seric **  SETCLASS -- set a word into a class
167410687Seric **
167510687Seric **	Parameters:
167610687Seric **		class -- the class to put the word in.
167710687Seric **		word -- the word to enter
167810687Seric **
167910687Seric **	Returns:
168010687Seric **		none.
168110687Seric **
168210687Seric **	Side Effects:
168310687Seric **		puts the word into the symbol table.
168410687Seric */
168510687Seric 
168610687Seric setclass(class, word)
168710687Seric 	int class;
168810687Seric 	char *word;
168910687Seric {
169010687Seric 	register STAB *s;
169110687Seric 
169257943Seric 	if (tTd(37, 8))
169364326Seric 		printf("setclass(%c, %s)\n", class, word);
169410687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
169510687Seric 	setbitn(class, s->s_class);
169610687Seric }
169753654Seric /*
169853654Seric **  MAKEMAPENTRY -- create a map entry
169953654Seric **
170053654Seric **	Parameters:
170153654Seric **		line -- the config file line
170253654Seric **
170353654Seric **	Returns:
170453654Seric **		TRUE if it successfully entered the map entry.
170553654Seric **		FALSE otherwise (usually syntax error).
170653654Seric **
170753654Seric **	Side Effects:
170853654Seric **		Enters the map into the dictionary.
170953654Seric */
171053654Seric 
171153654Seric void
171253654Seric makemapentry(line)
171353654Seric 	char *line;
171453654Seric {
171553654Seric 	register char *p;
171653654Seric 	char *mapname;
171753654Seric 	char *classname;
171864078Seric 	register STAB *s;
171953654Seric 	STAB *class;
172053654Seric 
172158050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
172253654Seric 		continue;
172358050Seric 	if (!(isascii(*p) && isalnum(*p)))
172453654Seric 	{
172553654Seric 		syserr("readcf: config K line: no map name");
172653654Seric 		return;
172753654Seric 	}
172853654Seric 
172953654Seric 	mapname = p;
173058050Seric 	while (isascii(*++p) && isalnum(*p))
173153654Seric 		continue;
173253654Seric 	if (*p != '\0')
173353654Seric 		*p++ = '\0';
173458050Seric 	while (isascii(*p) && isspace(*p))
173553654Seric 		p++;
173658050Seric 	if (!(isascii(*p) && isalnum(*p)))
173753654Seric 	{
173853654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
173953654Seric 		return;
174053654Seric 	}
174153654Seric 	classname = p;
174258050Seric 	while (isascii(*++p) && isalnum(*p))
174353654Seric 		continue;
174453654Seric 	if (*p != '\0')
174553654Seric 		*p++ = '\0';
174658050Seric 	while (isascii(*p) && isspace(*p))
174753654Seric 		p++;
174853654Seric 
174953654Seric 	/* look up the class */
175053654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
175153654Seric 	if (class == NULL)
175253654Seric 	{
175353654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
175453654Seric 		return;
175553654Seric 	}
175653654Seric 
175753654Seric 	/* enter the map */
175864078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
175964078Seric 	s->s_map.map_class = &class->s_mapclass;
176064078Seric 	s->s_map.map_mname = newstr(mapname);
176153654Seric 
176264078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
176364078Seric 		s->s_map.map_mflags |= MF_VALID;
176464078Seric 
176564078Seric 	if (tTd(37, 5))
176664078Seric 	{
176764078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
176864078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
176964078Seric 			s->s_map.map_mflags,
177064078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
177164078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
177264078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
177364078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
177464078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
177564078Seric 	}
177653654Seric }
177758112Seric /*
177858112Seric **  SETTIMEOUTS -- parse and set timeout values
177958112Seric **
178058112Seric **	Parameters:
178158112Seric **		val -- a pointer to the values.  If NULL, do initial
178258112Seric **			settings.
178358112Seric **
178458112Seric **	Returns:
178558112Seric **		none.
178658112Seric **
178758112Seric **	Side Effects:
178858112Seric **		Initializes the TimeOuts structure
178958112Seric */
179058112Seric 
179164255Seric #define SECONDS
179258112Seric #define MINUTES	* 60
179358112Seric #define HOUR	* 3600
179458112Seric 
179558112Seric settimeouts(val)
179658112Seric 	register char *val;
179758112Seric {
179858112Seric 	register char *p;
179958671Seric 	extern time_t convtime();
180058112Seric 
180158112Seric 	if (val == NULL)
180258112Seric 	{
180358112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
180458112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
180558112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
180658112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
180758112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
180858112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
180958112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
181058112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
181158112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
181258112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
181358112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
181464255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
181567711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
181658112Seric 		return;
181758112Seric 	}
181858112Seric 
181958112Seric 	for (;; val = p)
182058112Seric 	{
182158112Seric 		while (isascii(*val) && isspace(*val))
182258112Seric 			val++;
182358112Seric 		if (*val == '\0')
182458112Seric 			break;
182558112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
182658112Seric 			continue;
182758112Seric 		if (*p != '\0')
182858112Seric 			*p++ = '\0';
182958112Seric 
183058112Seric 		if (isascii(*val) && isdigit(*val))
183158112Seric 		{
183258112Seric 			/* old syntax -- set everything */
183358796Seric 			TimeOuts.to_mail = convtime(val, 'm');
183458112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
183558112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
183658112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
183758112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
183858112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
183958112Seric 			continue;
184058112Seric 		}
184158112Seric 		else
184258112Seric 		{
184367711Seric 			register char *q = strchr(val, ':');
184458112Seric 			time_t to;
184558112Seric 
184667711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
184758112Seric 			{
184858112Seric 				/* syntax error */
184958112Seric 				continue;
185058112Seric 			}
185158112Seric 			*q++ = '\0';
185258796Seric 			to = convtime(q, 'm');
185358112Seric 
185458112Seric 			if (strcasecmp(val, "initial") == 0)
185558112Seric 				TimeOuts.to_initial = to;
185658112Seric 			else if (strcasecmp(val, "mail") == 0)
185758112Seric 				TimeOuts.to_mail = to;
185858112Seric 			else if (strcasecmp(val, "rcpt") == 0)
185958112Seric 				TimeOuts.to_rcpt = to;
186058112Seric 			else if (strcasecmp(val, "datainit") == 0)
186158112Seric 				TimeOuts.to_datainit = to;
186258112Seric 			else if (strcasecmp(val, "datablock") == 0)
186358112Seric 				TimeOuts.to_datablock = to;
186458112Seric 			else if (strcasecmp(val, "datafinal") == 0)
186558112Seric 				TimeOuts.to_datafinal = to;
186658112Seric 			else if (strcasecmp(val, "command") == 0)
186758112Seric 				TimeOuts.to_nextcommand = to;
186858112Seric 			else if (strcasecmp(val, "rset") == 0)
186958112Seric 				TimeOuts.to_rset = to;
187058112Seric 			else if (strcasecmp(val, "helo") == 0)
187158112Seric 				TimeOuts.to_helo = to;
187258112Seric 			else if (strcasecmp(val, "quit") == 0)
187358112Seric 				TimeOuts.to_quit = to;
187458112Seric 			else if (strcasecmp(val, "misc") == 0)
187558112Seric 				TimeOuts.to_miscshort = to;
187664255Seric 			else if (strcasecmp(val, "ident") == 0)
187764255Seric 				TimeOuts.to_ident = to;
187867711Seric 			else if (strcasecmp(val, "fileopen") == 0)
187967711Seric 				TimeOuts.to_fileopen = to;
188067711Seric 			else if (strcasecmp(val, "queuewarn") == 0)
188167730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
188267711Seric 			else if (strcasecmp(val, "queuereturn") == 0)
188367730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
188467730Seric 			else if (strcasecmp(val, "queuewarn.normal") == 0)
188567730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
188667730Seric 			else if (strcasecmp(val, "queuereturn.normal") == 0)
188767730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
188867730Seric 			else if (strcasecmp(val, "queuewarn.urgent") == 0)
188967730Seric 				TimeOuts.to_q_warning[TOC_URGENT] = to;
189067730Seric 			else if (strcasecmp(val, "queuereturn.urgent") == 0)
189167730Seric 				TimeOuts.to_q_return[TOC_URGENT] = to;
189267730Seric 			else if (strcasecmp(val, "queuewarn.non-urgent") == 0)
189367730Seric 				TimeOuts.to_q_warning[TOC_NONURGENT] = to;
189467730Seric 			else if (strcasecmp(val, "queuereturn.non-urgent") == 0)
189567730Seric 				TimeOuts.to_q_return[TOC_NONURGENT] = to;
189658112Seric 			else
189758112Seric 				syserr("settimeouts: invalid timeout %s", val);
189858112Seric 		}
189958112Seric 	}
190058112Seric }
1901