122709Sdist /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
362530Sbostic * Copyright (c) 1988, 1993
462530Sbostic * The Regents of the University of California. All rights reserved.
533731Sbostic *
642829Sbostic * %sccs.include.redist.c%
733731Sbostic */
822709Sdist
922709Sdist #ifndef lint
10*69976Seric static char sccsid[] = "@(#)readcf.c 8.113 (Berkeley) 06/22/95";
1133731Sbostic #endif /* not lint */
1222709Sdist
133313Seric # include "sendmail.h"
1464133Seric # include <grp.h>
1566334Seric #if NAMED_BIND
1657207Seric # include <resolv.h>
1757207Seric #endif
183308Seric
193308Seric /*
203308Seric ** READCF -- read control file.
213308Seric **
223308Seric ** This routine reads the control file and builds the internal
233308Seric ** form.
243308Seric **
254432Seric ** The file is formatted as a sequence of lines, each taken
264432Seric ** atomically. The first character of each line describes how
274432Seric ** the line is to be interpreted. The lines are:
284432Seric ** Dxval Define macro x to have value val.
294432Seric ** Cxword Put word into class x.
304432Seric ** Fxfile [fmt] Read file for lines to put into
314432Seric ** class x. Use scanf string 'fmt'
324432Seric ** or "%s" if not present. Fmt should
334432Seric ** only produce one string-valued result.
344432Seric ** Hname: value Define header with field-name 'name'
354432Seric ** and value as specified; this will be
364432Seric ** macro expanded immediately before
374432Seric ** use.
384432Seric ** Sn Use rewriting set n.
394432Seric ** Rlhs rhs Rewrite addresses that match lhs to
404432Seric ** be rhs.
4124944Seric ** Mn arg=val... Define mailer. n is the internal name.
4224944Seric ** Args specify mailer parameters.
438252Seric ** Oxvalue Set option x to value.
448252Seric ** Pname=value Set precedence name to value.
4564718Seric ** Vversioncode[/vendorcode]
4664718Seric ** Version level/vendor name of
4764718Seric ** configuration syntax.
4853654Seric ** Kmapname mapclass arguments....
4953654Seric ** Define keyed lookup of a given class.
5053654Seric ** Arguments are class dependent.
5169476Seric ** Eenvar=value Set the environment value to the given value.
524432Seric **
533308Seric ** Parameters:
543308Seric ** cfname -- control file name.
5554973Seric ** safe -- TRUE if this is the system config file;
5654973Seric ** FALSE otherwise.
5755012Seric ** e -- the main envelope.
583308Seric **
593308Seric ** Returns:
603308Seric ** none.
613308Seric **
623308Seric ** Side Effects:
633308Seric ** Builds several internal tables.
643308Seric */
653308Seric
6669748Seric void
readcf(cfname,safe,e)6755012Seric readcf(cfname, safe, e)
683308Seric char *cfname;
6954973Seric bool safe;
7055012Seric register ENVELOPE *e;
713308Seric {
723308Seric FILE *cf;
738547Seric int ruleset = 0;
748547Seric char *q;
759350Seric struct rewrite *rwp = NULL;
7657135Seric char *bp;
7764718Seric auto char *ep;
7857589Seric int nfuzzy;
7964133Seric char *file;
8064133Seric bool optional;
8168481Seric int mid;
823308Seric char buf[MAXLINE];
833308Seric register char *p;
843308Seric extern char **copyplist();
8552647Seric struct stat statb;
865909Seric char exbuf[MAXLINE];
8765066Seric char pvpbuf[MAXLINE + MAXATOM];
8868481Seric static char *null_list[1] = { NULL };
8969748Seric extern char *munchstring __P((char *, char **));
9069748Seric extern void fileclass __P((int, char *, char *, bool, bool));
9169748Seric extern void toomany __P((int, int));
923308Seric
9352647Seric FileName = cfname;
9452647Seric LineNumber = 0;
9552647Seric
963308Seric cf = fopen(cfname, "r");
973308Seric if (cf == NULL)
983308Seric {
9952647Seric syserr("cannot open");
1003308Seric exit(EX_OSFILE);
1013308Seric }
1023308Seric
10352647Seric if (fstat(fileno(cf), &statb) < 0)
10452647Seric {
10552647Seric syserr("cannot fstat");
10652647Seric exit(EX_OSFILE);
10752647Seric }
10852647Seric
10952647Seric if (!S_ISREG(statb.st_mode))
11052647Seric {
11152647Seric syserr("not a plain file");
11252647Seric exit(EX_OSFILE);
11352647Seric }
11452647Seric
11552647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
11652647Seric {
11769686Seric if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
11853037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
11953037Seric FileName);
12053037Seric #ifdef LOG
12153037Seric if (LogLevel > 0)
12253037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
12353037Seric FileName);
12453037Seric #endif
12552647Seric }
12652647Seric
12759254Seric #ifdef XLA
12859254Seric xla_zero();
12959254Seric #endif
13059254Seric
13157135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
1323308Seric {
13357135Seric if (bp[0] == '#')
13457135Seric {
13557135Seric if (bp != buf)
13657135Seric free(bp);
13752637Seric continue;
13857135Seric }
13952637Seric
14068481Seric /* do macro expansion mappings */
14157135Seric for (p = bp; *p != '\0'; p++)
14216157Seric {
14357135Seric if (*p == '#' && p > bp && ConfigLevel >= 3)
14452647Seric {
14552647Seric /* this is an on-line comment */
14652647Seric register char *e;
14752647Seric
14858050Seric switch (*--p & 0377)
14952647Seric {
15058050Seric case MACROEXPAND:
15152647Seric /* it's from $# -- let it go through */
15252647Seric p++;
15352647Seric break;
15452647Seric
15552647Seric case '\\':
15652647Seric /* it's backslash escaped */
15752647Seric (void) strcpy(p, p + 1);
15852647Seric break;
15952647Seric
16052647Seric default:
16152647Seric /* delete preceeding white space */
16258050Seric while (isascii(*p) && isspace(*p) && p > bp)
16352647Seric p--;
16456795Seric if ((e = strchr(++p, '\n')) != NULL)
16552647Seric (void) strcpy(p, e);
16652647Seric else
16752647Seric p[0] = p[1] = '\0';
16852647Seric break;
16952647Seric }
17052647Seric continue;
17152647Seric }
17252647Seric
17368481Seric if (*p != '$' || p[1] == '\0')
17416157Seric continue;
17516157Seric
17616157Seric if (p[1] == '$')
17716157Seric {
17816157Seric /* actual dollar sign.... */
17923111Seric (void) strcpy(p, p + 1);
18016157Seric continue;
18116157Seric }
18216157Seric
18316157Seric /* convert to macro expansion character */
18468481Seric *p++ = MACROEXPAND;
18568481Seric
18669975Seric /* special handling for $=, $~, and $& */
18769975Seric if (*p == '=' || *p == '~' || *p == '&')
18869975Seric p++;
18969975Seric
19068481Seric /* convert macro name to code */
19168481Seric *p = macid(p, &ep);
19268481Seric if (ep != p)
19368481Seric strcpy(p + 1, ep);
19416157Seric }
19516157Seric
19616157Seric /* interpret this line */
19764718Seric errno = 0;
19857135Seric switch (bp[0])
1993308Seric {
2003308Seric case '\0':
2013308Seric case '#': /* comment */
2023308Seric break;
2033308Seric
2043308Seric case 'R': /* rewriting rule */
20557135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
2063308Seric continue;
2073308Seric
2083308Seric if (*p == '\0')
2095909Seric {
21065821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp);
2115909Seric break;
2125909Seric }
2135909Seric
2145909Seric /* allocate space for the rule header */
2155909Seric if (rwp == NULL)
2165909Seric {
2175909Seric RewriteRules[ruleset] = rwp =
2185909Seric (struct rewrite *) xalloc(sizeof *rwp);
2195909Seric }
2203308Seric else
2213308Seric {
2225909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
2235909Seric rwp = rwp->r_next;
2245909Seric }
2255909Seric rwp->r_next = NULL;
2263308Seric
2275909Seric /* expand and save the LHS */
2285909Seric *p = '\0';
22968529Seric expand(&bp[1], exbuf, sizeof exbuf, e);
23065066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
23168711Seric sizeof pvpbuf, NULL, NULL);
23257589Seric nfuzzy = 0;
2335909Seric if (rwp->r_lhs != NULL)
23457589Seric {
23557589Seric register char **ap;
23657589Seric
2375909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
23857589Seric
23957589Seric /* count the number of fuzzy matches in LHS */
24057589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++)
24157589Seric {
24258148Seric char *botch;
24358148Seric
24458148Seric botch = NULL;
24558050Seric switch (**ap & 0377)
24657589Seric {
24757589Seric case MATCHZANY:
24857589Seric case MATCHANY:
24957589Seric case MATCHONE:
25057589Seric case MATCHCLASS:
25157589Seric case MATCHNCLASS:
25257589Seric nfuzzy++;
25358148Seric break;
25458148Seric
25558148Seric case MATCHREPL:
25658148Seric botch = "$0-$9";
25758148Seric break;
25858148Seric
25958148Seric case CANONNET:
26058148Seric botch = "$#";
26158148Seric break;
26258148Seric
26358148Seric case CANONUSER:
26458148Seric botch = "$:";
26558148Seric break;
26658148Seric
26758148Seric case CALLSUBR:
26858148Seric botch = "$>";
26958148Seric break;
27058148Seric
27158148Seric case CONDIF:
27258148Seric botch = "$?";
27358148Seric break;
27458148Seric
27558148Seric case CONDELSE:
27658148Seric botch = "$|";
27758148Seric break;
27858148Seric
27958148Seric case CONDFI:
28058148Seric botch = "$.";
28158148Seric break;
28258148Seric
28358148Seric case HOSTBEGIN:
28458148Seric botch = "$[";
28558148Seric break;
28658148Seric
28758148Seric case HOSTEND:
28858148Seric botch = "$]";
28958148Seric break;
29058148Seric
29158148Seric case LOOKUPBEGIN:
29258148Seric botch = "$(";
29358148Seric break;
29458148Seric
29558148Seric case LOOKUPEND:
29658148Seric botch = "$)";
29758148Seric break;
29857589Seric }
29958148Seric if (botch != NULL)
30058148Seric syserr("Inappropriate use of %s on LHS",
30158148Seric botch);
30257589Seric }
30357589Seric }
30456678Seric else
30568481Seric {
30656678Seric syserr("R line: null LHS");
30768481Seric rwp->r_lhs = null_list;
30868481Seric }
3095909Seric
3105909Seric /* expand and save the RHS */
3115909Seric while (*++p == '\t')
3125909Seric continue;
3137231Seric q = p;
3147231Seric while (*p != '\0' && *p != '\t')
3157231Seric p++;
3167231Seric *p = '\0';
31768529Seric expand(q, exbuf, sizeof exbuf, e);
31865066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
31968711Seric sizeof pvpbuf, NULL, NULL);
3205909Seric if (rwp->r_rhs != NULL)
32157589Seric {
32257589Seric register char **ap;
32357589Seric
3245909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
32557589Seric
32657589Seric /* check no out-of-bounds replacements */
32757589Seric nfuzzy += '0';
32857589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++)
32957589Seric {
33058148Seric char *botch;
33158148Seric
33258148Seric botch = NULL;
33358148Seric switch (**ap & 0377)
33457589Seric {
33558148Seric case MATCHREPL:
33658148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
33758148Seric {
33858148Seric syserr("replacement $%c out of bounds",
33958148Seric (*ap)[1]);
34058148Seric }
34158148Seric break;
34258148Seric
34358148Seric case MATCHZANY:
34458148Seric botch = "$*";
34558148Seric break;
34658148Seric
34758148Seric case MATCHANY:
34858148Seric botch = "$+";
34958148Seric break;
35058148Seric
35158148Seric case MATCHONE:
35258148Seric botch = "$-";
35358148Seric break;
35458148Seric
35558148Seric case MATCHCLASS:
35658148Seric botch = "$=";
35758148Seric break;
35858148Seric
35958148Seric case MATCHNCLASS:
36058148Seric botch = "$~";
36158148Seric break;
36257589Seric }
36358148Seric if (botch != NULL)
36458148Seric syserr("Inappropriate use of %s on RHS",
36558148Seric botch);
36657589Seric }
36757589Seric }
36856678Seric else
36968481Seric {
37056678Seric syserr("R line: null RHS");
37168481Seric rwp->r_rhs = null_list;
37268481Seric }
3733308Seric break;
3743308Seric
3754072Seric case 'S': /* select rewriting set */
37669783Seric ruleset = strtorwset(&bp[1], NULL, ST_ENTER);
37769789Seric rwp = RewriteRules[ruleset];
37869789Seric if (rwp != NULL)
37969789Seric {
38069789Seric while (rwp->r_next != NULL)
38169789Seric rwp = rwp->r_next;
38269789Seric fprintf(stderr, "WARNING: Ruleset %s redefined\n",
38369789Seric &bp[1]);
38469789Seric }
3854072Seric break;
3864072Seric
3873308Seric case 'D': /* macro definition */
38868481Seric mid = macid(&bp[1], &ep);
38968481Seric p = munchstring(ep, NULL);
39068481Seric define(mid, newstr(p), e);
3913308Seric break;
3923308Seric
3933387Seric case 'H': /* required header line */
39468717Seric (void) chompheader(&bp[1], TRUE, NULL, e);
3953387Seric break;
3963387Seric
3974061Seric case 'C': /* word class */
39868481Seric case 'T': /* trusted user (set class `t') */
39968481Seric if (bp[0] == 'C')
4004061Seric {
40168481Seric mid = macid(&bp[1], &ep);
40268529Seric expand(ep, exbuf, sizeof exbuf, e);
40368481Seric p = exbuf;
40468481Seric }
40568481Seric else
40668481Seric {
40768481Seric mid = 't';
40868481Seric p = &bp[1];
40968481Seric }
41068481Seric while (*p != '\0')
41168481Seric {
4124061Seric register char *wd;
4134061Seric char delim;
4144061Seric
41558050Seric while (*p != '\0' && isascii(*p) && isspace(*p))
4164061Seric p++;
4174061Seric wd = p;
41858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4194061Seric p++;
4204061Seric delim = *p;
4214061Seric *p = '\0';
4224061Seric if (wd[0] != '\0')
42368481Seric setclass(mid, wd);
4244061Seric *p = delim;
4254061Seric }
4264061Seric break;
4274061Seric
42859272Seric case 'F': /* word class from file */
42968481Seric mid = macid(&bp[1], &ep);
43068481Seric for (p = ep; isascii(*p) && isspace(*p); )
43164133Seric p++;
43264133Seric if (p[0] == '-' && p[1] == 'o')
43364133Seric {
43464133Seric optional = TRUE;
43564133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
43664133Seric p++;
43764133Seric while (isascii(*p) && isspace(*p))
43868481Seric p++;
43964133Seric }
44064133Seric else
44164133Seric optional = FALSE;
44264133Seric file = p;
44364133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
44464133Seric p++;
44559272Seric if (*p == '\0')
44659272Seric p = "%s";
44759272Seric else
44859272Seric {
44959272Seric *p = '\0';
45059272Seric while (isascii(*++p) && isspace(*p))
45159272Seric continue;
45259272Seric }
45364133Seric fileclass(bp[1], file, p, safe, optional);
45459272Seric break;
45559272Seric
45659156Seric #ifdef XLA
45759156Seric case 'L': /* extended load average description */
45859156Seric xla_init(&bp[1]);
45959156Seric break;
46059156Seric #endif
46159156Seric
4624096Seric case 'M': /* define mailer */
46357135Seric makemailer(&bp[1]);
4644096Seric break;
4654096Seric
4668252Seric case 'O': /* set option */
46758734Seric setoption(bp[1], &bp[2], safe, FALSE, e);
4688252Seric break;
4698252Seric
4708252Seric case 'P': /* set precedence */
4718252Seric if (NumPriorities >= MAXPRIORITIES)
4728252Seric {
4738547Seric toomany('P', MAXPRIORITIES);
4748252Seric break;
4758252Seric }
47669956Seric for (p = &bp[1]; *p != '\0' && *p != '='; p++)
4778252Seric continue;
4788252Seric if (*p == '\0')
4798252Seric goto badline;
4808252Seric *p = '\0';
48157135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]);
4828252Seric Priorities[NumPriorities].pri_val = atoi(++p);
4838252Seric NumPriorities++;
4848252Seric break;
4858252Seric
48652645Seric case 'V': /* configuration syntax version */
48764440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
48864440Seric continue;
48964440Seric if (!isascii(*p) || !isdigit(*p))
49064440Seric {
49164440Seric syserr("invalid argument to V line: \"%.20s\"",
49264440Seric &bp[1]);
49364440Seric break;
49464440Seric }
49564718Seric ConfigLevel = strtol(p, &ep, 10);
49668805Seric
49768805Seric /*
49868805Seric ** Do heuristic tweaking for back compatibility.
49968805Seric */
50068805Seric
50164279Seric if (ConfigLevel >= 5)
50264279Seric {
50364279Seric /* level 5 configs have short name in $w */
50464279Seric p = macvalue('w', e);
50564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL)
50664279Seric *p = '\0';
507*69976Seric if (tTd(35, 9))
508*69976Seric printf("redefine('w' as %s)\n",
509*69976Seric macvalue('w', e));
51064279Seric }
51168805Seric if (ConfigLevel >= 6)
51268805Seric {
51368805Seric ColonOkInAddr = FALSE;
51468805Seric }
51568805Seric
51668805Seric /*
51768805Seric ** Look for vendor code.
51868805Seric */
51968805Seric
52064718Seric if (*ep++ == '/')
52164718Seric {
52264718Seric /* extract vendor code */
52364718Seric for (p = ep; isascii(*p) && isalpha(*p); )
52464718Seric p++;
52564718Seric *p = '\0';
52664718Seric
52764718Seric if (!setvendor(ep))
52864718Seric syserr("invalid V line vendor code: \"%s\"",
52964718Seric ep);
53064718Seric }
53152645Seric break;
53252645Seric
53353654Seric case 'K':
53469774Seric (void) makemapentry(&bp[1]);
53553654Seric break;
53653654Seric
53769476Seric case 'E':
53869476Seric p = strchr(bp, '=');
53969476Seric if (p != NULL)
54069476Seric *p++ = '\0';
54169476Seric setuserenv(&bp[1], p);
54269476Seric break;
54369476Seric
5443308Seric default:
5454061Seric badline:
54657135Seric syserr("unknown control line \"%s\"", bp);
5473308Seric }
54857135Seric if (bp != buf)
54957135Seric free(bp);
5503308Seric }
55152637Seric if (ferror(cf))
55252637Seric {
55352647Seric syserr("I/O read error", cfname);
55452637Seric exit(EX_OSFILE);
55552637Seric }
55652637Seric fclose(cf);
5579381Seric FileName = NULL;
55856836Seric
55968481Seric /* initialize host maps from local service tables */
56068481Seric inithostmaps();
56168481Seric
56268481Seric /* determine if we need to do special name-server frotz */
56367905Seric {
56468481Seric int nmaps;
56568481Seric char *maptype[MAXMAPSTACK];
56668481Seric short mapreturn[MAXMAPACTIONS];
56768481Seric
56868481Seric nmaps = switch_map_find("hosts", maptype, mapreturn);
56968481Seric UseNameServer = FALSE;
57068481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK)
57168481Seric {
57268481Seric register int mapno;
57368481Seric
57468481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
57568481Seric {
57668481Seric if (strcmp(maptype[mapno], "dns") == 0)
57768481Seric UseNameServer = TRUE;
57868481Seric }
57968481Seric }
58068481Seric
58168481Seric #ifdef HESIOD
58268481Seric nmaps = switch_map_find("passwd", maptype, mapreturn);
58368481Seric UseHesiod = FALSE;
58468481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK)
58568481Seric {
58668481Seric register int mapno;
58768481Seric
58868481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
58968481Seric {
59068481Seric if (strcmp(maptype[mapno], "hesiod") == 0)
59168481Seric UseHesiod = TRUE;
59268481Seric }
59368481Seric }
59468204Seric #endif
59567905Seric }
5964096Seric }
5974096Seric /*
5988547Seric ** TOOMANY -- signal too many of some option
5998547Seric **
6008547Seric ** Parameters:
6018547Seric ** id -- the id of the error line
6028547Seric ** maxcnt -- the maximum possible values
6038547Seric **
6048547Seric ** Returns:
6058547Seric ** none.
6068547Seric **
6078547Seric ** Side Effects:
6088547Seric ** gives a syserr.
6098547Seric */
6108547Seric
61169748Seric void
toomany(id,maxcnt)6128547Seric toomany(id, maxcnt)
61369748Seric int id;
6148547Seric int maxcnt;
6158547Seric {
6169381Seric syserr("too many %c lines, %d max", id, maxcnt);
6178547Seric }
6188547Seric /*
6194432Seric ** FILECLASS -- read members of a class from a file
6204432Seric **
6214432Seric ** Parameters:
6224432Seric ** class -- class to define.
6234432Seric ** filename -- name of file to read.
6244432Seric ** fmt -- scanf string to use for match.
62564133Seric ** safe -- if set, this is a safe read.
62664133Seric ** optional -- if set, it is not an error for the file to
62764133Seric ** not exist.
6284432Seric **
6294432Seric ** Returns:
6304432Seric ** none
6314432Seric **
6324432Seric ** Side Effects:
6334432Seric **
6344432Seric ** puts all lines in filename that match a scanf into
6354432Seric ** the named class.
6364432Seric */
6374432Seric
63869748Seric void
fileclass(class,filename,fmt,safe,optional)63964133Seric fileclass(class, filename, fmt, safe, optional)
6404432Seric int class;
6414432Seric char *filename;
6424432Seric char *fmt;
64354973Seric bool safe;
64464133Seric bool optional;
6454432Seric {
64625808Seric FILE *f;
64768513Seric int sff;
64869453Seric int pid;
64969453Seric register char *p;
6504432Seric char buf[MAXLINE];
6514432Seric
65266101Seric if (tTd(37, 2))
65366101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt);
65466101Seric
65566031Seric if (filename[0] == '|')
65666031Seric {
65769453Seric auto int fd;
65869453Seric int i;
65969453Seric char *argv[MAXPV + 1];
66069453Seric
66169453Seric i = 0;
66269453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
66369453Seric {
66469453Seric if (i >= MAXPV)
66569453Seric break;
66669453Seric argv[i++] = p;
66769453Seric }
66869453Seric argv[i] = NULL;
66969453Seric pid = prog_open(argv, &fd, CurEnv);
67069453Seric if (pid < 0)
67169453Seric f = NULL;
67269453Seric else
67369453Seric f = fdopen(fd, "r");
67466031Seric }
67569453Seric else
67669453Seric {
67769453Seric pid = -1;
67869453Seric sff = SFF_REGONLY;
67969453Seric if (safe)
68069453Seric sff |= SFF_OPENASROOT;
68169453Seric f = safefopen(filename, O_RDONLY, 0, sff);
68269453Seric }
68368602Seric if (f == NULL)
68454973Seric {
68568602Seric if (!optional)
68668602Seric syserr("fileclass: cannot open %s", filename);
6874432Seric return;
6884432Seric }
6894432Seric
6904432Seric while (fgets(buf, sizeof buf, f) != NULL)
6914432Seric {
69225808Seric register char *p;
69369935Seric # if SCANF
6944432Seric char wordbuf[MAXNAME+1];
6954432Seric
6964432Seric if (sscanf(buf, fmt, wordbuf) != 1)
6974432Seric continue;
69825808Seric p = wordbuf;
69956795Seric # else /* SCANF */
70025808Seric p = buf;
70156795Seric # endif /* SCANF */
70225808Seric
70325808Seric /*
70425808Seric ** Break up the match into words.
70525808Seric */
70625808Seric
70725808Seric while (*p != '\0')
70825808Seric {
70925808Seric register char *q;
71025808Seric
71125808Seric /* strip leading spaces */
71258050Seric while (isascii(*p) && isspace(*p))
71325808Seric p++;
71425808Seric if (*p == '\0')
71525808Seric break;
71625808Seric
71725808Seric /* find the end of the word */
71825808Seric q = p;
71958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
72025808Seric p++;
72125808Seric if (*p != '\0')
72225808Seric *p++ = '\0';
72325808Seric
72425808Seric /* enter the word in the symbol table */
72566101Seric setclass(class, q);
72625808Seric }
7274432Seric }
7284432Seric
72954973Seric (void) fclose(f);
73069453Seric if (pid > 0)
73169453Seric (void) waitfor(pid);
7324432Seric }
7334432Seric /*
7344096Seric ** MAKEMAILER -- define a new mailer.
7354096Seric **
7364096Seric ** Parameters:
73710327Seric ** line -- description of mailer. This is in labeled
73810327Seric ** fields. The fields are:
73968481Seric ** A -- the argv for this mailer
74068481Seric ** C -- the character set for MIME conversions
74168481Seric ** D -- the directory to run in
74268481Seric ** E -- the eol string
74368481Seric ** F -- the flags associated with the mailer
74468481Seric ** L -- the maximum line length
74568481Seric ** M -- the maximum message size
74668816Seric ** N -- the niceness at which to run
74768479Seric ** P -- the path to the mailer
74868481Seric ** R -- the recipient rewriting set
74968479Seric ** S -- the sender rewriting set
75068481Seric ** T -- the mailer type (for DSNs)
75168481Seric ** U -- the uid to run as
75210327Seric ** The first word is the canonical name of the mailer.
7534096Seric **
7544096Seric ** Returns:
7554096Seric ** none.
7564096Seric **
7574096Seric ** Side Effects:
7584096Seric ** enters the mailer into the mailer table.
7594096Seric */
7603308Seric
76169748Seric void
makemailer(line)76221066Seric makemailer(line)
7634096Seric char *line;
7644096Seric {
7654096Seric register char *p;
7668067Seric register struct mailer *m;
7678067Seric register STAB *s;
7688067Seric int i;
76910327Seric char fcode;
77058020Seric auto char *endp;
7714096Seric extern int NextMailer;
77210327Seric extern char **makeargv();
77310327Seric extern char *munchstring();
7744096Seric
77510327Seric /* allocate a mailer and set up defaults */
77610327Seric m = (struct mailer *) xalloc(sizeof *m);
77710327Seric bzero((char *) m, sizeof *m);
77810327Seric m->m_eol = "\n";
77968481Seric m->m_uid = m->m_gid = 0;
78010327Seric
78110327Seric /* collect the mailer name */
78258050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
78310327Seric continue;
78410327Seric if (*p != '\0')
78510327Seric *p++ = '\0';
78610327Seric m->m_name = newstr(line);
78710327Seric
78810327Seric /* now scan through and assign info from the fields */
78910327Seric while (*p != '\0')
79010327Seric {
79158333Seric auto char *delimptr;
79258333Seric
79358050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
79410327Seric p++;
79510327Seric
79610327Seric /* p now points to field code */
79710327Seric fcode = *p;
79810327Seric while (*p != '\0' && *p != '=' && *p != ',')
79910327Seric p++;
80010327Seric if (*p++ != '=')
80110327Seric {
80252637Seric syserr("mailer %s: `=' expected", m->m_name);
80310327Seric return;
80410327Seric }
80558050Seric while (isascii(*p) && isspace(*p))
80610327Seric p++;
80710327Seric
80810327Seric /* p now points to the field body */
80958333Seric p = munchstring(p, &delimptr);
81010327Seric
81110327Seric /* install the field into the mailer struct */
81210327Seric switch (fcode)
81310327Seric {
81410327Seric case 'P': /* pathname */
81510327Seric m->m_mailer = newstr(p);
81610327Seric break;
81710327Seric
81810327Seric case 'F': /* flags */
81910687Seric for (; *p != '\0'; p++)
82058050Seric if (!(isascii(*p) && isspace(*p)))
82152637Seric setbitn(*p, m->m_flags);
82210327Seric break;
82310327Seric
82410327Seric case 'S': /* sender rewriting ruleset */
82510327Seric case 'R': /* recipient rewriting ruleset */
82669783Seric i = strtorwset(p, &endp, ST_ENTER);
82769783Seric if (i < 0)
82810327Seric return;
82910327Seric if (fcode == 'S')
83058020Seric m->m_sh_rwset = m->m_se_rwset = i;
83110327Seric else
83258020Seric m->m_rh_rwset = m->m_re_rwset = i;
83358020Seric
83458020Seric p = endp;
83559985Seric if (*p++ == '/')
83658020Seric {
83769971Seric i = strtorwset(p, NULL, ST_ENTER);
83869783Seric if (i < 0)
83958020Seric return;
84058020Seric if (fcode == 'S')
84158020Seric m->m_sh_rwset = i;
84258020Seric else
84358020Seric m->m_rh_rwset = i;
84458020Seric }
84510327Seric break;
84610327Seric
84710327Seric case 'E': /* end of line string */
84810327Seric m->m_eol = newstr(p);
84910327Seric break;
85010327Seric
85110327Seric case 'A': /* argument vector */
85210327Seric m->m_argv = makeargv(p);
85310327Seric break;
85410701Seric
85510701Seric case 'M': /* maximum message size */
85610701Seric m->m_maxsize = atol(p);
85710701Seric break;
85852106Seric
85952106Seric case 'L': /* maximum line length */
86052106Seric m->m_linelimit = atoi(p);
86152106Seric break;
86258935Seric
86368816Seric case 'N': /* run niceness */
86468816Seric m->m_nice = atoi(p);
86568816Seric break;
86668816Seric
86758935Seric case 'D': /* working directory */
86858935Seric m->m_execdir = newstr(p);
86958935Seric break;
87068481Seric
87168481Seric case 'C': /* default charset */
87268481Seric m->m_defcharset = newstr(p);
87368481Seric break;
87468481Seric
87569720Seric case 'T': /* MTA-Name/Address/Diagnostic types */
87669858Seric /* extract MTA name type; default to "dns" */
87768481Seric m->m_mtatype = newstr(p);
87868481Seric p = strchr(m->m_mtatype, '/');
87968481Seric if (p != NULL)
88068481Seric {
88168481Seric *p++ = '\0';
88268481Seric if (*p == '\0')
88368481Seric p = NULL;
88468481Seric }
88569858Seric if (*m->m_mtatype == '\0')
88669858Seric m->m_mtatype = "dns";
88769858Seric
88869858Seric /* extract address type; default to "rfc822" */
88969858Seric m->m_addrtype = p;
89069858Seric if (p != NULL)
89168481Seric p = strchr(p, '/');
89268481Seric if (p != NULL)
89368481Seric {
89468481Seric *p++ = '\0';
89568481Seric if (*p == '\0')
89668481Seric p = NULL;
89768481Seric }
89869858Seric if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
89969858Seric m->m_addrtype = "rfc822";
90069858Seric
90169858Seric /* extract diagnostic type; default to "smtp" */
90269858Seric m->m_diagtype = p;
90369858Seric if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
90469858Seric m->m_diagtype = "smtp";
90568481Seric break;
90668481Seric
90768481Seric case 'U': /* user id */
90868481Seric if (isascii(*p) && !isdigit(*p))
90968481Seric {
91068481Seric char *q = p;
91168481Seric struct passwd *pw;
91268481Seric
91368481Seric while (isascii(*p) && isalnum(*p))
91468481Seric p++;
91568481Seric while (isascii(*p) && isspace(*p))
91668481Seric *p++ = '\0';
91768481Seric if (*p != '\0')
91868481Seric *p++ = '\0';
91968693Seric pw = sm_getpwnam(q);
92068481Seric if (pw == NULL)
92168481Seric syserr("readcf: mailer U= flag: unknown user %s", q);
92268481Seric else
92368481Seric {
92468481Seric m->m_uid = pw->pw_uid;
92568481Seric m->m_gid = pw->pw_gid;
92668481Seric }
92768481Seric }
92868481Seric else
92968481Seric {
93068481Seric auto char *q;
93168481Seric
93268481Seric m->m_uid = strtol(p, &q, 0);
93368481Seric p = q;
93468481Seric }
93568481Seric while (isascii(*p) && isspace(*p))
93668481Seric p++;
93768481Seric if (*p == '\0')
93868481Seric break;
93968481Seric if (isascii(*p) && !isdigit(*p))
94068481Seric {
94168481Seric char *q = p;
94268481Seric struct group *gr;
94368481Seric
94468481Seric while (isascii(*p) && isalnum(*p))
94568481Seric p++;
94668481Seric *p++ = '\0';
94768481Seric gr = getgrnam(q);
94868481Seric if (gr == NULL)
94968481Seric syserr("readcf: mailer U= flag: unknown group %s", q);
95068481Seric else
95168481Seric m->m_gid = gr->gr_gid;
95268481Seric }
95368481Seric else
95468481Seric {
95568481Seric m->m_gid = strtol(p, NULL, 0);
95668481Seric }
95768481Seric break;
95810327Seric }
95910327Seric
96058333Seric p = delimptr;
96110327Seric }
96210327Seric
96358321Seric /* do some rationality checking */
96458321Seric if (m->m_argv == NULL)
96558321Seric {
96658321Seric syserr("M%s: A= argument required", m->m_name);
96758321Seric return;
96858321Seric }
96958321Seric if (m->m_mailer == NULL)
97058321Seric {
97158321Seric syserr("M%s: P= argument required", m->m_name);
97258321Seric return;
97358321Seric }
97458321Seric
9754096Seric if (NextMailer >= MAXMAILERS)
9764096Seric {
9779381Seric syserr("too many mailers defined (%d max)", MAXMAILERS);
9784096Seric return;
9794096Seric }
98057402Seric
98168481Seric /* do some heuristic cleanup for back compatibility */
98268481Seric if (bitnset(M_LIMITS, m->m_flags))
98368481Seric {
98468481Seric if (m->m_linelimit == 0)
98568481Seric m->m_linelimit = SMTPLINELIM;
98668481Seric if (ConfigLevel < 2)
98768481Seric setbitn(M_7BITS, m->m_flags);
98868481Seric }
98968481Seric
99068481Seric if (ConfigLevel < 6 &&
99168481Seric (strcmp(m->m_mailer, "[IPC]") == 0 ||
99268481Seric strcmp(m->m_mailer, "[TCP]") == 0))
99368481Seric {
99468481Seric if (m->m_mtatype == NULL)
99568481Seric m->m_mtatype = "dns";
99668481Seric if (m->m_addrtype == NULL)
99768481Seric m->m_addrtype = "rfc822";
99868481Seric if (m->m_diagtype == NULL)
99968481Seric m->m_diagtype = "smtp";
100068481Seric }
100168481Seric
100268481Seric /* enter the mailer into the symbol table */
100310327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER);
100457402Seric if (s->s_mailer != NULL)
100557402Seric {
100657402Seric i = s->s_mailer->m_mno;
100757402Seric free(s->s_mailer);
100857402Seric }
100957402Seric else
101057402Seric {
101157402Seric i = NextMailer++;
101257402Seric }
101357402Seric Mailer[i] = s->s_mailer = m;
101457454Seric m->m_mno = i;
101510327Seric }
101610327Seric /*
101710327Seric ** MUNCHSTRING -- translate a string into internal form.
101810327Seric **
101910327Seric ** Parameters:
102010327Seric ** p -- the string to munch.
102158333Seric ** delimptr -- if non-NULL, set to the pointer of the
102258333Seric ** field delimiter character.
102310327Seric **
102410327Seric ** Returns:
102510327Seric ** the munched string.
102610327Seric */
10274096Seric
102810327Seric char *
munchstring(p,delimptr)102958333Seric munchstring(p, delimptr)
103010327Seric register char *p;
103158333Seric char **delimptr;
103210327Seric {
103310327Seric register char *q;
103410327Seric bool backslash = FALSE;
103510327Seric bool quotemode = FALSE;
103610327Seric static char buf[MAXLINE];
10374096Seric
103810327Seric for (q = buf; *p != '\0'; p++)
10394096Seric {
104010327Seric if (backslash)
104110327Seric {
104210327Seric /* everything is roughly literal */
104310357Seric backslash = FALSE;
104410327Seric switch (*p)
104510327Seric {
104610327Seric case 'r': /* carriage return */
104710327Seric *q++ = '\r';
104810327Seric continue;
104910327Seric
105010327Seric case 'n': /* newline */
105110327Seric *q++ = '\n';
105210327Seric continue;
105310327Seric
105410327Seric case 'f': /* form feed */
105510327Seric *q++ = '\f';
105610327Seric continue;
105710327Seric
105810327Seric case 'b': /* backspace */
105910327Seric *q++ = '\b';
106010327Seric continue;
106110327Seric }
106210327Seric *q++ = *p;
106310327Seric }
106410327Seric else
106510327Seric {
106610327Seric if (*p == '\\')
106710327Seric backslash = TRUE;
106810327Seric else if (*p == '"')
106910327Seric quotemode = !quotemode;
107010327Seric else if (quotemode || *p != ',')
107110327Seric *q++ = *p;
107210327Seric else
107310327Seric break;
107410327Seric }
10754096Seric }
10764096Seric
107758333Seric if (delimptr != NULL)
107858333Seric *delimptr = p;
107910327Seric *q++ = '\0';
108010327Seric return (buf);
108110327Seric }
108210327Seric /*
108310327Seric ** MAKEARGV -- break up a string into words
108410327Seric **
108510327Seric ** Parameters:
108610327Seric ** p -- the string to break up.
108710327Seric **
108810327Seric ** Returns:
108910327Seric ** a char **argv (dynamically allocated)
109010327Seric **
109110327Seric ** Side Effects:
109210327Seric ** munges p.
109310327Seric */
10944096Seric
109510327Seric char **
makeargv(p)109610327Seric makeargv(p)
109710327Seric register char *p;
109810327Seric {
109910327Seric char *q;
110010327Seric int i;
110110327Seric char **avp;
110210327Seric char *argv[MAXPV + 1];
110310327Seric
110410327Seric /* take apart the words */
110510327Seric i = 0;
110610327Seric while (*p != '\0' && i < MAXPV)
11074096Seric {
110810327Seric q = p;
110958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
111010327Seric p++;
111158050Seric while (isascii(*p) && isspace(*p))
111210327Seric *p++ = '\0';
111310327Seric argv[i++] = newstr(q);
11144096Seric }
111510327Seric argv[i++] = NULL;
11164096Seric
111710327Seric /* now make a copy of the argv */
111810327Seric avp = (char **) xalloc(sizeof *avp * i);
111916893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i);
112010327Seric
112110327Seric return (avp);
11223308Seric }
11233308Seric /*
11243308Seric ** PRINTRULES -- print rewrite rules (for debugging)
11253308Seric **
11263308Seric ** Parameters:
11273308Seric ** none.
11283308Seric **
11293308Seric ** Returns:
11303308Seric ** none.
11313308Seric **
11323308Seric ** Side Effects:
11333308Seric ** prints rewrite rules.
11343308Seric */
11353308Seric
113669748Seric void
printrules()11373308Seric printrules()
11383308Seric {
11393308Seric register struct rewrite *rwp;
11404072Seric register int ruleset;
11413308Seric
11424072Seric for (ruleset = 0; ruleset < 10; ruleset++)
11433308Seric {
11444072Seric if (RewriteRules[ruleset] == NULL)
11454072Seric continue;
11468067Seric printf("\n----Rule Set %d:", ruleset);
11473308Seric
11484072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
11493308Seric {
11508067Seric printf("\nLHS:");
11518067Seric printav(rwp->r_lhs);
11528067Seric printf("RHS:");
11538067Seric printav(rwp->r_rhs);
11543308Seric }
11553308Seric }
11563308Seric }
115768481Seric /*
115868481Seric ** PRINTMAILER -- print mailer structure (for debugging)
115968481Seric **
116068481Seric ** Parameters:
116168481Seric ** m -- the mailer to print
116268481Seric **
116368481Seric ** Returns:
116468481Seric ** none.
116568481Seric */
11664319Seric
116769748Seric void
printmailer(m)116868481Seric printmailer(m)
116968481Seric register MAILER *m;
117068481Seric {
117168481Seric int j;
117268481Seric
117368481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=",
117468481Seric m->m_mno, m->m_name,
117568481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
117668481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize,
117768481Seric m->m_uid, m->m_gid);
117868481Seric for (j = '\0'; j <= '\177'; j++)
117968481Seric if (bitnset(j, m->m_flags))
118068481Seric (void) putchar(j);
118168481Seric printf(" L=%d E=", m->m_linelimit);
118268481Seric xputs(m->m_eol);
118368481Seric if (m->m_defcharset != NULL)
118468481Seric printf(" C=%s", m->m_defcharset);
118568481Seric printf(" T=%s/%s/%s",
118668481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
118768481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
118868481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
118968481Seric if (m->m_argv != NULL)
119068481Seric {
119168481Seric char **a = m->m_argv;
119268481Seric
119368481Seric printf(" A=");
119468481Seric while (*a != NULL)
119568481Seric {
119668481Seric if (a != m->m_argv)
119768481Seric printf(" ");
119868481Seric xputs(*a++);
119968481Seric }
120068481Seric }
120168481Seric printf("\n");
120268481Seric }
12034096Seric /*
12048256Seric ** SETOPTION -- set global processing option
12058256Seric **
12068256Seric ** Parameters:
12078256Seric ** opt -- option name.
12088256Seric ** val -- option value (as a text string).
120921755Seric ** safe -- set if this came from a configuration file.
121021755Seric ** Some options (if set from the command line) will
121121755Seric ** reset the user id to avoid security problems.
12128269Seric ** sticky -- if set, don't let other setoptions override
12138269Seric ** this value.
121458734Seric ** e -- the main envelope.
12158256Seric **
12168256Seric ** Returns:
12178256Seric ** none.
12188256Seric **
12198256Seric ** Side Effects:
12208256Seric ** Sets options as implied by the arguments.
12218256Seric */
12228256Seric
122310687Seric static BITMAP StickyOpt; /* set if option is stuck */
122469748Seric extern void settimeout __P((char *, char *));
12258269Seric
122657207Seric
122766334Seric #if NAMED_BIND
122857207Seric
122957207Seric struct resolverflags
123057207Seric {
123157207Seric char *rf_name; /* name of the flag */
123257207Seric long rf_bits; /* bits to set/clear */
123357207Seric } ResolverFlags[] =
123457207Seric {
123557207Seric "debug", RES_DEBUG,
123657207Seric "aaonly", RES_AAONLY,
123757207Seric "usevc", RES_USEVC,
123857207Seric "primary", RES_PRIMARY,
123957207Seric "igntc", RES_IGNTC,
124057207Seric "recurse", RES_RECURSE,
124157207Seric "defnames", RES_DEFNAMES,
124257207Seric "stayopen", RES_STAYOPEN,
124357207Seric "dnsrch", RES_DNSRCH,
124465583Seric "true", 0, /* to avoid error on old syntax */
124557207Seric NULL, 0
124657207Seric };
124757207Seric
124857207Seric #endif
124957207Seric
125068481Seric struct optioninfo
125168481Seric {
125268481Seric char *o_name; /* long name of option */
125368481Seric u_char o_code; /* short name of option */
125468481Seric bool o_safe; /* safe for random people to use */
125568481Seric } OptionTab[] =
125668481Seric {
125768481Seric "SevenBitInput", '7', TRUE,
125869480Seric #if MIME8TO7
125968481Seric "EightBitMode", '8', TRUE,
126069480Seric #endif
126168481Seric "AliasFile", 'A', FALSE,
126268481Seric "AliasWait", 'a', FALSE,
126368481Seric "BlankSub", 'B', FALSE,
126468481Seric "MinFreeBlocks", 'b', TRUE,
126568481Seric "CheckpointInterval", 'C', TRUE,
126668481Seric "HoldExpensive", 'c', FALSE,
126768481Seric "AutoRebuildAliases", 'D', FALSE,
126868481Seric "DeliveryMode", 'd', TRUE,
126968481Seric "ErrorHeader", 'E', FALSE,
127068481Seric "ErrorMode", 'e', TRUE,
127168481Seric "TempFileMode", 'F', FALSE,
127268481Seric "SaveFromLine", 'f', FALSE,
127368481Seric "MatchGECOS", 'G', FALSE,
127468481Seric "HelpFile", 'H', FALSE,
127568481Seric "MaxHopCount", 'h', FALSE,
127668569Seric "ResolverOptions", 'I', FALSE,
127768481Seric "IgnoreDots", 'i', TRUE,
127868481Seric "ForwardPath", 'J', FALSE,
127968481Seric "SendMimeErrors", 'j', TRUE,
128068481Seric "ConnectionCacheSize", 'k', FALSE,
128168481Seric "ConnectionCacheTimeout", 'K', FALSE,
128268481Seric "UseErrorsTo", 'l', FALSE,
128368481Seric "LogLevel", 'L', FALSE,
128468481Seric "MeToo", 'm', TRUE,
128568481Seric "CheckAliases", 'n', FALSE,
128668481Seric "OldStyleHeaders", 'o', TRUE,
128768481Seric "DaemonPortOptions", 'O', FALSE,
128868481Seric "PrivacyOptions", 'p', TRUE,
128968481Seric "PostmasterCopy", 'P', FALSE,
129068481Seric "QueueFactor", 'q', FALSE,
129168481Seric "QueueDirectory", 'Q', FALSE,
129268481Seric "DontPruneRoutes", 'R', FALSE,
129368481Seric "Timeout", 'r', TRUE,
129468481Seric "StatusFile", 'S', FALSE,
129568481Seric "SuperSafe", 's', TRUE,
129668481Seric "QueueTimeout", 'T', FALSE,
129768481Seric "TimeZoneSpec", 't', FALSE,
129868481Seric "UserDatabaseSpec", 'U', FALSE,
129968481Seric "DefaultUser", 'u', FALSE,
130068481Seric "FallbackMXhost", 'V', FALSE,
130168481Seric "Verbose", 'v', TRUE,
130268481Seric "TryNullMXList", 'w', TRUE,
130368481Seric "QueueLA", 'x', FALSE,
130468481Seric "RefuseLA", 'X', FALSE,
130568481Seric "RecipientFactor", 'y', FALSE,
130668569Seric "ForkEachJob", 'Y', FALSE,
130768481Seric "ClassFactor", 'z', FALSE,
130868569Seric "RetryFactor", 'Z', FALSE,
130968481Seric #define O_QUEUESORTORD 0x81
131068481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE,
131169401Seric #define O_HOSTSFILE 0x82
131269401Seric "HostsFile", O_HOSTSFILE, FALSE,
131368481Seric #define O_MQA 0x83
131468481Seric "MinQueueAge", O_MQA, TRUE,
131568481Seric #define O_MHSA 0x84
131668481Seric /*
131768481Seric "MaxHostStatAge", O_MHSA, TRUE,
131868481Seric */
131968481Seric #define O_DEFCHARSET 0x85
132068481Seric "DefaultCharSet", O_DEFCHARSET, TRUE,
132168481Seric #define O_SSFILE 0x86
132268481Seric "ServiceSwitchFile", O_SSFILE, FALSE,
132368481Seric #define O_DIALDELAY 0x87
132468481Seric "DialDelay", O_DIALDELAY, TRUE,
132568481Seric #define O_NORCPTACTION 0x88
132668481Seric "NoRecipientAction", O_NORCPTACTION, TRUE,
132768490Seric #define O_SAFEFILEENV 0x89
132868490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE,
132968569Seric #define O_MAXMSGSIZE 0x8a
133068569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE,
133168756Seric #define O_COLONOKINADDR 0x8b
133268756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE,
133369724Seric #define O_MAXQUEUERUN 0x8c
133469724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE,
133569838Seric #define O_MAXCHILDREN 0x8d
133669838Seric /*
133769838Seric "MaxDaemonChildren", O_MAXCHILDREN, FALSE,
133869838Seric */
133969852Seric #define O_KEEPCNAMES 0x8e
134069852Seric "DontExpandCnames", O_KEEPCNAMES, FALSE,
134168481Seric
134268481Seric NULL, '\0', FALSE,
134368481Seric };
134468481Seric
134568481Seric
134668481Seric
134769748Seric void
setoption(opt,val,safe,sticky,e)134858734Seric setoption(opt, val, safe, sticky, e)
134969748Seric int opt;
13508256Seric char *val;
135121755Seric bool safe;
13528269Seric bool sticky;
135358734Seric register ENVELOPE *e;
13548256Seric {
135557207Seric register char *p;
135668481Seric register struct optioninfo *o;
135768481Seric char *subopt;
13588265Seric extern bool atobool();
135912633Seric extern time_t convtime();
136014879Seric extern int QueueLA;
136114879Seric extern int RefuseLA;
136264718Seric extern bool Warn_Q_option;
13638256Seric
136468481Seric errno = 0;
136568481Seric if (opt == ' ')
136668481Seric {
136768481Seric /* full word options */
136868481Seric struct optioninfo *sel;
136968481Seric
137068481Seric p = strchr(val, '=');
137168481Seric if (p == NULL)
137268481Seric p = &val[strlen(val)];
137368481Seric while (*--p == ' ')
137468481Seric continue;
137568481Seric while (*++p == ' ')
137668481Seric *p = '\0';
137768481Seric if (p == val)
137868481Seric {
137968481Seric syserr("readcf: null option name");
138068481Seric return;
138168481Seric }
138268481Seric if (*p == '=')
138368481Seric *p++ = '\0';
138468481Seric while (*p == ' ')
138568481Seric p++;
138668481Seric subopt = strchr(val, '.');
138768481Seric if (subopt != NULL)
138868481Seric *subopt++ = '\0';
138968481Seric sel = NULL;
139068481Seric for (o = OptionTab; o->o_name != NULL; o++)
139168481Seric {
139268481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0)
139368481Seric continue;
139468481Seric if (strlen(o->o_name) == strlen(val))
139568481Seric {
139668481Seric /* completely specified -- this must be it */
139768481Seric sel = NULL;
139868481Seric break;
139968481Seric }
140068481Seric if (sel != NULL)
140168481Seric break;
140268481Seric sel = o;
140368481Seric }
140468481Seric if (sel != NULL && o->o_name == NULL)
140568481Seric o = sel;
140668481Seric else if (o->o_name == NULL)
140768481Seric {
140868481Seric syserr("readcf: unknown option name %s", val);
140968481Seric return;
141068481Seric }
141168481Seric else if (sel != NULL)
141268481Seric {
141368481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)",
141468481Seric val, sel->o_name, o->o_name);
141568481Seric return;
141668481Seric }
141768481Seric if (strlen(val) != strlen(o->o_name))
141868481Seric {
141968481Seric bool oldVerbose = Verbose;
142068481Seric
142168481Seric Verbose = TRUE;
142268481Seric message("Option %s used as abbreviation for %s",
142368481Seric val, o->o_name);
142468481Seric Verbose = oldVerbose;
142568481Seric }
142668481Seric opt = o->o_code;
142768481Seric val = p;
142868481Seric }
142968481Seric else
143068481Seric {
143168481Seric for (o = OptionTab; o->o_name != NULL; o++)
143268481Seric {
143368481Seric if (o->o_code == opt)
143468481Seric break;
143568481Seric }
143668481Seric subopt = NULL;
143768481Seric }
143868481Seric
14398256Seric if (tTd(37, 1))
144068481Seric {
144168481Seric printf(isascii(opt) && isprint(opt) ?
144269917Seric "setoption %s (%c).%s=" :
144369917Seric "setoption %s (0x%x).%s=",
144468481Seric o->o_name == NULL ? "<unknown>" : o->o_name,
144568481Seric opt,
144669917Seric subopt == NULL ? "" : subopt);
144769917Seric xputs(val);
144868481Seric }
14498256Seric
14508256Seric /*
14518269Seric ** See if this option is preset for us.
14528256Seric */
14538256Seric
145459731Seric if (!sticky && bitnset(opt, StickyOpt))
14558269Seric {
14569341Seric if (tTd(37, 1))
14579341Seric printf(" (ignored)\n");
14588269Seric return;
14598269Seric }
14608269Seric
146121755Seric /*
146221755Seric ** Check to see if this option can be specified by this user.
146321755Seric */
146421755Seric
146563787Seric if (!safe && RealUid == 0)
146621755Seric safe = TRUE;
146768481Seric if (!safe && !o->o_safe)
146821755Seric {
146939111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
147021755Seric {
147136582Sbostic if (tTd(37, 1))
147236582Sbostic printf(" (unsafe)");
147363787Seric if (RealUid != geteuid())
147436582Sbostic {
147551210Seric if (tTd(37, 1))
147651210Seric printf("(Resetting uid)");
147769963Seric endpwent();
147863787Seric (void) setgid(RealGid);
147963787Seric (void) setuid(RealUid);
148036582Sbostic }
148121755Seric }
148221755Seric }
148351210Seric if (tTd(37, 1))
148417985Seric printf("\n");
14858269Seric
148668481Seric switch (opt & 0xff)
14878256Seric {
148859709Seric case '7': /* force seven-bit input */
148968481Seric SevenBitInput = atobool(val);
149052106Seric break;
149152106Seric
149269480Seric #if MIME8TO7
149368481Seric case '8': /* handling of 8-bit input */
149468481Seric switch (*val)
149568481Seric {
149668481Seric case 'm': /* convert 8-bit, convert MIME */
149768481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT;
149868481Seric break;
149968481Seric
150068481Seric case 'p': /* pass 8 bit, convert MIME */
150168856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT;
150268481Seric break;
150368481Seric
150468481Seric case 's': /* strict adherence */
150568481Seric MimeMode = MM_CVTMIME;
150668481Seric break;
150768481Seric
150868856Seric #if 0
150968856Seric case 'r': /* reject 8-bit, don't convert MIME */
151068856Seric MimeMode = 0;
151168856Seric break;
151268856Seric
151368856Seric case 'j': /* "just send 8" */
151468856Seric MimeMode = MM_PASS8BIT;
151568856Seric break;
151668856Seric
151768481Seric case 'a': /* encode 8 bit if available */
151868481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
151968481Seric break;
152068481Seric
152168481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */
152268481Seric MimeMode = MM_MIME8BIT;
152368481Seric break;
152468856Seric #endif
152568481Seric
152668481Seric default:
152768481Seric syserr("Unknown 8-bit mode %c", *val);
152868481Seric exit(EX_USAGE);
152968481Seric }
153068481Seric break;
153169480Seric #endif
153268481Seric
15338256Seric case 'A': /* set default alias file */
15349381Seric if (val[0] == '\0')
153559672Seric setalias("aliases");
15369381Seric else
153759672Seric setalias(val);
15388256Seric break;
15398256Seric
154017474Seric case 'a': /* look N minutes for "@:@" in alias file */
154117474Seric if (val[0] == '\0')
154264796Seric SafeAlias = 5 * 60; /* five minutes */
154317474Seric else
154464796Seric SafeAlias = convtime(val, 'm');
154517474Seric break;
154617474Seric
154716843Seric case 'B': /* substitution for blank character */
154816843Seric SpaceSub = val[0];
154916843Seric if (SpaceSub == '\0')
155016843Seric SpaceSub = ' ';
155116843Seric break;
155216843Seric
155359283Seric case 'b': /* min blocks free on queue fs/max msg size */
155459283Seric p = strchr(val, '/');
155559283Seric if (p != NULL)
155659283Seric {
155759283Seric *p++ = '\0';
155859283Seric MaxMessageSize = atol(p);
155959283Seric }
156058082Seric MinBlocksFree = atol(val);
156158082Seric break;
156258082Seric
15639284Seric case 'c': /* don't connect to "expensive" mailers */
15649381Seric NoConnect = atobool(val);
15659284Seric break;
15669284Seric
156751305Seric case 'C': /* checkpoint every N addresses */
156851305Seric CheckpointInterval = atoi(val);
156924944Seric break;
157024944Seric
15719284Seric case 'd': /* delivery mode */
15729284Seric switch (*val)
15738269Seric {
15749284Seric case '\0':
157558734Seric e->e_sendmode = SM_DELIVER;
15768269Seric break;
15778269Seric
157810755Seric case SM_QUEUE: /* queue only */
157910755Seric #ifndef QUEUE
158010755Seric syserr("need QUEUE to set -odqueue");
158156795Seric #endif /* QUEUE */
158210755Seric /* fall through..... */
158310755Seric
15849284Seric case SM_DELIVER: /* do everything */
15859284Seric case SM_FORK: /* fork after verification */
158658734Seric e->e_sendmode = *val;
15878269Seric break;
15888269Seric
15898269Seric default:
15909284Seric syserr("Unknown delivery mode %c", *val);
15918269Seric exit(EX_USAGE);
15928269Seric }
15938269Seric break;
15948269Seric
15959146Seric case 'D': /* rebuild alias database as needed */
15969381Seric AutoRebuild = atobool(val);
15979146Seric break;
15989146Seric
159955372Seric case 'E': /* error message header/header file */
160055379Seric if (*val != '\0')
160155379Seric ErrMsgFile = newstr(val);
160255372Seric break;
160355372Seric
16048269Seric case 'e': /* set error processing mode */
16058269Seric switch (*val)
16068269Seric {
16079381Seric case EM_QUIET: /* be silent about it */
16089381Seric case EM_MAIL: /* mail back */
16099381Seric case EM_BERKNET: /* do berknet error processing */
16109381Seric case EM_WRITE: /* write back (or mail) */
16119381Seric case EM_PRINT: /* print errors normally (default) */
161258734Seric e->e_errormode = *val;
16138269Seric break;
16148269Seric }
16158269Seric break;
16168269Seric
16179049Seric case 'F': /* file mode */
161817975Seric FileMode = atooct(val) & 0777;
16199049Seric break;
16209049Seric
16218269Seric case 'f': /* save Unix-style From lines on front */
16229381Seric SaveFrom = atobool(val);
16238269Seric break;
16248269Seric
162553735Seric case 'G': /* match recipients against GECOS field */
162653735Seric MatchGecos = atobool(val);
162753735Seric break;
162853735Seric
16298256Seric case 'g': /* default gid */
163068481Seric g_opt:
163164133Seric if (isascii(*val) && isdigit(*val))
163264133Seric DefGid = atoi(val);
163364133Seric else
163464133Seric {
163564133Seric register struct group *gr;
163664133Seric
163764133Seric DefGid = -1;
163864133Seric gr = getgrnam(val);
163964133Seric if (gr == NULL)
164068481Seric syserr("readcf: option %c: unknown group %s",
164168481Seric opt, val);
164264133Seric else
164364133Seric DefGid = gr->gr_gid;
164464133Seric }
16458256Seric break;
16468256Seric
16478256Seric case 'H': /* help file */
16489381Seric if (val[0] == '\0')
16498269Seric HelpFile = "sendmail.hf";
16509381Seric else
16519381Seric HelpFile = newstr(val);
16528256Seric break;
16538256Seric
165451305Seric case 'h': /* maximum hop count */
165551305Seric MaxHopCount = atoi(val);
165651305Seric break;
165751305Seric
165835651Seric case 'I': /* use internet domain name server */
165966334Seric #if NAMED_BIND
166057207Seric for (p = val; *p != 0; )
166157207Seric {
166257207Seric bool clearmode;
166357207Seric char *q;
166457207Seric struct resolverflags *rfp;
166557207Seric
166657207Seric while (*p == ' ')
166757207Seric p++;
166857207Seric if (*p == '\0')
166957207Seric break;
167057207Seric clearmode = FALSE;
167157207Seric if (*p == '-')
167257207Seric clearmode = TRUE;
167357207Seric else if (*p != '+')
167457207Seric p--;
167557207Seric p++;
167657207Seric q = p;
167758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
167857207Seric p++;
167957207Seric if (*p != '\0')
168057207Seric *p++ = '\0';
168168759Seric if (strcasecmp(q, "HasWildcardMX") == 0)
168268759Seric {
168369896Seric HasWildcardMX = !clearmode;
168468759Seric continue;
168568759Seric }
168657207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
168757207Seric {
168857207Seric if (strcasecmp(q, rfp->rf_name) == 0)
168957207Seric break;
169057207Seric }
169164923Seric if (rfp->rf_name == NULL)
169264923Seric syserr("readcf: I option value %s unrecognized", q);
169364923Seric else if (clearmode)
169457207Seric _res.options &= ~rfp->rf_bits;
169557207Seric else
169657207Seric _res.options |= rfp->rf_bits;
169757207Seric }
169857207Seric if (tTd(8, 2))
169968759Seric printf("_res.options = %x, HasWildcardMX = %d\n",
170069896Seric _res.options, HasWildcardMX);
170157207Seric #else
170257207Seric usrerr("name server (I option) specified but BIND not compiled in");
170357207Seric #endif
170435651Seric break;
170535651Seric
17068269Seric case 'i': /* ignore dot lines in message */
17079381Seric IgnrDot = atobool(val);
17088269Seric break;
17098269Seric
171059730Seric case 'j': /* send errors in MIME (RFC 1341) format */
171159730Seric SendMIMEErrors = atobool(val);
171259730Seric break;
171359730Seric
171457136Seric case 'J': /* .forward search path */
171557136Seric ForwardPath = newstr(val);
171657136Seric break;
171757136Seric
171854967Seric case 'k': /* connection cache size */
171954967Seric MaxMciCache = atoi(val);
172056215Seric if (MaxMciCache < 0)
172156215Seric MaxMciCache = 0;
172254967Seric break;
172354967Seric
172454967Seric case 'K': /* connection cache timeout */
172558796Seric MciCacheTimeout = convtime(val, 'm');
172654967Seric break;
172754967Seric
172861104Seric case 'l': /* use Errors-To: header */
172961104Seric UseErrorsTo = atobool(val);
173061104Seric break;
173161104Seric
17328256Seric case 'L': /* log level */
173364140Seric if (safe || LogLevel < atoi(val))
173464140Seric LogLevel = atoi(val);
17358256Seric break;
17368256Seric
17378269Seric case 'M': /* define macro */
173868267Seric p = newstr(&val[1]);
173968267Seric if (!safe)
174068267Seric cleanstrcpy(p, p, MAXNAME);
174168267Seric define(val[0], p, CurEnv);
174216878Seric sticky = FALSE;
17438269Seric break;
17448269Seric
17458269Seric case 'm': /* send to me too */
17469381Seric MeToo = atobool(val);
17478269Seric break;
17488269Seric
174925820Seric case 'n': /* validate RHS in newaliases */
175025820Seric CheckAliases = atobool(val);
175125820Seric break;
175225820Seric
175361104Seric /* 'N' available -- was "net name" */
175461104Seric
175558851Seric case 'O': /* daemon options */
175658851Seric setdaemonoptions(val);
175758851Seric break;
175858851Seric
17598269Seric case 'o': /* assume old style headers */
17609381Seric if (atobool(val))
17619341Seric CurEnv->e_flags |= EF_OLDSTYLE;
17629341Seric else
17639341Seric CurEnv->e_flags &= ~EF_OLDSTYLE;
17648269Seric break;
17658269Seric
176658082Seric case 'p': /* select privacy level */
176758082Seric p = val;
176858082Seric for (;;)
176958082Seric {
177058082Seric register struct prival *pv;
177158082Seric extern struct prival PrivacyValues[];
177258082Seric
177358082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p)))
177458082Seric p++;
177558082Seric if (*p == '\0')
177658082Seric break;
177758082Seric val = p;
177858082Seric while (isascii(*p) && isalnum(*p))
177958082Seric p++;
178058082Seric if (*p != '\0')
178158082Seric *p++ = '\0';
178258082Seric
178358082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
178458082Seric {
178558082Seric if (strcasecmp(val, pv->pv_name) == 0)
178658082Seric break;
178758082Seric }
178858886Seric if (pv->pv_name == NULL)
178958886Seric syserr("readcf: Op line: %s unrecognized", val);
179058082Seric PrivacyFlags |= pv->pv_flag;
179158082Seric }
179268479Seric sticky = FALSE;
179358082Seric break;
179458082Seric
179524944Seric case 'P': /* postmaster copy address for returned mail */
179624944Seric PostMasterCopy = newstr(val);
179724944Seric break;
179824944Seric
179924944Seric case 'q': /* slope of queue only function */
180024944Seric QueueFactor = atoi(val);
180124944Seric break;
180224944Seric
18038256Seric case 'Q': /* queue directory */
18049381Seric if (val[0] == '\0')
18058269Seric QueueDir = "mqueue";
18069381Seric else
18079381Seric QueueDir = newstr(val);
180858789Seric if (RealUid != 0 && !safe)
180964718Seric Warn_Q_option = TRUE;
18108256Seric break;
18118256Seric
181258148Seric case 'R': /* don't prune routes */
181358148Seric DontPruneRoutes = atobool(val);
181458148Seric break;
181558148Seric
18168256Seric case 'r': /* read timeout */
181768481Seric if (subopt == NULL)
181868481Seric inittimeouts(val);
181968481Seric else
182068481Seric settimeout(subopt, val);
18218256Seric break;
18228256Seric
18238256Seric case 'S': /* status file */
18249381Seric if (val[0] == '\0')
18258269Seric StatFile = "sendmail.st";
18269381Seric else
18279381Seric StatFile = newstr(val);
18288256Seric break;
18298256Seric
18308265Seric case 's': /* be super safe, even if expensive */
18319381Seric SuperSafe = atobool(val);
18328256Seric break;
18338256Seric
18348256Seric case 'T': /* queue timeout */
183558737Seric p = strchr(val, '/');
183658737Seric if (p != NULL)
183758737Seric {
183858737Seric *p++ = '\0';
183968481Seric settimeout("queuewarn", p);
184058737Seric }
184168481Seric settimeout("queuereturn", val);
184254967Seric break;
18438256Seric
18448265Seric case 't': /* time zone name */
184552106Seric TimeZoneSpec = newstr(val);
18468265Seric break;
18478265Seric
184850556Seric case 'U': /* location of user database */
184951360Seric UdbSpec = newstr(val);
185050556Seric break;
185150556Seric
18528256Seric case 'u': /* set default uid */
185368481Seric for (p = val; *p != '\0'; p++)
185468481Seric {
185568481Seric if (*p == '.' || *p == '/' || *p == ':')
185668481Seric {
185768481Seric *p++ = '\0';
185868481Seric break;
185968481Seric }
186068481Seric }
186164133Seric if (isascii(*val) && isdigit(*val))
186264133Seric DefUid = atoi(val);
186364133Seric else
186464133Seric {
186564133Seric register struct passwd *pw;
186664133Seric
186764133Seric DefUid = -1;
186868693Seric pw = sm_getpwnam(val);
186964133Seric if (pw == NULL)
187064133Seric syserr("readcf: option u: unknown user %s", val);
187164133Seric else
187268481Seric {
187364133Seric DefUid = pw->pw_uid;
187468481Seric DefGid = pw->pw_gid;
187568481Seric }
187664133Seric }
187740973Sbostic setdefuser();
18788256Seric
187968481Seric /* handle the group if it is there */
188068481Seric if (*p == '\0')
188168481Seric break;
188268481Seric val = p;
188368481Seric goto g_opt;
188468481Seric
188558851Seric case 'V': /* fallback MX host */
188658851Seric FallBackMX = newstr(val);
188758851Seric break;
188858851Seric
18898269Seric case 'v': /* run in verbose mode */
18909381Seric Verbose = atobool(val);
18918256Seric break;
18928256Seric
189363837Seric case 'w': /* if we are best MX, try host directly */
189463837Seric TryNullMXList = atobool(val);
189563837Seric break;
189661104Seric
189761104Seric /* 'W' available -- was wizard password */
189861104Seric
189914879Seric case 'x': /* load avg at which to auto-queue msgs */
190014879Seric QueueLA = atoi(val);
190114879Seric break;
190214879Seric
190314879Seric case 'X': /* load avg at which to auto-reject connections */
190414879Seric RefuseLA = atoi(val);
190514879Seric break;
190614879Seric
190724981Seric case 'y': /* work recipient factor */
190824981Seric WkRecipFact = atoi(val);
190924981Seric break;
191024981Seric
191124981Seric case 'Y': /* fork jobs during queue runs */
191224952Seric ForkQueueRuns = atobool(val);
191324952Seric break;
191424952Seric
191524981Seric case 'z': /* work message class factor */
191624981Seric WkClassFact = atoi(val);
191724981Seric break;
191824981Seric
191924981Seric case 'Z': /* work time factor */
192024981Seric WkTimeFact = atoi(val);
192124981Seric break;
192224981Seric
192368481Seric case O_QUEUESORTORD: /* queue sorting order */
192468481Seric switch (*val)
192568481Seric {
192668481Seric case 'h': /* Host first */
192768481Seric case 'H':
192868481Seric QueueSortOrder = QS_BYHOST;
192968481Seric break;
193068481Seric
193168481Seric case 'p': /* Priority order */
193268481Seric case 'P':
193368481Seric QueueSortOrder = QS_BYPRIORITY;
193468481Seric break;
193568481Seric
193668481Seric default:
193768481Seric syserr("Invalid queue sort order \"%s\"", val);
193868481Seric }
193968481Seric break;
194068481Seric
194169401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */
194269401Seric HostsFile = newstr(val);
194369401Seric break;
194469401Seric
194568481Seric case O_MQA: /* minimum queue age between deliveries */
194668481Seric MinQueueAge = convtime(val, 'm');
194768481Seric break;
194868481Seric
194968481Seric case O_MHSA: /* maximum age of cached host status */
195068481Seric MaxHostStatAge = convtime(val, 'm');
195168481Seric break;
195268481Seric
195368481Seric case O_DEFCHARSET: /* default character set for mimefying */
195468481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
195568481Seric break;
195668481Seric
195768481Seric case O_SSFILE: /* service switch file */
195868481Seric ServiceSwitchFile = newstr(val);
195968481Seric break;
196068481Seric
196168481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */
196268481Seric DialDelay = convtime(val, 's');
196368481Seric break;
196468481Seric
196568481Seric case O_NORCPTACTION: /* what to do if no recipient */
196668481Seric if (strcasecmp(val, "none") == 0)
196768481Seric NoRecipientAction = NRA_NO_ACTION;
196868481Seric else if (strcasecmp(val, "add-to") == 0)
196968481Seric NoRecipientAction = NRA_ADD_TO;
197068481Seric else if (strcasecmp(val, "add-apparently-to") == 0)
197168481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO;
197268481Seric else if (strcasecmp(val, "add-bcc") == 0)
197368481Seric NoRecipientAction = NRA_ADD_BCC;
197468481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0)
197568481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
197668481Seric else
197768481Seric syserr("Invalid NoRecipientAction: %s", val);
197868481Seric
197968490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */
198068490Seric SafeFileEnv = newstr(val);
198168490Seric break;
198268490Seric
198368569Seric case O_MAXMSGSIZE: /* maximum message size */
198469748Seric MaxMessageSize = atol(val);
198568569Seric break;
198668569Seric
198768756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */
198869748Seric ColonOkInAddr = atobool(val);
198968756Seric break;
199068756Seric
199169724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
199269748Seric MaxQueueRun = atol(val);
199369724Seric break;
199469724Seric
199569838Seric case O_MAXCHILDREN: /* max # of children of daemon */
199669838Seric MaxChildren = atoi(val);
199769852Seric break;
199869838Seric
199969852Seric case O_KEEPCNAMES: /* don't expand CNAME records */
200069852Seric DontExpandCnames = atobool(val);
200169852Seric break;
200269852Seric
20038256Seric default:
200468481Seric if (tTd(37, 1))
200568481Seric {
200668481Seric if (isascii(opt) && isprint(opt))
200768481Seric printf("Warning: option %c unknown\n", opt);
200868481Seric else
200968481Seric printf("Warning: option 0x%x unknown\n", opt);
201068481Seric }
20118256Seric break;
20128256Seric }
201316878Seric if (sticky)
201416878Seric setbitn(opt, StickyOpt);
20158256Seric }
201610687Seric /*
201768481Seric ** SETCLASS -- set a string into a class
201810687Seric **
201910687Seric ** Parameters:
202068481Seric ** class -- the class to put the string in.
202168481Seric ** str -- the string to enter
202210687Seric **
202310687Seric ** Returns:
202410687Seric ** none.
202510687Seric **
202610687Seric ** Side Effects:
202710687Seric ** puts the word into the symbol table.
202810687Seric */
202910687Seric
203069748Seric void
setclass(class,str)203168481Seric setclass(class, str)
203210687Seric int class;
203368481Seric char *str;
203410687Seric {
203510687Seric register STAB *s;
203610687Seric
203757943Seric if (tTd(37, 8))
2038*69976Seric printf("setclass(%s, %s)\n", macname(class), str);
203968481Seric s = stab(str, ST_CLASS, ST_ENTER);
204010687Seric setbitn(class, s->s_class);
204110687Seric }
204253654Seric /*
204353654Seric ** MAKEMAPENTRY -- create a map entry
204453654Seric **
204553654Seric ** Parameters:
204653654Seric ** line -- the config file line
204753654Seric **
204853654Seric ** Returns:
204969774Seric ** A pointer to the map that has been created.
205069774Seric ** NULL if there was a syntax error.
205153654Seric **
205253654Seric ** Side Effects:
205353654Seric ** Enters the map into the dictionary.
205453654Seric */
205553654Seric
205669774Seric MAP *
makemapentry(line)205753654Seric makemapentry(line)
205853654Seric char *line;
205953654Seric {
206053654Seric register char *p;
206153654Seric char *mapname;
206253654Seric char *classname;
206364078Seric register STAB *s;
206453654Seric STAB *class;
206553654Seric
206658050Seric for (p = line; isascii(*p) && isspace(*p); p++)
206753654Seric continue;
206858050Seric if (!(isascii(*p) && isalnum(*p)))
206953654Seric {
207053654Seric syserr("readcf: config K line: no map name");
207169774Seric return NULL;
207253654Seric }
207353654Seric
207453654Seric mapname = p;
207568481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.')
207653654Seric continue;
207753654Seric if (*p != '\0')
207853654Seric *p++ = '\0';
207958050Seric while (isascii(*p) && isspace(*p))
208053654Seric p++;
208158050Seric if (!(isascii(*p) && isalnum(*p)))
208253654Seric {
208353654Seric syserr("readcf: config K line, map %s: no map class", mapname);
208469774Seric return NULL;
208553654Seric }
208653654Seric classname = p;
208758050Seric while (isascii(*++p) && isalnum(*p))
208853654Seric continue;
208953654Seric if (*p != '\0')
209053654Seric *p++ = '\0';
209158050Seric while (isascii(*p) && isspace(*p))
209253654Seric p++;
209353654Seric
209453654Seric /* look up the class */
209553654Seric class = stab(classname, ST_MAPCLASS, ST_FIND);
209653654Seric if (class == NULL)
209753654Seric {
209853654Seric syserr("readcf: map %s: class %s not available", mapname, classname);
209969774Seric return NULL;
210053654Seric }
210153654Seric
210253654Seric /* enter the map */
210364078Seric s = stab(mapname, ST_MAP, ST_ENTER);
210464078Seric s->s_map.map_class = &class->s_mapclass;
210564078Seric s->s_map.map_mname = newstr(mapname);
210653654Seric
210764078Seric if (class->s_mapclass.map_parse(&s->s_map, p))
210864078Seric s->s_map.map_mflags |= MF_VALID;
210964078Seric
211064078Seric if (tTd(37, 5))
211164078Seric {
211264078Seric printf("map %s, class %s, flags %x, file %s,\n",
211364078Seric s->s_map.map_mname, s->s_map.map_class->map_cname,
211464078Seric s->s_map.map_mflags,
211564078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
211664078Seric printf("\tapp %s, domain %s, rebuild %s\n",
211764078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
211864078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
211964078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
212064078Seric }
212169774Seric
212269774Seric return &s->s_map;
212353654Seric }
212458112Seric /*
212569783Seric ** STRTORWSET -- convert string to rewriting set number
212669783Seric **
212769783Seric ** Parameters:
212869783Seric ** p -- the pointer to the string to decode.
212969783Seric ** endp -- if set, store the trailing delimiter here.
213069783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if
213169783Seric ** it must already exist.
213269783Seric **
213369783Seric ** Returns:
213469783Seric ** The appropriate ruleset number.
213569783Seric ** -1 if it is not valid (error already printed)
213669783Seric */
213769783Seric
213869783Seric int
strtorwset(p,endp,stabmode)213969783Seric strtorwset(p, endp, stabmode)
214069783Seric char *p;
214169783Seric char **endp;
214269783Seric int stabmode;
214369783Seric {
214469783Seric int ruleset;
214569783Seric static int nextruleset = MAXRWSETS;
214669783Seric
214769783Seric while (isascii(*p) && isspace(*p))
214869783Seric p++;
214969783Seric if (!isascii(*p))
215069783Seric {
215169783Seric syserr("invalid ruleset name: \"%.20s\"", p);
215269783Seric return -1;
215369783Seric }
215469783Seric if (isdigit(*p))
215569783Seric {
215669783Seric ruleset = strtol(p, endp, 10);
215769783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
215869783Seric {
215969783Seric syserr("bad ruleset %d (%d max)",
216069783Seric ruleset, MAXRWSETS / 2);
216169783Seric ruleset = -1;
216269783Seric }
216369783Seric }
216469783Seric else
216569783Seric {
216669783Seric STAB *s;
216769783Seric char delim;
216869783Seric char *q;
216969783Seric
217069783Seric q = p;
217169783Seric while (*p != '\0' && isascii(*p) &&
217269783Seric (isalnum(*p) || strchr("-_$", *p) != NULL))
217369783Seric p++;
217469970Seric if (q == p || !isalpha(*q))
217569970Seric {
217669970Seric /* no valid characters */
217769970Seric syserr("invalid ruleset name: \"%.20s\"", q);
217869970Seric return -1;
217969970Seric }
218069783Seric while (isascii(*p) && isspace(*p))
218169783Seric *p++ = '\0';
218269783Seric delim = *p;
218369783Seric if (delim != '\0')
218469783Seric *p = '\0';
218569783Seric s = stab(q, ST_RULESET, stabmode);
218669783Seric if (delim != '\0')
218769783Seric *p = delim;
218869783Seric
218969783Seric if (s == NULL)
219069783Seric {
219169783Seric syserr("unknown ruleset %s", q);
219269783Seric return -1;
219369783Seric }
219469783Seric
219569783Seric if (stabmode == ST_ENTER && delim == '=')
219669783Seric {
219769962Seric ruleset = strtol(++p, endp, 10);
219869783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
219969783Seric {
220069783Seric syserr("bad ruleset %s = %d (%d max)",
220169783Seric q, ruleset, MAXRWSETS / 2);
220269783Seric ruleset = -1;
220369783Seric }
220469783Seric }
220569783Seric else
220669783Seric {
220769783Seric if (endp != NULL)
220869783Seric *endp = p;
220969783Seric if (s->s_ruleset > 0)
221069783Seric ruleset = s->s_ruleset;
221169783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
221269783Seric {
221369783Seric syserr("%s: too many named rulesets (%d max)",
221469783Seric q, MAXRWSETS / 2);
221569783Seric ruleset = -1;
221669783Seric }
221769783Seric }
221869783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset)
221969783Seric {
222069783Seric syserr("%s: ruleset changed value (old %d, new %d)",
222169783Seric q, ruleset, s->s_ruleset);
222269783Seric ruleset = s->s_ruleset;
222369783Seric }
222469783Seric else if (ruleset > 0)
222569783Seric {
222669783Seric s->s_ruleset = ruleset;
222769783Seric }
222869783Seric }
222969783Seric return ruleset;
223069783Seric }
223169783Seric /*
223268481Seric ** INITTIMEOUTS -- parse and set timeout values
223358112Seric **
223458112Seric ** Parameters:
223558112Seric ** val -- a pointer to the values. If NULL, do initial
223658112Seric ** settings.
223758112Seric **
223858112Seric ** Returns:
223958112Seric ** none.
224058112Seric **
224158112Seric ** Side Effects:
224258112Seric ** Initializes the TimeOuts structure
224358112Seric */
224458112Seric
224564255Seric #define SECONDS
224658112Seric #define MINUTES * 60
224758112Seric #define HOUR * 3600
224858112Seric
224969748Seric void
inittimeouts(val)225068481Seric inittimeouts(val)
225158112Seric register char *val;
225258112Seric {
225358112Seric register char *p;
225458671Seric extern time_t convtime();
225558112Seric
225658112Seric if (val == NULL)
225758112Seric {
225858112Seric TimeOuts.to_initial = (time_t) 5 MINUTES;
225958112Seric TimeOuts.to_helo = (time_t) 5 MINUTES;
226058112Seric TimeOuts.to_mail = (time_t) 10 MINUTES;
226158112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR;
226258112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES;
226358112Seric TimeOuts.to_datablock = (time_t) 1 HOUR;
226458112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR;
226558112Seric TimeOuts.to_rset = (time_t) 5 MINUTES;
226658112Seric TimeOuts.to_quit = (time_t) 2 MINUTES;
226758112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR;
226858112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES;
226968481Seric #if IDENTPROTO
227064255Seric TimeOuts.to_ident = (time_t) 30 SECONDS;
227168481Seric #else
227268481Seric TimeOuts.to_ident = (time_t) 0 SECONDS;
227368481Seric #endif
227468481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS;
227558112Seric return;
227658112Seric }
227758112Seric
227858112Seric for (;; val = p)
227958112Seric {
228058112Seric while (isascii(*val) && isspace(*val))
228158112Seric val++;
228258112Seric if (*val == '\0')
228358112Seric break;
228458112Seric for (p = val; *p != '\0' && *p != ','; p++)
228558112Seric continue;
228658112Seric if (*p != '\0')
228758112Seric *p++ = '\0';
228858112Seric
228958112Seric if (isascii(*val) && isdigit(*val))
229058112Seric {
229158112Seric /* old syntax -- set everything */
229258796Seric TimeOuts.to_mail = convtime(val, 'm');
229358112Seric TimeOuts.to_rcpt = TimeOuts.to_mail;
229458112Seric TimeOuts.to_datainit = TimeOuts.to_mail;
229558112Seric TimeOuts.to_datablock = TimeOuts.to_mail;
229658112Seric TimeOuts.to_datafinal = TimeOuts.to_mail;
229758112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail;
229858112Seric continue;
229958112Seric }
230058112Seric else
230158112Seric {
230268481Seric register char *q = strchr(val, ':');
230358112Seric
230468481Seric if (q == NULL && (q = strchr(val, '=')) == NULL)
230558112Seric {
230658112Seric /* syntax error */
230758112Seric continue;
230858112Seric }
230958112Seric *q++ = '\0';
231068481Seric settimeout(val, q);
231168481Seric }
231268481Seric }
231368481Seric }
231468481Seric /*
231568481Seric ** SETTIMEOUT -- set an individual timeout
231668481Seric **
231768481Seric ** Parameters:
231868481Seric ** name -- the name of the timeout.
231968481Seric ** val -- the value of the timeout.
232068481Seric **
232168481Seric ** Returns:
232268481Seric ** none.
232368481Seric */
232458112Seric
232569748Seric void
settimeout(name,val)232668481Seric settimeout(name, val)
232768481Seric char *name;
232868481Seric char *val;
232968481Seric {
233068481Seric register char *p;
233168481Seric time_t to;
233268481Seric extern time_t convtime();
233368481Seric
233468481Seric to = convtime(val, 'm');
233568481Seric p = strchr(name, '.');
233668481Seric if (p != NULL)
233768481Seric *p++ = '\0';
233868481Seric
233968481Seric if (strcasecmp(name, "initial") == 0)
234068481Seric TimeOuts.to_initial = to;
234168481Seric else if (strcasecmp(name, "mail") == 0)
234268481Seric TimeOuts.to_mail = to;
234368481Seric else if (strcasecmp(name, "rcpt") == 0)
234468481Seric TimeOuts.to_rcpt = to;
234568481Seric else if (strcasecmp(name, "datainit") == 0)
234668481Seric TimeOuts.to_datainit = to;
234768481Seric else if (strcasecmp(name, "datablock") == 0)
234868481Seric TimeOuts.to_datablock = to;
234968481Seric else if (strcasecmp(name, "datafinal") == 0)
235068481Seric TimeOuts.to_datafinal = to;
235168481Seric else if (strcasecmp(name, "command") == 0)
235268481Seric TimeOuts.to_nextcommand = to;
235368481Seric else if (strcasecmp(name, "rset") == 0)
235468481Seric TimeOuts.to_rset = to;
235568481Seric else if (strcasecmp(name, "helo") == 0)
235668481Seric TimeOuts.to_helo = to;
235768481Seric else if (strcasecmp(name, "quit") == 0)
235868481Seric TimeOuts.to_quit = to;
235968481Seric else if (strcasecmp(name, "misc") == 0)
236068481Seric TimeOuts.to_miscshort = to;
236168481Seric else if (strcasecmp(name, "ident") == 0)
236268481Seric TimeOuts.to_ident = to;
236368481Seric else if (strcasecmp(name, "fileopen") == 0)
236468481Seric TimeOuts.to_fileopen = to;
236568481Seric else if (strcasecmp(name, "queuewarn") == 0)
236668481Seric {
236768481Seric to = convtime(val, 'h');
236868481Seric if (p == NULL || strcmp(p, "*") == 0)
236968481Seric {
237068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to;
237168481Seric TimeOuts.to_q_warning[TOC_URGENT] = to;
237268481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to;
237358112Seric }
237468481Seric else if (strcasecmp(p, "normal") == 0)
237568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to;
237668481Seric else if (strcasecmp(p, "urgent") == 0)
237768481Seric TimeOuts.to_q_warning[TOC_URGENT] = to;
237868481Seric else if (strcasecmp(p, "non-urgent") == 0)
237968481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to;
238068481Seric else
238168481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p);
238258112Seric }
238368481Seric else if (strcasecmp(name, "queuereturn") == 0)
238468481Seric {
238568481Seric to = convtime(val, 'd');
238668481Seric if (p == NULL || strcmp(p, "*") == 0)
238768481Seric {
238868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to;
238968481Seric TimeOuts.to_q_return[TOC_URGENT] = to;
239068481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to;
239168481Seric }
239268481Seric else if (strcasecmp(p, "normal") == 0)
239368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to;
239468481Seric else if (strcasecmp(p, "urgent") == 0)
239568481Seric TimeOuts.to_q_return[TOC_URGENT] = to;
239668481Seric else if (strcasecmp(p, "non-urgent") == 0)
239768481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to;
239868481Seric else
239968481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p);
240068481Seric }
240168481Seric else
240268481Seric syserr("settimeout: invalid timeout %s", name);
240358112Seric }
2404