xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67730)
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*67730Seric static char sccsid[] = "@(#)readcf.c	8.35 (Berkeley) 08/21/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 
514*67730Seric 	/* initialize host maps from local service tables */
515*67730Seric 	inithostmaps();
516*67730Seric 
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';
117167614Seric 		if (*p == '=')
117267614Seric 			*p++ = '\0';
117367614Seric 		while (*p == ' ')
117467614Seric 			p++;
117567614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
117667614Seric 		{
117767614Seric 			if (strcasecmp(o->o_name, val) == 0)
117867614Seric 				break;
117967614Seric 		}
118067614Seric 		if (o->o_name == NULL)
118167614Seric 			syserr("readcf: unknown option name %s", val);
118267614Seric 		opt = o->o_code;
118367614Seric 		val = p;
118467614Seric 	}
118567614Seric 	else
118667614Seric 	{
118767614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
118867614Seric 		{
118967614Seric 			if (o->o_code == opt)
119067614Seric 				break;
119167614Seric 		}
119267614Seric 	}
119367614Seric 
11948256Seric 	if (tTd(37, 1))
119567614Seric 		printf("setoption %s (0x%x)=%s",
119667614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
119767614Seric 			opt, val);
11988256Seric 
11998256Seric 	/*
12008269Seric 	**  See if this option is preset for us.
12018256Seric 	*/
12028256Seric 
120359731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12048269Seric 	{
12059341Seric 		if (tTd(37, 1))
12069341Seric 			printf(" (ignored)\n");
12078269Seric 		return;
12088269Seric 	}
12098269Seric 
121021755Seric 	/*
121121755Seric 	**  Check to see if this option can be specified by this user.
121221755Seric 	*/
121321755Seric 
121463787Seric 	if (!safe && RealUid == 0)
121521755Seric 		safe = TRUE;
121667614Seric 	if (!safe && !o->o_safe)
121721755Seric 	{
121839111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
121921755Seric 		{
122036582Sbostic 			if (tTd(37, 1))
122136582Sbostic 				printf(" (unsafe)");
122263787Seric 			if (RealUid != geteuid())
122336582Sbostic 			{
122451210Seric 				if (tTd(37, 1))
122551210Seric 					printf("(Resetting uid)");
122663787Seric 				(void) setgid(RealGid);
122763787Seric 				(void) setuid(RealUid);
122836582Sbostic 			}
122921755Seric 		}
123021755Seric 	}
123151210Seric 	if (tTd(37, 1))
123217985Seric 		printf("\n");
12338269Seric 
123467614Seric 	switch (opt & 0xff)
12358256Seric 	{
123659709Seric 	  case '7':		/* force seven-bit input */
123767546Seric 		SevenBitInput = atobool(val);
123852106Seric 		break;
123952106Seric 
124067546Seric 	  case '8':		/* handling of 8-bit input */
124167546Seric 		switch (*val)
124267546Seric 		{
124367547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
124467546Seric 			MimeMode = 0;
124567546Seric 			break;
124667546Seric 
124767547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
124867546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
124967546Seric 			break;
125067546Seric 
125167547Seric 		  case 'j':		/* "just send 8" */
125267546Seric 			MimeMode = MM_PASS8BIT;
125367546Seric 			break;
125467546Seric 
125567546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
125667546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
125767546Seric 			break;
125867546Seric 
125967546Seric 		  case 's':		/* strict adherence */
126067546Seric 			MimeMode = MM_CVTMIME;
126167546Seric 			break;
126267546Seric 
126367547Seric 		  case 'a':		/* encode 8 bit if available */
126467546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
126567546Seric 			break;
126667546Seric 
126767547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
126867547Seric 			MimeMode = MM_MIME8BIT;
126967547Seric 			break;
127067547Seric 
127167546Seric 		  default:
127267546Seric 			syserr("Unknown 8-bit mode %c", *val);
127367546Seric 			exit(EX_USAGE);
127467546Seric 		}
127567546Seric 		break;
127667546Seric 
12778256Seric 	  case 'A':		/* set default alias file */
12789381Seric 		if (val[0] == '\0')
127959672Seric 			setalias("aliases");
12809381Seric 		else
128159672Seric 			setalias(val);
12828256Seric 		break;
12838256Seric 
128417474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
128517474Seric 		if (val[0] == '\0')
128664796Seric 			SafeAlias = 5 * 60;		/* five minutes */
128717474Seric 		else
128864796Seric 			SafeAlias = convtime(val, 'm');
128917474Seric 		break;
129017474Seric 
129116843Seric 	  case 'B':		/* substitution for blank character */
129216843Seric 		SpaceSub = val[0];
129316843Seric 		if (SpaceSub == '\0')
129416843Seric 			SpaceSub = ' ';
129516843Seric 		break;
129616843Seric 
129759283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
129859283Seric 		p = strchr(val, '/');
129959283Seric 		if (p != NULL)
130059283Seric 		{
130159283Seric 			*p++ = '\0';
130259283Seric 			MaxMessageSize = atol(p);
130359283Seric 		}
130458082Seric 		MinBlocksFree = atol(val);
130558082Seric 		break;
130658082Seric 
13079284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13089381Seric 		NoConnect = atobool(val);
13099284Seric 		break;
13109284Seric 
131151305Seric 	  case 'C':		/* checkpoint every N addresses */
131251305Seric 		CheckpointInterval = atoi(val);
131324944Seric 		break;
131424944Seric 
13159284Seric 	  case 'd':		/* delivery mode */
13169284Seric 		switch (*val)
13178269Seric 		{
13189284Seric 		  case '\0':
131958734Seric 			e->e_sendmode = SM_DELIVER;
13208269Seric 			break;
13218269Seric 
132210755Seric 		  case SM_QUEUE:	/* queue only */
132310755Seric #ifndef QUEUE
132410755Seric 			syserr("need QUEUE to set -odqueue");
132556795Seric #endif /* QUEUE */
132610755Seric 			/* fall through..... */
132710755Seric 
13289284Seric 		  case SM_DELIVER:	/* do everything */
13299284Seric 		  case SM_FORK:		/* fork after verification */
133058734Seric 			e->e_sendmode = *val;
13318269Seric 			break;
13328269Seric 
13338269Seric 		  default:
13349284Seric 			syserr("Unknown delivery mode %c", *val);
13358269Seric 			exit(EX_USAGE);
13368269Seric 		}
13378269Seric 		break;
13388269Seric 
13399146Seric 	  case 'D':		/* rebuild alias database as needed */
13409381Seric 		AutoRebuild = atobool(val);
13419146Seric 		break;
13429146Seric 
134355372Seric 	  case 'E':		/* error message header/header file */
134455379Seric 		if (*val != '\0')
134555379Seric 			ErrMsgFile = newstr(val);
134655372Seric 		break;
134755372Seric 
13488269Seric 	  case 'e':		/* set error processing mode */
13498269Seric 		switch (*val)
13508269Seric 		{
13519381Seric 		  case EM_QUIET:	/* be silent about it */
13529381Seric 		  case EM_MAIL:		/* mail back */
13539381Seric 		  case EM_BERKNET:	/* do berknet error processing */
13549381Seric 		  case EM_WRITE:	/* write back (or mail) */
13559381Seric 		  case EM_PRINT:	/* print errors normally (default) */
135658734Seric 			e->e_errormode = *val;
13578269Seric 			break;
13588269Seric 		}
13598269Seric 		break;
13608269Seric 
13619049Seric 	  case 'F':		/* file mode */
136217975Seric 		FileMode = atooct(val) & 0777;
13639049Seric 		break;
13649049Seric 
13658269Seric 	  case 'f':		/* save Unix-style From lines on front */
13669381Seric 		SaveFrom = atobool(val);
13678269Seric 		break;
13688269Seric 
136953735Seric 	  case 'G':		/* match recipients against GECOS field */
137053735Seric 		MatchGecos = atobool(val);
137153735Seric 		break;
137253735Seric 
13738256Seric 	  case 'g':		/* default gid */
137464133Seric 		if (isascii(*val) && isdigit(*val))
137564133Seric 			DefGid = atoi(val);
137664133Seric 		else
137764133Seric 		{
137864133Seric 			register struct group *gr;
137964133Seric 
138064133Seric 			DefGid = -1;
138164133Seric 			gr = getgrnam(val);
138264133Seric 			if (gr == NULL)
138364133Seric 				syserr("readcf: option g: unknown group %s", val);
138464133Seric 			else
138564133Seric 				DefGid = gr->gr_gid;
138664133Seric 		}
13878256Seric 		break;
13888256Seric 
13898256Seric 	  case 'H':		/* help file */
13909381Seric 		if (val[0] == '\0')
13918269Seric 			HelpFile = "sendmail.hf";
13929381Seric 		else
13939381Seric 			HelpFile = newstr(val);
13948256Seric 		break;
13958256Seric 
139651305Seric 	  case 'h':		/* maximum hop count */
139751305Seric 		MaxHopCount = atoi(val);
139851305Seric 		break;
139951305Seric 
140035651Seric 	  case 'I':		/* use internet domain name server */
140166334Seric #if NAMED_BIND
140257207Seric 		UseNameServer = TRUE;
140357207Seric 		for (p = val; *p != 0; )
140457207Seric 		{
140557207Seric 			bool clearmode;
140657207Seric 			char *q;
140757207Seric 			struct resolverflags *rfp;
140857207Seric 
140957207Seric 			while (*p == ' ')
141057207Seric 				p++;
141157207Seric 			if (*p == '\0')
141257207Seric 				break;
141357207Seric 			clearmode = FALSE;
141457207Seric 			if (*p == '-')
141557207Seric 				clearmode = TRUE;
141657207Seric 			else if (*p != '+')
141757207Seric 				p--;
141857207Seric 			p++;
141957207Seric 			q = p;
142058050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
142157207Seric 				p++;
142257207Seric 			if (*p != '\0')
142357207Seric 				*p++ = '\0';
142457207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
142557207Seric 			{
142657207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
142757207Seric 					break;
142857207Seric 			}
142964923Seric 			if (rfp->rf_name == NULL)
143064923Seric 				syserr("readcf: I option value %s unrecognized", q);
143164923Seric 			else if (clearmode)
143257207Seric 				_res.options &= ~rfp->rf_bits;
143357207Seric 			else
143457207Seric 				_res.options |= rfp->rf_bits;
143557207Seric 		}
143657207Seric 		if (tTd(8, 2))
143757207Seric 			printf("_res.options = %x\n", _res.options);
143857207Seric #else
143957207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
144057207Seric #endif
144135651Seric 		break;
144235651Seric 
14438269Seric 	  case 'i':		/* ignore dot lines in message */
14449381Seric 		IgnrDot = atobool(val);
14458269Seric 		break;
14468269Seric 
144759730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
144859730Seric 		SendMIMEErrors = atobool(val);
144959730Seric 		break;
145059730Seric 
145157136Seric 	  case 'J':		/* .forward search path */
145257136Seric 		ForwardPath = newstr(val);
145357136Seric 		break;
145457136Seric 
145554967Seric 	  case 'k':		/* connection cache size */
145654967Seric 		MaxMciCache = atoi(val);
145756215Seric 		if (MaxMciCache < 0)
145856215Seric 			MaxMciCache = 0;
145954967Seric 		break;
146054967Seric 
146154967Seric 	  case 'K':		/* connection cache timeout */
146258796Seric 		MciCacheTimeout = convtime(val, 'm');
146354967Seric 		break;
146454967Seric 
146561104Seric 	  case 'l':		/* use Errors-To: header */
146661104Seric 		UseErrorsTo = atobool(val);
146761104Seric 		break;
146861104Seric 
14698256Seric 	  case 'L':		/* log level */
147064140Seric 		if (safe || LogLevel < atoi(val))
147164140Seric 			LogLevel = atoi(val);
14728256Seric 		break;
14738256Seric 
14748269Seric 	  case 'M':		/* define macro */
14759381Seric 		define(val[0], newstr(&val[1]), CurEnv);
147616878Seric 		sticky = FALSE;
14778269Seric 		break;
14788269Seric 
14798269Seric 	  case 'm':		/* send to me too */
14809381Seric 		MeToo = atobool(val);
14818269Seric 		break;
14828269Seric 
148325820Seric 	  case 'n':		/* validate RHS in newaliases */
148425820Seric 		CheckAliases = atobool(val);
148525820Seric 		break;
148625820Seric 
148761104Seric 	    /* 'N' available -- was "net name" */
148861104Seric 
148958851Seric 	  case 'O':		/* daemon options */
149058851Seric 		setdaemonoptions(val);
149158851Seric 		break;
149258851Seric 
14938269Seric 	  case 'o':		/* assume old style headers */
14949381Seric 		if (atobool(val))
14959341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
14969341Seric 		else
14979341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
14988269Seric 		break;
14998269Seric 
150058082Seric 	  case 'p':		/* select privacy level */
150158082Seric 		p = val;
150258082Seric 		for (;;)
150358082Seric 		{
150458082Seric 			register struct prival *pv;
150558082Seric 			extern struct prival PrivacyValues[];
150658082Seric 
150758082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
150858082Seric 				p++;
150958082Seric 			if (*p == '\0')
151058082Seric 				break;
151158082Seric 			val = p;
151258082Seric 			while (isascii(*p) && isalnum(*p))
151358082Seric 				p++;
151458082Seric 			if (*p != '\0')
151558082Seric 				*p++ = '\0';
151658082Seric 
151758082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
151858082Seric 			{
151958082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
152058082Seric 					break;
152158082Seric 			}
152258886Seric 			if (pv->pv_name == NULL)
152358886Seric 				syserr("readcf: Op line: %s unrecognized", val);
152458082Seric 			PrivacyFlags |= pv->pv_flag;
152558082Seric 		}
152658082Seric 		break;
152758082Seric 
152824944Seric 	  case 'P':		/* postmaster copy address for returned mail */
152924944Seric 		PostMasterCopy = newstr(val);
153024944Seric 		break;
153124944Seric 
153224944Seric 	  case 'q':		/* slope of queue only function */
153324944Seric 		QueueFactor = atoi(val);
153424944Seric 		break;
153524944Seric 
15368256Seric 	  case 'Q':		/* queue directory */
15379381Seric 		if (val[0] == '\0')
15388269Seric 			QueueDir = "mqueue";
15399381Seric 		else
15409381Seric 			QueueDir = newstr(val);
154158789Seric 		if (RealUid != 0 && !safe)
154264718Seric 			Warn_Q_option = TRUE;
15438256Seric 		break;
15448256Seric 
154558148Seric 	  case 'R':		/* don't prune routes */
154658148Seric 		DontPruneRoutes = atobool(val);
154758148Seric 		break;
154858148Seric 
15498256Seric 	  case 'r':		/* read timeout */
155058112Seric 		settimeouts(val);
15518256Seric 		break;
15528256Seric 
15538256Seric 	  case 'S':		/* status file */
15549381Seric 		if (val[0] == '\0')
15558269Seric 			StatFile = "sendmail.st";
15569381Seric 		else
15579381Seric 			StatFile = newstr(val);
15588256Seric 		break;
15598256Seric 
15608265Seric 	  case 's':		/* be super safe, even if expensive */
15619381Seric 		SuperSafe = atobool(val);
15628256Seric 		break;
15638256Seric 
15648256Seric 	  case 'T':		/* queue timeout */
156558737Seric 		p = strchr(val, '/');
156658737Seric 		if (p != NULL)
156758737Seric 		{
156858737Seric 			*p++ = '\0';
1569*67730Seric 			TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd');
157058737Seric 		}
1571*67730Seric 		TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h');
157254967Seric 		break;
15738256Seric 
15748265Seric 	  case 't':		/* time zone name */
157552106Seric 		TimeZoneSpec = newstr(val);
15768265Seric 		break;
15778265Seric 
157850556Seric 	  case 'U':		/* location of user database */
157951360Seric 		UdbSpec = newstr(val);
158050556Seric 		break;
158150556Seric 
15828256Seric 	  case 'u':		/* set default uid */
158364133Seric 		if (isascii(*val) && isdigit(*val))
158464133Seric 			DefUid = atoi(val);
158564133Seric 		else
158664133Seric 		{
158764133Seric 			register struct passwd *pw;
158864133Seric 
158964133Seric 			DefUid = -1;
159064133Seric 			pw = getpwnam(val);
159164133Seric 			if (pw == NULL)
159264133Seric 				syserr("readcf: option u: unknown user %s", val);
159364133Seric 			else
159464133Seric 				DefUid = pw->pw_uid;
159564133Seric 		}
159640973Sbostic 		setdefuser();
15978256Seric 		break;
15988256Seric 
159958851Seric 	  case 'V':		/* fallback MX host */
160058851Seric 		FallBackMX = newstr(val);
160158851Seric 		break;
160258851Seric 
16038269Seric 	  case 'v':		/* run in verbose mode */
16049381Seric 		Verbose = atobool(val);
16058256Seric 		break;
16068256Seric 
160763837Seric 	  case 'w':		/* if we are best MX, try host directly */
160863837Seric 		TryNullMXList = atobool(val);
160963837Seric 		break;
161061104Seric 
161161104Seric 	    /* 'W' available -- was wizard password */
161261104Seric 
161314879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
161414879Seric 		QueueLA = atoi(val);
161514879Seric 		break;
161614879Seric 
161714879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
161814879Seric 		RefuseLA = atoi(val);
161914879Seric 		break;
162014879Seric 
162124981Seric 	  case 'y':		/* work recipient factor */
162224981Seric 		WkRecipFact = atoi(val);
162324981Seric 		break;
162424981Seric 
162524981Seric 	  case 'Y':		/* fork jobs during queue runs */
162624952Seric 		ForkQueueRuns = atobool(val);
162724952Seric 		break;
162824952Seric 
162924981Seric 	  case 'z':		/* work message class factor */
163024981Seric 		WkClassFact = atoi(val);
163124981Seric 		break;
163224981Seric 
163324981Seric 	  case 'Z':		/* work time factor */
163424981Seric 		WkTimeFact = atoi(val);
163524981Seric 		break;
163624981Seric 
163767614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
163867614Seric 		BrokenSmtpPeers = atobool(val);
163967614Seric 		break;
164067614Seric 
164167614Seric 	  case O_SQBH:		/* sort work queue by host first */
164267614Seric 		SortQueueByHost = atobool(val);
164367614Seric 		break;
164467614Seric 
164567707Seric 	  case O_DNICE:		/* delivery nice value */
164667707Seric 		DeliveryNiceness = atoi(val);
164767707Seric 		break;
164867707Seric 
164967707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
165067707Seric 		MinQueueAge = convtime(val, 'm');
165167707Seric 		break;
165267707Seric 
165367707Seric 	  case O_MHSA:		/* maximum age of cached host status */
165467707Seric 		MaxHostStatAge = convtime(val, 'm');
165567707Seric 		break;
165667707Seric 
16578256Seric 	  default:
16588256Seric 		break;
16598256Seric 	}
166016878Seric 	if (sticky)
166116878Seric 		setbitn(opt, StickyOpt);
16629188Seric 	return;
16638256Seric }
166410687Seric /*
166510687Seric **  SETCLASS -- set a word into a class
166610687Seric **
166710687Seric **	Parameters:
166810687Seric **		class -- the class to put the word in.
166910687Seric **		word -- the word to enter
167010687Seric **
167110687Seric **	Returns:
167210687Seric **		none.
167310687Seric **
167410687Seric **	Side Effects:
167510687Seric **		puts the word into the symbol table.
167610687Seric */
167710687Seric 
167810687Seric setclass(class, word)
167910687Seric 	int class;
168010687Seric 	char *word;
168110687Seric {
168210687Seric 	register STAB *s;
168310687Seric 
168457943Seric 	if (tTd(37, 8))
168564326Seric 		printf("setclass(%c, %s)\n", class, word);
168610687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
168710687Seric 	setbitn(class, s->s_class);
168810687Seric }
168953654Seric /*
169053654Seric **  MAKEMAPENTRY -- create a map entry
169153654Seric **
169253654Seric **	Parameters:
169353654Seric **		line -- the config file line
169453654Seric **
169553654Seric **	Returns:
169653654Seric **		TRUE if it successfully entered the map entry.
169753654Seric **		FALSE otherwise (usually syntax error).
169853654Seric **
169953654Seric **	Side Effects:
170053654Seric **		Enters the map into the dictionary.
170153654Seric */
170253654Seric 
170353654Seric void
170453654Seric makemapentry(line)
170553654Seric 	char *line;
170653654Seric {
170753654Seric 	register char *p;
170853654Seric 	char *mapname;
170953654Seric 	char *classname;
171064078Seric 	register STAB *s;
171153654Seric 	STAB *class;
171253654Seric 
171358050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
171453654Seric 		continue;
171558050Seric 	if (!(isascii(*p) && isalnum(*p)))
171653654Seric 	{
171753654Seric 		syserr("readcf: config K line: no map name");
171853654Seric 		return;
171953654Seric 	}
172053654Seric 
172153654Seric 	mapname = p;
172258050Seric 	while (isascii(*++p) && isalnum(*p))
172353654Seric 		continue;
172453654Seric 	if (*p != '\0')
172553654Seric 		*p++ = '\0';
172658050Seric 	while (isascii(*p) && isspace(*p))
172753654Seric 		p++;
172858050Seric 	if (!(isascii(*p) && isalnum(*p)))
172953654Seric 	{
173053654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
173153654Seric 		return;
173253654Seric 	}
173353654Seric 	classname = p;
173458050Seric 	while (isascii(*++p) && isalnum(*p))
173553654Seric 		continue;
173653654Seric 	if (*p != '\0')
173753654Seric 		*p++ = '\0';
173858050Seric 	while (isascii(*p) && isspace(*p))
173953654Seric 		p++;
174053654Seric 
174153654Seric 	/* look up the class */
174253654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
174353654Seric 	if (class == NULL)
174453654Seric 	{
174553654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
174653654Seric 		return;
174753654Seric 	}
174853654Seric 
174953654Seric 	/* enter the map */
175064078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
175164078Seric 	s->s_map.map_class = &class->s_mapclass;
175264078Seric 	s->s_map.map_mname = newstr(mapname);
175353654Seric 
175464078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
175564078Seric 		s->s_map.map_mflags |= MF_VALID;
175664078Seric 
175764078Seric 	if (tTd(37, 5))
175864078Seric 	{
175964078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
176064078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
176164078Seric 			s->s_map.map_mflags,
176264078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
176364078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
176464078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
176564078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
176664078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
176764078Seric 	}
176853654Seric }
176958112Seric /*
177058112Seric **  SETTIMEOUTS -- parse and set timeout values
177158112Seric **
177258112Seric **	Parameters:
177358112Seric **		val -- a pointer to the values.  If NULL, do initial
177458112Seric **			settings.
177558112Seric **
177658112Seric **	Returns:
177758112Seric **		none.
177858112Seric **
177958112Seric **	Side Effects:
178058112Seric **		Initializes the TimeOuts structure
178158112Seric */
178258112Seric 
178364255Seric #define SECONDS
178458112Seric #define MINUTES	* 60
178558112Seric #define HOUR	* 3600
178658112Seric 
178758112Seric settimeouts(val)
178858112Seric 	register char *val;
178958112Seric {
179058112Seric 	register char *p;
179158671Seric 	extern time_t convtime();
179258112Seric 
179358112Seric 	if (val == NULL)
179458112Seric 	{
179558112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
179658112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
179758112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
179858112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
179958112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
180058112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
180158112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
180258112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
180358112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
180458112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
180558112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
180664255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
180767711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
180858112Seric 		return;
180958112Seric 	}
181058112Seric 
181158112Seric 	for (;; val = p)
181258112Seric 	{
181358112Seric 		while (isascii(*val) && isspace(*val))
181458112Seric 			val++;
181558112Seric 		if (*val == '\0')
181658112Seric 			break;
181758112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
181858112Seric 			continue;
181958112Seric 		if (*p != '\0')
182058112Seric 			*p++ = '\0';
182158112Seric 
182258112Seric 		if (isascii(*val) && isdigit(*val))
182358112Seric 		{
182458112Seric 			/* old syntax -- set everything */
182558796Seric 			TimeOuts.to_mail = convtime(val, 'm');
182658112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
182758112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
182858112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
182958112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
183058112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
183158112Seric 			continue;
183258112Seric 		}
183358112Seric 		else
183458112Seric 		{
183567711Seric 			register char *q = strchr(val, ':');
183658112Seric 			time_t to;
183758112Seric 
183867711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
183958112Seric 			{
184058112Seric 				/* syntax error */
184158112Seric 				continue;
184258112Seric 			}
184358112Seric 			*q++ = '\0';
184458796Seric 			to = convtime(q, 'm');
184558112Seric 
184658112Seric 			if (strcasecmp(val, "initial") == 0)
184758112Seric 				TimeOuts.to_initial = to;
184858112Seric 			else if (strcasecmp(val, "mail") == 0)
184958112Seric 				TimeOuts.to_mail = to;
185058112Seric 			else if (strcasecmp(val, "rcpt") == 0)
185158112Seric 				TimeOuts.to_rcpt = to;
185258112Seric 			else if (strcasecmp(val, "datainit") == 0)
185358112Seric 				TimeOuts.to_datainit = to;
185458112Seric 			else if (strcasecmp(val, "datablock") == 0)
185558112Seric 				TimeOuts.to_datablock = to;
185658112Seric 			else if (strcasecmp(val, "datafinal") == 0)
185758112Seric 				TimeOuts.to_datafinal = to;
185858112Seric 			else if (strcasecmp(val, "command") == 0)
185958112Seric 				TimeOuts.to_nextcommand = to;
186058112Seric 			else if (strcasecmp(val, "rset") == 0)
186158112Seric 				TimeOuts.to_rset = to;
186258112Seric 			else if (strcasecmp(val, "helo") == 0)
186358112Seric 				TimeOuts.to_helo = to;
186458112Seric 			else if (strcasecmp(val, "quit") == 0)
186558112Seric 				TimeOuts.to_quit = to;
186658112Seric 			else if (strcasecmp(val, "misc") == 0)
186758112Seric 				TimeOuts.to_miscshort = to;
186864255Seric 			else if (strcasecmp(val, "ident") == 0)
186964255Seric 				TimeOuts.to_ident = to;
187067711Seric 			else if (strcasecmp(val, "fileopen") == 0)
187167711Seric 				TimeOuts.to_fileopen = to;
187267711Seric 			else if (strcasecmp(val, "queuewarn") == 0)
1873*67730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
187467711Seric 			else if (strcasecmp(val, "queuereturn") == 0)
1875*67730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
1876*67730Seric 			else if (strcasecmp(val, "queuewarn.normal") == 0)
1877*67730Seric 				TimeOuts.to_q_warning[TOC_NORMAL] = to;
1878*67730Seric 			else if (strcasecmp(val, "queuereturn.normal") == 0)
1879*67730Seric 				TimeOuts.to_q_return[TOC_NORMAL] = to;
1880*67730Seric 			else if (strcasecmp(val, "queuewarn.urgent") == 0)
1881*67730Seric 				TimeOuts.to_q_warning[TOC_URGENT] = to;
1882*67730Seric 			else if (strcasecmp(val, "queuereturn.urgent") == 0)
1883*67730Seric 				TimeOuts.to_q_return[TOC_URGENT] = to;
1884*67730Seric 			else if (strcasecmp(val, "queuewarn.non-urgent") == 0)
1885*67730Seric 				TimeOuts.to_q_warning[TOC_NONURGENT] = to;
1886*67730Seric 			else if (strcasecmp(val, "queuereturn.non-urgent") == 0)
1887*67730Seric 				TimeOuts.to_q_return[TOC_NONURGENT] = to;
188858112Seric 			else
188958112Seric 				syserr("settimeouts: invalid timeout %s", val);
189058112Seric 		}
189158112Seric 	}
189258112Seric }
1893