138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2006, 2008-2010, 2013 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
15168515Sgshapiro#include <sm/sendmail.h>
16363466Sgshapiro#if STARTTLS
17363466Sgshapiro# include <tls.h>
18363466Sgshapiro#endif
19363466Sgshapiro#if DNSSEC_TEST
20363466Sgshapiro# include <sm_resolve.h>
21363466Sgshapiro#endif
2238032Speter
23266527SgshapiroSM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
2464562Sgshapiro
2564562Sgshapiro#if NETINET || NETINET6
2664562Sgshapiro# include <arpa/inet.h>
27363466Sgshapiro#endif
2864562Sgshapiro
29223067Sgshapiro
3064562Sgshapiro#define SECONDS
3164562Sgshapiro#define MINUTES	* 60
3264562Sgshapiro#define HOUR	* 3600
3364562Sgshapiro#define HOURS	HOUR
3464562Sgshapiro
3594334Sgshapirostatic void	fileclass __P((int, char *, char *, bool, bool, bool));
3664562Sgshapirostatic char	**makeargv __P((char *));
3764562Sgshapirostatic void	settimeout __P((char *, char *, bool));
3864562Sgshapirostatic void	toomany __P((int, int));
3990792Sgshapirostatic char	*extrquotstr __P((char *, char **, char *, bool *));
40141858Sgshapirostatic void	parse_class_words __P((int, char *));
4164562Sgshapiro
42285229Sgshapiro
43285229Sgshapiro#if _FFR_BOUNCE_QUEUE
44285229Sgshapirostatic char *bouncequeue = NULL;
45285229Sgshapirostatic void initbouncequeue __P((void));
46285229Sgshapiro
4738032Speter/*
48285229Sgshapiro**  INITBOUNCEQUEUE -- determine BounceQueue if option is set.
49285229Sgshapiro**
50285229Sgshapiro**	Parameters:
51285229Sgshapiro**		none.
52285229Sgshapiro**
53285229Sgshapiro**	Returns:
54285229Sgshapiro**		none.
55285229Sgshapiro**
56285229Sgshapiro**	Side Effects:
57285229Sgshapiro**		sets BounceQueue
58285229Sgshapiro*/
59285229Sgshapiro
60285229Sgshapirostatic void
61285229Sgshapiroinitbouncequeue()
62285229Sgshapiro{
63285229Sgshapiro	STAB *s;
64285229Sgshapiro
65285229Sgshapiro	BounceQueue = NOQGRP;
66285229Sgshapiro	if (bouncequeue == NULL || bouncequeue[0] == '\0')
67285229Sgshapiro		return;
68285229Sgshapiro
69285229Sgshapiro	s = stab(bouncequeue, ST_QUEUE, ST_FIND);
70285229Sgshapiro	if (s == NULL)
71285229Sgshapiro	{
72285229Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
73285229Sgshapiro			"Warning: option BounceQueue: unknown queue group %s\n",
74285229Sgshapiro			bouncequeue);
75285229Sgshapiro	}
76285229Sgshapiro	else
77285229Sgshapiro		BounceQueue = s->s_quegrp->qg_index;
78285229Sgshapiro}
79285229Sgshapiro#endif /* _FFR_BOUNCE_QUEUE */
80285229Sgshapiro
81285229Sgshapiro#if _FFR_RCPTFLAGS
82285229Sgshapirovoid setupdynmailers __P((void));
83285229Sgshapiro#else
84285229Sgshapiro#define setupdynmailers()
85285229Sgshapiro#endif
86285229Sgshapiro
87285229Sgshapiro/*
8838032Speter**  READCF -- read configuration file.
8938032Speter**
9038032Speter**	This routine reads the configuration file and builds the internal
9138032Speter**	form.
9238032Speter**
9338032Speter**	The file is formatted as a sequence of lines, each taken
9438032Speter**	atomically.  The first character of each line describes how
9538032Speter**	the line is to be interpreted.  The lines are:
9638032Speter**		Dxval		Define macro x to have value val.
9738032Speter**		Cxword		Put word into class x.
9838032Speter**		Fxfile [fmt]	Read file for lines to put into
9938032Speter**				class x.  Use scanf string 'fmt'
10038032Speter**				or "%s" if not present.  Fmt should
10138032Speter**				only produce one string-valued result.
10238032Speter**		Hname: value	Define header with field-name 'name'
10338032Speter**				and value as specified; this will be
10438032Speter**				macro expanded immediately before
10538032Speter**				use.
10638032Speter**		Sn		Use rewriting set n.
10738032Speter**		Rlhs rhs	Rewrite addresses that match lhs to
10838032Speter**				be rhs.
10938032Speter**		Mn arg=val...	Define mailer.  n is the internal name.
11038032Speter**				Args specify mailer parameters.
11138032Speter**		Oxvalue		Set option x to value.
11290792Sgshapiro**		O option value	Set option (long name) to value.
11338032Speter**		Pname=value	Set precedence name to value.
11490792Sgshapiro**		Qn arg=val...	Define queue groups.  n is the internal name.
11590792Sgshapiro**				Args specify queue parameters.
11638032Speter**		Vversioncode[/vendorcode]
11738032Speter**				Version level/vendor name of
11838032Speter**				configuration syntax.
11938032Speter**		Kmapname mapclass arguments....
12038032Speter**				Define keyed lookup of a given class.
12138032Speter**				Arguments are class dependent.
12238032Speter**		Eenvar=value	Set the environment value to the given value.
12338032Speter**
12438032Speter**	Parameters:
12538032Speter**		cfname -- configuration file name.
12690792Sgshapiro**		safe -- true if this is the system config file;
12790792Sgshapiro**			false otherwise.
12838032Speter**		e -- the main envelope.
12938032Speter**
13038032Speter**	Returns:
13138032Speter**		none.
13238032Speter**
13338032Speter**	Side Effects:
13438032Speter**		Builds several internal tables.
13538032Speter*/
13638032Speter
13738032Spetervoid
13838032Speterreadcf(cfname, safe, e)
13938032Speter	char *cfname;
14038032Speter	bool safe;
14138032Speter	register ENVELOPE *e;
14238032Speter{
14390792Sgshapiro	SM_FILE_T *cf;
14464562Sgshapiro	int ruleset = -1;
14538032Speter	char *q;
14638032Speter	struct rewrite *rwp = NULL;
14738032Speter	char *bp;
14838032Speter	auto char *ep;
14938032Speter	int nfuzzy;
15038032Speter	char *file;
15138032Speter	bool optional;
15290792Sgshapiro	bool ok;
15394334Sgshapiro	bool ismap;
15438032Speter	int mid;
15538032Speter	register char *p;
15664562Sgshapiro	long sff = SFF_OPENASROOT;
15738032Speter	struct stat statb;
15838032Speter	char buf[MAXLINE];
159168515Sgshapiro	int bufsize;
16038032Speter	char exbuf[MAXLINE];
16138032Speter	char pvpbuf[MAXLINE + MAXATOM];
16238032Speter	static char *null_list[1] = { NULL };
16390792Sgshapiro	extern unsigned char TokTypeNoC[];
16438032Speter
16538032Speter	FileName = cfname;
16638032Speter	LineNumber = 0;
16738032Speter
16838032Speter	if (DontLockReadFiles)
16938032Speter		sff |= SFF_NOLOCK;
17038032Speter	cf = safefopen(cfname, O_RDONLY, 0444, sff);
17138032Speter	if (cf == NULL)
17238032Speter	{
17338032Speter		syserr("cannot open");
17490792Sgshapiro		finis(false, true, EX_OSFILE);
17538032Speter	}
17638032Speter
17790792Sgshapiro	if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0)
17838032Speter	{
17938032Speter		syserr("cannot fstat");
18090792Sgshapiro		finis(false, true, EX_OSFILE);
18138032Speter	}
18238032Speter
18338032Speter	if (!S_ISREG(statb.st_mode))
18438032Speter	{
18538032Speter		syserr("not a plain file");
18690792Sgshapiro		finis(false, true, EX_OSFILE);
18738032Speter	}
18838032Speter
18938032Speter	if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
19038032Speter	{
191203004Sgshapiro		if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS || OpMode == MD_CHECKCONFIG)
19290792Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
19390792Sgshapiro					     "%s: WARNING: dangerous write permissions\n",
19490792Sgshapiro					     FileName);
19538032Speter		if (LogLevel > 0)
19638032Speter			sm_syslog(LOG_CRIT, NOQID,
19764562Sgshapiro				  "%s: WARNING: dangerous write permissions",
19864562Sgshapiro				  FileName);
19938032Speter	}
20038032Speter
20190792Sgshapiro#if XLA
20238032Speter	xla_zero();
203363466Sgshapiro#endif
20438032Speter
205168515Sgshapiro	while (bufsize = sizeof(buf),
206168515Sgshapiro	       (bp = fgetfolded(buf, &bufsize, cf)) != NULL)
20738032Speter	{
208168515Sgshapiro		char *nbp;
209168515Sgshapiro
21038032Speter		if (bp[0] == '#')
21138032Speter		{
21238032Speter			if (bp != buf)
21390792Sgshapiro				sm_free(bp); /* XXX */
21438032Speter			continue;
21538032Speter		}
21638032Speter
21738032Speter		/* do macro expansion mappings */
218168515Sgshapiro		nbp = translate_dollars(bp, bp, &bufsize);
219168515Sgshapiro		if (nbp != bp && bp != buf)
220168515Sgshapiro			sm_free(bp);
221168515Sgshapiro		bp = nbp;
22238032Speter
22338032Speter		/* interpret this line */
22438032Speter		errno = 0;
22538032Speter		switch (bp[0])
22638032Speter		{
22738032Speter		  case '\0':
22838032Speter		  case '#':		/* comment */
22938032Speter			break;
23038032Speter
23138032Speter		  case 'R':		/* rewriting rule */
23264562Sgshapiro			if (ruleset < 0)
23364562Sgshapiro			{
23464562Sgshapiro				syserr("missing valid ruleset for \"%s\"", bp);
23564562Sgshapiro				break;
23664562Sgshapiro			}
23738032Speter			for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
23838032Speter				continue;
23938032Speter
24038032Speter			if (*p == '\0')
24138032Speter			{
24238032Speter				syserr("invalid rewrite line \"%s\" (tab expected)", bp);
24338032Speter				break;
24438032Speter			}
24538032Speter
24638032Speter			/* allocate space for the rule header */
24738032Speter			if (rwp == NULL)
24838032Speter			{
24938032Speter				RewriteRules[ruleset] = rwp =
250168515Sgshapiro					(struct rewrite *) xalloc(sizeof(*rwp));
25138032Speter			}
25238032Speter			else
25338032Speter			{
254168515Sgshapiro				rwp->r_next = (struct rewrite *) xalloc(sizeof(*rwp));
25538032Speter				rwp = rwp->r_next;
25638032Speter			}
25738032Speter			rwp->r_next = NULL;
25838032Speter
25938032Speter			/* expand and save the LHS */
26038032Speter			*p = '\0';
261168515Sgshapiro			expand(&bp[1], exbuf, sizeof(exbuf), e);
26238032Speter			rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
263168515Sgshapiro					     sizeof(pvpbuf), NULL,
264168515Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
265132943Sgshapiro					     true);
26638032Speter			nfuzzy = 0;
26738032Speter			if (rwp->r_lhs != NULL)
26838032Speter			{
26938032Speter				register char **ap;
27038032Speter
27190792Sgshapiro				rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL);
27238032Speter
27338032Speter				/* count the number of fuzzy matches in LHS */
27438032Speter				for (ap = rwp->r_lhs; *ap != NULL; ap++)
27538032Speter				{
27638032Speter					char *botch;
27738032Speter
27838032Speter					botch = NULL;
279168515Sgshapiro					switch (ap[0][0] & 0377)
28038032Speter					{
28138032Speter					  case MATCHZANY:
28238032Speter					  case MATCHANY:
28338032Speter					  case MATCHONE:
28438032Speter					  case MATCHCLASS:
28538032Speter					  case MATCHNCLASS:
28638032Speter						nfuzzy++;
28738032Speter						break;
28838032Speter
28938032Speter					  case MATCHREPL:
290168515Sgshapiro						botch = "$1-$9";
29138032Speter						break;
29238032Speter
29338032Speter					  case CANONUSER:
29438032Speter						botch = "$:";
29538032Speter						break;
29638032Speter
29738032Speter					  case CALLSUBR:
29838032Speter						botch = "$>";
29938032Speter						break;
30038032Speter
30138032Speter					  case CONDIF:
30238032Speter						botch = "$?";
30338032Speter						break;
30438032Speter
30538032Speter					  case CONDFI:
30638032Speter						botch = "$.";
30738032Speter						break;
30838032Speter
30938032Speter					  case HOSTBEGIN:
31038032Speter						botch = "$[";
31138032Speter						break;
31238032Speter
31338032Speter					  case HOSTEND:
31438032Speter						botch = "$]";
31538032Speter						break;
31638032Speter
31738032Speter					  case LOOKUPBEGIN:
31838032Speter						botch = "$(";
31938032Speter						break;
32038032Speter
32138032Speter					  case LOOKUPEND:
32238032Speter						botch = "$)";
32338032Speter						break;
32438032Speter					}
32538032Speter					if (botch != NULL)
32638032Speter						syserr("Inappropriate use of %s on LHS",
32738032Speter							botch);
32838032Speter				}
32964562Sgshapiro				rwp->r_line = LineNumber;
33038032Speter			}
33138032Speter			else
33238032Speter			{
33338032Speter				syserr("R line: null LHS");
33438032Speter				rwp->r_lhs = null_list;
33538032Speter			}
33682017Sgshapiro			if (nfuzzy > MAXMATCH)
33782017Sgshapiro			{
33882017Sgshapiro				syserr("R line: too many wildcards");
33982017Sgshapiro				rwp->r_lhs = null_list;
34082017Sgshapiro			}
34138032Speter
34238032Speter			/* expand and save the RHS */
34338032Speter			while (*++p == '\t')
34438032Speter				continue;
34538032Speter			q = p;
34638032Speter			while (*p != '\0' && *p != '\t')
34738032Speter				p++;
34838032Speter			*p = '\0';
349168515Sgshapiro			expand(q, exbuf, sizeof(exbuf), e);
35038032Speter			rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
351168515Sgshapiro					     sizeof(pvpbuf), NULL,
352168515Sgshapiro					     ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
353132943Sgshapiro					     true);
35438032Speter			if (rwp->r_rhs != NULL)
35538032Speter			{
35638032Speter				register char **ap;
357120256Sgshapiro				int args, endtoken;
358120256Sgshapiro#if _FFR_EXTRA_MAP_CHECK
359120256Sgshapiro				int nexttoken;
360363466Sgshapiro#endif
361120256Sgshapiro				bool inmap;
36238032Speter
36390792Sgshapiro				rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
36438032Speter
36538032Speter				/* check no out-of-bounds replacements */
36638032Speter				nfuzzy += '0';
367120256Sgshapiro				inmap = false;
368120256Sgshapiro				args = 0;
369120256Sgshapiro				endtoken = 0;
37038032Speter				for (ap = rwp->r_rhs; *ap != NULL; ap++)
37138032Speter				{
37238032Speter					char *botch;
37338032Speter
37438032Speter					botch = NULL;
375168515Sgshapiro					switch (ap[0][0] & 0377)
37638032Speter					{
37738032Speter					  case MATCHREPL:
378168515Sgshapiro						if (ap[0][1] <= '0' ||
379168515Sgshapiro						    ap[0][1] > nfuzzy)
38038032Speter						{
38138032Speter							syserr("replacement $%c out of bounds",
382168515Sgshapiro								ap[0][1]);
38338032Speter						}
38438032Speter						break;
38538032Speter
38638032Speter					  case MATCHZANY:
38738032Speter						botch = "$*";
38838032Speter						break;
38938032Speter
39038032Speter					  case MATCHANY:
39138032Speter						botch = "$+";
39238032Speter						break;
39338032Speter
39438032Speter					  case MATCHONE:
39538032Speter						botch = "$-";
39638032Speter						break;
39738032Speter
39838032Speter					  case MATCHCLASS:
39938032Speter						botch = "$=";
40038032Speter						break;
40138032Speter
40238032Speter					  case MATCHNCLASS:
40338032Speter						botch = "$~";
40438032Speter						break;
40590792Sgshapiro
406120256Sgshapiro					  case CANONHOST:
407120256Sgshapiro						if (!inmap)
408120256Sgshapiro							break;
409120256Sgshapiro						if (++args >= MAX_MAP_ARGS)
410120256Sgshapiro							syserr("too many arguments for map lookup");
411120256Sgshapiro						break;
412120256Sgshapiro
413120256Sgshapiro					  case HOSTBEGIN:
414120256Sgshapiro						endtoken = HOSTEND;
415120256Sgshapiro						/* FALLTHROUGH */
416120256Sgshapiro					  case LOOKUPBEGIN:
417120256Sgshapiro						/* see above... */
418168515Sgshapiro						if ((ap[0][0] & 0377) == LOOKUPBEGIN)
419120256Sgshapiro							endtoken = LOOKUPEND;
420120256Sgshapiro						if (inmap)
421120256Sgshapiro							syserr("cannot nest map lookups");
422120256Sgshapiro						inmap = true;
423120256Sgshapiro						args = 0;
424120256Sgshapiro#if _FFR_EXTRA_MAP_CHECK
425168515Sgshapiro						if (ap[1] == NULL)
426120256Sgshapiro						{
427120256Sgshapiro							syserr("syntax error in map lookup");
428120256Sgshapiro							break;
429120256Sgshapiro						}
430168515Sgshapiro						nexttoken = ap[1][0] & 0377;
431120256Sgshapiro						if (nexttoken == CANONHOST ||
432120256Sgshapiro						    nexttoken == CANONUSER ||
433363466Sgshapiro						    nexttoken == endtoken)
434120256Sgshapiro						{
435120256Sgshapiro							syserr("missing map name for lookup");
436120256Sgshapiro							break;
437120256Sgshapiro						}
438168515Sgshapiro						if (ap[2] == NULL)
439120256Sgshapiro						{
440120256Sgshapiro							syserr("syntax error in map lookup");
441120256Sgshapiro							break;
442120256Sgshapiro						}
443363466Sgshapiro						if ((unsigned char) ap[0][0] == HOSTBEGIN)
444120256Sgshapiro							break;
445168515Sgshapiro						nexttoken = ap[2][0] & 0377;
446120256Sgshapiro						if (nexttoken == CANONHOST ||
447120256Sgshapiro						    nexttoken == CANONUSER ||
448120256Sgshapiro						    nexttoken == endtoken)
449120256Sgshapiro						{
450120256Sgshapiro							syserr("missing key name for lookup");
451120256Sgshapiro							break;
452120256Sgshapiro						}
453120256Sgshapiro#endif /* _FFR_EXTRA_MAP_CHECK */
454120256Sgshapiro						break;
455120256Sgshapiro
456120256Sgshapiro					  case HOSTEND:
457120256Sgshapiro					  case LOOKUPEND:
458168515Sgshapiro						if ((ap[0][0] & 0377) != endtoken)
459120256Sgshapiro							break;
460120256Sgshapiro						inmap = false;
461120256Sgshapiro						endtoken = 0;
462120256Sgshapiro						break;
463120256Sgshapiro
464120256Sgshapiro
46590792Sgshapiro#if 0
46690792Sgshapiro/*
46790792Sgshapiro**  This doesn't work yet as there are maps defined *after* the cf
46890792Sgshapiro**  is read such as host, user, and alias.  So for now, it's removed.
46990792Sgshapiro**  When it comes back, the RELEASE_NOTES entry will be:
47090792Sgshapiro**	Emit warnings for unknown maps when reading the .cf file.  Based on
47190792Sgshapiro**		patch from Robert Harker of Harker Systems.
47290792Sgshapiro*/
47390792Sgshapiro
47490792Sgshapiro					  case LOOKUPBEGIN:
47590792Sgshapiro						/*
47690792Sgshapiro						**  Got a database lookup,
47790792Sgshapiro						**  check if map is defined.
47890792Sgshapiro						*/
47990792Sgshapiro
480168515Sgshapiro						ep = ap[1];
481168515Sgshapiro						if ((ep[0] & 0377) != MACRODEXPAND &&
482168515Sgshapiro						    stab(ep, ST_MAP, ST_FIND) == NULL)
48390792Sgshapiro						{
48490792Sgshapiro							(void) sm_io_fprintf(smioout,
48590792Sgshapiro									     SM_TIME_DEFAULT,
48690792Sgshapiro									     "Warning: %s: line %d: map %s not found\n",
48790792Sgshapiro									     FileName,
48890792Sgshapiro									     LineNumber,
48990792Sgshapiro									     ep);
49090792Sgshapiro						}
49190792Sgshapiro						break;
49290792Sgshapiro#endif /* 0 */
49338032Speter					}
49438032Speter					if (botch != NULL)
49538032Speter						syserr("Inappropriate use of %s on RHS",
49638032Speter							botch);
49738032Speter				}
498120256Sgshapiro				if (inmap)
499120256Sgshapiro					syserr("missing map closing token");
50038032Speter			}
50138032Speter			else
50238032Speter			{
50338032Speter				syserr("R line: null RHS");
50438032Speter				rwp->r_rhs = null_list;
50538032Speter			}
50638032Speter			break;
50738032Speter
50838032Speter		  case 'S':		/* select rewriting set */
509168515Sgshapiro			expand(&bp[1], exbuf, sizeof(exbuf), e);
51038032Speter			ruleset = strtorwset(exbuf, NULL, ST_ENTER);
51138032Speter			if (ruleset < 0)
51238032Speter				break;
51364562Sgshapiro
51438032Speter			rwp = RewriteRules[ruleset];
51538032Speter			if (rwp != NULL)
51638032Speter			{
517203004Sgshapiro				if (OpMode == MD_TEST || OpMode == MD_CHECKCONFIG)
51890792Sgshapiro					(void) sm_io_fprintf(smioout,
51990792Sgshapiro							     SM_TIME_DEFAULT,
52090792Sgshapiro							     "WARNING: Ruleset %s has multiple definitions\n",
52190792Sgshapiro							    &bp[1]);
52264562Sgshapiro				if (tTd(37, 1))
52390792Sgshapiro					sm_dprintf("WARNING: Ruleset %s has multiple definitions\n",
52490792Sgshapiro						   &bp[1]);
52538032Speter				while (rwp->r_next != NULL)
52638032Speter					rwp = rwp->r_next;
52738032Speter			}
52838032Speter			break;
52938032Speter
53038032Speter		  case 'D':		/* macro definition */
53190792Sgshapiro			mid = macid_parse(&bp[1], &ep);
53271345Sgshapiro			if (mid == 0)
53371345Sgshapiro				break;
53438032Speter			p = munchstring(ep, NULL, '\0');
53590792Sgshapiro			macdefine(&e->e_macro, A_TEMP, mid, p);
53638032Speter			break;
53738032Speter
53838032Speter		  case 'H':		/* required header line */
53964562Sgshapiro			(void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
54038032Speter			break;
54138032Speter
54238032Speter		  case 'C':		/* word class */
54338032Speter		  case 'T':		/* trusted user (set class `t') */
54438032Speter			if (bp[0] == 'C')
54538032Speter			{
54690792Sgshapiro				mid = macid_parse(&bp[1], &ep);
54771345Sgshapiro				if (mid == 0)
54871345Sgshapiro					break;
549168515Sgshapiro				expand(ep, exbuf, sizeof(exbuf), e);
55038032Speter				p = exbuf;
55138032Speter			}
55238032Speter			else
55338032Speter			{
55438032Speter				mid = 't';
55538032Speter				p = &bp[1];
55638032Speter			}
55738032Speter			while (*p != '\0')
55838032Speter			{
55938032Speter				register char *wd;
56038032Speter				char delim;
56138032Speter
562363466Sgshapiro				while (*p != '\0' && SM_ISSPACE(*p))
56338032Speter					p++;
56438032Speter				wd = p;
565363466Sgshapiro				while (*p != '\0' && !(SM_ISSPACE(*p)))
56638032Speter					p++;
56738032Speter				delim = *p;
56838032Speter				*p = '\0';
56938032Speter				if (wd[0] != '\0')
57038032Speter					setclass(mid, wd);
57138032Speter				*p = delim;
57238032Speter			}
57338032Speter			break;
57438032Speter
57538032Speter		  case 'F':		/* word class from file */
57690792Sgshapiro			mid = macid_parse(&bp[1], &ep);
57771345Sgshapiro			if (mid == 0)
57871345Sgshapiro				break;
579363466Sgshapiro			for (p = ep; SM_ISSPACE(*p); )
58038032Speter				p++;
58138032Speter			if (p[0] == '-' && p[1] == 'o')
58238032Speter			{
58390792Sgshapiro				optional = true;
58490792Sgshapiro				while (*p != '\0' &&
585363466Sgshapiro				       !(SM_ISSPACE(*p)))
58638032Speter					p++;
587363466Sgshapiro				while (SM_ISSPACE(*p))
58838032Speter					p++;
58938032Speter			}
59038032Speter			else
59190792Sgshapiro				optional = false;
59264562Sgshapiro
59394334Sgshapiro			/* check if [key]@map:spec */
59494334Sgshapiro			ismap = false;
59594334Sgshapiro			if (!SM_IS_DIR_DELIM(*p) &&
59694334Sgshapiro			    *p != '|' &&
59794334Sgshapiro			    (q = strchr(p, '@')) != NULL)
59890792Sgshapiro			{
59994334Sgshapiro				q++;
60094334Sgshapiro
60194334Sgshapiro				/* look for @LDAP or @map: in string */
60294334Sgshapiro				if (strcmp(q, "LDAP") == 0 ||
60394334Sgshapiro				    (*q != ':' &&
60494334Sgshapiro				     strchr(q, ':') != NULL))
60594334Sgshapiro					ismap = true;
60694334Sgshapiro			}
60794334Sgshapiro
60894334Sgshapiro			if (ismap)
60994334Sgshapiro			{
61090792Sgshapiro				/* use entire spec */
61190792Sgshapiro				file = p;
61290792Sgshapiro			}
61390792Sgshapiro			else
61490792Sgshapiro			{
61590792Sgshapiro				file = extrquotstr(p, &q, " ", &ok);
61690792Sgshapiro				if (!ok)
61790792Sgshapiro				{
61890792Sgshapiro					syserr("illegal filename '%s'", p);
61990792Sgshapiro					break;
62090792Sgshapiro				}
62190792Sgshapiro			}
62290792Sgshapiro
62394334Sgshapiro			if (*file == '|' || ismap)
62438032Speter				p = "%s";
62538032Speter			else
62638032Speter			{
62764562Sgshapiro				p = q;
62838032Speter				if (*p == '\0')
62938032Speter					p = "%s";
63038032Speter				else
63138032Speter				{
63238032Speter					*p = '\0';
63338032Speter					while (isascii(*++p) && isspace(*p))
63438032Speter						continue;
63538032Speter				}
63638032Speter			}
63794334Sgshapiro			fileclass(mid, file, p, ismap, safe, optional);
63838032Speter			break;
63938032Speter
64090792Sgshapiro#if XLA
64138032Speter		  case 'L':		/* extended load average description */
64238032Speter			xla_init(&bp[1]);
64338032Speter			break;
644363466Sgshapiro#endif
64538032Speter
64638032Speter#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
64738032Speter		  case 'L':		/* lookup macro */
64838032Speter		  case 'G':		/* lookup class */
64938032Speter			/* reserved for Sun -- NIS+ database lookup */
65038032Speter			if (VendorCode != VENDOR_SUN)
65138032Speter				goto badline;
65238032Speter			sun_lg_config_line(bp, e);
65338032Speter			break;
65464562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
65538032Speter
65638032Speter		  case 'M':		/* define mailer */
65738032Speter			makemailer(&bp[1]);
65838032Speter			break;
65938032Speter
66038032Speter		  case 'O':		/* set option */
66190792Sgshapiro			setoption(bp[1], &bp[2], safe, false, e);
66238032Speter			break;
66338032Speter
66438032Speter		  case 'P':		/* set precedence */
66538032Speter			if (NumPriorities >= MAXPRIORITIES)
66638032Speter			{
66738032Speter				toomany('P', MAXPRIORITIES);
66838032Speter				break;
66938032Speter			}
67038032Speter			for (p = &bp[1]; *p != '\0' && *p != '='; p++)
67138032Speter				continue;
67238032Speter			if (*p == '\0')
67338032Speter				goto badline;
67438032Speter			*p = '\0';
67538032Speter			Priorities[NumPriorities].pri_name = newstr(&bp[1]);
67638032Speter			Priorities[NumPriorities].pri_val = atoi(++p);
67738032Speter			NumPriorities++;
67838032Speter			break;
67938032Speter
68090792Sgshapiro		  case 'Q':		/* define queue */
68190792Sgshapiro			makequeue(&bp[1], true);
68290792Sgshapiro			break;
68390792Sgshapiro
68438032Speter		  case 'V':		/* configuration syntax version */
685363466Sgshapiro			for (p = &bp[1]; SM_ISSPACE(*p); p++)
68638032Speter				continue;
68738032Speter			if (!isascii(*p) || !isdigit(*p))
68838032Speter			{
68964562Sgshapiro				syserr("invalid argument to V line: \"%.20s\"",
69038032Speter					&bp[1]);
69138032Speter				break;
69238032Speter			}
69338032Speter			ConfigLevel = strtol(p, &ep, 10);
69438032Speter
69538032Speter			/*
69638032Speter			**  Do heuristic tweaking for back compatibility.
69738032Speter			*/
69838032Speter
69938032Speter			if (ConfigLevel >= 5)
70038032Speter			{
70138032Speter				/* level 5 configs have short name in $w */
70238032Speter				p = macvalue('w', e);
70338032Speter				if (p != NULL && (p = strchr(p, '.')) != NULL)
70490792Sgshapiro				{
70538032Speter					*p = '\0';
70690792Sgshapiro					macdefine(&e->e_macro, A_TEMP, 'w',
70790792Sgshapiro						  macvalue('w', e));
70890792Sgshapiro				}
70938032Speter			}
71038032Speter			if (ConfigLevel >= 6)
71138032Speter			{
71290792Sgshapiro				ColonOkInAddr = false;
71338032Speter			}
71438032Speter
71538032Speter			/*
71638032Speter			**  Look for vendor code.
71738032Speter			*/
71838032Speter
71938032Speter			if (*ep++ == '/')
72038032Speter			{
72138032Speter				/* extract vendor code */
72238032Speter				for (p = ep; isascii(*p) && isalpha(*p); )
72338032Speter					p++;
72438032Speter				*p = '\0';
72538032Speter
72638032Speter				if (!setvendor(ep))
72738032Speter					syserr("invalid V line vendor code: \"%s\"",
72838032Speter						ep);
72938032Speter			}
73038032Speter			break;
73138032Speter
73238032Speter		  case 'K':
733168515Sgshapiro			expand(&bp[1], exbuf, sizeof(exbuf), e);
73438032Speter			(void) makemapentry(exbuf);
73538032Speter			break;
73638032Speter
73738032Speter		  case 'E':
73838032Speter			p = strchr(bp, '=');
73938032Speter			if (p != NULL)
74038032Speter				*p++ = '\0';
741157001Sgshapiro			sm_setuserenv(&bp[1], p);
74238032Speter			break;
74338032Speter
74464562Sgshapiro		  case 'X':		/* mail filter */
74590792Sgshapiro#if MILTER
74664562Sgshapiro			milter_setup(&bp[1]);
74790792Sgshapiro#else /* MILTER */
74890792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
74990792Sgshapiro					     "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n");
75090792Sgshapiro#endif /* MILTER */
75164562Sgshapiro			break;
75264562Sgshapiro
75338032Speter		  default:
75438032Speter		  badline:
75538032Speter			syserr("unknown configuration line \"%s\"", bp);
75638032Speter		}
75738032Speter		if (bp != buf)
75890792Sgshapiro			sm_free(bp); /* XXX */
75938032Speter	}
76090792Sgshapiro	if (sm_io_error(cf))
76138032Speter	{
76238032Speter		syserr("I/O read error");
76390792Sgshapiro		finis(false, true, EX_OSFILE);
76438032Speter	}
76590792Sgshapiro	(void) sm_io_close(cf, SM_TIME_DEFAULT);
76638032Speter	FileName = NULL;
76738032Speter
768285229Sgshapiro#if _FFR_BOUNCE_QUEUE
769285229Sgshapiro	initbouncequeue();
770285229Sgshapiro#endif
771285229Sgshapiro
77238032Speter	/* initialize host maps from local service tables */
77338032Speter	inithostmaps();
77438032Speter
77564562Sgshapiro	/* initialize daemon (if not defined yet) */
77664562Sgshapiro	initdaemon();
77764562Sgshapiro
77838032Speter	/* determine if we need to do special name-server frotz */
77938032Speter	{
78038032Speter		int nmaps;
78138032Speter		char *maptype[MAXMAPSTACK];
78238032Speter		short mapreturn[MAXMAPACTIONS];
78338032Speter
78438032Speter		nmaps = switch_map_find("hosts", maptype, mapreturn);
78590792Sgshapiro		UseNameServer = false;
78638032Speter		if (nmaps > 0 && nmaps <= MAXMAPSTACK)
78738032Speter		{
78838032Speter			register int mapno;
78938032Speter
79090792Sgshapiro			for (mapno = 0; mapno < nmaps && !UseNameServer;
79190792Sgshapiro			     mapno++)
79238032Speter			{
79338032Speter				if (strcmp(maptype[mapno], "dns") == 0)
79490792Sgshapiro					UseNameServer = true;
79538032Speter			}
79638032Speter		}
79738032Speter	}
798285229Sgshapiro	setupdynmailers();
79938032Speter}
800168515Sgshapiro
80190792Sgshapiro/*
80238032Speter**  TRANSLATE_DOLLARS -- convert $x into internal form
80338032Speter**
80438032Speter**	Actually does all appropriate pre-processing of a config line
80538032Speter**	to turn it into internal form.
80638032Speter**
80738032Speter**	Parameters:
808168515Sgshapiro**		ibp -- the buffer to translate.
809168515Sgshapiro**		obp -- where to put the translation; may be the same as obp
810168515Sgshapiro**		bsp -- a pointer to the size of obp; will be updated if
811168515Sgshapiro**			the buffer needs to be replaced.
81238032Speter**
81338032Speter**	Returns:
814168515Sgshapiro**		The buffer pointer; may differ from obp if the expansion
815168515Sgshapiro**		is larger then *bsp, in which case this will point to
816168515Sgshapiro**		malloc()ed memory which must be free()d by the caller.
81738032Speter*/
81838032Speter
819168515Sgshapirochar *
820168515Sgshapirotranslate_dollars(ibp, obp, bsp)
821168515Sgshapiro	char *ibp;
822168515Sgshapiro	char *obp;
823168515Sgshapiro	int *bsp;
82438032Speter{
82538032Speter	register char *p;
82638032Speter	auto char *ep;
827168515Sgshapiro	char *bp;
82838032Speter
829168515Sgshapiro	if (tTd(37, 53))
830168515Sgshapiro	{
831168515Sgshapiro		sm_dprintf("translate_dollars(");
832168515Sgshapiro		xputs(sm_debug_file(), ibp);
833168515Sgshapiro		sm_dprintf(")\n");
834168515Sgshapiro	}
835168515Sgshapiro
836168515Sgshapiro	bp = quote_internal_chars(ibp, obp, bsp);
837168515Sgshapiro
83838032Speter	for (p = bp; *p != '\0'; p++)
83938032Speter	{
84038032Speter		if (*p == '#' && p > bp && ConfigLevel >= 3)
84138032Speter		{
84238032Speter			register char *e;
84338032Speter
84438032Speter			switch (*--p & 0377)
84538032Speter			{
84638032Speter			  case MACROEXPAND:
84738032Speter				/* it's from $# -- let it go through */
84838032Speter				p++;
84938032Speter				break;
85038032Speter
85138032Speter			  case '\\':
85238032Speter				/* it's backslash escaped */
85390792Sgshapiro				(void) sm_strlcpy(p, p + 1, strlen(p));
85438032Speter				break;
85538032Speter
85638032Speter			  default:
85764562Sgshapiro				/* delete leading white space */
858363466Sgshapiro				while (SM_ISSPACE(*p) &&
85938032Speter				       *p != '\n' && p > bp)
860168515Sgshapiro				{
86138032Speter					p--;
862168515Sgshapiro				}
86338032Speter				if ((e = strchr(++p, '\n')) != NULL)
86490792Sgshapiro					(void) sm_strlcpy(p, e, strlen(p));
86538032Speter				else
86638032Speter					*p-- = '\0';
86738032Speter				break;
86838032Speter			}
86938032Speter			continue;
87038032Speter		}
87138032Speter
87238032Speter		if (*p != '$' || p[1] == '\0')
87338032Speter			continue;
87438032Speter
87538032Speter		if (p[1] == '$')
87638032Speter		{
87738032Speter			/* actual dollar sign.... */
87890792Sgshapiro			(void) sm_strlcpy(p, p + 1, strlen(p));
87938032Speter			continue;
88038032Speter		}
88138032Speter
88238032Speter		/* convert to macro expansion character */
88338032Speter		*p++ = MACROEXPAND;
88438032Speter
88538032Speter		/* special handling for $=, $~, $&, and $? */
88638032Speter		if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
88738032Speter			p++;
88838032Speter
88938032Speter		/* convert macro name to code */
89090792Sgshapiro		*p = macid_parse(p, &ep);
89164562Sgshapiro		if (ep != p + 1)
89290792Sgshapiro			(void) sm_strlcpy(p + 1, ep, strlen(p + 1));
89338032Speter	}
89438032Speter
89538032Speter	/* strip trailing white space from the line */
896363466Sgshapiro	while (--p > bp && SM_ISSPACE(*p))
89738032Speter		*p = '\0';
898168515Sgshapiro
899168515Sgshapiro	if (tTd(37, 53))
900168515Sgshapiro	{
901168515Sgshapiro		sm_dprintf("  translate_dollars => ");
902168515Sgshapiro		xputs(sm_debug_file(), bp);
903168515Sgshapiro		sm_dprintf("\n");
904168515Sgshapiro	}
905168515Sgshapiro
906168515Sgshapiro	return bp;
90738032Speter}
90890792Sgshapiro/*
90938032Speter**  TOOMANY -- signal too many of some option
91038032Speter**
91138032Speter**	Parameters:
91238032Speter**		id -- the id of the error line
91338032Speter**		maxcnt -- the maximum possible values
91438032Speter**
91538032Speter**	Returns:
91638032Speter**		none.
91738032Speter**
91838032Speter**	Side Effects:
91938032Speter**		gives a syserr.
92038032Speter*/
92138032Speter
92264562Sgshapirostatic void
92338032Spetertoomany(id, maxcnt)
92438032Speter	int id;
92538032Speter	int maxcnt;
92638032Speter{
92738032Speter	syserr("too many %c lines, %d max", id, maxcnt);
92838032Speter}
92990792Sgshapiro/*
93038032Speter**  FILECLASS -- read members of a class from a file
93138032Speter**
93238032Speter**	Parameters:
93338032Speter**		class -- class to define.
93438032Speter**		filename -- name of file to read.
93538032Speter**		fmt -- scanf string to use for match.
93694334Sgshapiro**		ismap -- if set, this is a map lookup.
93738032Speter**		safe -- if set, this is a safe read.
93838032Speter**		optional -- if set, it is not an error for the file to
93938032Speter**			not exist.
94038032Speter**
94138032Speter**	Returns:
94238032Speter**		none
94338032Speter**
94438032Speter**	Side Effects:
94538032Speter**		puts all lines in filename that match a scanf into
94638032Speter**			the named class.
94738032Speter*/
94838032Speter
94990792Sgshapiro/*
95090792Sgshapiro**  Break up the match into words and add to class.
95190792Sgshapiro*/
95290792Sgshapiro
95364562Sgshapirostatic void
95490792Sgshapiroparse_class_words(class, line)
95590792Sgshapiro	int class;
95690792Sgshapiro	char *line;
95790792Sgshapiro{
95890792Sgshapiro	while (line != NULL && *line != '\0')
95990792Sgshapiro	{
96090792Sgshapiro		register char *q;
96190792Sgshapiro
96290792Sgshapiro		/* strip leading spaces */
963363466Sgshapiro		while (SM_ISSPACE(*line))
96490792Sgshapiro			line++;
96590792Sgshapiro		if (*line == '\0')
96690792Sgshapiro			break;
96790792Sgshapiro
96890792Sgshapiro		/* find the end of the word */
96990792Sgshapiro		q = line;
970363466Sgshapiro		while (*line != '\0' && !(SM_ISSPACE(*line)))
97190792Sgshapiro			line++;
97290792Sgshapiro		if (*line != '\0')
97390792Sgshapiro			*line++ = '\0';
97490792Sgshapiro
97590792Sgshapiro		/* enter the word in the symbol table */
97690792Sgshapiro		setclass(class, q);
97790792Sgshapiro	}
97890792Sgshapiro}
97990792Sgshapiro
98090792Sgshapirostatic void
98194334Sgshapirofileclass(class, filename, fmt, ismap, safe, optional)
98238032Speter	int class;
98338032Speter	char *filename;
98438032Speter	char *fmt;
98594334Sgshapiro	bool ismap;
98638032Speter	bool safe;
98738032Speter	bool optional;
98838032Speter{
98990792Sgshapiro	SM_FILE_T *f;
99064562Sgshapiro	long sff;
99138032Speter	pid_t pid;
99238032Speter	register char *p;
99338032Speter	char buf[MAXLINE];
99438032Speter
99538032Speter	if (tTd(37, 2))
99690792Sgshapiro		sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
99738032Speter
99890792Sgshapiro	if (*filename == '\0')
99938032Speter	{
100090792Sgshapiro		syserr("fileclass: missing file name");
100190792Sgshapiro		return;
100290792Sgshapiro	}
100394334Sgshapiro	else if (ismap)
100490792Sgshapiro	{
100590792Sgshapiro		int status = 0;
100690792Sgshapiro		char *key;
100790792Sgshapiro		char *mn;
100890792Sgshapiro		char *cl, *spec;
100990792Sgshapiro		STAB *mapclass;
101090792Sgshapiro		MAP map;
101190792Sgshapiro
101290792Sgshapiro		mn = newstr(macname(class));
101390792Sgshapiro
101490792Sgshapiro		key = filename;
101590792Sgshapiro
101694334Sgshapiro		/* skip past key */
101794334Sgshapiro		if ((p = strchr(filename, '@')) == NULL)
101894334Sgshapiro		{
101994334Sgshapiro			/* should not happen */
102094334Sgshapiro			syserr("fileclass: bogus map specification");
102194334Sgshapiro			sm_free(mn);
102294334Sgshapiro			return;
102394334Sgshapiro		}
102494334Sgshapiro
102590792Sgshapiro		/* skip past '@' */
102690792Sgshapiro		*p++ = '\0';
102790792Sgshapiro		cl = p;
102890792Sgshapiro
1029120256Sgshapiro#if LDAPMAP
103090792Sgshapiro		if (strcmp(cl, "LDAP") == 0)
103190792Sgshapiro		{
103290792Sgshapiro			int n;
103390792Sgshapiro			char *lc;
103490792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
103590792Sgshapiro			char lcbuf[MAXLINE];
103690792Sgshapiro
103790792Sgshapiro			/* Get $j */
1038168515Sgshapiro			expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
103990792Sgshapiro			if (jbuf[0] == '\0')
104090792Sgshapiro			{
104190792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
1042168515Sgshapiro						  sizeof(jbuf));
104390792Sgshapiro			}
104490792Sgshapiro
104590792Sgshapiro			/* impose the default schema */
104690792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
104790792Sgshapiro			if (lc == NULL)
104890792Sgshapiro				lc = "";
104990792Sgshapiro			else
105090792Sgshapiro			{
1051168515Sgshapiro				expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
105290792Sgshapiro				lc = lcbuf;
105390792Sgshapiro			}
105490792Sgshapiro
105590792Sgshapiro			cl = "ldap";
1056168515Sgshapiro			n = sm_snprintf(buf, sizeof(buf),
1057132943Sgshapiro					"-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass",
105890792Sgshapiro					mn, lc, jbuf);
1059168515Sgshapiro			if (n >= sizeof(buf))
106090792Sgshapiro			{
106190792Sgshapiro				syserr("fileclass: F{%s}: Default LDAP string too long",
106290792Sgshapiro				       mn);
106390792Sgshapiro				sm_free(mn);
106490792Sgshapiro				return;
106590792Sgshapiro			}
106690792Sgshapiro			spec = buf;
106790792Sgshapiro		}
106890792Sgshapiro		else
1069120256Sgshapiro#endif /* LDAPMAP */
107090792Sgshapiro		{
107190792Sgshapiro			if ((spec = strchr(cl, ':')) == NULL)
107290792Sgshapiro			{
107390792Sgshapiro				syserr("fileclass: F{%s}: missing map class",
107490792Sgshapiro				       mn);
107590792Sgshapiro				sm_free(mn);
107690792Sgshapiro				return;
107790792Sgshapiro			}
107890792Sgshapiro			*spec++ ='\0';
107990792Sgshapiro		}
108090792Sgshapiro
108190792Sgshapiro		/* set up map structure */
108290792Sgshapiro		mapclass = stab(cl, ST_MAPCLASS, ST_FIND);
108390792Sgshapiro		if (mapclass == NULL)
108490792Sgshapiro		{
108590792Sgshapiro			syserr("fileclass: F{%s}: class %s not available",
108690792Sgshapiro			       mn, cl);
108790792Sgshapiro			sm_free(mn);
108890792Sgshapiro			return;
108990792Sgshapiro		}
1090168515Sgshapiro		memset(&map, '\0', sizeof(map));
109190792Sgshapiro		map.map_class = &mapclass->s_mapclass;
109290792Sgshapiro		map.map_mname = mn;
109390792Sgshapiro		map.map_mflags |= MF_FILECLASS;
109490792Sgshapiro
109594334Sgshapiro		if (tTd(37, 5))
109694334Sgshapiro			sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
109794334Sgshapiro				   mn, cl, key, spec);
109894334Sgshapiro
109994334Sgshapiro
110090792Sgshapiro		/* parse map spec */
110190792Sgshapiro		if (!map.map_class->map_parse(&map, spec))
110290792Sgshapiro		{
110390792Sgshapiro			/* map_parse() showed the error already */
110490792Sgshapiro			sm_free(mn);
110590792Sgshapiro			return;
110690792Sgshapiro		}
110790792Sgshapiro		map.map_mflags |= MF_VALID;
110890792Sgshapiro
110990792Sgshapiro		/* open map */
111090792Sgshapiro		if (map.map_class->map_open(&map, O_RDONLY))
111190792Sgshapiro		{
111290792Sgshapiro			map.map_mflags |= MF_OPEN;
111390792Sgshapiro			map.map_pid = getpid();
111490792Sgshapiro		}
111590792Sgshapiro		else
111690792Sgshapiro		{
111790792Sgshapiro			if (!optional &&
111890792Sgshapiro			    !bitset(MF_OPTIONAL, map.map_mflags))
111990792Sgshapiro				syserr("fileclass: F{%s}: map open failed",
112090792Sgshapiro				       mn);
112190792Sgshapiro			sm_free(mn);
112290792Sgshapiro			return;
112390792Sgshapiro		}
112490792Sgshapiro
112590792Sgshapiro		/* lookup */
112690792Sgshapiro		p = (*map.map_class->map_lookup)(&map, key, NULL, &status);
112790792Sgshapiro		if (status != EX_OK && status != EX_NOTFOUND)
112890792Sgshapiro		{
112990792Sgshapiro			if (!optional)
113090792Sgshapiro				syserr("fileclass: F{%s}: map lookup failed",
113190792Sgshapiro				       mn);
113290792Sgshapiro			p = NULL;
113390792Sgshapiro		}
113490792Sgshapiro
113590792Sgshapiro		/* use the results */
113690792Sgshapiro		if (p != NULL)
113790792Sgshapiro			parse_class_words(class, p);
113890792Sgshapiro
113990792Sgshapiro		/* close map */
114090792Sgshapiro		map.map_mflags |= MF_CLOSING;
114190792Sgshapiro		map.map_class->map_close(&map);
114290792Sgshapiro		map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
114390792Sgshapiro		sm_free(mn);
114490792Sgshapiro		return;
114590792Sgshapiro	}
114690792Sgshapiro	else if (filename[0] == '|')
114790792Sgshapiro	{
114838032Speter		auto int fd;
114938032Speter		int i;
115038032Speter		char *argv[MAXPV + 1];
115138032Speter
115238032Speter		i = 0;
115390792Sgshapiro		for (p = strtok(&filename[1], " \t");
115490792Sgshapiro		     p != NULL && i < MAXPV;
115590792Sgshapiro		     p = strtok(NULL, " \t"))
115638032Speter			argv[i++] = p;
115738032Speter		argv[i] = NULL;
115838032Speter		pid = prog_open(argv, &fd, CurEnv);
115938032Speter		if (pid < 0)
116038032Speter			f = NULL;
116138032Speter		else
116290792Sgshapiro			f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
116390792Sgshapiro				       (void *) &fd, SM_IO_RDONLY, NULL);
116438032Speter	}
116538032Speter	else
116638032Speter	{
116738032Speter		pid = -1;
116838032Speter		sff = SFF_REGONLY;
116964562Sgshapiro		if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
117038032Speter			sff |= SFF_SAFEDIRPATH;
117164562Sgshapiro		if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
117264562Sgshapiro			     DontBlameSendmail))
117338032Speter			sff |= SFF_NOWLINK;
117438032Speter		if (safe)
117538032Speter			sff |= SFF_OPENASROOT;
117690792Sgshapiro		else if (RealUid == 0)
117790792Sgshapiro			sff |= SFF_ROOTOK;
117838032Speter		if (DontLockReadFiles)
117938032Speter			sff |= SFF_NOLOCK;
118038032Speter		f = safefopen(filename, O_RDONLY, 0, sff);
118138032Speter	}
118238032Speter	if (f == NULL)
118338032Speter	{
118438032Speter		if (!optional)
118564562Sgshapiro			syserr("fileclass: cannot open '%s'", filename);
118638032Speter		return;
118738032Speter	}
118838032Speter
1189249729Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
119038032Speter	{
119164562Sgshapiro#if SCANF
119238032Speter		char wordbuf[MAXLINE + 1];
1193363466Sgshapiro#endif
119438032Speter
119538032Speter		if (buf[0] == '#')
119638032Speter			continue;
119764562Sgshapiro#if SCANF
119890792Sgshapiro		if (sm_io_sscanf(buf, fmt, wordbuf) != 1)
119938032Speter			continue;
120038032Speter		p = wordbuf;
120164562Sgshapiro#else /* SCANF */
120238032Speter		p = buf;
120364562Sgshapiro#endif /* SCANF */
120438032Speter
120590792Sgshapiro		parse_class_words(class, p);
120690792Sgshapiro
120738032Speter		/*
120890792Sgshapiro		**  If anything else is added here,
120990792Sgshapiro		**  check if the '@' map case above
121090792Sgshapiro		**  needs the code as well.
121138032Speter		*/
121238032Speter	}
121338032Speter
121490792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
121538032Speter	if (pid > 0)
121638032Speter		(void) waitfor(pid);
121738032Speter}
1218285229Sgshapiro
1219285229Sgshapiro#if _FFR_RCPTFLAGS
1220285229Sgshapiro/* first character for dynamically created mailers */
1221285229Sgshapirostatic char dynmailerp = ' ';
1222285229Sgshapiro
1223285229Sgshapiro/* list of first characters for cf defined mailers */
1224285229Sgshapirostatic char frst[MAXMAILERS + 1];
1225285229Sgshapiro
122690792Sgshapiro/*
1227285229Sgshapiro**  SETUPDYNMAILERS -- find a char that isn't used as first element of any
1228285229Sgshapiro**		mailer name.
1229285229Sgshapiro**
1230285229Sgshapiro**	Parameters:
1231285229Sgshapiro**		none
1232285229Sgshapiro**
1233285229Sgshapiro**	Returns:
1234285229Sgshapiro**		none
1235363466Sgshapiro**
1236285229Sgshapiro**	Note: space is not valid in cf defined mailers hence the function
1237285229Sgshapiro**		will always find a char. It's not nice, but this is for
1238285229Sgshapiro**		internal names only.
1239285229Sgshapiro*/
1240285229Sgshapiro
1241285229Sgshapirovoid
1242285229Sgshapirosetupdynmailers()
1243285229Sgshapiro{
1244285229Sgshapiro	int i;
1245285229Sgshapiro	char pp[] = "YXZ0123456789ABCDEFGHIJKLMNOPQRSTUVWyxzabcfghijkmnoqtuvw ";
1246285229Sgshapiro
1247285229Sgshapiro	frst[MAXMAILERS] = '\0';
1248285229Sgshapiro	for (i = 0; i < strlen(pp); i++)
1249285229Sgshapiro	{
1250285229Sgshapiro		if (strchr(frst, pp[i]) == NULL)
1251285229Sgshapiro		{
1252285229Sgshapiro			dynmailerp = pp[i];
1253285229Sgshapiro			if (tTd(25, 8))
1254285229Sgshapiro				sm_dprintf("dynmailerp=%c\n", dynmailerp);
1255285229Sgshapiro			return;
1256285229Sgshapiro		}
1257285229Sgshapiro	}
1258285229Sgshapiro
1259285229Sgshapiro	/* NOTREACHED */
1260285229Sgshapiro	SM_ASSERT(0);
1261285229Sgshapiro}
1262285229Sgshapiro
1263285229Sgshapiro/*
1264285229Sgshapiro**  NEWMODMAILER -- Create a new mailer with modifications
1265285229Sgshapiro**
1266285229Sgshapiro**	Parameters:
1267285229Sgshapiro**		rcpt -- current RCPT
1268285229Sgshapiro**		fl -- flag to set
1269285229Sgshapiro**
1270285229Sgshapiro**	Returns:
1271285229Sgshapiro**		true iff successful.
1272285229Sgshapiro**
1273285229Sgshapiro**	Note: this creates a copy of the mailer for the rcpt and
1274285229Sgshapiro**		modifies exactly one flag.  It does not work
1275285229Sgshapiro**		for multiple flags!
1276285229Sgshapiro*/
1277285229Sgshapiro
1278285229Sgshapirobool
1279285229Sgshapironewmodmailer(rcpt, fl)
1280285229Sgshapiro	ADDRESS *rcpt;
1281285229Sgshapiro	int fl;
1282285229Sgshapiro{
1283285229Sgshapiro	int idx;
1284285229Sgshapiro	struct mailer *m;
1285285229Sgshapiro	STAB *s;
1286285229Sgshapiro	char mname[256];
1287285229Sgshapiro
1288285229Sgshapiro	SM_REQUIRE(rcpt != NULL);
1289285229Sgshapiro	if (rcpt->q_mailer == NULL)
1290285229Sgshapiro		return false;
1291285229Sgshapiro	if (tTd(25, 8))
1292285229Sgshapiro		sm_dprintf("newmodmailer: rcpt=%s\n", rcpt->q_paddr);
1293285229Sgshapiro	SM_REQUIRE(rcpt->q_mailer->m_name != NULL);
1294285229Sgshapiro	SM_REQUIRE(rcpt->q_mailer->m_name[0] != '\0');
1295285229Sgshapiro	sm_strlcpy(mname, rcpt->q_mailer->m_name, sizeof(mname));
1296285229Sgshapiro	mname[0] = dynmailerp;
1297285229Sgshapiro	if (tTd(25, 8))
1298285229Sgshapiro		sm_dprintf("newmodmailer: name=%s\n", mname);
1299285229Sgshapiro	s = stab(mname, ST_MAILER, ST_ENTER);
1300285229Sgshapiro	if (s->s_mailer != NULL)
1301285229Sgshapiro	{
1302285229Sgshapiro		idx = s->s_mailer->m_mno;
1303285229Sgshapiro		if (tTd(25, 6))
1304285229Sgshapiro			sm_dprintf("newmodmailer: found idx=%d\n", idx);
1305285229Sgshapiro	}
1306285229Sgshapiro	else
1307285229Sgshapiro	{
1308285229Sgshapiro		idx = rcpt->q_mailer->m_mno;
1309285229Sgshapiro		idx += MAXMAILERS;
1310285229Sgshapiro		if (tTd(25, 6))
1311285229Sgshapiro			sm_dprintf("newmodmailer: idx=%d\n", idx);
1312285229Sgshapiro		if (idx > SM_ARRAY_SIZE(Mailer))
1313285229Sgshapiro			return false;
1314285229Sgshapiro	}
1315285229Sgshapiro
1316285229Sgshapiro	m = Mailer[idx];
1317285229Sgshapiro	if (m == NULL)
1318285229Sgshapiro		m = (struct mailer *) xalloc(sizeof(*m));
1319285229Sgshapiro	memset((char *) m, '\0', sizeof(*m));
1320285229Sgshapiro	STRUCTCOPY(*rcpt->q_mailer, *m);
1321285229Sgshapiro	Mailer[idx] = m;
1322285229Sgshapiro
1323285229Sgshapiro	/* "modify" the mailer */
1324285229Sgshapiro	setbitn(bitidx(fl), m->m_flags);
1325285229Sgshapiro	rcpt->q_mailer = m;
1326285229Sgshapiro	m->m_mno = idx;
1327285229Sgshapiro	m->m_name = newstr(mname);
1328285229Sgshapiro	if (tTd(25, 1))
1329285229Sgshapiro		sm_dprintf("newmodmailer: mailer[%d]=%s %p\n",
1330285229Sgshapiro			idx, Mailer[idx]->m_name, Mailer[idx]);
1331285229Sgshapiro
1332285229Sgshapiro	return true;
1333285229Sgshapiro}
1334285229Sgshapiro
1335285229Sgshapiro#endif /* _FFR_RCPTFLAGS */
1336285229Sgshapiro
1337285229Sgshapiro/*
133838032Speter**  MAKEMAILER -- define a new mailer.
133938032Speter**
134038032Speter**	Parameters:
134138032Speter**		line -- description of mailer.  This is in labeled
134238032Speter**			fields.  The fields are:
134338032Speter**			   A -- the argv for this mailer
134438032Speter**			   C -- the character set for MIME conversions
134538032Speter**			   D -- the directory to run in
134638032Speter**			   E -- the eol string
134738032Speter**			   F -- the flags associated with the mailer
134838032Speter**			   L -- the maximum line length
134938032Speter**			   M -- the maximum message size
135038032Speter**			   N -- the niceness at which to run
135138032Speter**			   P -- the path to the mailer
135290792Sgshapiro**			   Q -- the queue group for the mailer
135338032Speter**			   R -- the recipient rewriting set
135438032Speter**			   S -- the sender rewriting set
135538032Speter**			   T -- the mailer type (for DSNs)
135638032Speter**			   U -- the uid to run as
135764562Sgshapiro**			   W -- the time to wait at the end
135873188Sgshapiro**			   m -- maximum messages per connection
135990792Sgshapiro**			   r -- maximum number of recipients per message
136073188Sgshapiro**			   / -- new root directory
136138032Speter**			The first word is the canonical name of the mailer.
136238032Speter**
136338032Speter**	Returns:
136438032Speter**		none.
136538032Speter**
136638032Speter**	Side Effects:
136738032Speter**		enters the mailer into the mailer table.
136838032Speter*/
136938032Speter
1370285229Sgshapiro
137138032Spetervoid
137238032Spetermakemailer(line)
137338032Speter	char *line;
137438032Speter{
137538032Speter	register char *p;
137638032Speter	register struct mailer *m;
137738032Speter	register STAB *s;
137838032Speter	int i;
137938032Speter	char fcode;
138038032Speter	auto char *endp;
138190792Sgshapiro	static int nextmailer = 0;	/* "free" index into Mailer struct */
138238032Speter
138338032Speter	/* allocate a mailer and set up defaults */
1384168515Sgshapiro	m = (struct mailer *) xalloc(sizeof(*m));
1385168515Sgshapiro	memset((char *) m, '\0', sizeof(*m));
138690792Sgshapiro	errno = 0; /* avoid bogus error text */
138738032Speter
138838032Speter	/* collect the mailer name */
138990792Sgshapiro	for (p = line;
1390363466Sgshapiro	     *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
139190792Sgshapiro	     p++)
139238032Speter		continue;
139338032Speter	if (*p != '\0')
139438032Speter		*p++ = '\0';
139538032Speter	if (line[0] == '\0')
139671345Sgshapiro	{
139738032Speter		syserr("name required for mailer");
139871345Sgshapiro		return;
139971345Sgshapiro	}
140038032Speter	m->m_name = newstr(line);
1401285229Sgshapiro#if _FFR_RCPTFLAGS
1402285229Sgshapiro	frst[nextmailer] = line[0];
1403285229Sgshapiro#endif
140494334Sgshapiro	m->m_qgrp = NOQGRP;
1405132943Sgshapiro	m->m_uid = NO_UID;
1406132943Sgshapiro	m->m_gid = NO_GID;
140738032Speter
140838032Speter	/* now scan through and assign info from the fields */
140938032Speter	while (*p != '\0')
141038032Speter	{
141138032Speter		auto char *delimptr;
141238032Speter
141390792Sgshapiro		while (*p != '\0' &&
1414363466Sgshapiro		       (*p == ',' || (SM_ISSPACE(*p))))
141538032Speter			p++;
141638032Speter
141738032Speter		/* p now points to field code */
141838032Speter		fcode = *p;
141938032Speter		while (*p != '\0' && *p != '=' && *p != ',')
142038032Speter			p++;
142138032Speter		if (*p++ != '=')
142238032Speter		{
142338032Speter			syserr("mailer %s: `=' expected", m->m_name);
142438032Speter			return;
142538032Speter		}
1426363466Sgshapiro		while (SM_ISSPACE(*p))
142738032Speter			p++;
142838032Speter
142938032Speter		/* p now points to the field body */
143038032Speter		p = munchstring(p, &delimptr, ',');
143138032Speter
143238032Speter		/* install the field into the mailer struct */
143338032Speter		switch (fcode)
143438032Speter		{
143538032Speter		  case 'P':		/* pathname */
143690792Sgshapiro			if (*p != '\0')	/* error is issued below */
143771345Sgshapiro				m->m_mailer = newstr(p);
143838032Speter			break;
143938032Speter
144038032Speter		  case 'F':		/* flags */
144138032Speter			for (; *p != '\0'; p++)
144290792Sgshapiro			{
1443363466Sgshapiro				if (!(SM_ISSPACE(*p)))
144490792Sgshapiro				{
144590792Sgshapiro					if (*p == M_INTERNAL)
144690792Sgshapiro						sm_syslog(LOG_WARNING, NOQID,
144790792Sgshapiro							  "WARNING: mailer=%s, flag=%c deprecated",
144890792Sgshapiro							  m->m_name, *p);
144971345Sgshapiro					setbitn(bitidx(*p), m->m_flags);
145090792Sgshapiro				}
145190792Sgshapiro			}
145238032Speter			break;
145338032Speter
145438032Speter		  case 'S':		/* sender rewriting ruleset */
145538032Speter		  case 'R':		/* recipient rewriting ruleset */
145638032Speter			i = strtorwset(p, &endp, ST_ENTER);
145738032Speter			if (i < 0)
145838032Speter				return;
145938032Speter			if (fcode == 'S')
146038032Speter				m->m_sh_rwset = m->m_se_rwset = i;
146138032Speter			else
146238032Speter				m->m_rh_rwset = m->m_re_rwset = i;
146338032Speter
146438032Speter			p = endp;
146538032Speter			if (*p++ == '/')
146638032Speter			{
146738032Speter				i = strtorwset(p, NULL, ST_ENTER);
146838032Speter				if (i < 0)
146938032Speter					return;
147038032Speter				if (fcode == 'S')
147138032Speter					m->m_sh_rwset = i;
147238032Speter				else
147338032Speter					m->m_rh_rwset = i;
147438032Speter			}
147538032Speter			break;
147638032Speter
147738032Speter		  case 'E':		/* end of line string */
147838032Speter			if (*p == '\0')
147938032Speter				syserr("mailer %s: null end-of-line string",
148038032Speter					m->m_name);
148171345Sgshapiro			else
148271345Sgshapiro				m->m_eol = newstr(p);
148338032Speter			break;
148438032Speter
148538032Speter		  case 'A':		/* argument vector */
148690792Sgshapiro			if (*p != '\0')	/* error is issued below */
148771345Sgshapiro				m->m_argv = makeargv(p);
148838032Speter			break;
148938032Speter
149038032Speter		  case 'M':		/* maximum message size */
149138032Speter			m->m_maxsize = atol(p);
149238032Speter			break;
149338032Speter
149464562Sgshapiro		  case 'm':		/* maximum messages per connection */
149564562Sgshapiro			m->m_maxdeliveries = atoi(p);
149664562Sgshapiro			break;
149764562Sgshapiro
149864562Sgshapiro		  case 'r':		/* max recipient per envelope */
149964562Sgshapiro			m->m_maxrcpt = atoi(p);
150064562Sgshapiro			break;
150164562Sgshapiro
150238032Speter		  case 'L':		/* maximum line length */
150338032Speter			m->m_linelimit = atoi(p);
150438032Speter			if (m->m_linelimit < 0)
150538032Speter				m->m_linelimit = 0;
150638032Speter			break;
150738032Speter
150838032Speter		  case 'N':		/* run niceness */
150938032Speter			m->m_nice = atoi(p);
151038032Speter			break;
151138032Speter
151238032Speter		  case 'D':		/* working directory */
151338032Speter			if (*p == '\0')
151438032Speter				syserr("mailer %s: null working directory",
151538032Speter					m->m_name);
151671345Sgshapiro			else
151771345Sgshapiro				m->m_execdir = newstr(p);
151838032Speter			break;
151938032Speter
152038032Speter		  case 'C':		/* default charset */
152138032Speter			if (*p == '\0')
152238032Speter				syserr("mailer %s: null charset", m->m_name);
152371345Sgshapiro			else
152471345Sgshapiro				m->m_defcharset = newstr(p);
152538032Speter			break;
152638032Speter
152790792Sgshapiro		  case 'Q':		/* queue for this mailer */
152890792Sgshapiro			if (*p == '\0')
152990792Sgshapiro			{
153090792Sgshapiro				syserr("mailer %s: null queue", m->m_name);
153190792Sgshapiro				break;
153290792Sgshapiro			}
153390792Sgshapiro			s = stab(p, ST_QUEUE, ST_FIND);
153490792Sgshapiro			if (s == NULL)
153590792Sgshapiro				syserr("mailer %s: unknown queue %s",
153690792Sgshapiro					m->m_name, p);
153790792Sgshapiro			else
153890792Sgshapiro				m->m_qgrp = s->s_quegrp->qg_index;
153990792Sgshapiro			break;
154090792Sgshapiro
154138032Speter		  case 'T':		/* MTA-Name/Address/Diagnostic types */
154238032Speter			/* extract MTA name type; default to "dns" */
154338032Speter			m->m_mtatype = newstr(p);
154438032Speter			p = strchr(m->m_mtatype, '/');
154538032Speter			if (p != NULL)
154638032Speter			{
154738032Speter				*p++ = '\0';
154838032Speter				if (*p == '\0')
154938032Speter					p = NULL;
155038032Speter			}
155138032Speter			if (*m->m_mtatype == '\0')
155238032Speter				m->m_mtatype = "dns";
155338032Speter
155438032Speter			/* extract address type; default to "rfc822" */
155538032Speter			m->m_addrtype = p;
155638032Speter			if (p != NULL)
155738032Speter				p = strchr(p, '/');
155838032Speter			if (p != NULL)
155938032Speter			{
156038032Speter				*p++ = '\0';
156138032Speter				if (*p == '\0')
156238032Speter					p = NULL;
156338032Speter			}
156438032Speter			if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
156538032Speter				m->m_addrtype = "rfc822";
156638032Speter
156738032Speter			/* extract diagnostic type; default to "smtp" */
156838032Speter			m->m_diagtype = p;
156938032Speter			if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
157038032Speter				m->m_diagtype = "smtp";
157138032Speter			break;
157238032Speter
157338032Speter		  case 'U':		/* user id */
157438032Speter			if (isascii(*p) && !isdigit(*p))
157538032Speter			{
157638032Speter				char *q = p;
157738032Speter				struct passwd *pw;
157838032Speter
157938032Speter				while (*p != '\0' && isascii(*p) &&
1580285229Sgshapiro# if _FFR_DOTTED_USERNAMES
1581285229Sgshapiro				       (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
1582363466Sgshapiro# else
158338032Speter				       (isalnum(*p) || strchr("-_", *p) != NULL))
1584363466Sgshapiro# endif
158538032Speter					p++;
1586363466Sgshapiro				while (SM_ISSPACE(*p))
158738032Speter					*p++ = '\0';
158838032Speter				if (*p != '\0')
158938032Speter					*p++ = '\0';
159038032Speter				if (*q == '\0')
159171345Sgshapiro				{
159238032Speter					syserr("mailer %s: null user name",
159338032Speter						m->m_name);
159471345Sgshapiro					break;
159571345Sgshapiro				}
159638032Speter				pw = sm_getpwnam(q);
159738032Speter				if (pw == NULL)
159871345Sgshapiro				{
159938032Speter					syserr("readcf: mailer U= flag: unknown user %s", q);
160071345Sgshapiro					break;
160171345Sgshapiro				}
160238032Speter				else
160338032Speter				{
160438032Speter					m->m_uid = pw->pw_uid;
160538032Speter					m->m_gid = pw->pw_gid;
160638032Speter				}
160738032Speter			}
160838032Speter			else
160938032Speter			{
161038032Speter				auto char *q;
161138032Speter
161238032Speter				m->m_uid = strtol(p, &q, 0);
161338032Speter				p = q;
1614363466Sgshapiro				while (SM_ISSPACE(*p))
161538032Speter					p++;
161638032Speter				if (*p != '\0')
161738032Speter					p++;
161838032Speter			}
1619363466Sgshapiro			while (SM_ISSPACE(*p))
162038032Speter				p++;
162138032Speter			if (*p == '\0')
162238032Speter				break;
162338032Speter			if (isascii(*p) && !isdigit(*p))
162438032Speter			{
162538032Speter				char *q = p;
162638032Speter				struct group *gr;
162738032Speter
1628285229Sgshapiro				while (isascii(*p) &&
1629285229Sgshapiro				       (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
163038032Speter					p++;
163138032Speter				*p++ = '\0';
163238032Speter				if (*q == '\0')
163371345Sgshapiro				{
163438032Speter					syserr("mailer %s: null group name",
163538032Speter						m->m_name);
163671345Sgshapiro					break;
163771345Sgshapiro				}
163838032Speter				gr = getgrnam(q);
163938032Speter				if (gr == NULL)
164071345Sgshapiro				{
164138032Speter					syserr("readcf: mailer U= flag: unknown group %s", q);
164271345Sgshapiro					break;
164371345Sgshapiro				}
164438032Speter				else
164538032Speter					m->m_gid = gr->gr_gid;
164638032Speter			}
164738032Speter			else
164838032Speter			{
164938032Speter				m->m_gid = strtol(p, NULL, 0);
165038032Speter			}
165138032Speter			break;
165264562Sgshapiro
165364562Sgshapiro		  case 'W':		/* wait timeout */
165464562Sgshapiro			m->m_wait = convtime(p, 's');
165564562Sgshapiro			break;
165664562Sgshapiro
165764562Sgshapiro		  case '/':		/* new root directory */
165864562Sgshapiro			if (*p == '\0')
165964562Sgshapiro				syserr("mailer %s: null root directory",
166064562Sgshapiro					m->m_name);
166164562Sgshapiro			else
166264562Sgshapiro				m->m_rootdir = newstr(p);
166364562Sgshapiro			break;
166464562Sgshapiro
166564562Sgshapiro		  default:
166664562Sgshapiro			syserr("M%s: unknown mailer equate %c=",
166764562Sgshapiro			       m->m_name, fcode);
166864562Sgshapiro			break;
166938032Speter		}
167038032Speter
167138032Speter		p = delimptr;
167238032Speter	}
167338032Speter
167490792Sgshapiro#if !HASRRESVPORT
167590792Sgshapiro	if (bitnset(M_SECURE_PORT, m->m_flags))
167690792Sgshapiro	{
167790792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
167890792Sgshapiro				     "M%s: Warning: F=%c set on system that doesn't support rresvport()\n",
167990792Sgshapiro				     m->m_name, M_SECURE_PORT);
168090792Sgshapiro	}
168190792Sgshapiro#endif /* !HASRRESVPORT */
168290792Sgshapiro
168390792Sgshapiro#if !HASNICE
168490792Sgshapiro	if (m->m_nice != 0)
168590792Sgshapiro	{
168690792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
168790792Sgshapiro				     "M%s: Warning: N= set on system that doesn't support nice()\n",
168890792Sgshapiro				     m->m_name);
168990792Sgshapiro	}
169090792Sgshapiro#endif /* !HASNICE */
169190792Sgshapiro
169238032Speter	/* do some rationality checking */
169338032Speter	if (m->m_argv == NULL)
169438032Speter	{
169538032Speter		syserr("M%s: A= argument required", m->m_name);
169638032Speter		return;
169738032Speter	}
169838032Speter	if (m->m_mailer == NULL)
169938032Speter	{
170038032Speter		syserr("M%s: P= argument required", m->m_name);
170138032Speter		return;
170238032Speter	}
170338032Speter
170490792Sgshapiro	if (nextmailer >= MAXMAILERS)
170538032Speter	{
170638032Speter		syserr("too many mailers defined (%d max)", MAXMAILERS);
170738032Speter		return;
170838032Speter	}
170938032Speter
171064562Sgshapiro	if (m->m_maxrcpt <= 0)
171164562Sgshapiro		m->m_maxrcpt = DEFAULT_MAX_RCPT;
171264562Sgshapiro
171338032Speter	/* do some heuristic cleanup for back compatibility */
171438032Speter	if (bitnset(M_LIMITS, m->m_flags))
171538032Speter	{
171638032Speter		if (m->m_linelimit == 0)
171738032Speter			m->m_linelimit = SMTPLINELIM;
171838032Speter		if (ConfigLevel < 2)
171938032Speter			setbitn(M_7BITS, m->m_flags);
172038032Speter	}
172138032Speter
172264562Sgshapiro	if (strcmp(m->m_mailer, "[TCP]") == 0)
172338032Speter	{
172490792Sgshapiro		syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name);
172571345Sgshapiro		return;
172638032Speter	}
172738032Speter
172890792Sgshapiro	if (strcmp(m->m_mailer, "[IPC]") == 0)
172938032Speter	{
173064562Sgshapiro		/* Use the second argument for host or path to socket */
173164562Sgshapiro		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
173264562Sgshapiro		    m->m_argv[1][0] == '\0')
173364562Sgshapiro		{
173464562Sgshapiro			syserr("M%s: too few parameters for %s mailer",
173564562Sgshapiro			       m->m_name, m->m_mailer);
173671345Sgshapiro			return;
173764562Sgshapiro		}
173866494Sgshapiro		if (strcmp(m->m_argv[0], "TCP") != 0
173964562Sgshapiro#if NETUNIX
174066494Sgshapiro		    && strcmp(m->m_argv[0], "FILE") != 0
1741363466Sgshapiro#endif
174264562Sgshapiro		    )
174364562Sgshapiro		{
174490792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
174590792Sgshapiro					     "M%s: Warning: first argument in %s mailer must be %s\n",
174690792Sgshapiro					     m->m_name, m->m_mailer,
174764562Sgshapiro#if NETUNIX
174890792Sgshapiro					     "TCP or FILE"
1749363466Sgshapiro#else
175090792Sgshapiro					     "TCP"
1751363466Sgshapiro#endif
175290792Sgshapiro				     );
175364562Sgshapiro		}
175490792Sgshapiro		if (m->m_mtatype == NULL)
175590792Sgshapiro			m->m_mtatype = "dns";
175690792Sgshapiro		if (m->m_addrtype == NULL)
175790792Sgshapiro			m->m_addrtype = "rfc822";
175890792Sgshapiro		if (m->m_diagtype == NULL)
175990792Sgshapiro		{
176090792Sgshapiro			if (m->m_argv[0] != NULL &&
176190792Sgshapiro			    strcmp(m->m_argv[0], "FILE") == 0)
176290792Sgshapiro				m->m_diagtype = "x-unix";
176390792Sgshapiro			else
176490792Sgshapiro				m->m_diagtype = "smtp";
176590792Sgshapiro		}
176664562Sgshapiro	}
176764562Sgshapiro	else if (strcmp(m->m_mailer, "[FILE]") == 0)
176864562Sgshapiro	{
176938032Speter		/* Use the second argument for filename */
177038032Speter		if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
177138032Speter		    m->m_argv[2] != NULL)
177238032Speter		{
177338032Speter			syserr("M%s: too %s parameters for [FILE] mailer",
177438032Speter			       m->m_name,
177538032Speter			       (m->m_argv[0] == NULL ||
177638032Speter				m->m_argv[1] == NULL) ? "few" : "many");
177771345Sgshapiro			return;
177838032Speter		}
177938032Speter		else if (strcmp(m->m_argv[0], "FILE") != 0)
178038032Speter		{
178138032Speter			syserr("M%s: first argument in [FILE] mailer must be FILE",
178238032Speter			       m->m_name);
178371345Sgshapiro			return;
178438032Speter		}
178538032Speter	}
178638032Speter
178738032Speter	if (m->m_eol == NULL)
178838032Speter	{
178938032Speter		char **pp;
179038032Speter
179138032Speter		/* default for SMTP is \r\n; use \n for local delivery */
179238032Speter		for (pp = m->m_argv; *pp != NULL; pp++)
179338032Speter		{
179438032Speter			for (p = *pp; *p != '\0'; )
179538032Speter			{
179638032Speter				if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
179738032Speter					break;
179838032Speter			}
179938032Speter			if (*p != '\0')
180038032Speter				break;
180138032Speter		}
180238032Speter		if (*pp == NULL)
180338032Speter			m->m_eol = "\r\n";
180438032Speter		else
180538032Speter			m->m_eol = "\n";
180638032Speter	}
180738032Speter
180838032Speter	/* enter the mailer into the symbol table */
180938032Speter	s = stab(m->m_name, ST_MAILER, ST_ENTER);
181038032Speter	if (s->s_mailer != NULL)
181138032Speter	{
181238032Speter		i = s->s_mailer->m_mno;
181390792Sgshapiro		sm_free(s->s_mailer); /* XXX */
181438032Speter	}
181538032Speter	else
181638032Speter	{
181790792Sgshapiro		i = nextmailer++;
181838032Speter	}
181938032Speter	Mailer[i] = s->s_mailer = m;
182038032Speter	m->m_mno = i;
182138032Speter}
182290792Sgshapiro/*
182338032Speter**  MUNCHSTRING -- translate a string into internal form.
182438032Speter**
182538032Speter**	Parameters:
182638032Speter**		p -- the string to munch.
182738032Speter**		delimptr -- if non-NULL, set to the pointer of the
182838032Speter**			field delimiter character.
182938032Speter**		delim -- the delimiter for the field.
183038032Speter**
183138032Speter**	Returns:
183238032Speter**		the munched string.
183364562Sgshapiro**
183464562Sgshapiro**	Side Effects:
183564562Sgshapiro**		the munched string is a local static buffer.
183664562Sgshapiro**		it must be copied before the function is called again.
183738032Speter*/
183838032Speter
183938032Speterchar *
184038032Spetermunchstring(p, delimptr, delim)
184138032Speter	register char *p;
184238032Speter	char **delimptr;
184338032Speter	int delim;
184438032Speter{
184538032Speter	register char *q;
184690792Sgshapiro	bool backslash = false;
184790792Sgshapiro	bool quotemode = false;
184838032Speter	static char buf[MAXLINE];
184938032Speter
1850168515Sgshapiro	for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
185138032Speter	{
185238032Speter		if (backslash)
185338032Speter		{
185438032Speter			/* everything is roughly literal */
185590792Sgshapiro			backslash = false;
185638032Speter			switch (*p)
185738032Speter			{
185838032Speter			  case 'r':		/* carriage return */
185938032Speter				*q++ = '\r';
186038032Speter				continue;
186138032Speter
186238032Speter			  case 'n':		/* newline */
186338032Speter				*q++ = '\n';
186438032Speter				continue;
186538032Speter
186638032Speter			  case 'f':		/* form feed */
186738032Speter				*q++ = '\f';
186838032Speter				continue;
186938032Speter
187038032Speter			  case 'b':		/* backspace */
187138032Speter				*q++ = '\b';
187238032Speter				continue;
187338032Speter			}
187438032Speter			*q++ = *p;
187538032Speter		}
187638032Speter		else
187738032Speter		{
187838032Speter			if (*p == '\\')
187990792Sgshapiro				backslash = true;
188038032Speter			else if (*p == '"')
188138032Speter				quotemode = !quotemode;
188238032Speter			else if (quotemode || *p != delim)
188338032Speter				*q++ = *p;
188438032Speter			else
188538032Speter				break;
188638032Speter		}
188738032Speter	}
188838032Speter
188938032Speter	if (delimptr != NULL)
189038032Speter		*delimptr = p;
189138032Speter	*q++ = '\0';
189264562Sgshapiro	return buf;
189338032Speter}
189490792Sgshapiro/*
189590792Sgshapiro**  EXTRQUOTSTR -- extract a (quoted) string.
189690792Sgshapiro**
189790792Sgshapiro**	This routine deals with quoted (") strings and escaped
189890792Sgshapiro**	spaces (\\ ).
189990792Sgshapiro**
190090792Sgshapiro**	Parameters:
190190792Sgshapiro**		p -- source string.
190290792Sgshapiro**		delimptr -- if non-NULL, set to the pointer of the
190390792Sgshapiro**			field delimiter character.
190490792Sgshapiro**		delimbuf -- delimiters for the field.
190590792Sgshapiro**		st -- if non-NULL, store the return value (whether the
190690792Sgshapiro**			string was correctly quoted) here.
190790792Sgshapiro**
190890792Sgshapiro**	Returns:
190990792Sgshapiro**		the extracted string.
191090792Sgshapiro**
191190792Sgshapiro**	Side Effects:
191290792Sgshapiro**		the returned string is a local static buffer.
191390792Sgshapiro**		it must be copied before the function is called again.
191490792Sgshapiro*/
191590792Sgshapiro
191690792Sgshapirostatic char *
191790792Sgshapiroextrquotstr(p, delimptr, delimbuf, st)
191890792Sgshapiro	register char *p;
191990792Sgshapiro	char **delimptr;
192090792Sgshapiro	char *delimbuf;
192190792Sgshapiro	bool *st;
192290792Sgshapiro{
192390792Sgshapiro	register char *q;
192490792Sgshapiro	bool backslash = false;
192590792Sgshapiro	bool quotemode = false;
192690792Sgshapiro	static char buf[MAXLINE];
192790792Sgshapiro
1928168515Sgshapiro	for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
192990792Sgshapiro	{
193090792Sgshapiro		if (backslash)
193190792Sgshapiro		{
193290792Sgshapiro			backslash = false;
193390792Sgshapiro			if (*p != ' ')
193490792Sgshapiro				*q++ = '\\';
193590792Sgshapiro		}
193690792Sgshapiro		if (*p == '\\')
193790792Sgshapiro			backslash = true;
193890792Sgshapiro		else if (*p == '"')
193990792Sgshapiro			quotemode = !quotemode;
194090792Sgshapiro		else if (quotemode ||
194190792Sgshapiro			 strchr(delimbuf, (int) *p) == NULL)
194290792Sgshapiro			*q++ = *p;
194390792Sgshapiro		else
194490792Sgshapiro			break;
194590792Sgshapiro	}
194690792Sgshapiro
194790792Sgshapiro	if (delimptr != NULL)
194890792Sgshapiro		*delimptr = p;
194990792Sgshapiro	*q++ = '\0';
195090792Sgshapiro	if (st != NULL)
195190792Sgshapiro		*st = !(quotemode || backslash);
195290792Sgshapiro	return buf;
195390792Sgshapiro}
195490792Sgshapiro/*
195538032Speter**  MAKEARGV -- break up a string into words
195638032Speter**
195738032Speter**	Parameters:
195838032Speter**		p -- the string to break up.
195938032Speter**
196038032Speter**	Returns:
196138032Speter**		a char **argv (dynamically allocated)
196238032Speter**
196338032Speter**	Side Effects:
196438032Speter**		munges p.
196538032Speter*/
196638032Speter
196764562Sgshapirostatic char **
196838032Spetermakeargv(p)
196938032Speter	register char *p;
197038032Speter{
197138032Speter	char *q;
197238032Speter	int i;
197338032Speter	char **avp;
197438032Speter	char *argv[MAXPV + 1];
197538032Speter
197638032Speter	/* take apart the words */
197738032Speter	i = 0;
197838032Speter	while (*p != '\0' && i < MAXPV)
197938032Speter	{
198038032Speter		q = p;
1981363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
198238032Speter			p++;
1983363466Sgshapiro		while (SM_ISSPACE(*p))
198438032Speter			*p++ = '\0';
198538032Speter		argv[i++] = newstr(q);
198638032Speter	}
198738032Speter	argv[i++] = NULL;
198838032Speter
198938032Speter	/* now make a copy of the argv */
1990168515Sgshapiro	avp = (char **) xalloc(sizeof(*avp) * i);
1991168515Sgshapiro	memmove((char *) avp, (char *) argv, sizeof(*avp) * i);
199238032Speter
199364562Sgshapiro	return avp;
199438032Speter}
199590792Sgshapiro/*
199638032Speter**  PRINTRULES -- print rewrite rules (for debugging)
199738032Speter**
199838032Speter**	Parameters:
199938032Speter**		none.
200038032Speter**
200138032Speter**	Returns:
200238032Speter**		none.
200338032Speter**
200438032Speter**	Side Effects:
200538032Speter**		prints rewrite rules.
200638032Speter*/
200738032Speter
200838032Spetervoid
200938032Speterprintrules()
201038032Speter{
201138032Speter	register struct rewrite *rwp;
201238032Speter	register int ruleset;
201338032Speter
201438032Speter	for (ruleset = 0; ruleset < 10; ruleset++)
201538032Speter	{
201638032Speter		if (RewriteRules[ruleset] == NULL)
201738032Speter			continue;
2018132943Sgshapiro		sm_dprintf("\n----Rule Set %d:", ruleset);
201938032Speter
202038032Speter		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
202138032Speter		{
2022132943Sgshapiro			sm_dprintf("\nLHS:");
2023132943Sgshapiro			printav(sm_debug_file(), rwp->r_lhs);
2024132943Sgshapiro			sm_dprintf("RHS:");
2025132943Sgshapiro			printav(sm_debug_file(), rwp->r_rhs);
202638032Speter		}
202738032Speter	}
202838032Speter}
202990792Sgshapiro/*
203038032Speter**  PRINTMAILER -- print mailer structure (for debugging)
203138032Speter**
203238032Speter**	Parameters:
2033132943Sgshapiro**		fp -- output file
203438032Speter**		m -- the mailer to print
203538032Speter**
203638032Speter**	Returns:
203738032Speter**		none.
203838032Speter*/
203938032Speter
204038032Spetervoid
2041132943Sgshapiroprintmailer(fp, m)
2042132943Sgshapiro	SM_FILE_T *fp;
204338032Speter	register MAILER *m;
204438032Speter{
204538032Speter	int j;
204638032Speter
2047132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
204890792Sgshapiro			     "mailer %d (%s): P=%s S=", m->m_mno, m->m_name,
204990792Sgshapiro			     m->m_mailer);
205064562Sgshapiro	if (RuleSetNames[m->m_se_rwset] == NULL)
2051132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
205290792Sgshapiro				     m->m_se_rwset);
205364562Sgshapiro	else
2054132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
205590792Sgshapiro				     RuleSetNames[m->m_se_rwset]);
205664562Sgshapiro	if (RuleSetNames[m->m_sh_rwset] == NULL)
2057132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d R=",
205890792Sgshapiro				     m->m_sh_rwset);
205964562Sgshapiro	else
2060132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s R=",
206190792Sgshapiro				     RuleSetNames[m->m_sh_rwset]);
206264562Sgshapiro	if (RuleSetNames[m->m_re_rwset] == NULL)
2063132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
206490792Sgshapiro				     m->m_re_rwset);
206564562Sgshapiro	else
2066132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
206790792Sgshapiro				     RuleSetNames[m->m_re_rwset]);
206864562Sgshapiro	if (RuleSetNames[m->m_rh_rwset] == NULL)
2069132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d ",
207090792Sgshapiro				     m->m_rh_rwset);
207164562Sgshapiro	else
2072132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s ",
207390792Sgshapiro				     RuleSetNames[m->m_rh_rwset]);
2074132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=",
207590792Sgshapiro			     m->m_maxsize, (int) m->m_uid, (int) m->m_gid);
207638032Speter	for (j = '\0'; j <= '\177'; j++)
207738032Speter		if (bitnset(j, m->m_flags))
2078132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, j);
2079132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " L=%d E=",
208090792Sgshapiro			     m->m_linelimit);
2081132943Sgshapiro	xputs(fp, m->m_eol);
208238032Speter	if (m->m_defcharset != NULL)
2083132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " C=%s",
208490792Sgshapiro				     m->m_defcharset);
2085132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " T=%s/%s/%s",
208690792Sgshapiro			     m->m_mtatype == NULL
208790792Sgshapiro				? "<undefined>" : m->m_mtatype,
208890792Sgshapiro			     m->m_addrtype == NULL
208990792Sgshapiro				? "<undefined>" : m->m_addrtype,
209090792Sgshapiro			     m->m_diagtype == NULL
209190792Sgshapiro				? "<undefined>" : m->m_diagtype);
2092132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt);
209338032Speter	if (m->m_argv != NULL)
209438032Speter	{
209538032Speter		char **a = m->m_argv;
209638032Speter
2097132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " A=");
209838032Speter		while (*a != NULL)
209938032Speter		{
210038032Speter			if (a != m->m_argv)
2101132943Sgshapiro				(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
210290792Sgshapiro						     " ");
2103132943Sgshapiro			xputs(fp, *a++);
210438032Speter		}
210538032Speter	}
2106132943Sgshapiro	(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n");
210738032Speter}
2108285229Sgshapiro
2109285229Sgshapiro#if STARTTLS
2110285229Sgshapirostatic struct ssl_options
2111285229Sgshapiro{
2112285229Sgshapiro	const char	*sslopt_name;	/* name of the flag */
2113285229Sgshapiro	long		sslopt_bits;	/* bits to set/clear */
2114285229Sgshapiro} SSL_Option[] =
2115285229Sgshapiro{
2116285229Sgshapiro/* Workaround for bugs are turned on by default (as well as some others) */
2117285229Sgshapiro#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
2118285229Sgshapiro	{ "SSL_OP_MICROSOFT_SESS_ID_BUG",	SSL_OP_MICROSOFT_SESS_ID_BUG	},
2119285229Sgshapiro#endif
2120285229Sgshapiro#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
2121285229Sgshapiro	{ "SSL_OP_NETSCAPE_CHALLENGE_BUG",	SSL_OP_NETSCAPE_CHALLENGE_BUG	},
2122285229Sgshapiro#endif
2123285229Sgshapiro#ifdef SSL_OP_LEGACY_SERVER_CONNECT
2124285229Sgshapiro	{ "SSL_OP_LEGACY_SERVER_CONNECT",	SSL_OP_LEGACY_SERVER_CONNECT	},
2125285229Sgshapiro#endif
2126285229Sgshapiro#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
2127285229Sgshapiro	{ "SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG",	SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG	},
2128285229Sgshapiro#endif
2129285229Sgshapiro#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
2130285229Sgshapiro	{ "SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG",	SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG	},
2131285229Sgshapiro#endif
2132285229Sgshapiro#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
2133285229Sgshapiro	{ "SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER",	SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER	},
2134285229Sgshapiro#endif
2135285229Sgshapiro#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
2136285229Sgshapiro	{ "SSL_OP_MSIE_SSLV2_RSA_PADDING",	SSL_OP_MSIE_SSLV2_RSA_PADDING	},
2137285229Sgshapiro#endif
2138285229Sgshapiro#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
2139285229Sgshapiro	{ "SSL_OP_SSLEAY_080_CLIENT_DH_BUG",	SSL_OP_SSLEAY_080_CLIENT_DH_BUG	},
2140285229Sgshapiro#endif
2141285229Sgshapiro#ifdef SSL_OP_TLS_D5_BUG
2142285229Sgshapiro	{ "SSL_OP_TLS_D5_BUG",	SSL_OP_TLS_D5_BUG	},
2143285229Sgshapiro#endif
2144285229Sgshapiro#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
2145285229Sgshapiro	{ "SSL_OP_TLS_BLOCK_PADDING_BUG",	SSL_OP_TLS_BLOCK_PADDING_BUG	},
2146285229Sgshapiro#endif
2147285229Sgshapiro#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
2148285229Sgshapiro	{ "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS",	SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS	},
2149285229Sgshapiro#endif
2150285229Sgshapiro#ifdef SSL_OP_ALL
2151285229Sgshapiro	{ "SSL_OP_ALL",	SSL_OP_ALL	},
2152285229Sgshapiro#endif
2153285229Sgshapiro#ifdef SSL_OP_NO_QUERY_MTU
2154285229Sgshapiro	{ "SSL_OP_NO_QUERY_MTU",	SSL_OP_NO_QUERY_MTU	},
2155285229Sgshapiro#endif
2156285229Sgshapiro#ifdef SSL_OP_COOKIE_EXCHANGE
2157285229Sgshapiro	{ "SSL_OP_COOKIE_EXCHANGE",	SSL_OP_COOKIE_EXCHANGE	},
2158285229Sgshapiro#endif
2159285229Sgshapiro#ifdef SSL_OP_NO_TICKET
2160285229Sgshapiro	{ "SSL_OP_NO_TICKET",	SSL_OP_NO_TICKET	},
2161285229Sgshapiro#endif
2162285229Sgshapiro#ifdef SSL_OP_CISCO_ANYCONNECT
2163285229Sgshapiro	{ "SSL_OP_CISCO_ANYCONNECT",	SSL_OP_CISCO_ANYCONNECT	},
2164285229Sgshapiro#endif
2165285229Sgshapiro#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
2166285229Sgshapiro	{ "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION",	SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	},
2167285229Sgshapiro#endif
2168285229Sgshapiro#ifdef SSL_OP_NO_COMPRESSION
2169285229Sgshapiro	{ "SSL_OP_NO_COMPRESSION",	SSL_OP_NO_COMPRESSION	},
2170285229Sgshapiro#endif
2171285229Sgshapiro#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
2172285229Sgshapiro	{ "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION",	SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION	},
2173285229Sgshapiro#endif
2174285229Sgshapiro#ifdef SSL_OP_SINGLE_ECDH_USE
2175285229Sgshapiro	{ "SSL_OP_SINGLE_ECDH_USE",	SSL_OP_SINGLE_ECDH_USE	},
2176285229Sgshapiro#endif
2177285229Sgshapiro#ifdef SSL_OP_SINGLE_DH_USE
2178285229Sgshapiro	{ "SSL_OP_SINGLE_DH_USE",	SSL_OP_SINGLE_DH_USE	},
2179285229Sgshapiro#endif
2180285229Sgshapiro#ifdef SSL_OP_EPHEMERAL_RSA
2181285229Sgshapiro	{ "SSL_OP_EPHEMERAL_RSA",	SSL_OP_EPHEMERAL_RSA	},
2182285229Sgshapiro#endif
2183285229Sgshapiro#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
2184285229Sgshapiro	{ "SSL_OP_CIPHER_SERVER_PREFERENCE",	SSL_OP_CIPHER_SERVER_PREFERENCE	},
2185285229Sgshapiro#endif
2186285229Sgshapiro#ifdef SSL_OP_TLS_ROLLBACK_BUG
2187285229Sgshapiro	{ "SSL_OP_TLS_ROLLBACK_BUG",	SSL_OP_TLS_ROLLBACK_BUG	},
2188285229Sgshapiro#endif
2189285229Sgshapiro#ifdef SSL_OP_NO_SSLv2
2190285229Sgshapiro	{ "SSL_OP_NO_SSLv2",	SSL_OP_NO_SSLv2	},
2191285229Sgshapiro#endif
2192285229Sgshapiro#ifdef SSL_OP_NO_SSLv3
2193285229Sgshapiro	{ "SSL_OP_NO_SSLv3",	SSL_OP_NO_SSLv3	},
2194285229Sgshapiro#endif
2195285229Sgshapiro#ifdef SSL_OP_NO_TLSv1
2196285229Sgshapiro	{ "SSL_OP_NO_TLSv1",	SSL_OP_NO_TLSv1	},
2197285229Sgshapiro#endif
2198363466Sgshapiro#ifdef SSL_OP_NO_TLSv1_3
2199363466Sgshapiro	{ "SSL_OP_NO_TLSv1_3",	SSL_OP_NO_TLSv1_3	},
2200363466Sgshapiro#endif
2201285229Sgshapiro#ifdef SSL_OP_NO_TLSv1_2
2202285229Sgshapiro	{ "SSL_OP_NO_TLSv1_2",	SSL_OP_NO_TLSv1_2	},
2203285229Sgshapiro#endif
2204285229Sgshapiro#ifdef SSL_OP_NO_TLSv1_1
2205285229Sgshapiro	{ "SSL_OP_NO_TLSv1_1",	SSL_OP_NO_TLSv1_1	},
2206285229Sgshapiro#endif
2207285229Sgshapiro#ifdef SSL_OP_PKCS1_CHECK_1
2208285229Sgshapiro	{ "SSL_OP_PKCS1_CHECK_1",	SSL_OP_PKCS1_CHECK_1	},
2209285229Sgshapiro#endif
2210285229Sgshapiro#ifdef SSL_OP_PKCS1_CHECK_2
2211285229Sgshapiro	{ "SSL_OP_PKCS1_CHECK_2",	SSL_OP_PKCS1_CHECK_2	},
2212285229Sgshapiro#endif
2213285229Sgshapiro#ifdef SSL_OP_NETSCAPE_CA_DN_BUG
2214285229Sgshapiro	{ "SSL_OP_NETSCAPE_CA_DN_BUG",	SSL_OP_NETSCAPE_CA_DN_BUG	},
2215285229Sgshapiro#endif
2216285229Sgshapiro#ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
2217285229Sgshapiro	{ "SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG",	SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG	},
2218285229Sgshapiro#endif
2219285229Sgshapiro#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
2220285229Sgshapiro	{ "SSL_OP_CRYPTOPRO_TLSEXT_BUG",	SSL_OP_CRYPTOPRO_TLSEXT_BUG	},
2221285229Sgshapiro#endif
2222285229Sgshapiro#ifdef SSL_OP_TLSEXT_PADDING
2223285229Sgshapiro	{ "SSL_OP_TLSEXT_PADDING",	SSL_OP_TLSEXT_PADDING	},
2224285229Sgshapiro#endif
2225363466Sgshapiro#ifdef SSL_OP_NO_RENEGOTIATION
2226363466Sgshapiro	{ "SSL_OP_NO_RENEGOTIATION",    SSL_OP_NO_RENEGOTIATION },
2227363466Sgshapiro#endif
2228363466Sgshapiro#ifdef SSL_OP_NO_ANTI_REPLAY
2229363466Sgshapiro	{ "SSL_OP_NO_ANTI_REPLAY",	SSL_OP_NO_ANTI_REPLAY },
2230363466Sgshapiro#endif
2231363466Sgshapiro#ifdef SSL_OP_ALLOW_NO_DHE_KEX
2232363466Sgshapiro	{ "SSL_OP_ALLOW_NO_DHE_KEX",	SSL_OP_ALLOW_NO_DHE_KEX },
2233363466Sgshapiro#endif
2234363466Sgshapiro#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC
2235363466Sgshapiro	{ "SSL_OP_NO_ENCRYPT_THEN_MAC",	SSL_OP_NO_ENCRYPT_THEN_MAC },
2236363466Sgshapiro#endif
2237363466Sgshapiro#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
2238363466Sgshapiro	{ "SSL_OP_ENABLE_MIDDLEBOX_COMPAT",	SSL_OP_ENABLE_MIDDLEBOX_COMPAT },
2239363466Sgshapiro#endif
2240363466Sgshapiro#ifdef SSL_OP_PRIORITIZE_CHACHA
2241363466Sgshapiro	{ "SSL_OP_PRIORITIZE_CHACHA",	SSL_OP_PRIORITIZE_CHACHA },
2242363466Sgshapiro#endif
2243285229Sgshapiro	{ NULL,		0		}
2244285229Sgshapiro};
2245285229Sgshapiro
224690792Sgshapiro/*
2247285229Sgshapiro** READSSLOPTIONS  -- read SSL_OP_* values
2248285229Sgshapiro**
2249285229Sgshapiro**	Parameters:
2250285229Sgshapiro**		opt -- name of option (can be NULL)
2251285229Sgshapiro**		val -- string with SSL_OP_* values or hex value
2252285229Sgshapiro**		delim -- end of string (e.g., '\0' or ';')
2253285229Sgshapiro**		pssloptions -- return value (output)
2254285229Sgshapiro**
2255285229Sgshapiro**	Returns:
2256285229Sgshapiro**		0 on success.
2257285229Sgshapiro*/
2258285229Sgshapiro
2259285229Sgshapiro#define SSLOPERR_NAN	1
2260285229Sgshapiro#define SSLOPERR_NOTFOUND	2
2261285229Sgshapiro
2262363466Sgshapirostatic int readssloptions __P((char *, char *, unsigned long *, int ));
2263363466Sgshapiro
2264285229Sgshapirostatic int
2265285229Sgshapiroreadssloptions(opt, val, pssloptions, delim)
2266285229Sgshapiro	char *opt;
2267285229Sgshapiro	char *val;
2268285229Sgshapiro	unsigned long *pssloptions;
2269285229Sgshapiro	int delim;
2270285229Sgshapiro{
2271285229Sgshapiro	char *p;
2272285229Sgshapiro	int ret;
2273285229Sgshapiro
2274285229Sgshapiro	ret = 0;
2275285229Sgshapiro	for (p = val; *p != '\0' && *p != delim; )
2276285229Sgshapiro	{
2277285229Sgshapiro		bool clearmode;
2278285229Sgshapiro		char *q;
2279285229Sgshapiro		unsigned long sslopt_val;
2280285229Sgshapiro		struct ssl_options *sslopts;
2281285229Sgshapiro
2282285229Sgshapiro		while (*p == ' ')
2283285229Sgshapiro			p++;
2284285229Sgshapiro		if (*p == '\0')
2285285229Sgshapiro			break;
2286285229Sgshapiro		clearmode = false;
2287285229Sgshapiro		if (*p == '-' || *p == '+')
2288285229Sgshapiro			clearmode = *p++ == '-';
2289285229Sgshapiro		q = p;
2290285229Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)) && *p != ',')
2291285229Sgshapiro			p++;
2292285229Sgshapiro		if (*p != '\0')
2293285229Sgshapiro			*p++ = '\0';
2294285229Sgshapiro		sslopt_val = 0;
2295285229Sgshapiro		if (isdigit(*q))
2296285229Sgshapiro		{
2297285229Sgshapiro			char *end;
2298285229Sgshapiro
2299285229Sgshapiro			sslopt_val = strtoul(q, &end, 0);
2300285229Sgshapiro
2301285229Sgshapiro			/* not a complete "syntax" check but good enough */
2302285229Sgshapiro			if (end == q)
2303285229Sgshapiro			{
2304285229Sgshapiro				errno = 0;
2305285229Sgshapiro				ret = SSLOPERR_NAN;
2306285229Sgshapiro				if (opt != NULL)
2307285229Sgshapiro					syserr("readcf: %s option value %s not a number",
2308285229Sgshapiro						opt, q);
2309285229Sgshapiro				sslopt_val = 0;
2310285229Sgshapiro			}
2311285229Sgshapiro		}
2312285229Sgshapiro		else
2313285229Sgshapiro		{
2314285229Sgshapiro			for (sslopts = SSL_Option;
2315285229Sgshapiro			     sslopts->sslopt_name != NULL; sslopts++)
2316285229Sgshapiro			{
2317285229Sgshapiro				if (sm_strcasecmp(q, sslopts->sslopt_name) == 0)
2318285229Sgshapiro				{
2319285229Sgshapiro					sslopt_val = sslopts->sslopt_bits;
2320285229Sgshapiro					break;
2321285229Sgshapiro				}
2322285229Sgshapiro			}
2323285229Sgshapiro			if (sslopts->sslopt_name == NULL)
2324285229Sgshapiro			{
2325285229Sgshapiro				errno = 0;
2326285229Sgshapiro				ret = SSLOPERR_NOTFOUND;
2327285229Sgshapiro				if (opt != NULL)
2328285229Sgshapiro					syserr("readcf: %s option value %s unrecognized",
2329285229Sgshapiro						opt, q);
2330285229Sgshapiro			}
2331285229Sgshapiro		}
2332285229Sgshapiro		if (sslopt_val != 0)
2333285229Sgshapiro		{
2334285229Sgshapiro			if (clearmode)
2335285229Sgshapiro				*pssloptions &= ~sslopt_val;
2336285229Sgshapiro			else
2337285229Sgshapiro				*pssloptions |= sslopt_val;
2338285229Sgshapiro		}
2339285229Sgshapiro	}
2340285229Sgshapiro	return ret;
2341285229Sgshapiro}
2342285229Sgshapiro
2343285229Sgshapiro/*
2344285229Sgshapiro** GET_TLS_SE_OPTIONS -- get TLS session options (from ruleset)
2345285229Sgshapiro**
2346285229Sgshapiro**	Parameters:
2347285229Sgshapiro**		e -- envelope
2348285229Sgshapiro**		ssl -- TLS session context
2349363466Sgshapiro**		tlsi_ctx -- TLS info context
2350285229Sgshapiro**		srv -- server?
2351285229Sgshapiro**
2352285229Sgshapiro**	Returns:
2353285229Sgshapiro**		0 on success.
2354285229Sgshapiro*/
2355285229Sgshapiro
2356285229Sgshapiroint
2357363466Sgshapiroget_tls_se_options(e, ssl, tlsi_ctx, srv)
2358285229Sgshapiro	ENVELOPE *e;
2359285229Sgshapiro	SSL *ssl;
2360363466Sgshapiro	tlsi_ctx_T *tlsi_ctx;
2361285229Sgshapiro	bool srv;
2362285229Sgshapiro{
2363285229Sgshapiro	bool saveQuickAbort, saveSuprErrs, ok;
2364285229Sgshapiro	char *optionlist, *opt, *val;
2365285229Sgshapiro	char *keyfile, *certfile;
2366285229Sgshapiro	size_t len, i;
2367285229Sgshapiro	int ret;
2368285229Sgshapiro
2369285229Sgshapiro#  define who (srv ? "server" : "client")
2370285229Sgshapiro#  define NAME_C_S macvalue(macid(srv ? "{client_name}" : "{server_name}"), e)
2371285229Sgshapiro#  define ADDR_C_S macvalue(macid(srv ? "{client_addr}" : "{server_addr}"), e)
2372285229Sgshapiro#  define WHICH srv ? "srv" : "clt"
2373285229Sgshapiro
2374285229Sgshapiro	ret = 0;
2375285229Sgshapiro	keyfile = certfile = opt = val = NULL;
2376285229Sgshapiro	saveQuickAbort = QuickAbort;
2377285229Sgshapiro	saveSuprErrs = SuprErrs;
2378285229Sgshapiro	SuprErrs = true;
2379285229Sgshapiro	QuickAbort = false;
2380285229Sgshapiro
2381285229Sgshapiro	optionlist = NULL;
2382285229Sgshapiro	ok = rscheck(srv ? "tls_srv_features" : "tls_clt_features",
2383285229Sgshapiro		     NAME_C_S, ADDR_C_S, e,
2384285229Sgshapiro		     RSF_RMCOMM|RSF_ADDR|RSF_STRING,
2385285229Sgshapiro		     5, NULL, NOQID, NULL, &optionlist) == EX_OK;
2386285229Sgshapiro	if (!ok && LogLevel > 8)
2387285229Sgshapiro	{
2388285229Sgshapiro		sm_syslog(LOG_NOTICE, NOQID,
2389285229Sgshapiro			  "rscheck(tls_%s_features)=failed, relay=%s [%s], errors=%d",
2390285229Sgshapiro			  WHICH, NAME_C_S, ADDR_C_S,
2391285229Sgshapiro			  Errors);
2392285229Sgshapiro	}
2393285229Sgshapiro	QuickAbort = saveQuickAbort;
2394285229Sgshapiro	SuprErrs = saveSuprErrs;
2395285229Sgshapiro	if (ok && LogLevel > 9)
2396285229Sgshapiro	{
2397285229Sgshapiro		sm_syslog(LOG_INFO, NOQID,
2398285229Sgshapiro			  "tls_%s_features=%s, relay=%s [%s]",
2399285229Sgshapiro			  WHICH, optionlist, NAME_C_S, ADDR_C_S);
2400285229Sgshapiro	}
2401285229Sgshapiro	if (!ok || optionlist == NULL || (len = strlen(optionlist)) < 2)
2402285229Sgshapiro	{
2403285229Sgshapiro		if (LogLevel > 9)
2404285229Sgshapiro			sm_syslog(LOG_INFO, NOQID,
2405285229Sgshapiro				  "tls_%s_features=empty, relay=%s [%s]",
2406363466Sgshapiro				  WHICH, NAME_C_S, ADDR_C_S);
2407285229Sgshapiro
2408285229Sgshapiro		return ok ? 0 : 1;
2409285229Sgshapiro	}
2410285229Sgshapiro
2411285229Sgshapiro	i = 0;
2412285229Sgshapiro	if (optionlist[0] == '"' && optionlist[len - 1] == '"')
2413285229Sgshapiro	{
2414285229Sgshapiro		optionlist[0] = ' ';
2415285229Sgshapiro		optionlist[--len] = '\0';
2416285229Sgshapiro		if (len <= 2)
2417285229Sgshapiro		{
2418285229Sgshapiro			if (LogLevel > 9 && len > 1)
2419285229Sgshapiro				sm_syslog(LOG_INFO, NOQID,
2420285229Sgshapiro				  "tls_%s_features=too_short, relay=%s [%s]",
2421363466Sgshapiro				  WHICH, NAME_C_S, ADDR_C_S);
2422285229Sgshapiro
2423285229Sgshapiro			/* this is not treated as error! */
2424285229Sgshapiro			return 0;
2425285229Sgshapiro		}
2426285229Sgshapiro		i = 1;
2427285229Sgshapiro	}
2428285229Sgshapiro
2429285229Sgshapiro#  define INVALIDSYNTAX	\
2430285229Sgshapiro	do {	\
2431285229Sgshapiro		if (LogLevel > 7)	\
2432285229Sgshapiro			sm_syslog(LOG_INFO, NOQID,	\
2433285229Sgshapiro				  "tls_%s_features=invalid_syntax, opt=%s, relay=%s [%s]",	\
2434363466Sgshapiro				  WHICH, opt, NAME_C_S, ADDR_C_S);	\
2435285229Sgshapiro		return -1;	\
2436285229Sgshapiro	} while (0)
2437285229Sgshapiro
2438285229Sgshapiro#  define CHECKLEN	\
2439285229Sgshapiro	do {	\
2440285229Sgshapiro		if (i >= len)	\
2441285229Sgshapiro			INVALIDSYNTAX;	\
2442285229Sgshapiro	} while (0)
2443285229Sgshapiro
2444285229Sgshapiro#  define SKIPWS	\
2445285229Sgshapiro	do {	\
2446285229Sgshapiro		while (i < len && SM_ISSPACE(optionlist[i]))	\
2447285229Sgshapiro			++i;	\
2448285229Sgshapiro		CHECKLEN;	\
2449285229Sgshapiro	} while (0)
2450285229Sgshapiro
2451285229Sgshapiro	/* parse and handle opt=val; */
2452285229Sgshapiro	do {
2453285229Sgshapiro		char sep;
2454285229Sgshapiro
2455285229Sgshapiro		SKIPWS;
2456285229Sgshapiro		opt = optionlist + i;
2457285229Sgshapiro		sep = '=';
2458285229Sgshapiro		while (i < len && optionlist[i] != sep
2459285229Sgshapiro			&& optionlist[i] != '\0' && !SM_ISSPACE(optionlist[i]))
2460285229Sgshapiro			++i;
2461285229Sgshapiro		CHECKLEN;
2462285229Sgshapiro		while (i < len && SM_ISSPACE(optionlist[i]))
2463285229Sgshapiro			optionlist[i++] = '\0';
2464285229Sgshapiro		CHECKLEN;
2465285229Sgshapiro		if (optionlist[i] != sep)
2466285229Sgshapiro			INVALIDSYNTAX;
2467285229Sgshapiro		optionlist[i++] = '\0';
2468285229Sgshapiro
2469285229Sgshapiro		SKIPWS;
2470285229Sgshapiro		val = optionlist + i;
2471285229Sgshapiro		sep = ';';
2472285229Sgshapiro		while (i < len && optionlist[i] != sep && optionlist[i] != '\0')
2473285229Sgshapiro			++i;
2474285229Sgshapiro		if (optionlist[i] != '\0')
2475285229Sgshapiro		{
2476285229Sgshapiro			CHECKLEN;
2477285229Sgshapiro			optionlist[i++] = '\0';
2478285229Sgshapiro		}
2479285229Sgshapiro
2480285229Sgshapiro		if (LogLevel > 13)
2481285229Sgshapiro			sm_syslog(LOG_DEBUG, NOQID,
2482285229Sgshapiro				  "tls_%s_features=parsed, %s=%s, relay=%s [%s]",
2483285229Sgshapiro				  WHICH, opt, val, NAME_C_S, ADDR_C_S);
2484285229Sgshapiro
2485285229Sgshapiro		if (sm_strcasecmp(opt, "options") == 0)
2486285229Sgshapiro		{
2487285229Sgshapiro			unsigned long ssloptions;
2488285229Sgshapiro
2489285229Sgshapiro			ssloptions = 0;
2490285229Sgshapiro			ret = readssloptions(NULL, val, &ssloptions, ';');
2491285229Sgshapiro			if (ret == 0)
2492285229Sgshapiro				(void) SSL_set_options(ssl, (long) ssloptions);
2493285229Sgshapiro			else if (LogLevel > 8)
2494285229Sgshapiro			{
2495285229Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
2496285229Sgshapiro					  "tls_%s_features=%s, error=%s, relay=%s [%s]",
2497285229Sgshapiro					  WHICH, val,
2498285229Sgshapiro					  (ret == SSLOPERR_NAN) ? "not a number" :
2499285229Sgshapiro					  ((ret == SSLOPERR_NOTFOUND) ? "SSL_OP not found" :
2500285229Sgshapiro					  "unknown"),
2501285229Sgshapiro					  NAME_C_S, ADDR_C_S);
2502285229Sgshapiro			}
2503285229Sgshapiro		}
2504285229Sgshapiro		else if (sm_strcasecmp(opt, "cipherlist") == 0)
2505285229Sgshapiro		{
2506285229Sgshapiro			if (SSL_set_cipher_list(ssl, val) <= 0)
2507285229Sgshapiro			{
2508285229Sgshapiro				ret = 1;
2509285229Sgshapiro				if (LogLevel > 7)
2510285229Sgshapiro				{
2511285229Sgshapiro					sm_syslog(LOG_WARNING, NOQID,
2512285229Sgshapiro						  "STARTTLS=%s, error: SSL_set_cipher_list(%s) failed",
2513285229Sgshapiro						  who, val);
2514285229Sgshapiro
2515363466Sgshapiro					tlslogerr(LOG_WARNING, 9, who);
2516285229Sgshapiro				}
2517285229Sgshapiro			}
2518285229Sgshapiro		}
2519363466Sgshapiro		else if (sm_strcasecmp(opt, "flags") == 0)
2520363466Sgshapiro		{
2521363466Sgshapiro			char *p;
2522363466Sgshapiro
2523363466Sgshapiro			for (p = val; *p != '\0'; p++)
2524363466Sgshapiro			{
2525363466Sgshapiro				if (isascii(*p) && isalnum(*p))
2526363466Sgshapiro					setbitn(bitidx(*p), tlsi_ctx->tlsi_flags);
2527363466Sgshapiro			}
2528363466Sgshapiro		}
2529285229Sgshapiro		else if (sm_strcasecmp(opt, "keyfile") == 0)
2530285229Sgshapiro			keyfile = val;
2531285229Sgshapiro		else if (sm_strcasecmp(opt, "certfile") == 0)
2532285229Sgshapiro			certfile = val;
2533285229Sgshapiro		else
2534285229Sgshapiro		{
2535285229Sgshapiro			ret = 1;
2536285229Sgshapiro			if (LogLevel > 7)
2537285229Sgshapiro			{
2538285229Sgshapiro				sm_syslog(LOG_INFO, NOQID,
2539285229Sgshapiro					  "tls_%s_features=unknown_option, opt=%s, relay=%s [%s]",
2540363466Sgshapiro					  WHICH, opt, NAME_C_S, ADDR_C_S);
2541285229Sgshapiro			}
2542285229Sgshapiro		}
2543285229Sgshapiro
2544285229Sgshapiro	} while (optionlist[i] != '\0' && i < len);
2545285229Sgshapiro
2546285229Sgshapiro	/* need cert and key before we can use the options */
2547285229Sgshapiro	/* does not implement the "," hack for 2nd cert/key pair */
2548285229Sgshapiro	if (keyfile != NULL && certfile != NULL)
2549285229Sgshapiro	{
2550285229Sgshapiro		load_certkey(ssl, srv, certfile, keyfile);
2551285229Sgshapiro		keyfile = certfile = NULL;
2552285229Sgshapiro	}
2553285229Sgshapiro	else if (keyfile != NULL || certfile != NULL)
2554285229Sgshapiro	{
2555285229Sgshapiro		ret = 1;
2556285229Sgshapiro		if (LogLevel > 7)
2557285229Sgshapiro		{
2558285229Sgshapiro			sm_syslog(LOG_INFO, NOQID,
2559285229Sgshapiro				  "tls_%s_features=only_one_of_CertFile/KeyFile_specified, relay=%s [%s]",
2560363466Sgshapiro				  WHICH, NAME_C_S, ADDR_C_S);
2561285229Sgshapiro		}
2562285229Sgshapiro	}
2563285229Sgshapiro
2564285229Sgshapiro	return ret;
2565285229Sgshapiro#  undef who
2566285229Sgshapiro#  undef NAME_C_S
2567285229Sgshapiro#  undef ADDR_C_S
2568285229Sgshapiro#  undef WHICH
2569285229Sgshapiro}
2570285229Sgshapiro#endif /* STARTTLS */
2571285229Sgshapiro
2572285229Sgshapiro/*
257338032Speter**  SETOPTION -- set global processing option
257438032Speter**
257538032Speter**	Parameters:
257638032Speter**		opt -- option name.
257738032Speter**		val -- option value (as a text string).
257838032Speter**		safe -- set if this came from a configuration file.
257938032Speter**			Some options (if set from the command line) will
258038032Speter**			reset the user id to avoid security problems.
258138032Speter**		sticky -- if set, don't let other setoptions override
258238032Speter**			this value.
258338032Speter**		e -- the main envelope.
258438032Speter**
258538032Speter**	Returns:
258638032Speter**		none.
258738032Speter**
258838032Speter**	Side Effects:
258938032Speter**		Sets options as implied by the arguments.
259038032Speter*/
259138032Speter
259264562Sgshapirostatic BITMAP256	StickyOpt;		/* set if option is stuck */
259338032Speter
259438032Speter#if NAMED_BIND
259538032Speter
259664562Sgshapirostatic struct resolverflags
259738032Speter{
259838032Speter	char	*rf_name;	/* name of the flag */
259938032Speter	long	rf_bits;	/* bits to set/clear */
260038032Speter} ResolverFlags[] =
260138032Speter{
260238032Speter	{ "debug",	RES_DEBUG	},
260338032Speter	{ "aaonly",	RES_AAONLY	},
260438032Speter	{ "usevc",	RES_USEVC	},
260538032Speter	{ "primary",	RES_PRIMARY	},
260638032Speter	{ "igntc",	RES_IGNTC	},
260738032Speter	{ "recurse",	RES_RECURSE	},
260838032Speter	{ "defnames",	RES_DEFNAMES	},
260938032Speter	{ "stayopen",	RES_STAYOPEN	},
261038032Speter	{ "dnsrch",	RES_DNSRCH	},
261190792Sgshapiro# ifdef RES_USE_INET6
261290792Sgshapiro	{ "use_inet6",	RES_USE_INET6	},
2613363466Sgshapiro# endif
2614363466Sgshapiro# ifdef RES_USE_EDNS0
2615363466Sgshapiro	{ "use_edns0",	RES_USE_EDNS0	},
2616363466Sgshapiro# endif
2617363466Sgshapiro# ifdef RES_USE_DNSSEC
2618363466Sgshapiro	{ "use_dnssec",	RES_USE_DNSSEC	},
2619363466Sgshapiro# endif
2620363466Sgshapiro# if RES_TRUSTAD
2621363466Sgshapiro	{ "trustad",	RES_TRUSTAD	},
2622363466Sgshapiro# endif
262338032Speter	{ "true",	0		},	/* avoid error on old syntax */
2624363466Sgshapiro	{ "true",	0		},	/* avoid error on old syntax */
262538032Speter	{ NULL,		0		}
262638032Speter};
262738032Speter
262864562Sgshapiro#endif /* NAMED_BIND */
262938032Speter
263064562Sgshapiro#define OI_NONE		0	/* no special treatment */
263164562Sgshapiro#define OI_SAFE		0x0001	/* safe for random people to use */
263264562Sgshapiro#define OI_SUBOPT	0x0002	/* option has suboptions */
263364562Sgshapiro
263464562Sgshapirostatic struct optioninfo
263538032Speter{
263690792Sgshapiro	char		*o_name;	/* long name of option */
263790792Sgshapiro	unsigned char	o_code;		/* short name of option */
263890792Sgshapiro	unsigned short	o_flags;	/* option flags */
263938032Speter} OptionTab[] =
264038032Speter{
264164562Sgshapiro#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
264264562Sgshapiro	{ "RemoteMode",			'>',		OI_NONE	},
2643363466Sgshapiro#endif
264464562Sgshapiro	{ "SevenBitInput",		'7',		OI_SAFE	},
264564562Sgshapiro	{ "EightBitMode",		'8',		OI_SAFE	},
264664562Sgshapiro	{ "AliasFile",			'A',		OI_NONE	},
264764562Sgshapiro	{ "AliasWait",			'a',		OI_NONE	},
264864562Sgshapiro	{ "BlankSub",			'B',		OI_NONE	},
264964562Sgshapiro	{ "MinFreeBlocks",		'b',		OI_SAFE	},
265064562Sgshapiro	{ "CheckpointInterval",		'C',		OI_SAFE	},
265164562Sgshapiro	{ "HoldExpensive",		'c',		OI_NONE	},
265264562Sgshapiro	{ "DeliveryMode",		'd',		OI_SAFE	},
265364562Sgshapiro	{ "ErrorHeader",		'E',		OI_NONE	},
265464562Sgshapiro	{ "ErrorMode",			'e',		OI_SAFE	},
265564562Sgshapiro	{ "TempFileMode",		'F',		OI_NONE	},
265664562Sgshapiro	{ "SaveFromLine",		'f',		OI_NONE	},
265764562Sgshapiro	{ "MatchGECOS",			'G',		OI_NONE	},
265890792Sgshapiro
265990792Sgshapiro	/* no long name, just here to avoid problems in setoption */
266090792Sgshapiro	{ "",				'g',		OI_NONE	},
266164562Sgshapiro	{ "HelpFile",			'H',		OI_NONE	},
266264562Sgshapiro	{ "MaxHopCount",		'h',		OI_NONE	},
266364562Sgshapiro	{ "ResolverOptions",		'I',		OI_NONE	},
266464562Sgshapiro	{ "IgnoreDots",			'i',		OI_SAFE	},
266564562Sgshapiro	{ "ForwardPath",		'J',		OI_NONE	},
266664562Sgshapiro	{ "SendMimeErrors",		'j',		OI_SAFE	},
266764562Sgshapiro	{ "ConnectionCacheSize",	'k',		OI_NONE	},
266864562Sgshapiro	{ "ConnectionCacheTimeout",	'K',		OI_NONE	},
266964562Sgshapiro	{ "UseErrorsTo",		'l',		OI_NONE	},
267064562Sgshapiro	{ "LogLevel",			'L',		OI_SAFE	},
267164562Sgshapiro	{ "MeToo",			'm',		OI_SAFE	},
267290792Sgshapiro
267390792Sgshapiro	/* no long name, just here to avoid problems in setoption */
267490792Sgshapiro	{ "",				'M',		OI_NONE	},
267564562Sgshapiro	{ "CheckAliases",		'n',		OI_NONE	},
267664562Sgshapiro	{ "OldStyleHeaders",		'o',		OI_SAFE	},
267764562Sgshapiro	{ "DaemonPortOptions",		'O',		OI_NONE	},
267864562Sgshapiro	{ "PrivacyOptions",		'p',		OI_SAFE	},
267964562Sgshapiro	{ "PostmasterCopy",		'P',		OI_NONE	},
268064562Sgshapiro	{ "QueueFactor",		'q',		OI_NONE	},
268164562Sgshapiro	{ "QueueDirectory",		'Q',		OI_NONE	},
268264562Sgshapiro	{ "DontPruneRoutes",		'R',		OI_NONE	},
268364562Sgshapiro	{ "Timeout",			'r',		OI_SUBOPT },
268464562Sgshapiro	{ "StatusFile",			'S',		OI_NONE	},
268564562Sgshapiro	{ "SuperSafe",			's',		OI_SAFE	},
268664562Sgshapiro	{ "QueueTimeout",		'T',		OI_NONE	},
268764562Sgshapiro	{ "TimeZoneSpec",		't',		OI_NONE	},
268864562Sgshapiro	{ "UserDatabaseSpec",		'U',		OI_NONE	},
268964562Sgshapiro	{ "DefaultUser",		'u',		OI_NONE	},
269064562Sgshapiro	{ "FallbackMXhost",		'V',		OI_NONE	},
269164562Sgshapiro	{ "Verbose",			'v',		OI_SAFE	},
269264562Sgshapiro	{ "TryNullMXList",		'w',		OI_NONE	},
269364562Sgshapiro	{ "QueueLA",			'x',		OI_NONE	},
269464562Sgshapiro	{ "RefuseLA",			'X',		OI_NONE	},
269564562Sgshapiro	{ "RecipientFactor",		'y',		OI_NONE	},
269664562Sgshapiro	{ "ForkEachJob",		'Y',		OI_NONE	},
269764562Sgshapiro	{ "ClassFactor",		'z',		OI_NONE	},
269864562Sgshapiro	{ "RetryFactor",		'Z',		OI_NONE	},
269938032Speter#define O_QUEUESORTORD	0x81
270064562Sgshapiro	{ "QueueSortOrder",		O_QUEUESORTORD,	OI_SAFE	},
270138032Speter#define O_HOSTSFILE	0x82
270264562Sgshapiro	{ "HostsFile",			O_HOSTSFILE,	OI_NONE	},
270338032Speter#define O_MQA		0x83
270464562Sgshapiro	{ "MinQueueAge",		O_MQA,		OI_SAFE	},
270538032Speter#define O_DEFCHARSET	0x85
270664562Sgshapiro	{ "DefaultCharSet",		O_DEFCHARSET,	OI_SAFE	},
270738032Speter#define O_SSFILE	0x86
270864562Sgshapiro	{ "ServiceSwitchFile",		O_SSFILE,	OI_NONE	},
270938032Speter#define O_DIALDELAY	0x87
271064562Sgshapiro	{ "DialDelay",			O_DIALDELAY,	OI_SAFE	},
271138032Speter#define O_NORCPTACTION	0x88
271264562Sgshapiro	{ "NoRecipientAction",		O_NORCPTACTION,	OI_SAFE	},
271338032Speter#define O_SAFEFILEENV	0x89
271464562Sgshapiro	{ "SafeFileEnvironment",	O_SAFEFILEENV,	OI_NONE	},
271538032Speter#define O_MAXMSGSIZE	0x8a
271664562Sgshapiro	{ "MaxMessageSize",		O_MAXMSGSIZE,	OI_NONE	},
271738032Speter#define O_COLONOKINADDR	0x8b
271864562Sgshapiro	{ "ColonOkInAddr",		O_COLONOKINADDR, OI_SAFE },
271938032Speter#define O_MAXQUEUERUN	0x8c
272064562Sgshapiro	{ "MaxQueueRunSize",		O_MAXQUEUERUN,	OI_SAFE	},
272138032Speter#define O_MAXCHILDREN	0x8d
272264562Sgshapiro	{ "MaxDaemonChildren",		O_MAXCHILDREN,	OI_NONE	},
272338032Speter#define O_KEEPCNAMES	0x8e
272464562Sgshapiro	{ "DontExpandCnames",		O_KEEPCNAMES,	OI_NONE	},
272538032Speter#define O_MUSTQUOTE	0x8f
272664562Sgshapiro	{ "MustQuoteChars",		O_MUSTQUOTE,	OI_NONE	},
272738032Speter#define O_SMTPGREETING	0x90
272864562Sgshapiro	{ "SmtpGreetingMessage",	O_SMTPGREETING,	OI_NONE	},
272938032Speter#define O_UNIXFROM	0x91
273064562Sgshapiro	{ "UnixFromLine",		O_UNIXFROM,	OI_NONE	},
273138032Speter#define O_OPCHARS	0x92
273264562Sgshapiro	{ "OperatorChars",		O_OPCHARS,	OI_NONE	},
273338032Speter#define O_DONTINITGRPS	0x93
273464562Sgshapiro	{ "DontInitGroups",		O_DONTINITGRPS,	OI_NONE	},
273538032Speter#define O_SLFH		0x94
273664562Sgshapiro	{ "SingleLineFromHeader",	O_SLFH,		OI_SAFE	},
273738032Speter#define O_ABH		0x95
273864562Sgshapiro	{ "AllowBogusHELO",		O_ABH,		OI_SAFE	},
273938032Speter#define O_CONNTHROT	0x97
274064562Sgshapiro	{ "ConnectionRateThrottle",	O_CONNTHROT,	OI_NONE	},
274138032Speter#define O_UGW		0x99
274264562Sgshapiro	{ "UnsafeGroupWrites",		O_UGW,		OI_NONE	},
274338032Speter#define O_DBLBOUNCE	0x9a
274464562Sgshapiro	{ "DoubleBounceAddress",	O_DBLBOUNCE,	OI_NONE	},
274538032Speter#define O_HSDIR		0x9b
274664562Sgshapiro	{ "HostStatusDirectory",	O_HSDIR,	OI_NONE	},
274738032Speter#define O_SINGTHREAD	0x9c
274864562Sgshapiro	{ "SingleThreadDelivery",	O_SINGTHREAD,	OI_NONE	},
274938032Speter#define O_RUNASUSER	0x9d
275064562Sgshapiro	{ "RunAsUser",			O_RUNASUSER,	OI_NONE	},
275138032Speter#define O_DSN_RRT	0x9e
275264562Sgshapiro	{ "RrtImpliesDsn",		O_DSN_RRT,	OI_NONE	},
275338032Speter#define O_PIDFILE	0x9f
275464562Sgshapiro	{ "PidFile",			O_PIDFILE,	OI_NONE	},
275538032Speter#define O_DONTBLAMESENDMAIL	0xa0
275664562Sgshapiro	{ "DontBlameSendmail",		O_DONTBLAMESENDMAIL,	OI_NONE	},
275738032Speter#define O_DPI		0xa1
275864562Sgshapiro	{ "DontProbeInterfaces",	O_DPI,		OI_NONE	},
275938032Speter#define O_MAXRCPT	0xa2
276064562Sgshapiro	{ "MaxRecipientsPerMessage",	O_MAXRCPT,	OI_SAFE	},
276138032Speter#define O_DEADLETTER	0xa3
276264562Sgshapiro	{ "DeadLetterDrop",		O_DEADLETTER,	OI_NONE	},
276338032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
276464562Sgshapiro# define O_DONTLOCK	0xa4
276564562Sgshapiro	{ "DontLockFilesForRead",	O_DONTLOCK,	OI_NONE	},
2766363466Sgshapiro#endif
276738032Speter#define O_MAXALIASRCSN	0xa5
276864562Sgshapiro	{ "MaxAliasRecursion",		O_MAXALIASRCSN,	OI_NONE	},
276938032Speter#define O_CNCTONLYTO	0xa6
277064562Sgshapiro	{ "ConnectOnlyTo",		O_CNCTONLYTO,	OI_NONE	},
277142575Speter#define O_TRUSTUSER	0xa7
277264562Sgshapiro	{ "TrustedUser",		O_TRUSTUSER,	OI_NONE	},
277342575Speter#define O_MAXMIMEHDRLEN	0xa8
277464562Sgshapiro	{ "MaxMimeHeaderLength",	O_MAXMIMEHDRLEN,	OI_NONE	},
277542575Speter#define O_CONTROLSOCKET	0xa9
277664562Sgshapiro	{ "ControlSocketName",		O_CONTROLSOCKET,	OI_NONE	},
277743730Speter#define O_MAXHDRSLEN	0xaa
277864562Sgshapiro	{ "MaxHeadersLength",		O_MAXHDRSLEN,	OI_NONE	},
277964562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
278064562Sgshapiro# define O_MAXFORWARD	0xab
278164562Sgshapiro	{ "MaxForwardEntries",		O_MAXFORWARD,	OI_NONE	},
2782363466Sgshapiro#endif
278364562Sgshapiro#define O_PROCTITLEPREFIX	0xac
278464562Sgshapiro	{ "ProcessTitlePrefix",		O_PROCTITLEPREFIX,	OI_NONE	},
278564562Sgshapiro#define O_SASLINFO	0xad
278664562Sgshapiro#if _FFR_ALLOW_SASLINFO
278764562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_SAFE	},
2788363466Sgshapiro#else
278964562Sgshapiro	{ "DefaultAuthInfo",		O_SASLINFO,	OI_NONE	},
2790363466Sgshapiro#endif
279164562Sgshapiro#define O_SASLMECH	0xae
279264562Sgshapiro	{ "AuthMechanisms",		O_SASLMECH,	OI_NONE	},
279364562Sgshapiro#define O_CLIENTPORT	0xaf
279464562Sgshapiro	{ "ClientPortOptions",		O_CLIENTPORT,	OI_NONE	},
279564562Sgshapiro#define O_DF_BUFSIZE	0xb0
279664562Sgshapiro	{ "DataFileBufferSize",		O_DF_BUFSIZE,	OI_NONE	},
279764562Sgshapiro#define O_XF_BUFSIZE	0xb1
279864562Sgshapiro	{ "XscriptFileBufferSize",	O_XF_BUFSIZE,	OI_NONE	},
279990792Sgshapiro#define O_LDAPDEFAULTSPEC	0xb2
280064562Sgshapiro	{ "LDAPDefaultSpec",		O_LDAPDEFAULTSPEC,	OI_NONE	},
280190792Sgshapiro#define O_SRVCERTFILE	0xb4
280264562Sgshapiro	{ "ServerCertFile",		O_SRVCERTFILE,	OI_NONE	},
280390792Sgshapiro#define O_SRVKEYFILE	0xb5
2804102528Sgshapiro	{ "ServerKeyFile",		O_SRVKEYFILE,	OI_NONE	},
280590792Sgshapiro#define O_CLTCERTFILE	0xb6
280664562Sgshapiro	{ "ClientCertFile",		O_CLTCERTFILE,	OI_NONE	},
280790792Sgshapiro#define O_CLTKEYFILE	0xb7
2808102528Sgshapiro	{ "ClientKeyFile",		O_CLTKEYFILE,	OI_NONE	},
280990792Sgshapiro#define O_CACERTFILE	0xb8
2810110560Sgshapiro	{ "CACertFile",			O_CACERTFILE,	OI_NONE	},
281190792Sgshapiro#define O_CACERTPATH	0xb9
2812110560Sgshapiro	{ "CACertPath",			O_CACERTPATH,	OI_NONE	},
281390792Sgshapiro#define O_DHPARAMS	0xba
281464562Sgshapiro	{ "DHParameters",		O_DHPARAMS,	OI_NONE	},
281564562Sgshapiro#define O_INPUTMILTER	0xbb
281664562Sgshapiro	{ "InputMailFilters",		O_INPUTMILTER,	OI_NONE	},
281764562Sgshapiro#define O_MILTER	0xbc
281864562Sgshapiro	{ "Milter",			O_MILTER,	OI_SUBOPT	},
281964562Sgshapiro#define O_SASLOPTS	0xbd
282064562Sgshapiro	{ "AuthOptions",		O_SASLOPTS,	OI_NONE	},
282164562Sgshapiro#define O_QUEUE_FILE_MODE	0xbe
282264562Sgshapiro	{ "QueueFileMode",		O_QUEUE_FILE_MODE, OI_NONE	},
2823285229Sgshapiro#define O_DIG_ALG	0xbf
2824285229Sgshapiro	{ "CertFingerprintAlgorithm",		O_DIG_ALG,	OI_NONE	},
2825285229Sgshapiro#define O_CIPHERLIST	0xc0
282664562Sgshapiro	{ "CipherList",			O_CIPHERLIST,	OI_NONE	},
282790792Sgshapiro#define O_RANDFILE	0xc1
282864562Sgshapiro	{ "RandFile",			O_RANDFILE,	OI_NONE	},
282990792Sgshapiro#define O_TLS_SRV_OPTS	0xc2
283090792Sgshapiro	{ "TLSSrvOptions",		O_TLS_SRV_OPTS,	OI_NONE	},
283190792Sgshapiro#define O_RCPTTHROT	0xc3
283290792Sgshapiro	{ "BadRcptThrottle",		O_RCPTTHROT,	OI_SAFE	},
283390792Sgshapiro#define O_DLVR_MIN	0xc4
283490792Sgshapiro	{ "DeliverByMin",		O_DLVR_MIN,	OI_NONE	},
283590792Sgshapiro#define O_MAXQUEUECHILDREN	0xc5
283690792Sgshapiro	{ "MaxQueueChildren",		O_MAXQUEUECHILDREN,	OI_NONE	},
283790792Sgshapiro#define O_MAXRUNNERSPERQUEUE	0xc6
283890792Sgshapiro	{ "MaxRunnersPerQueue",		O_MAXRUNNERSPERQUEUE,	OI_NONE },
283990792Sgshapiro#define O_DIRECTSUBMODIFIERS	0xc7
284090792Sgshapiro	{ "DirectSubmissionModifiers",	O_DIRECTSUBMODIFIERS,	OI_NONE },
284190792Sgshapiro#define O_NICEQUEUERUN	0xc8
284290792Sgshapiro	{ "NiceQueueRun",		O_NICEQUEUERUN,	OI_NONE	},
284390792Sgshapiro#define O_SHMKEY	0xc9
284490792Sgshapiro	{ "SharedMemoryKey",		O_SHMKEY,	OI_NONE	},
284590792Sgshapiro#define O_SASLBITS	0xca
284690792Sgshapiro	{ "AuthMaxBits",		O_SASLBITS,	OI_NONE	},
284790792Sgshapiro#define O_MBDB		0xcb
284890792Sgshapiro	{ "MailboxDatabase",		O_MBDB,		OI_NONE	},
284990792Sgshapiro#define O_MSQ		0xcc
285090792Sgshapiro	{ "UseMSP",	O_MSQ,		OI_NONE	},
285190792Sgshapiro#define O_DELAY_LA	0xcd
285290792Sgshapiro	{ "DelayLA",	O_DELAY_LA,	OI_NONE	},
285390792Sgshapiro#define O_FASTSPLIT	0xce
285490792Sgshapiro	{ "FastSplit",	O_FASTSPLIT,	OI_NONE	},
2855168515Sgshapiro#define O_SOFTBOUNCE	0xcf
285690792Sgshapiro	{ "SoftBounce",	O_SOFTBOUNCE,	OI_NONE	},
2857168515Sgshapiro#define O_SHMKEYFILE	0xd0
285894334Sgshapiro	{ "SharedMemoryKeyFile",	O_SHMKEYFILE,	OI_NONE	},
2859132943Sgshapiro#define O_REJECTLOGINTERVAL	0xd1
2860110560Sgshapiro	{ "RejectLogInterval",	O_REJECTLOGINTERVAL,	OI_NONE	},
2861132943Sgshapiro#define O_REQUIRES_DIR_FSYNC	0xd2
2862110560Sgshapiro	{ "RequiresDirfsync",	O_REQUIRES_DIR_FSYNC,	OI_NONE	},
2863132943Sgshapiro#define O_CONNECTION_RATE_WINDOW_SIZE	0xd3
2864132943Sgshapiro	{ "ConnectionRateWindowSize", O_CONNECTION_RATE_WINDOW_SIZE, OI_NONE },
2865132943Sgshapiro#define O_CRLFILE	0xd4
2866132943Sgshapiro	{ "CRLFile",		O_CRLFILE,	OI_NONE	},
2867132943Sgshapiro#define O_FALLBACKSMARTHOST	0xd5
2868132943Sgshapiro	{ "FallbackSmartHost",		O_FALLBACKSMARTHOST,	OI_NONE	},
2869132943Sgshapiro#define O_SASLREALM	0xd6
2870132943Sgshapiro	{ "AuthRealm",		O_SASLREALM,	OI_NONE	},
2871363466Sgshapiro#define O_CRLPATH	0xd7
2872132943Sgshapiro	{ "CRLPath",		O_CRLPATH,	OI_NONE	},
2873168515Sgshapiro#define O_HELONAME 0xd8
2874132943Sgshapiro	{ "HeloName",   O_HELONAME,     OI_NONE },
2875157001Sgshapiro#if _FFR_MEMSTAT
2876157001Sgshapiro# define O_REFUSELOWMEM	0xd9
2877157001Sgshapiro	{ "RefuseLowMem",	O_REFUSELOWMEM,	OI_NONE },
2878157001Sgshapiro# define O_QUEUELOWMEM	0xda
2879157001Sgshapiro	{ "QueueLowMem",	O_QUEUELOWMEM,	OI_NONE },
2880157001Sgshapiro# define O_MEMRESOURCE	0xdb
2881157001Sgshapiro	{ "MemoryResource",	O_MEMRESOURCE,	OI_NONE },
2882157001Sgshapiro#endif /* _FFR_MEMSTAT */
2883168515Sgshapiro#define O_MAXNOOPCOMMANDS 0xdc
2884157001Sgshapiro	{ "MaxNOOPCommands",	O_MAXNOOPCOMMANDS,	OI_NONE },
2885157001Sgshapiro#if _FFR_MSG_ACCEPT
2886157001Sgshapiro# define O_MSG_ACCEPT 0xdd
2887157001Sgshapiro	{ "MessageAccept",	O_MSG_ACCEPT,	OI_NONE },
2888363466Sgshapiro#endif
2889157001Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA
2890157001Sgshapiro# define O_CHK_Q_RUNNERS 0xde
2891157001Sgshapiro	{ "CheckQueueRunners",	O_CHK_Q_RUNNERS,	OI_NONE },
2892363466Sgshapiro#endif
2893168515Sgshapiro#if _FFR_EIGHT_BIT_ADDR_OK
2894168515Sgshapiro# if !ALLOW_255
2895168515Sgshapiro#  ERROR FFR_EIGHT_BIT_ADDR_OK requires _ALLOW_255
2896363466Sgshapiro# endif
2897168515Sgshapiro# define O_EIGHT_BIT_ADDR_OK	0xdf
2898168515Sgshapiro	{ "EightBitAddrOK",	O_EIGHT_BIT_ADDR_OK,	OI_NONE },
2899168515Sgshapiro#endif /* _FFR_EIGHT_BIT_ADDR_OK */
2900173340Sgshapiro#if _FFR_ADDR_TYPE_MODES
2901173340Sgshapiro# define O_ADDR_TYPE_MODES	0xe0
2902173340Sgshapiro	{ "AddrTypeModes",	O_ADDR_TYPE_MODES,	OI_NONE },
2903363466Sgshapiro#endif
2904182352Sgshapiro#if _FFR_BADRCPT_SHUTDOWN
2905182352Sgshapiro# define O_RCPTSHUTD	0xe1
2906182352Sgshapiro	{ "BadRcptShutdown",		O_RCPTSHUTD,	OI_SAFE },
2907182352Sgshapiro# define O_RCPTSHUTDG	0xe2
2908182352Sgshapiro	{ "BadRcptShutdownGood",	O_RCPTSHUTDG,	OI_SAFE	},
2909182352Sgshapiro#endif /* _FFR_BADRCPT_SHUTDOWN */
2910285229Sgshapiro#define O_SRV_SSL_OPTIONS	0xe3
2911203004Sgshapiro	{ "ServerSSLOptions",		O_SRV_SSL_OPTIONS,	OI_NONE	},
2912285229Sgshapiro#define O_CLT_SSL_OPTIONS	0xe4
2913203004Sgshapiro	{ "ClientSSLOptions",		O_CLT_SSL_OPTIONS,	OI_NONE	},
2914285229Sgshapiro#define O_MAX_QUEUE_AGE	0xe5
2915203004Sgshapiro	{ "MaxQueueAge",	O_MAX_QUEUE_AGE,	OI_NONE },
2916203004Sgshapiro#if _FFR_RCPTTHROTDELAY
2917203004Sgshapiro# define O_RCPTTHROTDELAY	0xe6
2918203004Sgshapiro	{ "BadRcptThrottleDelay",	O_RCPTTHROTDELAY,	OI_SAFE	},
2919363466Sgshapiro#endif
2920223067Sgshapiro#if 0 && _FFR_QOS && defined(SOL_IP) && defined(IP_TOS)
2921223067Sgshapiro# define O_INETQOS	0xe7	/* reserved for FFR_QOS */
2922223067Sgshapiro	{ "InetQoS",			O_INETQOS,	OI_NONE },
2923223067Sgshapiro#endif
2924249729Sgshapiro#if STARTTLS && _FFR_FIPSMODE
2925249729Sgshapiro# define O_FIPSMODE	0xe8
2926249729Sgshapiro	{ "FIPSMode",		O_FIPSMODE,	OI_NONE	},
2927363466Sgshapiro#endif
2928249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
2929249729Sgshapiro# define O_REJECTNUL	0xe9
2930249729Sgshapiro	{ "RejectNUL",	O_REJECTNUL,	OI_SAFE	},
2931363466Sgshapiro#endif
2932285229Sgshapiro#if _FFR_BOUNCE_QUEUE
2933285229Sgshapiro# define O_BOUNCEQUEUE 0xea
2934285229Sgshapiro	{ "BounceQueue",		O_BOUNCEQUEUE,	OI_NONE },
2935363466Sgshapiro#endif
2936285229Sgshapiro#if _FFR_ADD_BCC
2937285229Sgshapiro# define O_ADDBCC 0xeb
2938285229Sgshapiro	{ "AddBcc",			O_ADDBCC,	OI_NONE },
2939285229Sgshapiro#endif
2940285229Sgshapiro#define O_USECOMPRESSEDIPV6ADDRESSES 0xec
2941285229Sgshapiro	{ "UseCompressedIPv6Addresses",	O_USECOMPRESSEDIPV6ADDRESSES, OI_NONE },
2942363466Sgshapiro#if STARTTLS
2943363466Sgshapiro# define O_SSLENGINE	0xed
2944363466Sgshapiro	{ "SSLEngine",		O_SSLENGINE,	OI_NONE	},
2945363466Sgshapiro# define O_SSLENGINEPATH	0xee
2946363466Sgshapiro	{ "SSLEnginePath",	O_SSLENGINEPATH,	OI_NONE	},
2947363466Sgshapiro# define O_TLSFB2CLEAR		0xef
2948363466Sgshapiro	{ "TLSFallbacktoClear",	O_TLSFB2CLEAR,	OI_NONE	},
2949363466Sgshapiro#endif
2950363466Sgshapiro#if DNSSEC_TEST
2951363466Sgshapiro# define O_NSPORTIP		0xf0
2952363466Sgshapiro	{ "NameServer",	O_NSPORTIP,	OI_NONE	},
2953363466Sgshapiro#endif
2954363466Sgshapiro#if DANE
2955363466Sgshapiro# define O_DANE		0xf1
2956363466Sgshapiro	{ "DANE",	O_DANE,	OI_NONE	},
2957363466Sgshapiro#endif
2958363466Sgshapiro#if DNSSEC_TEST
2959363466Sgshapiro# define O_NSSRCHLIST		0xf2
2960363466Sgshapiro	{ "NameSearchList",	O_NSSRCHLIST,	OI_NONE	},
2961363466Sgshapiro#endif
2962363466Sgshapiro#if _FFR_BLANKENV_MACV
2963363466Sgshapiro# define O_HACKS	0xf4
2964363466Sgshapiro	{ "Hacks",		O_HACKS,	OI_NONE	},
2965363466Sgshapiro#endif
2966363466Sgshapiro#if _FFR_KEEPBCC
2967363466Sgshapiro# define O_KEEPBCC	0xf3
2968363466Sgshapiro	{ "KeepBcc",		O_KEEPBCC,	OI_NONE	},
2969363466Sgshapiro#endif
2970132943Sgshapiro
2971363466Sgshapiro#if _FFR_CLIENTCA
2972363466Sgshapiro#define O_CLTCACERTFILE	0xf5
2973363466Sgshapiro	{ "ClientCACertFile",			O_CLTCACERTFILE, OI_NONE },
2974363466Sgshapiro#define O_CLTCACERTPATH	0xf6
2975363466Sgshapiro	{ "ClientCACertPath",			O_CLTCACERTPATH, OI_NONE },
2976363466Sgshapiro#endif
2977363466Sgshapiro#if _FFR_TLS_ALTNAMES
2978363466Sgshapiro# define O_CHECKALTNAMES 0xf7
2979363466Sgshapiro	{ "SetCertAltnames",			O_CHECKALTNAMES, OI_NONE },
2980363466Sgshapiro#endif
2981363466Sgshapiro
298264562Sgshapiro	{ NULL,				'\0',		OI_NONE	}
298338032Speter};
298438032Speter
298590792Sgshapiro# define CANONIFY(val)
298690792Sgshapiro
298790792Sgshapiro# define SET_OPT_DEFAULT(opt, val)	opt = val
298890792Sgshapiro
298990792Sgshapiro/* set a string option by expanding the value and assigning it */
299090792Sgshapiro/* WARNING this belongs ONLY into a case statement! */
299190792Sgshapiro#define SET_STRING_EXP(str)	\
2992168515Sgshapiro		expand(val, exbuf, sizeof(exbuf), e);	\
299390792Sgshapiro		newval = sm_pstrdup_x(exbuf);		\
299490792Sgshapiro		if (str != NULL)	\
299590792Sgshapiro			sm_free(str);	\
299690792Sgshapiro		CANONIFY(newval);	\
299790792Sgshapiro		str = newval;		\
299890792Sgshapiro		break
299990792Sgshapiro
300090792Sgshapiro#define OPTNAME	o->o_name == NULL ? "<unknown>" : o->o_name
300190792Sgshapiro
300238032Spetervoid
300338032Spetersetoption(opt, val, safe, sticky, e)
300438032Speter	int opt;
300538032Speter	char *val;
300638032Speter	bool safe;
300738032Speter	bool sticky;
300838032Speter	register ENVELOPE *e;
300938032Speter{
301038032Speter	register char *p;
301138032Speter	register struct optioninfo *o;
301238032Speter	char *subopt;
3013363466Sgshapiro	int i;
301438032Speter	bool can_setuid = RunAsUid == 0;
301538032Speter	auto char *ep;
301638032Speter	char buf[50];
301738032Speter	extern bool Warn_Q_option;
301864562Sgshapiro#if _FFR_ALLOW_SASLINFO
301990792Sgshapiro	extern unsigned int SubmitMode;
3020363466Sgshapiro#endif
3021168515Sgshapiro#if STARTTLS || SM_CONF_SHM
302290792Sgshapiro	char *newval;
302390792Sgshapiro	char exbuf[MAXLINE];
3024363466Sgshapiro#endif
3025285229Sgshapiro#if STARTTLS
3026285229Sgshapiro	unsigned long *pssloptions = NULL;
3027285229Sgshapiro#endif
302838032Speter
302938032Speter	errno = 0;
303038032Speter	if (opt == ' ')
303138032Speter	{
303238032Speter		/* full word options */
303338032Speter		struct optioninfo *sel;
303438032Speter
303538032Speter		p = strchr(val, '=');
303638032Speter		if (p == NULL)
303738032Speter			p = &val[strlen(val)];
303838032Speter		while (*--p == ' ')
303938032Speter			continue;
304038032Speter		while (*++p == ' ')
304138032Speter			*p = '\0';
304238032Speter		if (p == val)
304338032Speter		{
304438032Speter			syserr("readcf: null option name");
304538032Speter			return;
304638032Speter		}
304738032Speter		if (*p == '=')
304838032Speter			*p++ = '\0';
304938032Speter		while (*p == ' ')
305038032Speter			p++;
305138032Speter		subopt = strchr(val, '.');
305238032Speter		if (subopt != NULL)
305338032Speter			*subopt++ = '\0';
305438032Speter		sel = NULL;
305538032Speter		for (o = OptionTab; o->o_name != NULL; o++)
305638032Speter		{
305790792Sgshapiro			if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0)
305838032Speter				continue;
305938032Speter			if (strlen(o->o_name) == strlen(val))
306038032Speter			{
306138032Speter				/* completely specified -- this must be it */
306238032Speter				sel = NULL;
306338032Speter				break;
306438032Speter			}
306538032Speter			if (sel != NULL)
306638032Speter				break;
306738032Speter			sel = o;
306838032Speter		}
306938032Speter		if (sel != NULL && o->o_name == NULL)
307038032Speter			o = sel;
307138032Speter		else if (o->o_name == NULL)
307238032Speter		{
307338032Speter			syserr("readcf: unknown option name %s", val);
307438032Speter			return;
307538032Speter		}
307638032Speter		else if (sel != NULL)
307738032Speter		{
307838032Speter			syserr("readcf: ambiguous option name %s (matches %s and %s)",
307938032Speter				val, sel->o_name, o->o_name);
308038032Speter			return;
308138032Speter		}
308238032Speter		if (strlen(val) != strlen(o->o_name))
308338032Speter		{
308438032Speter			int oldVerbose = Verbose;
308538032Speter
308638032Speter			Verbose = 1;
308738032Speter			message("Option %s used as abbreviation for %s",
308838032Speter				val, o->o_name);
308938032Speter			Verbose = oldVerbose;
309038032Speter		}
309138032Speter		opt = o->o_code;
309238032Speter		val = p;
309338032Speter	}
309438032Speter	else
309538032Speter	{
309638032Speter		for (o = OptionTab; o->o_name != NULL; o++)
309738032Speter		{
309838032Speter			if (o->o_code == opt)
309938032Speter				break;
310038032Speter		}
310190792Sgshapiro		if (o->o_name == NULL)
310290792Sgshapiro		{
310390792Sgshapiro			syserr("readcf: unknown option name 0x%x", opt & 0xff);
310490792Sgshapiro			return;
310590792Sgshapiro		}
310638032Speter		subopt = NULL;
310738032Speter	}
310838032Speter
310964562Sgshapiro	if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
311064562Sgshapiro	{
311164562Sgshapiro		if (tTd(37, 1))
311290792Sgshapiro			sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
311390792Sgshapiro				   OPTNAME, subopt);
311464562Sgshapiro		subopt = NULL;
311564562Sgshapiro	}
311664562Sgshapiro
311738032Speter	if (tTd(37, 1))
311838032Speter	{
311990792Sgshapiro		sm_dprintf(isascii(opt) && isprint(opt) ?
312090792Sgshapiro			   "setoption %s (%c)%s%s=" :
312190792Sgshapiro			   "setoption %s (0x%x)%s%s=",
312290792Sgshapiro			   OPTNAME, opt, subopt == NULL ? "" : ".",
312390792Sgshapiro			   subopt == NULL ? "" : subopt);
3124132943Sgshapiro		xputs(sm_debug_file(), val);
312538032Speter	}
312638032Speter
312738032Speter	/*
312838032Speter	**  See if this option is preset for us.
312938032Speter	*/
313038032Speter
313138032Speter	if (!sticky && bitnset(opt, StickyOpt))
313238032Speter	{
313338032Speter		if (tTd(37, 1))
313490792Sgshapiro			sm_dprintf(" (ignored)\n");
313538032Speter		return;
313638032Speter	}
313738032Speter
313838032Speter	/*
313938032Speter	**  Check to see if this option can be specified by this user.
314038032Speter	*/
314138032Speter
314238032Speter	if (!safe && RealUid == 0)
314390792Sgshapiro		safe = true;
314464562Sgshapiro	if (!safe && !bitset(OI_SAFE, o->o_flags))
314538032Speter	{
314638032Speter		if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
314738032Speter		{
314864562Sgshapiro			int dp;
314964562Sgshapiro
315038032Speter			if (tTd(37, 1))
315190792Sgshapiro				sm_dprintf(" (unsafe)");
315290792Sgshapiro			dp = drop_privileges(true);
315364562Sgshapiro			setstat(dp);
315438032Speter		}
315538032Speter	}
315638032Speter	if (tTd(37, 1))
315790792Sgshapiro		sm_dprintf("\n");
315838032Speter
315938032Speter	switch (opt & 0xff)
316038032Speter	{
316138032Speter	  case '7':		/* force seven-bit input */
316238032Speter		SevenBitInput = atobool(val);
316338032Speter		break;
316438032Speter
316577349Sgshapiro	  case '8':		/* handling of 8-bit input */
316638032Speter#if MIME8TO7
316738032Speter		switch (*val)
316838032Speter		{
316990792Sgshapiro		  case 'p':		/* pass 8 bit, convert MIME */
317090792Sgshapiro			MimeMode = MM_CVTMIME|MM_PASS8BIT;
317190792Sgshapiro			break;
317290792Sgshapiro
317338032Speter		  case 'm':		/* convert 8-bit, convert MIME */
317438032Speter			MimeMode = MM_CVTMIME|MM_MIME8BIT;
317538032Speter			break;
317638032Speter
317738032Speter		  case 's':		/* strict adherence */
317838032Speter			MimeMode = MM_CVTMIME;
317938032Speter			break;
318038032Speter
318164562Sgshapiro# if 0
318238032Speter		  case 'r':		/* reject 8-bit, don't convert MIME */
318338032Speter			MimeMode = 0;
318438032Speter			break;
318538032Speter
318638032Speter		  case 'j':		/* "just send 8" */
318738032Speter			MimeMode = MM_PASS8BIT;
318838032Speter			break;
318938032Speter
319038032Speter		  case 'a':		/* encode 8 bit if available */
319138032Speter			MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
319238032Speter			break;
319338032Speter
319438032Speter		  case 'c':		/* convert 8 bit to MIME, never 7 bit */
319538032Speter			MimeMode = MM_MIME8BIT;
319638032Speter			break;
319764562Sgshapiro# endif /* 0 */
319838032Speter
319938032Speter		  default:
320038032Speter			syserr("Unknown 8-bit mode %c", *val);
320190792Sgshapiro			finis(false, true, EX_USAGE);
320238032Speter		}
320377349Sgshapiro#else /* MIME8TO7 */
320490792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
320590792Sgshapiro				     "Warning: Option: %s requires MIME8TO7 support\n",
320690792Sgshapiro				     OPTNAME);
320777349Sgshapiro#endif /* MIME8TO7 */
320838032Speter		break;
320938032Speter
321038032Speter	  case 'A':		/* set default alias file */
321138032Speter		if (val[0] == '\0')
321290792Sgshapiro		{
321390792Sgshapiro			char *al;
321490792Sgshapiro
321590792Sgshapiro			SET_OPT_DEFAULT(al, "aliases");
321690792Sgshapiro			setalias(al);
321790792Sgshapiro		}
321838032Speter		else
321938032Speter			setalias(val);
322038032Speter		break;
322138032Speter
322238032Speter	  case 'a':		/* look N minutes for "@:@" in alias file */
322338032Speter		if (val[0] == '\0')
322490792Sgshapiro			SafeAlias = 5 MINUTES;
322538032Speter		else
322638032Speter			SafeAlias = convtime(val, 'm');
322738032Speter		break;
322838032Speter
322938032Speter	  case 'B':		/* substitution for blank character */
323038032Speter		SpaceSub = val[0];
323138032Speter		if (SpaceSub == '\0')
323238032Speter			SpaceSub = ' ';
323338032Speter		break;
323438032Speter
323538032Speter	  case 'b':		/* min blocks free on queue fs/max msg size */
323638032Speter		p = strchr(val, '/');
323738032Speter		if (p != NULL)
323838032Speter		{
323938032Speter			*p++ = '\0';
324038032Speter			MaxMessageSize = atol(p);
324138032Speter		}
324238032Speter		MinBlocksFree = atol(val);
324338032Speter		break;
324438032Speter
324538032Speter	  case 'c':		/* don't connect to "expensive" mailers */
324638032Speter		NoConnect = atobool(val);
324738032Speter		break;
324838032Speter
324938032Speter	  case 'C':		/* checkpoint every N addresses */
3250132943Sgshapiro		if (safe || CheckpointInterval > atoi(val))
3251132943Sgshapiro			CheckpointInterval = atoi(val);
325238032Speter		break;
325338032Speter
325438032Speter	  case 'd':		/* delivery mode */
325538032Speter		switch (*val)
325638032Speter		{
325738032Speter		  case '\0':
325864562Sgshapiro			set_delivery_mode(SM_DELIVER, e);
325938032Speter			break;
326038032Speter
326138032Speter		  case SM_QUEUE:	/* queue only */
326238032Speter		  case SM_DEFER:	/* queue only and defer map lookups */
326338032Speter		  case SM_DELIVER:	/* do everything */
326438032Speter		  case SM_FORK:		/* fork after verification */
3265157001Sgshapiro#if _FFR_DM_ONE
3266157001Sgshapiro		/* deliver first TA in background, then queue */
3267157001Sgshapiro		  case SM_DM_ONE:
3268363466Sgshapiro#endif
326964562Sgshapiro			set_delivery_mode(*val, e);
327038032Speter			break;
327138032Speter
3272285229Sgshapiro#if _FFR_PROXY
3273285229Sgshapiro		  case SM_PROXY_REQ:
3274285229Sgshapiro			set_delivery_mode(*val, e);
3275285229Sgshapiro			break;
3276285229Sgshapiro#endif /* _FFR_PROXY */
3277223067Sgshapiro
327838032Speter		  default:
327938032Speter			syserr("Unknown delivery mode %c", *val);
328090792Sgshapiro			finis(false, true, EX_USAGE);
328138032Speter		}
328238032Speter		break;
328338032Speter
328438032Speter	  case 'E':		/* error message header/header file */
328538032Speter		if (*val != '\0')
328638032Speter			ErrMsgFile = newstr(val);
328738032Speter		break;
328838032Speter
328938032Speter	  case 'e':		/* set error processing mode */
329038032Speter		switch (*val)
329138032Speter		{
329238032Speter		  case EM_QUIET:	/* be silent about it */
329338032Speter		  case EM_MAIL:		/* mail back */
329438032Speter		  case EM_BERKNET:	/* do berknet error processing */
329538032Speter		  case EM_WRITE:	/* write back (or mail) */
329638032Speter		  case EM_PRINT:	/* print errors normally (default) */
329738032Speter			e->e_errormode = *val;
329838032Speter			break;
329938032Speter		}
330038032Speter		break;
330138032Speter
330238032Speter	  case 'F':		/* file mode */
330338032Speter		FileMode = atooct(val) & 0777;
330438032Speter		break;
330538032Speter
330638032Speter	  case 'f':		/* save Unix-style From lines on front */
330738032Speter		SaveFrom = atobool(val);
330838032Speter		break;
330938032Speter
331038032Speter	  case 'G':		/* match recipients against GECOS field */
331138032Speter		MatchGecos = atobool(val);
331238032Speter		break;
331338032Speter
331438032Speter	  case 'g':		/* default gid */
331538032Speter  g_opt:
331638032Speter		if (isascii(*val) && isdigit(*val))
331738032Speter			DefGid = atoi(val);
331838032Speter		else
331938032Speter		{
332038032Speter			register struct group *gr;
332138032Speter
332238032Speter			DefGid = -1;
332338032Speter			gr = getgrnam(val);
332438032Speter			if (gr == NULL)
332538032Speter				syserr("readcf: option %c: unknown group %s",
332638032Speter					opt, val);
332738032Speter			else
332838032Speter				DefGid = gr->gr_gid;
332938032Speter		}
333038032Speter		break;
333138032Speter
333238032Speter	  case 'H':		/* help file */
333338032Speter		if (val[0] == '\0')
333490792Sgshapiro		{
333590792Sgshapiro			SET_OPT_DEFAULT(HelpFile, "helpfile");
333690792Sgshapiro		}
333738032Speter		else
333873188Sgshapiro		{
333990792Sgshapiro			CANONIFY(val);
334038032Speter			HelpFile = newstr(val);
334173188Sgshapiro		}
334238032Speter		break;
334338032Speter
334438032Speter	  case 'h':		/* maximum hop count */
334538032Speter		MaxHopCount = atoi(val);
334638032Speter		break;
334738032Speter
334838032Speter	  case 'I':		/* use internet domain name server */
334938032Speter#if NAMED_BIND
335038032Speter		for (p = val; *p != 0; )
335138032Speter		{
335238032Speter			bool clearmode;
335338032Speter			char *q;
335438032Speter			struct resolverflags *rfp;
335538032Speter
335638032Speter			while (*p == ' ')
335738032Speter				p++;
335838032Speter			if (*p == '\0')
335938032Speter				break;
336090792Sgshapiro			clearmode = false;
336138032Speter			if (*p == '-')
336290792Sgshapiro				clearmode = true;
336338032Speter			else if (*p != '+')
336438032Speter				p--;
336538032Speter			p++;
336638032Speter			q = p;
3367363466Sgshapiro			while (*p != '\0' && !(SM_ISSPACE(*p)))
336838032Speter				p++;
336938032Speter			if (*p != '\0')
337038032Speter				*p++ = '\0';
337190792Sgshapiro			if (sm_strcasecmp(q, "HasWildcardMX") == 0)
337238032Speter			{
337338032Speter				HasWildcardMX = !clearmode;
337438032Speter				continue;
337538032Speter			}
337673188Sgshapiro			if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
337773188Sgshapiro			{
337873188Sgshapiro				WorkAroundBrokenAAAA = !clearmode;
337973188Sgshapiro				continue;
338073188Sgshapiro			}
338138032Speter			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
338238032Speter			{
338390792Sgshapiro				if (sm_strcasecmp(q, rfp->rf_name) == 0)
338438032Speter					break;
338538032Speter			}
338638032Speter			if (rfp->rf_name == NULL)
338738032Speter				syserr("readcf: I option value %s unrecognized", q);
338838032Speter			else if (clearmode)
338938032Speter				_res.options &= ~rfp->rf_bits;
339038032Speter			else
339138032Speter				_res.options |= rfp->rf_bits;
339238032Speter		}
339338032Speter		if (tTd(8, 2))
339490792Sgshapiro			sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
339590792Sgshapiro				   (unsigned int) _res.options, HasWildcardMX);
339664562Sgshapiro#else /* NAMED_BIND */
339738032Speter		usrerr("name server (I option) specified but BIND not compiled in");
339864562Sgshapiro#endif /* NAMED_BIND */
339938032Speter		break;
340038032Speter
340138032Speter	  case 'i':		/* ignore dot lines in message */
340238032Speter		IgnrDot = atobool(val);
340338032Speter		break;
340438032Speter
340538032Speter	  case 'j':		/* send errors in MIME (RFC 1341) format */
340638032Speter		SendMIMEErrors = atobool(val);
340738032Speter		break;
340838032Speter
340938032Speter	  case 'J':		/* .forward search path */
341090792Sgshapiro		CANONIFY(val);
341138032Speter		ForwardPath = newstr(val);
341238032Speter		break;
341338032Speter
341438032Speter	  case 'k':		/* connection cache size */
341538032Speter		MaxMciCache = atoi(val);
341638032Speter		if (MaxMciCache < 0)
341738032Speter			MaxMciCache = 0;
341838032Speter		break;
341938032Speter
342038032Speter	  case 'K':		/* connection cache timeout */
342138032Speter		MciCacheTimeout = convtime(val, 'm');
342238032Speter		break;
342338032Speter
342438032Speter	  case 'l':		/* use Errors-To: header */
342538032Speter		UseErrorsTo = atobool(val);
342638032Speter		break;
342738032Speter
342838032Speter	  case 'L':		/* log level */
342938032Speter		if (safe || LogLevel < atoi(val))
343038032Speter			LogLevel = atoi(val);
343138032Speter		break;
343238032Speter
343338032Speter	  case 'M':		/* define macro */
343490792Sgshapiro		sticky = false;
3435363466Sgshapiro		i = macid_parse(val, &ep);
3436363466Sgshapiro		if (i == 0)
343771345Sgshapiro			break;
343838032Speter		p = newstr(ep);
343938032Speter		if (!safe)
3440120256Sgshapiro			cleanstrcpy(p, p, strlen(p) + 1);
3441363466Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, i, p);
344238032Speter		break;
344338032Speter
344438032Speter	  case 'm':		/* send to me too */
344538032Speter		MeToo = atobool(val);
344638032Speter		break;
344738032Speter
344838032Speter	  case 'n':		/* validate RHS in newaliases */
344938032Speter		CheckAliases = atobool(val);
345038032Speter		break;
345138032Speter
345238032Speter	    /* 'N' available -- was "net name" */
345338032Speter
345438032Speter	  case 'O':		/* daemon options */
345564562Sgshapiro		if (!setdaemonoptions(val))
345664562Sgshapiro			syserr("too many daemons defined (%d max)", MAXDAEMONS);
345738032Speter		break;
345838032Speter
345938032Speter	  case 'o':		/* assume old style headers */
346038032Speter		if (atobool(val))
346138032Speter			CurEnv->e_flags |= EF_OLDSTYLE;
346238032Speter		else
346338032Speter			CurEnv->e_flags &= ~EF_OLDSTYLE;
346438032Speter		break;
346538032Speter
346638032Speter	  case 'p':		/* select privacy level */
346738032Speter		p = val;
346838032Speter		for (;;)
346938032Speter		{
347038032Speter			register struct prival *pv;
347138032Speter			extern struct prival PrivacyValues[];
347238032Speter
347338032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
347438032Speter				p++;
347538032Speter			if (*p == '\0')
347638032Speter				break;
347738032Speter			val = p;
347838032Speter			while (isascii(*p) && isalnum(*p))
347938032Speter				p++;
348038032Speter			if (*p != '\0')
348138032Speter				*p++ = '\0';
348238032Speter
348338032Speter			for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
348438032Speter			{
348590792Sgshapiro				if (sm_strcasecmp(val, pv->pv_name) == 0)
348638032Speter					break;
348738032Speter			}
348838032Speter			if (pv->pv_name == NULL)
348938032Speter				syserr("readcf: Op line: %s unrecognized", val);
349071345Sgshapiro			else
349171345Sgshapiro				PrivacyFlags |= pv->pv_flag;
349238032Speter		}
349390792Sgshapiro		sticky = false;
349438032Speter		break;
349538032Speter
349638032Speter	  case 'P':		/* postmaster copy address for returned mail */
349738032Speter		PostMasterCopy = newstr(val);
349838032Speter		break;
349938032Speter
350038032Speter	  case 'q':		/* slope of queue only function */
350138032Speter		QueueFactor = atoi(val);
350238032Speter		break;
350338032Speter
350438032Speter	  case 'Q':		/* queue directory */
350538032Speter		if (val[0] == '\0')
350666494Sgshapiro		{
350738032Speter			QueueDir = "mqueue";
350866494Sgshapiro		}
350938032Speter		else
351066494Sgshapiro		{
351138032Speter			QueueDir = newstr(val);
351266494Sgshapiro		}
351338032Speter		if (RealUid != 0 && !safe)
351490792Sgshapiro			Warn_Q_option = true;
351538032Speter		break;
351638032Speter
351738032Speter	  case 'R':		/* don't prune routes */
351838032Speter		DontPruneRoutes = atobool(val);
351938032Speter		break;
352038032Speter
352138032Speter	  case 'r':		/* read timeout */
352238032Speter		if (subopt == NULL)
352364562Sgshapiro			inittimeouts(val, sticky);
352438032Speter		else
352564562Sgshapiro			settimeout(subopt, val, sticky);
352638032Speter		break;
352738032Speter
352838032Speter	  case 'S':		/* status file */
352938032Speter		if (val[0] == '\0')
353090792Sgshapiro		{
353190792Sgshapiro			SET_OPT_DEFAULT(StatFile, "statistics");
353290792Sgshapiro		}
353338032Speter		else
353473188Sgshapiro		{
353590792Sgshapiro			CANONIFY(val);
353638032Speter			StatFile = newstr(val);
353773188Sgshapiro		}
353838032Speter		break;
353938032Speter
354038032Speter	  case 's':		/* be super safe, even if expensive */
354190792Sgshapiro		if (tolower(*val) == 'i')
354290792Sgshapiro			SuperSafe = SAFE_INTERACTIVE;
3543132943Sgshapiro		else if (tolower(*val) == 'p')
3544132943Sgshapiro#if MILTER
3545132943Sgshapiro			SuperSafe = SAFE_REALLY_POSTMILTER;
3546132943Sgshapiro#else /* MILTER */
3547132943Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3548132943Sgshapiro				"Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
3549132943Sgshapiro#endif /* MILTER */
355090792Sgshapiro		else
355190792Sgshapiro			SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO;
355238032Speter		break;
355338032Speter
355438032Speter	  case 'T':		/* queue timeout */
355538032Speter		p = strchr(val, '/');
355638032Speter		if (p != NULL)
355738032Speter		{
355838032Speter			*p++ = '\0';
355964562Sgshapiro			settimeout("queuewarn", p, sticky);
356038032Speter		}
356164562Sgshapiro		settimeout("queuereturn", val, sticky);
356238032Speter		break;
356338032Speter
356438032Speter	  case 't':		/* time zone name */
356538032Speter		TimeZoneSpec = newstr(val);
356638032Speter		break;
356738032Speter
356838032Speter	  case 'U':		/* location of user database */
356938032Speter		UdbSpec = newstr(val);
357038032Speter		break;
357138032Speter
357238032Speter	  case 'u':		/* set default uid */
357338032Speter		for (p = val; *p != '\0'; p++)
357438032Speter		{
357594334Sgshapiro# if _FFR_DOTTED_USERNAMES
357690792Sgshapiro			if (*p == '/' || *p == ':')
3577363466Sgshapiro# else
357838032Speter			if (*p == '.' || *p == '/' || *p == ':')
3579363466Sgshapiro# endif
358038032Speter			{
358138032Speter				*p++ = '\0';
358238032Speter				break;
358338032Speter			}
358438032Speter		}
358538032Speter		if (isascii(*val) && isdigit(*val))
358638032Speter		{
358738032Speter			DefUid = atoi(val);
358838032Speter			setdefuser();
358938032Speter		}
359038032Speter		else
359138032Speter		{
359238032Speter			register struct passwd *pw;
359338032Speter
359438032Speter			DefUid = -1;
359538032Speter			pw = sm_getpwnam(val);
359638032Speter			if (pw == NULL)
359771345Sgshapiro			{
359838032Speter				syserr("readcf: option u: unknown user %s", val);
359971345Sgshapiro				break;
360071345Sgshapiro			}
360138032Speter			else
360238032Speter			{
360338032Speter				DefUid = pw->pw_uid;
360438032Speter				DefGid = pw->pw_gid;
360538032Speter				DefUser = newstr(pw->pw_name);
360638032Speter			}
360738032Speter		}
360838032Speter
360990792Sgshapiro# ifdef UID_MAX
361038032Speter		if (DefUid > UID_MAX)
361138032Speter		{
361238032Speter			syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
361390792Sgshapiro				(long)DefUid, (long)UID_MAX);
361471345Sgshapiro			break;
361538032Speter		}
361690792Sgshapiro# endif /* UID_MAX */
361738032Speter
361838032Speter		/* handle the group if it is there */
361938032Speter		if (*p == '\0')
362038032Speter			break;
362138032Speter		val = p;
362238032Speter		goto g_opt;
362338032Speter
362438032Speter	  case 'V':		/* fallback MX host */
362538032Speter		if (val[0] != '\0')
3626132943Sgshapiro			FallbackMX = newstr(val);
362738032Speter		break;
362838032Speter
362938032Speter	  case 'v':		/* run in verbose mode */
363038032Speter		Verbose = atobool(val) ? 1 : 0;
363138032Speter		break;
363238032Speter
363338032Speter	  case 'w':		/* if we are best MX, try host directly */
363438032Speter		TryNullMXList = atobool(val);
363538032Speter		break;
363638032Speter
363738032Speter	    /* 'W' available -- was wizard password */
363838032Speter
363938032Speter	  case 'x':		/* load avg at which to auto-queue msgs */
364038032Speter		QueueLA = atoi(val);
364138032Speter		break;
364238032Speter
364390792Sgshapiro	  case 'X':	/* load avg at which to auto-reject connections */
364438032Speter		RefuseLA = atoi(val);
364538032Speter		break;
364638032Speter
364790792Sgshapiro	  case O_DELAY_LA:	/* load avg at which to delay connections */
364890792Sgshapiro		DelayLA = atoi(val);
364990792Sgshapiro		break;
365090792Sgshapiro
365138032Speter	  case 'y':		/* work recipient factor */
365238032Speter		WkRecipFact = atoi(val);
365338032Speter		break;
365438032Speter
365538032Speter	  case 'Y':		/* fork jobs during queue runs */
365638032Speter		ForkQueueRuns = atobool(val);
365738032Speter		break;
365838032Speter
365938032Speter	  case 'z':		/* work message class factor */
366038032Speter		WkClassFact = atoi(val);
366138032Speter		break;
366238032Speter
366338032Speter	  case 'Z':		/* work time factor */
366438032Speter		WkTimeFact = atoi(val);
366538032Speter		break;
366638032Speter
366764562Sgshapiro
366894334Sgshapiro#if _FFR_QUEUE_GROUP_SORTORDER
366994334Sgshapiro	/* coordinate this with makequeue() */
3670363466Sgshapiro#endif
367138032Speter	  case O_QUEUESORTORD:	/* queue sorting order */
367238032Speter		switch (*val)
367338032Speter		{
367490792Sgshapiro		  case 'f':	/* File Name */
367590792Sgshapiro		  case 'F':
367690792Sgshapiro			QueueSortOrder = QSO_BYFILENAME;
367790792Sgshapiro			break;
367890792Sgshapiro
367938032Speter		  case 'h':	/* Host first */
368038032Speter		  case 'H':
368164562Sgshapiro			QueueSortOrder = QSO_BYHOST;
368238032Speter			break;
368338032Speter
368490792Sgshapiro		  case 'm':	/* Modification time */
368590792Sgshapiro		  case 'M':
368690792Sgshapiro			QueueSortOrder = QSO_BYMODTIME;
368790792Sgshapiro			break;
368890792Sgshapiro
368938032Speter		  case 'p':	/* Priority order */
369038032Speter		  case 'P':
369164562Sgshapiro			QueueSortOrder = QSO_BYPRIORITY;
369238032Speter			break;
369338032Speter
369438032Speter		  case 't':	/* Submission time */
369538032Speter		  case 'T':
369664562Sgshapiro			QueueSortOrder = QSO_BYTIME;
369738032Speter			break;
369838032Speter
369990792Sgshapiro		  case 'r':	/* Random */
370090792Sgshapiro		  case 'R':
370190792Sgshapiro			QueueSortOrder = QSO_RANDOM;
370264562Sgshapiro			break;
370364562Sgshapiro
370490792Sgshapiro#if _FFR_RHS
370590792Sgshapiro		  case 's':	/* Shuffled host name */
370690792Sgshapiro		  case 'S':
370790792Sgshapiro			QueueSortOrder = QSO_BYSHUFFLE;
370890792Sgshapiro			break;
370990792Sgshapiro#endif /* _FFR_RHS */
371090792Sgshapiro
3711132943Sgshapiro		  case 'n':	/* none */
3712132943Sgshapiro		  case 'N':
3713132943Sgshapiro			QueueSortOrder = QSO_NONE;
371464562Sgshapiro			break;
371564562Sgshapiro
371664562Sgshapiro		  default:
3717132943Sgshapiro			syserr("Invalid queue sort order \"%s\"", val);
371864562Sgshapiro		}
371964562Sgshapiro		break;
372064562Sgshapiro
372138032Speter	  case O_HOSTSFILE:	/* pathname of /etc/hosts file */
372290792Sgshapiro		CANONIFY(val);
372338032Speter		HostsFile = newstr(val);
372438032Speter		break;
372538032Speter
372638032Speter	  case O_MQA:		/* minimum queue age between deliveries */
372738032Speter		MinQueueAge = convtime(val, 'm');
372838032Speter		break;
372938032Speter
3730203004Sgshapiro	  case O_MAX_QUEUE_AGE:
3731203004Sgshapiro		MaxQueueAge = convtime(val, 'm');
3732203004Sgshapiro		break;
3733203004Sgshapiro
373438032Speter	  case O_DEFCHARSET:	/* default character set for mimefying */
373590792Sgshapiro		DefaultCharSet = newstr(denlstring(val, true, true));
373638032Speter		break;
373738032Speter
373838032Speter	  case O_SSFILE:	/* service switch file */
373990792Sgshapiro		CANONIFY(val);
374038032Speter		ServiceSwitchFile = newstr(val);
374138032Speter		break;
374238032Speter
374338032Speter	  case O_DIALDELAY:	/* delay for dial-on-demand operation */
374438032Speter		DialDelay = convtime(val, 's');
374538032Speter		break;
374638032Speter
374738032Speter	  case O_NORCPTACTION:	/* what to do if no recipient */
374890792Sgshapiro		if (sm_strcasecmp(val, "none") == 0)
374938032Speter			NoRecipientAction = NRA_NO_ACTION;
375090792Sgshapiro		else if (sm_strcasecmp(val, "add-to") == 0)
375138032Speter			NoRecipientAction = NRA_ADD_TO;
375290792Sgshapiro		else if (sm_strcasecmp(val, "add-apparently-to") == 0)
375338032Speter			NoRecipientAction = NRA_ADD_APPARENTLY_TO;
375490792Sgshapiro		else if (sm_strcasecmp(val, "add-bcc") == 0)
375538032Speter			NoRecipientAction = NRA_ADD_BCC;
375690792Sgshapiro		else if (sm_strcasecmp(val, "add-to-undisclosed") == 0)
375738032Speter			NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
375838032Speter		else
375938032Speter			syserr("Invalid NoRecipientAction: %s", val);
376038032Speter		break;
376138032Speter
376238032Speter	  case O_SAFEFILEENV:	/* chroot() environ for writing to files */
376394334Sgshapiro		if (*val == '\0')
376494334Sgshapiro			break;
376594334Sgshapiro
376694334Sgshapiro		/* strip trailing slashes */
376794334Sgshapiro		p = val + strlen(val) - 1;
376894334Sgshapiro		while (p >= val && *p == '/')
376994334Sgshapiro			*p-- = '\0';
377094334Sgshapiro
377194334Sgshapiro		if (*val == '\0')
377294334Sgshapiro			break;
377394334Sgshapiro
377438032Speter		SafeFileEnv = newstr(val);
377538032Speter		break;
377638032Speter
377738032Speter	  case O_MAXMSGSIZE:	/* maximum message size */
377838032Speter		MaxMessageSize = atol(val);
377938032Speter		break;
378038032Speter
378138032Speter	  case O_COLONOKINADDR:	/* old style handling of colon addresses */
378238032Speter		ColonOkInAddr = atobool(val);
378338032Speter		break;
378438032Speter
378538032Speter	  case O_MAXQUEUERUN:	/* max # of jobs in a single queue run */
378690792Sgshapiro		MaxQueueRun = atoi(val);
378738032Speter		break;
378838032Speter
378938032Speter	  case O_MAXCHILDREN:	/* max # of children of daemon */
379038032Speter		MaxChildren = atoi(val);
379138032Speter		break;
379238032Speter
379390792Sgshapiro	  case O_MAXQUEUECHILDREN: /* max # of children of daemon */
379490792Sgshapiro		MaxQueueChildren = atoi(val);
379590792Sgshapiro		break;
379690792Sgshapiro
379790792Sgshapiro	  case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */
379890792Sgshapiro		MaxRunnersPerQueue = atoi(val);
379990792Sgshapiro		break;
380090792Sgshapiro
380190792Sgshapiro	  case O_NICEQUEUERUN:		/* nice queue runs */
380290792Sgshapiro#if !HASNICE
380390792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
380490792Sgshapiro				     "Warning: NiceQueueRun set on system that doesn't support nice()\n");
3805363466Sgshapiro#endif
380690792Sgshapiro
380790792Sgshapiro		/* XXX do we want to check the range? > 0 ? */
380890792Sgshapiro		NiceQueueRun = atoi(val);
380990792Sgshapiro		break;
381090792Sgshapiro
381194334Sgshapiro	  case O_SHMKEY:		/* shared memory key */
381290792Sgshapiro#if SM_CONF_SHM
381390792Sgshapiro		ShmKey = atol(val);
381490792Sgshapiro#else /* SM_CONF_SHM */
381590792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
381690792Sgshapiro				     "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
381790792Sgshapiro				     OPTNAME);
381890792Sgshapiro#endif /* SM_CONF_SHM */
381990792Sgshapiro		break;
382090792Sgshapiro
382194334Sgshapiro	  case O_SHMKEYFILE:		/* shared memory key file */
3822168515Sgshapiro#if SM_CONF_SHM
382398841Sgshapiro		SET_STRING_EXP(ShmKeyFile);
3824168515Sgshapiro#else /* SM_CONF_SHM */
382594334Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
382694334Sgshapiro				     "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
382794334Sgshapiro				     OPTNAME);
382898841Sgshapiro		break;
3829168515Sgshapiro#endif /* SM_CONF_SHM */
383094334Sgshapiro
383164562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES
383264562Sgshapiro	  case O_MAXFORWARD:	/* max # of forward entries */
383364562Sgshapiro		MaxForwardEntries = atoi(val);
383464562Sgshapiro		break;
3835363466Sgshapiro#endif
383664562Sgshapiro
383738032Speter	  case O_KEEPCNAMES:	/* don't expand CNAME records */
383838032Speter		DontExpandCnames = atobool(val);
383938032Speter		break;
384038032Speter
384138032Speter	  case O_MUSTQUOTE:	/* must quote these characters in phrases */
3842168515Sgshapiro		(void) sm_strlcpy(buf, "@,;:\\()[]", sizeof(buf));
3843168515Sgshapiro		if (strlen(val) < sizeof(buf) - 10)
3844168515Sgshapiro			(void) sm_strlcat(buf, val, sizeof(buf));
384564562Sgshapiro		else
384690792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
384790792Sgshapiro					     "Warning: MustQuoteChars too long, ignored.\n");
384838032Speter		MustQuoteChars = newstr(buf);
384938032Speter		break;
385038032Speter
385138032Speter	  case O_SMTPGREETING:	/* SMTP greeting message (old $e macro) */
385238032Speter		SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
385338032Speter		break;
385438032Speter
385538032Speter	  case O_UNIXFROM:	/* UNIX From_ line (old $l macro) */
385638032Speter		UnixFromLine = newstr(munchstring(val, NULL, '\0'));
385738032Speter		break;
385838032Speter
385938032Speter	  case O_OPCHARS:	/* operator characters (old $o macro) */
386064562Sgshapiro		if (OperatorChars != NULL)
386190792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
386290792Sgshapiro					     "Warning: OperatorChars is being redefined.\n         It should only be set before ruleset definitions.\n");
386338032Speter		OperatorChars = newstr(munchstring(val, NULL, '\0'));
386438032Speter		break;
386538032Speter
386638032Speter	  case O_DONTINITGRPS:	/* don't call initgroups(3) */
386738032Speter		DontInitGroups = atobool(val);
386838032Speter		break;
386938032Speter
387038032Speter	  case O_SLFH:		/* make sure from fits on one line */
387138032Speter		SingleLineFromHeader = atobool(val);
387238032Speter		break;
387338032Speter
387438032Speter	  case O_ABH:		/* allow HELO commands with syntax errors */
387538032Speter		AllowBogusHELO = atobool(val);
387638032Speter		break;
387738032Speter
387838032Speter	  case O_CONNTHROT:	/* connection rate throttle */
387938032Speter		ConnRateThrottle = atoi(val);
388038032Speter		break;
388138032Speter
388238032Speter	  case O_UGW:		/* group writable files are unsafe */
388338032Speter		if (!atobool(val))
388464562Sgshapiro		{
388564562Sgshapiro			setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
388664562Sgshapiro				DontBlameSendmail);
388764562Sgshapiro			setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
388864562Sgshapiro				DontBlameSendmail);
388964562Sgshapiro		}
389038032Speter		break;
389138032Speter
389238032Speter	  case O_DBLBOUNCE:	/* address to which to send double bounces */
389390792Sgshapiro		DoubleBounceAddr = newstr(val);
389438032Speter		break;
389538032Speter
389638032Speter	  case O_HSDIR:		/* persistent host status directory */
389738032Speter		if (val[0] != '\0')
389873188Sgshapiro		{
389990792Sgshapiro			CANONIFY(val);
390038032Speter			HostStatDir = newstr(val);
390173188Sgshapiro		}
390238032Speter		break;
390338032Speter
390438032Speter	  case O_SINGTHREAD:	/* single thread deliveries (requires hsdir) */
390538032Speter		SingleThreadDelivery = atobool(val);
390638032Speter		break;
390738032Speter
390838032Speter	  case O_RUNASUSER:	/* run bulk of code as this user */
390938032Speter		for (p = val; *p != '\0'; p++)
391038032Speter		{
391194334Sgshapiro# if _FFR_DOTTED_USERNAMES
391290792Sgshapiro			if (*p == '/' || *p == ':')
3913363466Sgshapiro# else
391438032Speter			if (*p == '.' || *p == '/' || *p == ':')
3915363466Sgshapiro# endif
391638032Speter			{
391738032Speter				*p++ = '\0';
391838032Speter				break;
391938032Speter			}
392038032Speter		}
392138032Speter		if (isascii(*val) && isdigit(*val))
392238032Speter		{
392338032Speter			if (can_setuid)
392438032Speter				RunAsUid = atoi(val);
392538032Speter		}
392638032Speter		else
392738032Speter		{
392838032Speter			register struct passwd *pw;
392938032Speter
393038032Speter			pw = sm_getpwnam(val);
393138032Speter			if (pw == NULL)
393271345Sgshapiro			{
393338032Speter				syserr("readcf: option RunAsUser: unknown user %s", val);
393471345Sgshapiro				break;
393571345Sgshapiro			}
393638032Speter			else if (can_setuid)
393738032Speter			{
393838032Speter				if (*p == '\0')
393938032Speter					RunAsUserName = newstr(val);
394038032Speter				RunAsUid = pw->pw_uid;
394138032Speter				RunAsGid = pw->pw_gid;
394238032Speter			}
394390792Sgshapiro			else if (EffGid == pw->pw_gid)
394490792Sgshapiro				RunAsGid = pw->pw_gid;
394590792Sgshapiro			else if (UseMSP && *p == '\0')
394690792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3947285229Sgshapiro						     "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3948285229Sgshapiro						     (long) EffGid,
3949285229Sgshapiro						     (long) pw->pw_gid);
395038032Speter		}
395190792Sgshapiro# ifdef UID_MAX
395238032Speter		if (RunAsUid > UID_MAX)
395338032Speter		{
395438032Speter			syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
395571345Sgshapiro				(long) RunAsUid, (long) UID_MAX);
395671345Sgshapiro			break;
395738032Speter		}
395890792Sgshapiro# endif /* UID_MAX */
395938032Speter		if (*p != '\0')
396038032Speter		{
396138032Speter			if (isascii(*p) && isdigit(*p))
396238032Speter			{
396390792Sgshapiro				gid_t runasgid;
396490792Sgshapiro
396590792Sgshapiro				runasgid = (gid_t) atoi(p);
396690792Sgshapiro				if (can_setuid || EffGid == runasgid)
396790792Sgshapiro					RunAsGid = runasgid;
396890792Sgshapiro				else if (UseMSP)
396990792Sgshapiro					(void) sm_io_fprintf(smioout,
397090792Sgshapiro							     SM_TIME_DEFAULT,
3971285229Sgshapiro							     "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3972285229Sgshapiro							     (long) EffGid,
3973285229Sgshapiro							     (long) runasgid);
397438032Speter			}
397538032Speter			else
397638032Speter			{
397738032Speter				register struct group *gr;
397864562Sgshapiro
397938032Speter				gr = getgrnam(p);
398038032Speter				if (gr == NULL)
398138032Speter					syserr("readcf: option RunAsUser: unknown group %s",
398238032Speter						p);
398390792Sgshapiro				else if (can_setuid || EffGid == gr->gr_gid)
398438032Speter					RunAsGid = gr->gr_gid;
398590792Sgshapiro				else if (UseMSP)
398690792Sgshapiro					(void) sm_io_fprintf(smioout,
398790792Sgshapiro							     SM_TIME_DEFAULT,
3988285229Sgshapiro							     "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3989285229Sgshapiro							     (long) EffGid,
3990285229Sgshapiro							     (long) gr->gr_gid);
399138032Speter			}
399238032Speter		}
399338032Speter		if (tTd(47, 5))
399490792Sgshapiro			sm_dprintf("readcf: RunAsUser = %d:%d\n",
399590792Sgshapiro				   (int) RunAsUid, (int) RunAsGid);
399638032Speter		break;
399738032Speter
399838032Speter	  case O_DSN_RRT:
399938032Speter		RrtImpliesDsn = atobool(val);
400038032Speter		break;
400138032Speter
400238032Speter	  case O_PIDFILE:
400390792Sgshapiro		PSTRSET(PidFile, val);
400438032Speter		break;
400538032Speter
400690792Sgshapiro	  case O_DONTBLAMESENDMAIL:
400738032Speter		p = val;
400838032Speter		for (;;)
400938032Speter		{
401038032Speter			register struct dbsval *dbs;
401138032Speter			extern struct dbsval DontBlameSendmailValues[];
401238032Speter
401338032Speter			while (isascii(*p) && (isspace(*p) || ispunct(*p)))
401438032Speter				p++;
401538032Speter			if (*p == '\0')
401638032Speter				break;
401738032Speter			val = p;
401838032Speter			while (isascii(*p) && isalnum(*p))
401938032Speter				p++;
402038032Speter			if (*p != '\0')
402138032Speter				*p++ = '\0';
402238032Speter
402338032Speter			for (dbs = DontBlameSendmailValues;
402438032Speter			     dbs->dbs_name != NULL; dbs++)
402538032Speter			{
402690792Sgshapiro				if (sm_strcasecmp(val, dbs->dbs_name) == 0)
402738032Speter					break;
402838032Speter			}
402938032Speter			if (dbs->dbs_name == NULL)
403038032Speter				syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
403138032Speter			else if (dbs->dbs_flag == DBS_SAFE)
403264562Sgshapiro				clrbitmap(DontBlameSendmail);
403338032Speter			else
403464562Sgshapiro				setbitn(dbs->dbs_flag, DontBlameSendmail);
403538032Speter		}
403690792Sgshapiro		sticky = false;
403738032Speter		break;
403838032Speter
403938032Speter	  case O_DPI:
404090792Sgshapiro		if (sm_strcasecmp(val, "loopback") == 0)
404190792Sgshapiro			DontProbeInterfaces = DPI_SKIPLOOPBACK;
404290792Sgshapiro		else if (atobool(val))
404390792Sgshapiro			DontProbeInterfaces = DPI_PROBENONE;
404490792Sgshapiro		else
404590792Sgshapiro			DontProbeInterfaces = DPI_PROBEALL;
404638032Speter		break;
404738032Speter
404838032Speter	  case O_MAXRCPT:
404938032Speter		MaxRcptPerMsg = atoi(val);
405038032Speter		break;
405138032Speter
405290792Sgshapiro	  case O_RCPTTHROT:
405390792Sgshapiro		BadRcptThrottle = atoi(val);
405490792Sgshapiro		break;
405590792Sgshapiro
4056203004Sgshapiro#if _FFR_RCPTTHROTDELAY
4057203004Sgshapiro	  case O_RCPTTHROTDELAY:
4058203004Sgshapiro		BadRcptThrottleDelay = atoi(val);
4059203004Sgshapiro		break;
4060363466Sgshapiro#endif
4061203004Sgshapiro
406238032Speter	  case O_DEADLETTER:
406390792Sgshapiro		CANONIFY(val);
406490792Sgshapiro		PSTRSET(DeadLetterDrop, val);
406538032Speter		break;
406638032Speter
406738032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION
406838032Speter	  case O_DONTLOCK:
406938032Speter		DontLockReadFiles = atobool(val);
407038032Speter		break;
4071363466Sgshapiro#endif
407238032Speter
407338032Speter	  case O_MAXALIASRCSN:
407438032Speter		MaxAliasRecursion = atoi(val);
407538032Speter		break;
407638032Speter
407738032Speter	  case O_CNCTONLYTO:
407838032Speter		/* XXX should probably use gethostbyname */
407964562Sgshapiro#if NETINET || NETINET6
4080363466Sgshapiro		i = 0;
4081363466Sgshapiro		if ((subopt = strchr(val, '@')) != NULL)
4082363466Sgshapiro		{
4083363466Sgshapiro			*subopt = '\0';
4084363466Sgshapiro			i = (int) strtoul(val, NULL, 0);
4085363466Sgshapiro
4086363466Sgshapiro			/* stricter checks? probably not useful. */
4087363466Sgshapiro			if (i > USHRT_MAX)
4088363466Sgshapiro			{
4089363466Sgshapiro				syserr("readcf: option ConnectOnlyTo: invalid port %s",
4090363466Sgshapiro					val);
4091363466Sgshapiro				break;
4092363466Sgshapiro			}
4093363466Sgshapiro			val = subopt + 1;
4094363466Sgshapiro		}
409590792Sgshapiro		ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
409664562Sgshapiro# if NETINET6
409790792Sgshapiro		if (anynet_pton(AF_INET6, val,
4098223067Sgshapiro				&ConnectOnlyTo.sin6.sin6_addr) == 1)
4099363466Sgshapiro		{
410064562Sgshapiro			ConnectOnlyTo.sa.sa_family = AF_INET6;
4101363466Sgshapiro			if (i != 0)
4102363466Sgshapiro				ConnectOnlyTo.sin6.sin6_port = htons(i);
4103363466Sgshapiro		}
410464562Sgshapiro		else
410564562Sgshapiro# endif /* NETINET6 */
410690792Sgshapiro# if NETINET
410764562Sgshapiro		{
410864562Sgshapiro			ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
410990792Sgshapiro			if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
411090792Sgshapiro				ConnectOnlyTo.sa.sa_family = AF_INET;
4111363466Sgshapiro			if (i != 0)
4112363466Sgshapiro				ConnectOnlyTo.sin.sin_port = htons(i);
411364562Sgshapiro		}
411490792Sgshapiro
411590792Sgshapiro# endif /* NETINET */
411690792Sgshapiro		if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC)
411790792Sgshapiro		{
411890792Sgshapiro			syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
411990792Sgshapiro			       val);
412090792Sgshapiro			break;
412190792Sgshapiro		}
412264562Sgshapiro#endif /* NETINET || NETINET6 */
412338032Speter		break;
412438032Speter
412542575Speter	  case O_TRUSTUSER:
412690792Sgshapiro# if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING)
412790792Sgshapiro		if (!UseMSP)
412890792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
412990792Sgshapiro					     "readcf: option TrustedUser may cause problems on systems\n        which do not support fchown() if UseMSP is not set.\n");
413090792Sgshapiro# endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */
413138032Speter		if (isascii(*val) && isdigit(*val))
413242575Speter			TrustedUid = atoi(val);
413338032Speter		else
413438032Speter		{
413538032Speter			register struct passwd *pw;
413638032Speter
413742575Speter			TrustedUid = 0;
413838032Speter			pw = sm_getpwnam(val);
413938032Speter			if (pw == NULL)
414071345Sgshapiro			{
414142575Speter				syserr("readcf: option TrustedUser: unknown user %s", val);
414271345Sgshapiro				break;
414371345Sgshapiro			}
414438032Speter			else
414542575Speter				TrustedUid = pw->pw_uid;
414638032Speter		}
414738032Speter
414864562Sgshapiro# ifdef UID_MAX
414942575Speter		if (TrustedUid > UID_MAX)
415038032Speter		{
415142575Speter			syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
415271345Sgshapiro				(long) TrustedUid, (long) UID_MAX);
415342575Speter			TrustedUid = 0;
415438032Speter		}
415564562Sgshapiro# endif /* UID_MAX */
415638032Speter		break;
415738032Speter
415842575Speter	  case O_MAXMIMEHDRLEN:
415942575Speter		p = strchr(val, '/');
416042575Speter		if (p != NULL)
416142575Speter			*p++ = '\0';
416242575Speter		MaxMimeHeaderLength = atoi(val);
416342575Speter		if (p != NULL && *p != '\0')
416442575Speter			MaxMimeFieldLength = atoi(p);
416542575Speter		else
416642575Speter			MaxMimeFieldLength = MaxMimeHeaderLength / 2;
416742575Speter
4168120256Sgshapiro		if (MaxMimeHeaderLength <= 0)
416942575Speter			MaxMimeHeaderLength = 0;
417042575Speter		else if (MaxMimeHeaderLength < 128)
417190792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
417290792Sgshapiro					     "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
417342575Speter
4174120256Sgshapiro		if (MaxMimeFieldLength <= 0)
417542575Speter			MaxMimeFieldLength = 0;
417642575Speter		else if (MaxMimeFieldLength < 40)
417790792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
417890792Sgshapiro					     "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
4179168515Sgshapiro
4180168515Sgshapiro		/*
4181168515Sgshapiro		**  Headers field values now include leading space, so let's
4182168515Sgshapiro		**  adjust the values to be "backward compatible".
4183168515Sgshapiro		*/
4184168515Sgshapiro
4185168515Sgshapiro		if (MaxMimeHeaderLength > 0)
4186168515Sgshapiro			MaxMimeHeaderLength++;
4187168515Sgshapiro		if (MaxMimeFieldLength > 0)
4188168515Sgshapiro			MaxMimeFieldLength++;
418942575Speter		break;
419042575Speter
419142575Speter	  case O_CONTROLSOCKET:
419290792Sgshapiro		PSTRSET(ControlSocketName, val);
419342575Speter		break;
419442575Speter
419543730Speter	  case O_MAXHDRSLEN:
419643730Speter		MaxHeadersLength = atoi(val);
419743148Speter
419843730Speter		if (MaxHeadersLength > 0 &&
419943730Speter		    MaxHeadersLength < (MAXHDRSLEN / 2))
420090792Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
420190792Sgshapiro					     "Warning: MaxHeadersLength: headers length limit set lower than %d\n",
420290792Sgshapiro					     (MAXHDRSLEN / 2));
420343148Speter		break;
420443148Speter
420564562Sgshapiro	  case O_PROCTITLEPREFIX:
420690792Sgshapiro		PSTRSET(ProcTitlePrefix, val);
420764562Sgshapiro		break;
420864562Sgshapiro
420964562Sgshapiro#if SASL
421064562Sgshapiro	  case O_SASLINFO:
421190792Sgshapiro# if _FFR_ALLOW_SASLINFO
421264562Sgshapiro		/*
421390792Sgshapiro		**  Allow users to select their own authinfo file
421490792Sgshapiro		**  under certain circumstances, otherwise just ignore
421590792Sgshapiro		**  the option.  If the option isn't ignored, several
421690792Sgshapiro		**  commands don't work very well, e.g., mailq.
421764562Sgshapiro		**  However, this is not a "perfect" solution.
421864562Sgshapiro		**  If mail is queued, the authentication info
421964562Sgshapiro		**  will not be used in subsequent delivery attempts.
422064562Sgshapiro		**  If we really want to support this, then it has
422164562Sgshapiro		**  to be stored in the queue file.
422264562Sgshapiro		*/
422364562Sgshapiro		if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
422464562Sgshapiro		    RunAsUid != RealUid)
422564562Sgshapiro			break;
422690792Sgshapiro# endif /* _FFR_ALLOW_SASLINFO */
422790792Sgshapiro		PSTRSET(SASLInfo, val);
422864562Sgshapiro		break;
422964562Sgshapiro
423064562Sgshapiro	  case O_SASLMECH:
423164562Sgshapiro		if (AuthMechanisms != NULL)
423290792Sgshapiro			sm_free(AuthMechanisms); /* XXX */
423364562Sgshapiro		if (*val != '\0')
423464562Sgshapiro			AuthMechanisms = newstr(val);
423564562Sgshapiro		else
423664562Sgshapiro			AuthMechanisms = NULL;
423764562Sgshapiro		break;
423864562Sgshapiro
4239132943Sgshapiro	  case O_SASLREALM:
4240132943Sgshapiro		if (AuthRealm != NULL)
4241132943Sgshapiro			sm_free(AuthRealm);
4242132943Sgshapiro		if (*val != '\0')
4243132943Sgshapiro			AuthRealm = newstr(val);
4244132943Sgshapiro		else
4245132943Sgshapiro			AuthRealm = NULL;
4246132943Sgshapiro		break;
4247132943Sgshapiro
424864562Sgshapiro	  case O_SASLOPTS:
424964562Sgshapiro		while (val != NULL && *val != '\0')
425064562Sgshapiro		{
425190792Sgshapiro			switch (*val)
425264562Sgshapiro			{
425364562Sgshapiro			  case 'A':
425464562Sgshapiro				SASLOpts |= SASL_AUTH_AUTH;
425564562Sgshapiro				break;
4256110560Sgshapiro
425764562Sgshapiro			  case 'a':
425864562Sgshapiro				SASLOpts |= SASL_SEC_NOACTIVE;
425964562Sgshapiro				break;
4260110560Sgshapiro
426164562Sgshapiro			  case 'c':
426264562Sgshapiro				SASLOpts |= SASL_SEC_PASS_CREDENTIALS;
426364562Sgshapiro				break;
4264110560Sgshapiro
426564562Sgshapiro			  case 'd':
426664562Sgshapiro				SASLOpts |= SASL_SEC_NODICTIONARY;
426764562Sgshapiro				break;
4268110560Sgshapiro
426964562Sgshapiro			  case 'f':
427064562Sgshapiro				SASLOpts |= SASL_SEC_FORWARD_SECRECY;
427164562Sgshapiro				break;
4272110560Sgshapiro
427398121Sgshapiro#  if SASL >= 20101
427498121Sgshapiro			  case 'm':
427598121Sgshapiro				SASLOpts |= SASL_SEC_MUTUAL_AUTH;
427698121Sgshapiro				break;
427798121Sgshapiro#  endif /* SASL >= 20101 */
4278110560Sgshapiro
427964562Sgshapiro			  case 'p':
428064562Sgshapiro				SASLOpts |= SASL_SEC_NOPLAINTEXT;
428164562Sgshapiro				break;
4282110560Sgshapiro
428364562Sgshapiro			  case 'y':
428464562Sgshapiro				SASLOpts |= SASL_SEC_NOANONYMOUS;
428564562Sgshapiro				break;
4286110560Sgshapiro
428790792Sgshapiro			  case ' ':	/* ignore */
428890792Sgshapiro			  case '\t':	/* ignore */
428990792Sgshapiro			  case ',':	/* ignore */
429090792Sgshapiro				break;
4291110560Sgshapiro
429264562Sgshapiro			  default:
429390792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
429490792Sgshapiro						     "Warning: Option: %s unknown parameter '%c'\n",
429590792Sgshapiro						     OPTNAME,
429690792Sgshapiro						     (isascii(*val) &&
429790792Sgshapiro							isprint(*val))
429890792Sgshapiro							? *val : '?');
429964562Sgshapiro				break;
430064562Sgshapiro			}
430164562Sgshapiro			++val;
430264562Sgshapiro			val = strpbrk(val, ", \t");
430364562Sgshapiro			if (val != NULL)
430464562Sgshapiro				++val;
430564562Sgshapiro		}
430664562Sgshapiro		break;
4307110560Sgshapiro
430890792Sgshapiro	  case O_SASLBITS:
430990792Sgshapiro		MaxSLBits = atoi(val);
431090792Sgshapiro		break;
431164562Sgshapiro
431264562Sgshapiro#else /* SASL */
431364562Sgshapiro	  case O_SASLINFO:
431464562Sgshapiro	  case O_SASLMECH:
4315132943Sgshapiro	  case O_SASLREALM:
431664562Sgshapiro	  case O_SASLOPTS:
431790792Sgshapiro	  case O_SASLBITS:
431890792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
431990792Sgshapiro				     "Warning: Option: %s requires SASL support (-DSASL)\n",
432090792Sgshapiro				     OPTNAME);
432164562Sgshapiro		break;
432264562Sgshapiro#endif /* SASL */
432364562Sgshapiro
432464562Sgshapiro#if STARTTLS
4325363466Sgshapiro	  case O_TLSFB2CLEAR:
4326363466Sgshapiro		TLSFallbacktoClear = atobool(val);
4327363466Sgshapiro		break;
432864562Sgshapiro	  case O_SRVCERTFILE:
4329110560Sgshapiro		SET_STRING_EXP(SrvCertFile);
433064562Sgshapiro	  case O_SRVKEYFILE:
4331110560Sgshapiro		SET_STRING_EXP(SrvKeyFile);
433264562Sgshapiro	  case O_CLTCERTFILE:
4333110560Sgshapiro		SET_STRING_EXP(CltCertFile);
433464562Sgshapiro	  case O_CLTKEYFILE:
4335110560Sgshapiro		SET_STRING_EXP(CltKeyFile);
433664562Sgshapiro	  case O_CACERTFILE:
4337110560Sgshapiro		SET_STRING_EXP(CACertFile);
433864562Sgshapiro	  case O_CACERTPATH:
4339110560Sgshapiro		SET_STRING_EXP(CACertPath);
4340363466Sgshapiro#if _FFR_CLIENTCA
4341363466Sgshapiro	  case O_CLTCACERTFILE:
4342363466Sgshapiro		SET_STRING_EXP(CltCACertFile);
4343363466Sgshapiro	  case O_CLTCACERTPATH:
4344363466Sgshapiro		SET_STRING_EXP(CltCACertPath);
4345363466Sgshapiro#endif
434664562Sgshapiro	  case O_DHPARAMS:
434790792Sgshapiro		SET_STRING_EXP(DHParams);
434890792Sgshapiro	  case O_CIPHERLIST:
434990792Sgshapiro		SET_STRING_EXP(CipherList);
4350285229Sgshapiro	  case O_DIG_ALG:
4351285229Sgshapiro		SET_STRING_EXP(CertFingerprintAlgorithm);
4352363466Sgshapiro	  case O_SSLENGINEPATH:
4353363466Sgshapiro		SET_STRING_EXP(SSLEnginePath);
4354363466Sgshapiro	  case O_SSLENGINE:
4355363466Sgshapiro		newval = sm_pstrdup_x(val);
4356363466Sgshapiro		if (SSLEngine != NULL)
4357363466Sgshapiro			sm_free(SSLEngine);
4358363466Sgshapiro		SSLEngine = newval;
4359363466Sgshapiro
4360363466Sgshapiro		/*
4361363466Sgshapiro		**  Which engines need to be initialized before fork()?
4362363466Sgshapiro		**  XXX hack, should be an option?
4363363466Sgshapiro		*/
4364363466Sgshapiro
4365363466Sgshapiro		if (strcmp(SSLEngine, "chil") == 0)
4366363466Sgshapiro			SSLEngineprefork = true;
4367363466Sgshapiro		break;
4368203004Sgshapiro	  case O_SRV_SSL_OPTIONS:
4369203004Sgshapiro		pssloptions = &Srv_SSL_Options;
4370203004Sgshapiro	  case O_CLT_SSL_OPTIONS:
4371203004Sgshapiro		if (pssloptions == NULL)
4372203004Sgshapiro			pssloptions = &Clt_SSL_Options;
4373285229Sgshapiro		(void) readssloptions(o->o_name, val, pssloptions, '\0');
4374285229Sgshapiro		if (tTd(37, 8))
4375285229Sgshapiro			sm_dprintf("ssloptions=%#lx\n", *pssloptions);
4376203004Sgshapiro
4377203004Sgshapiro		pssloptions = NULL;
4378203004Sgshapiro		break;
4379203004Sgshapiro
4380132943Sgshapiro	  case O_CRLFILE:
4381132943Sgshapiro		SET_STRING_EXP(CRLFile);
4382132943Sgshapiro		break;
438364562Sgshapiro
4384132943Sgshapiro	  case O_CRLPATH:
4385132943Sgshapiro		SET_STRING_EXP(CRLPath);
4386132943Sgshapiro		break;
4387132943Sgshapiro
438890792Sgshapiro	/*
438990792Sgshapiro	**  XXX How about options per daemon/client instead of globally?
439090792Sgshapiro	**  This doesn't work well for some options, e.g., no server cert,
439190792Sgshapiro	**  but fine for others.
439290792Sgshapiro	**
439390792Sgshapiro	**  XXX Some people may want different certs per server.
439490792Sgshapiro	**
439590792Sgshapiro	**  See also srvfeatures()
439690792Sgshapiro	*/
439790792Sgshapiro
439890792Sgshapiro	  case O_TLS_SRV_OPTS:
439990792Sgshapiro		while (val != NULL && *val != '\0')
440090792Sgshapiro		{
440190792Sgshapiro			switch (*val)
440290792Sgshapiro			{
440390792Sgshapiro			  case 'V':
440490792Sgshapiro				TLS_Srv_Opts |= TLS_I_NO_VRFY;
440590792Sgshapiro				break;
440690792Sgshapiro			/*
440790792Sgshapiro			**  Server without a cert? That works only if
440890792Sgshapiro			**  AnonDH is enabled as cipher, which is not in the
440990792Sgshapiro			**  default list. Hence the CipherList option must
441090792Sgshapiro			**  be available. Moreover: which clients support this
441190792Sgshapiro			**  besides sendmail with this setting?
441290792Sgshapiro			*/
441390792Sgshapiro
441490792Sgshapiro			  case 'C':
441590792Sgshapiro				TLS_Srv_Opts &= ~TLS_I_SRV_CERT;
441690792Sgshapiro				break;
441790792Sgshapiro			  case ' ':	/* ignore */
441890792Sgshapiro			  case '\t':	/* ignore */
441990792Sgshapiro			  case ',':	/* ignore */
442090792Sgshapiro				break;
442190792Sgshapiro			  default:
442290792Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
442390792Sgshapiro						     "Warning: Option: %s unknown parameter '%c'\n",
442490792Sgshapiro						     OPTNAME,
442590792Sgshapiro						     (isascii(*val) &&
442690792Sgshapiro							isprint(*val))
442790792Sgshapiro							? *val : '?');
442890792Sgshapiro				break;
442990792Sgshapiro			}
443090792Sgshapiro			++val;
443190792Sgshapiro			val = strpbrk(val, ", \t");
443290792Sgshapiro			if (val != NULL)
443390792Sgshapiro				++val;
443490792Sgshapiro		}
443564562Sgshapiro		break;
443664562Sgshapiro
443764562Sgshapiro	  case O_RANDFILE:
443890792Sgshapiro		PSTRSET(RandFile, val);
443964562Sgshapiro		break;
444064562Sgshapiro
444190792Sgshapiro#else /* STARTTLS */
444264562Sgshapiro	  case O_SRVCERTFILE:
444364562Sgshapiro	  case O_SRVKEYFILE:
444464562Sgshapiro	  case O_CLTCERTFILE:
444564562Sgshapiro	  case O_CLTKEYFILE:
444664562Sgshapiro	  case O_CACERTFILE:
444764562Sgshapiro	  case O_CACERTPATH:
4448363466Sgshapiro#if _FFR_CLIENTCA
4449363466Sgshapiro	  case O_CLTCACERTFILE:
4450363466Sgshapiro	  case O_CLTCACERTPATH:
4451363466Sgshapiro#endif
445264562Sgshapiro	  case O_DHPARAMS:
4453285229Sgshapiro	  case O_SRV_SSL_OPTIONS:
4454285229Sgshapiro	  case O_CLT_SSL_OPTIONS:
445564562Sgshapiro	  case O_CIPHERLIST:
4456363466Sgshapiro	  case O_DIG_ALG:
4457132943Sgshapiro	  case O_CRLFILE:
4458132943Sgshapiro	  case O_CRLPATH:
445964562Sgshapiro	  case O_RANDFILE:
446090792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
446190792Sgshapiro				     "Warning: Option: %s requires TLS support\n",
446290792Sgshapiro				     OPTNAME);
446364562Sgshapiro		break;
446464562Sgshapiro
446590792Sgshapiro#endif /* STARTTLS */
4466249729Sgshapiro#if STARTTLS && _FFR_FIPSMODE
4467249729Sgshapiro	  case O_FIPSMODE:
4468249729Sgshapiro		FipsMode = atobool(val);
4469249729Sgshapiro		break;
4470363466Sgshapiro#endif
447164562Sgshapiro
447264562Sgshapiro	  case O_CLIENTPORT:
447364562Sgshapiro		setclientoptions(val);
447464562Sgshapiro		break;
447564562Sgshapiro
447664562Sgshapiro	  case O_DF_BUFSIZE:
447764562Sgshapiro		DataFileBufferSize = atoi(val);
447864562Sgshapiro		break;
447964562Sgshapiro
448064562Sgshapiro	  case O_XF_BUFSIZE:
448164562Sgshapiro		XscriptFileBufferSize = atoi(val);
448264562Sgshapiro		break;
448364562Sgshapiro
448464562Sgshapiro	  case O_LDAPDEFAULTSPEC:
448590792Sgshapiro#if LDAPMAP
448664562Sgshapiro		ldapmap_set_defaults(val);
448764562Sgshapiro#else /* LDAPMAP */
448890792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
448990792Sgshapiro				     "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
449090792Sgshapiro				     OPTNAME);
449164562Sgshapiro#endif /* LDAPMAP */
449264562Sgshapiro		break;
449364562Sgshapiro
449464562Sgshapiro	  case O_INPUTMILTER:
449590792Sgshapiro#if MILTER
449664562Sgshapiro		InputFilterList = newstr(val);
449790792Sgshapiro#else /* MILTER */
449890792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
449990792Sgshapiro				     "Warning: Option: %s requires Milter support (-DMILTER)\n",
450090792Sgshapiro				     OPTNAME);
450190792Sgshapiro#endif /* MILTER */
450264562Sgshapiro		break;
450364562Sgshapiro
450464562Sgshapiro	  case O_MILTER:
450590792Sgshapiro#if MILTER
450664562Sgshapiro		milter_set_option(subopt, val, sticky);
450790792Sgshapiro#else /* MILTER */
450890792Sgshapiro		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
450990792Sgshapiro				     "Warning: Option: %s requires Milter support (-DMILTER)\n",
451090792Sgshapiro				     OPTNAME);
451190792Sgshapiro#endif /* MILTER */
451264562Sgshapiro		break;
451364562Sgshapiro
451464562Sgshapiro	  case O_QUEUE_FILE_MODE:	/* queue file mode */
451564562Sgshapiro		QueueFileMode = atooct(val) & 0777;
451664562Sgshapiro		break;
451764562Sgshapiro
451890792Sgshapiro	  case O_DLVR_MIN:	/* deliver by minimum time */
451990792Sgshapiro		DeliverByMin = convtime(val, 's');
452090792Sgshapiro		break;
452190792Sgshapiro
452290792Sgshapiro	  /* modifiers {daemon_flags} for direct submissions */
452390792Sgshapiro	  case O_DIRECTSUBMODIFIERS:
452490792Sgshapiro		{
452590792Sgshapiro			BITMAP256 m;	/* ignored */
452690792Sgshapiro			extern ENVELOPE BlankEnvelope;
452790792Sgshapiro
452890792Sgshapiro			macdefine(&BlankEnvelope.e_macro, A_PERM,
452990792Sgshapiro				  macid("{daemon_flags}"),
453090792Sgshapiro				  getmodifiers(val, m));
453190792Sgshapiro		}
453290792Sgshapiro		break;
453390792Sgshapiro
453490792Sgshapiro	  case O_FASTSPLIT:
453590792Sgshapiro		FastSplit = atoi(val);
453690792Sgshapiro		break;
453790792Sgshapiro
453890792Sgshapiro	  case O_MBDB:
453990792Sgshapiro		Mbdb = newstr(val);
454090792Sgshapiro		break;
454190792Sgshapiro
454290792Sgshapiro	  case O_MSQ:
454390792Sgshapiro		UseMSP = atobool(val);
454490792Sgshapiro		break;
454590792Sgshapiro
454690792Sgshapiro	  case O_SOFTBOUNCE:
454790792Sgshapiro		SoftBounce = atobool(val);
454890792Sgshapiro		break;
454990792Sgshapiro
4550110560Sgshapiro	  case O_REJECTLOGINTERVAL:	/* time btwn log msgs while refusing */
4551110560Sgshapiro		RejectLogInterval = convtime(val, 'h');
4552110560Sgshapiro		break;
4553110560Sgshapiro
4554110560Sgshapiro	  case O_REQUIRES_DIR_FSYNC:
4555132943Sgshapiro#if REQUIRES_DIR_FSYNC
4556110560Sgshapiro		RequiresDirfsync = atobool(val);
4557363466Sgshapiro#else
4558110560Sgshapiro		/* silently ignored... required for cf file option */
4559363466Sgshapiro#endif
4560110560Sgshapiro		break;
4561110560Sgshapiro
4562132943Sgshapiro	  case O_CONNECTION_RATE_WINDOW_SIZE:
4563132943Sgshapiro		ConnectionRateWindowSize = convtime(val, 's');
4564132943Sgshapiro		break;
4565132943Sgshapiro
4566132943Sgshapiro	  case O_FALLBACKSMARTHOST:	/* fallback smart host */
4567132943Sgshapiro		if (val[0] != '\0')
4568132943Sgshapiro			FallbackSmartHost = newstr(val);
4569132943Sgshapiro		break;
4570132943Sgshapiro
4571132943Sgshapiro	  case O_HELONAME:
4572157001Sgshapiro		HeloName = newstr(val);
4573157001Sgshapiro		break;
4574168515Sgshapiro
4575157001Sgshapiro#if _FFR_MEMSTAT
4576157001Sgshapiro	  case O_REFUSELOWMEM:
4577157001Sgshapiro		RefuseLowMem = atoi(val);
4578157001Sgshapiro		break;
4579157001Sgshapiro	  case O_QUEUELOWMEM:
4580157001Sgshapiro		QueueLowMem = atoi(val);
4581157001Sgshapiro		break;
4582157001Sgshapiro	  case O_MEMRESOURCE:
4583157001Sgshapiro		MemoryResource = newstr(val);
4584157001Sgshapiro		break;
4585157001Sgshapiro#endif /* _FFR_MEMSTAT */
4586132943Sgshapiro
4587157001Sgshapiro	  case O_MAXNOOPCOMMANDS:
4588157001Sgshapiro		MaxNOOPCommands = atoi(val);
4589157001Sgshapiro		break;
4590157001Sgshapiro
4591157001Sgshapiro#if _FFR_MSG_ACCEPT
4592157001Sgshapiro	  case O_MSG_ACCEPT:
4593157001Sgshapiro		MessageAccept = newstr(val);
4594157001Sgshapiro		break;
4595363466Sgshapiro#endif
4596157001Sgshapiro
4597157001Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA
4598157001Sgshapiro	  case O_CHK_Q_RUNNERS:
4599157001Sgshapiro		CheckQueueRunners = atoi(val);
4600157001Sgshapiro		break;
4601363466Sgshapiro#endif
4602157001Sgshapiro
4603168515Sgshapiro#if _FFR_EIGHT_BIT_ADDR_OK
4604168515Sgshapiro	  case O_EIGHT_BIT_ADDR_OK:
4605168515Sgshapiro		EightBitAddrOK = atobool(val);
4606168515Sgshapiro		break;
4607363466Sgshapiro#endif
4608168515Sgshapiro
4609173340Sgshapiro#if _FFR_ADDR_TYPE_MODES
4610173340Sgshapiro	  case O_ADDR_TYPE_MODES:
4611173340Sgshapiro		AddrTypeModes = atobool(val);
4612173340Sgshapiro		break;
4613363466Sgshapiro#endif
4614173340Sgshapiro
4615182352Sgshapiro#if _FFR_BADRCPT_SHUTDOWN
4616182352Sgshapiro	  case O_RCPTSHUTD:
4617182352Sgshapiro		BadRcptShutdown = atoi(val);
4618182352Sgshapiro		break;
4619182352Sgshapiro
4620182352Sgshapiro	  case O_RCPTSHUTDG:
4621182352Sgshapiro		BadRcptShutdownGood = atoi(val);
4622182352Sgshapiro		break;
4623182352Sgshapiro#endif /* _FFR_BADRCPT_SHUTDOWN */
4624182352Sgshapiro
4625249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
4626249729Sgshapiro	  case O_REJECTNUL:
4627249729Sgshapiro		RejectNUL = atobool(val);
4628249729Sgshapiro		break;
4629363466Sgshapiro#endif
4630249729Sgshapiro
4631285229Sgshapiro#if _FFR_BOUNCE_QUEUE
4632285229Sgshapiro	  case O_BOUNCEQUEUE:
4633285229Sgshapiro		bouncequeue = newstr(val);
4634285229Sgshapiro		break;
4635363466Sgshapiro#endif
4636285229Sgshapiro
4637285229Sgshapiro#if _FFR_ADD_BCC
4638285229Sgshapiro	  case O_ADDBCC:
4639285229Sgshapiro		AddBcc = atobool(val);
4640285229Sgshapiro		break;
4641285229Sgshapiro#endif
4642285229Sgshapiro	  case O_USECOMPRESSEDIPV6ADDRESSES:
4643285229Sgshapiro		UseCompressedIPv6Addresses = atobool(val);
4644285229Sgshapiro		break;
4645285229Sgshapiro
4646363466Sgshapiro#if DNSSEC_TEST
4647363466Sgshapiro	  case O_NSPORTIP:
4648363466Sgshapiro		nsportip(val);
4649363466Sgshapiro		break;
4650363466Sgshapiro	  case O_NSSRCHLIST:
4651363466Sgshapiro		NameSearchList = sm_strdup(val);
4652363466Sgshapiro		break;
4653363466Sgshapiro#endif
4654363466Sgshapiro
4655363466Sgshapiro#if DANE
4656363466Sgshapiro	  case O_DANE:
4657363466Sgshapiro		if (sm_strcasecmp(val, "always") == 0)
4658363466Sgshapiro			Dane = DANE_ALWAYS;
4659363466Sgshapiro		else
4660363466Sgshapiro			Dane = atobool(val) ? DANE_SECURE : DANE_NEVER;
4661363466Sgshapiro		break;
4662363466Sgshapiro#endif
4663363466Sgshapiro
4664363466Sgshapiro#if _FFR_BLANKENV_MACV
4665363466Sgshapiro	  case O_HACKS:
4666363466Sgshapiro		Hacks = (int) strtol(val, NULL, 0);
4667363466Sgshapiro		break;
4668363466Sgshapiro#endif
4669363466Sgshapiro
4670363466Sgshapiro#if _FFR_KEEPBCC
4671363466Sgshapiro	  case O_KEEPBCC:
4672363466Sgshapiro		KeepBcc = atobool(val);
4673363466Sgshapiro		break;
4674363466Sgshapiro#endif
4675363466Sgshapiro
4676363466Sgshapiro# if _FFR_TLS_ALTNAMES
4677363466Sgshapiro	  case O_CHECKALTNAMES:
4678363466Sgshapiro		SetCertAltnames = atobool(val);
4679363466Sgshapiro		break;
4680363466Sgshapiro# endif
4681363466Sgshapiro
468238032Speter	  default:
468338032Speter		if (tTd(37, 1))
468438032Speter		{
468538032Speter			if (isascii(opt) && isprint(opt))
468690792Sgshapiro				sm_dprintf("Warning: option %c unknown\n", opt);
468738032Speter			else
468890792Sgshapiro				sm_dprintf("Warning: option 0x%x unknown\n", opt);
468938032Speter		}
469038032Speter		break;
469138032Speter	}
469264562Sgshapiro
469364562Sgshapiro	/*
469464562Sgshapiro	**  Options with suboptions are responsible for taking care
469564562Sgshapiro	**  of sticky-ness (e.g., that a command line setting is kept
469664562Sgshapiro	**  when reading in the sendmail.cf file).  This has to be done
469764562Sgshapiro	**  when the suboptions are parsed since each suboption must be
469864562Sgshapiro	**  sticky, not the root option.
469964562Sgshapiro	*/
470064562Sgshapiro
470164562Sgshapiro	if (sticky && !bitset(OI_SUBOPT, o->o_flags))
470238032Speter		setbitn(opt, StickyOpt);
470338032Speter}
470490792Sgshapiro/*
470538032Speter**  SETCLASS -- set a string into a class
470638032Speter**
470738032Speter**	Parameters:
470838032Speter**		class -- the class to put the string in.
470938032Speter**		str -- the string to enter
471038032Speter**
471138032Speter**	Returns:
471238032Speter**		none.
471338032Speter**
471438032Speter**	Side Effects:
471538032Speter**		puts the word into the symbol table.
471638032Speter*/
471738032Speter
471838032Spetervoid
471938032Spetersetclass(class, str)
472038032Speter	int class;
472138032Speter	char *str;
472238032Speter{
472338032Speter	register STAB *s;
472438032Speter
4725168515Sgshapiro	if ((str[0] & 0377) == MATCHCLASS)
472664562Sgshapiro	{
472764562Sgshapiro		int mid;
472864562Sgshapiro
472964562Sgshapiro		str++;
473090792Sgshapiro		mid = macid(str);
473171345Sgshapiro		if (mid == 0)
473264562Sgshapiro			return;
473364562Sgshapiro
473464562Sgshapiro		if (tTd(37, 8))
473590792Sgshapiro			sm_dprintf("setclass(%s, $=%s)\n",
473690792Sgshapiro				   macname(class), macname(mid));
473764562Sgshapiro		copy_class(mid, class);
473864562Sgshapiro	}
473964562Sgshapiro	else
474064562Sgshapiro	{
474164562Sgshapiro		if (tTd(37, 8))
474290792Sgshapiro			sm_dprintf("setclass(%s, %s)\n", macname(class), str);
474364562Sgshapiro
474464562Sgshapiro		s = stab(str, ST_CLASS, ST_ENTER);
474571345Sgshapiro		setbitn(bitidx(class), s->s_class);
474664562Sgshapiro	}
474738032Speter}
474890792Sgshapiro/*
474938032Speter**  MAKEMAPENTRY -- create a map entry
475038032Speter**
475138032Speter**	Parameters:
475238032Speter**		line -- the config file line
475338032Speter**
475438032Speter**	Returns:
475538032Speter**		A pointer to the map that has been created.
475638032Speter**		NULL if there was a syntax error.
475738032Speter**
475838032Speter**	Side Effects:
475938032Speter**		Enters the map into the dictionary.
476038032Speter*/
476138032Speter
476238032SpeterMAP *
476338032Spetermakemapentry(line)
476438032Speter	char *line;
476538032Speter{
476638032Speter	register char *p;
476738032Speter	char *mapname;
476838032Speter	char *classname;
476938032Speter	register STAB *s;
477038032Speter	STAB *class;
477138032Speter
4772363466Sgshapiro	for (p = line; SM_ISSPACE(*p); p++)
477338032Speter		continue;
477438032Speter	if (!(isascii(*p) && isalnum(*p)))
477538032Speter	{
477638032Speter		syserr("readcf: config K line: no map name");
477738032Speter		return NULL;
477838032Speter	}
477938032Speter
478038032Speter	mapname = p;
478138032Speter	while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
478238032Speter		continue;
478338032Speter	if (*p != '\0')
478438032Speter		*p++ = '\0';
4785363466Sgshapiro	while (SM_ISSPACE(*p))
478638032Speter		p++;
478738032Speter	if (!(isascii(*p) && isalnum(*p)))
478838032Speter	{
478938032Speter		syserr("readcf: config K line, map %s: no map class", mapname);
479038032Speter		return NULL;
479138032Speter	}
479238032Speter	classname = p;
479338032Speter	while (isascii(*++p) && isalnum(*p))
479438032Speter		continue;
479538032Speter	if (*p != '\0')
479638032Speter		*p++ = '\0';
4797363466Sgshapiro	while (SM_ISSPACE(*p))
479838032Speter		p++;
479938032Speter
480038032Speter	/* look up the class */
480138032Speter	class = stab(classname, ST_MAPCLASS, ST_FIND);
480238032Speter	if (class == NULL)
480338032Speter	{
480490792Sgshapiro		syserr("readcf: map %s: class %s not available", mapname,
480590792Sgshapiro			classname);
480638032Speter		return NULL;
480738032Speter	}
480838032Speter
480938032Speter	/* enter the map */
481038032Speter	s = stab(mapname, ST_MAP, ST_ENTER);
481138032Speter	s->s_map.map_class = &class->s_mapclass;
481238032Speter	s->s_map.map_mname = newstr(mapname);
481338032Speter
481438032Speter	if (class->s_mapclass.map_parse(&s->s_map, p))
481538032Speter		s->s_map.map_mflags |= MF_VALID;
481638032Speter
481738032Speter	if (tTd(37, 5))
481838032Speter	{
481990792Sgshapiro		sm_dprintf("map %s, class %s, flags %lx, file %s,\n",
482090792Sgshapiro			   s->s_map.map_mname, s->s_map.map_class->map_cname,
482190792Sgshapiro			   s->s_map.map_mflags, s->s_map.map_file);
482290792Sgshapiro		sm_dprintf("\tapp %s, domain %s, rebuild %s\n",
482390792Sgshapiro			   s->s_map.map_app, s->s_map.map_domain,
482490792Sgshapiro			   s->s_map.map_rebuild);
482538032Speter	}
482638032Speter	return &s->s_map;
482738032Speter}
482890792Sgshapiro/*
482938032Speter**  STRTORWSET -- convert string to rewriting set number
483038032Speter**
483138032Speter**	Parameters:
483238032Speter**		p -- the pointer to the string to decode.
483338032Speter**		endp -- if set, store the trailing delimiter here.
483438032Speter**		stabmode -- ST_ENTER to create this entry, ST_FIND if
483538032Speter**			it must already exist.
483638032Speter**
483738032Speter**	Returns:
483838032Speter**		The appropriate ruleset number.
483938032Speter**		-1 if it is not valid (error already printed)
484038032Speter*/
484138032Speter
484238032Speterint
484338032Speterstrtorwset(p, endp, stabmode)
484438032Speter	char *p;
484538032Speter	char **endp;
484638032Speter	int stabmode;
484738032Speter{
484838032Speter	int ruleset;
484938032Speter	static int nextruleset = MAXRWSETS;
485038032Speter
4851363466Sgshapiro	while (SM_ISSPACE(*p))
485238032Speter		p++;
485338032Speter	if (!isascii(*p))
485438032Speter	{
485538032Speter		syserr("invalid ruleset name: \"%.20s\"", p);
485638032Speter		return -1;
485738032Speter	}
485838032Speter	if (isdigit(*p))
485938032Speter	{
486038032Speter		ruleset = strtol(p, endp, 10);
486138032Speter		if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
486238032Speter		{
486338032Speter			syserr("bad ruleset %d (%d max)",
486438032Speter				ruleset, MAXRWSETS / 2);
486538032Speter			ruleset = -1;
486638032Speter		}
486738032Speter	}
486838032Speter	else
486938032Speter	{
487038032Speter		STAB *s;
487138032Speter		char delim;
487264562Sgshapiro		char *q = NULL;
487338032Speter
487438032Speter		q = p;
4875203004Sgshapiro		while (*p != '\0' && isascii(*p) && (isalnum(*p) || *p == '_'))
487638032Speter			p++;
487738032Speter		if (q == p || !(isascii(*q) && isalpha(*q)))
487838032Speter		{
487938032Speter			/* no valid characters */
488038032Speter			syserr("invalid ruleset name: \"%.20s\"", q);
488138032Speter			return -1;
488238032Speter		}
4883363466Sgshapiro		while (SM_ISSPACE(*p))
488438032Speter			*p++ = '\0';
488538032Speter		delim = *p;
488638032Speter		if (delim != '\0')
488738032Speter			*p = '\0';
488838032Speter		s = stab(q, ST_RULESET, stabmode);
488938032Speter		if (delim != '\0')
489038032Speter			*p = delim;
489138032Speter
489238032Speter		if (s == NULL)
489338032Speter			return -1;
489438032Speter
489538032Speter		if (stabmode == ST_ENTER && delim == '=')
489638032Speter		{
489738032Speter			while (isascii(*++p) && isspace(*p))
489838032Speter				continue;
489938032Speter			if (!(isascii(*p) && isdigit(*p)))
490038032Speter			{
490138032Speter				syserr("bad ruleset definition \"%s\" (number required after `=')", q);
490238032Speter				ruleset = -1;
490338032Speter			}
490438032Speter			else
490538032Speter			{
490638032Speter				ruleset = strtol(p, endp, 10);
490738032Speter				if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
490838032Speter				{
490938032Speter					syserr("bad ruleset number %d in \"%s\" (%d max)",
491038032Speter						ruleset, q, MAXRWSETS / 2);
491138032Speter					ruleset = -1;
491238032Speter				}
491338032Speter			}
491438032Speter		}
491538032Speter		else
491638032Speter		{
491738032Speter			if (endp != NULL)
491838032Speter				*endp = p;
491964562Sgshapiro			if (s->s_ruleset >= 0)
492038032Speter				ruleset = s->s_ruleset;
492138032Speter			else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
492238032Speter			{
492338032Speter				syserr("%s: too many named rulesets (%d max)",
492438032Speter					q, MAXRWSETS / 2);
492538032Speter				ruleset = -1;
492638032Speter			}
492738032Speter		}
492864562Sgshapiro		if (s->s_ruleset >= 0 &&
492964562Sgshapiro		    ruleset >= 0 &&
493064562Sgshapiro		    ruleset != s->s_ruleset)
493138032Speter		{
493238032Speter			syserr("%s: ruleset changed value (old %d, new %d)",
493338032Speter				q, s->s_ruleset, ruleset);
493438032Speter			ruleset = s->s_ruleset;
493538032Speter		}
493664562Sgshapiro		else if (ruleset >= 0)
493738032Speter		{
493838032Speter			s->s_ruleset = ruleset;
493938032Speter		}
494071345Sgshapiro		if (stabmode == ST_ENTER && ruleset >= 0)
494164562Sgshapiro		{
494264562Sgshapiro			char *h = NULL;
494364562Sgshapiro
494464562Sgshapiro			if (RuleSetNames[ruleset] != NULL)
494590792Sgshapiro				sm_free(RuleSetNames[ruleset]); /* XXX */
494664562Sgshapiro			if (delim != '\0' && (h = strchr(q, delim)) != NULL)
494764562Sgshapiro				*h = '\0';
494864562Sgshapiro			RuleSetNames[ruleset] = newstr(q);
494964562Sgshapiro			if (delim == '/' && h != NULL)
495064562Sgshapiro				*h = delim;	/* put back delim */
495164562Sgshapiro		}
495238032Speter	}
495338032Speter	return ruleset;
495438032Speter}
495590792Sgshapiro/*
495664562Sgshapiro**  SETTIMEOUT -- set an individual timeout
495764562Sgshapiro**
495864562Sgshapiro**	Parameters:
495964562Sgshapiro**		name -- the name of the timeout.
496064562Sgshapiro**		val -- the value of the timeout.
496164562Sgshapiro**		sticky -- if set, don't let other setoptions override
496264562Sgshapiro**			this value.
496364562Sgshapiro**
496464562Sgshapiro**	Returns:
496564562Sgshapiro**		none.
496664562Sgshapiro*/
496764562Sgshapiro
496864562Sgshapiro/* set if Timeout sub-option is stuck */
496964562Sgshapirostatic BITMAP256	StickyTimeoutOpt;
497064562Sgshapiro
497164562Sgshapirostatic struct timeoutinfo
497264562Sgshapiro{
497390792Sgshapiro	char		*to_name;	/* long name of timeout */
497490792Sgshapiro	unsigned char	to_code;	/* code for option */
497564562Sgshapiro} TimeOutTab[] =
497664562Sgshapiro{
497764562Sgshapiro#define TO_INITIAL			0x01
497864562Sgshapiro	{ "initial",			TO_INITIAL			},
497964562Sgshapiro#define TO_MAIL				0x02
498064562Sgshapiro	{ "mail",			TO_MAIL				},
498164562Sgshapiro#define TO_RCPT				0x03
498264562Sgshapiro	{ "rcpt",			TO_RCPT				},
498364562Sgshapiro#define TO_DATAINIT			0x04
498464562Sgshapiro	{ "datainit",			TO_DATAINIT			},
498564562Sgshapiro#define TO_DATABLOCK			0x05
498664562Sgshapiro	{ "datablock",			TO_DATABLOCK			},
498764562Sgshapiro#define TO_DATAFINAL			0x06
498864562Sgshapiro	{ "datafinal",			TO_DATAFINAL			},
498964562Sgshapiro#define TO_COMMAND			0x07
499064562Sgshapiro	{ "command",			TO_COMMAND			},
499164562Sgshapiro#define TO_RSET				0x08
499264562Sgshapiro	{ "rset",			TO_RSET				},
499364562Sgshapiro#define TO_HELO				0x09
499464562Sgshapiro	{ "helo",			TO_HELO				},
499564562Sgshapiro#define TO_QUIT				0x0A
499664562Sgshapiro	{ "quit",			TO_QUIT				},
499764562Sgshapiro#define TO_MISC				0x0B
499864562Sgshapiro	{ "misc",			TO_MISC				},
499964562Sgshapiro#define TO_IDENT			0x0C
500064562Sgshapiro	{ "ident",			TO_IDENT			},
500164562Sgshapiro#define TO_FILEOPEN			0x0D
500264562Sgshapiro	{ "fileopen",			TO_FILEOPEN			},
500364562Sgshapiro#define TO_CONNECT			0x0E
500464562Sgshapiro	{ "connect",			TO_CONNECT			},
500564562Sgshapiro#define TO_ICONNECT			0x0F
500664562Sgshapiro	{ "iconnect",			TO_ICONNECT			},
500764562Sgshapiro#define TO_QUEUEWARN			0x10
500864562Sgshapiro	{ "queuewarn",			TO_QUEUEWARN			},
500964562Sgshapiro	{ "queuewarn.*",		TO_QUEUEWARN			},
501064562Sgshapiro#define TO_QUEUEWARN_NORMAL		0x11
501164562Sgshapiro	{ "queuewarn.normal",		TO_QUEUEWARN_NORMAL		},
501264562Sgshapiro#define TO_QUEUEWARN_URGENT		0x12
501364562Sgshapiro	{ "queuewarn.urgent",		TO_QUEUEWARN_URGENT		},
501464562Sgshapiro#define TO_QUEUEWARN_NON_URGENT		0x13
501564562Sgshapiro	{ "queuewarn.non-urgent",	TO_QUEUEWARN_NON_URGENT		},
501664562Sgshapiro#define TO_QUEUERETURN			0x14
501764562Sgshapiro	{ "queuereturn",		TO_QUEUERETURN			},
501864562Sgshapiro	{ "queuereturn.*",		TO_QUEUERETURN			},
501964562Sgshapiro#define TO_QUEUERETURN_NORMAL		0x15
502064562Sgshapiro	{ "queuereturn.normal",		TO_QUEUERETURN_NORMAL		},
502164562Sgshapiro#define TO_QUEUERETURN_URGENT		0x16
502264562Sgshapiro	{ "queuereturn.urgent",		TO_QUEUERETURN_URGENT		},
502364562Sgshapiro#define TO_QUEUERETURN_NON_URGENT	0x17
502464562Sgshapiro	{ "queuereturn.non-urgent",	TO_QUEUERETURN_NON_URGENT	},
502564562Sgshapiro#define TO_HOSTSTATUS			0x18
502664562Sgshapiro	{ "hoststatus",			TO_HOSTSTATUS			},
502764562Sgshapiro#define TO_RESOLVER_RETRANS		0x19
502864562Sgshapiro	{ "resolver.retrans",		TO_RESOLVER_RETRANS		},
502964562Sgshapiro#define TO_RESOLVER_RETRANS_NORMAL	0x1A
503064562Sgshapiro	{ "resolver.retrans.normal",	TO_RESOLVER_RETRANS_NORMAL	},
503164562Sgshapiro#define TO_RESOLVER_RETRANS_FIRST	0x1B
503264562Sgshapiro	{ "resolver.retrans.first",	TO_RESOLVER_RETRANS_FIRST	},
503364562Sgshapiro#define TO_RESOLVER_RETRY		0x1C
503464562Sgshapiro	{ "resolver.retry",		TO_RESOLVER_RETRY		},
503564562Sgshapiro#define TO_RESOLVER_RETRY_NORMAL	0x1D
503664562Sgshapiro	{ "resolver.retry.normal",	TO_RESOLVER_RETRY_NORMAL	},
503764562Sgshapiro#define TO_RESOLVER_RETRY_FIRST		0x1E
503864562Sgshapiro	{ "resolver.retry.first",	TO_RESOLVER_RETRY_FIRST		},
503964562Sgshapiro#define TO_CONTROL			0x1F
504064562Sgshapiro	{ "control",			TO_CONTROL			},
504190792Sgshapiro#define TO_LHLO				0x20
504290792Sgshapiro	{ "lhlo",			TO_LHLO				},
504390792Sgshapiro#define TO_AUTH				0x21
504490792Sgshapiro	{ "auth",			TO_AUTH				},
504590792Sgshapiro#define TO_STARTTLS			0x22
504690792Sgshapiro	{ "starttls",			TO_STARTTLS			},
504790792Sgshapiro#define TO_ACONNECT			0x23
504890792Sgshapiro	{ "aconnect",			TO_ACONNECT			},
5049132943Sgshapiro#define TO_QUEUEWARN_DSN		0x24
5050112810Sgshapiro	{ "queuewarn.dsn",		TO_QUEUEWARN_DSN		},
5051132943Sgshapiro#define TO_QUEUERETURN_DSN		0x25
5052112810Sgshapiro	{ "queuereturn.dsn",		TO_QUEUERETURN_DSN		},
505364562Sgshapiro	{ NULL,				0				},
505464562Sgshapiro};
505564562Sgshapiro
505664562Sgshapiro
505764562Sgshapirostatic void
505864562Sgshapirosettimeout(name, val, sticky)
505964562Sgshapiro	char *name;
506064562Sgshapiro	char *val;
506164562Sgshapiro	bool sticky;
506264562Sgshapiro{
506364562Sgshapiro	register struct timeoutinfo *to;
506490792Sgshapiro	int i, addopts;
506564562Sgshapiro	time_t toval;
506664562Sgshapiro
506764562Sgshapiro	if (tTd(37, 2))
506890792Sgshapiro		sm_dprintf("settimeout(%s = %s)", name, val);
506964562Sgshapiro
507064562Sgshapiro	for (to = TimeOutTab; to->to_name != NULL; to++)
507164562Sgshapiro	{
507290792Sgshapiro		if (sm_strcasecmp(to->to_name, name) == 0)
507364562Sgshapiro			break;
507464562Sgshapiro	}
507564562Sgshapiro
507664562Sgshapiro	if (to->to_name == NULL)
507771345Sgshapiro	{
507871345Sgshapiro		errno = 0; /* avoid bogus error text */
507964562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
508071345Sgshapiro		return;
508171345Sgshapiro	}
508264562Sgshapiro
508364562Sgshapiro	/*
508464562Sgshapiro	**  See if this option is preset for us.
508564562Sgshapiro	*/
508664562Sgshapiro
508764562Sgshapiro	if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
508864562Sgshapiro	{
508964562Sgshapiro		if (tTd(37, 2))
509090792Sgshapiro			sm_dprintf(" (ignored)\n");
509164562Sgshapiro		return;
509264562Sgshapiro	}
509364562Sgshapiro
509464562Sgshapiro	if (tTd(37, 2))
509590792Sgshapiro		sm_dprintf("\n");
509664562Sgshapiro
509764562Sgshapiro	toval = convtime(val, 'm');
509880785Sgshapiro	addopts = 0;
509964562Sgshapiro
510064562Sgshapiro	switch (to->to_code)
510164562Sgshapiro	{
510264562Sgshapiro	  case TO_INITIAL:
510364562Sgshapiro		TimeOuts.to_initial = toval;
510464562Sgshapiro		break;
510564562Sgshapiro
510664562Sgshapiro	  case TO_MAIL:
510764562Sgshapiro		TimeOuts.to_mail = toval;
510864562Sgshapiro		break;
510964562Sgshapiro
511064562Sgshapiro	  case TO_RCPT:
511164562Sgshapiro		TimeOuts.to_rcpt = toval;
511264562Sgshapiro		break;
511364562Sgshapiro
511464562Sgshapiro	  case TO_DATAINIT:
511564562Sgshapiro		TimeOuts.to_datainit = toval;
511664562Sgshapiro		break;
511764562Sgshapiro
511864562Sgshapiro	  case TO_DATABLOCK:
511964562Sgshapiro		TimeOuts.to_datablock = toval;
512064562Sgshapiro		break;
512164562Sgshapiro
512264562Sgshapiro	  case TO_DATAFINAL:
512364562Sgshapiro		TimeOuts.to_datafinal = toval;
512464562Sgshapiro		break;
512564562Sgshapiro
512664562Sgshapiro	  case TO_COMMAND:
512764562Sgshapiro		TimeOuts.to_nextcommand = toval;
512864562Sgshapiro		break;
512964562Sgshapiro
513064562Sgshapiro	  case TO_RSET:
513164562Sgshapiro		TimeOuts.to_rset = toval;
513264562Sgshapiro		break;
513364562Sgshapiro
513464562Sgshapiro	  case TO_HELO:
513564562Sgshapiro		TimeOuts.to_helo = toval;
513664562Sgshapiro		break;
513764562Sgshapiro
513864562Sgshapiro	  case TO_QUIT:
513964562Sgshapiro		TimeOuts.to_quit = toval;
514064562Sgshapiro		break;
514164562Sgshapiro
514264562Sgshapiro	  case TO_MISC:
514364562Sgshapiro		TimeOuts.to_miscshort = toval;
514464562Sgshapiro		break;
514564562Sgshapiro
514664562Sgshapiro	  case TO_IDENT:
514764562Sgshapiro		TimeOuts.to_ident = toval;
514864562Sgshapiro		break;
514964562Sgshapiro
515064562Sgshapiro	  case TO_FILEOPEN:
515164562Sgshapiro		TimeOuts.to_fileopen = toval;
515264562Sgshapiro		break;
515364562Sgshapiro
515464562Sgshapiro	  case TO_CONNECT:
515564562Sgshapiro		TimeOuts.to_connect = toval;
515664562Sgshapiro		break;
515764562Sgshapiro
515864562Sgshapiro	  case TO_ICONNECT:
515964562Sgshapiro		TimeOuts.to_iconnect = toval;
516064562Sgshapiro		break;
516164562Sgshapiro
516290792Sgshapiro	  case TO_ACONNECT:
516390792Sgshapiro		TimeOuts.to_aconnect = toval;
516490792Sgshapiro		break;
516590792Sgshapiro
516664562Sgshapiro	  case TO_QUEUEWARN:
516764562Sgshapiro		toval = convtime(val, 'h');
516864562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
516964562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
517064562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
5171112810Sgshapiro		TimeOuts.to_q_warning[TOC_DSN] = toval;
517280785Sgshapiro		addopts = 2;
517364562Sgshapiro		break;
517464562Sgshapiro
517564562Sgshapiro	  case TO_QUEUEWARN_NORMAL:
517664562Sgshapiro		toval = convtime(val, 'h');
517764562Sgshapiro		TimeOuts.to_q_warning[TOC_NORMAL] = toval;
517864562Sgshapiro		break;
517964562Sgshapiro
518064562Sgshapiro	  case TO_QUEUEWARN_URGENT:
518164562Sgshapiro		toval = convtime(val, 'h');
518264562Sgshapiro		TimeOuts.to_q_warning[TOC_URGENT] = toval;
518364562Sgshapiro		break;
518464562Sgshapiro
518564562Sgshapiro	  case TO_QUEUEWARN_NON_URGENT:
518664562Sgshapiro		toval = convtime(val, 'h');
518764562Sgshapiro		TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
518864562Sgshapiro		break;
518964562Sgshapiro
5190112810Sgshapiro	  case TO_QUEUEWARN_DSN:
5191112810Sgshapiro		toval = convtime(val, 'h');
5192112810Sgshapiro		TimeOuts.to_q_warning[TOC_DSN] = toval;
5193112810Sgshapiro		break;
5194112810Sgshapiro
519564562Sgshapiro	  case TO_QUEUERETURN:
519664562Sgshapiro		toval = convtime(val, 'd');
519764562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
519864562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
519964562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
5200112810Sgshapiro		TimeOuts.to_q_return[TOC_DSN] = toval;
520180785Sgshapiro		addopts = 2;
520264562Sgshapiro		break;
520364562Sgshapiro
520464562Sgshapiro	  case TO_QUEUERETURN_NORMAL:
520564562Sgshapiro		toval = convtime(val, 'd');
520664562Sgshapiro		TimeOuts.to_q_return[TOC_NORMAL] = toval;
520764562Sgshapiro		break;
520864562Sgshapiro
520964562Sgshapiro	  case TO_QUEUERETURN_URGENT:
521064562Sgshapiro		toval = convtime(val, 'd');
521164562Sgshapiro		TimeOuts.to_q_return[TOC_URGENT] = toval;
521264562Sgshapiro		break;
521364562Sgshapiro
521464562Sgshapiro	  case TO_QUEUERETURN_NON_URGENT:
521564562Sgshapiro		toval = convtime(val, 'd');
521664562Sgshapiro		TimeOuts.to_q_return[TOC_NONURGENT] = toval;
521764562Sgshapiro		break;
521864562Sgshapiro
5219112810Sgshapiro	  case TO_QUEUERETURN_DSN:
5220112810Sgshapiro		toval = convtime(val, 'd');
5221112810Sgshapiro		TimeOuts.to_q_return[TOC_DSN] = toval;
5222112810Sgshapiro		break;
5223112810Sgshapiro
522464562Sgshapiro	  case TO_HOSTSTATUS:
522564562Sgshapiro		MciInfoTimeout = toval;
522664562Sgshapiro		break;
522764562Sgshapiro
522864562Sgshapiro	  case TO_RESOLVER_RETRANS:
522964562Sgshapiro		toval = convtime(val, 's');
523064562Sgshapiro		TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
523164562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = toval;
523264562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
523380785Sgshapiro		addopts = 2;
523464562Sgshapiro		break;
523564562Sgshapiro
523664562Sgshapiro	  case TO_RESOLVER_RETRY:
523764562Sgshapiro		i = atoi(val);
523864562Sgshapiro		TimeOuts.res_retry[RES_TO_DEFAULT] = i;
523964562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = i;
524064562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = i;
524180785Sgshapiro		addopts = 2;
524264562Sgshapiro		break;
524364562Sgshapiro
524464562Sgshapiro	  case TO_RESOLVER_RETRANS_NORMAL:
524564562Sgshapiro		TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
524664562Sgshapiro		break;
524764562Sgshapiro
524864562Sgshapiro	  case TO_RESOLVER_RETRY_NORMAL:
524964562Sgshapiro		TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
525064562Sgshapiro		break;
525164562Sgshapiro
525264562Sgshapiro	  case TO_RESOLVER_RETRANS_FIRST:
525364562Sgshapiro		TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
525464562Sgshapiro		break;
525564562Sgshapiro
525664562Sgshapiro	  case TO_RESOLVER_RETRY_FIRST:
525764562Sgshapiro		TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
525864562Sgshapiro		break;
525964562Sgshapiro
526064562Sgshapiro	  case TO_CONTROL:
526164562Sgshapiro		TimeOuts.to_control = toval;
526264562Sgshapiro		break;
526364562Sgshapiro
526490792Sgshapiro	  case TO_LHLO:
526590792Sgshapiro		TimeOuts.to_lhlo = toval;
526690792Sgshapiro		break;
526790792Sgshapiro
526890792Sgshapiro#if SASL
526990792Sgshapiro	  case TO_AUTH:
527090792Sgshapiro		TimeOuts.to_auth = toval;
527190792Sgshapiro		break;
5272363466Sgshapiro#endif
527390792Sgshapiro
527490792Sgshapiro#if STARTTLS
527590792Sgshapiro	  case TO_STARTTLS:
527690792Sgshapiro		TimeOuts.to_starttls = toval;
527790792Sgshapiro		break;
5278363466Sgshapiro#endif
527990792Sgshapiro
528064562Sgshapiro	  default:
528164562Sgshapiro		syserr("settimeout: invalid timeout %s", name);
528264562Sgshapiro		break;
528364562Sgshapiro	}
528464562Sgshapiro
528564562Sgshapiro	if (sticky)
528680785Sgshapiro	{
528780785Sgshapiro		for (i = 0; i <= addopts; i++)
528880785Sgshapiro			setbitn(to->to_code + i, StickyTimeoutOpt);
528980785Sgshapiro	}
529064562Sgshapiro}
529190792Sgshapiro/*
529238032Speter**  INITTIMEOUTS -- parse and set timeout values
529338032Speter**
529438032Speter**	Parameters:
529538032Speter**		val -- a pointer to the values.  If NULL, do initial
529638032Speter**			settings.
529764562Sgshapiro**		sticky -- if set, don't let other setoptions override
529864562Sgshapiro**			this suboption value.
529938032Speter**
530038032Speter**	Returns:
530138032Speter**		none.
530238032Speter**
530338032Speter**	Side Effects:
530438032Speter**		Initializes the TimeOuts structure
530538032Speter*/
530638032Speter
530738032Spetervoid
530864562Sgshapiroinittimeouts(val, sticky)
530938032Speter	register char *val;
531064562Sgshapiro	bool sticky;
531138032Speter{
531238032Speter	register char *p;
531338032Speter
531438032Speter	if (tTd(37, 2))
531590792Sgshapiro		sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
531638032Speter	if (val == NULL)
531738032Speter	{
531838032Speter		TimeOuts.to_connect = (time_t) 0 SECONDS;
531990792Sgshapiro		TimeOuts.to_aconnect = (time_t) 0 SECONDS;
532094334Sgshapiro		TimeOuts.to_iconnect = (time_t) 0 SECONDS;
532138032Speter		TimeOuts.to_initial = (time_t) 5 MINUTES;
532238032Speter		TimeOuts.to_helo = (time_t) 5 MINUTES;
532338032Speter		TimeOuts.to_mail = (time_t) 10 MINUTES;
532438032Speter		TimeOuts.to_rcpt = (time_t) 1 HOUR;
532538032Speter		TimeOuts.to_datainit = (time_t) 5 MINUTES;
532638032Speter		TimeOuts.to_datablock = (time_t) 1 HOUR;
532738032Speter		TimeOuts.to_datafinal = (time_t) 1 HOUR;
532838032Speter		TimeOuts.to_rset = (time_t) 5 MINUTES;
532938032Speter		TimeOuts.to_quit = (time_t) 2 MINUTES;
533038032Speter		TimeOuts.to_nextcommand = (time_t) 1 HOUR;
533138032Speter		TimeOuts.to_miscshort = (time_t) 2 MINUTES;
533238032Speter#if IDENTPROTO
533364562Sgshapiro		TimeOuts.to_ident = (time_t) 5 SECONDS;
5334363466Sgshapiro#else
533538032Speter		TimeOuts.to_ident = (time_t) 0 SECONDS;
5336363466Sgshapiro#endif
533738032Speter		TimeOuts.to_fileopen = (time_t) 60 SECONDS;
533864562Sgshapiro		TimeOuts.to_control = (time_t) 2 MINUTES;
533990792Sgshapiro		TimeOuts.to_lhlo = (time_t) 2 MINUTES;
534090792Sgshapiro#if SASL
534190792Sgshapiro		TimeOuts.to_auth = (time_t) 10 MINUTES;
5342363466Sgshapiro#endif
534390792Sgshapiro#if STARTTLS
534490792Sgshapiro		TimeOuts.to_starttls = (time_t) 1 HOUR;
5345363466Sgshapiro#endif
534638032Speter		if (tTd(37, 5))
534738032Speter		{
534890792Sgshapiro			sm_dprintf("Timeouts:\n");
534990792Sgshapiro			sm_dprintf("  connect = %ld\n",
535090792Sgshapiro				   (long) TimeOuts.to_connect);
535190792Sgshapiro			sm_dprintf("  aconnect = %ld\n",
535290792Sgshapiro				   (long) TimeOuts.to_aconnect);
535390792Sgshapiro			sm_dprintf("  initial = %ld\n",
535490792Sgshapiro				   (long) TimeOuts.to_initial);
535590792Sgshapiro			sm_dprintf("  helo = %ld\n", (long) TimeOuts.to_helo);
535690792Sgshapiro			sm_dprintf("  mail = %ld\n", (long) TimeOuts.to_mail);
535790792Sgshapiro			sm_dprintf("  rcpt = %ld\n", (long) TimeOuts.to_rcpt);
535890792Sgshapiro			sm_dprintf("  datainit = %ld\n",
535990792Sgshapiro				   (long) TimeOuts.to_datainit);
536090792Sgshapiro			sm_dprintf("  datablock = %ld\n",
536190792Sgshapiro				   (long) TimeOuts.to_datablock);
536290792Sgshapiro			sm_dprintf("  datafinal = %ld\n",
536390792Sgshapiro				   (long) TimeOuts.to_datafinal);
536490792Sgshapiro			sm_dprintf("  rset = %ld\n", (long) TimeOuts.to_rset);
536590792Sgshapiro			sm_dprintf("  quit = %ld\n", (long) TimeOuts.to_quit);
536690792Sgshapiro			sm_dprintf("  nextcommand = %ld\n",
536790792Sgshapiro				   (long) TimeOuts.to_nextcommand);
536890792Sgshapiro			sm_dprintf("  miscshort = %ld\n",
536990792Sgshapiro				   (long) TimeOuts.to_miscshort);
537090792Sgshapiro			sm_dprintf("  ident = %ld\n", (long) TimeOuts.to_ident);
537190792Sgshapiro			sm_dprintf("  fileopen = %ld\n",
537290792Sgshapiro				   (long) TimeOuts.to_fileopen);
537390792Sgshapiro			sm_dprintf("  lhlo = %ld\n",
537490792Sgshapiro				   (long) TimeOuts.to_lhlo);
537590792Sgshapiro			sm_dprintf("  control = %ld\n",
537690792Sgshapiro				   (long) TimeOuts.to_control);
537738032Speter		}
537838032Speter		return;
537938032Speter	}
538038032Speter
538138032Speter	for (;; val = p)
538238032Speter	{
5383363466Sgshapiro		while (SM_ISSPACE(*val))
538438032Speter			val++;
538538032Speter		if (*val == '\0')
538638032Speter			break;
538738032Speter		for (p = val; *p != '\0' && *p != ','; p++)
538838032Speter			continue;
538938032Speter		if (*p != '\0')
539038032Speter			*p++ = '\0';
539138032Speter
539238032Speter		if (isascii(*val) && isdigit(*val))
539338032Speter		{
539438032Speter			/* old syntax -- set everything */
539538032Speter			TimeOuts.to_mail = convtime(val, 'm');
539638032Speter			TimeOuts.to_rcpt = TimeOuts.to_mail;
539738032Speter			TimeOuts.to_datainit = TimeOuts.to_mail;
539838032Speter			TimeOuts.to_datablock = TimeOuts.to_mail;
539938032Speter			TimeOuts.to_datafinal = TimeOuts.to_mail;
540038032Speter			TimeOuts.to_nextcommand = TimeOuts.to_mail;
540164562Sgshapiro			if (sticky)
540264562Sgshapiro			{
540364562Sgshapiro				setbitn(TO_MAIL, StickyTimeoutOpt);
540464562Sgshapiro				setbitn(TO_RCPT, StickyTimeoutOpt);
540564562Sgshapiro				setbitn(TO_DATAINIT, StickyTimeoutOpt);
540664562Sgshapiro				setbitn(TO_DATABLOCK, StickyTimeoutOpt);
540764562Sgshapiro				setbitn(TO_DATAFINAL, StickyTimeoutOpt);
540864562Sgshapiro				setbitn(TO_COMMAND, StickyTimeoutOpt);
540964562Sgshapiro			}
541038032Speter			continue;
541138032Speter		}
541238032Speter		else
541338032Speter		{
541438032Speter			register char *q = strchr(val, ':');
541538032Speter
541638032Speter			if (q == NULL && (q = strchr(val, '=')) == NULL)
541738032Speter			{
541838032Speter				/* syntax error */
541938032Speter				continue;
542038032Speter			}
542138032Speter			*q++ = '\0';
542264562Sgshapiro			settimeout(val, q, sticky);
542338032Speter		}
542438032Speter	}
542538032Speter}
5426