xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 67711)
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*67711Seric static char sccsid[] = "@(#)readcf.c	8.34 (Berkeley) 08/20/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 
51457076Seric 	if (stab("host", ST_MAP, ST_FIND) == NULL)
51557076Seric 	{
51657076Seric 		/* user didn't initialize: set up host map */
51757076Seric 		strcpy(buf, "host host");
51866334Seric #if NAMED_BIND
51957076Seric 		if (ConfigLevel >= 2)
52057076Seric 			strcat(buf, " -a.");
52164947Seric #endif
52257076Seric 		makemapentry(buf);
52357076Seric 	}
5244096Seric }
5254096Seric /*
5268547Seric **  TOOMANY -- signal too many of some option
5278547Seric **
5288547Seric **	Parameters:
5298547Seric **		id -- the id of the error line
5308547Seric **		maxcnt -- the maximum possible values
5318547Seric **
5328547Seric **	Returns:
5338547Seric **		none.
5348547Seric **
5358547Seric **	Side Effects:
5368547Seric **		gives a syserr.
5378547Seric */
5388547Seric 
5398547Seric toomany(id, maxcnt)
5408547Seric 	char id;
5418547Seric 	int maxcnt;
5428547Seric {
5439381Seric 	syserr("too many %c lines, %d max", id, maxcnt);
5448547Seric }
5458547Seric /*
5464432Seric **  FILECLASS -- read members of a class from a file
5474432Seric **
5484432Seric **	Parameters:
5494432Seric **		class -- class to define.
5504432Seric **		filename -- name of file to read.
5514432Seric **		fmt -- scanf string to use for match.
55264133Seric **		safe -- if set, this is a safe read.
55364133Seric **		optional -- if set, it is not an error for the file to
55464133Seric **			not exist.
5554432Seric **
5564432Seric **	Returns:
5574432Seric **		none
5584432Seric **
5594432Seric **	Side Effects:
5604432Seric **
5614432Seric **		puts all lines in filename that match a scanf into
5624432Seric **			the named class.
5634432Seric */
5644432Seric 
56564133Seric fileclass(class, filename, fmt, safe, optional)
5664432Seric 	int class;
5674432Seric 	char *filename;
5684432Seric 	char *fmt;
56954973Seric 	bool safe;
57064133Seric 	bool optional;
5714432Seric {
57225808Seric 	FILE *f;
57354973Seric 	struct stat stbuf;
5744432Seric 	char buf[MAXLINE];
5754432Seric 
57666101Seric 	if (tTd(37, 2))
57766101Seric 		printf("fileclass(%s, fmt=%s)\n", filename, fmt);
57866101Seric 
57966031Seric 	if (filename[0] == '|')
58066031Seric 	{
58166031Seric 		syserr("fileclass: pipes (F%c%s) not supported due to security problems",
58266031Seric 			class, filename);
58366031Seric 		return;
58466031Seric 	}
58554973Seric 	if (stat(filename, &stbuf) < 0)
58654973Seric 	{
58766101Seric 		if (tTd(37, 2))
58866101Seric 			printf("  cannot stat (%s)\n", errstring(errno));
58964133Seric 		if (!optional)
59064133Seric 			syserr("fileclass: cannot stat %s", filename);
59154973Seric 		return;
59254973Seric 	}
59354973Seric 	if (!S_ISREG(stbuf.st_mode))
59454973Seric 	{
59554973Seric 		syserr("fileclass: %s not a regular file", filename);
59654973Seric 		return;
59754973Seric 	}
59854973Seric 	if (!safe && access(filename, R_OK) < 0)
59954973Seric 	{
60054973Seric 		syserr("fileclass: access denied on %s", filename);
60154973Seric 		return;
60254973Seric 	}
60354973Seric 	f = fopen(filename, "r");
6044432Seric 	if (f == NULL)
6054432Seric 	{
60654973Seric 		syserr("fileclass: cannot open %s", filename);
6074432Seric 		return;
6084432Seric 	}
6094432Seric 
6104432Seric 	while (fgets(buf, sizeof buf, f) != NULL)
6114432Seric 	{
6124432Seric 		register STAB *s;
61325808Seric 		register char *p;
61425808Seric # ifdef SCANF
6154432Seric 		char wordbuf[MAXNAME+1];
6164432Seric 
6174432Seric 		if (sscanf(buf, fmt, wordbuf) != 1)
6184432Seric 			continue;
61925808Seric 		p = wordbuf;
62056795Seric # else /* SCANF */
62125808Seric 		p = buf;
62256795Seric # endif /* SCANF */
62325808Seric 
62425808Seric 		/*
62525808Seric 		**  Break up the match into words.
62625808Seric 		*/
62725808Seric 
62825808Seric 		while (*p != '\0')
62925808Seric 		{
63025808Seric 			register char *q;
63125808Seric 
63225808Seric 			/* strip leading spaces */
63358050Seric 			while (isascii(*p) && isspace(*p))
63425808Seric 				p++;
63525808Seric 			if (*p == '\0')
63625808Seric 				break;
63725808Seric 
63825808Seric 			/* find the end of the word */
63925808Seric 			q = p;
64058050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
64125808Seric 				p++;
64225808Seric 			if (*p != '\0')
64325808Seric 				*p++ = '\0';
64425808Seric 
64525808Seric 			/* enter the word in the symbol table */
64666101Seric 			setclass(class, q);
64725808Seric 		}
6484432Seric 	}
6494432Seric 
65054973Seric 	(void) fclose(f);
6514432Seric }
6524432Seric /*
6534096Seric **  MAKEMAILER -- define a new mailer.
6544096Seric **
6554096Seric **	Parameters:
65610327Seric **		line -- description of mailer.  This is in labeled
65710327Seric **			fields.  The fields are:
65810327Seric **			   P -- the path to the mailer
65910327Seric **			   F -- the flags associated with the mailer
66010327Seric **			   A -- the argv for this mailer
66110327Seric **			   S -- the sender rewriting set
66210327Seric **			   R -- the recipient rewriting set
66310327Seric **			   E -- the eol string
66410327Seric **			The first word is the canonical name of the mailer.
6654096Seric **
6664096Seric **	Returns:
6674096Seric **		none.
6684096Seric **
6694096Seric **	Side Effects:
6704096Seric **		enters the mailer into the mailer table.
6714096Seric */
6723308Seric 
67321066Seric makemailer(line)
6744096Seric 	char *line;
6754096Seric {
6764096Seric 	register char *p;
6778067Seric 	register struct mailer *m;
6788067Seric 	register STAB *s;
6798067Seric 	int i;
68010327Seric 	char fcode;
68158020Seric 	auto char *endp;
6824096Seric 	extern int NextMailer;
68310327Seric 	extern char **makeargv();
68410327Seric 	extern char *munchstring();
68510701Seric 	extern long atol();
6864096Seric 
68710327Seric 	/* allocate a mailer and set up defaults */
68810327Seric 	m = (struct mailer *) xalloc(sizeof *m);
68910327Seric 	bzero((char *) m, sizeof *m);
69010327Seric 	m->m_eol = "\n";
69167604Seric 	m->m_uid = m->m_gid = 0;
69210327Seric 
69310327Seric 	/* collect the mailer name */
69458050Seric 	for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
69510327Seric 		continue;
69610327Seric 	if (*p != '\0')
69710327Seric 		*p++ = '\0';
69810327Seric 	m->m_name = newstr(line);
69910327Seric 
70010327Seric 	/* now scan through and assign info from the fields */
70110327Seric 	while (*p != '\0')
70210327Seric 	{
70358333Seric 		auto char *delimptr;
70458333Seric 
70558050Seric 		while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
70610327Seric 			p++;
70710327Seric 
70810327Seric 		/* p now points to field code */
70910327Seric 		fcode = *p;
71010327Seric 		while (*p != '\0' && *p != '=' && *p != ',')
71110327Seric 			p++;
71210327Seric 		if (*p++ != '=')
71310327Seric 		{
71452637Seric 			syserr("mailer %s: `=' expected", m->m_name);
71510327Seric 			return;
71610327Seric 		}
71758050Seric 		while (isascii(*p) && isspace(*p))
71810327Seric 			p++;
71910327Seric 
72010327Seric 		/* p now points to the field body */
72158333Seric 		p = munchstring(p, &delimptr);
72210327Seric 
72310327Seric 		/* install the field into the mailer struct */
72410327Seric 		switch (fcode)
72510327Seric 		{
72610327Seric 		  case 'P':		/* pathname */
72710327Seric 			m->m_mailer = newstr(p);
72810327Seric 			break;
72910327Seric 
73010327Seric 		  case 'F':		/* flags */
73110687Seric 			for (; *p != '\0'; p++)
73258050Seric 				if (!(isascii(*p) && isspace(*p)))
73352637Seric 					setbitn(*p, m->m_flags);
73410327Seric 			break;
73510327Seric 
73610327Seric 		  case 'S':		/* sender rewriting ruleset */
73710327Seric 		  case 'R':		/* recipient rewriting ruleset */
73858020Seric 			i = strtol(p, &endp, 10);
73910327Seric 			if (i < 0 || i >= MAXRWSETS)
74010327Seric 			{
74110327Seric 				syserr("invalid rewrite set, %d max", MAXRWSETS);
74210327Seric 				return;
74310327Seric 			}
74410327Seric 			if (fcode == 'S')
74558020Seric 				m->m_sh_rwset = m->m_se_rwset = i;
74610327Seric 			else
74758020Seric 				m->m_rh_rwset = m->m_re_rwset = i;
74858020Seric 
74958020Seric 			p = endp;
75059985Seric 			if (*p++ == '/')
75158020Seric 			{
75258020Seric 				i = strtol(p, NULL, 10);
75358020Seric 				if (i < 0 || i >= MAXRWSETS)
75458020Seric 				{
75558020Seric 					syserr("invalid rewrite set, %d max",
75658020Seric 						MAXRWSETS);
75758020Seric 					return;
75858020Seric 				}
75958020Seric 				if (fcode == 'S')
76058020Seric 					m->m_sh_rwset = i;
76158020Seric 				else
76258020Seric 					m->m_rh_rwset = i;
76358020Seric 			}
76410327Seric 			break;
76510327Seric 
76610327Seric 		  case 'E':		/* end of line string */
76710327Seric 			m->m_eol = newstr(p);
76810327Seric 			break;
76910327Seric 
77010327Seric 		  case 'A':		/* argument vector */
77110327Seric 			m->m_argv = makeargv(p);
77210327Seric 			break;
77310701Seric 
77410701Seric 		  case 'M':		/* maximum message size */
77510701Seric 			m->m_maxsize = atol(p);
77610701Seric 			break;
77752106Seric 
77852106Seric 		  case 'L':		/* maximum line length */
77952106Seric 			m->m_linelimit = atoi(p);
78052106Seric 			break;
78158935Seric 
78258935Seric 		  case 'D':		/* working directory */
78358935Seric 			m->m_execdir = newstr(p);
78458935Seric 			break;
78567604Seric 
78667604Seric 		  case 'U':		/* user id */
78767604Seric 			if (isascii(*p) && !isdigit(*p))
78867604Seric 			{
78967604Seric 				char *q = p;
79067604Seric 				struct passwd *pw;
79167604Seric 
79267604Seric 				while (isascii(*p) && isalnum(*p))
79367604Seric 					p++;
79467604Seric 				while (isascii(*p) && isspace(*p))
79567604Seric 					*p++ = '\0';
79667604Seric 				if (*p != '\0')
79767604Seric 					*p++ = '\0';
79867604Seric 				pw = getpwnam(q);
79967604Seric 				if (pw == NULL)
80067604Seric 					syserr("readcf: mailer U= flag: unknown user %s", q);
80167604Seric 				else
80267604Seric 				{
80367604Seric 					m->m_uid = pw->pw_uid;
80467604Seric 					m->m_gid = pw->pw_gid;
80567604Seric 				}
80667604Seric 			}
80767604Seric 			else
80867604Seric 			{
80967604Seric 				auto char *q;
81067604Seric 
81167604Seric 				m->m_uid = strtol(p, &q, 0);
81267604Seric 				p = q;
81367604Seric 			}
81467604Seric 			while (isascii(*p) && isspace(*p))
81567604Seric 				p++;
81667604Seric 			if (*p == '\0')
81767604Seric 				break;
81867604Seric 			if (isascii(*p) && !isdigit(*p))
81967604Seric 			{
82067604Seric 				char *q = p;
82167604Seric 				struct group *gr;
82267604Seric 
82367604Seric 				while (isascii(*p) && isalnum(*p))
82467604Seric 					p++;
82567604Seric 				*p++ = '\0';
82667604Seric 				gr = getgrnam(q);
82767604Seric 				if (gr == NULL)
82867604Seric 					syserr("readcf: mailer U= flag: unknown group %s", q);
82967604Seric 				else
83067604Seric 					m->m_gid = gr->gr_gid;
83167604Seric 			}
83267604Seric 			else
83367604Seric 			{
83467604Seric 				m->m_gid = strtol(p, NULL, 0);
83567604Seric 			}
83667604Seric 			break;
83710327Seric 		}
83810327Seric 
83958333Seric 		p = delimptr;
84010327Seric 	}
84110327Seric 
84252106Seric 	/* do some heuristic cleanup for back compatibility */
84352106Seric 	if (bitnset(M_LIMITS, m->m_flags))
84452106Seric 	{
84552106Seric 		if (m->m_linelimit == 0)
84652106Seric 			m->m_linelimit = SMTPLINELIM;
84755418Seric 		if (ConfigLevel < 2)
84852106Seric 			setbitn(M_7BITS, m->m_flags);
84952106Seric 	}
85052106Seric 
85158321Seric 	/* do some rationality checking */
85258321Seric 	if (m->m_argv == NULL)
85358321Seric 	{
85458321Seric 		syserr("M%s: A= argument required", m->m_name);
85558321Seric 		return;
85658321Seric 	}
85758321Seric 	if (m->m_mailer == NULL)
85858321Seric 	{
85958321Seric 		syserr("M%s: P= argument required", m->m_name);
86058321Seric 		return;
86158321Seric 	}
86258321Seric 
8634096Seric 	if (NextMailer >= MAXMAILERS)
8644096Seric 	{
8659381Seric 		syserr("too many mailers defined (%d max)", MAXMAILERS);
8664096Seric 		return;
8674096Seric 	}
86857402Seric 
86910327Seric 	s = stab(m->m_name, ST_MAILER, ST_ENTER);
87057402Seric 	if (s->s_mailer != NULL)
87157402Seric 	{
87257402Seric 		i = s->s_mailer->m_mno;
87357402Seric 		free(s->s_mailer);
87457402Seric 	}
87557402Seric 	else
87657402Seric 	{
87757402Seric 		i = NextMailer++;
87857402Seric 	}
87957402Seric 	Mailer[i] = s->s_mailer = m;
88057454Seric 	m->m_mno = i;
88110327Seric }
88210327Seric /*
88310327Seric **  MUNCHSTRING -- translate a string into internal form.
88410327Seric **
88510327Seric **	Parameters:
88610327Seric **		p -- the string to munch.
88758333Seric **		delimptr -- if non-NULL, set to the pointer of the
88858333Seric **			field delimiter character.
88910327Seric **
89010327Seric **	Returns:
89110327Seric **		the munched string.
89210327Seric */
8934096Seric 
89410327Seric char *
89558333Seric munchstring(p, delimptr)
89610327Seric 	register char *p;
89758333Seric 	char **delimptr;
89810327Seric {
89910327Seric 	register char *q;
90010327Seric 	bool backslash = FALSE;
90110327Seric 	bool quotemode = FALSE;
90210327Seric 	static char buf[MAXLINE];
9034096Seric 
90410327Seric 	for (q = buf; *p != '\0'; p++)
9054096Seric 	{
90610327Seric 		if (backslash)
90710327Seric 		{
90810327Seric 			/* everything is roughly literal */
90910357Seric 			backslash = FALSE;
91010327Seric 			switch (*p)
91110327Seric 			{
91210327Seric 			  case 'r':		/* carriage return */
91310327Seric 				*q++ = '\r';
91410327Seric 				continue;
91510327Seric 
91610327Seric 			  case 'n':		/* newline */
91710327Seric 				*q++ = '\n';
91810327Seric 				continue;
91910327Seric 
92010327Seric 			  case 'f':		/* form feed */
92110327Seric 				*q++ = '\f';
92210327Seric 				continue;
92310327Seric 
92410327Seric 			  case 'b':		/* backspace */
92510327Seric 				*q++ = '\b';
92610327Seric 				continue;
92710327Seric 			}
92810327Seric 			*q++ = *p;
92910327Seric 		}
93010327Seric 		else
93110327Seric 		{
93210327Seric 			if (*p == '\\')
93310327Seric 				backslash = TRUE;
93410327Seric 			else if (*p == '"')
93510327Seric 				quotemode = !quotemode;
93610327Seric 			else if (quotemode || *p != ',')
93710327Seric 				*q++ = *p;
93810327Seric 			else
93910327Seric 				break;
94010327Seric 		}
9414096Seric 	}
9424096Seric 
94358333Seric 	if (delimptr != NULL)
94458333Seric 		*delimptr = p;
94510327Seric 	*q++ = '\0';
94610327Seric 	return (buf);
94710327Seric }
94810327Seric /*
94910327Seric **  MAKEARGV -- break up a string into words
95010327Seric **
95110327Seric **	Parameters:
95210327Seric **		p -- the string to break up.
95310327Seric **
95410327Seric **	Returns:
95510327Seric **		a char **argv (dynamically allocated)
95610327Seric **
95710327Seric **	Side Effects:
95810327Seric **		munges p.
95910327Seric */
9604096Seric 
96110327Seric char **
96210327Seric makeargv(p)
96310327Seric 	register char *p;
96410327Seric {
96510327Seric 	char *q;
96610327Seric 	int i;
96710327Seric 	char **avp;
96810327Seric 	char *argv[MAXPV + 1];
96910327Seric 
97010327Seric 	/* take apart the words */
97110327Seric 	i = 0;
97210327Seric 	while (*p != '\0' && i < MAXPV)
9734096Seric 	{
97410327Seric 		q = p;
97558050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
97610327Seric 			p++;
97758050Seric 		while (isascii(*p) && isspace(*p))
97810327Seric 			*p++ = '\0';
97910327Seric 		argv[i++] = newstr(q);
9804096Seric 	}
98110327Seric 	argv[i++] = NULL;
9824096Seric 
98310327Seric 	/* now make a copy of the argv */
98410327Seric 	avp = (char **) xalloc(sizeof *avp * i);
98516893Seric 	bcopy((char *) argv, (char *) avp, sizeof *avp * i);
98610327Seric 
98710327Seric 	return (avp);
9883308Seric }
9893308Seric /*
9903308Seric **  PRINTRULES -- print rewrite rules (for debugging)
9913308Seric **
9923308Seric **	Parameters:
9933308Seric **		none.
9943308Seric **
9953308Seric **	Returns:
9963308Seric **		none.
9973308Seric **
9983308Seric **	Side Effects:
9993308Seric **		prints rewrite rules.
10003308Seric */
10013308Seric 
10023308Seric printrules()
10033308Seric {
10043308Seric 	register struct rewrite *rwp;
10054072Seric 	register int ruleset;
10063308Seric 
10074072Seric 	for (ruleset = 0; ruleset < 10; ruleset++)
10083308Seric 	{
10094072Seric 		if (RewriteRules[ruleset] == NULL)
10104072Seric 			continue;
10118067Seric 		printf("\n----Rule Set %d:", ruleset);
10123308Seric 
10134072Seric 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
10143308Seric 		{
10158067Seric 			printf("\nLHS:");
10168067Seric 			printav(rwp->r_lhs);
10178067Seric 			printf("RHS:");
10188067Seric 			printav(rwp->r_rhs);
10193308Seric 		}
10203308Seric 	}
10213308Seric }
10224319Seric 
10234096Seric /*
10248256Seric **  SETOPTION -- set global processing option
10258256Seric **
10268256Seric **	Parameters:
10278256Seric **		opt -- option name.
10288256Seric **		val -- option value (as a text string).
102921755Seric **		safe -- set if this came from a configuration file.
103021755Seric **			Some options (if set from the command line) will
103121755Seric **			reset the user id to avoid security problems.
10328269Seric **		sticky -- if set, don't let other setoptions override
10338269Seric **			this value.
103458734Seric **		e -- the main envelope.
10358256Seric **
10368256Seric **	Returns:
10378256Seric **		none.
10388256Seric **
10398256Seric **	Side Effects:
10408256Seric **		Sets options as implied by the arguments.
10418256Seric */
10428256Seric 
104310687Seric static BITMAP	StickyOpt;		/* set if option is stuck */
10448269Seric 
104557207Seric 
104666334Seric #if NAMED_BIND
104757207Seric 
104857207Seric struct resolverflags
104957207Seric {
105057207Seric 	char	*rf_name;	/* name of the flag */
105157207Seric 	long	rf_bits;	/* bits to set/clear */
105257207Seric } ResolverFlags[] =
105357207Seric {
105457207Seric 	"debug",	RES_DEBUG,
105557207Seric 	"aaonly",	RES_AAONLY,
105657207Seric 	"usevc",	RES_USEVC,
105757207Seric 	"primary",	RES_PRIMARY,
105857207Seric 	"igntc",	RES_IGNTC,
105957207Seric 	"recurse",	RES_RECURSE,
106057207Seric 	"defnames",	RES_DEFNAMES,
106157207Seric 	"stayopen",	RES_STAYOPEN,
106257207Seric 	"dnsrch",	RES_DNSRCH,
106365583Seric 	"true",		0,		/* to avoid error on old syntax */
106457207Seric 	NULL,		0
106557207Seric };
106657207Seric 
106757207Seric #endif
106857207Seric 
106967614Seric struct optioninfo
107067614Seric {
107167614Seric 	char	*o_name;	/* long name of option */
107267614Seric 	char	o_code;		/* short name of option */
107367614Seric 	bool	o_safe;		/* safe for random people to use */
107467614Seric } OptionTab[] =
107567614Seric {
107667707Seric 	"SevenBitInput",	'7',		TRUE,
107767707Seric 	"EightBitMode",		'8',		TRUE,
107867707Seric 	"AliasFile",		'A',		FALSE,
107967707Seric 	"AliasWait",		'a',		FALSE,
108067707Seric 	"BlankSub",		'B',		FALSE,
108167707Seric 	"MinFreeBlocks",	'b',		TRUE,
108267707Seric 	"CheckpointInterval",	'C',		TRUE,
108367707Seric 	"HoldExpensive",	'c',		FALSE,
108467707Seric 	"AutoRebuildAliases",	'D',		FALSE,
108567707Seric 	"DeliveryMode",		'd',		TRUE,
108667707Seric 	"ErrorHeader",		'E',		FALSE,
108767707Seric 	"ErrorMode",		'e',		TRUE,
108867707Seric 	"TempFileMode",		'F',		FALSE,
108967707Seric 	"SaveFromLine",		'f',		FALSE,
109067707Seric 	"MatchGECOS",		'G',		FALSE,
109167707Seric 	"HelpFile",		'H',		FALSE,
109267707Seric 	"MaxHopCount",		'h',		FALSE,
109367707Seric 	"NameServerOptions",	'I',		FALSE,
109467707Seric 	"IgnoreDots",		'i',		TRUE,
109567707Seric 	"ForwardPath",		'J',		FALSE,
109667707Seric 	"SendMimeErrors",	'j',		TRUE,
109767707Seric 	"ConnectionCacheSize",	'k',		FALSE,
109867707Seric 	"ConnectionCacheTimeout", 'K',		FALSE,
109967707Seric 	"UseErrorsTo",		'l',		FALSE,
110067707Seric 	"LogLevel",		'L',		FALSE,
110167707Seric 	"MeToo",		'm',		TRUE,
110267707Seric 	"CheckAliases",		'n',		FALSE,
110367707Seric 	"OldStyleHeaders",	'o',		TRUE,
110467707Seric 	"DaemonPortOptions",	'O',		FALSE,
110567707Seric 	"PrivacyOptions",	'p',		TRUE,
110667707Seric 	"PostmasterCopy",	'P',		FALSE,
110767707Seric 	"QueueFactor",		'q',		FALSE,
110867707Seric 	"QueueDirectory",	'Q',		FALSE,
110967707Seric 	"DontPruneRoutes",	'R',		FALSE,
1110*67711Seric 	"Timeouts",		'r',		TRUE,
111167707Seric 	"StatusFile",		'S',		FALSE,
111267707Seric 	"SuperSafe",		's',		TRUE,
111367707Seric 	"QueueTimeout",		'T',		FALSE,
111467707Seric 	"TimeZoneSpec",		't',		FALSE,
111567707Seric 	"UserDatabaseSpec",	'U',		FALSE,
111667707Seric 	"DefaultUser",		'u',		FALSE,
111767707Seric 	"FallbackMXhost",	'V',		FALSE,
111867707Seric 	"Verbose",		'v',		TRUE,
111967707Seric 	"TryNullMXList",	'w',		TRUE,
112067707Seric 	"QueueLA",		'x',		FALSE,
112167707Seric 	"RefuseLA",		'X',		FALSE,
112267707Seric 	"RecipientFactor",	'y',		FALSE,
112367707Seric 	"ForkQueueRuns",	'Y',		FALSE,
112467707Seric 	"ClassFactor",		'z',		FALSE,
112567707Seric 	"TimeFactor",		'Z',		FALSE,
112667707Seric #define O_BSP		0x80
112767707Seric 	"BrokenSmtpPeers",	O_BSP,		TRUE,
112867707Seric #define O_SQBH		0x81
112967707Seric 	"SortQueueByHost",	O_SQBH,		TRUE,
113067707Seric #define O_DNICE		0x82
113167707Seric 	"DeliveryNiceness",	O_DNICE,	TRUE,
113267707Seric #define O_MQA		0x83
113367707Seric 	"MinQueueAge",		O_MQA,		TRUE,
113467707Seric #define O_MHSA		0x84
113567707Seric 	"MaxHostStatAge",	O_MHSA,		TRUE,
113667707Seric 
113767707Seric 	NULL,			'\0',		FALSE,
113867614Seric };
113967614Seric 
114067614Seric 
114167614Seric 
114258734Seric setoption(opt, val, safe, sticky, e)
114367614Seric 	u_char opt;
11448256Seric 	char *val;
114521755Seric 	bool safe;
11468269Seric 	bool sticky;
114758734Seric 	register ENVELOPE *e;
11488256Seric {
114957207Seric 	register char *p;
115067614Seric 	register struct optioninfo *o;
11518265Seric 	extern bool atobool();
115212633Seric 	extern time_t convtime();
115314879Seric 	extern int QueueLA;
115414879Seric 	extern int RefuseLA;
115564718Seric 	extern bool Warn_Q_option;
115617474Seric 	extern bool trusteduser();
11578256Seric 
115867614Seric 	if (opt == ' ')
115967614Seric 	{
116067614Seric 		/* full word options */
116167614Seric 
116267614Seric 		p = strchr(val, '=');
116367614Seric 		if (p == NULL)
116467614Seric 			p = &val[strlen(val)];
116567614Seric 		while (*--p == ' ')
116667614Seric 			continue;
116767614Seric 		while (*++p == ' ')
116867614Seric 			*p = '\0';
116967614Seric 		if (*p == '=')
117067614Seric 			*p++ = '\0';
117167614Seric 		while (*p == ' ')
117267614Seric 			p++;
117367614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
117467614Seric 		{
117567614Seric 			if (strcasecmp(o->o_name, val) == 0)
117667614Seric 				break;
117767614Seric 		}
117867614Seric 		if (o->o_name == NULL)
117967614Seric 			syserr("readcf: unknown option name %s", val);
118067614Seric 		opt = o->o_code;
118167614Seric 		val = p;
118267614Seric 	}
118367614Seric 	else
118467614Seric 	{
118567614Seric 		for (o = OptionTab; o->o_name != NULL; o++)
118667614Seric 		{
118767614Seric 			if (o->o_code == opt)
118867614Seric 				break;
118967614Seric 		}
119067614Seric 	}
119167614Seric 
11928256Seric 	if (tTd(37, 1))
119367614Seric 		printf("setoption %s (0x%x)=%s",
119467614Seric 			o->o_name == NULL ? "<unknown>" : o->o_name,
119567614Seric 			opt, val);
11968256Seric 
11978256Seric 	/*
11988269Seric 	**  See if this option is preset for us.
11998256Seric 	*/
12008256Seric 
120159731Seric 	if (!sticky && bitnset(opt, StickyOpt))
12028269Seric 	{
12039341Seric 		if (tTd(37, 1))
12049341Seric 			printf(" (ignored)\n");
12058269Seric 		return;
12068269Seric 	}
12078269Seric 
120821755Seric 	/*
120921755Seric 	**  Check to see if this option can be specified by this user.
121021755Seric 	*/
121121755Seric 
121263787Seric 	if (!safe && RealUid == 0)
121321755Seric 		safe = TRUE;
121467614Seric 	if (!safe && !o->o_safe)
121521755Seric 	{
121639111Srick 		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
121721755Seric 		{
121836582Sbostic 			if (tTd(37, 1))
121936582Sbostic 				printf(" (unsafe)");
122063787Seric 			if (RealUid != geteuid())
122136582Sbostic 			{
122251210Seric 				if (tTd(37, 1))
122351210Seric 					printf("(Resetting uid)");
122463787Seric 				(void) setgid(RealGid);
122563787Seric 				(void) setuid(RealUid);
122636582Sbostic 			}
122721755Seric 		}
122821755Seric 	}
122951210Seric 	if (tTd(37, 1))
123017985Seric 		printf("\n");
12318269Seric 
123267614Seric 	switch (opt & 0xff)
12338256Seric 	{
123459709Seric 	  case '7':		/* force seven-bit input */
123567546Seric 		SevenBitInput = atobool(val);
123652106Seric 		break;
123752106Seric 
123867546Seric 	  case '8':		/* handling of 8-bit input */
123967546Seric 		switch (*val)
124067546Seric 		{
124167547Seric 		  case 'r':		/* reject 8-bit, don't convert MIME */
124267546Seric 			MimeMode = 0;
124367546Seric 			break;
124467546Seric 
124567547Seric 		  case 'm':		/* convert 8-bit, convert MIME */
124667546Seric 			MimeMode = MM_CVTMIME|MM_MIME8BIT;
124767546Seric 			break;
124867546Seric 
124967547Seric 		  case 'j':		/* "just send 8" */
125067546Seric 			MimeMode = MM_PASS8BIT;
125167546Seric 			break;
125267546Seric 
125367546Seric 		  case 'p':		/* pass 8 bit, convert MIME */
125467546Seric 			MimeMode = MM_PASS8BIT|MM_CVTMIME;
125567546Seric 			break;
125667546Seric 
125767546Seric 		  case 's':		/* strict adherence */
125867546Seric 			MimeMode = MM_CVTMIME;
125967546Seric 			break;
126067546Seric 
126167547Seric 		  case 'a':		/* encode 8 bit if available */
126267546Seric 			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
126367546Seric 			break;
126467546Seric 
126567547Seric 		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
126667547Seric 			MimeMode = MM_MIME8BIT;
126767547Seric 			break;
126867547Seric 
126967546Seric 		  default:
127067546Seric 			syserr("Unknown 8-bit mode %c", *val);
127167546Seric 			exit(EX_USAGE);
127267546Seric 		}
127367546Seric 		break;
127467546Seric 
12758256Seric 	  case 'A':		/* set default alias file */
12769381Seric 		if (val[0] == '\0')
127759672Seric 			setalias("aliases");
12789381Seric 		else
127959672Seric 			setalias(val);
12808256Seric 		break;
12818256Seric 
128217474Seric 	  case 'a':		/* look N minutes for "@:@" in alias file */
128317474Seric 		if (val[0] == '\0')
128464796Seric 			SafeAlias = 5 * 60;		/* five minutes */
128517474Seric 		else
128664796Seric 			SafeAlias = convtime(val, 'm');
128717474Seric 		break;
128817474Seric 
128916843Seric 	  case 'B':		/* substitution for blank character */
129016843Seric 		SpaceSub = val[0];
129116843Seric 		if (SpaceSub == '\0')
129216843Seric 			SpaceSub = ' ';
129316843Seric 		break;
129416843Seric 
129559283Seric 	  case 'b':		/* min blocks free on queue fs/max msg size */
129659283Seric 		p = strchr(val, '/');
129759283Seric 		if (p != NULL)
129859283Seric 		{
129959283Seric 			*p++ = '\0';
130059283Seric 			MaxMessageSize = atol(p);
130159283Seric 		}
130258082Seric 		MinBlocksFree = atol(val);
130358082Seric 		break;
130458082Seric 
13059284Seric 	  case 'c':		/* don't connect to "expensive" mailers */
13069381Seric 		NoConnect = atobool(val);
13079284Seric 		break;
13089284Seric 
130951305Seric 	  case 'C':		/* checkpoint every N addresses */
131051305Seric 		CheckpointInterval = atoi(val);
131124944Seric 		break;
131224944Seric 
13139284Seric 	  case 'd':		/* delivery mode */
13149284Seric 		switch (*val)
13158269Seric 		{
13169284Seric 		  case '\0':
131758734Seric 			e->e_sendmode = SM_DELIVER;
13188269Seric 			break;
13198269Seric 
132010755Seric 		  case SM_QUEUE:	/* queue only */
132110755Seric #ifndef QUEUE
132210755Seric 			syserr("need QUEUE to set -odqueue");
132356795Seric #endif /* QUEUE */
132410755Seric 			/* fall through..... */
132510755Seric 
13269284Seric 		  case SM_DELIVER:	/* do everything */
13279284Seric 		  case SM_FORK:		/* fork after verification */
132858734Seric 			e->e_sendmode = *val;
13298269Seric 			break;
13308269Seric 
13318269Seric 		  default:
13329284Seric 			syserr("Unknown delivery mode %c", *val);
13338269Seric 			exit(EX_USAGE);
13348269Seric 		}
13358269Seric 		break;
13368269Seric 
13379146Seric 	  case 'D':		/* rebuild alias database as needed */
13389381Seric 		AutoRebuild = atobool(val);
13399146Seric 		break;
13409146Seric 
134155372Seric 	  case 'E':		/* error message header/header file */
134255379Seric 		if (*val != '\0')
134355379Seric 			ErrMsgFile = newstr(val);
134455372Seric 		break;
134555372Seric 
13468269Seric 	  case 'e':		/* set error processing mode */
13478269Seric 		switch (*val)
13488269Seric 		{
13499381Seric 		  case EM_QUIET:	/* be silent about it */
13509381Seric 		  case EM_MAIL:		/* mail back */
13519381Seric 		  case EM_BERKNET:	/* do berknet error processing */
13529381Seric 		  case EM_WRITE:	/* write back (or mail) */
13539381Seric 		  case EM_PRINT:	/* print errors normally (default) */
135458734Seric 			e->e_errormode = *val;
13558269Seric 			break;
13568269Seric 		}
13578269Seric 		break;
13588269Seric 
13599049Seric 	  case 'F':		/* file mode */
136017975Seric 		FileMode = atooct(val) & 0777;
13619049Seric 		break;
13629049Seric 
13638269Seric 	  case 'f':		/* save Unix-style From lines on front */
13649381Seric 		SaveFrom = atobool(val);
13658269Seric 		break;
13668269Seric 
136753735Seric 	  case 'G':		/* match recipients against GECOS field */
136853735Seric 		MatchGecos = atobool(val);
136953735Seric 		break;
137053735Seric 
13718256Seric 	  case 'g':		/* default gid */
137264133Seric 		if (isascii(*val) && isdigit(*val))
137364133Seric 			DefGid = atoi(val);
137464133Seric 		else
137564133Seric 		{
137664133Seric 			register struct group *gr;
137764133Seric 
137864133Seric 			DefGid = -1;
137964133Seric 			gr = getgrnam(val);
138064133Seric 			if (gr == NULL)
138164133Seric 				syserr("readcf: option g: unknown group %s", val);
138264133Seric 			else
138364133Seric 				DefGid = gr->gr_gid;
138464133Seric 		}
13858256Seric 		break;
13868256Seric 
13878256Seric 	  case 'H':		/* help file */
13889381Seric 		if (val[0] == '\0')
13898269Seric 			HelpFile = "sendmail.hf";
13909381Seric 		else
13919381Seric 			HelpFile = newstr(val);
13928256Seric 		break;
13938256Seric 
139451305Seric 	  case 'h':		/* maximum hop count */
139551305Seric 		MaxHopCount = atoi(val);
139651305Seric 		break;
139751305Seric 
139835651Seric 	  case 'I':		/* use internet domain name server */
139966334Seric #if NAMED_BIND
140057207Seric 		UseNameServer = TRUE;
140157207Seric 		for (p = val; *p != 0; )
140257207Seric 		{
140357207Seric 			bool clearmode;
140457207Seric 			char *q;
140557207Seric 			struct resolverflags *rfp;
140657207Seric 
140757207Seric 			while (*p == ' ')
140857207Seric 				p++;
140957207Seric 			if (*p == '\0')
141057207Seric 				break;
141157207Seric 			clearmode = FALSE;
141257207Seric 			if (*p == '-')
141357207Seric 				clearmode = TRUE;
141457207Seric 			else if (*p != '+')
141557207Seric 				p--;
141657207Seric 			p++;
141757207Seric 			q = p;
141858050Seric 			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
141957207Seric 				p++;
142057207Seric 			if (*p != '\0')
142157207Seric 				*p++ = '\0';
142257207Seric 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
142357207Seric 			{
142457207Seric 				if (strcasecmp(q, rfp->rf_name) == 0)
142557207Seric 					break;
142657207Seric 			}
142764923Seric 			if (rfp->rf_name == NULL)
142864923Seric 				syserr("readcf: I option value %s unrecognized", q);
142964923Seric 			else if (clearmode)
143057207Seric 				_res.options &= ~rfp->rf_bits;
143157207Seric 			else
143257207Seric 				_res.options |= rfp->rf_bits;
143357207Seric 		}
143457207Seric 		if (tTd(8, 2))
143557207Seric 			printf("_res.options = %x\n", _res.options);
143657207Seric #else
143757207Seric 		usrerr("name server (I option) specified but BIND not compiled in");
143857207Seric #endif
143935651Seric 		break;
144035651Seric 
14418269Seric 	  case 'i':		/* ignore dot lines in message */
14429381Seric 		IgnrDot = atobool(val);
14438269Seric 		break;
14448269Seric 
144559730Seric 	  case 'j':		/* send errors in MIME (RFC 1341) format */
144659730Seric 		SendMIMEErrors = atobool(val);
144759730Seric 		break;
144859730Seric 
144957136Seric 	  case 'J':		/* .forward search path */
145057136Seric 		ForwardPath = newstr(val);
145157136Seric 		break;
145257136Seric 
145354967Seric 	  case 'k':		/* connection cache size */
145454967Seric 		MaxMciCache = atoi(val);
145556215Seric 		if (MaxMciCache < 0)
145656215Seric 			MaxMciCache = 0;
145754967Seric 		break;
145854967Seric 
145954967Seric 	  case 'K':		/* connection cache timeout */
146058796Seric 		MciCacheTimeout = convtime(val, 'm');
146154967Seric 		break;
146254967Seric 
146361104Seric 	  case 'l':		/* use Errors-To: header */
146461104Seric 		UseErrorsTo = atobool(val);
146561104Seric 		break;
146661104Seric 
14678256Seric 	  case 'L':		/* log level */
146864140Seric 		if (safe || LogLevel < atoi(val))
146964140Seric 			LogLevel = atoi(val);
14708256Seric 		break;
14718256Seric 
14728269Seric 	  case 'M':		/* define macro */
14739381Seric 		define(val[0], newstr(&val[1]), CurEnv);
147416878Seric 		sticky = FALSE;
14758269Seric 		break;
14768269Seric 
14778269Seric 	  case 'm':		/* send to me too */
14789381Seric 		MeToo = atobool(val);
14798269Seric 		break;
14808269Seric 
148125820Seric 	  case 'n':		/* validate RHS in newaliases */
148225820Seric 		CheckAliases = atobool(val);
148325820Seric 		break;
148425820Seric 
148561104Seric 	    /* 'N' available -- was "net name" */
148661104Seric 
148758851Seric 	  case 'O':		/* daemon options */
148858851Seric 		setdaemonoptions(val);
148958851Seric 		break;
149058851Seric 
14918269Seric 	  case 'o':		/* assume old style headers */
14929381Seric 		if (atobool(val))
14939341Seric 			CurEnv->e_flags |= EF_OLDSTYLE;
14949341Seric 		else
14959341Seric 			CurEnv->e_flags &= ~EF_OLDSTYLE;
14968269Seric 		break;
14978269Seric 
149858082Seric 	  case 'p':		/* select privacy level */
149958082Seric 		p = val;
150058082Seric 		for (;;)
150158082Seric 		{
150258082Seric 			register struct prival *pv;
150358082Seric 			extern struct prival PrivacyValues[];
150458082Seric 
150558082Seric 			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
150658082Seric 				p++;
150758082Seric 			if (*p == '\0')
150858082Seric 				break;
150958082Seric 			val = p;
151058082Seric 			while (isascii(*p) && isalnum(*p))
151158082Seric 				p++;
151258082Seric 			if (*p != '\0')
151358082Seric 				*p++ = '\0';
151458082Seric 
151558082Seric 			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
151658082Seric 			{
151758082Seric 				if (strcasecmp(val, pv->pv_name) == 0)
151858082Seric 					break;
151958082Seric 			}
152058886Seric 			if (pv->pv_name == NULL)
152158886Seric 				syserr("readcf: Op line: %s unrecognized", val);
152258082Seric 			PrivacyFlags |= pv->pv_flag;
152358082Seric 		}
152458082Seric 		break;
152558082Seric 
152624944Seric 	  case 'P':		/* postmaster copy address for returned mail */
152724944Seric 		PostMasterCopy = newstr(val);
152824944Seric 		break;
152924944Seric 
153024944Seric 	  case 'q':		/* slope of queue only function */
153124944Seric 		QueueFactor = atoi(val);
153224944Seric 		break;
153324944Seric 
15348256Seric 	  case 'Q':		/* queue directory */
15359381Seric 		if (val[0] == '\0')
15368269Seric 			QueueDir = "mqueue";
15379381Seric 		else
15389381Seric 			QueueDir = newstr(val);
153958789Seric 		if (RealUid != 0 && !safe)
154064718Seric 			Warn_Q_option = TRUE;
15418256Seric 		break;
15428256Seric 
154358148Seric 	  case 'R':		/* don't prune routes */
154458148Seric 		DontPruneRoutes = atobool(val);
154558148Seric 		break;
154658148Seric 
15478256Seric 	  case 'r':		/* read timeout */
154858112Seric 		settimeouts(val);
15498256Seric 		break;
15508256Seric 
15518256Seric 	  case 'S':		/* status file */
15529381Seric 		if (val[0] == '\0')
15538269Seric 			StatFile = "sendmail.st";
15549381Seric 		else
15559381Seric 			StatFile = newstr(val);
15568256Seric 		break;
15578256Seric 
15588265Seric 	  case 's':		/* be super safe, even if expensive */
15599381Seric 		SuperSafe = atobool(val);
15608256Seric 		break;
15618256Seric 
15628256Seric 	  case 'T':		/* queue timeout */
156358737Seric 		p = strchr(val, '/');
156458737Seric 		if (p != NULL)
156558737Seric 		{
156658737Seric 			*p++ = '\0';
156758796Seric 			TimeOuts.to_q_warning = convtime(p, 'd');
156858737Seric 		}
156958796Seric 		TimeOuts.to_q_return = convtime(val, 'h');
157054967Seric 		break;
15718256Seric 
15728265Seric 	  case 't':		/* time zone name */
157352106Seric 		TimeZoneSpec = newstr(val);
15748265Seric 		break;
15758265Seric 
157650556Seric 	  case 'U':		/* location of user database */
157751360Seric 		UdbSpec = newstr(val);
157850556Seric 		break;
157950556Seric 
15808256Seric 	  case 'u':		/* set default uid */
158164133Seric 		if (isascii(*val) && isdigit(*val))
158264133Seric 			DefUid = atoi(val);
158364133Seric 		else
158464133Seric 		{
158564133Seric 			register struct passwd *pw;
158664133Seric 
158764133Seric 			DefUid = -1;
158864133Seric 			pw = getpwnam(val);
158964133Seric 			if (pw == NULL)
159064133Seric 				syserr("readcf: option u: unknown user %s", val);
159164133Seric 			else
159264133Seric 				DefUid = pw->pw_uid;
159364133Seric 		}
159440973Sbostic 		setdefuser();
15958256Seric 		break;
15968256Seric 
159758851Seric 	  case 'V':		/* fallback MX host */
159858851Seric 		FallBackMX = newstr(val);
159958851Seric 		break;
160058851Seric 
16018269Seric 	  case 'v':		/* run in verbose mode */
16029381Seric 		Verbose = atobool(val);
16038256Seric 		break;
16048256Seric 
160563837Seric 	  case 'w':		/* if we are best MX, try host directly */
160663837Seric 		TryNullMXList = atobool(val);
160763837Seric 		break;
160861104Seric 
160961104Seric 	    /* 'W' available -- was wizard password */
161061104Seric 
161114879Seric 	  case 'x':		/* load avg at which to auto-queue msgs */
161214879Seric 		QueueLA = atoi(val);
161314879Seric 		break;
161414879Seric 
161514879Seric 	  case 'X':		/* load avg at which to auto-reject connections */
161614879Seric 		RefuseLA = atoi(val);
161714879Seric 		break;
161814879Seric 
161924981Seric 	  case 'y':		/* work recipient factor */
162024981Seric 		WkRecipFact = atoi(val);
162124981Seric 		break;
162224981Seric 
162324981Seric 	  case 'Y':		/* fork jobs during queue runs */
162424952Seric 		ForkQueueRuns = atobool(val);
162524952Seric 		break;
162624952Seric 
162724981Seric 	  case 'z':		/* work message class factor */
162824981Seric 		WkClassFact = atoi(val);
162924981Seric 		break;
163024981Seric 
163124981Seric 	  case 'Z':		/* work time factor */
163224981Seric 		WkTimeFact = atoi(val);
163324981Seric 		break;
163424981Seric 
163567614Seric 	  case O_BSP:		/* SMTP Peers can't handle 2-line greeting */
163667614Seric 		BrokenSmtpPeers = atobool(val);
163767614Seric 		break;
163867614Seric 
163967614Seric 	  case O_SQBH:		/* sort work queue by host first */
164067614Seric 		SortQueueByHost = atobool(val);
164167614Seric 		break;
164267614Seric 
164367707Seric 	  case O_DNICE:		/* delivery nice value */
164467707Seric 		DeliveryNiceness = atoi(val);
164567707Seric 		break;
164667707Seric 
164767707Seric 	  case O_MQA:		/* minimum queue age between deliveries */
164867707Seric 		MinQueueAge = convtime(val, 'm');
164967707Seric 		break;
165067707Seric 
165167707Seric 	  case O_MHSA:		/* maximum age of cached host status */
165267707Seric 		MaxHostStatAge = convtime(val, 'm');
165367707Seric 		break;
165467707Seric 
16558256Seric 	  default:
16568256Seric 		break;
16578256Seric 	}
165816878Seric 	if (sticky)
165916878Seric 		setbitn(opt, StickyOpt);
16609188Seric 	return;
16618256Seric }
166210687Seric /*
166310687Seric **  SETCLASS -- set a word into a class
166410687Seric **
166510687Seric **	Parameters:
166610687Seric **		class -- the class to put the word in.
166710687Seric **		word -- the word to enter
166810687Seric **
166910687Seric **	Returns:
167010687Seric **		none.
167110687Seric **
167210687Seric **	Side Effects:
167310687Seric **		puts the word into the symbol table.
167410687Seric */
167510687Seric 
167610687Seric setclass(class, word)
167710687Seric 	int class;
167810687Seric 	char *word;
167910687Seric {
168010687Seric 	register STAB *s;
168110687Seric 
168257943Seric 	if (tTd(37, 8))
168364326Seric 		printf("setclass(%c, %s)\n", class, word);
168410687Seric 	s = stab(word, ST_CLASS, ST_ENTER);
168510687Seric 	setbitn(class, s->s_class);
168610687Seric }
168753654Seric /*
168853654Seric **  MAKEMAPENTRY -- create a map entry
168953654Seric **
169053654Seric **	Parameters:
169153654Seric **		line -- the config file line
169253654Seric **
169353654Seric **	Returns:
169453654Seric **		TRUE if it successfully entered the map entry.
169553654Seric **		FALSE otherwise (usually syntax error).
169653654Seric **
169753654Seric **	Side Effects:
169853654Seric **		Enters the map into the dictionary.
169953654Seric */
170053654Seric 
170153654Seric void
170253654Seric makemapentry(line)
170353654Seric 	char *line;
170453654Seric {
170553654Seric 	register char *p;
170653654Seric 	char *mapname;
170753654Seric 	char *classname;
170864078Seric 	register STAB *s;
170953654Seric 	STAB *class;
171053654Seric 
171158050Seric 	for (p = line; isascii(*p) && isspace(*p); p++)
171253654Seric 		continue;
171358050Seric 	if (!(isascii(*p) && isalnum(*p)))
171453654Seric 	{
171553654Seric 		syserr("readcf: config K line: no map name");
171653654Seric 		return;
171753654Seric 	}
171853654Seric 
171953654Seric 	mapname = p;
172058050Seric 	while (isascii(*++p) && isalnum(*p))
172153654Seric 		continue;
172253654Seric 	if (*p != '\0')
172353654Seric 		*p++ = '\0';
172458050Seric 	while (isascii(*p) && isspace(*p))
172553654Seric 		p++;
172658050Seric 	if (!(isascii(*p) && isalnum(*p)))
172753654Seric 	{
172853654Seric 		syserr("readcf: config K line, map %s: no map class", mapname);
172953654Seric 		return;
173053654Seric 	}
173153654Seric 	classname = p;
173258050Seric 	while (isascii(*++p) && isalnum(*p))
173353654Seric 		continue;
173453654Seric 	if (*p != '\0')
173553654Seric 		*p++ = '\0';
173658050Seric 	while (isascii(*p) && isspace(*p))
173753654Seric 		p++;
173853654Seric 
173953654Seric 	/* look up the class */
174053654Seric 	class = stab(classname, ST_MAPCLASS, ST_FIND);
174153654Seric 	if (class == NULL)
174253654Seric 	{
174353654Seric 		syserr("readcf: map %s: class %s not available", mapname, classname);
174453654Seric 		return;
174553654Seric 	}
174653654Seric 
174753654Seric 	/* enter the map */
174864078Seric 	s = stab(mapname, ST_MAP, ST_ENTER);
174964078Seric 	s->s_map.map_class = &class->s_mapclass;
175064078Seric 	s->s_map.map_mname = newstr(mapname);
175153654Seric 
175264078Seric 	if (class->s_mapclass.map_parse(&s->s_map, p))
175364078Seric 		s->s_map.map_mflags |= MF_VALID;
175464078Seric 
175564078Seric 	if (tTd(37, 5))
175664078Seric 	{
175764078Seric 		printf("map %s, class %s, flags %x, file %s,\n",
175864078Seric 			s->s_map.map_mname, s->s_map.map_class->map_cname,
175964078Seric 			s->s_map.map_mflags,
176064078Seric 			s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
176164078Seric 		printf("\tapp %s, domain %s, rebuild %s\n",
176264078Seric 			s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
176364078Seric 			s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
176464078Seric 			s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
176564078Seric 	}
176653654Seric }
176758112Seric /*
176858112Seric **  SETTIMEOUTS -- parse and set timeout values
176958112Seric **
177058112Seric **	Parameters:
177158112Seric **		val -- a pointer to the values.  If NULL, do initial
177258112Seric **			settings.
177358112Seric **
177458112Seric **	Returns:
177558112Seric **		none.
177658112Seric **
177758112Seric **	Side Effects:
177858112Seric **		Initializes the TimeOuts structure
177958112Seric */
178058112Seric 
178164255Seric #define SECONDS
178258112Seric #define MINUTES	* 60
178358112Seric #define HOUR	* 3600
178458112Seric 
178558112Seric settimeouts(val)
178658112Seric 	register char *val;
178758112Seric {
178858112Seric 	register char *p;
178958671Seric 	extern time_t convtime();
179058112Seric 
179158112Seric 	if (val == NULL)
179258112Seric 	{
179358112Seric 		TimeOuts.to_initial = (time_t) 5 MINUTES;
179458112Seric 		TimeOuts.to_helo = (time_t) 5 MINUTES;
179558112Seric 		TimeOuts.to_mail = (time_t) 10 MINUTES;
179658112Seric 		TimeOuts.to_rcpt = (time_t) 1 HOUR;
179758112Seric 		TimeOuts.to_datainit = (time_t) 5 MINUTES;
179858112Seric 		TimeOuts.to_datablock = (time_t) 1 HOUR;
179958112Seric 		TimeOuts.to_datafinal = (time_t) 1 HOUR;
180058112Seric 		TimeOuts.to_rset = (time_t) 5 MINUTES;
180158112Seric 		TimeOuts.to_quit = (time_t) 2 MINUTES;
180258112Seric 		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
180358112Seric 		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
180464255Seric 		TimeOuts.to_ident = (time_t) 30 SECONDS;
1805*67711Seric 		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
180658112Seric 		return;
180758112Seric 	}
180858112Seric 
180958112Seric 	for (;; val = p)
181058112Seric 	{
181158112Seric 		while (isascii(*val) && isspace(*val))
181258112Seric 			val++;
181358112Seric 		if (*val == '\0')
181458112Seric 			break;
181558112Seric 		for (p = val; *p != '\0' && *p != ','; p++)
181658112Seric 			continue;
181758112Seric 		if (*p != '\0')
181858112Seric 			*p++ = '\0';
181958112Seric 
182058112Seric 		if (isascii(*val) && isdigit(*val))
182158112Seric 		{
182258112Seric 			/* old syntax -- set everything */
182358796Seric 			TimeOuts.to_mail = convtime(val, 'm');
182458112Seric 			TimeOuts.to_rcpt = TimeOuts.to_mail;
182558112Seric 			TimeOuts.to_datainit = TimeOuts.to_mail;
182658112Seric 			TimeOuts.to_datablock = TimeOuts.to_mail;
182758112Seric 			TimeOuts.to_datafinal = TimeOuts.to_mail;
182858112Seric 			TimeOuts.to_nextcommand = TimeOuts.to_mail;
182958112Seric 			continue;
183058112Seric 		}
183158112Seric 		else
183258112Seric 		{
1833*67711Seric 			register char *q = strchr(val, ':');
183458112Seric 			time_t to;
183558112Seric 
1836*67711Seric 			if (q == NULL && (q = strchr(val, '=')) == NULL)
183758112Seric 			{
183858112Seric 				/* syntax error */
183958112Seric 				continue;
184058112Seric 			}
184158112Seric 			*q++ = '\0';
184258796Seric 			to = convtime(q, 'm');
184358112Seric 
184458112Seric 			if (strcasecmp(val, "initial") == 0)
184558112Seric 				TimeOuts.to_initial = to;
184658112Seric 			else if (strcasecmp(val, "mail") == 0)
184758112Seric 				TimeOuts.to_mail = to;
184858112Seric 			else if (strcasecmp(val, "rcpt") == 0)
184958112Seric 				TimeOuts.to_rcpt = to;
185058112Seric 			else if (strcasecmp(val, "datainit") == 0)
185158112Seric 				TimeOuts.to_datainit = to;
185258112Seric 			else if (strcasecmp(val, "datablock") == 0)
185358112Seric 				TimeOuts.to_datablock = to;
185458112Seric 			else if (strcasecmp(val, "datafinal") == 0)
185558112Seric 				TimeOuts.to_datafinal = to;
185658112Seric 			else if (strcasecmp(val, "command") == 0)
185758112Seric 				TimeOuts.to_nextcommand = to;
185858112Seric 			else if (strcasecmp(val, "rset") == 0)
185958112Seric 				TimeOuts.to_rset = to;
186058112Seric 			else if (strcasecmp(val, "helo") == 0)
186158112Seric 				TimeOuts.to_helo = to;
186258112Seric 			else if (strcasecmp(val, "quit") == 0)
186358112Seric 				TimeOuts.to_quit = to;
186458112Seric 			else if (strcasecmp(val, "misc") == 0)
186558112Seric 				TimeOuts.to_miscshort = to;
186664255Seric 			else if (strcasecmp(val, "ident") == 0)
186764255Seric 				TimeOuts.to_ident = to;
1868*67711Seric 			else if (strcasecmp(val, "fileopen") == 0)
1869*67711Seric 				TimeOuts.to_fileopen = to;
1870*67711Seric 			else if (strcasecmp(val, "queuewarn") == 0)
1871*67711Seric 				TimeOuts.to_q_warning = to;
1872*67711Seric 			else if (strcasecmp(val, "queuereturn") == 0)
1873*67711Seric 				TimeOuts.to_q_return = to;
187458112Seric 			else
187558112Seric 				syserr("settimeouts: invalid timeout %s", val);
187658112Seric 		}
187758112Seric 	}
187858112Seric }
1879